fix(provider): narrow DeepSeek reasoning history cleanup

Made-with: Cursor
This commit is contained in:
Xubin Ren
2026-05-01 19:52:38 +08:00
committed by Xubin Ren
parent 8ca575bdeb
commit 43a58335f6
2 changed files with 67 additions and 9 deletions
+54 -4
View File
@@ -913,8 +913,8 @@ def test_deepseek_backfills_reasoning_content_on_legacy_tool_call_messages() ->
assert msg["reasoning_content"] == ""
def test_backfill_does_not_touch_messages_when_thinking_off() -> None:
"""When reasoning_effort is None or minimal, legacy messages must NOT be altered."""
def test_backfill_does_not_touch_messages_when_thinking_explicitly_off() -> None:
"""When thinking is explicitly disabled, legacy messages must NOT be altered."""
spec = find_by_name("deepseek")
with patch("nanobot.providers.openai_compat_provider.AsyncOpenAI"):
p = OpenAICompatProvider(api_key="k", default_model="deepseek-v4-pro", spec=spec)
@@ -926,7 +926,7 @@ def test_backfill_does_not_touch_messages_when_thinking_off() -> None:
{"role": "tool", "tool_call_id": "tc1", "content": "result"},
{"role": "user", "content": "thanks"},
]
for effort in (None, "minimal"):
for effort in ("minimal", "none"):
kw = p._build_kwargs(
messages=list(messages), tools=None, model="deepseek-v4-pro",
max_tokens=1024, temperature=0.7,
@@ -937,6 +937,56 @@ def test_backfill_does_not_touch_messages_when_thinking_off() -> None:
assert "reasoning_content" not in msg
def test_deepseek_v4_drops_incomplete_reasoning_history_when_effort_implicit() -> None:
"""DeepSeek-V4 may default to thinking, so incomplete legacy history is trimmed."""
spec = find_by_name("deepseek")
with patch("nanobot.providers.openai_compat_provider.AsyncOpenAI"):
p = OpenAICompatProvider(api_key="k", default_model="deepseek-v4-pro", spec=spec)
messages = [
{"role": "system", "content": "system"},
{"role": "user", "content": "hi"},
{"role": "assistant", "content": "", "tool_calls": [
{"id": "tc1", "type": "function", "function": {"name": "web_search", "arguments": "{}"}}
]},
{"role": "tool", "tool_call_id": "tc1", "content": "result"},
{"role": "user", "content": "thanks"},
]
kw = p._build_kwargs(
messages=list(messages), tools=None, model="deepseek-v4-pro",
max_tokens=1024, temperature=0.7,
reasoning_effort=None, tool_choice=None,
)
assert [msg["role"] for msg in kw["messages"]] == ["system", "user"]
assert kw["messages"][-1]["content"] == "thanks"
def test_deepseek_chat_keeps_tool_history_when_effort_implicit() -> None:
"""Implicit cleanup must not trim non-thinking DeepSeek chat models."""
spec = find_by_name("deepseek")
with patch("nanobot.providers.openai_compat_provider.AsyncOpenAI"):
p = OpenAICompatProvider(api_key="k", default_model="deepseek-chat", spec=spec)
messages = [
{"role": "user", "content": "hi"},
{"role": "assistant", "content": "", "tool_calls": [
{"id": "tc1", "type": "function", "function": {"name": "web_search", "arguments": "{}"}}
]},
{"role": "tool", "tool_call_id": "tc1", "content": "result"},
{"role": "user", "content": "thanks"},
]
kw = p._build_kwargs(
messages=list(messages), tools=None, model="deepseek-chat",
max_tokens=1024, temperature=0.7,
reasoning_effort=None, tool_choice=None,
)
roles = [msg["role"] for msg in kw["messages"]]
assert roles == ["user", "assistant", "tool", "user"]
assert kw["messages"][1]["tool_calls"]
def test_deepseek_coerces_list_content_to_string() -> None:
"""DeepSeek chat endpoint expects message.content to be a string."""
spec = find_by_name("deepseek")
@@ -1061,7 +1111,7 @@ def test_kimi_k2_thinking_series_no_thinking_injection() -> None:
# ---------------------------------------------------------------------------
# reasoning_effort="none" — treated as thinking disabled
# reasoning_effort="none" — treated as thinking disabled
# ---------------------------------------------------------------------------
def test_deepseek_thinking_disabled_for_none_string() -> None: