Skip to content

fix deepseek v4 reasoning content problem in thinking mode#1

Closed
wya-tt wants to merge 1 commit intopanyw5:devfrom
wya-tt:dev
Closed

fix deepseek v4 reasoning content problem in thinking mode#1
wya-tt wants to merge 1 commit intopanyw5:devfrom
wya-tt:dev

Conversation

@wya-tt
Copy link
Copy Markdown

@wya-tt wya-tt commented Apr 30, 2026

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

This fixes DeepSeek reasoning message handling when assistant messages include tool calls. The changes is made by Cursor with GPT 5.5, based on the official update of OpenCode.

DeepSeek-compatible models can require reasoning_content to be sent back in provider options on later requests, including when the reasoning content is empty. Previously the transform could drop that field, which breaks follow-up tool-call flows.

The change preserves existing reasoning_content, keeps empty reasoning content instead of omitting it, and defaults reasoning-capable models to use reasoning_content when no explicit interleaved field is configured.

How did you verify your code works?

Added regression tests for DeepSeek provider transforms covering:

  • assistant messages with reasoning and tool calls
  • empty reasoning_content
  • repeated transform calls preserving existing reasoning content
  • reasoning models without explicit interleaved config

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

panyw5 added a commit that referenced this pull request May 1, 2026
Cherry-pick the targeted DeepSeek interleaved-default tweak from upstream
opencode (sst#24630, commit 738b306) and apply a properly scoped
version of the empty-content preserving fix from #1.

provider.ts (custom-provider parser only):
- Default `interleaved` to { field: "reasoning_content" } only for
  brand-new openai-compatible providers whose api id contains
  "deepseek". Existing user/source config still wins via the ?? chain.
  fromModelsDevModel is intentionally left alone — models.dev already
  carries the explicit interleaved config for DeepSeek there.

transform.ts (the existing interleaved branch):
- Switch the providerOptions namespace from hard-coded
  "openaiCompatible" to sdkKey(model.api.npm) ?? "openaiCompatible"
  so providers wired through other AI SDKs land in the right slot.
- Always emit the field (even when reasoningText is empty) so
  DeepSeek's follow-up tool-call requests stop 400-ing, and preserve
  any existing reasoning_content across re-transforms instead of
  overwriting with "".

Deliberately does NOT add a fallback `if (model.capabilities.reasoning)`
branch — that would inject reasoning_content into providerOptions for
OpenAI o1/o3, Claude reasoning, Gemini thinking etc., which is not a
valid key for those SDKs.

tests:
- Share a deepseekModel fixture across the DeepSeek tests.
- Add empty-reasoning preservation regression.
- Add re-transform existing-reasoning preservation regression.
- Add reverse guard: OpenAI o1 (reasoning=true, interleaved=false) must
  NOT pick up reasoning_content in providerOptions.

Supersedes #1 (that PR's broader scope would affect non-DeepSeek
reasoning providers).
Copy link
Copy Markdown
Owner

@panyw5 panyw5 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

谢谢提交。Bug 抓得对,patch 大方向也对,但作用域太宽。已在 dev (commit f5d2963) 落了一个收窄版。

采用了原 PR 的

  • transform.ts 把硬编码的 "openaiCompatible" 换成 sdkKey(model.api.npm) ?? "openaiCompatible"
  • transform.ts 总是写 [field](即使为空字符串)+ 跨 transform 用 || 链保留已有 reasoning_content——核心 bug fix
  • 测试 fixture 重构(共享 deepseekModel)+ 空 reasoning / 重复 transform 两个回归测试

没有采用的

  • provider.tsinterleaved 兜底到所有 model.reasoning === true 的模型——会把 DeepSeek 专属字段套到 OpenAI o1/o3、Claude reasoning、Gemini thinking 上,污染它们的 providerOptions
  • transform.ts 新增的 if (model.capabilities.reasoning) { … } 分支——同上,且会硬编码 reasoning_content 字段名,无视 interleaved.field 配置

改用 upstream 的设计

provider.tsinterleaved 默认值改为 anomalyco#24630(commit 738b3065d)的写法,三重门控:

interleaved:
  model.interleaved ??
  existingModel?.capabilities.interleaved ??
  (!existingModel && apiNpm === "@ai-sdk/openai-compatible" && apiID.toLowerCase().includes("deepseek")
    ? { field: "reasoning_content" }
    : false),

只对全新 openai-compatible + DeepSeek 命名的模型默认开启,user/source config 仍然优先。fromModelsDevModel 那处不动——models.dev 已经显式给 DeepSeek 配了 interleaved

额外加的

OpenAI o1-mini(reasoning=true, interleaved=false)transform 后不应providerOptions.openai.reasoning_content 的反向 guard,防止之后再有人想往这个方向扩。

@panyw5
Copy link
Copy Markdown
Owner

panyw5 commented May 1, 2026

Close pull request. Thanks.

@panyw5 panyw5 closed this May 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants