Skip to content

Conversation

@omarluq
Copy link
Owner

@omarluq omarluq commented Feb 11, 2026

No description provided.

Copilot AI review requested due to automatic review settings February 11, 2026 17:51
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 11, 2026

Caution

Review failed

Failed to post review comments

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes

    • Preserves all fields inside "thinking" content blocks, removes outdated signatures from tool-use blocks, and improves block ordering and signature-update reliability.
  • New Features

    • Modular per-block analysis enabling selective in-place signature updates, a slow-path rebuild for structural changes, and consistent non-streaming response handling with signature caching/prefixing.
  • Tests

    • Added tests for client signature priority, drop/reorder behavior, and unknown-field preservation.
  • Chores

    • Updated build/version metadata sourcing and linter module path.

Walkthrough

Adds a modular analysis-and-processing path for assistant content thinking/tool_use blocks: per-block analysis, signature resolution/caching, optional in-place (surgical) signature updates, block dropping/reordering, and non‑streaming handling; updates tests and renames the internal version package to vinfo.

Changes

Cohort / File(s) Summary
Thinking processing
internal/proxy/thinking.go
Adds thinkingBlockResult, blockAnalysis, analyzeContentBlocks, countKeptBlocks, rebuildContent, surgicalUpdate, resolveThinkingSignature, checkReorderNeeded, ProcessResponseSignature utilities; refactors processAssistantContent / collectBlocks to analyze blocks, resolve signatures, choose surgical in-place updates or full rebuild, drop/reorder thinking/tool_use blocks, and preserve unknown thinking fields while removing tool_use signatures.
Tests
internal/proxy/thinking_test.go
Introduces tests and path constants: TestProcessRequestThinkingClientSignatureTakesPriority, TestProcessRequestThinkingDropsAndReordersCorrectly, TestProcessRequestThinkingPreservesUnknownFields; verifies client signature preference, drop/reorder behavior, and preservation of unknown fields.
Version package rename & build flags
internal/vinfo/..., cmd/cc-relay/..., Taskfile.yml, .goreleaser.yaml
Renames package versionvinfo, updates imports and call sites to use vinfo.String(); updates build/linker flags and goreleaser ldflags to reference internal/vinfo for embedded version metadata.
Tooling config
.mise.toml
Updates linter module path to github.com/golangci/golangci-lint/v2/cmd/golangci-lint (v2 module path).

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Client
participant Proxy as Proxy (thinking processor)
participant Cache as SignatureCache
participant Rebuilder as ContentRebuilder
Client->>Proxy: Send assistant content (streaming or non-streaming)
Proxy->>Proxy: analyzeContentBlocks -> produce blockAnalysis
Proxy->>Cache: resolveThinkingSignature (client-provided? else cached)
alt Surgical possible
Proxy->>Proxy: surgicalUpdate signatures / remove tool_use sigs
else Rebuild needed
Proxy->>Rebuilder: rebuildContent (drop/reorder/preserve fields)
Rebuilder-->>Proxy: transformed content
end
Proxy->>Cache: cache/prefix signatures for non-streaming responses
Proxy-->>Client: Return processed assistant content

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I nibble at signatures, quick and spry,

I sort the thoughts that flutter by.
I tuck each mark, keep what should stay,
drop and reorder—hop away.
A tiny rabbit patch—code saved with a sigh 🥕

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 32.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive No description was provided by the author; the check cannot assess whether a description relates to the changeset. Add a pull request description explaining the rationale, changes, and testing approach for this signature priority fix and refactoring work.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title directly describes the main functional change: prioritizing client-provided signatures over cached ones in the proxy layer.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/thinking-block-signature-priority

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.

@omarluq omarluq force-pushed the fix/thinking-block-signature-priority branch from 97fd66d to 486a0ca Compare February 11, 2026 17:51
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes an Anthropic API error ("thinking blocks in the latest assistant message cannot be modified") by implementing two key changes: (1) prioritizing client-provided signatures over cached signatures to match Anthropic's exact signature expectations, and (2) introducing a "surgical update" approach that preserves unknown fields in thinking blocks byte-for-byte rather than reconstructing them from scratch.

