feat(claude): upgrade Claude Code 2.1.258 wire fingerprint and model behavioral parity - #5456
feat(claude): upgrade Claude Code 2.1.258 wire fingerprint and model behavioral parity#5456sususu98 wants to merge 8 commits into
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6861da0cac
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if strings.Contains(model, "fable") && !helps.IsClaudeProbeOrHelperRequest(payload) { | ||
| if !gjson.GetBytes(payload, "fallbacks").Exists() { | ||
| payload, _ = sjson.SetRawBytes(payload, "fallbacks", []byte(`[{"model":"claude-opus-5"}]`)) |
There was a problem hiding this comment.
Restrict fallback injection to Fable 5.1
When cloaking is enabled for the separately registered claude-fable-5 model, this substring check also injects fallbacks: [{"model":"claude-opus-5"}] and the server-side-fallback beta, even though the captured behavior documented immediately above is specific to claude-fable-5-1. If fallback is activated, a request for Fable 5 can silently execute as Opus 5; match the normalized Fable 5.1 model IDs rather than every model containing fable.
Useful? React with 👍 / 👎.
| explicitPromptID = strings.TrimSpace(explicitPromptID) | ||
| if explicitPromptID != "" && IsValidClaudePromptID(explicitPromptID) { | ||
| entry.promptID = strings.ToLower(explicitPromptID) | ||
| } else if isNewPromptTurn || entry.promptID == "" { | ||
| entry.promptID = uuid.NewString() | ||
| } |
There was a problem hiding this comment.
Keep prompt IDs scoped to their request generation
When two new prompt turns for the same credential/session overlap, the second BeginClaudeContinuity overwrites entry.promptID before either response commits. If the first response then completes and its tool continuation starts before the second completes (or after the second fails), the cache combines the first response's previousRequestID/previousMessageID with the second request's prompt ID. The prompt ID should be associated with the sequence and advanced atomically with that generation's successful commit.
Useful? React with 👍 / 👎.
| diagnosticsState := claudeDiagnosticsRequestState{} | ||
| isProbeOrHelper := helps.IsClaudeProbeOrHelperRequest(body) |
There was a problem hiding this comment.
Preserve helper classification before replacing the system prompt
For a title helper recognized only by the system text containing Return a short title rather than by the exact output schema, applyCloaking initially recognizes it but then replaces that top-level system field. This post-cloaking check therefore returns false, causing diagnostics to be injected and committed for a request that is meant to be isolated; subsequent beta and Fable checks misclassify it as well. Compute the helper/probe classification from the pre-cloaking body and reuse it throughout the request.
Useful? React with 👍 / 👎.
| parsed, err := uuid.Parse(id) | ||
| return err == nil && parsed.Version() == 4 |
There was a problem hiding this comment.
Validate the RFC 4122 variant of prompt UUIDs
For an incoming UUID such as 3c6489dc-badc-42b2-0d28-49f8ebabfedd, uuid.Parse succeeds and Version() is 4 even though the variant bits are not RFC 4122. This validator consequently accepts and forwards an identifier that contradicts its strict UUIDv4 contract instead of healing it; also require parsed.Variant() == uuid.RFC4122.
Useful? React with 👍 / 👎.
…int chain
- Assemble x-anthropic-billing-header strictly following official 2.1.258 binary order: cc_version, cc_entrypoint, cch, cc_workload, cc_is_subagent, cc_prev_req, and cc_prompt_id.
- Track upstream request-id (/^req_[A-Za-z0-9_-]{1,36}$/) in thread-safe, bounded session continuity state and inject into subsequent turns as cc_prev_req.
- Generate UUIDv4 cc_prompt_id per user prompt turn, preserving it across tool-use continuation loops while suppressing it on probes (max_tokens: 1) and title helpers.
- Detect subagents via agent headers or parent_session_id metadata and emit cc_is_subagent=true.
- Harmonize diagnostics and continuity lifecycles to prevent auxiliary/probe turns or truncated streams from corrupting conversation state.
- Add end-to-end multi-turn continuity and predicate tests in runtime executor.
…backs
- Gate effort-2025-11-24 so it is omitted on Haiku models, probe requests (max_tokens: 1), and when thinking is disabled.
- Add thinking-display-updates-2026-08-18 beta and emit it when thinking.display is updates.
- Automatically emit server-side-fallback-2026-06-01 when the body contains a fallbacks array.
- Suppress extended-cache-ttl-2025-04-11 on subagent and probe requests.
- Inject fallbacks: [{"model": "claude-opus-5"}] and set display: updates for claude-fable-5-1 during cloaking.
- Update and extend CLI betas matrix tests.
…ble models - Add claudeCodeFableReportingOutcomes constant matching Claude Code 2.1.258 binary. - Inject as System[2] without cache_control for fable and mythos models during cloaking. - Retain passthrough behavior for confirmed native Claude Code and when cloaking is disabled. - Add unit tests for Fable injection, non-Fable omission, DisableClaudeCloakMode, and native Claude Code.
…ty context fallback - Validate cc_prompt_id strictly as RFC 4122 UUIDv4 in BeginClaudeContinuity and ExtractClaudeBillingTags. - Sanitize and heal invalid or non-v4 prompt IDs by generating compliant UUIDv4 values instead of propagating malformed tags. - Fallback to ClaudeContinuityContext in claudeCCHFallbackBillingHeader when payload rules or upstream transformations strip billing tags. - Add comprehensive unit test suite for IsValidClaudePromptID.
…iant, probe isolation, and atomic prompt ID commit - Restrict fallback injection and Reporting outcomes system block strictly to Fable 5.1 / Mythos 5.1 (isClaudeFable51Model), preventing unexpected Opus fallback on claude-fable-5. - Require uuid.RFC4122 variant check in IsValidClaudePromptID to heal non-standard UUIDv4 variants. - Compute isProbeOrHelper from pre-cloaking body to preserve title helper detection when system prompt is replaced. - Make BeginClaudeContinuity return generation prompt ID without prematurely overwriting cached state, and commit prompt ID atomically in CommitClaudeContinuity.
6861da0 to
7cfa992
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7cfa992ffe
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if oauthToken && !helps.IsClaudeSubagentRequest(nil, body) && !helps.IsClaudeProbeOrHelperRequest(body) { | ||
| betas = append(betas, claudeExtendedCacheTTLBeta) |
There was a problem hiding this comment.
Keep the cache TTL paired with its beta
For OAuth cloaked subagent, probe, and title-helper requests, this new condition removes extended-cache-ttl-2025-04-11, but both Execute and ExecuteStream still call upgradeClaudeCacheControlTTL(..., "1h") whenever CPA owns cache placement and the credential uses the Claude Code profile. Because cloaking already installs a cache marker, these requests carry cache_control.ttl: "1h" without the beta required to enable it, breaking the pairing invariant and potentially causing Anthropic to reject the request; gate the TTL upgrade with the same request predicates or retain the beta.
Useful? React with 👍 / 👎.
…l beta - Only upgrade cache_control TTL to 1h when the request is eligible for extended-cache-ttl-2025-04-11 (!isSubagent && !isProbeOrHelper). - In native Claude Code 2.1.258, 1h cache is restricted to main interaction threads (repl_main_thread*), while subagents, probes, and side queries omit both the beta and 1h TTL.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0d3dafe1f5
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| model := strings.ToLower(strings.TrimSpace(gjson.GetBytes(payload, "model").String())) | ||
| if isClaudeFable51Model(model) && !isProbeOrHelper { |
There was a problem hiding this comment.
Apply Fable additions after payload model overrides
When an operator uses a payload override to change model, this decision is made from the pre-override model because both Execute and ExecuteStream call ApplyPayloadConfigWithRequestTracked only after applyCloaking. Rewriting Fable 5.1 to another model therefore leaves its Opus fallback, thinking.display, and reporting system block attached, allowing an unexpected Opus fallback; rewriting another model to Fable 5.1 omits all of those required additions. Reconcile these model-dependent fields after payload rules have established the final upstream model.
Useful? React with 👍 / 👎.
…er payload model overrides - When payload rules rewrite a request model across Fable 5.1 and non-Fable models, reconcile the Fable-exclusive fields (Opus fallback, thinking.display=updates, and # Reporting outcomes system block). - Prevent sending unexpected Opus fallback or reporting outcomes on non-Fable models (e.g. Sonnet 5). - Ensure required Fable 5.1 wire properties are attached when a model is rewritten to Fable 5.1.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5fd4609144
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if oauthToken && !helps.IsClaudeSubagentRequest(nil, body) && !helps.IsClaudeProbeOrHelperRequest(body) { | ||
| betas = append(betas, claudeExtendedCacheTTLBeta) |
There was a problem hiding this comment.
Prune the cache beta on confirmed subagent requests
When a confirmed native Claude Code subagent is forwarded using an OAuth credential, applyClaudeHeadersWithNativeProfile bypasses this rebuilt list, restores the caller's betas, and then calls withClaudeOAuthCredentialBetas, which unconditionally appends extended-cache-ttl-2025-04-11. Consequently, header-identified native subagents still receive the beta even though their body is left without the new 1h TTL; apply the subagent/probe predicate to the confirmed-client credential-restoration path as well.
Useful? React with 👍 / 👎.
| if !gjson.GetBytes(originalBody, "fallbacks").Exists() { | ||
| fallbacks := gjson.GetBytes(body, "fallbacks") | ||
| if fallbacks.IsArray() && len(fallbacks.Array()) == 1 && fallbacks.Array()[0].Get("model").String() == "claude-opus-5" { | ||
| body, _ = sjson.DeleteBytes(body, "fallbacks") |
There was a problem hiding this comment.
Preserve explicit payload fallback overrides
When a payload rule changes Fable 5.1 to another model while explicitly retaining fallbacks: [{"model":"claude-opus-5"}], this branch deletes the configured fallback because originalBody predates both cloaking and ApplyPayloadConfigWithRequestTracked. The same provenance problem affects an explicit thinking.display: "updates" override below; track which fields were injected by cloaking or touched by payload rules rather than inferring ownership solely from their final values.
Useful? React with 👍 / 👎.
| if requestID != "" && claudeRequestIDPattern.MatchString(requestID) { | ||
| entry.previousRequestID = requestID | ||
| } |
There was a problem hiding this comment.
Clear stale request IDs when a response has none
If a normal successful response lacks a valid request-id header—for example because an Anthropic-compatible gateway omits it—this commit advances previousMessageID and the prompt generation but leaves the prior response's previousRequestID intact. The next request then emits a stale cc_prev_req referring to an older response rather than omitting the unavailable immediate predecessor, producing an inconsistent continuity chain.
Useful? React with 👍 / 👎.
…ng, explicit fallback overrides, and stale request ID clearing - Prune extended-cache-ttl beta for confirmed native Claude Code subagents and probes in withClaudeOAuthCredentialBetas. - Track Fable field provenance and check payload rule overrides so explicit operator-configured fallbacks/display are never deleted. - Clear previousRequestID in CommitClaudeContinuity when upstream response provides no valid request-id.
Summary
Upgrade CPA's built-in Claude Code CLI wire fingerprint from
2.1.220to2.1.258, aligning request headers, body parameters, and session continuity with measured native wire behavior.Key Changes
P0 Billing Header Continuity Chain:
x-anthropic-billing-headerstrictly to the native Bun byte order:cc_version -> cc_entrypoint -> cch -> cc_workload -> cc_is_subagent -> cc_prev_req -> cc_prompt_id.cc_prev_reqto upstreamrequest-id: req_...headers with continuity cache.cc_prompt_id, with automatic healing for malformed/non-v4 IDs.max_tokens: 1) and side-queries to prevent session poisoning.claudeCCHFallbackBillingHeaderto preserve subagent flags during CCH regeneration.P1 Dynamic Anthropic-Beta Pruning & Fallbacks:
effort-2025-11-24on Haiku models, probe requests, and when thinking is disabled.thinking-display-updates-2026-08-18beta and automatically dropredact-thinking-2026-02-12when thinking display isupdatesorsummarized.server-side-fallback-2026-06-01whenever the body containsfallbacks.extended-cache-ttl-2025-04-11on subagents and probes.P2 Model Cloaking Parity:
"fallbacks": [{"model": "claude-opus-5"}]and defaultdisplay: updateswhen cloakingclaude-fable-5-1.# Reporting outcomesasSystem[2]without cache control for Fable 5.1 / Mythos models when cloaking is enabled.disable-claude-cloak-modeis true.ClaudeContinuityContextinclaudeCCHFallbackBillingHeaderwhen payload transformations strip billing tags.Verification
go test -count=1 ./internal/runtime/executor/...andgo test ./cmd/... ./internal/api/....go build -ldflags="-s -w" -o /dev/null ./cmd/server.