Skip to content

fix(cli,gateway): fully preserve DeepSeek reasoning_content across tool calls#9502

Draft
scottnzuk wants to merge 5 commits intoKilo-Org:mainfrom
scottnzuk:fix/deepseek-reasoning-complete
Draft

fix(cli,gateway): fully preserve DeepSeek reasoning_content across tool calls#9502
scottnzuk wants to merge 5 commits intoKilo-Org:mainfrom
scottnzuk:fix/deepseek-reasoning-complete

Conversation

@scottnzuk
Copy link
Copy Markdown

Context

The reasoning_content fix from PR #9470 was incomplete. Three additional layers needed: gateway extractReasoning, dynamic SDK key for OpenRouter, and unconditional injection for historical messages. This PR applies the complete fix matching upstream anomalyco/opencode#24250.

Fixes #9501 - DeepSeek reasoning_content error in multi-turn tool call conversations.

Implementation

Layer 1: Gateway extractReasoning

  • Added extractReasoning: true to gateway's createOpenAI() and createOpenAICompatible() calls
  • Enables Vercel AI SDK to create structured reasoning content parts

Layer 2: Transform Logic Updates

  • Used existing sdkKey() for dynamic providerOptions key selection in interleaved block
  • Added unconditional fallback block injecting empty reasoning_content for all assistant messages on reasoning models
  • Handles historical messages saved before the fix and tool-only responses

Layer 3: Auto-Enable Interleaved

  • Modified capability assembly in provider.ts to auto-enable interleaved for reasoning models
  • Ensures ANY model with reasoning: true gets the interleaved treatment

Layer 4: Comprehensive Testing

  • Added 4 new tests covering OpenRouter dynamic key, historical messages, auto-interleaved, and regression protection
  • All existing tests still pass (153/153)

Screenshots

N/A (no UI changes)

How to Test

Use a DeepSeek model with thinking mode, trigger a tool call (e.g., ask it to run a bash command), then send a follow-up message. Both turns should succeed without 400 errors.

Verify with both OpenRouter and native DeepSeek provider paths.

Files Changed

  • packages/kilo-gateway/src/provider.ts - Added extractReasoning flags
  • packages/opencode/src/provider/transform.ts - Dynamic SDK key + unconditional fallback
  • packages/opencode/src/provider/provider.ts - Auto-enable interleaved for reasoning models
  • packages/opencode/test/provider/transform.test.ts - Added comprehensive tests
  • .changeset/deepseek-reasoning-complete.md - Release notes

Testing Results

  • ✅ 153/153 tests pass in transform.test.ts
  • bun turbo typecheck passes across all packages
  • ✅ No spurious kilocode_change markers
  • ✅ No opencode annotation issues

Get in Touch

Questions about the implementation or testing scenarios.

…ol calls

Apply complete fix for DeepSeek reasoning_content 400 errors in multi-turn
tool call conversations. Addresses four interconnected root causes:

- Layer 1: Add extractReasoning: true to gateway provider creation
- Layer 2: Dynamic SDK key selection and unconditional reasoning_content injection
- Layer 3: Auto-enable interleaved capability for reasoning models
- Layer 4: Comprehensive test coverage for all provider paths

Fixes issues with OpenRouter, native DeepSeek API, and custom OpenAI-compatible
providers. Ensures backward compatibility with historical messages and seamless
multi-turn conversations.

Closes Kilo-Org#9471, Kilo-Org#9482
Related upstream: anomalyco/opencode#24250
Comment thread packages/opencode/src/provider/provider.ts Outdated
Comment thread packages/opencode/src/provider/transform.ts Outdated
@kilo-code-bot
Copy link
Copy Markdown
Contributor

kilo-code-bot Bot commented Apr 25, 2026

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (5 files)
  • .changeset/deepseek-reasoning-complete.md
  • packages/kilo-gateway/src/provider.ts
  • packages/opencode/src/provider/provider.ts
  • packages/opencode/src/provider/transform.ts
  • packages/opencode/test/provider/transform.test.ts

Reviewed by gpt-5.4-2026-03-05 · 529,365 tokens

- Make interleaved auto-enablement specific to DeepSeek models only
- Fix interleaved block to handle string content assistant messages
- Add test for string content message handling
- Ensure no early return prevents fallback processing
@scottnzuk
Copy link
Copy Markdown
Author

✅ Code Review Issues Addressed

I've fixed both issues identified by the code review:

Issue 1: Auto-enabling interleaved for all reasoning models

Fixed: Made the auto-enablement specific to DeepSeek models only by checking instead of applying to all reasoning models. This prevents incorrect handling for providers that don't use this field format.

Issue 2: Early return skipping string content handling

Fixed: Removed the early return in the interleaved block and modified it to handle both array and string content messages. Now assistant messages with string content (not just array content) get proper injection when they don't already have it.

Additional Changes:

  • Added comprehensive test for string content message handling
  • Fixed TypeScript errors in the auto-enablement logic
  • All tests pass (154/154) and type checking succeeds

The fixes ensure that only DeepSeek models get the interleaved auto-enablement, and all assistant message types (array and string content) are properly handled for reasoning content injection.

@scottnzuk
Copy link
Copy Markdown
Author

✅ Code Review Issues Addressed

I've fixed both issues identified by the code review:

Issue 1: Auto-enabling interleaved for all reasoning models

Fixed: Made the auto-enablement specific to DeepSeek models only by checking model.id.includes('deepseek') instead of applying to all reasoning models. This prevents incorrect reasoning_content handling for providers that don't use this field format.

Issue 2: Early return skipping string content handling

