Uh oh!
There was an error while loading. Please reload this page.
fix(opencode): support interleaved reasoning_content for anthropic protocol non-Claude models - #14637
fix(opencode): support interleaved reasoning_content for anthropic protocol non-Claude models#14637llc1123 wants to merge 2 commits into
Conversation
…-Claude models Models like kimi-k2.5 on ZenMux use @ai-sdk/anthropic but expect reasoning_content on assistant messages. The SDK requires a signature for thinking blocks which non-Claude models lack. Inject a placeholder signature in transform so the SDK emits thinking blocks, then convert them to reasoning_content in the fetch wrapper at wire level.
There was a problem hiding this comment.
Pull request overview
This PR fixes a bug where non-Claude models (e.g., kimi-k2.5) using the Anthropic SDK with interleaved reasoning fail to correctly round-trip reasoning content from previous assistant messages. The fix implements a two-phase transformation approach: first converting internal reasoning parts to thinking blocks with a placeholder signature (so the Anthropic SDK will serialize them), then intercepting the HTTP request to move those thinking blocks to the top-level reasoning_content/reasoning_details field that the upstream API expects.
Changes:
- Added detection and special handling for Anthropic SDK models with interleaved reasoning capability
- Implemented reasoning-to-thinking-block transformation in transform.ts using a placeholder signature
- Added fetch wrapper in provider.ts to convert thinking blocks back to reasoning_content field in HTTP requests
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
| packages/opencode/src/provider/transform.ts | Adds logic to detect Anthropic protocol models and inject reasoning parts with placeholder signature to trigger thinking block serialization |
| packages/opencode/src/provider/provider.ts | Adds fetch wrapper to intercept HTTP requests and move thinking blocks to top-level reasoning_content/reasoning_details field |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
llc1123
commented
Feb 22, 2026
Addressing Copilot's review comments: 1. JSON.parse try-catch — The existing OpenAI itemId block at L1116 does the same 2 & 3. Empty content after filtering — Assistant messages always contain text or tool-call parts alongside thinking/reasoning blocks. A message with only reasoning and no text/tool-call is not a real state. The early return at L146 ( 4. Reasoning order — Intentional. The Anthropic API expects thinking blocks before text content in a message. 5. Tests — Acknowledged, can be added as a follow-up. 6. Placeholder signature fragility — Already documented in the code comment at L150-151. This is a known trade-off with no better alternative short of patching the SDK. |
Closing this pull request because it has had no updates for more than 60 days. If you plan to continue working on it, feel free to reopen or open a new PR. |
Issue for this PR
Closes#14638
Type of change
What does this PR do?
When non-Claude models (e.g. kimi-k2.5) are used via the Anthropic SDK (
@ai-sdk/anthropic/@ai-sdk/google-vertex/anthropic) withinterleavedreasoning enabled, previous assistant messages containing reasoning content fail to round-trip correctly. The Anthropic SDK doesn't natively support areasoning_contentfield on messages — it only serializesthinkingblocks.This PR fixes it with a two-phase approach:
transform.ts: Converts storedreasoningparts intothinkingblocks with a placeholder signature, so the Anthropic SDK will serialize them into the request body.provider.ts(fetch wrapper): Intercepts the outgoing HTTP request, extracts thethinkingblocks from assistant messages, and moves them to the top-levelreasoning_content(orreasoning_details) field that the upstream API expects.How did you verify your code works?
bun turbo typecheck— all 12 packages green)reasoning_contenton assistant messagesScreenshots / recordings
N/A — no UI changes.
Checklist