openclaw - 💡(How to fix) Fix Bug: DeepSeek V4 Flash Free via OpenCode Zen provider fails with 400 on follow-up API calls (reasoning_content stripped) [1 pull requests]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Error Message

400 Error from provider (DeepSeek): "stopReason": "error", "errorMessage": "400 Error from provider (DeepSeek): The reasoning_content in the thinking mode must be passed back to the API.",

Fix Action

Fixed

Code Example

400 Error from provider (DeepSeek):
The `reasoning_content` in the thinking mode must be passed back to the API.

---

{
  "type": "message",
  "message": {
    "role": "assistant",
    "content": [],
    "api": "openai-completions",
    "provider": "opencode",
    "model": "deepseek-v4-flash-free",
    "stopReason": "error",
    "errorMessage": "400 Error from provider (DeepSeek): The `reasoning_content` in the thinking mode must be passed back to the API.",
    "errorCode": "invalid_request_error",
    "errorType": "invalid_request_error"
  }
}

---

const isDeepSeek = endpointClass === "deepseek-native" || 
                   isDefaultRoute && isDefaultRouteProvider(input.provider, "deepseek");

---

const REASONING_CONTENT_REPLAY_MODEL_IDS = new Set([
    "deepseek-v4-flash",         // 不含 -free 后缀
    "deepseek-v4-pro",
    "kimi-for-coding",
    "kimi-k2.5",
    "kimi-k2.6",
    "kimi-k2-thinking",
    "kimi-k2-thinking-turbo",
    "mimo-v2-pro",
    "mimo-v2-omni",
    "mimo-v2.5",
    "mimo-v2.5-pro",
    "mimo-v2.6-pro"
]);

---

api.registerProvider({
    id: "opencode",
    ...
    // 缺少 wrapStreamFn
});

---

wrapStreamFn: (ctx) => createOpencodeGoWrapper(ctx.streamFn, ctx.thinkingLevel),

---

function isOpencodeGoDeepSeekV4ModelId(modelId) {
    return modelId === "deepseek-v4-flash" || modelId === "deepseek-v4-pro";
}

---

const REASONING_CONTENT_REPLAY_MODEL_IDS = new Set([
    "deepseek-v4-flash",
+   "deepseek-v4-flash-free",
    "deepseek-v4-pro",

---

{
  "opencode": {
    "baseUrl": "https://opencode.ai/zen/v1",
    "api": "openai-completions",
    "apiKey": "***",
    "models": [
      { "id": "deepseek-v4-flash-free", "reasoning": true, ... }
    ]
  }
}
RAW_BUFFERClick to expand / collapse

Bug Report: DeepSeek V4 Flash Free via OpenCode Zen provider 会话卡死

OpenClaw 版本: 2026.5.22 (a374c3a)
运行环境: WSL2 (Ubuntu 24.04), Node.js v22.22.2
OpenCode API: https://opencode.ai/zen/v1


问题描述

通过 OpenCode Zen provider 使用 deepseek-v4-flash-free 模型时,首次对话正常,但只要模型发起 tool call 并需要第二次 API 调用时,OpenClaw 就会收到 400 错误,会话卡死在 "in progress" 状态,仅能通过重置会话恢复。

错误信息:

400 Error from provider (DeepSeek):
The `reasoning_content` in the thinking mode must be passed back to the API.

复现步骤

  1. 配置 OpenCode Zen provider,使用 deepseek-v4-flash-free 模型(reasoning: true)
  2. 发送一条需要 tool call 的消息(如 "今天天气怎么样")
  3. 模型第一次响应正常,返回 thinking + tool_calls
  4. tool 执行完毕后,OpenClaw 将 tool 结果发回给 API 发起第二次调用
  5. 第二次 API 调用返回 400 错误 → 会话卡死

会话日志中的完整错误

{
  "type": "message",
  "message": {
    "role": "assistant",
    "content": [],
    "api": "openai-completions",
    "provider": "opencode",
    "model": "deepseek-v4-flash-free",
    "stopReason": "error",
    "errorMessage": "400 Error from provider (DeepSeek): The `reasoning_content` in the thinking mode must be passed back to the API.",
    "errorCode": "invalid_request_error",
    "errorType": "invalid_request_error"
  }
}

根因分析

涉及 4 处代码问题,它们叠加导致了这个 bug:

问题一:isDeepSeek 检测不匹配 OpenCode 路由

文件: dist/provider-model-compat-CmPOKTzc.js (第 12 行)

const isDeepSeek = endpointClass === "deepseek-native" || 
                   isDefaultRoute && isDefaultRouteProvider(input.provider, "deepseek");

通过 opencode.ai 访问 DeepSeek 时,端点类型为 "opencode-native"(不是 "deepseek-native"),provider 名为 "opencode"(不是 "deepseek")。因此 isDeepSeek = false,导致:

  • 第 25 行: thinkingFormat 被设为 "openai" 而非 "deepseek"
  • 第 28 行: requiresReasoningContentOnAssistantMessages 被设为 false

问题二:reasoning_content 被错误地剥离

文件: dist/openai-transport-stream-Pgx5hpN7.js (第 3650-3680 行)

shouldPreserveReasoningContentReplay() 因上述原因返回 false,导致 sanitizeCompletionsReasoningReplayFields() 在构建后续 API 请求时删除了 assistant 消息中的 reasoning_content 字段。但 DeepSeek V4 的 API 在 thinking mode 下要求保留 reasoning_content

问题三:deepseek-v4-flash-free 不在回放白名单中

文件: dist/openai-transport-stream-Pgx5hpN7.js (第 3625-3642 行)

const REASONING_CONTENT_REPLAY_MODEL_IDS = new Set([
    "deepseek-v4-flash",         // 不含 -free 后缀
    "deepseek-v4-pro",
    "kimi-for-coding",
    "kimi-k2.5",
    "kimi-k2.6",
    "kimi-k2-thinking",
    "kimi-k2-thinking-turbo",
    "mimo-v2-pro",
    "mimo-v2-omni",
    "mimo-v2.5",
    "mimo-v2.5-pro",
    "mimo-v2.6-pro"
]);

API 返回的模型 ID 是 "deepseek-v4-flash-free"getReasoningContentReplayModelIdCandidates() 提取到 "deepseek-v4-flash-free",但白名单中只有 "deepseek-v4-flash"不含 -free 后缀),导致匹配失败。

问题四:OpenCode Zen 缺少 DeepSeek V4 的 stream wrapper

文件: dist/extensions/opencode/index.js

OpenCode Zen 注册 provider 时没有设置 wrapStreamFn

api.registerProvider({
    id: "opencode",
    ...
    // 缺少 wrapStreamFn
});

而 OpenCode Go(dist/extensions/opencode-go/index.js,第 90 行)有正确实现:

wrapStreamFn: (ctx) => createOpencodeGoWrapper(ctx.streamFn, ctx.thinkingLevel),

即使加上 wrapper,createOpencodeGoDeepSeekV4Wrapperdist/stream-DcrKLb1r.js,第 6-7 行)也只匹配不含后缀的 ID

