Repository navigation
[WRONG BRANCH] release: promote dev 52c326b479 to main as 2.89.0 - #7372
Merged
Merged
Conversation
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…sentation (#7282) * feat(compatibility): separate custom-tool grammar evidence from representation Record custom-tool representation and grammar as separate compatibility claims, and add a second exact subject where grammar is lost. - canonical Codex forward (gpt-5.6-sol): new request.custom_tools.grammar passthrough claim backed by a format assertion with a real Lark definition; manifest 1.4.0 - OpenGateway key auth (z-ai/glm-5.3-flash-ultrafast on the Responses wire, supportsResponsesCustomTools=false): custom tools translated to a string-input function, grammar degraded, custom_tool_call and custom_tool_call_output history translated - manifest test runs each fixture against the production adapter for its own subject, pins every subject's route, and adds a catalog evidence gate: cited assertion ids must exist in the owning fixture, and a passthrough claim may only cite equals assertions whose expected value is the caller's own input, so grammar loss cannot be labeled lossless No runtime behavior change; manifests stay passive. Refs #2358 * test(compatibility): bind passthrough evidence to the claimed feature A passthrough claim could cite any preserved caller value, so a grammar claim backed by an equals assertion on /body/model passed the gate while the grammar was dropped. Each passthrough-claimable feature now names the selectors that can prove it, grammar evidence must carry a non-empty definition, and unbound features cannot be claimed as passthrough. Refs #2358 * docs(contributing): sync passthrough evidence rule to localized guides Refs #2358
* fix(antigravity): show the Gemini 4 Argon quota group separately retrieveUserQuotaSummary reports Gemini 4 Argon as its own group. The summary parser matched it as "gemini", so its weekly bucket collided with Gem (Weekly) and was dropped, or replaced the Gemini reading when the Argon group came first. The model-list fallback had the same order problem. Each bucket now decides its family from its own id and name (Argon before Gemini), with the group display name only as a fallback. Argon buckets become Argon / Argon (Weekly) windows tagged with the canonical pool model gemini-4-argon, which keeps them out of headroom, exhaustion, reset ordering and reset notifications like the existing model rows. The account reset-time selection now skips model-attributed rows as well. Closes #7272 * docs(structure): state the Antigravity group fallback rules exactly
* fix(google): honor Vertex project endpoints with API keys * fix(vertex): select API-key project endpoints from provider config only Keep #7266's project/location endpoint for API keys, but only when the provider configures project explicitly. Ambient GOOGLE_CLOUD_PROJECT, GCLOUD_PROJECT and GOOGLE_CLOUD_LOCATION stay ADC fallbacks, so a gcloud default in the shell cannot move an express-mode key onto another project. Endpoint selection now lives in src/adapters/google-vertex-endpoint.ts and also derives the thought-signature replay namespace. Every Vertex branch rejects a model id that is not a single path segment before credentials are attached. * fix(vertex): separate express and project replay namespaces Prefix the Vertex replay key with the endpoint kind and encode the project, so a configured project named "api-key" can no longer share express mode's thought-signature namespace. * fix(vertex): treat a blank project as unset and sync translated docs Trim provider.project once so a whitespace-only value keeps API keys on express mode and lets ADC use its environment fallback, and update the project/location rows in the seven translated provider references. --------- Co-authored-by: JUN <jun@lidgeai.com>
) * fix(google): nest Vertex Argon tool-result images * fix(google): separate orphan images from Vertex Argon response batches * docs(google): clarify orphan result ordering guarantee * test(google): cover Argon signature replay with matched and duplicate tool images Seeds a real replay signature, then checks on one continuation that the matched image nests in functionResponse.parts, the duplicate image moves to the following marked user turn, and neither image's bytes leak into text parts. * test(google): cover streaming continuations and error results for Argon tool images The continuation request now runs with stream on and off, and isError results keep matched-image nesting and orphan-image placement. Both cases fail on the pre-#7280 serializer. * test(google): cover API-key project endpoints with Argon tool images Combines #7266 and #7280 on one request: a configured-project API key uses the project endpoint with location global, a projectless key stays on express, and in both the matched image nests in functionResponse.parts while the duplicate image moves to the marked orphan turn. Ambient project/location variables are set to conflicting values and restored. --------- Co-authored-by: JUN <jun@lidgeai.com>
) * feat(combos): let a combo set its catalog row description (#7229) Combos could relabel their Codex picker row with displayName but the row description was always the generated "Routed via opencodex → combo (combo)." text. Add an optional combos.<id>.description, validated like displayName, accepted by the management API (omission keeps the saved value, "" clears) and by ocx combo set --description <text|->. Catalog maintenance recognized OpenCodex-authored rows by that generated prefix, so an overridden row now carries opencodex_routed_origin: "combo-v1". src/codex/catalog/ownership.ts owns both signals and replaces every prefix check (removal, shadow restore, template selection, auto-review, exact-combo admission, native residue). Rows without an override are byte-identical. * fix(combos): re-project the current description onto retained combo rows A combo row kept from the previous catalog when its fresh derivation fails (for example a native-alias combo whose member provider is disabled) bypassed deriveEntry, so changing or clearing the description in config did not reach the picker. Config-aware merges now pass the current combo descriptions and the retained loop re-applies them; a cleared override returns the generated combo text and drops the marker. * fix(combos): reject C1 controls in descriptions; document zh-tw flags Review follow-up for #7229: the description validator now rejects the full Unicode Cc class (C1 included), with NEL/CSI regression cases, and the Traditional Chinese combo guide lists --display-name/--description and the description field like the other locales.
…uest bodies (#7285) * feat(responses): opt-in compression of outbound ChatGPT Responses request bodies (#7247) Codex re-sends the full conversation every turn; over HTTP OpenCodex forwarded it to chatgpt.com identity-encoded. upstreamRequestCompression ("gzip" | "zstd", default off) compresses canonical codex responses/compact string bodies of 1 KiB-16 MiB at the final send in sendWithConnectionPolicy, sets Content-Encoding and drops stale Content-Length. WebSocket frames, other destinations, pre-coded or non-string bodies and codec failures keep today's representation. Compression is synchronous so no await separates dispatch admission from the physical send; the 16 MiB ceiling bounds the event-loop block. The setting is read per send from the live server config installed by setLiveStateStoreConfig. * test(responses): make request-compression assertions prove nesting, fallback and caller immutability Count codec calls, assert Buffer fallbacks with Buffer.isBuffer, snapshot caller headers independently, and route the nested case back through sendWithConnectionPolicy with a barely compressible body so a missing idempotence guard double-codes (driven red once). Also asserts the dispatch receipt precedes executor entry with compression active. * fix(config): refuse unknown upstreamRequestCompression values on live writes The schema keeps degrading a hand-edited unknown codec to identity, but validateConfigCandidate now rejects it so ocx config set and imports report the error instead of persisting success and dropping the value (Codex/CodeRabbit review on #7285). Docs name the CLI setter and the restart requirement.
* feat(accounts): opt in to auto-pause permanent account refusals * fix(accounts): register pause route and extracted Responses owners * fix(accounts): inject refusal observer across transport leaf boundary * Preserve pause ownership through distributed revisions and pacing rewraps * test(responses): cover replay ownership after auto-pause rotation * test(responses): supply the replay conversation header * fix(responses): rebind replay owners after auto-pause rotation * test(responses): require the exact sibling replay identity * fix(accounts): fence auto-pause against policy changes and address review Persist a per-provider accountAutoPausePolicyRevisions UUID, minted only by persistConfigUnlocked from the pre-write file when a tracked provider's effective policy fingerprint changes. Attempts capture revision, local generation, threshold and route; OAuth, API-key and Codex pauses commit only while the in-memory and fresh persisted fence still match, with the OAuth automatic publication serialized under the config mutation lock. Also preserve key pause fields across dual-auth OAuth upserts, keep an omitted accountAutoPause on full provider saves, accept the policy as a canonical-provider overlay, reject non-object pause bodies, degrade malformed pause display metadata, and fix CLI/dashboard pause messages, translations and accessible names. * fix(accounts): count auto-pause refusals only for the credential on the wire sendWithConnectionPolicy now reports the final destination and headers, after plugin rewrites and queued rebuilds, through an init symbol. Auto-pause observers count a response only when that wire credential and destination match the captured attempt; a Codex WebSocket send, which has no HTTP final-send report, counts only while no plugin upstream rewriter is registered. Native Chat, native Messages and the Responses providerFetch path all report the final send. * fix(accounts): report oauthDispatch final sends and fence WebSocket attribution The Responses oauthDispatch send now attaches its auto-pause observer's final-send report. A send without an HTTP report (Codex WebSocket) counts only when no upstream rewriter was registered at capture and the rewriter registration epoch is unchanged at the response, so a rewriter that registers or unregisters mid-send can no longer make a rewritten dial look attributable. * fix(accounts): count a nested physical response once per account A providerFetch observer and the dispatchOverride observer inside it see the same physical response. Count it once per account key, and never let an observer without a final-send report attribute a response that another observer reported as sent with a different credential. * fix(accounts): keep live auto-pause fences across detached config loads A loadConfig() snapshot now adopts only the disk revision; fingerprints and local generations start there only for providers not yet observed, so a detached snapshot that differs from the live config can no longer keep invalidating in-flight fences. API-key quota rows also keep the pause flag and known pause details, matching the plain key listing. * fix(accounts): fence observed disk policy changes across detached loads Track the last observed disk fingerprint separately from the live one. A loadConfig() snapshot advances the local generation when the disk policy differs from the previously observed disk policy, so an external change followed by a restore still invalidates older attempts, while a snapshot that merely differs from the live config does not. * fix(accounts): bind the Codex workspace into auto-pause ownership and reclaim deleted-provider epochs Codex pool and main-pool attempts now own a response only when the final wire request carries the captured bearer, the context's chatgpt-account-id and unchanged organization/project selectors, at capture and in the final-send report. Policy revision records are kept only for providers that exist after disk-only preservation, observed records for deleted providers are dropped, and every new record or advance draws from one process-wide generation counter so a recreated provider cannot revive an older fence. * fix(accounts): never re-enroll an observed-deleted provider from a stale capture Once a config path has been observed, captureAccountAutoPauseFence no longer seeds a missing provider from the caller's config object; only load, reload or save adoption can enroll it. A capture taken from a stale live config while its provider is observed deleted therefore cannot survive an identical restore. * test(accounts): auto-pause attribution reads post-compression wire headers With opt-in gzip request compression enabled, the auto-pause final-send report sees the compressed send's headers (content-encoding set, stale content-length removed) and still attributes a refusal to the credential actually sent.
* feat(providers): explicit single-model completion test Add a user-confirmed, bounded completion diagnostic for one provider and one model, next to the existing no-completion connectivity probe: POST /api/providers/test-completion, `ocx provider test <name> --model <id>`, and a dashboard control in the provider workspace. The runner talks to the upstream through the provider's normal credential, destination and egress path and reports TTFT, total latency and the raw upstream model metadata read before response.model is rewritten. Comparison is metadata only and never claims identity. Refs #2834 * fix(providers): dispose diagnostic translator budget, resolve aliases before wire, count real sends in ingress tests Refs #2834 * fix(providers): admit local cleartext providers and keep gateway routing in completion test Refs #2834 * fix(providers): bound completion-test body reads, round latency, align CLI model check Refs #2834
…7286) * feat(codex): opt-in OS desktop notification for low-quota protection Low-quota protection already pauses Codex Pool accounts and records a "logged" alert, but never reached the operating system. A new opt-in codexPool.lowQuotaProtection.actions.desktop flag (requires notify) hands each notice to the proxy host's notifier: /usr/bin/osascript on macOS, notify-send from a literal system path on Linux. Windows and hosts without a notifier stay "logged". The notice text is a separate argv item (constant AppleScript, "--" for notify-send) and names the account only by its pseudonymous log label. Each in-flight notice is abortable: every episode end (reset boundary, recovery, account removal, policy change, shutdown) kills the child and records one "cancelled". Delivery failures and timeouts record "failed" and retry on a later eligible observation. Armed test processes never reach a real notifier without an injected spawn. Refs #5649 * test(codex): cover notifier cleanup and adapter-composed low-quota delivery Refs #5649 * fix(codex): back off failed low-quota notices and log once per episode A notifier that keeps failing (for example notify-send without a session bus) was respawned and logged on every eligible observation. A failed notice now retries no sooner than five minutes later, and each episode writes its log line once. Refs #5649 * docs(codex): state that low-quota notice cancellation is observation-driven Refs #5649
…6814) * feat(combos): opt-in advisory quota signals for JEV decisions Add per-Combo opt-in decisionQuotaSignals/decisionQuotaTiers so the JEV decision backends can see loaded-only, in-memory advisory quota evidence (limited / nearly exhausted) for the candidate targets. Unset Combos are byte-identical to before; no level or pin behavior is added. Evidence is published by the existing quota producers into a snapshot bound to the credential generation, goes stale after 30 minutes, treats unknown as healthy, and marks a pool nearly exhausted only when every usable account is. Credits are never treated as quota windows. The second Anthropic instance pool is excluded explicitly: only the primary instance publishes or is read, covered by a regression test. Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(combos): address review on advisory quota publication and document touched functions - Keep main-account advisory publication explicit opt-in: setAccountQuotaFromParsed no longer defaults decisionRaw to the policy observation, so a live main writer that omits it publishes no codex-main evidence. Adds a regression test (red before the change). - Parse the usage body once in the reserve capability read and reuse the observation. - Add docstrings to the functions touched by this change (docs only). Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(oauth): keep advisory quota publication from affecting auth-store load and persist Roster publication ran inside the load try, so a publication failure would reach the invalid-config backup path and return an empty store. Publish after the parse, make the auth-owned publisher non-throwing, and withdraw the roster (unknown, not stale) when projection fails. Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(codex): keep advisory quota publication from affecting Codex account-store load and persist Roster publication ran inside the load parse try, so a publication failure reached the invalid-config backup path (spurious codex-accounts.json.invalid-* backup) and propagated. Publish after the parse, make the Codex-owned and main-credential publishers non-throwing, and withdraw the roster (unknown, not stale) when projection fails. Co-Authored-By: Claude Code <noreply@anthropic.com> * test(routing): realign the sweeper generation before the invalid-reset quota tests An earlier file in a shared bun process can leave a failed (incomplete-context) reconciliation behind: owners that ran before the failing one keep the raised fence while the shared generation stays behind, so default-generation Codex quota writers are discarded as stale and the invalid-reset tests saw no advisory window. Reconcile with a complete empty context in beforeEach, and capture the real generation instead of a literal 0 in the WHAM commit test. Co-Authored-By: Claude Code <noreply@anthropic.com> * test(layout): keep the layout registry under the file-size cap after merging dev Both this branch and dev added registry lines; the merged file reached exactly 2000 lines (the ratchet threshold). Put the two entries this branch adds on existing lines, as the neighbouring entries already do. No cap or baseline changed; the registry is back to 1998 lines. Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(jev-quota): register advisory quota publication only while a combo opts in Maintainer review (2026-10-15) asked that core credential stores stop publishing decision-quota rosters for every install. Publication is now activation-owned: - src/lib/decision-quota-sink.ts: core slot; every producer helper is a no-op without a sink. - src/combos/jev-quota-activation.ts: sole runtime importer of the decision snapshot; registers the snapshot-backed sink while a live JEV combo has decisionQuotaSignals true, replays stores once via observe-only reads, detaches and withdraws on the last disable, deletion or config-root change. - Auth/Codex stores, native-main cache and quota producers call the slot; raw-window binding and projection are skipped while inactive, and unbound observations never fall back to display values. - Live-config observer slot in state-store-registrations (live adoption, live reconciliation and published-but-unreconciled combo writes); started/stopped with the optional listener set. - Native-main decision row is owned by the config root that observed the credential; unknown otherwise. - Tests: signals-off zero writes, activation/deactivation/root switch/reentrancy/published-error paths, and a static guard that keeps the snapshot off the stores/router/lifecycle/core graph. * fix(jev-quota): keep a credential-less native main known-unusable across roots CodeRabbit (src/combos/jev-quota.ts:60): root ownership made a confirmed-absent main unknown, so a pool with every account at 95% read as healthy instead of nearly_exhausted. Root ownership now applies only to a retained credential; with none the row is known-unusable as before. Regression added. * fix(codex): keep the core main credential binding on presence loss; retire advisory state separately Presence loss (including transient failed credential reads) cleared mainQuotaCredential and advanced its generation, which dev never did; policy checks that match the observed main bearer (hard lock, caller cooldowns) could then stop matching for every install. The core binding is restored to dev behavior. Decision evidence now uses its own generation and a fresh-observation flag, so absence still retires advisory windows and stale writers. Regressions: signals-off binding survives presence loss; active presence loss retires the main row's windows and writers. --------- Co-authored-by: Claude Code <noreply@anthropic.com> Co-authored-by: JUN <jun@lidgeai.com>
* feat(messaging): add explicit enrolled Codex SSH peers - Added an opt-in foreground owner, private directional enrollment and authenticated same-connection queued delivery with return leases. - Reused shared SSH policy without activating messaging during normal proxy startup or changing local Unix-only defaults. - Added isolated lifecycle, recovery, transport and native-contract regressions with public CLI and ownership documentation. - Qualified isolated loopback SSH and stock Codex 0.160.1; integrated suite and independent security review are being completed before review readiness. * fix(messaging): join unpublished remote tunnel cleanup - Join both owned helpers before propagating startup configuration changes or cleanup failures. - Bound native qualification fixture requests by their cancellation budget and keep test registrations within the existing layout size cap. - Passed typecheck and six corrected lifecycle regressions; independent delta review found no new security issue. Final rebased integration qualification remains separate. * docs(messaging): record rebased contribution qualification boundary - Refresh the individual-peer contribution baseline and completed preparation sequence. - Record the full-suite resource exception without claiming a passing run or relaxing gates. - Preserve hosted CI, macOS interoperability and maintainer acceptance as separate outstanding requirements. - Verified range-diff equivalence, typecheck, privacy, ownership, generated surfaces and 259 focused regressions after rebase. * test(messaging): wait for native turn history after queue acceptance - Assert the stock daemon pre-history state before submitting a fixture message. - Poll only exact known read-only history errors within the existing deadline; keep queue submission outside the polling loop and sanitize other errors. - Verified the isolated stock 0.160.1 gateway queue, completed synthetic turn, correlated reply and owned cleanup: one pass, six assertions. - Independent fixture-delta review found no concern; no production behavior changed. * fix(messaging): enforce remote admission and cleanup ownership - Bind enrollment completion and recovery cleanup to the current transaction under one store lock; invalidate recovery before publishing revocation. - Revalidate source authority before remote submission without retiring unrelated peers or replaying unknown outcomes. - Retain withdrawn tunnel cleanup joins and bound logical helper settlement while charging unresolved physical children. - Reserve eight persistent and two transient helper slots; cover Darwin listener polling with isolated fixtures. - Verified 283 focused tests, real loopback SSH and stock Codex round trips, typecheck, privacy, structure, surface and docs checks; broader changed-test qualification remains incomplete. * fix(docs): refresh remote messaging contribution base - Record the latest dev base and unchanged five-patch rebase for the remote messaging contribution. - Update the handover publication boundary to reflect user authorization while keeping deployment separate. - Revalidated 283 focused tests, isolated SSH and stock Codex round trips, typecheck, privacy, structure, surface and docs build; broad changed-test selection remains incomplete at its documented ceiling. * fix(messaging): recover enrollment and retire stale remote routes - Add exact-transaction enrollment abandonment with explicit unconfirmed remote cleanup and correlated receiver-capacity refusal. - Accept trusted configuration parents while keeping messaging storage private; tolerate only a missing Linux IPv6 listener table. - Fence return-lease replacement against live generations and retire unexpected tunnel loss after joined cleanup. - Synchronize CLI metadata, generated references and architecture/user documentation. - Validate with 294 passing focused regressions, six skipped cases, typecheck, privacy, structure, surface checks and the 569-page docs build. * fix(messaging): scope cleanup and refresh leases before readiness - Guard receipt-driven cleanup by the exact enrollment transaction under the mutation lock so old receipts cannot revoke replacement peers. - Renew return leases within the shared startup deadline before readiness, and join helper exit with natural pipe EOF without signalling historical process groups. - Add stale-receipt, slow-startup, renewal-failure and descendant-pipe regressions; synchronize CLI references and lifetime documentation. - Verified 302 focused tests, typecheck, privacy, structure, generated surfaces, the docs build and disposable SSH enrollment/duplex delivery; broader suite and macOS qualification remain outstanding. * fix(messaging): harden enrollment durability and helper draining - Keep malformed recovery journals from blocking peer revocation while preserving matching-journal invalidation safeguards. - Sync published and removed journal entries before dependent work; report uncertain crash durability explicitly. - Drain discarded helper output to natural EOF, preserve first failures, and retain incomplete-cleanup evidence and capacity. - Add regression and fault-injection coverage; update storage, cleanup and CLI documentation. - Verified 318 focused tests, typecheck, privacy, structure, surface and docs build; the 180-second changed-graph run remains incomplete. * fix(messaging): isolate revocation keys and normalize SSH probes - Preserve alias-prefixed private host-key records despite HashKnownHosts user defaults, without changing pinned trust policy or normal known_hosts files. - Isolate each revocation attempt and report committed local removal even when preparing or sending remote cleanup fails; remove owned scratch files in finally. - Complete the structure source map, regenerate its index, and update messaging and Remote Link documentation. - Added five targeted regressions: all failed against the old implementation and pass after the fix; the disposable SSH fixture now enables HashKnownHosts. * fix(messaging): classify malformed local enrollment journals - Share strict journal interpretation between enrollment retries and recovery metadata reads, preserving original evidence and storage/lock errors. - Cover malformed JSON, outer/nested records and invalid capabilities at the enrollment and CLI boundaries; document explicit operator recovery. - Verify 43 enrollment tests and strict typecheck; broader messaging and documentation qualification follows before publication. * fix(messaging): bind remote admission to peer consent - Reconstruct envelopes against authenticated peer identity and separate outbound enrollment from explicit local inbound consent. - Bound one-shot correlated reply routes across consent changes, native rejection and uncertain delivery. - Isolate pre-auth capacity and clean attempt-owned enrollment pins without disturbing recovery journals. - Add regression and contract documentation coverage; 388 focused tests pass under Bun 1.4.3, including isolated native and SSH interop. - Verify typecheck, privacy, structure, generated surfaces and docs; broad changed-graph lane remains incomplete at its 180-second ceiling. * refactor(messaging): clarify remote admission and cleanup branches - Expanded connection retirement, queue rejection and reply-grant settlement into explicit ordered blocks. - Split envelope validation into readable guards while preserving the sanitized public error and canonical attribution checks. - Clarified enrollment journal publication and scratch cleanup without changing lock or recovery semantics. - Validated 105 focused regressions, 114 import-connected integration tests and nine file-size checks; typecheck, privacy and structure checks passed. * fix(test): clean up partially started messaging owners - Move both fixture owner starts into the cleanup scope and await all initialized owners on failure. - Preserve the original startup error and successful fixture behavior. - Verified Bun 1.4.3 typecheck, whitespace checks and 138 focused tests; two opt-in integration tests skipped. * fix(messaging): keep owner connection slots out of enrolled peers' reach Review item 3 asked that unauthenticated sockets not starve the owner. The pre-auth cap covers silent clients, but every authenticated peer socket still drew from the same 16-slot pool that local owner control, outgoing probes and lease renewal use, so enrolled peers holding sockets could make the next renewal fail and retire the owner. Authenticated peer sockets now share twelve connections; four stay reserved for the owner's own paths. There is deliberately no per-peer share: capping a peer at its fair share (three) let three legitimate in-flight sends refuse that peer's own lease exchange and retire the owner. Docs and structure state the remaining fail-fast contract: one enrolled peer can still occupy the peer share, and an initiated peer can end the owner by failing lease renewal. * test(messaging): prove the review guards are not vacuous Adds regressions for receiver-bound attribution variants, concurrent replies on one route, consent withdrawn during a suspended lookup, repeated RPC ids, cross-socket replay of a captured authorize proof, lost-outcome grant consumption, and messaging SSH consumers going through the shared argv builder. The overlapping-enrollment scratch test now records observations in the SSH runner and asserts outside it, so a shared scratch name fails an assertion instead of surfacing as enrollment_unknown. --------- Co-authored-by: JUN <jun@lidgeai.com>
…pic (#7341) * feat(anthropic): default prompt-cache TTL to 1h on first-party Anthropic Unset cacheRetention now resolves to long (ttl 1h) for api.anthropic.com (API key and OAuth pools) on the translated adapter, the native /v1/messages passthrough, and the translated /v1/messages lane. Anthropic-compatible endpoints keep 5m. Explicit config and caller-pinned 5m breakpoints still win. 1h cache writes reported by Anthropic are priced at 2x base input. * fix(anthropic): carry 1h cache-write share through merges and Messages output * fix(anthropic): keep Zed on 5m and carry the 1h write share through every usage path Zed borrows the api.anthropic.com body builder but sends to its own gateway; thread cacheRetention through and keep the omitted default at 5m. Parse cache_write_1h_tokens from Responses usage, claude-cli stream usage, the combo summary projection and the native steering log. Treat tool input_examples as caller data. * fix(responses): parse the 1h cache-write share from Responses upstream usage
) With Claude Code CLI first-party on, ~/.claude/settings.json sets HTTPS_PROXY to OpenCodex's own intercept listener (http://opencodex:<token>@127.0.0.1:<port>), and every process Claude Code starts inherits it. Installing or restarting the service from such a shell baked that URL into the service definition, so the proxy sent its own outbound traffic back through its intercept listener and the per-install token ended up in the wrapper script. resolvedProxyEnv now skips the token-bearing intercept URL and falls through to the lower-case spelling when it holds a real proxy. A tokenless loopback proxy such as a local Clash or v2rayN port is still baked.
…7352) * fix(sidecar): pass pacing-queue overload through image and web-search loops When an image-bridge or web-search loop iteration hit a full request-pacing queue (or an exhausted key pool), the header-phase catch wrapped the RequestPacingQueueOverloadError into LoopError(502, "Provider unreachable"). The caller saw a 502 upstream failure instead of the 429 overload answer with Retry-After that every other route returns. Rethrow the overload like the shared transport classifier already does, so the handler's requestPacingOverloadResponse maps it. Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(bridge): keep the adapter's usage on a translator-overflow terminal When an adapter raised `translation_buffer_limit` as an error event, the bridge handed it to `terminateForTranslatorOverflow`, which ignored its argument and synthesized a usage-less `response.failed`. A turn the provider had already billed was therefore logged with zero usage and cost. The overflow terminal now reports the event's usage through `onUsage` and on the `response.failed` frame, as the ordinary error terminal already does. The client-facing error is unchanged. Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(sidecar): map provider input overflow to context_length_exceeded An upstream 413 (or a 400/422 carrying a definite context-overflow message, or an adapter's own context_length_exceeded event) behind the web-search or image sidecar leaked out as a generic upstream failure, so Codex resent the identical oversized payload through its retry budget instead of compacting. One classifier in context-overflow.ts now serves both loops: the sidecar boundary maps a first-iteration failure to the main path's streaming or JSON overflow response, and both loops end a later iteration's overflow with the same terminal event. Combo attempts keep their raw failure for the combo layer, which already maps a final 413 itself. Closes #7316 * fix(sidecar): keep combo evidence and non-replayable failures on overflow Review follow-up for #7316: - A worded in-stream overflow keeps its status and provider wording beside context_length_exceeded, so combo stream preflight can still hop to a larger-context target; only a bare 413 gets the proxy-owned message. - Rate-window wording ("too many tokens per minute") and an explicit rate_limit_exceeded code are never classified as an overflow. - A first-iteration failure marked x-should-retry: false keeps its status and header instead of inviting a compacted resend. - Document the sidecar overflow contract in structure/transports/responses.md. * fix(sidecar): classify overflow where the loop still has the evidence Round-2 review follow-up for #7316: - The loops classify each failure with its status, wording, upstream error.code and non-replayable mark, and tag a qualifying first-iteration JSON failure; the sidecar boundary maps only tagged responses instead of re-parsing the loop's envelope. - A non-replayable failure (HTTP or adapter event) keeps its own verdict mid-stream too, so it never invites a compacted resend. - An upstream rate_limit_exceeded code survives into classification, so a "too many tokens" rate refusal is not read as an overflow. - A 413 with definite overflow wording keeps that wording for combo failover; only a status-only 413 gets the proxy message. * fix(sidecar): keep a non-overflow verdict typed through the SSE bridge Round-3 review follow-up for #7316: when the sidecar classifier keeps a failure (non-replayable, or an upstream rate_limit_exceeded) but its wording would match the bridge's context-window heuristics, the in-stream event now carries an explicit code, so classifyError cannot rename it context_length_exceeded on the wire. --------- Co-authored-by: Vadym O <bolein95@gmail.com> Co-authored-by: Claude Code <noreply@anthropic.com>
* ci(release): sign Windows binaries and MSI via SignPath (#7207) Submit the standalone ocx.exe and the desktop MSI to SignPath Foundation from the release workflow, verify the returned Authenticode signatures on the Windows runner, and regenerate the Tauri updater signature over the signed MSI before the assets are renamed, checksummed and verified. Signing never blocks a release: missing or partial configuration, SignPath outages, timeouts, rejections and verification failures all keep the unsigned file with a warning, and a test-signing policy never signs a real release. A dispatch-only Windows signing test workflow exercises test-signing end to end without publishing. * docs: Windows code signing policy and verification (#7207)
…) (#7353) * fix: project hosted-search history during native Lite compaction * fix(responses): project hosted-search history when no search tool is declared (#7250) Native Sol answers a replayed web_search_call without a matching web_search declaration with a generic server_error. Project unreferenced cells into the existing bounded reference notes whenever the final body declares no hosted search, on every Responses destination; declared requests keep structural history. Also translates the comments carried over from #7268 into English. * fix(web-search): replay sidecar search results to routed models (#7269) Codex replays a hosted web_search_call cell without its result text, and the parser dropped it for routed providers, so a model whose turn ended on a client tool call forgot it had searched and repeated the search and the tool. Rebuild the cell as a web_search call/result pair when search is declared, and let the sidecar loops record the result under the emitted cell id so the next turn restores it, scoped to caller and conversation. * fix(web-search): rebuild replayed searches at the input level and drop them without a sidecar Review round 1: the parse-time pair could call an undeclared web_search tool when no sidecar plan resolves, split a parallel client batch, and collide with client call ids. Rewrite cells into function_call/output items before the item loop, defer the output past the following call batch, allocate collision-free call ids mapped back to cell ids, and remove the pairs when the search plan is undefined. * fix(web-search): answer a replayed search before the next client batch Review round 2: a deferred search output crossed into the following assistant turn when consecutive client batches followed the cell, and a restored failed search lost its error flag. Flush the deferred output when a call follows the batch outputs, and set the flag independently of the restored text. --------- Co-authored-by: Junming Feng <12311031@mail.sustech.edu.cn>
* refactor(providers): remove opencode-free with config migration * docs(providers): document OpenCode Free removal across locales * docs(providers): recount presets after OpenCode Free retirement * fix(config): keep retired OpenCode references pruned across saves * docs(providers): clarify retired OpenCode reference migration
…safe (#7298) (#7354) * fix(combos): keep tool loops on one target and make failover history safe (#7298) A combo re-picked its target on every request, so the request carrying a tool result could land on a different model than the one that issued the call. A GPT turn leaves no reasoning item, and DeepSeek's thinking mode refuses a bare tool continuation with HTTP 400 ("The reasoning_text in the thinking mode must be passed back to the API"). - Pin a tool-output continuation to the lane's previous combo target while it is enabled, still a member, out of cooldown and eligible; skip the JEV decision for it and record reason combo-tool-loop-pin. New user turns re-pick as before. - When a switch is unavoidable, give every bare assistant tool-call turn a reasoning_text " " item on strict plaintext-replay Responses destinations (the Responses twin of the #5421 Chat placeholder). - Apply the Gemini-only thought-signature sentinel on AI Studio, as Antigravity and Vertex already do, for calls another model issued. Closes #7298 * test(deepseek): expect the bare-turn reasoning placeholder on the strict wire (#7298)
) (#7355) * fix(combo): retry zero-output response.incomplete with no reason A combo target that ends with `response.incomplete` before any output and without `incomplete_details.reason` was accepted as the turn's answer, so the caller got an empty incomplete turn instead of failover to the next target. Treat a missing reason like the transport reasons already listed; semantic reasons such as max_output_tokens still commit the target. Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(combos): hold the turn lease across the failover ladder Each combo child relay binds the turn admission lease to its own controller and unbinds it when its stream ends; the lease releases once nothing is bound. When target 1 returned 200 SSE and then failed before output, the combo cancelled that relay, its unbind released the parent's lease, and target 2 was aborted on bind with "turn already settled" (502). handleComboResponses now binds its own controller for the whole ladder and unbinds it on return. The accepted child's stream is bound before that, so it keeps the lease until it ends. Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(responses): count Combo recovery sends in the shared send budget * fix(responses): preserve reserved Anthropic pool recovery sends * test(adapters): assert exact combo cooldown rejection and single refund * fix(combo): log the upstream refusal reason on combo target failure The combo hop warning printed only `<target> failed with 401 after Nms`, so a revoked credential or plan downgrade logged hundreds of identical lines that read like a provider outage. Append the upstream error code and parsed message (falling back to the normalized body text), collapsed to one line, redacted and capped at 200 characters via sanitizeLogMetadataString. Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(combo): log only the parsed upstream code and message on a hop failure Drop the classificationText fallback so an unparsed upstream body never reaches the warning line; the log boundary is now the two parsed fields. Co-Authored-By: Claude Code <noreply@anthropic.com> * fix(combo): redact failure fields before flattening log metadata Preserve credential framing until the shared redactor has removed credential values. Cover multipart framing in a parsed upstream code at the actual combo hop warning boundary. Co-authored-by: Vadym O <bolein95@gmail.com> * fix(combo): retain output carried by reasonless incomplete snapshots A terminal-only upstream can include text or tool items in its final snapshot. Keep that response committed, and cover explicit semantic/unknown reasons and output-first streams as well. Co-authored-by: Vadym O <bolein95@gmail.com> * fix(combo): unbind only registered turn lease controllers Match registerTurn capability checks for plain admission leases so the ladder does not report a spurious release miss. Add accepted fallback stream completion, cancellation and caller-abort coverage with exactly-once attached lease settlement. Co-authored-by: Vadym O <bolein95@gmail.com> * docs(combo): describe incomplete, lease and recovery-budget boundaries * docs(structure): split combo streaming boundaries within the line budget --------- Co-authored-by: Vadym O <bolein95@gmail.com> Co-authored-by: Claude Code <noreply@anthropic.com> Co-authored-by: Epinephrine <luvs01@hanmail.net>
… assertions (#7358) The pricing-cache case asserted warm-cache reuse while startServer's unawaited config-dir ACL harden was still rewriting inherited ACEs; on NTFS that moves usage.jsonl ChangeTime and the aggregate cache correctly rebuilds. Drain the flight first. AUTH-11 billed each writer's icacls work (registration hardening plus the exit drain, 30 s budget each) to the parent's 15 s registration deadline. ACL policy has its own suites; the fixture now pins the ACL platform gate off.
…MP aliases (#7359) * test(temp): resolve TEMP and the locked path with one native resolver Hosted Windows runners export TEMP as C:\Users\RUNNER~1\... while test paths arrive long-form. containedRunTemp used the JS realpath, which keeps 8.3 spellings, so the containment check never matched and the final-EPERM quarantine from #6861 never ran on CI: a 15 s external hold failed the case instead. Resolve both sides through diagnostic.realpath, defaulting to realpathSync.native. * test(temp): pin the native resolver as the containment default
…7363) Removing the handshake data listener does not pause a flowing socket, so a TLS ClientHello that arrived before the fixture's upstream connected was dropped and the dial stalled until its 10 s deadline (macOS run 39215956943). Pause until pipe() resumes; add a delayed-upstream regression.
… it starts (#7362) * fix(launcher): scope an inherited transpiler cache to the Bun version it starts The CI shard cache is shared by the test-runner Bun (1.4.3) and the bundled runtime the launcher starts (1.4.2). Bun keys .pile entries by source hash and deletes entries written in another release's format, so each version evicted the other's on every start and launcher children loaded the CLI graph cold (15 s Windows spawnSync timeout, run 38697651428). Pass the child <cache>/bun-<version>; leave disabled/unset caches and overrides untouched. Drop the attest test's cold budget now that the cause is gone. * fix(launcher): match the cache variable case-insensitively on Windows
…ng idempotent (#7364) * fix(runtime): scope server children's transpiler cache and keep scoping idempotent Server spawns of the bundled runtime (startup-health probe, dashboard startup install, Windows tray) bypassed the launcher and still evicted the test runner's cache. Scope them through durableBunChildEnv when the child is a different Bun version; re-scope an already scoped path in place; accept prerelease/build versions; type the helper. * fix(runtime): keep the root when re-scoping a root-level transpiler cache * fix(runtime): re-scope relative and drive-relative transpiler caches in place
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
Contributor
|
✅ Deterministic PR hygiene checks passed. |
Contributor
⏳ DRAFT
What to do
Its title has been prefixed with |
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.
Summary
This promotes the frozen
devcandidate52c326b479d0d5a7549d35663042f0731861202dtomainas stable 2.89.0. The promotion head merges inmainancestry with theoursstrategy, and its tree is exactly the candidate tree (99b3f420c3). The candidate already sets the version to 2.89.0 in package.json, desktop tauri.conf.json, Cargo.toml and Cargo.lock. The dev pre-move is #7371 (dev → 2.90.0), merged before this promotion.2.89.0 carries the fixes and features merged since 2.88.0:
context_length_exceeded([Bug] Upstream HTTP 413 is not mapped to context_length_exceeded on the web-search/images sidecar path #7316, absorbs fix(sidecar): pass pacing-queue overload through image and web-search loops #7319, fix(bridge): keep the adapter's usage on a translator-overflow terminal #7322).cacheRetentionto 1 hour for OAuth (subscription) accounts #7294).Verification
52c326b479: manual Cross-platform CIlane=allrun 39221379295 completed with success (windows 1–9/9, macos 1–3/3, macos control, Linux test 1–4/4, gates, desktop shell). Service lifecycle run 39221407401 succeeded on the same SHA.c344c6ca10and the launcher delta re-verification passed on7dfc1412b4(remaining source-invariant oracles fixed by test(launcher): assert the scoped env and versioned bundled runtime in source oracles #7365).release.ymlruns as a dry run, then live withexpected-shaset to that SHA.Main-review disposition. Promotion from
devtomainand npm releases are maintainer-controlled (MAINTAINERS.md). The project owner authorized this release, so the promotion merges with owner authority (--admin). The PR targetsmaindeliberately, so anenforce-targetwrong_base failure is expected (as in #7094, #7110, #7249 and #7264).Checklist