Skip to content

fix: surface Claude thinking blocks as reasoning_content and fix Gemini reasoning param#145

Merged
SantiagoDePolonia merged 2 commits intomainfrom
feature/claude-thinking-fix
Mar 13, 2026
Merged

fix: surface Claude thinking blocks as reasoning_content and fix Gemini reasoning param#145
SantiagoDePolonia merged 2 commits intomainfrom
feature/claude-thinking-fix

Conversation

@SantiagoDePolonia
Copy link
Copy Markdown
Contributor

@SantiagoDePolonia SantiagoDePolonia commented Mar 13, 2026

Summary

  • Anthropic thinking blocks were silently dropped during response normalization — now surfaced as reasoning_content in both non-streaming and streaming responses (OpenAI SDK compatible)
  • Gemini reasoning param caused 400 errors — now translated from nested reasoning.effort to Gemini's expected top-level reasoning_effort string

What changed

Anthropic provider (internal/providers/anthropic/anthropic.go)

  • anthropicContent and anthropicDelta structs now capture thinking and signature fields
  • Non-streaming: convertFromAnthropicResponse extracts thinking content and sets reasoning_content via ExtraFields
  • Streaming (chat): handles thinking_delta → emits reasoning_content chunks; handles signature_delta → skips silently
  • Streaming (responses): handles thinking/signature blocks gracefully (no Responses API equivalent)
  • extractTextContent refined to skip preamble text blocks before thinking blocks

Gemini provider (internal/providers/gemini/gemini.go)

  • New adaptChatRequest() translates {"reasoning": {"effort": "low"}}{"reasoning_effort": "low"}
  • Applied to both ChatCompletion and StreamChatCompletion

Test plan

  • All unit tests pass (make test)
  • All E2E tests pass (make test-e2e)
  • Lint clean (make lint)
  • Verified non-streaming Claude thinking via curl — reasoning_content present in response
  • Verified streaming Claude thinking via curl — reasoning_content chunks emitted before content
  • Verified OpenAI Python SDK (non-streaming + streaming) — message.reasoning_content accessible
  • Verified OpenAI Node.js SDK (non-streaming + streaming) — message.reasoning_content accessible
  • Verified Gemini with reasoning.effort — no longer returns 400, response is correct

🤖 Generated with Claude Code

Summary by CodeRabbit

New Features

  • Added extended thinking/reasoning support for Anthropic models: responses now surface structured reasoning content and streaming includes reasoning deltas for richer, OpenAI-compatible outputs.
  • Added reasoning effort promotion for Gemini requests: reasoning effort is now exposed and honored in chat requests and streaming.
  • Tests
    • Updated test fixtures to include explicit reasoning_content for validation.

…e Gemini reasoning param

Claude's extended thinking content was silently dropped during Anthropic→OpenAI
normalization. Thinking blocks now flow through as `reasoning_content` in both
non-streaming and streaming responses, matching the format OpenAI SDKs expect.

Gemini's OpenAI-compatible endpoint requires `reasoning_effort` as a top-level
string rather than the nested `reasoning.effort` object — requests now translate
the parameter automatically, fixing 400 errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 13, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: bfe601de-7016-4ddb-b636-6f1251502e02

📥 Commits

Reviewing files that changed from the base of the PR and between bddc7bb and 20ed3fc.

📒 Files selected for processing (1)
  • tests/contract/testdata/golden/anthropic/messages_extended_thinking.golden.json

📝 Walkthrough

Walkthrough

Anthropic provider: added Thinking and Signature fields, tracks thinking blocks in stream converters, extracts and surfaces reasoning_content separately from text in both streaming and batch flows. Gemini provider: adapts chat requests by promoting nested reasoning.Effort to a top-level reasoning_effort field before sending to /chat/completions.

Changes

Cohort / File(s) Summary
Anthropic core + streams
internal/providers/anthropic/anthropic.go
Added Thinking and Signature to anthropicContent and anthropicDelta; added thinkingBlocks maps to streamConverter and responsesStreamConverter; implemented extractThinkingContent and updated extractTextContent; updated event handlers to detect/track thinking blocks and surface reasoning_content; suppressed signature deltas for OpenAI compatibility.
Anthropic tests/golden
tests/contract/testdata/golden/anthropic/messages_extended_thinking.golden.json
Added reasoning_content field to golden output to reflect surfaced extended thinking content.
Gemini request adaptation
internal/providers/gemini/gemini.go
Added adaptChatRequest to promote reasoning.Effort to top-level reasoning_effort; applied adaptation in ChatCompletion and StreamChatCompletion, with marshal/unmarshal error handling producing InvalidRequestError.
Module file
go.mod
Minor dependency changes to accommodate edits (small delta).

Sequence Diagram

sequenceDiagram
    participant Client
    participant StreamConverter as StreamConverter (Anthropic)
    participant ContentService as Content Provider
    participant Extractor as Content Extractor
    participant ExtraFields as ExtraFields (Reasoning)

    Client->>StreamConverter: Receive streaming events
    StreamConverter->>ContentService: content_block_start
    ContentService-->>StreamConverter: block metadata (type: thinking/text)
    StreamConverter->>StreamConverter: mark thinkingBlocks[index] = true

    StreamConverter->>ContentService: content_block_delta
    ContentService-->>StreamConverter: thinking_delta / text_delta / signature_delta

    alt thinking_delta
        StreamConverter->>Extractor: append to thinking buffer
        Extractor-->>ExtraFields: populate reasoning_content
    else signature_delta
        StreamConverter->>StreamConverter: suppress for OpenAI-compatible output
    else text_delta
        StreamConverter->>Extractor: append to text buffer (skip pre-thinking when applicable)
    end

    ExtraFields-->>Client: emit message with `content` and `reasoning_content`
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hopped through code in moonlit thinking,

I tracked each block where ideas were blinking,
Text and thoughts now travel side by side,
Reasoning surfaced, signatures hide,
A little rabbit cheers the wise new binding.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 71.43% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the two main changes: surfacing Claude thinking blocks as reasoning_content and fixing Gemini's reasoning parameter mapping.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/claude-thinking-fix
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

The contract replay test golden file was stale — now includes the
reasoning_content field that the gateway correctly surfaces from
Anthropic thinking blocks.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@SantiagoDePolonia
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 13, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@SantiagoDePolonia
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 13, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@SantiagoDePolonia SantiagoDePolonia merged commit 302f594 into main Mar 13, 2026
13 checks passed
@SantiagoDePolonia SantiagoDePolonia deleted the feature/claude-thinking-fix branch April 4, 2026 11:52
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