Repository navigation
fix(claude): carry a provider's own encrypted reasoning, bound to its minting route (carry #6741) - #6804
Conversation
…laude route On the translated Claude Messages route a Responses provider's native encrypted_content was discarded on the way out, and nothing could carry it back: the body is store:false and Claude Code replays only the thinking block. The routed model lost its own reasoning every turn (#6736). Keep the native blob in the thinking block's ocxr1 envelope as `nat`, with the client-facing model and the provider's item id, and emit that block even when no summary arrived. Inbound restores it as encrypted_content and id only for a request naming the same model; any other model gets the visible text alone. Translated bodies that reason now request include: ["reasoning.encrypted_content"], as Codex does. Refs #6736 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 1 minute. View limit detailsLimit details: You’ve used all 10 included reviews currently available. Review configuration: ⚙️ Run configuration
📒 Files selected for processing (16)
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. Comment |
|
✅ Deterministic PR hygiene checks passed. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 4b6cf535a8
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const signature = open.reasoningSig ?? encodeReasoningEnvelope({ | ||
| txt: open.thinkingBuf ?? "", | ||
| ...(tag ? { nat: { ...native, model, tag } } : {}), | ||
| }, translatorBudget); |
There was a problem hiding this comment.
Bind native reasoning to the effective routed model
The envelope records the client-facing model, not the model that actually produced the ciphertext. For synthetic effort/Fast rows, handleClaudeMessages saves the suffixed selector in requestedModel and then replaces anthropicBody.model with the base ID before translation, so the next turn compares this stored value with the normalized ID in inbound.ts:320 and always drops otherwise-valid continuity. Conversely, a combo or policy can retain the same client selector while switching between two physical models at the same endpoint and credential, allowing the tag and model checks to pass and forwarding one model's blob to another. Carry the effective routed model identity through minting and route verification instead of using the response-display selector.
Useful? React with 👍 / 👎.
| body.reasoning = reasoning; | ||
| // store:false returns a provider's encrypted reasoning only on request. The outbound | ||
| // envelope (`nat`) carries it to the client so the next turn can hand it back. | ||
| body.include = ["reasoning.encrypted_content"]; |
There was a problem hiding this comment.
Remove encrypted-content include when reasoning is stripped
When the selected model has an explicitly empty effort ladder, claude-messages.ts:1158-1161 deletes internalBody.reasoning as a safety valve, but this new include remains on the raw body and is forwarded by an openai-responses route. The resulting request asks for reasoning.encrypted_content despite no longer requesting reasoning, defeating the no-reasoning-model guard and potentially causing strict Responses-compatible endpoints to reject the unsupported parameter. Delete the include alongside reasoning, or add it only after final route capability resolution.
Useful? React with 👍 / 👎.
Summary
Maintainer carry of #6741 by @rhomat27, with a stricter replay boundary added before it can merge. Closes #6736.
On the translated Claude Messages → Responses route, a Responses provider's own
encrypted_contentwas never requested (store: falseand noinclude) and was dropped on the way back to Claude Code, becausesrc/claude/outbound.tsonly decodesocxr1:envelopes. Claude Code replays only the thinking block, so the routed model lost its own reasoning every turn. With Muse Spark that shows as long reading phases before the first edit.The contributor's design is kept. A new
natfield in the reasoning envelope (src/responses/reasoning-envelope.ts) carries the provider's blob inside the thinking block's signature, outbound signs it in on both the streaming and JSON paths, and inbound turns it back into a reasoning item when the request names the same model; any other model gets the visible text only. Bodies that reason now sendinclude: ["reasoning.encrypted_content"].Maintainer changes make replay depend on where a blob came from, not on a model name, because one client-facing name can be served by a combo, a changed route, another account or another endpoint:
natblob carries a tag: an HMAC under the installation's persisted replay salt over the minting route's owner (endpointbaseUrl+responsesPath, and a durable credential identity that includes the OAuth or Codex-pool token generation) and a hash of the blob itself. The owner is captured when the serving attempt's upstream accepts the turn, so a failed attempt never names a blob.bindRouteReasoningReplayScopeinsrc/server/responses/core-replay.ts) a restored blob is kept only when its tag verifies for the route about to send. Otherwise it is removed from both carriers, the raw-body reasoning item and the parser's thinking-signature copy, before any adapter builds a body. Removal never comes back on a later failover attempt.nat: blob-only thinking blocks are dropped, other proxy envelopes are re-encoded withoutnat, and undecodableocxr1:blocks are dropped. The projection reserves its decode and encode copies against the request's translator budget and answers 413translation_buffer_limiton overflow.structure/clients/claude-desktop.mdandstructure/transports/responses.mddescribe the rule; the latter stays at its 600-line budget.Co-authored-by: rhomat27 8294456+rhomat27@users.noreply.github.com
Verification
bun test tests/claude-integration/claude-native-reasoning-provenance.test.ts tests/claude-integration/claude-native-reasoning-continuity.test.ts tests/claude-integration/claude-outbound.test.ts tests/claude-integration/claude-inbound.test.ts tests/responses/reasoning-envelope.test.ts tests/responses/responses-account-change-scrub.test.ts tests/test-layout.test.ts tests/test-layout-tooling.test.ts tests/ci-workflows/file-size-ratchet.test.ts: 272 pass, 0 fail.tests/claude-integration/claude-native-reasoning-provenance.test.ts(registered in both layout registries) driveshandleClaudeMessageswith stubbed upstreams through: same route replays (also across a simulated restart); destination, credential andresponsesPathswitches strip before send; OAuth generation change strips; model switch and transplanted, altered or conflicting tags never replay; direct-forward never mints; streamed failover tags the serving attempt only; a block closing before commit gets nonat; anopenai-chatdestination gets no blob bytes; both native Anthropic branches get no blob bytes, including escaped-key and undecodable envelopes; budget rejection at the decode and encode boundaries; noincludewithout reasoning. OAuth generation and late-commit cases run at their binding and converter seams.bun run typecheck,bun run structure:check,bun run privacy:scan: pass. No log lines were added.bun run testsuite was not run locally (lane constraint: minimal local tests, several worktrees running in parallel). Exact-head hosted CI is the full-suite evidence. The contributor's live recall results in fix(claude): carry a provider's own encrypted reasoning through the Claude route #6741 predate these maintainer changes; the same-route behavior they measured is unchanged.Checklist