@@ -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