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:
- Turn 1: User → API → Assistant responds with
reasoning_content + tool_calls → ✅ Works
- Turn 2: OpenCode sends history to API but assistant message missing
reasoning_content → ❌ 400 error
- 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
- Configure OpenCode with DeepSeek provider / OpenRouter using
deepseek-v4-pro or deepseek-v4-flash
- Start a conversation and send a prompt that triggers a tool call (e.g., "search for X" or "read file Y")
- The first turn completes successfully (tool executes, result returned)
- 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):
- Detect when the model is a DeepSeek V4 series (by model name prefix or base URL containing
deepseek.com)
- Capture
reasoning_content from each streaming/non-streaming assistant response
- Re-attach it to the corresponding assistant message when building the request history for subsequent API calls
- 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
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:
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:
tool_callsfrom a prior turnRoot Cause
DeepSeek V4 enables thinking mode by default. Each assistant response includes a
reasoning_contentfield alongsidecontentand optionallytool_calls. Per the DeepSeek Thinking Mode documentation:OpenCode's provider layer currently strips
reasoning_contentwhen constructing message history for subsequent API requests. This means:reasoning_content+tool_calls→ ✅ Worksreasoning_content→ ❌ 400 errorThis 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
deepseek-v4-proordeepseek-v4-flashConsistently reproducible. Simple chat without tools works fine because no
reasoning_contentrequirement is triggered.Expected behavior
OpenCode should preserve
reasoning_contenton 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):deepseek.com)reasoning_contentfrom each streaming/non-streaming assistant responseAdditional context
api.deepseek.com) and OpenRouter using DeepSeek V4 modelsdeepseek-chat,deepseek-reasoner) are NOT affected — they use the opposite rule (do NOT pass back reasoning)reasoning_contentround-trip requirement is triggeredPlugins
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