mirror of
https://github.com/NCBM/plyngent.git
synced 2026-11-07 23:47:54 +08:00
core/todo-nag: inject reasoning_content on synthetic assistant messages
DeepSeek's reasoning API enforces: if an assistant with tool_calls sits between two user messages, its reasoning_content must be passed back. The synthetic todo nag pair creates an AssistantChatMessage with tool_calls but no reasoning_content, which triggered a 400 error: "The reasoning_content in the thinking mode must be passed back to the API." Fix: 1. _append_synthetic_todo_list now sets reasoning_content="" so NEW pairs carry the field. 2. refresh_synthetic_todo_nags runs _inject_reasoning_content_for_synthetic to fix EXISTING pairs (in DB) even if reasoning_content was UNSET. 3. The earlier _inject_thinking change is reverted in the next commit since the real root cause was the missing reasoning_content on forged tool_call messages, not the thinking parameter itself.
This commit is contained in:
@@ -69,6 +69,7 @@ def _append_synthetic_todo_list(messages: list[AnyChatMessage], body: str) -> st
|
|||||||
messages.append(
|
messages.append(
|
||||||
AssistantChatMessage(
|
AssistantChatMessage(
|
||||||
content=UNSET,
|
content=UNSET,
|
||||||
|
reasoning_content="",
|
||||||
tool_calls=[
|
tool_calls=[
|
||||||
AssistantFunctionToolCall(
|
AssistantFunctionToolCall(
|
||||||
id=call_id,
|
id=call_id,
|
||||||
@@ -130,9 +131,39 @@ def refresh_synthetic_todo_nags(
|
|||||||
continue
|
continue
|
||||||
messages[index] = ToolChatMessage(tool_call_id=msg.tool_call_id, content=body)
|
messages[index] = ToolChatMessage(tool_call_id=msg.tool_call_id, content=body)
|
||||||
updated += 1
|
updated += 1
|
||||||
|
|
||||||
|
# Synthetic assistant messages (tool calls but no reasoning_content) trip
|
||||||
|
# DeepSeek's rule: "if the model performed a tool call between two user
|
||||||
|
# messages, the assistant's reasoning_content must be passed back."
|
||||||
|
# Inject empty reasoning_content so the API doesn't reject the request.
|
||||||
|
updated += _inject_reasoning_content_for_synthetic(messages)
|
||||||
return updated
|
return updated
|
||||||
|
|
||||||
|
|
||||||
|
def _inject_reasoning_content_for_synthetic(
|
||||||
|
messages: list[AnyChatMessage],
|
||||||
|
) -> int:
|
||||||
|
"""Inject ``reasoning_content=\"\"`` into synthetic nag assistants that lack it."""
|
||||||
|
injected = 0
|
||||||
|
for index, msg in enumerate(messages):
|
||||||
|
if not isinstance(msg, AssistantChatMessage):
|
||||||
|
continue
|
||||||
|
tool_calls = msg.tool_calls
|
||||||
|
if tool_calls is UNSET or not tool_calls:
|
||||||
|
continue
|
||||||
|
if not any(
|
||||||
|
isinstance(c, AssistantFunctionToolCall) and is_synthetic_todo_nag_call_id(c.id) for c in tool_calls
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
if msg.reasoning_content is not UNSET:
|
||||||
|
continue
|
||||||
|
from msgspec import structs
|
||||||
|
|
||||||
|
messages[index] = structs.replace(msg, reasoning_content="")
|
||||||
|
injected += 1
|
||||||
|
return injected
|
||||||
|
|
||||||
|
|
||||||
def inject_todo_nag(
|
def inject_todo_nag(
|
||||||
messages: list[AnyChatMessage],
|
messages: list[AnyChatMessage],
|
||||||
body: str,
|
body: str,
|
||||||
|
|||||||
Reference in New Issue
Block a user