Fixed: Removed the early return in the interleaved block and modified it to handle both array and string content messages. Now assistant messages with string content (not just array content) get proper reasoning_content injection when they don't already have it.

Additional Changes:

  • Added comprehensive test for string content message handling
  • Fixed TypeScript errors in the auto-enablement logic
  • All tests pass (154/154) and type checking succeeds

The fixes ensure that only DeepSeek models get the interleaved auto-enablement, and all assistant message types (array and string content) are properly handled for reasoning content injection.

@scottnzuk
Copy link
Copy Markdown
Author

📊 Updated Testing Results

Updated the testing results in the PR description:

  • 154/154 tests pass in transform.test.ts (was 153/153)
  • ✅ • Packages in scope: @kilocode/cli, @kilocode/kilo-docs, @kilocode/kilo-gateway, @kilocode/kilo-i18n, @kilocode/kilo-jetbrains, @kilocode/kilo-telemetry, @kilocode/kilo-ui, @kilocode/plugin, @kilocode/sdk, @opencode-ai/app, @opencode-ai/desktop, @opencode-ai/desktop-electron, @opencode-ai/script, @opencode-ai/shared, @opencode-ai/storybook, @opencode-ai/ui, kilo-code
    • Running typecheck in 17 packages
    • Remote caching disabled
    @kilocode/kilo-i18n:typecheck: cache hit, replaying logs db03c9f323690b0c
    @opencode-ai/shared:typecheck: cache hit, replaying logs fc2b76b2d5b75a34
    @kilocode/sdk:typecheck: cache hit, replaying logs 2f4d466616f4c6a1
    @kilocode/kilo-i18n:typecheck: $ tsgo --noEmit
    @opencode-ai/shared:typecheck: $ tsgo --noEmit
    @kilocode/sdk:typecheck: $ tsgo --noEmit
    @kilocode/plugin:typecheck: cache hit, replaying logs 338fe6f83792cbfd
    @kilocode/plugin:typecheck: $ tsgo --noEmit
    @opencode-ai/ui:typecheck: cache hit, replaying logs 8fd867f86f2e6608
    @opencode-ai/ui:typecheck: $ tsgo --noEmit
    @kilocode/kilo-gateway:typecheck: cache hit, replaying logs 2e57b4b2fda8189a
    @kilocode/kilo-gateway:typecheck: $ tsgo --noEmit
    @opencode-ai/app:typecheck: cache miss, executing cff9fc37e8c3b695
    kilo-code:typecheck: cache miss, executing 5fe1aab7af98f966
    @kilocode/kilo-telemetry:typecheck: cache hit, replaying logs ffcddaca397e3cc5
    @kilocode/kilo-telemetry:typecheck: $ tsgo --noEmit
    @kilocode/cli:typecheck: cache miss, executing b7e7d2e218ead293
    @opencode-ai/app:typecheck: $ tsgo -b
    @kilocode/cli:typecheck: $ tsgo --noEmit
    kilo-code:typecheck: $ bun run check-types:extension && bun run check-types:webview
    kilo-code:typecheck: $ bun script/typecheck.ts
    @opencode-ai/desktop:typecheck: cache miss, executing d3aff5a1b72466f2
    @opencode-ai/desktop-electron:typecheck: cache miss, executing e282aa0d53c73485
    @opencode-ai/desktop:typecheck: $ tsgo -b
    @opencode-ai/desktop-electron:typecheck: $ tsgo -b
    kilo-code:typecheck: $ bun script/typecheck.ts --project webview-ui/tsconfig.json

Tasks: 12 successful, 12 total
Cached: 7 cached, 12 total
Time: 11.877s passes across all packages

  • ✅ No spurious kilocode_change markers
  • ✅ No opencode annotation issues

The additional test covers string content message handling that was added to address the code review feedback.

@scottnzuk
Copy link
Copy Markdown
Author

@kilocode-bot anything else needed from me?

@scottnzuk scottnzuk marked this pull request as draft April 25, 2026 18:54
Resolves DeepSeek reasoning_content API error by ensuring the Vercel AI SDK
includes reasoning content in requests for reasoning models when using
OpenAI-compatible providers.

Fixes: The 'reasoning_content in the thinking mode must be passed back to the API' error
that occurred on the 9th+ assistant message in sessions with DeepSeek reasoning models.

This change adds the extractReasoning: true option to provider options when:
- The model has reasoning capability (model.capabilities.reasoning === true)
- The extractReasoning option is not already explicitly set

The fix mirrors what was already implemented in the Kilo Gateway provider
but was missing from the CLI's direct provider creation for bundled SDKs.,
@scottnzuk
Copy link
Copy Markdown
Author

Well after 3 revisions, endless token use and testing, still can't get to the bottom of this.. if anyone else wants to review this and see if I'm on the right track, and/or fix it, that would be amazing.

For now, my fix is: when the error shows up, swap from Deepseek-V4 Flash to Deepseek-Chat. Oddly enough, they are actually both the same DeepSeek pass and API calls to chat to the new flash. But it allows me to skip over the error and carry on.

ugh lol

@edulml98
Copy link
Copy Markdown

edulml98 commented Apr 26, 2026

Issue is related to openrouter OpenRouterTeam/ai-sdk-provider#487
edit: bump the ai-sdk-provider to the latest version and test again

@scottnzuk
Copy link
Copy Markdown
Author

Issue is related to openrouter OpenRouterTeam/ai-sdk-provider#487 edit: bump the ai-sdk-provider to the latest version and test again

that would be correct for kilo version but i use direct api that or is that using open router back end as well?

@babang1da
Copy link
Copy Markdown

please fix it

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 reasoning_content error in multi-turn tool call conversations

3 participants