fix(sse): pass Claude passthrough thinking blocks through unchanged - #3775
Conversation
…prevent E415 hard-link tarball rejection
Bumps [esbuild](https://github.com/evanw/esbuild) from 0.28.0 to 0.28.1. - [Release notes](https://github.com/evanw/esbuild/releases) - [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md) - [Commits](evanw/esbuild@v0.28.0...v0.28.1) --- updated-dependencies: - dependency-name: esbuild dependency-version: 0.28.1 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Rewriting assistant `thinking` blocks to `redacted_thinking` made the Anthropic Messages API reject multi-turn requests with extended thinking: 400 messages.N.content.M: `thinking` or `redacted_thinking` blocks in the latest assistant message cannot be modified. Submitted thinking blocks are validated against the original response, so any rewrite is rejected. This broke every multi-turn request with thinking on the Anthropic-native Claude OAuth passthrough (most visible on long Claude Code tool-loops). The thinking-block signature is validated server-side and stays valid on replay, including under a different OAuth token, so the redaction added for diegosouzapw#2454 is unnecessary. Pass the blocks through unchanged.
There was a problem hiding this comment.
Code Review
This pull request stops rewriting assistant thinking blocks to redacted_thinking in the Claude OAuth passthrough, resolving a 400 error where the Messages API rejected modified thinking blocks. The redactPassthroughThinkingSignatures function is now a no-op that returns the messages unchanged, and unit tests have been updated accordingly. The reviewer suggested marking this now-obsolete function as @deprecated in its JSDoc to signal that it should be refactored out of call sites.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| * responses. The redaction is therefore both unnecessary and the cause of the | ||
| * regression, so the blocks are now returned verbatim. The `signature` parameter | ||
| * is kept for call-site compatibility. | ||
| */ |
There was a problem hiding this comment.
Since redactPassthroughThinkingSignatures is now a no-op that returns the input messages unchanged, it is highly recommended to mark this function as @deprecated in the JSDoc. This informs other developers and IDEs that the function is obsolete and should be refactored out of call sites in future cleanups.
| */ | |
| *\n * @deprecated This function is now a no-op and returns the messages unchanged.\n * Callers should be refactored to avoid calling this function.\n */ |
✅ Live validation (Rule #18) — confirmed against the real Anthropic Messages APIValidated the core claim directly against
Result: the verbatim passthrough this PR restores is accepted; the redaction it removes is rejected by Anthropic. The fix resolves a real multi-turn extended-thinking breakage and does not reintroduce #2454. Minor note: the observed 400 string was Merging into |
c0a57d2
into
diegosouzapw:release/v3.8.24
Resolve file-size-baseline.json conflict in the _rebaseline keys block: keep this PR's combo_quota_audit key + release's v3824_3776 key (#3776); drop the now-redundant drift_3780 key (release's #3776 key already documents the base.ts 1205->1218 carry-over from #3780). frozen values auto-merged (combo.ts 5131 mine, base.ts 1218 both, chatCore.ts 5808 theirs). Verified on the merged tree: all 14 Fast Quality Gates pass (incl. file-size: chatCore 5736<=5808, combo 5131<=5131), W1 streaming hook intact, quota-streaming 8 / complexity-router 6 / scoring-clamp 7 / combo-routing-engine 81 green. Pre-existing release app-tsc noise in chatCore (3026-4380, from #3775) is untouched by this PR.
…contributor credits - Restructure [3.8.24] into ✨ Features / 🔒 Security / 🐛 Fixed / 📝 Maintenance - Add bullets for every PR landed since v3.8.23 that was missing: marketplace (#3656), strict-mode CC defaults (#3776), emergency-fallback flag (#3752), xhigh effort (#3756), Codex memory WS (#3749), IPv6 egress (#3777), marketplace SSRF (#3774), CodeQL/Dependabot (#3778), anthropic sampling (#3780), thinking passthrough (#3775), mcp dist entry (#3765), streamed tool args (#3762), logs light-mode (#3760), clean-history purge (#3751), quality-gates (#3757), docs gaps (#3453), file-size re-baseline (#3770), E415 publish guard, i18n prune - Move misplaced #3775 bullet out of [Unreleased] into [3.8.24] - Date [3.8.23] header (TBD -> 2026-06-12, the release tag date)
…iegosouzapw#3775) Pass Claude passthrough thinking blocks through unchanged (fixes the redacted_thinking 400). Live-validated against the Anthropic API. Integrated into release/v3.8.24.
…contributor credits - Restructure [3.8.24] into ✨ Features / 🔒 Security / 🐛 Fixed / 📝 Maintenance - Add bullets for every PR landed since v3.8.23 that was missing: marketplace (diegosouzapw#3656), strict-mode CC defaults (diegosouzapw#3776), emergency-fallback flag (diegosouzapw#3752), xhigh effort (diegosouzapw#3756), Codex memory WS (diegosouzapw#3749), IPv6 egress (diegosouzapw#3777), marketplace SSRF (diegosouzapw#3774), CodeQL/Dependabot (diegosouzapw#3778), anthropic sampling (diegosouzapw#3780), thinking passthrough (diegosouzapw#3775), mcp dist entry (diegosouzapw#3765), streamed tool args (diegosouzapw#3762), logs light-mode (diegosouzapw#3760), clean-history purge (diegosouzapw#3751), quality-gates (diegosouzapw#3757), docs gaps (diegosouzapw#3453), file-size re-baseline (diegosouzapw#3770), E415 publish guard, i18n prune - Move misplaced diegosouzapw#3775 bullet out of [Unreleased] into [3.8.24] - Date [3.8.23] header (TBD -> 2026-06-12, the release tag date)
Problem
On the Anthropic-native Claude OAuth passthrough, every multi-turn request that carries extended thinking fails with:
It is especially visible on long Claude Code tool-loops (the conversation accumulates many thinking turns, so it reproduces on almost every follow-up request).
Root cause
redactPassthroughThinkingSignatures(open-sse/handlers/chatCore.ts) rewrites every assistantthinking/redacted_thinkingblock toredacted_thinking{data:<synthetic>}before forwarding to Anthropic.The Messages API validates submitted thinking blocks against the original response and rejects any modification — so converting them is exactly what triggers the
cannot be modified400.The rewrite was added to avoid a presumed
400 "Invalid signature in thinking block"(#2454) on a token/model switch, on the assumption that the signature is bound to the auth token that produced it. In practice the thinking-block signature is validated server-side by Anthropic and stays valid on replay — including under a different OAuth token, which I verified by preserving the blocks across a mid-conversation account switch with zeroInvalid signatureresponses. So the redaction is both unnecessary and the cause of this regression.Fix
Pass the
thinking/redacted_thinkingblocks through unchanged (the function now returnsmessagesas-is). Thesignatureparameter is kept for call-site compatibility, and the doc-comment is updated to explain the two errors and why the redaction was removed.Testing
tests/unit/claude-passthrough-thinking-2454.test.tsto assert the blocks pass through unchanged (historical and latest), pre-existingredacted_thinkingis not re-stamped, and non-array input passes through. Run:Invalid signature.Checklist
tests/unit/claude-passthrough-thinking-2454.test.ts)prettier --checkclean on changed files;eslintclean on changed files[Unreleased]Co-Authored-Bytrailers