function isOpencodeGoDeepSeekV4ModelId(modelId) {
    return modelId === "deepseek-v4-flash" || modelId === "deepseek-v4-pro";
}

建议修复方案

方案 A(最小改动,推荐)

deepseek-v4-flash-free(及所有 *-free 后缀变体)加入 REASONING_CONTENT_REPLAY_MODEL_IDS 白名单,使 shouldPreserveReasoningContentReplay 返回 true,从而避免 reasoning_content 被剥离。

修改位置:dist/openai-transport-stream-Pgx5hpN7.js 第 3625 行

const REASONING_CONTENT_REPLAY_MODEL_IDS = new Set([
    "deepseek-v4-flash",
+   "deepseek-v4-flash-free",
    "deepseek-v4-pro",

同时建议将匹配方式改为 startsWith 或包含检测,而非严格等于,以适配各种后缀变体。

方案 B(彻底修复)

  1. opencode-native 端点纳入 isDeepSeek 检测,或提供通用机制让代理类端点正确识别下游模型类型
  2. 为 OpenCode Zen provider 添加 wrapStreamFn(与 OpenCode Go 一致)
  3. 使 isOpencodeGoDeepSeekV4ModelId 支持后缀变体

用户侧临时绕过

将默认模型切换为 mimo-v2.5-free(该模型不触发 reasoning_content 回放要求)可正常工作。


补充信息

  • openclaw.json 中 OpenCode provider 配置:
{
  "opencode": {
    "baseUrl": "https://opencode.ai/zen/v1",
    "api": "openai-completions",
    "apiKey": "***",
    "models": [
      { "id": "deepseek-v4-flash-free", "reasoning": true, ... }
    ]
  }
}
  • 模型 ID 在首次 API 响应中返回为 "deepseek-v4-flash"(OpenCode 映射去掉了 -free 后缀),但用户配置中为 "deepseek-v4-flash-free"
  • 首次 API 调用(无历史 assistant 消息)正常,第二次调用(有 reasoning_content 的 assistant 消息)才出错
  • 可通过 ~/.openclaw/agents/main/sessions/ 下的 session JSONL 文件复现完整错误轨迹

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING