Skip to content

Commit 8455af0

Browse files
authored
fix: #2155 DeepSeek reasoning_content missing in tool call messages (#2328)
1 parent 11ec33a commit 8455af0

2 files changed

Lines changed: 392 additions & 1 deletion

File tree

src/agents/models/chatcmpl_converter.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -428,15 +428,20 @@ def items_to_messages(
428428
result: list[ChatCompletionMessageParam] = []
429429
current_assistant_msg: ChatCompletionAssistantMessageParam | None = None
430430
pending_thinking_blocks: list[dict[str, str]] | None = None
431+
pending_reasoning_content: str | None = None # For DeepSeek reasoning_content
431432

432433
def flush_assistant_message() -> None:
433-
nonlocal current_assistant_msg
434+
nonlocal current_assistant_msg, pending_reasoning_content
434435
if current_assistant_msg is not None:
435436
# The API doesn't support empty arrays for tool_calls
436437
if not current_assistant_msg.get("tool_calls"):
437438
del current_assistant_msg["tool_calls"]
439+
# prevents stale reasoning_content from contaminating later turns
440+
pending_reasoning_content = None
438441
result.append(current_assistant_msg)
439442
current_assistant_msg = None
443+
else:
444+
pending_reasoning_content = None
440445

441446
def ensure_assistant_message() -> ChatCompletionAssistantMessageParam:
442447
nonlocal current_assistant_msg, pending_thinking_blocks
@@ -579,6 +584,11 @@ def ensure_assistant_message() -> ChatCompletionAssistantMessageParam:
579584
elif func_call := cls.maybe_function_tool_call(item):
580585
asst = ensure_assistant_message()
581586

587+
# If we have pending reasoning content for DeepSeek, add it to the assistant message
588+
if pending_reasoning_content:
589+
asst["reasoning_content"] = pending_reasoning_content # type: ignore[typeddict-unknown-key]
590+
pending_reasoning_content = None # Clear after using
591+
582592
# If we have pending thinking blocks, use them as the content
583593
# This is required for Anthropic API tool calls with interleaved thinking
584594
if pending_thinking_blocks:
@@ -687,6 +697,26 @@ def ensure_assistant_message() -> ChatCompletionAssistantMessageParam:
687697
# This preserves the original behavior
688698
pending_thinking_blocks = reconstructed_thinking_blocks
689699

700+
# DeepSeek requires reasoning_content field in assistant messages with tool calls
701+
# Items may not all originate from DeepSeek, so need to check for model match.
702+
# For backward compatibility, if provider_data is missing, ignore the check.
703+
elif (
704+
model
705+
and "deepseek" in model.lower()
706+
and (
707+
(item_model and "deepseek" in item_model.lower())
708+
or item_provider_data == {}
709+
)
710+
):
711+
summary_items = reasoning_item.get("summary", [])
712+
if summary_items:
713+
reasoning_texts = []
714+
for summary_item in summary_items:
715+
if isinstance(summary_item, dict) and summary_item.get("text"):
716+
reasoning_texts.append(summary_item["text"])
717+
if reasoning_texts:
718+
pending_reasoning_content = "\n".join(reasoning_texts)
719+
690720
# 8) compaction items => reject for chat completions
691721
elif isinstance(item, dict) and item.get("type") == "compaction":
692722
raise UserError(

0 commit comments

Comments
 (0)