Changes:

  • Refactored signature resolution to prioritize client signatures first, then cache as fallback (reversed from previous cache-first approach)
  • Added surgical update optimization that only modifies signature fields in-place, preserving all other fields like 'data' and 'redacted_thinking'
  • Extracted analysis logic into separate functions to reduce cognitive complexity

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
internal/proxy/thinking.go Implements signature priority change and surgical update approach with new helper functions (analyzeContentBlocks, surgicalUpdate, resolveThinkingSignature)
internal/proxy/thinking_test.go Adds regression test verifying unknown fields are preserved in thinking blocks

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +262 to +385
func TestProcessRequestThinkingPreservesUnknownFields(t *testing.T) {
// Regression test for Anthropic API error:
// "thinking blocks in the latest assistant message cannot be modified"
// The proxy was reconstructing thinking blocks from scratch, losing fields like
// 'data' and 'redacted_thinking' that Anthropic now requires to be preserved.
ctx := context.Background()

sig := "valid_signature_that_is_definitely_long_enough_for_validation"

// Thinking block with additional fields that must be preserved
body := `{
"model": "claude-sonnet-4",
"messages": [
{
"role": "assistant",
"content": [
{
"type": "thinking",
"thinking": "Some thinking...",
"signature": "` + sig + `",
"data": {"some": "metadata", "tokens": 1234}
},
{
"type": "thinking",
"thinking": "Redacted thinking...",
"signature": "` + sig + `",
"redacted_thinking": true
}
]
}
]
}`

modifiedBody, thinkingCtx, err := ProcessRequestThinking(ctx, []byte(body), "claude-sonnet-4", nil)
require.NoError(t, err)
assert.Equal(t, 0, thinkingCtx.DroppedBlocks)

// Verify first thinking block preserves 'data' field
dataField := gjson.GetBytes(modifiedBody, "messages.0.content.0.data")
assert.True(t, dataField.Exists(), "data field should be preserved")
assert.Equal(t, "metadata", dataField.Get("some").String(), "data.some should be preserved")
assert.Equal(t, float64(1234), dataField.Get("tokens").Float(), "data.tokens should be preserved")

// Verify second thinking block preserves 'redacted_thinking' field
redactedField := gjson.GetBytes(modifiedBody, "messages.0.content.1.redacted_thinking")
assert.True(t, redactedField.Exists(), "redacted_thinking field should be preserved")
assert.True(t, redactedField.Bool(), "redacted_thinking should be true")
}
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR title mentions "prioritize client signature over cache to match Anthropic's exact signature", but there's no test coverage for this critical behavior change. Consider adding a test that:

  1. Sets up a cache with one signature for a thinking block
  2. Sends a request with the same thinking text but a DIFFERENT valid client-provided signature
  3. Verifies that the client signature is used (not the cached one)

This would ensure the priority order in resolveThinkingSignature (lines 283-318 in thinking.go) is working correctly.

Copilot uses AI. Check for mistakes.
}

needsDrop := keptCount < analysis.totalBlocks
needsReorder := !needsDrop && checkReorderNeeded(analysis.blockTypes)
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a logic bug when both drops and reordering are needed. The condition needsReorder := !needsDrop && checkReorderNeeded(analysis.blockTypes) on line 228 means that if any blocks are dropped, reordering is never performed, even if the remaining blocks still need to be reordered.

Example scenario:

  • Input: [{"type": "text"}, {"type": "thinking", "signature": ""}, {"type": "thinking", "signature": "valid_sig..."}]
  • After dropping unsigned thinking block: [{"type": "text"}, {"type": "thinking", "signature": "valid_sig..."}]
  • Expected: [{"type": "thinking", "signature": "valid_sig..."}, {"type": "text"}] (thinking should come first)
  • Actual: [{"type": "text"}, {"type": "thinking", "signature": "valid_sig..."}] (not reordered)

The old code checked reordering AFTER collection (using collector.modifiedTypes), but the new code checks BEFORE collection (using analysis.blockTypes) and short-circuits when drops are needed.

Fix: Either always reorder in rebuildContent regardless of needsReorder, or calculate reordering need based on the collected blocks rather than original blocks.

Suggested change
needsReorder := !needsDrop && checkReorderNeeded(analysis.blockTypes)
needsReorder := checkReorderNeeded(analysis.blockTypes)

Copilot uses AI. Check for mistakes.
@omarluq omarluq force-pushed the fix/thinking-block-signature-priority branch from 486a0ca to f240e27 Compare February 12, 2026 01:46
@omarluq omarluq force-pushed the fix/thinking-block-signature-priority branch from f240e27 to ac073e5 Compare February 12, 2026 04:50
@codecov-commenter
Copy link

codecov-commenter commented Feb 12, 2026

Codecov Report

❌ Patch coverage is 84.52381% with 13 lines in your changes missing coverage. Please review.
✅ Project coverage is 78.15%. Comparing base (52299c7) to head (6be49b9).

Files with missing lines Patch % Lines
internal/proxy/thinking.go 86.58% 7 Missing and 4 partials ⚠️
cmd/cc-relay/main.go 0.00% 1 Missing ⚠️
cmd/cc-relay/version_cmd.go 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #90      +/-   ##
==========================================
- Coverage   78.30%   78.15%   -0.15%     
==========================================
  Files          94       94              
  Lines        5743     5800      +57     
==========================================
+ Hits         4497     4533      +36     
- Misses        961      980      +19     
- Partials      285      287       +2     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@sonarqubecloud
Copy link

@omarluq omarluq merged commit 845fb4b into main Feb 12, 2026
14 checks passed
@omarluq omarluq deleted the fix/thinking-block-signature-priority branch February 12, 2026 05:22
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.

2 participants