Skip to content

[DeepSeek V4] reasoning_content not round-tripped — 400 error on multi-turn tool calls #24190

@ihoooohi

Description

@ihoooohi

Description

When using DeepSeek V4 Pro/Flash (deepseek-v4-pro / deepseek-v4-flash) via the official DeepSeek API or OpenRouter, multi-turn conversations with tool calls fail with a 400 error starting from the second turn. The first turn always works; subsequent turns fail.

Error message:

400 The `reasoning_content` in the thinking mode must be passed back to the API.

Full error payload:

{
  "error": {
    "message": "The `reasoning_content` in the thinking mode must be passed back to the API.",
    "type": "invalid_request_error",
    "param": null,
    "code": "invalid_request_error"
  }
}

When it happens:

  • Interrupted and resumed sessions
  • Subagent / Task tool invocations
  • Any scenario where the conversation history includes an assistant message with tool_calls from a prior turn

Root Cause

DeepSeek V4 enables thinking mode by default. Each assistant response includes a reasoning_content field alongside content and optionally tool_calls. Per the DeepSeek Thinking Mode documentation:

Between two user messages, if the model performed a tool call, the intermediate assistant's reasoning_content must participate in the context concatenation and must be passed back to the API in all subsequent user interaction turns.

OpenCode's provider layer currently strips reasoning_content when constructing message history for subsequent API requests. This means:

  1. Turn 1: User → API → Assistant responds with reasoning_content + tool_calls → ✅ Works
  2. Turn 2: OpenCode sends history to API but assistant message missing reasoning_content → ❌ 400 error
  3. All subsequent turns fail the same way

This is the same bug that has affected multiple AI coding tools with the V4 release (Kilo Code, OpenClaude, Hermes Agent, Roo Code, etc.) — nearly all of them have published fixes or PRs within the last 24 hours.

Steps to reproduce

  1. Configure OpenCode with DeepSeek provider / OpenRouter using deepseek-v4-pro or deepseek-v4-flash
  2. Start a conversation and send a prompt that triggers a tool call (e.g., "search for X" or "read file Y")
  3. The first turn completes successfully (tool executes, result returned)
  4. Send a follow-up message in the same session → 400 error

Consistently reproducible. Simple chat without tools works fine because no reasoning_content requirement is triggered.

Expected behavior

OpenCode should preserve reasoning_content on assistant messages in the request history when using DeepSeek V4 models. The field should be echoed back verbatim on every assistant message that originally contained it (or empty string for turns without reasoning).

Suggested fix direction

Based on similar fixes in other projects (e.g., gitlawb/openclaude#878):

  1. Detect when the model is a DeepSeek V4 series (by model name prefix or base URL containing deepseek.com)
  2. Capture reasoning_content from each streaming/non-streaming assistant response
  3. Re-attach it to the corresponding assistant message when building the request history for subsequent API calls
  4. This should be gated to DeepSeek V4 only to avoid affecting OpenAI / Anthropic / other providers

Additional context

  • This affects both the official DeepSeek API (api.deepseek.com) and OpenRouter using DeepSeek V4 models
  • Legacy DeepSeek models (deepseek-chat, deepseek-reasoner) are NOT affected — they use the opposite rule (do NOT pass back reasoning)
  • Simple chat (no tools) works because no reasoning_content round-trip requirement is triggered

Plugins

No response

OpenCode version

1.14.24

Steps to reproduce

See "Steps to reproduce" section above.

Screenshot and/or share link

No response

Operating System

macOS

Terminal

kitty / VS Code terminal

Metadata

Metadata

Assignees

Labels

coreAnything pertaining to core functionality of the application (opencode server stuff)

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions