Skip to content

fix(antigravity): preserve thinking blocks in message converter#253

Closed
codewithkenzo wants to merge 6 commits into
code-yeongyu:devfrom
codewithkenzo:fix/preserve-thinking-blocks-in-message-converter
Closed

fix(antigravity): preserve thinking blocks in message converter#253
codewithkenzo wants to merge 6 commits into
code-yeongyu:devfrom
codewithkenzo:fix/preserve-thinking-blocks-in-message-converter

Conversation

@codewithkenzo

@codewithkenzo codewithkenzo commented Dec 25, 2025

Copy link
Copy Markdown

Summary

Fix thinking block handling in Antigravity message converter.

Problem

When using Claude models with extended thinking through Antigravity, thinking blocks (type: "thinking" or type: "redacted_thinking") were being dropped during OpenAI→Gemini message conversion.

Fix

  • Added thought?: boolean to GeminiPart interface
  • Added handling for thinking and redacted_thinking content types in convertContentToParts()
  • Converts to Gemini's thought: true format with text content

Note

There's a separate upstream issue where OpenCode doesn't preserve thinking block signatures in message history, causing multi-turn conversations to fail. That's tracked in anomalyco/opencode#6176 and needs to be fixed in OpenCode itself.

When using Claude extended thinking models (e.g., claude-opus-4-5-thinking)
through Antigravity, thinking and redacted_thinking blocks in assistant
message content arrays were being stripped during OpenAI→Gemini conversion.

This caused 'messages.X.content.0.type: Expected thinking or redacted_thinking,
but found text' errors when the API expected thinking blocks to be preserved.

Changes:
- Add thought property to GeminiPart interface
- Handle thinking/redacted_thinking content types in convertContentToParts
- Convert to Gemini thought format with thought=true flag
@github-actions

github-actions Bot commented Dec 25, 2025

Copy link
Copy Markdown
Contributor

All contributors have signed the CLA. Thank you! ✅
Posted by the CLA Assistant Lite bot.

@greptile-apps

greptile-apps Bot commented Dec 25, 2025

Copy link
Copy Markdown

Greptile Summary

This PR fixes a critical bug in the Antigravity message converter that caused API errors when using Claude extended thinking models through the proxy.

Key Changes:

  • Added thought?: boolean property to GeminiPart interface to support Gemini's thinking block format
  • Extended convertContentToParts() to handle thinking and redacted_thinking content types from Anthropic responses
  • Preserves thinking blocks by converting them to Gemini format with thought: true flag

Root Cause Fixed:
Previously, when assistant messages contained thinking blocks from Claude responses (using models like claude-opus-4-5-thinking), these blocks were silently dropped during OpenAI→Gemini conversion. This caused Anthropic API to reject requests with: "Expected thinking or redacted_thinking, but found text. When thinking is enabled, a final assistant message must start with a thinking block."

The fix properly extracts thinking content from part.thinking (Anthropic format) with fallback to part.text, then converts to Gemini's thought format.

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk - it fixes a critical bug with a focused, well-scoped change
  • The change is minimal (3 lines of interface modification + 5 lines of logic), addresses a specific API compatibility issue, follows existing patterns in the codebase (similar handling exists in src/tools/session-manager/utils.ts and src/auth/antigravity/thinking.ts), and includes proper fallback logic. The fix directly resolves the reported error without introducing side effects.
  • No files require special attention

Important Files Changed

Filename Overview
src/auth/antigravity/message-converter.ts Added support for thinking and redacted_thinking content types by adding thought property to GeminiPart interface and handling these types in convertContentToParts function

Sequence Diagram

sequenceDiagram
    participant Client
    participant Antigravity
    participant MessageConverter
    participant AnthropicAPI

    Client->>Antigravity: POST /chat (OpenAI format)
    Note over Client: model: claude-opus-4-5-thinking<br/>messages with thinking blocks
    
    Antigravity->>MessageConverter: convertOpenAIToGemini(messages)
    
    Note over MessageConverter: Process each message
    
    loop For each message
        alt Message role: assistant
            MessageConverter->>MessageConverter: convertContentToParts(content)
            
            loop For each content part
                alt part.type === "text"
                    MessageConverter->>MessageConverter: Add {text: part.text}
                else part.type === "thinking" or "redacted_thinking"
                    MessageConverter->>MessageConverter: Add {thought: true, text: part.thinking || part.text}
                else part.type === "image_url"
                    MessageConverter->>MessageConverter: Add {inlineData: {...}}
                end
            end
        end
    end
    
    MessageConverter-->>Antigravity: Gemini contents format
    Note over Antigravity: contents with thought parts
    
    Antigravity->>AnthropicAPI: POST /messages (Anthropic format)
    Note over AnthropicAPI: Validates thinking blocks present<br/>in assistant message
    
    AnthropicAPI-->>Antigravity: Success response
    Antigravity-->>Client: OpenAI-compatible response
Loading

@greptile-apps

greptile-apps Bot commented Dec 25, 2025

Copy link
Copy Markdown

Greptile found no issues!

From now on, if a review finishes and we haven't found any issues, we will not post anything, but you can confirm that we reviewed your changes in the status check section.

This feature can be toggled off in your Code Review Settings by deselecting "Create a status check for each PR".

@codewithkenzo

Copy link
Copy Markdown
Author

I have read the CLA Document and I hereby sign the CLA

github-actions Bot added a commit that referenced this pull request Dec 25, 2025
When converting thinking blocks from OpenAI to Gemini format:
- Extract and preserve signature from various field names
  (signature, thoughtSignature, thought_signature)
- Skip unsigned thinking blocks from history to avoid Claude API error:
  'assistant message must start with a thinking block'
- Claude requires valid signatures on all thinking blocks in multi-turn
  conversations, unsigned blocks cause 400 errors
kenzo added 3 commits December 26, 2025 01:48
When Claude thinking models are used with conversation history,
OpenCode doesn't preserve thinking block signatures. This causes
Claude API to reject requests with error:
'assistant message must start with a thinking block'

This fix detects Claude thinking models with history and strips
the thinking configuration to prevent the error.

Relates to: anomalyco/opencode#6176
@codewithkenzo

Copy link
Copy Markdown
Author

Closing in favor of a more comprehensive fix that addresses the complete signature flow issue.

@codewithkenzo codewithkenzo deleted the fix/preserve-thinking-blocks-in-message-converter branch January 5, 2026 18:56
codewithkenzo pushed a commit to codewithkenzo/oh-my-opencode that referenced this pull request Jan 9, 2026
sssgun pushed a commit to sssgun/oh-my-opencode that referenced this pull request Jan 18, 2026
Rolloniel pushed a commit to Rolloniel/oh-my-opencode that referenced this pull request Feb 22, 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.

1 participant