fix(translator): preserve reasoning_content across Codex Responses round-trip#3561
fix(translator): preserve reasoning_content across Codex Responses round-trip#3561shellus wants to merge 1 commit into
Conversation
|
This pull request targeted The base branch has been automatically changed to |
There was a problem hiding this comment.
Code Review
This pull request adds support for handling reasoning content when converting between OpenAI Chat Completions and OpenAI Responses. It collects reasoning content from either the summary text or the encrypted_content fallback, appending it as reasoning_content to assistant messages and pending tool calls. Additionally, it ensures encrypted_content is populated in the response so that Codex clients preserve it across turns. The reviewer suggested explicitly clearing pendingReasoningContent when encountering non-assistant messages to prevent potential leakage of reasoning content into subsequent turns.
| if role == "assistant" && pendingReasoningContent != "" { | ||
| message, _ = sjson.SetBytes(message, "reasoning_content", pendingReasoningContent) | ||
| pendingReasoningContent = "" | ||
| } |
There was a problem hiding this comment.
If the message role is not assistant (e.g., user or system), any accumulated pendingReasoningContent from a previous turn should be discarded to prevent it from leaking into subsequent assistant messages in case of malformed or incomplete history. We should explicitly clear pendingReasoningContent when encountering non-assistant messages.
\t\t\t\tif role == \"assistant\" {\n\t\t\t\t\tif pendingReasoningContent != \"\" {\n\t\t\t\t\t\tmessage, _ = sjson.SetBytes(message, \"reasoning_content\", pendingReasoningContent)\n\t\t\t\t\t\tpendingReasoningContent = \"\"\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tpendingReasoningContent = \"\"\n\t\t\t\t}…und-trip Codex clients discard reasoning item summary.text but retain encrypted_content between turns. Previously the response translator only populated summary.text and left encrypted_content empty, so Codex would send back an empty reasoning item. The request translator also had no reasoning item handler, losing any reasoning content that did survive. Response side (both streaming and non-streaming): - Populate encrypted_content with the same reasoning text. Request side: - Add case for 'reasoning' input items. - Extract reasoning content from summary.text first, falling back to encrypted_content when summary is empty (Codex behavior). - Attach collected reasoning_content to all assistant messages in the same turn (text message and tool_calls message). - Clear pending reasoning content on non-assistant messages to prevent cross-turn leakage. Fixes DeepSeek V4 400 error: 'The reasoning_content in the thinking mode must be passed back to the API.'
0747299 to
60910d3
Compare
|
Updated based on review feedback and additional testing:
Tested e2e with Codex CLI v0.125.0 + DeepSeek V4 Pro in both |
Problem
Codex clients using the Responses API (
/v1/responses) with DeepSeek V4 thinking models fail on multi-turn conversations with:Root cause: Codex clients discard reasoning item
summary.textbut retainencrypted_contentbetween turns. The response translator only populatedsummary.textand leftencrypted_contentempty. The request translator also had no reasoning item handler at all.Changes
Response translator (both streaming and non-streaming)
encrypted_contentwith the same text assummary.textin reasoning output itemsRequest translator
case "reasoning":handler for input itemssummary.textfirst, falling back toencrypted_content(Codex behavior)reasoning_contentto the next assistant message (both regular text and tool_calls)Verification
Related Issues
reasoning_content导致报错 #2999