fix(provider): backfill DeepSeek reasoning_content instead of dropping history (#3554, #3584)

This commit is contained in:
04cb
2026-05-04 12:14:38 +08:00
committed by Xubin Ren
parent 3ceabdecd5
commit 9d6afd86b5
2 changed files with 31 additions and 95 deletions
+16 -22
View File
@@ -620,7 +620,8 @@ def _tool_call(call_id: str) -> dict:
}
def test_deepseek_thinking_drops_tool_history_missing_reasoning_content() -> None:
def test_deepseek_thinking_backfills_missing_reasoning_content_on_tool_history() -> None:
"""Backfill reasoning_content="" instead of dropping the turn (#3554, #3584)."""
kwargs = _deepseek_kwargs([
{"role": "system", "content": "system"},
{"role": "user", "content": "can we use wechat?"},
@@ -629,10 +630,12 @@ def test_deepseek_thinking_drops_tool_history_missing_reasoning_content() -> Non
{"role": "user", "content": "continue"},
])
assert kwargs["messages"] == [
{"role": "system", "content": "system"},
{"role": "user", "content": "continue"},
assert [m["role"] for m in kwargs["messages"]] == [
"system", "user", "assistant", "tool", "user",
]
assistant = kwargs["messages"][2]
assert assistant["reasoning_content"] == ""
assert assistant["tool_calls"][0]["function"]["name"] == "my"
def test_deepseek_thinking_keeps_tool_history_with_reasoning_content() -> None:
@@ -654,20 +657,6 @@ def test_deepseek_thinking_keeps_tool_history_with_reasoning_content() -> None:
assert kwargs["messages"][2]["role"] == "tool"
def test_deepseek_thinking_drops_current_bad_tool_turn_without_followup_user() -> None:
kwargs = _deepseek_kwargs([
{"role": "system", "content": "system"},
{"role": "user", "content": "can we use wechat?"},
{"role": "assistant", "content": "", "tool_calls": [_tool_call("call_bad")]},
{"role": "tool", "tool_call_id": "call_bad", "name": "my", "content": "channels"},
])
assert kwargs["messages"] == [
{"role": "system", "content": "system"},
{"role": "user", "content": "can we use wechat?"},
]
def test_openai_compat_keeps_tool_calls_after_consecutive_assistant_messages() -> None:
with patch("nanobot.providers.openai_compat_provider.AsyncOpenAI"):
provider = OpenAICompatProvider()
@@ -937,8 +926,8 @@ def test_backfill_does_not_touch_messages_when_thinking_explicitly_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."""
def test_deepseek_v4_backfills_incomplete_reasoning_history_when_effort_implicit() -> None:
"""DeepSeek-V4 reasons natively: backfill even without explicit reasoning_effort."""
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)
@@ -958,12 +947,16 @@ def test_deepseek_v4_drops_incomplete_reasoning_history_when_effort_implicit() -
reasoning_effort=None, tool_choice=None,
)
assert [msg["role"] for msg in kw["messages"]] == ["system", "user"]
assert [msg["role"] for msg in kw["messages"]] == [
"system", "user", "assistant", "tool", "user",
]
assert kw["messages"][2]["reasoning_content"] == ""
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."""
"""Non-thinking deepseek-chat must keep history untouched and must NOT
receive backfilled reasoning_content (#3554, #3584)."""
spec = find_by_name("deepseek")
with patch("nanobot.providers.openai_compat_provider.AsyncOpenAI"):
p = OpenAICompatProvider(api_key="k", default_model="deepseek-chat", spec=spec)
@@ -985,6 +978,7 @@ def test_deepseek_chat_keeps_tool_history_when_effort_implicit() -> None:
roles = [msg["role"] for msg in kw["messages"]]
assert roles == ["user", "assistant", "tool", "user"]
assert kw["messages"][1]["tool_calls"]
assert "reasoning_content" not in kw["messages"][1]
def test_deepseek_coerces_list_content_to_string() -> None: