Skip to content

fix(opencode): ensure DeepSeek reasoning_content round-trips for all interleaved variants#25110

Open
nahoskins wants to merge 2 commits intoanomalyco:devfrom
nahoskins:fix/deepseek-reasoning-content-roundtrip
Open

fix(opencode): ensure DeepSeek reasoning_content round-trips for all interleaved variants#25110
nahoskins wants to merge 2 commits intoanomalyco:devfrom
nahoskins:fix/deepseek-reasoning-content-roundtrip

Conversation

@nahoskins
Copy link
Copy Markdown

@nahoskins nahoskins commented Apr 30, 2026

Issue for this PR

Closes #24722

Type of change

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

What does this PR do?

DeepSeek requires reasoning_content to be passed back on all assistant messages in multi-turn conversations, especially those with tool calls. Without it, the API returns a 400 error.

The existing interleaved reasoning extraction only ran when model.capabilities.interleaved was { field: "reasoning_content" }. But some DeepSeek model definitions have interleaved: true (boolean) or no interleaved field. In those cases reasoning stayed in content and the AI SDK may not properly round-trip it in tool-call scenarios.

This adds a fallback: any DeepSeek model on @ai-sdk/openai-compatible always gets reasoning extracted from content and placed in providerOptions.openaiCompatible.reasoning_content.

How did you verify your code works?

  • Added 4 new test cases: multi-turn tool calls, empty reasoning, boolean interleaved, missing interleaved
  • All 144 existing transform tests continue to pass
  • bun typecheck across all 19 packages passes
  • Built and smoke-tested on darwin-arm64

Screenshots / recordings

N/A

Checklist

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

…interleaved variants

DeepSeek requires reasoning_content to be passed back on all assistant
messages in multi-turn conversations, especially those with tool calls.
The existing interleaved extraction only ran when the model capability
was explicitly { field: "reasoning_content" }, but some DeepSeek model
definitions have interleaved: true (boolean) or no interleaved field at
all. In those cases reasoning stayed in the content array where the AI
SDK may not properly round-trip it in tool-call scenarios.

This adds a fallback check: any DeepSeek model on @ai-sdk/openai-compatible
always gets reasoning extracted from content and placed in
providerOptions.openaiCompatible.reasoning_content.

Closes anomalyco#24722, anomalyco#25000
@github-actions github-actions Bot added the needs:compliance This means the issue will auto-close after 2 hours. label Apr 30, 2026
@github-actions
Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

Based on the search results, I found a potentially related PR:

PR #24443: fix(provider): preserve reasoning_content on second interleaved pass (#24146 follow-up)

This PR appears closely related as it also deals with preserving reasoning_content in multi-turn conversations with interleaved reasoning, which is the core issue being addressed in PR #25110.

The current PR (25110) specifically targets ensuring DeepSeek reasoning_content round-trips for all interleaved variants, while PR #24443 focused on preserving reasoning_content on subsequent interleaved passes. They may be addressing related or overlapping issues in the same area.

@github-actions github-actions Bot removed the needs:compliance This means the issue will auto-close after 2 hours. label Apr 30, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Thanks for updating your PR! It now meets our contributing guidelines. 👍

@nahoskins
Copy link
Copy Markdown
Author

Relationship to #24443

The bot flagged PR #24443 (fix(provider): preserve reasoning_content on second interleaved pass) as potentially related. I reviewed it and these PRs fix different bugs in the same code path — they are complementary, not overlapping:

Scenario #24443 fixes #25110 fixes
interleaved: true (boolean, not object)
interleaved field missing entirely
Second-pass overwrite of providerOptions

What #24443 does: When the transform runs a second time on the same messages (e.g. retry, middleware re-run), reasoning has already been extracted from content on the first pass. On the second pass reasoningText is empty, which overwrites the previously-correct providerOptions.reasoning_content with "". It fixes this by falling back to the existing providerOptions value before defaulting to empty.

What #25110 does: When a DeepSeek model has interleaved: true (boolean) or no interleaved field at all, the interleaved extraction block never runs — reasoning stays in the content array where the AI SDK may not properly round-trip it in tool-call scenarios. This adds a fallback so any DeepSeek model on @ai-sdk/openai-compatible always gets reasoning extracted to providerOptions.

Both fixes touch the same region of transform.ts so there may be a minor merge conflict if both land independently. Happy to rebase if needed.

@rekram1-node
Copy link
Copy Markdown
Collaborator

This pr does nothing for 25000

@nahoskins
Copy link
Copy Markdown
Author

Good catch — you're right, #25000 is about the zen/go proxy side, not the SDK transform this PR touches. Updated the PR to only close #24722.

The proxy-side fix you mentioned (injecting reasoning_content: "" into streams) sounds like the right approach for #25000. DeepSeek's all-or-nothing semantics means the proxy needs to ensure consistency there.

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.

DeepSeek thinking mode: reasoning_content not passed back for tool call turns, causing 400 errors

2 participants