Client or integration
Codex App
Provider or upstream service
OpenCode Go (Console Go), model opencode-go/deepseek-v4-flash
OpenCodex version
2.10.0
Endpoint or capability
/v1/chat/completions — replay of reasoning metadata when continuing an assistant tool-call turn.
Current behaviour
During multi-turn Codex App tasks that use tools with DeepSeek thinking mode enabled, OpenCodex intermittently forwards a continuation without the original non-empty reasoning_content. OpenCode Go then rejects the request with HTTP 400.
Five matching failures were observed across two conversations: three consecutive failures in one conversation and two in another. Each failed after roughly 55–80 seconds. Retrying the same conversation can later succeed, which suggests a history transformation path such as resume, retry, compaction, or another synthetic continuation rather than a permanently invalid model configuration.
Expected behaviour
For every assistant message that contains tool_calls, OpenCodex should preserve and replay the exact non-empty reasoning_content returned by the provider when sending subsequent tool results and conversation history. This invariant should hold across normal tool continuations, retries, resumed conversations, compaction, and synthetic/web-search loops.
OpenCodex should not invent an empty placeholder. It should retain the provider's original reasoning payload for the matching assistant tool-call turn.
Minimal redacted request or reproduction
- Configure Codex App to use
opencode-go/deepseek-v4-flash through OpenCodex 2.10.0.
- Enable thinking mode with reasoning effort
max.
- Start a multi-turn task that causes the model to call tools.
- Continue or retry the conversation after tool results; longer runs that resume or compact history reproduce the problem more readily.
- Observe an intermittent HTTP 400 from OpenCode Go.
The request is redacted because the failure occurred in real conversations. The relevant shape is an assistant tool-call message originally returned with non-empty reasoning_content, followed by a later continuation in which that field is missing.
Actual response or error
stream disconnected before completion: Provider error 400: Error from provider (Console Go): Upstream request failed: [invalid_request_error] The `reasoning_content` in the thinking mode must be passed back to the API.
Upstream documentation
https://api-docs.deepseek.com/guides/thinking_mode
DeepSeek documents that, when a thinking-mode response performs a tool call, the assistant's reasoning_content must be passed back in subsequent requests; otherwise the API returns HTTP 400.
Suggested mapping or implementation notes
OpenCodex already has reasoning replay handling for the ordinary OpenCode Go DeepSeek tool-call path and for the web-search loop. The remaining intermittent failure likely occurs in another history transformation path; this is a hypothesis, not a confirmed root cause.
A robust fix would:
- Preserve the original raw reasoning value on the same assistant tool-call turn through resume, retry, compaction, and synthetic-history transformations.
- Serialize that value for models covered by
preserveReasoningContentModels.
- Add an invariant check immediately before provider serialization: an assistant message with
tool_calls that originally had non-empty reasoning must still have non-empty reasoning_content.
- Avoid generating empty or fabricated reasoning values.
- Emit privacy-safe diagnostics (path name and counters only, never reasoning text).
Suggested regression coverage:
- ordinary assistant tool call → tool result → continuation;
- retry after a failed continuation;
- resumed conversation;
- compacted history containing an assistant tool call;
- web-search or other synthetic tool loop;
- assertions that logs never contain reasoning text.
Additional context and attachments
Related implementation history appears to include #78 for normal OpenCode Go DeepSeek tool-call replay and #688 for web-search raw-reasoning replay. #875 concerns the official DeepSeek native Responses route and appears to be a separate integration path.
Observed environment:
- OpenCodex 2.10.0;
- Codex App;
opencode-go/deepseek-v4-flash;
- effective reasoning effort
max;
- five identical 400 responses across two conversations;
- no secrets, conversation identifiers, or reasoning payloads included.
A local diagnostic prototype previously exercised the proposed invariant and completed focused tests, type checking, privacy checks, and the full test suite (7,658 passing, 8 skipped, 0 failing). That prototype was reverted; this issue does not depend on any local patch.
Checks
Client or integration
Codex App
Provider or upstream service
OpenCode Go (Console Go), model
opencode-go/deepseek-v4-flashOpenCodex version
2.10.0
Endpoint or capability
/v1/chat/completions— replay of reasoning metadata when continuing an assistant tool-call turn.Current behaviour
During multi-turn Codex App tasks that use tools with DeepSeek thinking mode enabled, OpenCodex intermittently forwards a continuation without the original non-empty
reasoning_content. OpenCode Go then rejects the request with HTTP 400.Five matching failures were observed across two conversations: three consecutive failures in one conversation and two in another. Each failed after roughly 55–80 seconds. Retrying the same conversation can later succeed, which suggests a history transformation path such as resume, retry, compaction, or another synthetic continuation rather than a permanently invalid model configuration.
Expected behaviour
For every assistant message that contains
tool_calls, OpenCodex should preserve and replay the exact non-emptyreasoning_contentreturned by the provider when sending subsequent tool results and conversation history. This invariant should hold across normal tool continuations, retries, resumed conversations, compaction, and synthetic/web-search loops.OpenCodex should not invent an empty placeholder. It should retain the provider's original reasoning payload for the matching assistant tool-call turn.
Minimal redacted request or reproduction
opencode-go/deepseek-v4-flashthrough OpenCodex 2.10.0.max.The request is redacted because the failure occurred in real conversations. The relevant shape is an assistant tool-call message originally returned with non-empty
reasoning_content, followed by a later continuation in which that field is missing.Actual response or error
Upstream documentation
https://api-docs.deepseek.com/guides/thinking_mode
DeepSeek documents that, when a thinking-mode response performs a tool call, the assistant's
reasoning_contentmust be passed back in subsequent requests; otherwise the API returns HTTP 400.Suggested mapping or implementation notes
OpenCodex already has reasoning replay handling for the ordinary OpenCode Go DeepSeek tool-call path and for the web-search loop. The remaining intermittent failure likely occurs in another history transformation path; this is a hypothesis, not a confirmed root cause.
A robust fix would:
preserveReasoningContentModels.tool_callsthat originally had non-empty reasoning must still have non-emptyreasoning_content.Suggested regression coverage:
Additional context and attachments
Related implementation history appears to include #78 for normal OpenCode Go DeepSeek tool-call replay and #688 for web-search raw-reasoning replay. #875 concerns the official DeepSeek native Responses route and appears to be a separate integration path.
Observed environment:
opencode-go/deepseek-v4-flash;max;A local diagnostic prototype previously exercised the proposed invariant and completed focused tests, type checking, privacy checks, and the full test suite (7,658 passing, 8 skipped, 0 failing). That prototype was reverted; this issue does not depend on any local patch.
Checks