Skip to content

[Bug] OpenCode Go DeepSeek V4 Flash intermittently drops reasoning_content on tool-call continuation #950

Description

@mkarolczyk

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

  1. Configure Codex App to use opencode-go/deepseek-v4-flash through OpenCodex 2.10.0.
  2. Enable thinking mode with reasoning effort max.
  3. Start a multi-turn task that causes the model to call tools.
  4. Continue or retry the conversation after tool results; longer runs that resume or compact history reproduce the problem more readily.
  5. 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:

  1. Preserve the original raw reasoning value on the same assistant tool-call turn through resume, retry, compaction, and synthetic-history transformations.
  2. Serialize that value for models covered by preserveReasoningContentModels.
  3. 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.
  4. Avoid generating empty or fabricated reasoning values.
  5. 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

  • I searched existing provider and compatibility issues.
  • The request and response were redacted.
  • The expected behaviour is based on an upstream specification or a concrete client requirement.

Metadata

Metadata

Assignees

Labels

providerProvider adapters, OpenAI-compat presets, upstream API quirksprovider-compatibilityProvider compatibility reportstoolstool_calls, MCP, web-search / sidecar tools

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions