-
Notifications
You must be signed in to change notification settings - Fork 9.1k
fix: strip incompatible thinking blocks when switching to Claude #8958
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
fix: strip incompatible thinking blocks when switching to Claude #8958
Conversation
|
The following comment was made by an LLM, it may be inaccurate: Potential Duplicate FoundPR #6748: fix: strip incompatible thinking blocks when switching to Anthropic models Why it's related:
The current PR (#8958) explicitly states it "Supersedes #6748 (similar approach but that PR has been stale)", so you should check if #6748 needs to be closed or if this PR is intended to replace it. |
0980576 to
b498721
Compare
- Convert thinking blocks with signatures to wrapped text (preserves content) - Convert reasoning blocks to wrapped text for Claude - Track converted thinking messages to avoid incorrect removal - Only remove last assistant message if safe (no tool calls, no converted thinking) - Preserve tool_use/tool_result pairing Fixes the 'Invalid signature in thinking block' and 'Expected thinking or redacted_thinking but found text' errors when switching from GLM/MiniMax to Claude with extended thinking mid-session.
0a3c6c9 to
0d7f9e8
Compare
SummaryFixes the The Fix
This preserves tool_use/tool_result pairing while handling signature validation. Tested
|
00637c0 to
71e0ba2
Compare
f1ae801 to
08fa7f7
Compare
d-init-d
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Detailed Code Review
Thanks for tackling this issue @coleleavitt! The approach is solid - converting incompatible thinking blocks to wrapped text is the right direction. However, I've identified some issues that should be addressed before merging.
🐛 Critical Bugs
1. Devstral support regression (line ~133 in patch)
The original code includes devstral in the Mistral check, but this PR removes it:
// Original:
if (model.providerID === "mistral" || model.api.id.toLowerCase().includes("mistral") || model.api.id.toLocaleLowerCase().includes("devstral"))
// PR:
if (model.providerID === "mistral" || model.api.id.toLowerCase().includes("mistral"))This will break devstral model support!
2. Inconsistent tag naming
PR description mentions <assistant_reasoning> for reasoning parts, but code uses <assistant_thinking> for both. This inconsistency makes it harder to distinguish between converted thinking vs reasoning blocks when debugging.
⚠️ Edge Cases Not Handled
3. Empty content array after filtering
After converting and filtering parts with .filter((part: any) => part !== null), msg.content could become []. Claude API rejects empty content arrays with validation errors. Should add a check to filter out messages with empty content:
if (msg.content.length === 0) return undefined
// Then filter undefined messages at the end4. Valid Claude thinking blocks could be incorrectly converted
Currently, ANY thinking block with a signature gets converted. What about valid Claude thinking blocks that have proper Anthropic signatures from a previous Claude turn in the same session?
Consider checking signature format:
const isValidClaudeSignature = part.signature?.startsWith('ErUB')
if (part.type === "thinking" && part.signature && !isValidClaudeSignature) {
// Convert only invalid signatures
}🔧 Suggested Improvements
5. Type safety
Multiple uses of any casts ((part: any), (options as any)) could be replaced with proper types for better maintainability.
6. Extract helper function
The Claude-specific block has grown significantly (from ~10 lines to ~50+ lines). Consider extracting to a dedicated function like normalizeClaudeMessages() for better readability.
7. Missing test cases in thinking-blocks.test.ts
Good test coverage overall, but consider adding:
- Empty thinking text (edge case)
- Multiple thinking blocks in single message
- Valid Claude thinking blocks (should NOT be converted)
- Session with mixed Claude + non-Claude turns
I'm working on an improved PR that addresses these issues. Happy to collaborate if you'd like to incorporate these fixes into your PR instead!
Files reviewed:
packages/opencode/src/provider/transform.ts- Core logic changespackages/opencode/test/provider/thinking-blocks.test.ts- New test filepackages/opencode/test/provider/transform.test.ts- Test expectation update
Fixes anomalyco#6418 ## Problem When switching from models like GLM 4.7 or MiniMax to Claude with extended thinking enabled, users get API errors because other models produce thinking blocks with signatures incompatible with Claude. ## Solution 1. Add `isValidClaudeSignature()` helper to detect valid Claude signatures 2. Extract `normalizeClaudeThinkingBlocks()` for better code organization 3. Convert ONLY invalid signatures - preserve valid Claude thinking blocks 4. Use distinct `<assistant_reasoning>` tags for reasoning blocks 5. Filter out messages with empty content after processing 6. Preserve devstral support in Mistral check ## Improvements over PR anomalyco#8958 - Only converts thinking blocks with INVALID signatures (not all) - Uses distinct tags for thinking vs reasoning - Handles empty content edge case - Better type safety (reduced `any` usage) - Extracted helper function for maintainability - More comprehensive test coverage ## Testing 1. Start session with GLM 4.7 or MiniMax 2. Send messages including tool use 3. Switch to Claude with extended thinking 4. Should no longer get signature errors 5. Tool results still work correctly"
Fixes #6418
Problem
When switching from models like GLM 4.7 or MiniMax to Claude with extended thinking enabled, users get API errors:
or
This happens because:
thinkingblocks with signatures that are incompatible with Claude's signature validationreasoningparts from other models don't have the signature format Claude expectsSolution
In
normalizeMessages(), when the target model is Claude:<assistant_thinking>tags.<assistant_reasoning>tags.This approach preserves tool_use/tool_result pairing while still handling the signature validation issues.
Changes
packages/opencode/src/provider/transform.ts: Added thinking block conversion logic in Claude-specific sectionpackages/opencode/test/provider/thinking-blocks.test.ts: New test file with comprehensive coveragepackages/opencode/test/provider/transform.test.ts: Updated existing test expectationTesting
Related