Repository navigation
fix(thinking): resolve "latest assistant message cannot be modified" 400s — fabricated placeholders + cross-org signature replay (#17324) - #18102
Merged
diegosouzapw merged 12 commits intoNov 2, 2026
Conversation
modified' thinking-block 400 (cheaper-inference#17324) Anthropic's "thinking or redacted_thinking blocks in the latest assistant message cannot be modified" validation error was previously left to the normal error path unchanged (explicitly called out as out of scope in isAnthropicThinkingSignatureError's docstring, cheaper-inference#7899). Once it fires, every retry resends the same unreplayable thinking block and gets the same 400 forever, with no recovery. Unlike the signature-rejection recovery (stripHistoricalThinkingForSignatureRecovery, which protects the active tool-use cycle and strips only earlier turns), this error names the LATEST assistant message specifically, so stripping history does nothing. Add a parallel, narrowly-targeted recovery: - isAnthropicThinkingModifiedError(): matches only this exact 400 on an Anthropic target, mirroring the existing signature-error matcher. - stripLatestAssistantThinkingForModifiedRecovery(): touches only the latest assistant message. A block the thinking store restored is downgraded to the cheaper-inference#5312 redacted_thinking placeholder and forgotten (same recovery the signature path already uses); any other thinking block in that one message is dropped outright, since it cannot be resent regardless of how it became unreplayable. A tool_use left in the message keeps a redacted_thinking placeholder ahead of it so the turn's structural shape stays valid. - executeWithAnthropicThinkingSignatureRecovery() now tries either matcher/recovery pair; recoverAnthropicThinkingSignature()'s entry gate (the real chatCore call site, used by both the streaming and non-streaming pipelines) now admits both error classes. No call site signature changed. One likely source of this error: a turn whose upstream stream ended with stop_reason content_filter (still a hard failure per cheaper-inference#15505/ cheaper-inference#15488 by design) on otherwise ordinary content, which can leave OmniRoute without a complete, replayable thinking block for that turn. Reproduced against a long-running Prime Agent session via omniroute@3.8.52; downgrading to 3.8.51 was the only workaround until now. Full repro and root-cause chain in cheaper-inference#17324. 7 new unit tests in tests/unit/anthropic-thinking-modified-recovery.test.ts, mirroring the existing anthropic-thinking-signature-recovery.test.ts conventions. Full targeted suite (passthroughHelpers, thinkingSignatureRecovery, providerExecutionPipeline and all of their existing importers/tests, 142 tests total) passes with zero failures.
Keep the upstream error when the latest assistant has only thinking or an identical recovery placeholder. Match only the latest-assistant error contract. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
…g replays (cheaper-inference#17324) The cheaper-inference#5312 redacted_thinking placeholder (fabricated DEFAULT_THINKING_CLAUDE_SIGNATURE blob) was injected for ANY reasoning_content + tool_use turn with thinking enabled, including ADAPTIVE thinking. For adaptive turns Anthropic's prompt cache holds the genuine signed blocks for those tool_use ids; the fabricated blob mismatches and the request 400s with "latest assistant message cannot be modified" (cheaper-inference#17324, cheaper-inference#17344 follow-up). Verified live on the claude OAuth leg: identical body 400s with the blob inside the cache window and passes 200 without it — and a tool_use turn with NO thinking block at all is accepted under thinking:adaptive, so omission is safe. - openai-to-claude: inject the placeholder only for MANUAL thinking (type:"enabled"). Adaptive omits it entirely (thinking.type passed down to getContentBlocksFromMessage). - passthroughHelpers + claudeThinkingStore recovery/downgrade paths: drop rejected or store-restored thinking blocks without re-injecting the fabricated placeholder; the remaining tool_use turn is a valid request shape. - tests: new adaptive/manual regression cases (cheaper-inference#17324); recovery contract updated to expect no fabricated placeholder; continuity test expects drop-and-forget.
…ion (cheaper-inference#17324) Production 400s on the fixed image traced to the thinking store replaying signed/redacted thinking blocks across OAuth orgs. The store bound entries by provider + model only, but the best-reasoning-paid combo load-balances claude-opus-5-5 across two Claude Max orgs (5601260a contact@, 46bad4cd kopyt1): turns produced by org A were restored verbatim on org B's connection — Anthropic verifies block integrity against the producing org and rejects the whole request with 400 "latest assistant message cannot be modified" (messages.N.content.K), failing both legs since each carried at least one foreign-org turn. Bind store entries to the serving connection id on both sides: - streaming capture: initTranslateStreamState keeps the raw connectionId alongside the Gemini-scoped signatureNamespace - non-streaming capture: provider leg threads params.connectionId - restore: translateRequest threads the raw signatureNamespace value as _connectionId into openai-to-claude's thinkingBinding A connection mismatch restores nothing; on adaptive-thinking models the miss means omission, which Anthropic accepts (verified live, probes 2/3/6). Mirrors the existing Gemini thoughtSignature namespace pattern (cheaper-inference#4136).
…e#17324 \"cannot be modified\" 400s The gate only matched the invalid-signature variant, so cross-org restore / fabricated-placeholder / truncated-capture failures (the exact cheaper-inference#17324 class this gateway now defends against) emitted no structural diagnostics. Widen shouldEmitThinkingSignatureDiagnostics to isAnthropicThinkingModifiedError as well; keep the strict canonical phrasing so generic \"cannot be modified\" 400s still do not match. Tests: positive cheaper-inference#17324 case with Anthropic's exact wording asserts the same allowlisted scalar shape (no signature/thinking/header leakage), anthropic-compatible-* parity, non-400 negative; the truncated-paraphrase fixture stays as the over-match guard.
7 tasks done
# Conflicts: # open-sse/services/claudeThinkingStore.ts
Only adaptive thinking was verified live for a tool_use turn without a thinking precursor. Under thinking.type "enabled" Anthropic still requires that block, so: - the 'cannot be modified' recovery keeps the original failure (no retry) when the latest assistant turn holds a tool_use, instead of trading it for an 'expected thinking ... found tool_use' 400; - the signature recovery swaps a rejected restored block for the cheaper-inference#5312 placeholder again (keepToolUsePlaceholder), mirroring what the translator does for that mode. Adds enabled-mode tests for both paths and makes the existing adaptive expectation explicit. Prettier on thinkingSignatureRecovery.ts. Co-authored-by: Patryk Kopycinski <patryk.kopycinski@elastic.co>
…estore + recovery blind spot Live diagnostics (corr fc77e698, claude/claude-opus-5-5, 2026-10-27): ingress carried zero thinking blocks, outbound gained 3 redacted_thinking blocks across 30 tool-result turns, recoveryAttempted=false, then hard-fail with 400 "latest assistant message cannot be modified". Four defects, four fixes: 1. openai-to-claude.ts: the cheaper-inference#17324 fix gated the fabricated cheaper-inference#5312 placeholder to manual thinking but left the claudeThinkingStore restore ungated, so adaptive requests (opus-5-5 via reasoning_effort) still replayed stored blocks. Anthropic accepts a bare tool_use turn on adaptive; a replayed signed block breaks warm-cache block-equality whenever restore hits/misses differently than the cache-warming turn. Gate restore to thinkingTypeForRequest === "enabled" (same gate as the placeholder). 2. claudeThinkingStore.ts: entries captured without connectionId ("" org binding) matched any later equally-unbound replay (""===""). Signatures are org-scoped — refuse to store unbound captures at all. 3. passthroughHelpers.ts: modified-recovery only stripped the LATEST assistant message, but Anthropic flags by cache warmth, not recency (live 400s cited messages.1/messages.3 while the latest turn was clean) — the strip no-oped and the request failed with recoveryAttempted:false. Now drops server-restored blocks from every assistant turn (client-sent thinking in earlier turns stays untouched). 4. thinkingSignatureDiagnostics.ts: the ingress→outbound signature diff was blind to redacted_thinking blocks (collectSignatures only read thinking.signature), reporting 0/0/0 while outbound gained +3 redacted blocks. Count redacted_thinking.data blobs too (counts-only output stays privacy-safe). Tests: 171/171 green across the 23 thinking/translator suites, including the new tests/unit/thinking-modified-recovery-recurrence.test.ts (all four live failure modes reproduced RED before the fix).
Contributor
Author
|
Follow-up: the 400 reappeared on a live deployment of the v3.8.53 line carrying this PR's earlier fixes, on
Coverage: new red-first suite |
… the modified recovery The recurrence fix drops store-restored blocks from every assistant turn and, under thinking.type "enabled", swaps them for the cheaper-inference#5312 placeholder on earlier tool_use turns. Nothing pinned that enabled branch (the suite stayed green with it removed); this case fails without keepToolUsePlaceholder and passes with it.
The mutation test-coverage gate requires every unit test covering a mutated module to be listed in tap.testFiles, so its mutant kills count.
diegosouzapw
merged commit Nov 2, 2026
b6da8f7
into
cheaper-inference:release/v3.8.53
41 checks passed
diegosouzapw
added a commit
to DavyMassoneto/OmniRoute
that referenced
this pull request
Nov 2, 2026
cheaper-inference#18102 landed first and kept the cheaper-inference#5312 placeholder under manual extended thinking. This PR removes that placeholder, so the conflicts follow the no-blob contract and keep the rest of cheaper-inference#18102: - keep isAnthropicThinkingModifiedError and the latest-message recovery, and pass `model` through both error matchers - drop keepToolUsePlaceholder; recovery injects nothing and disables manual thinking when the final tool turn is left bare - keep the guard that returns the original failure for a manual latest tool_use turn - rewrite the three cheaper-inference#18102 tests that pinned the manual placeholder to assert that the blob is absent and thinking is disabled for the retry
diegosouzapw
pushed a commit
that referenced
this pull request
Nov 2, 2026
…#18036) Stops sending DEFAULT_THINKING_CLAUDE_SIGNATURE to Anthropic. The constant is a real encrypted thought from an unrelated session, and Claude decrypts it as its own reasoning, which derails long agent sessions. - Genuine signed thinking and redacted_thinking blocks are kept verbatim on every turn; unsigned blocks and any block equal to the placeholder are dropped - Nothing is injected on a store miss or during recovery; manual thinking is disabled for the request when the final tool_use turn has no thinking block - Signature 400 recovery now covers Vertex and any model whose targetFormat is claude - Replaces the manual-mode placeholder kept by #18102, whose modified-error recovery and connection binding stay Live coverage: the author reports 0 blobs and 200s on a self-hosted 3.8.52; manual mode has not been verified live by the maintainers.
diegosouzapw
added a commit
to serenity-X/OmniRoute
that referenced
this pull request
Nov 3, 2026
Resolve the claudeThinkingStore/openai-to-claude conflicts with cheaper-inference#18102 (connection binding, manual-thinking-only restore) and cheaper-inference#18036 (no placeholder): keep the per-tool_use segment layout on top of both, and align the 18607 tests and the store-API callers (store takes ordered content, restore returns segments) with the tip semantics. Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
This was referenced Nov 3, 2026
Draft
DarknessKiller
added a commit
to DarknessKiller/OmniRoute
that referenced
this pull request
Nov 3, 2026
… Kit (#22) * docs(ci): record the Team plan, the janitor ceiling of 8 and the hosted-only test lane in RUNNER_BOX (#18456) Records the 2026-10-28 state of the runner box in docs/ops/RUNNER_BOX.md: Team plan (60 hosted jobs), janitor ceiling 8, five OmniRoute listeners (113-7 also carries omni-build, 113-3/-4/-8 deleted), and the vars.USE_VPS_TEST_RUNNER rule (same-repo pull_request only, off) with the measurement that turned it off. The 66 mirrors and .i18n-state.json come from scripts/i18n/run-translation.mjs (record/replay against a local backend). * feat(i18n): Google fallback and quota circuit breaker for every translation entry point (#18461) * fix(docs): sync the migration and provider counts to the live tree (base-red #17219) (#18476) * feat(providers): extend expiry-first account routing (#16352) * feat(api): serve Gemini-native /v1beta routes on the API-only port (#16745) Co-authored-by: Muhammad Usama <55662931+MuhammadUsamaMX@users.noreply.github.com> * feat(dashboard): per-step Test button in the combo create/edit modal (#16748) Co-authored-by: Erwan Novianto <smserwan@gmail.com> * feat(dashboard): hide/show models across providers from the Models catalog (#16749) Co-authored-by: Muhammad Usama <55662931+MuhammadUsamaMX@users.noreply.github.com> * fix(usage): enforce pending-request byte ceiling on all mutation paths (#17282) Co-authored-by: turbolego <turbolego@gmail.com> * perf: settings/combo read caches, async fs routes, bounded limiter settings (#17304) Co-authored-by: Mayank Jaiswal <mayankjaiswal1707@gmail.com> * fix(providers): align chatplayground with the current web chat API (#17312) * fix(release): list the three covering tests in stryker tap.testFiles (#18485) Refs #17219 * fix(release): open-sse typecheck and README diagram counts (377) on release/v3.8.53 (#18472) Refs #17219 * feat(search): support Exa 3.0 lite pricing and field set (#17394) Co-authored-by: Praveen K Palaniswamy <Praveen.Palaniswamy@gmail.com> * fix(catalog): keep operator-defined custom models on curated providers (#18018) * fix(sse): preserve harness tool history in Codex app-server (#18105) Co-authored-by: Anton Shilin <coder.root@gmail.com> * fix(sse): strip learned-only effort suffix back to the base model (#18131) * fix(combo): keep durable exhaustion across set retries (#18133) * fix(antigravity): stop three retry layers from hammering Cloud Code with a refused request (#18140) Co-authored-by: Wital <witalo_rocha@hotmail.com> * fix(build): skip the webpack persistent cache in production builds (#18141) * fix(sse): copy-on-write in the JSON-schema fallbacks and skip non-JSON response_format (#18241) * fix(i18n): protect inline HTML in the Google engine and guard HTML structure in the output check (#18486) * ci(i18n): scheduled post-merge mirror refresh (LLM first, Google last resort) (#18489) * fix(sse): withhold tool calls cut mid-arguments in a truncated buffered stream (#18482) * feat(search): price Exa extra results and summaries like Exa bills them (#17396) Co-authored-by: Praveen K Palaniswamy <Praveen.Palaniswamy@gmail.com> * fix(usage): bound pending request retention (#17405) Co-authored-by: Hummern <hummernkloa@gmail.com> * fix(combo): fail over from a target whose buffered stream was cut before its terminal signal (#18490) * feat(search): record Tavily advanced search at 2 credits (#17902) Co-authored-by: Praveen K Palaniswamy <Praveen.Palaniswamy@gmail.com> * feat(search): record Linkup deep search at $0.05 (#17903) Co-authored-by: Praveen K Palaniswamy <Praveen.Palaniswamy@gmail.com> * feat(search): record Firecrawl search per block of 10 results (#17904) Co-authored-by: Praveen K Palaniswamy <Praveen.Palaniswamy@gmail.com> * fix(release): clear the 10-28 typecheck, boundary, stryker, route-map and i18n reds on release/v3.8.53 (#18515) Refs #17219 * fix(i18n): open the LLM circuit after three consecutive failures, not only on quota (#18474) * fix(dashboard): monospace code text and a non-Latin script fallback after the kit 0.0.66 bump (#18477) * fix(dashboard): bring the team costs, combo step test and catalog toggle onto the kit components (#18487) * fix(api): let operators limit the Telegram bot to allowlisted senders (#18475) A valid Telegram signature (webhook secret_token or Mini App initData) proves an update came from Telegram, not that its sender may use this instance. TELEGRAM_USER_ALLOWLIST_ENABLED=true now serves only the numeric user ids in TELEGRAM_ALLOWED_USER_IDS: unlisted Mini App users get 403 and webhook messages from unlisted senders are acknowledged and dropped. The check uses the sender (message.from.id), so group chats are covered; an empty list serves nobody; misconfiguration is logged once without echoing ids. Off by default. Co-authored-by: HouMinXi <19586012+HouMinXi@users.noreply.github.com> * fix(api): stop keyless cross-origin reads on the client API and inference WebSockets (#18512) HTTP: on a keyless install (REQUIRE_API_KEY=false) any Authorization, x-api-key or x-goog-api-key header, valid or not, made client-API routes echo the request Origin while serving the request as anonymous. The allow path now relaxes CLIENT_API CORS only for a non-anonymous subject; route-level 401s that refuse a presented key still echo Origin (Vary: Origin, no credentials header) so browser clients can read them (#5242). WebSocket: browsers do not apply CORS to WebSockets and the /v1/responses, /v1/ws and /api/v1/ws handshakes never read Origin. They now admit no-Origin clients, CORS-allowlisted origins, the gateway's own public origin and handshakes with a valid API key; everything else, null included, gets 403 ws_origin_forbidden. The bridge upgrades only when the route answers originChecked: true. /v1/responses now enforces REQUIRE_API_KEY. The service worker also bypasses the client-API aliases. CORS and PWA guide mirrors refreshed. Co-authored-by: HouMinXi <19586012+HouMinXi@users.noreply.github.com> * fix(release): clear the remaining release/v3.8.53 base-reds — namespaced combo lookup, curated imported rows, build-scope ceiling (#18516) * fix(sse): resolve client-namespaced combos through the cached name lookup #17304 replaced the exact-name combo lookups in getCombo() with getCachedComboByName and dropped the getComboByName import, but missed the third call site in getComboByClientNamespacedName (#16493). Any model id with a "/" that is not a provider pin or catalog id then threw "ReferenceError: getComboByName is not defined" inside getComboForModel, which broke reasoning routing for unknown models and the client-namespace combo resolution. Fixes reasoning-routing-decision-guards ("an unknown model with no rules is also a clean pass-through") and 5 cases of combo-prefixed-name-resolve. * fix(models): keep sync-imported custom rows off curated-only providers #18018 made custom models listable on curated-only providers so a model added through "Add Custom Model" can be routed. Its stated scope is the operator's own rows ("Discovery behaviour is unchanged ... only the operator's own rows are kept"), but the three read paths kept every custom row, including rows whose source is imported/api-sync/auto-sync. On a provider with no upstream catalog such a row is a stale leftover of a retired discovery path: #8451 removed exactly those obsolete Z.ai Web ids (they 404 upstream), and zai-web-models-discovery-7678 pins that. The provider listing merge, GET /api/providers/[id]/models and /v1/models now drop discovery-imported custom rows on curated providers through one helper (isDiscoveryImportedCustomSource); operator rows keep flowing. zai-web-models-discovery-7678 now also expects the manual row, which #18018 made listable on purpose. New cases pin the imported-row exclusion in the listing merge and in /v1/models. * chore(changelog): drop the duplicate namespaced-combo fragment (#18514 carries it) The client-namespaced combo lookup fix is the same one-line change as #18514, which already ships its changelog fragment. Refs #17219 * chore(quality): raise the build-scope ceiling to 13500 in-scope files The release branch reached 12267 in-scope .ts/.tsx/.js/.jsx files through legitimate test growth (tests/ went 7841 -> 8296 files since 10-21), so check:build-scope failed on every PR although nothing was leaking. A leaked worktree or vendored checkout adds roughly a full tree (~12k files), which 13500 still catches. Refs #17219 * chore(dashboard): sync the CI UI Kit to 0.0.79 and keep tracking the newest release (#18504) * docs(i18n): refresh the changed ENVIRONMENT sections in 66 locales (#18524) * feat(antigravity): add Gemini 3.8 Flash tiers and update client fallbacks (#12499) Co-authored-by: Abhishek Chhetri <abhishekchhetri@example.com> * feat(oauth): GitHub Copilot capability-driven account integrationClaude/GitHub copilot integration 748ebe (#12833) * feat(dashboard): size dialogs to 70% of the viewport (#14091) Co-authored-by: Felipe Almeman <felipe@aireset.com.br> * feat(opencode): sanitize the OpenCode PR 4145 fingerprint (#14142) * feat(resilience): recover queued quota-failed sessions (#14981) (#14982) * feat(providers): wire claude-haiku-5-5 across catalogs, pricing, and fallbacks (#16159) Co-authored-by: Tuan Dinh <tuan.dinh.truong@sap.com> * feat(models-health): report whether reasoning_effort none was honored per model (#16253) * feat(providers): bounded-turn tool-call support for the ChatGPT Web clean-room adapter (#14948) Co-authored-by: Arash <arash.ashrafi@gmail.com> * feat(oauth): add Freebuff browser login to the freebuff provider (#15336) (#15343) * feat(muse-code): consolidate open Muse Code PRs (#15234, #14138, #13634, #14267, #12687) (#15521) Co-authored-by: mdc2122 <mdc2122@users.noreply.github.com> Co-authored-by: SIGTERM-015 <SIGTERM-015@users.noreply.github.com> Co-authored-by: KSonny4 <KSonny4@users.noreply.github.com> Co-authored-by: caniko <caniko@users.noreply.github.com> Co-authored-by: Chewji9875 <Chewji9875@users.noreply.github.com> * feat(dashboard): show which combos use a model on the provider detail page (#16307) Co-authored-by: Farshad <asadpoor.f@gmail.com> * feat(pii): GDPR + POPIA PII patterns with validators (#16461) Co-authored-by: Wayne <wayne@local> * feat(affinity): optional Redis store for shared session-to-account affinity (#16569) * feat(oauth): opt-in passive token refresh for Codex replicas (#16577) * feat: improve adaptive routing and model health monitoring (#16746) * feat(providers): allow manual vision overrides for synced models (#16794) * fix(mcp): ignore client _meta scopes for stdio callers (#17112) * fix(xai): flatten Codex namespace tools for /v1/responses; no account cooldown on 422 shape errors (#17134) Co-authored-by: özcan Yaman <ozc.yaman@gmail.com> * perf(provider-stats): bound provider-stats history to a 7-day window and cache the payload (#17227) * fix(dashboard): decode percent-encoded combo route params for auto/* control center (#17271) (#17272) * fix(desktop): publish and verify indexed optional runtime packs (#17338) * refactor(a2a): share agent discovery metadata (#17357) Co-authored-by: Jan Leon <jan@leoncode.de> * fix: require reasoning_content presence for DeepSeek and align Grok 4.7 context and effort tiers (#17388) Co-authored-by: Felipe Fidelix <felipe@fdx.is> * fix(providers): isolate agy/antigravity hiddenModelGate and clear compat overrides on model reset (#17398) (#17400) * fix(providers): rotate the deprecated OpenCode Zen mimo-v2.5-free id to v2.6 flash (#17472) (#17788) Co-authored-by: vincent <webmaster@palmit.com.au> * feat(sse): follow the published OpenCode endpoint and client headers for keyed requests (#17864) * fix(tls): follow the newest wreq-js browser profile in the web providers (#17869) * fix(sse): match the native Antigravity CLI wire image (#17913) * fix(docker): pin node 26.12.1 / bun 1.4.4 so images reject the compromised eMudhra CAs (security) (#17927) Co-authored-by: Markus Hartung <mail@hartmark.se> * feat(db): maintain configurable SQLite planner statistics (#17936) * fix(translator): ensure all assistant tool_calls are answered in fixMissingToolResponses (#17946) (#17947) Co-authored-by: Felipe Fidelix <felipe@fdx.is> * fix(dev): avoid the macOS dev-startup EBADF and keep reasoning out of combo test output (#17955) * feat(combo): global outputLimitAdvisory setting and a per target context window check (#17958) * fix(docker): split clientless CLI runtime from Docker tooling (#17972) Co-authored-by: Sean P. Ford <sean@seanford.com> * fix(providers): preserve Gemini function tools with native web search (#18020) * fix(db): preserve utilization bucket timezone (#18083) * fix(stream): preserve queued chunks on 6 abortStreamFailure sites (#18094) * fix(sse): refuse non-JSON data lines in stream readiness and content checks (#18095) * fix(db): don't skip half-applied proxy timing migration 194 (#18096) * fix(sse): fold camel-case reasoning effort into the canonical field (#18117) * fix(providers): preserve Codex reasoning controls and expose Muse subscription metadata (#18124) Co-authored-by: Aldo <github@aldo.pw> * fix(sse): local backends answer 499 while draining instead of 502 (#18134) Co-authored-by: roomhackerfrom100 <megamen932@gmai.com> * fix(compression): keep the tail of a truncated lite tool result (#18138) * fix(zcode): stream native Anthropic responses to clients (#18190) Co-authored-by: roomhackerfrom100 <megamen932@gmai.com> * fix(quota): recognize international Kimi Coding usage endpoints (#18180) (#18224) Co-authored-by: Nabi Bukhsh <nabibuksh.baloch01@gmail.com> * feat(dashboard): assign catalog models and combos to API keys (#14890) Co-authored-by: Fouad Salkini <fouad@wecansync.com> * feat(ci): validate protection domains for admission jobs (#16142) * feat(dashboard): add inline toggle and bulk disable/enable for no-auth providers (#16553) * feat(cli-tools): add OpenClaude setup guide card (#16844) Co-authored-by: Nguyen Thanh Dat <ntdat812@gmail.com> * feat(api): opt-in "expose combos only" setting for /v1/models (#16846) Co-authored-by: snower <sujian199@gmail.com> * feat(mcp): add a deep research tool that is off by default (#17317) * fix(opencode): map custom-provider catalog identities to public prefixes (#17369) * feat(oauth): import Antigravity Manager account exports (#15746) * feat(logs): distinguish generation rate from end-to-end throughput (#17847) * feat(api): CLIProxyAPI management usage compatibility endpoints (#17999) Co-authored-by: Rahul Bansal <rtrrahulbansal@gmail.com> * feat(antigravity): add Gemini 4 Argon weekly quota, dual-resolver preflight, and 404 short-circuit (#18026) * fix(zcode): preserve exact native Coding Plan quota refusals (#18118) Co-authored-by: roomhackerfrom100 <megamen932@gmai.com> * feat(opencode-plugin-v2): publish one catalog branch with prefix wildcard and hide every combo (#18135) * fix(combo): test all model health targets without a cumulative deadline (#18231) (#18238) * fix(codex): distinguish transient capacity 429 from quota cooldown (#18221) (#18239) * feat(oauth): route Grok Build image, video and audio (#15305) * feat(codebuddy-cn): sync authenticated live model catalog (#17916) * feat(providers): add MiniMax M3.1 Flash model (#18110) * fix(build): select webpack automatically on low-memory builders (#18184) (#18242) * fix(resilience): keep combos routable after transient credential probe errors (#18037) (#18243) * fix(claude): keep model-credit 429 cooldown scoped to the affected model (#18058) (#18245) * feat(providers): add Token Harbor API-key provider (#16315) Co-authored-by: GitHub Actions <github-actions@github.com> * feat(cli-tools): add current Pi setup flow (#16381) Co-authored-by: Arash <arash.ashrafi@gmail.com> * feat(api): configurable unpriced-usage budget policy + admin notice (#14604) (#14608) * fix(i18n): escape the Maltese apostrophe in providers.usedInComboTooltip (base-red) (#18545) * fix(usage): release terminal pending attempts when completion bookkeeping fails (#18217) Co-authored-by: AiCapitan357 <ai-capitan-357@proton.me> * feat(providers): add Runcrate (#18061) * i18n: complete feature-flag definitions for all 66 locales, fix zh-CN/zh-TW mistranslations (#17960) * feat(i18n): wire hardcoded dashboard strings into message catalogs (#17987) * feat(providers): add Gisoo (OpenAI-compatible) (#18112) Co-authored-by: Nirupam Bhowmick <48842933+heydryft@users.noreply.github.com> * feat(providers): dashboard control for the advertised CLI client version (#14817) Co-authored-by: Abhishek Divekar <adivekar@utexas.edu> * feat(ui): add remove error models button in combo test results, default autoHideFailed, and fix db import crash (#14944) * feat(core-config): ingest multiple feeds per subscription with per-source isolation (#16439) * feat(db): prune expired semantic cache rows in bounded batches (#17939) * feat(compression): let compression combos select output styles (#18107) * feat(api): authenticate Claude Code to /v1/* with Entra ID SSO (#14665) Co-authored-by: Benjamin <aronsson.benjamin@gmail.com> * feat(services): add sing-box supervisor installer and tproxy integration (#12962) * fix(release): clear the release/v3.8.53 base-reds from the merge campaign (#18625) * ci: tune CodeRabbit for the open-source rate limit and review noise (#18458) Tunes CodeRabbit for the open-source rate limit: one review per PR, bot PRs ignored, slop labelling on, less walkthrough noise. Evidence: focused tests passed on a combined board (no test file, config only); lint, typecheck:core and check-deps OK; open-sse-typecheck OK; api-typecheck reports only errors in files this batch does not touch, reproduced on the pure tip; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(network): refuse reserved 240.0.0.0/4 and broadcast in the SSRF guard (#18415) The SSRF guard refuses the reserved 240.0.0.0/4 block and the broadcast address. Evidence: focused tests passed on a combined board (private-host-reserved-ranges.test.ts, upstream-proxy-host-spelling.test.ts); lint, typecheck:core and check-deps OK; open-sse-typecheck OK; api-typecheck reports only errors in files this batch does not touch, reproduced on the pure tip; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(api): continue web fetch after Jina balance exhaustion (#18455) Web fetch continues to the next provider after Jina reports an exhausted balance. Evidence: focused tests passed on a combined board (web-fetch-quota-fallback.test.ts); lint, typecheck:core and check-deps OK; open-sse-typecheck OK; api-typecheck reports only errors in files this batch does not touch, reproduced on the pure tip; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 Fixes #18449 * fix(sse): send budget_tokens with enabled thinking on the GLM Anthropic transport (#18378) Enabled thinking on the GLM Anthropic transport always carries `budget_tokens`, keeping a client budget and deriving a missing one from the effort tier, clamped to max_tokens. Evidence: focused tests passed on a combined board (glm-anthropic-thinking-budget-tokens.test.ts); lint, typecheck:core and check-deps OK; open-sse-typecheck OK; api-typecheck reports only errors in files this batch does not touch, reproduced on the pure tip; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(sse): keep chat heartbeats from initializing tool messages (#18468) Chat Completions startup and periodic heartbeats are emitted without application choices, so LangChain keeps aggregating tool calls and the upstream message identity survives. Evidence: focused tests passed on a combined board (chat-keepalive-no-choice.test.ts, early-stream-keepalive.test.ts, sse-heartbeat*.test.ts); lint, typecheck:core and check-deps OK; open-sse-typecheck OK; api-typecheck reports only errors in files this batch does not touch, reproduced on the pure tip; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(sse): route the Codex, Muse, Z Code and Entra token fingerprints through the opaque helper (CodeQL #1195 #1199 #1201 #1207) (#18613) Routes the Codex, Muse, Z Code and Entra token fingerprints through `opaqueTokenFingerprint()`; outputs stay byte-identical. Evidence: focused tests passed on a combined board (opaque-token-fingerprint.test.ts); lint, typecheck:core and check-deps OK; open-sse-typecheck OK; api-typecheck reports only errors in files this batch does not touch, reproduced on the pure tip; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(deps): raise the @hono/node-server override to ^2.1.3 (#18615) Raises the `@hono/node-server` override to ^2.1.3, resolving to 2.1.5, for the `serveStatic` double path decoding fix. Evidence: focused tests passed on a combined board (no test file, dependency override only; check-deps OK); lint, typecheck:core and check-deps OK; open-sse-typecheck OK; api-typecheck reports only errors in files this batch does not touch, reproduced on the pure tip; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(sse): keep Claude Code classifier turns out of Memory (#18622) Claude Code security-classifier turns no longer read from or write to Memory. Evidence: focused tests passed on a combined board (chatcore-sanitization.test.ts, no-memory-header.test.ts); lint, typecheck:core and check-deps OK; open-sse-typecheck OK; api-typecheck reports only errors in files this batch does not touch, reproduced on the pure tip; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * chore(providers): add opt-in model sync phase timing (#18466) Adds opt-in `OMNIROUTE_MODEL_SYNC_TIMINGS=1` phase timings for model sync, as evidence for the latency investigation in #18335; normal sync behavior is unchanged. Evidence: focused tests passed on a combined board (sync-models-phase-timings.test.ts); lint, typecheck:core and check-deps OK; open-sse-typecheck OK; api-typecheck reports only errors in files this batch does not touch, reproduced on the pure tip; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * feat(providers): page through Cloudflare Workers AI model discovery and skip non-chat models (#18321) Cloudflare Workers AI model discovery pages through every result and skips non-chat models. Evidence: focused tests passed on a combined board (cloudflare-model-discovery-pagination.test.ts); lint, typecheck:core and check-deps OK; open-sse-typecheck OK; api-typecheck reports only errors in files this batch does not touch, reproduced on the pure tip; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * feat(api): expose per-limit capability provenance via /api/models?withLimits=1 (#18327) `GET /api/models?withLimits=1` exposes each token limit together with the source that supplied it; the parameter is opt-in and Zod-validated. Evidence: focused tests passed on a combined board (model-limit-provenance.test.ts); lint, typecheck:core and check-deps OK; open-sse-typecheck OK; api-typecheck reports only errors in files this batch does not touch, reproduced on the pure tip; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(api): decode compressed JSON request bodies at chat admission (#18264) Chat admission decodes compressed JSON bodies once for every admitted route, with the expanded size capped by the existing hard limit and no zlib error echoed. Evidence: focused tests passed on a combined board (request-body-content-encoding.test.ts, responses-route-compressed-body.test.ts); lint, typecheck:core and check-deps OK; open-sse-typecheck OK; api-typecheck reports only errors in files this batch does not touch, reproduced on the pure tip; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(sse): preserve reasoning fields through streaming redaction (#18363) Streaming redaction keeps content, reasoning and tool-argument fields in separate buffers, emits only buffered tails and holds raw credential fragments until a safe boundary. Evidence: focused tests passed on a combined board (streaming-credential-*.test.ts, streaming-reasoning-fields-17291.test.ts, streaming-redaction-chain-reasoning-17291.test.ts); lint, typecheck:core and check-deps OK; open-sse-typecheck OK; api-typecheck reports only errors in files this batch does not touch, reproduced on the pure tip; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(ci): reject incomplete release workflow audits (#17412) The Release-Green observer and its report verifier treat a missing or broken workflow scanner as incomplete evidence instead of nonblocking drift. Evidence: focused tests passed on a combined board (build/release-green-workflow-evidence.test.ts); lint, typecheck:core and check-deps OK; open-sse-typecheck OK; api-typecheck reports only errors in files this batch does not touch, reproduced on the pure tip; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * chore(dashboard): sync the vendored CI UI Kit to 0.0.80 (#18698) * feat(api): publish readable model display names on /v1/models (#18354) `/v1/models` publishes readable `display_name` values, shared with the Crush and OpenClaw setup routes. Evidence: focused tests passed (model-display-name, v1-models-registry-names, cli-tools-model-display-names); lint, typecheck:core, check-deps and open-sse-typecheck OK; api-typecheck reports only the two errors in availabilityRouterFilters.ts and cliTools.ts that reproduce on the pure tip; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 Co-authored-by: asterxsk <112053934+asterxsk@users.noreply.github.com> * fix(translator): keep Chat Completions custom tools when routing to Claude (#18314) The OpenAI to Claude request translator unwraps Chat Completions custom tools, which were silently dropped because the name was read off the wrapper. Evidence: focused tests passed (openai-to-claude-custom-tool-4938); lint, typecheck:core, check-deps and open-sse-typecheck OK; api-typecheck reports only the two errors in availabilityRouterFilters.ts and cliTools.ts that reproduce on the pure tip; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 Co-authored-by: gebclogic <73856846+gebclogic@users.noreply.github.com> * fix(dashboard): dispose compression save callbacks on unmount (#17850) The compression panel disposes its saved-status timer and skips late state updates after unmount. Evidence: focused test passed (compressionPanelLifecycle); headless Chromium click-through on a throwaway DATA_DIR: toggled a setting, left the page before the timer fired, no page error and the change persisted; lint, typecheck:core, check-deps and open-sse-typecheck OK; api-typecheck reports only the two errors in availabilityRouterFilters.ts and cliTools.ts that reproduce on the pure tip; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * fix(dashboard): validate OAuth URLs and restore shared type contracts (#18457) The OAuth modal rejects a non-string `authUrl` with a visible error and shared dashboard type contracts are restored. Evidence: focused test passed (oauth-response-contracts); headless Chromium click-through on a throwaway DATA_DIR: with `authUrl: 123` stubbed on the OAuth routes the modal shows the connection-failed state and offers retry; lint, typecheck:core, check-deps and open-sse-typecheck OK; api-typecheck reports only the two errors in availabilityRouterFilters.ts and cliTools.ts that reproduce on the pure tip; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * feat(dashboard): animate the analytics overview counters on change (#18340) The analytics overview counters animate when their value changes. Evidence: focused test passed (animated-number); headless Chromium click-through on a throwaway DATA_DIR: with a stubbed summary the Total Tokens card went 1.0K, 2.4M, 5.0M after a range change; lint, typecheck:core, check-deps and open-sse-typecheck OK; api-typecheck reports only the two errors in availabilityRouterFilters.ts and cliTools.ts that reproduce on the pure tip; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 Co-authored-by: F0Rextasy <99847357+F0Rextasy@users.noreply.github.com> * fix(providers): preserve existing prefixes without active built-ins (#17339) An existing compatible node keeps its reserved prefix while the live built-in has no active connection; collisions surface as a derived `prefix_shadowed` diagnostic. Evidence: focused tests passed (provider-prefix-grandfather-17278, custom-provider-prefix-shadowing-11943, provider-connection-status, image-compat-node-alias-shadow); headless Chromium click-through on a throwaway DATA_DIR: the connection row rendered a stubbed diagnostic and a real connection reported none; lint, typecheck:core, check-deps and open-sse-typecheck OK; api-typecheck reports only the two errors in availabilityRouterFilters.ts and cliTools.ts that reproduce on the pure tip; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 * feat(combos): export/import combos as a standalone, secret-free JSON file (#16747) Combos export and import as a standalone JSON file without credentials, with merge and replace modes. Evidence: focused tests passed (combos-export-import, combo-header-actions-import); headless Chromium click-through on a throwaway DATA_DIR: exported a combo with no secret-like key, rejected an invalid file, merged without duplicating a name, and replace left only the file's combos; lint, typecheck:core, check-deps and open-sse-typecheck OK; api-typecheck reports only the two errors in availabilityRouterFilters.ts and cliTools.ts that reproduce on the pure tip; file-size OK; changelog integrity OK against origin/release/v3.8.53. ⚠️ base-red inherited: #17219 Co-authored-by: Alvian Rahman Hanif <alvian.hanif@pasarpolis.com> * fix(release): clear the remaining base-reds on release/v3.8.53 (docs counts, SSO entry guard, API diagnostics, vuln ratchet) (#18658) Clears the remaining base-reds tracked in #17219 except the Release-Green package ceiling (#18693). - docs counts and mirrors (providers, migrations), generated skill sync - SSO script direct-run guard, API route typecheck fixes, catalog schema - provider asset provenance, node-forge vulnerability ratchet, mutation mapping - model sync: env documentation and an explicit audit sink for the error-helper gate - reload-timer isolation in two dashboard tests Refs #17219 * fix(release): raise the Release-Green package ceiling and clear three guards (#18693) - Release-Green package lane ceiling goes from 20 to 40 min: next build was killed at 20 min on an idle runner on every scheduled run - dashboard-kit-sweep: mark the hidden combo import file input as a kit exception (#16747) - hard-session-lease-bypass-inventory: classify the combo import connection read as class C (#16747) - deprecated-provider-banner-13067: bring providers/page.tsx back to its 1989-line freeze after #17278, without changing the pin Refs #17219 * feat(resilience): per-provider rate-limit retry delay override (#16741) Adds a per-provider override for the rate-limit retry delay, with a dashboard selector on the provider page and documentation in the resilience guide. Port of upstream decolua/9router #2895 by @MuhammadUsamaMX. * fix(thinking): resolve "latest assistant message cannot be modified" 400s — fabricated placeholders + cross-org signature replay (#17324) (#18102) Fixes the Anthropic 400 "thinking blocks in the latest assistant message cannot be modified" on multi-turn conversations. - Stop fabricating redacted_thinking on adaptive turns; the placeholder stays only for manual extended thinking - Bind signed-thinking continuity to the serving connection - One-shot recovery for the latest assistant message, from #17344, gated on thinking.type so manual extended thinking stays safe - THINKING_SIGNATURE diagnostics event Refs #17324 Co-authored-by: Nick Carter <nick@nickcarter.dev> * test(cli): resolve repro-9156 test paths with fileURLToPath so they work on Windows (#18646) Resolve repro-9156 test paths with fileURLToPath so they work on Windows. Evidence: focused tests on the combined board 62/62; file-size, changelog integrity, check-deps, lint, typecheck:core, open-sse-typecheck and api-typecheck OK against origin/release/v3.8.53. * test(rate-limit): close the SQLite handle before removing the learned-cap temp dir (#18647) Close the SQLite handle before removing the learned-cap temp dir. Evidence: focused tests on the combined board 62/62; file-size, changelog integrity, check-deps, lint, typecheck:core, open-sse-typecheck and api-typecheck OK against origin/release/v3.8.53. * test(cli): isolate APPDATA in cli-tray test so Windows never sees the real Startup folder (#18645) Isolate APPDATA in cli-tray test so Windows never sees the real Startup folder. Evidence: focused tests on the combined board 62/62; file-size, changelog integrity, check-deps, lint, typecheck:core, open-sse-typecheck and api-typecheck OK against origin/release/v3.8.53. * docs(resilience): document saved-settings precedence over resilience env toggles (#18608) (#18617) Document saved-settings precedence over resilience env toggles. Evidence: focused tests on the combined board 62/62; file-size, changelog integrity, check-deps, lint, typecheck:core, open-sse-typecheck and api-typecheck OK against origin/release/v3.8.53. Closes #18608 * fix(providers): add prompt-cache breakpoints for the Anthropic API-key provider (#18532) Add prompt-cache breakpoints for the Anthropic API-key provider. Evidence: focused tests on the combined board 62/62; file-size, changelog integrity, check-deps, lint, typecheck:core, open-sse-typecheck and api-typecheck OK against origin/release/v3.8.53. Closes #18531 * fix(search): keep every Exa highlight in provider_raw (#18109) (#18282) Keep every Exa highlight in provider_raw. Evidence: focused tests on the combined board 62/62; file-size, changelog integrity, check-deps, lint, typecheck:core, open-sse-typecheck and api-typecheck OK against origin/release/v3.8.53. * fix(release): import the numeric helpers from the engine, not the src re-export (boundary 778 → 768) (#18627) Import the numeric helpers from the engine, not the src re-export (boundary 778 → 768). Evidence: focused tests on the combined board 62/62; file-size, changelog integrity, check-deps, lint, typecheck:core, open-sse-typecheck and api-typecheck OK against origin/release/v3.8.53. * fix(cloud-agent): keep Jules creation timestamps consistent (#18681) Keep Jules creation timestamps consistent. Evidence: focused tests on the combined board 62/62; file-size, changelog integrity, check-deps, lint, typecheck:core, open-sse-typecheck and api-typecheck OK against origin/release/v3.8.53. * fix(build): use name-only install-script approvals for npm 12 (#18690) Use name-only install-script approvals for npm 12. Evidence: focused tests on the combined board 62/62; file-size, changelog integrity, check-deps, lint, typecheck:core, open-sse-typecheck and api-typecheck OK against origin/release/v3.8.53. * fix(usage): share one spend batch writer per process so graceful shutdown flushes it (#18680) Share one spend batch writer per process so graceful shutdown flushes it. Evidence: focused tests on the combined board 62/62; file-size, changelog integrity, check-deps, lint, typecheck:core, open-sse-typecheck and api-typecheck OK against origin/release/v3.8.53. Closes #18678. * chore(pricing): drop six stale zero-priced NVIDIA models (#18500) (#18502) Drop six stale zero-priced NVIDIA models. Evidence: focused tests on the combined board 57/58 with one catalog_build_timeout 503 under host load, covered below; file-size, changelog integrity, check-deps, lint, typecheck:core, open-sse-typecheck and api-typecheck OK against origin/release/v3.8.53. tests/unit/codex-account-catalog-routing.test.ts passed 16/16 on isolated rerun with CATALOG_BUILD_TIMEOUT_MS=300000. Closes #18500. * fix(sse): only pin thinking temperature when a sampling param is present (#18636) (#18639) Only pin thinking temperature when a sampling param is present. Evidence: focused tests on the combined board 57/58 with one catalog_build_timeout 503 under host load, covered below; file-size, changelog integrity, check-deps, lint, typecheck:core, open-sse-typecheck and api-typecheck OK against origin/release/v3.8.53. tests/unit/codex-account-catalog-routing.test.ts passed 16/16 on isolated rerun with CATALOG_BUILD_TIMEOUT_MS=300000. Fixes #18636 Closes #18636. * fix(sse): treat Leonardo and Ideogram image models as image-only in model tests and chat (#18683) Treat Leonardo and Ideogram image models as image-only in model tests and chat. Evidence: focused tests on the combined board 57/58 with one catalog_build_timeout 503 under host load, covered below; file-size, changelog integrity, check-deps, lint, typecheck:core, open-sse-typecheck and api-typecheck OK against origin/release/v3.8.53. tests/unit/codex-account-catalog-routing.test.ts passed 16/16 on isolated rerun with CATALOG_BUILD_TIMEOUT_MS=300000. Closes #18682. * docs(cost): document four-layer pricing precedence and models.dev sync (#18498) (#18501) Document four-layer pricing precedence and models.dev sync. Evidence: focused tests on the combined board 57/58 with one catalog_build_timeout 503 under host load, covered below; file-size, changelog integrity, check-deps, lint, typecheck:core, open-sse-typecheck and api-typecheck OK against origin/release/v3.8.53. tests/unit/codex-account-catalog-routing.test.ts passed 16/16 on isolated rerun with CATALOG_BUILD_TIMEOUT_MS=300000. Closes #18498. * fix(sse): persist terminal account failures during combo fallback (#18649) Persist terminal account failures during combo fallback. Evidence: focused tests on the combined board 57/58 with one catalog_build_timeout 503 under host load, covered below; file-size, changelog integrity, check-deps, lint, typecheck:core, open-sse-typecheck and api-typecheck OK against origin/release/v3.8.53. tests/unit/codex-account-catalog-routing.test.ts passed 16/16 on isolated rerun with CATALOG_BUILD_TIMEOUT_MS=300000. Fixes #18633 Closes #18633. * fix(antigravity): restore saved Argon cooldowns after restart (#18663) Restore saved Argon cooldowns after restart. Evidence: focused tests on the combined board 57/58 with one catalog_build_timeout 503 under host load, covered below; file-size, changelog integrity, check-deps, lint, typecheck:core, open-sse-typecheck and api-typecheck OK against origin/release/v3.8.53. tests/unit/codex-account-catalog-routing.test.ts passed 16/16 on isolated rerun with CATALOG_BUILD_TIMEOUT_MS=300000. * test(sse): cover advertised Claude effort ids against the authoritative catalog (#18611) Cover advertised Claude effort ids against the authoritative catalog. Evidence: focused tests on the combined board 57/58 with one catalog_build_timeout 503 under host load, covered below; file-size, changelog integrity, check-deps, lint, typecheck:core, open-sse-typecheck and api-typecheck OK against origin/release/v3.8.53. tests/unit/codex-account-catalog-routing.test.ts passed 16/16 on isolated rerun with CATALOG_BUILD_TIMEOUT_MS=300000. * fix(sse): set X-Accel-Buffering no on self-built SSE responses that bypass the central header path (#18446) Set X-Accel-Buffering no on self-built SSE responses that bypass the central header path. Evidence: focused tests on the combined board 57/58 with one catalog_build_timeout 503 under host load, covered below; file-size, changelog integrity, check-deps, lint, typecheck:core, open-sse-typecheck and api-typecheck OK against origin/release/v3.8.53. tests/unit/codex-account-catalog-routing.test.ts passed 16/16 on isolated rerun with CATALOG_BUILD_TIMEOUT_MS=300000. * fix(providers): keep Codex accounts eligible for models no inventory lists (#18367) Keep Codex accounts eligible for models no inventory lists. Evidence: focused tests on the combined board 57/58 with one catalog_build_timeout 503 under host load, covered below; file-size, changelog integrity, check-deps, lint, typecheck:core, open-sse-typecheck and api-typecheck OK against origin/release/v3.8.53. tests/unit/codex-account-catalog-routing.test.ts passed 16/16 on isolated rerun with CATALOG_BUILD_TIMEOUT_MS=300000. Closes #18311 * fix(ws): enforce REQUIRE_API_KEY at the /v1/ws bridge handshake (#18540) Enforce REQUIRE_API_KEY at the /v1/ws bridge handshake. Evidence: focused tests on the combined board 57/58 with one catalog_build_timeout 503 under host load, covered below; file-size, changelog integrity, check-deps, lint, typecheck:core, open-sse-typecheck and api-typecheck OK against origin/release/v3.8.53. tests/unit/codex-account-catalog-routing.test.ts passed 16/16 on isolated rerun with CATALOG_BUILD_TIMEOUT_MS=300000. * fix(test): stabilize UI Vitest teardown and provider-stats tests (#18525) Stabilizes UI Vitest suites that failed intermittently on unrelated pull requests. - Studio smoke tests unmount each React root inside act() before removing its container - OmniGlyph cancels the saved-status timer on the next save and on unmount, and ignores a late PUT completion - Provider Stats keeps a dismissed error-only alert closed across background polling; an explicit refresh reopens it - The Provider Stats test uses a stable translator, as next-intl does in the app - Burn-rate chart test waits on real content instead of fixed ticks * fix(sse): strip GHE Copilot URL slashes in linear time (CodeQL #1204 #1200) (#18614) gheUrl was trimmed with /\/+$/, which retries from every slash and goes quadratic on a long slash run that does not reach the end of the string (13 s of CPU on one 100,000-slash value). It now uses the linear stripTrailingSlashes() helper; ordinary URLs resolve the same. The Codex recovery test matches the token host on the parsed URL instead of a substring. * fix(claude): never replay the hardcoded redacted_thinking placeholder (#18036) Stops sending DEFAULT_THINKING_CLAUDE_SIGNATURE to Anthropic. The constant is a real encrypted thought from an unrelated session, and Claude decrypts it as its own reasoning, which derails long agent sessions. - Genuine signed thinking and redacted_thinking blocks are kept verbatim on every turn; unsigned blocks and any block equal to the placeholder are dropped - Nothing is injected on a store miss or during recovery; manual thinking is disabled for the request when the final tool_use turn has no thinking block - Signature 400 recovery now covers Vertex and any model whose targetFormat is claude - Replaces the manual-mode placeholder kept by #18102, whose modified-error recovery and connection binding stay Live coverage: the author reports 0 blobs and 200s on a self-hosted 3.8.52; manual mode has not been verified live by the maintainers. * deps: bump follow-redirects from 1.16.1 to 1.16.2 (#18654) Bumps the transitive follow-redirects from 1.16.1 to 1.16.2 in package-lock.json (Dependabot alert #370, high): cross-realm sensitiveHeaders arrays were discarded and custom credentials could survive a redirect. * feat(db): persist queue wait (start to first upstream dispatch) on ca… (#18402) Persists the queue wait (start to first upstream dispatch) on call-log rows, as a nullable `queue_wait_ms` column. No change on the request path. Maintainer rework: migration renumbered to the next free slot (223); column reconciliation in `schemaColumns.ts`; DB round-trip and chat-path tests; migration count synced in AGENTS.md, llm.txt, README.md and mirrors, digits only, checked by script. Evidence: the lineage test fails with `no such column` against the tip's `schemaColumns.ts`. Gate / CI, Gate / Quality and Merge integrity green on this head. * feat(render): add 180s self-pinger to keep the free web service awake (#18656) Adds an optional self-pinger for the Render free tier. It stays inert unless a URL is configured: no timer, no request, no log. Maintainer rework: config and pinger moved to `scripts/build/runtime-env.mjs` (already shipped in the standalone bundle); `SELF_PING_PATH` can no longer replace the host; logs only on status changes; env vars documented in `.env.example` and ENVIRONMENT.md; 24 tests. Evidence: removing the path guard fails 3 tests. Gate / CI, Gate / Quality and Merge integrity green on this head. Not exercised on a real Render service. * test(compression): verify unchanged-history prefix reuse (#18304) Adds regression coverage for live-zone prefix reuse, including the fail-open case when `instructions` change, for both `messages` and `input`. Test-only. Maintainer rework: added the `instructions` cases; moved the changelog fragment to maintenance. Evidence: removing `instructions` from `STABLE_PREFIX_FIELDS` fails 3 tests. Gate / CI, Gate / Quality and Merge integrity green on this head. * chore(security): accept the minimatch and glob CVEs in the npm bundled in the image (#18766) Accepts CVE-2026-118764 (minimatch 10.2.5, fixed in 11.0.1) and CVE-2026-118773 (glob 13.0.6, fixed in 14.0.2), both medium, in the npm bundled in the image. npm 12.2.1 still declares the vulnerable lines, and an overlay would cross majors outside its ranges. OmniRoute calls npm with fixed subcommands and validated versions, so request input does not reach npm as a glob. Tracking and revisit date (2026-12-02): #18765. * test(ui): stop api-key-redis-auth-cache timing out on a loaded host (#18762) * refactor(dashboard): use the kit Alert dismissible prop for permanent notices (#18764) * test(mutation): register the credit-exhaustion test in the Stryker tap list (#18771) #18649 added a unit test covering two mutated modules without listing it, so check:mutation-test-coverage failed on release/v3.8.53 and on every open PR against it. * ci(dashboard): warn and track it when the UI Kit watch can't read upstream (#18759) * fix(i18n): open the mirror refresh PR with the locales that translated (#18539) Part of #18538. A partial translation run now opens the refresh PR with the units that translated, and failed units stay untouched. Socket resets are retried by the Google engine. * docs(i18n): re-sync the 25 documents that drifted during the week of 2026-10-26 (66 locales; Kimi then Google fallback, references restored) (#18789) * fix(ci): run main-green's suites on hosted runners (#18776) Refs #17267 * fix(ci): raise the Release-Green package lane ceiling to 60 min (#18794) * fix(ui): paginate combo inventory (#17985) Co-authored-by: Sean P. Ford <sean@seanford.com> * fix(compression): estimate automatic-prefix cache eligibility (#17114) * fix: collapse stacked provider-node model prefixes (#17334) * fix(api): preserve search-provider chat rejection responses (#17953) * fix(gemini): preserve cached and reasoning tokens in buffered SSE usage metadata (#18100) * feat(api): System One decisions as a model kind — POST /v1/systemone + /v1/decisions (#13987) (#17994) * feat(combo): add agentic-stall response classifier (#13954) Co-authored-by: Patryk Kopycinski <patryk.kopycinski@elastic.co> * feat(providers): improve Antigravity and Cursor request handling and resilience (#13125) Co-authored-by: Tuan Dinh <tuan.dinh.truong@sap.com> * fix(docs): serve translated /docs pages for the selected locale (#18768) * feat(dashboard): self-host Vazirmatn for Arabic-script RTL locales (#18355) * feat(resilience): payload-aware anti-avalanche failover guard (#15775) * docs(i18n): re-record target_hash for the 3 MCP-SERVER mirrors edited without a re-hash (release prep) (#18807) * test(combo): port the #17945 cooldown-expansion matrix with credit to @skygunner (#18811) Co-authored-by: skygunner <84759+skygunner@users.noreply.github.com> * docs(release): reconcile v3.8.53 — CHANGELOG, contributor credit and README numbers (#18816) * docs(i18n): re-sync ENVIRONMENT and 7 stale documents after the 2026-11-02 merges (structure-safe engine) (#18815) * chore(dashboard): sync the vendored CI UI Kit to 0.0.84 (#18812) * docs(readme): draw the README diagrams in Switzer as vector outlines (#18767) * docs(i18n): re-translate the README mirrors after the week's README changes (66 locales) (#18817) * docs(i18n): retouch the locales the structure-safe engine could not restore (9 documents, 36 mirrors) (#18821) * docs: sync AGENTS.md counts with source (db + services) (#17309) Co-authored-by: Mayank Jaiswal <mayankjaiswal1707@gmail.com> * fix(ci): free hosted runner disk before the unit shards (#18808) Hosted Unit Tests shards ran out of disk while writing raw V8 coverage and died with no test summary. Free preinstalled toolchains first, on hosted runners only. * docs(i18n): re-sync the API_REFERENCE mirrors after the 2026-10/11 API changes (66 locales) (#18822) * docs(i18n): re-sync QUALITY_GATES and DESIGN_SYSTEM mirrors after the 2026-11-03 source changes (#18824) * docs: add the creator credit (KEA-6307) and courtesy credit for #17183 (#18843) * fix(egress): record the observed egress address of each address family (#17326) Merged as part of the v3.8.53 fix sweep (author @maxmad64bis). Co-authored-by: Dizzle <112548150+maxmad64bis@users.noreply.github.com> Co-authored-by: # <docs/i18n/am/README.md> Co-authored-by: # <docs/i18n/ar/README.md> Co-authored-by: # <docs/i18n/az/README.md> Co-authored-by: # <docs/i18n/bg/README.md> Co-authored-by: # <docs/i18n/bn/README.md> Co-authored-by: # <docs/i18n/bs/README.md> Co-authored-by: # <docs/i18n/cs/README.md> Co-authored-by: # <docs/i18n/da/README.md> Co-authored-by: # <docs/i18n/de/README.md> Co-authored-by: # <docs/i18n/el/README.md> Co-authored-by: # <docs/i18n/es/README.md> Co-authored-by: # <docs/i18n/et/README.md> Co-authored-by: # <docs/i18n/fa/README.md> Co-authored-by: # <docs/i18n/fi/README.md> Co-authored-by: # <docs/i18n/fr/README.md> Co-authored-by: # <docs/i18n/ga/README.md> Co-authored-by: # <docs/i18n/gu/README.md> Co-authored-by: # <docs/i18n/ha/README.md> Co-authored-by: # <docs/i18n/he/README.md> Co-authored-by: # <docs/i18n/hi/README.md> Co-authored-by: # <docs/i18n/hr/README.md> Co-authored-by: # <docs/i18n/hu/README.md> Co-authored-by: # <docs/i18n/hy/README.md> Co-authored-by: # <docs/i18n/id/README.md> Co-authored-by: # <docs/i18n/ig/README.md> Co-authored-by: # <docs/i18n/ja/README.md> Co-authored-by: # <docs/i18n/ka/README.md> Co-authored-by: # <docs/i18n/km/README.md> Co-authored-by: # <docs/i18n/kn/README.md> Co-authored-by: # <docs/i18n/ko/README.md> Co-authored-by: # <docs/i18n/lt/README.md> Co-authored-by: # <docs/i18n/lv/README.md> Co-authored-by: # <docs/i18n/ml/README.md> Co-authored-by: # <docs/i18n/mr/README.md> Co-authored-by: # <docs/i18n/ms/README.md> Co-authored-by: # <docs/i18n/mt/README.md> Co-authored-by: # <docs/i18n/my/README.md> Co-authored-by: # <docs/i18n/ne/README.md> Co-authored-by: # <docs/i18n/nl/README.md> Co-authored-by: # <docs/i18n/no/README.md> Co-authored-by: # <docs/i18n/or/README.md> Co-authored-by: # <docs/i18n/pa/README.md> Co-authored-by: # <docs/i18n/phi/README.md> Co-authored-by: # <docs/i18n/pl/README.md> Co-authored-by: # <docs/i18n/pt-BR/README.md> Co-authored-by: # <docs/i18n/pt/README.md> Co-authored-by: # <docs/i18n/ro/README.md> Co-authored-by: # <docs/i18n/ru/README.md> Co-authored-by: # <docs/i18n/si/README.md> Co-authored-by: # <docs/i18n/sk/README.md> Co-authored-by: # <docs/i18n/sl/README.md> Co-authored-by: # <docs/i18n/sr/README.md> Co-authored-by: # <docs/i18n/sv/README.md> Co-authored-by: # <docs/i18n/sw/README.md> Co-authored-by: # <docs/i18n/ta/README.md> Co-authored-by: # <docs/i18n/te/README.md> Co-authored-by: # <docs/i18n/th/README.md> Co-authored-by: # <docs/i18n/tr/README.md> Co-authored-by: # <docs/i18n/uk-UA/README.md> Co-authored-by: # <docs/i18n/ur/README.md> Co-authored-by: # <docs/i18n/uz/README.md> Co-authored-by: # <docs/i18n/vi/README.md> Co-authored-by: # <docs/i18n/yo/README.md> Co-authored-by: # <docs/i18n/zh-CN/README.md> Co-authored-by: # <docs/i18n/zh-TW/README.md> * fix(auth): audit non-inference API-key touches (#17982) Merged as part of the v3.8.53 fix sweep (author @seanford). Co-authored-by: Sean P. Ford <sean@seanford.com> * fix(usage): preserve pending byte accounting across module reloads (#18267) Merged as part of the v3.8.53 fix sweep (author @AiCaptain357). Co-authored-by: AiCapitan357 <ai-capitan-357@proton.me> * fix(compression): honor safe configured downgrade steps (#18279) Merged as part of the v3.8.53 fix sweep (author @trespassmk). Co-authored-by: trespassmk <avtogram@gmail.com> * fix(combo): report the fallback rate as a share of requests (#18284) Merged as part of the v3.8.53 fix sweep (author @HouMinXi). Co-authored-by: Minxi Hou <houminxi@gmail.com> * fix(api): return /v1/messages 401s in Anthropic's error envelope (#18299) Merged as part of the v3.8.53 fix sweep (author @diegosouzapw). Co-authored-by: omar-nahhas <omar@innovativerealities.com> * fix(providers): a provider safety refusal is not an account ban (#18307) Merged as part of the v3.8.53 fix sweep (author @aldoeliacim). Co-authored-by: aldoeliacim <github@aldo.pw> * fix(dashboard): list zed-hosted live models in the combo model picker (#18315) Merged as part of the v3.8.53 fix sweep (author @diegosouzapw). Co-authored-by: Haidar Muhammad Yasin <haidarmy1@gmail.com> * fix(combo): report authentication_rejected when every target fails auth (#18366) Merged as part of the v3.8.53 fix sweep (author @HouMinXi). Co-authored-by: Bob.Hou <houminxi@gmail.com> * fix(combo): fall back from protected priority on structured context overflow (#18368) Merged as part of the v3.8.53 fix sweep (author @RaviTharuma). Co-authored-by: Ravi Tharuma <RaviTharuma@users.noreply.github.com> * fix(resilience): accept globalConcurrentRequests and budgetMs in the settings schema (#18401) Merged as part of the v3.8.53 fix sweep (author @HouMinXi). Co-authored-by: Bob.Hou <houminxi@gmail.com> * fix(autoCombo): keep the readiness gate for auto/<family> pools (#18428) Merged as part of the v3.8.53 fix sweep (author @HouMinXi). Co-authored-by: Bob.Hou <houminxi@gmail.com> * fix(devin): fail with a non-retryable 503 when DEVIN_AGENTIC_HOME is unset or unsafe (#18433) Merged as part of the v3.8.53 fix sweep (author @HouMinXi). Co-authored-by: Bob.Hou <houminxi@gmail.com> Co-authored-by: Bob.Hou <364432949@qq.com> * fix(pricing): price the NVIDIA free catalog models at zero (#18470) Merged as part of the v3.8.53 fix sweep (author @HouMinXi). Co-authored-by: Bob.Hou <houminxi@gmail.com> * fix(api-keys): check resolved models against the key the policy loaded (#18481) Merged as part of the v3.8.53 fix sweep (author @HouMinXi). Co-authored-by: Bob.Hou <houminxi@gmail.com> * fix(logs): show each completed attempt once (#18491) Merged as part of the v3.8.53 fix sweep (author @AiCaptain357). Co-authored-by: AiCapitan357 <ai-capitan-357@proton.me> * typecheck: add a production type ratchet, and pay down 453 -> 272 (#18603) Merged as part of the v3.8.53 fix sweep (author @HouMinXi). Co-authored-by: Minxi Hou <houminxi@gmail.com> * fix(api): drop evidence-free combo members from advertised limits (#18618) Merged as part of the v3.8.53 fix sweep (author @serenity-X). Co-authored-by: serenity-X <295272363+serenity-X@users.noreply.github.com> * docs(providers): document what the claude OAuth route does to client system prompts (#18640) Merged as part of the v3.8.53 fix sweep (author @serenity-X). Co-authored-by: serenity-X <295272363+serenity-X@users.noreply.github.com> * fix(sse): preserve failed empty turns and expose native diagnostics (#18685) Merged as part of the v3.8.53 fix sweep (author @fouadSalkini). Co-authored-by: Fouad Salkini <fouad@wecansync.com> * fix(db): preserve backup archives and unknown formats during retention (#18712) Merged as part of the v3.8.53 fix sweep (author @aldoeliacim). Co-authored-by: aldoeliacim <github@aldo.pw> * test: isolate daily quota clocks and VS Code catalog discovery (#18748) Merged as part of the v3.8.53 fix sweep (author @HouMinXi). Co-authored-by: Minxi Hou <houminxi@gmail.com> * fix(providers): accept Cloudflare test message model IDs (#18752) Merged as part of the v3.8.53 fix sweep (author @trespassmk). Co-authored-by: trespassmk <avtogram@gmail.com> * fix(capabilities): restrict GLM-5.3 vision heuristic to Flash (#18758) Merged as part of the v3.8.53 fix sweep (author @insoln). Co-authored-by: insoln <insoln@ya.ru> * fix(sse): keep in-stream provider safety stops terminal (#18760) Merged as part of the v3.8.53 fix sweep (author @aldoeliacim). Co-authored-by: aldoeliacim <github@aldo.pw> * fix(compression): keep tool results intact unless a request overflows (#18761) Merged as part of the v3.8.53 fix sweep (author @aldoeliacim). Co-authored-by: aldoeliacim <github@aldo.pw> * test(setup): opt-in egress guard for in-process tests, plus the #16631 Claude OAuth frozen-body case (#18819) Merged as part of the v3.8.53 fix sweep (author @AndresDiagoM). Co-authored-by: AndresDiagoM <andresdiag@unicauca.edu.co> * fix(executors): clamp-and-retry max_tokens when upstream advertises a lower ceiling (#18407) Merged as part of the v3.8.53 fix sweep (author @jjxyxsjr). Co-authored-by: 沈俊杰 <shenjunjie@nndrobot.com> * fix(translator): the system-role fold must not drop non-text parts of the first user message (#18437) Merged as part of the v3.8.53 fix sweep (author @jjxyxsjr). Co-authored-by: 沈俊杰 <shenjunjie@nndrobot.com> * fix(auto-combo): treat account-semaphore capacity errors as local queue capacity (#18442) Merged as part of the v3.8.53 fix sweep (author @jjxyxsjr). Co-authored-by: 沈俊杰 <shenjunjie@nndrobot.com> * fix(executors): forward Codex requests as the client sent them (#18274) Merged as part of the v3.8.53 fix sweep (author @aldoeliacim). Co-authored-by: aldoeliacim <github@aldo.pw> * fix(usage): show the Kimi Coding subscription plan (#18578) Merged as part of the v3.8.53 fix sweep (author @AiCaptain357). Co-authored-by: AiCapitan357 <ai-capitan-357@proton.me> * fix(antigravity): isolate consumer generation endpoints (#18706) Merged as part of the v3.8.53 fix sweep (author @AiCaptain357). Co-authored-by: AiCapitan357 <ai-capitan-357@proton.me> * fix(providers): register Codex gpt-6.1-sol as an image model for combos and edits (#18826) Merged as part of the v3.8.53 fix sweep (author @anhtahaylove). Co-authored-by: anhtahaylove <everest.kill1@gmail.com> * ci(dashboard): keep one UI kit sync PR open from the latest upstream release (#18769) The UI Kit upstream watch only opened a tracking issue, so a new kit release still waited for someone to run the sync by hand. It now runs daily and, while the pin is behind, keeps one PR open against the highest release/vX.Y.Z branch through scripts/ci/ui-kit-sync-pr.sh. It never merges: every kit release still needs a visual check on the local VPS. The PR lives on the rolling branch chore/ui-kit-sync-latest because upstream can ship several releases a day. The branch is rebuilt when a newer release is out and left alone otherwise. An open PR with commits pushed by hand isn't overwritten, and a PR that a maintainer closed unmerged stays closed until a newer release. The watch holds while the target release is frozen. When no PR can be opened, the tracking issue says why. It's edited in place, since a comment on every daily run would only be noise. The issue step no longer runs when the check itself failed: an empty state used to fall through to the branch that closes the issue as up to date. Opening the PR needs the new UI_KIT_SYNC_PR_TOKEN secret, because GITHUB_TOKEN can't create PRs in this repository and a PR it opened wouldn't trigger CI. Without it only the branch is pushed. * fix(claude): show a Team seat's own tier and name a member with no seat (#18763) Merged as part of the v3.8.53 fix sweep (author @shipsfromrio). Co-authored-by: Caio Figueiroa <334500047+shipsfromrio@users.noreply.github.com> * docs(i18n): fix typos and broken tables in Uzbek README (#18659) Merged as part of the v3.8.53 fix sweep (author @barkhayot). Co-authored-by: Barkhayot Juraev <coderviewer@gmail.com> * fix(sse): real newlines in the opencode DeepSeek json_schema prompt (#18691) Merged as part of the v3.8.53 fix sweep (author @AndresDiagoM). Co-authored-by: AndresDiagoM <andresdiag@unicauca.edu.co> * fix(sse): let a combo opt out of the cooldown wait (#18708) Merged as part of the v3.8.53 fix sweep (author @stanleytejakusuma). Co-authored-by: Stanley Tejakusuma <70442355+stanleytejakusuma@users.noreply.github.com> * fix(providers): drop retired Mistral devstral-latest (#18792) Merged as part of the v3.8.53 fix sweep (author @costajohnt). Co-authored-by: John Costa <costajohnt@gmail.com> * fix(sync): wire the combo inventory pagination and the dismissed stats error Closes the two gaps left open by the sync commit, and removes a duplicated model-catalog block the merge reintroduced. ## Ported upstream features - Combo inventory pagination is now wired into `combos/page.tsx`: `useComboPagination` over the filtered list, `ComboListToolbar` above the inventory, `ComboPaginationNav` below it, "Reorder all" as the only drag mode, `revealCreatedCombo` selecting the created combo's page (dropping the strategy filter when needed), and `prefetch={false}` on per-combo links. - Provider stats keeps the last good snapshot on a failed poll: the load error is a dismissible banner, polling leaves a dismissal alone, and the header refresh reopens it. ## Merge bug fixed `gpt-6.1-terra*` was present twice in the codex registry (the conflict resolution kept the fork's legacy block next to upstream's single entry) and once more in `modelSpecs`/the OpenAI registry. Those duplicates made an uncatalogued model carry a confirmed 872K cap, which broke the #18609 combo ceiling rule and would have advertised a window upstream does not. ## Tests - `tests/unit/ui/provider-stats-dismissed-error.test.tsx` (new) covers the banner: appears on a failed poll, survives later polls once dismissed, comes back on an explicit refresh. - `tests/unit/ui/combo-pagination.test.tsx` gains the wiring assertions. - `tests/unit/auto-combo-route-param-page.test.tsx` restored: the encoded `/dashboard/combos/auto%2Ffast` crumb fix is ported to `Breadcrumbs` (`decodeRouteParam` + the `costs/teams` label). - 26 upstream dashboard test files deleted: they assert the vendored UI kit's DOM (`data-slot`, `ci-button`, kit popover/dialog semantics) on surfaces this fork renders with its own components. They arrived with this sync and never matched this tree. --------- Co-authored-by: Diego Rodrigues de Sa e Souza <diegosouza.pw@gmail.com> Co-authored-by: Junior-HJ <sjaradj@ucvvirtual.edu.pe> Co-authored-by: Muhammad Usama <55662931+MuhammadUsamaMX@users.noreply.github.com> Co-authored-by: Erwan Novianto <smserwan@gmail.com> Co-authored-by: hummern <hummernkloa@gmail.com> Co-authored-by: turbolego <turbolego@gmail.com> Co-authored-by: Mayank Jaiswal <mayankjaiswal1707@gmail.com> Co-authored-by: James Martinez <james-martinez@users.noreply.github.com> Co-authored-by: Praveen K Palaniswamy <praveen.palaniswamy@gmail.com> Co-authored-by: xc0derx <11428624+xc0derx@users.noreply.github.com> Co-authored-by: Anton Shilin <coder.root@gmail.com> Co-authored-by: Dizzle <112548150+maxmad64bis@users.noreply.github.com> Co-authored-by: WITALO ROCHA <witalo_rocha@hotmail.com> Co-authored-by: Bob.Hou <houminxi@gmail.com> Co-authored-by: Andres Felipe Diago Matta <82129635+AndresDiagoM@users.noreply.github.com> Co-authored-by: HouMinXi <19586012+HouMinXi@users.noreply.github.com> Co-authored-by: Abhishekchhetri020 <145480099+Abhishekchhetri020@users.noreply.github.com> Co-authored-by: Abhishek Chhetri <abhishekchhetri@example.com> Co-authored-by: ScottyAmr <scott.kanowski@gmail.com> Co-authored-by: Felipe Almeman <4226997+zhiru@users.noreply.github.com> Co-authored-by: Felipe Almeman <felipe@aireset.com.br> Co-authored-by: Rafa Martins <146174365+rafacpti23@users.noreply.github.com> Co-authored-by: Dongwook <dongwook.chan@gmail.com> Co-authored-by: Tuan Dinh <tuan.dinh.truong@sap.com> Co-authored-by: arashashrafii <arash.ashrafi@gmail.com> Co-authored-by: Pranav Deshpande <134182346+PranavD2905@users.norep…
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this fixes
Two independent root causes of the Anthropic 400
messages.N.content.K: "thinking" or "redacted_thinking" blocks in the latest assistant message cannot be modifiedon multi-turn conversations routed through OmniRoute (#17324). Both were verified live against the Anthropic API before fixing. Stacked on #17344 — the first two commits are that PR's recovery work rebased onto currentmain; the last three are this PR's root-cause fixes.Cause 1 — fabricated
redacted_thinkingplaceholder on adaptive-thinking replaysThe #5312 placeholder (a fixed
DEFAULT_THINKING_CLAUDE_SIGNATUREblob) was injected for anyreasoning_content+tool_useturn with thinking enabled — including adaptive thinking. Anthropic's prompt cache holds the genuine signed blocks for thosetool_useids; a fabricated blob mismatches and the whole request 400s.Fix: inject only for manual budget thinking (
thinking.type === "enabled"); adaptive omits it entirely. Verified live: the identical body 400s with the blob inside the cache window and passes without it, and atool_useturn with no thinking block at all is accepted underthinking: adaptive— so omission is safe. Recovery paths likewise drop rejected/store-restored blocks without re-injecting the placeholder; the remainingtool_useturn is a valid request shape.Cause 2 — thinking store replayed signed blocks across OAuth orgs
The signed-thinking continuity store keyed entries by
provider + modelonly. A combo that load-balances one model across two Claude Max OAuth orgs restores org-A-signed blocks onto org-B connections; Anthropic verifies block integrity against the producing org and rejects the request — failing both legs once each carries a foreign-org turn.Fix: bind store entries to the serving connection id — capture side (
initTranslateStreamStaterawconnectionId+ non-streaming provider leg), restore side (translateRequestthreadssignatureNamespaceas_connectionIdintothinkingBinding). A cross-connection restore becomes a cache miss → block omitted → request passes (adaptive-safe per the cause-1 finding).Diagnostics follow-up
shouldEmitThinkingSignatureDiagnostics(#15534) only matched the invalid-signature variant, so this 400 class emitted no structural facts for post-mortems. The gate now also matches Anthropic's canonical "cannot be modified" phrasing — deliberately strict so generic 400s do not over-match — with the same allowlist-only scalar shape (no signature/thinking/header values, sentinel-enforced by tests).Verification
tool_use-only outbound turnclaude-thinking-continuity,anthropic-thinking-modified-recovery/-review-17344,anthropic-thinking-signature-recovery,thinking-signature-diagnostics-15534(+ chatcore wiring),diagnostics-claude-thinking-5108,openai-to-claude-redacted-replay-5312— including new cross-connection and canonical-phrase regressionsFixes #17324