From 137d6a7270e7ecfb1c791993800a17c0e30022d9 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 7 Sep 2026 06:31:28 +0900 Subject: [PATCH 001/412] chore(release): open dev at 2.46.0 before releasing 2.45.0 (#3812) Move dev to 2.46.0 before publishing 2.45.0. The owner explicitly authorized this release train and maintainer integration. Official pre-move workflow34061256762 passed the unused-version and release-version-line checks. This PR changes package.json only. Frozen release source cf9f662190c4c6770697c45c870941509cc98f9c is being validated by Cross-platform CI34061274315 and Service lifecycle34061276621; those pending runs are not claimed passing. Release publication remains gated on candidate and exact release-branch evidence. Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 34b7649856..bdf30eb215 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@bitkyc08/opencodex", - "version": "2.45.0", + "version": "2.46.0", "description": "Universal provider proxy for OpenAI Codex & Claude Code — use any LLM with Codex CLI/App/SDK and Claude Code", "type": "module", "main": "./bin/package-main.mjs", From e963aa6bde54522c883b57da0dfd073bc4022cfa Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 07:35:45 +0900 Subject: [PATCH 002/412] docs: plan platform validation follow-up Record scoped roadmap and independent plan audit. Local suites are excluded by owner instruction; final remote CI will verify the combined candidate. --- .../260907_platform_validation/000_plan.md | 31 +++++++++++++++++++ .../001_plan_audit.md | 5 +++ .../010_oauth_teardown.md | 14 +++++++++ .../020_container_smoke.md | 25 +++++++++++++++ .../030_container_ci.md | 21 +++++++++++++ .../035_body_diagnostics.md | 17 ++++++++++ .../040_residual_evidence.md | 15 +++++++++ 7 files changed, 128 insertions(+) create mode 100644 devlog/_plan/260907_platform_validation/000_plan.md create mode 100644 devlog/_plan/260907_platform_validation/001_plan_audit.md create mode 100644 devlog/_plan/260907_platform_validation/010_oauth_teardown.md create mode 100644 devlog/_plan/260907_platform_validation/020_container_smoke.md create mode 100644 devlog/_plan/260907_platform_validation/030_container_ci.md create mode 100644 devlog/_plan/260907_platform_validation/035_body_diagnostics.md create mode 100644 devlog/_plan/260907_platform_validation/040_residual_evidence.md diff --git a/devlog/_plan/260907_platform_validation/000_plan.md b/devlog/_plan/260907_platform_validation/000_plan.md new file mode 100644 index 0000000000..d1b3cb632f --- /dev/null +++ b/devlog/_plan/260907_platform_validation/000_plan.md @@ -0,0 +1,31 @@ +# Platform verification follow-up + +Baseline: dev `137d6a7270e7ecfb1c791993800a17c0e30022d9` (2026-09-07). + +## Objective and authority + +Satisfy the existing platform contracts for #3383, #3449, #3522 and #3573. The owner requested ordinary manual PRs, top-of-stack CI first, lower-layer CI only to diagnose a failed final run, no local test suites, push with --no-verify, admin merge after verification, and original contributor credit in commit trailers. No native GitHub stack registration. No publish, release, global settings changes, admission-limit increases, ACL relaxation, or speculative recovery policy. + +The initial assigned checkout contains unrelated dirty work and is preserved. Work lives in an isolated worktree. No SessionStart FSM binding is available in the supplied context; this record documents the work without claiming automatic loop continuation is armed. + +## Evidence and scope + +Dockerfile, compose.yaml, docker/bootstrap-token.ts and the source-build guide already exist. Cross-platform CI has no real image build/start/recreate check. #3522 requires same-process Windows recovery evidence; #3573 requires actual rejected compact-byte evidence. Existing diagnostics must be checked before adding anything. PR #3383 is a mixed historical source: only Windows temp/teardown residuals are in scope, not picker controls. + +Original Docker contributor: Buseong Kim , verified from original #3421 commit metadata. Carry this identity in commit trailers. + +## Dependency map + +1. `010_oauth_teardown.md`: drain the asynchronous ACL fixture before deletion. +2. `020_container_smoke.md`: executable isolated container acceptance probe. +3. `030_container_ci.md`: CI consumes that probe and gates its result. +4. `035_body_diagnostics.md`: distinguish declared size, observed lower bound, and decoded size without changing admission. +5. `040_residual_evidence.md`: settle the Windows/spill/compact residuals; implement only a proven narrow gap through a plan amendment, otherwise preserve open status. + +The manual review chain contains the independent OAuth fixture carry, bounded body diagnostics, the container probe, then its dependent CI integration. Independent code is prepared in disjoint files; the top CI validates their combined tree. Existing workflow triggers remain honest: final branch workflow_dispatch supplies the complete integration result; lower PR runs are not represented as passed if skipped/cancelled. Every implemented layer is reviewed, and final head is pinned before CI. After successful final CI, merge bottom-up using merge commits so reviewed commit ancestry survives. Revalidate the resulting integration and distinguish unrelated concurrent dev changes. + +## Verification and completion + +Local suites and typecheck are NOT RUN by owner instruction. Syntax and read-only diff checks are allowed. The real verifier is GitHub Cross-platform CI on the final branch, including the new Docker job. A failed final run is diagnosed on the smallest affected scope; do not repeatedly run passing gates. Independent Astra high review covers functionality and workflow/security boundaries. Security working notes remain in scratch, not this public unit. + +Completion means verified deliverable PRs merged with commit attribution, plus explicit no-op/blocked disposition for unavailable field evidence. It does not mean every original issue is fixed. New product/security policy choices remain outside scope. Evidence and final outcome are appended to this unit; workflow run URLs and SHAs are preserved. diff --git a/devlog/_plan/260907_platform_validation/001_plan_audit.md b/devlog/_plan/260907_platform_validation/001_plan_audit.md new file mode 100644 index 0000000000..96ac86c266 --- /dev/null +++ b/devlog/_plan/260907_platform_validation/001_plan_audit.md @@ -0,0 +1,5 @@ +# Plan audit disposition + +Independent Astra high reviewer: NEAR-PASS. OAuth teardown and bounded body diagnostics passed within scope. Three Docker/CI conditions were incorporated before implementation: explicit final lane=all executed-job inventory; isolated project/image/port and bounded cleanup; concrete readiness/admission/catalog/persistence checks before and after actual replacement. + +Main judgment: pass with those amendments. Scope remains unchanged: existing Docker contract verification, test-fixture teardown, bounded diagnostics. Live spill recovery and exact historical compact-body proof remain deferred. No local suites or typecheck were run. diff --git a/devlog/_plan/260907_platform_validation/010_oauth_teardown.md b/devlog/_plan/260907_platform_validation/010_oauth_teardown.md new file mode 100644 index 0000000000..d4ee405020 --- /dev/null +++ b/devlog/_plan/260907_platform_validation/010_oauth_teardown.md @@ -0,0 +1,14 @@ +# OAuth fixture teardown carry + +Original source: #3383 commit 51726d2c7c58146defdd6088aefa2b95a1e58553. +Original contributor: x3M3x (Git commit metadata). + +## Concrete delta + +MODIFY `tests/oauth/oauth-store-multi.test.ts` only: import flushConfigDirHardeningForTests and the async ICACLS test runner; stub synchronous and asynchronous runners consistently in setup. Change teardown to await the tracked hardening work before resetting runners/caches, restoring OPENCODEX_HOME, or removing the fixture. Preserve removeTreeWithRetry and all production semantics. Add a deterministic held-async-runner regression against the actual cleanup routine if the existing fixture seams allow it without a new production test API. + +Production path proof: store reads call hardenConfigDir; config/paths tracks asynchronous directory hardening; resetHardenedStateForTests clears caches but does not drain those jobs. Deletion retries alone do not ensure ordering. The prior carry #3258 only replaced the removal function. + +## Acceptance + +No real asynchronous ICACLS escapes the fixture runner. Cleanup waits while a controlled ACL flight is unresolved and only deletes/restores environment after completion. The same OAuth test file passes in final Linux/macOS/Windows CI. Local tests/typecheck are NOT RUN by owner instruction. No numeric-open-flags change is included without current Bun reproduction. No new API/auth policy, credentials, or production runtime change. diff --git a/devlog/_plan/260907_platform_validation/020_container_smoke.md b/devlog/_plan/260907_platform_validation/020_container_smoke.md new file mode 100644 index 0000000000..17d7139d35 --- /dev/null +++ b/devlog/_plan/260907_platform_validation/020_container_smoke.md @@ -0,0 +1,25 @@ +# Container smoke executable + +## File delta + +NEW `scripts/ci/docker-smoke.ts`: bounded Bun-native TypeScript probe for the existing source-build Compose contract. Reuse the canonical compatibility generator and docker/bootstrap-token.ts; do not add an alternative token writer or deployment configuration. The probe creates a unique temporary Compose project and image, builds the actual Dockerfile, bootstraps a freshly generated throwaway token through stdin, starts the hub, verifies health and data-plane admission, recreates the container on the same named volumes, and verifies persistent state again. Cleanup is limited to the unique test project and its generated artifacts. Never use an operator project, host home, provider credentials, global docker prune, or real upstream inference. + +MODIFY owning documentation only as needed to explain the CI acceptance scope and its limits; no claim of upstream-provider validation. + +## Acceptance + +- Real image builds from the checkout with a generated compatibility manifest. +- Read-only/non-root Compose service becomes healthy; requests without a token are refused. +- A synthetic catalog in the separate Codex volume is served with the throwaway token, proving admission and persistence without provider access. +- /readyz succeeds separately from liveness, token reinitialization fails without replacement, and effective container restrictions are verified. +- Token/config/catalog persist across an actual container replacement (different container id, same volumes). +- Failures and cleanup are bounded; token/body contents never appear in logs. +- Existing Docker settings and defaults remain unchanged. + +Run only in final remote CI. Locally perform source/static inspection, not the smoke or a test suite. Read the current lifecycle/API contracts before implementing assertions. + +## Audit amendments + +Use explicit unique project on every Compose command, unique image tag via a temporary override, controlled Compose environment, and loopback ephemeral host port. Preserve pre-existing generated files; cleanup must fail the probe if it cannot remove its own project resources. Bound every child, output capture and cleanup; terminate/reap timed-out children. Never print raw runtime logs or complete inspect output. + +Before/after replacement: require readyz 200 with status ready; authenticated catalog 200 with exact synthetic fixture; missing/wrong token 401 for catalog, Responses and compact. Second bootstrap must fail and preserve the original token while rejecting the proposed replacement. Verify different container IDs, identical named-volume identities and persistent config/catalog evidence without reseeding; check effective non-root UID and read-only root. diff --git a/devlog/_plan/260907_platform_validation/030_container_ci.md b/devlog/_plan/260907_platform_validation/030_container_ci.md new file mode 100644 index 0000000000..28f3e08fc9 --- /dev/null +++ b/devlog/_plan/260907_platform_validation/030_container_ci.md @@ -0,0 +1,21 @@ +# Container CI integration + +Depends on the committed probe from phase 1. + +## File delta + +MODIFY `.github/workflows/ci.yml`: include Dockerfile, compose.yaml, .dockerignore and docker/** in relevant scope detection; add an ubuntu-latest Docker smoke job using the existing pinned checkout and setup-project-bun action; invoke the script after installing required project dependencies if the generator needs them. Preserve read-only workflow permissions and persist-credentials false. Add the job to aggregate ci needs so failures cannot silently pass. No registry publishing, credentials, native stack integration or changes to existing suite retry/concurrency policy. + +MODIFY `tests/ci-workflows/ci-workflows.test.ts`: extend the existing source-oracle checks for scope paths, direct aggregate dependency, pinned actions, and actual probe invocation. Keep existing domain/layout registration unchanged by using the owning test file. + +MODIFY `docs-site/src/content/docs/guides/remote-hub.md`: describe image lifecycle validation and separate readiness/provider-auth limitations. + +## Acceptance and verifier + +Final-branch Cross-platform CI workflow_dispatch must run the smoke and the existing platform gates. The Docker job's failures must reach ci. Local suite/typecheck NOT RUN per owner. Independent review checks full workflow event, permission, input, credential, and cleanup boundaries before publishing. Existing source-oracle tests execute remotely in CI. + +Publish branches with --no-verify; do not claim lower-layer CI if only the final tree was tested. Final failure permits narrower runs. User authorized admin merge of verified layers; original author names/emails come from source commit metadata and are included as Co-authored-by trailers. + +## Final execution inventory + +Dispatch existing Cross-platform CI with lane=all on the immutable final head. Record each expected job and actual conclusion: Docker, four Linux shards, storage-policy, api-usage, gates, two macOS shards, macos-control, six Windows shards, keyring jobs, any selected npm packaging jobs, and ci. Aggregate green alone does not prove Windows or Docker ran. Explain legitimate scope skips instead of counting them as tests. diff --git a/devlog/_plan/260907_platform_validation/035_body_diagnostics.md b/devlog/_plan/260907_platform_validation/035_body_diagnostics.md new file mode 100644 index 0000000000..5165526583 --- /dev/null +++ b/devlog/_plan/260907_platform_validation/035_body_diagnostics.md @@ -0,0 +1,17 @@ +# Bounded inbound-body diagnostic semantics + +Issue #3573 requests usable size evidence. The existing error stores a byte value but returns only the admission limit; the byte value currently mixes declared length, observed wire bytes, an artificial limit+1 lower bound, and exact decoded length. + +## File delta + +MODIFY `src/server/request-decompress.ts`: extend DecompressedBodyTooLargeError with a closed measurement category and retained limit, preserving existing constructor call compatibility. Annotate existing throw sites: declared_wire, observed_wire_lower_bound, decoded_exact, decoded_lower_bound. Append a bounded numeric/category suffix to the current message so existing core.ts error mapping carries it. No request body, path, headers, item counts, further inflate/read, admission-limit changes, or new retry semantics. + +MODIFY `tests/usage/request-decompress.test.ts`: extend small-cap fixtures to verify identity/gzip/zstd/deflate and declared/fragmented input semantics. In particular, limit+1 remains a lower bound, never exact size. Verify HTTP 413 and existing error code/type through existing handler mapping. Preserve stream cancellation. + +MODIFY `docs-site/src/content/docs/reference/proxy-formats.md`: explain wire declared length vs measured/lower-bound diagnostics, separately from compact-response limits. State that Bun listener rejection may happen before application diagnostics and that this does not measure the exact historical compact payload. + +## Acceptance + +Unchanged 256 MiB listener/decoder limit and rejection classification. No context-window wording that causes errors.ts to reclassify the failure. Message remains bounded, only fixed categories and finite numeric values. Negative tests run in final remote CI; no local test/typecheck. Keep #3573 open pending exact real compact evidence. + +This is a new diagnostic refinement of an issue, not a carry of a new contributor PR. Credit reporter @nowhere1975 in commit prose without inventing name/email. Any borrowed existing PR patches must additionally retain their actual git author trailers. diff --git a/devlog/_plan/260907_platform_validation/040_residual_evidence.md b/devlog/_plan/260907_platform_validation/040_residual_evidence.md new file mode 100644 index 0000000000..f5466a4d38 --- /dev/null +++ b/devlog/_plan/260907_platform_validation/040_residual_evidence.md @@ -0,0 +1,15 @@ +# Windows and request diagnostic residuals + +## Read-only targets + +- #3383: inspect current PR and merged descendants for Windows temp creation and OAuth teardown. Confirm current source behavior and test coverage before proposing a residual patch. No picker UI changes. +- #3522: inspect response spill telemetry and fresh-versus-memoized timeout handling. The acceptance is recovery within the same affected Windows process; generic synthetic success does not prove the reported process recovered. +- #3573: inspect decompression rejection diagnostics and exact latest issue measurements. Serialized journal size and normal requests after raising a cap do not prove the rejected compact payload size or compact success. + +## Conditional delta + +No production edit is pre-approved by this document without a source-grounded residual. If the existing code covers the measurement, record the missing field evidence and leave the issue open. If a specific content-free diagnostic is missing, amend with exact files, field flow and negative assertions before implementation. Never change admission caps, parse a rejected body to count items, relax ACLs, clear memo state, or choose a new recovery/retry policy. + +## Completion + +Record source/commit evidence, original contributor attribution where code is carried, and a separate status per candidate: already implemented, proven patch delivered, or blocked on field evidence. Do not close an original feature PR or issue merely because one residual probe passes. From eabe7ce602af27e098f9bb40b5cb2130b4d7f371 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 07:36:21 +0900 Subject: [PATCH 003/412] docs: plan axis1 bounded bug fixes [skip ci] --- .../_plan/260907_axis1_bugfixes/000_plan.md | 22 +++++++++++++++++++ .../260907_axis1_bugfixes/010_roadmap.md | 3 +++ .../_plan/260907_axis1_bugfixes/011_audit.md | 5 +++++ .../260907_axis1_bugfixes/012_roadmap_lock.md | 5 +++++ .../020_bounded_fixes.md | 20 +++++++++++++++++ .../260907_axis1_bugfixes/030_delivery.md | 7 ++++++ 6 files changed, 62 insertions(+) create mode 100644 devlog/_plan/260907_axis1_bugfixes/000_plan.md create mode 100644 devlog/_plan/260907_axis1_bugfixes/010_roadmap.md create mode 100644 devlog/_plan/260907_axis1_bugfixes/011_audit.md create mode 100644 devlog/_plan/260907_axis1_bugfixes/012_roadmap_lock.md create mode 100644 devlog/_plan/260907_axis1_bugfixes/020_bounded_fixes.md create mode 100644 devlog/_plan/260907_axis1_bugfixes/030_delivery.md diff --git a/devlog/_plan/260907_axis1_bugfixes/000_plan.md b/devlog/_plan/260907_axis1_bugfixes/000_plan.md new file mode 100644 index 0000000000..1fa7537164 --- /dev/null +++ b/devlog/_plan/260907_axis1_bugfixes/000_plan.md @@ -0,0 +1,22 @@ +# Axis 1: measured bug fixes and failure diagnostics + +Archetype: satisfy existing contracts. Trigger: owner assigned axis 1 (#3809, #3464, #3661). Goal: deliver reviewable fixes through a manual PR chain and merge the verified scope. Non-goals: new account/retry policy, auth defaults, multipart recovery, releases, native stacks, sibling edits. Stop: merged feasible scope plus explicit unresolved dispositions. Escalation: defer a policy-dependent or unreproducible slice; reclaim a worker slice after two failed packets. Evidence: this unit plus ignored `.tmp/axis1/` and `.codexclaw` receipts. Resources: task-owned worktree/branches and GitHub repository access; Astra high leaves within host capacity; no caller-specified token or wall-clock budget. + +Baseline: origin/dev 137d6a727; source PR #3809 at 4a1012359a522ddd6d7ff77203c9e5f3632d605c. Assigned 5cc8 checkout has pre-existing changes and remains untouched. Code lives in /tmp/ocx-axis1-20260907. + +## Cycle map +1. wp0: docs-only scope, source audit and dependency roadmap; no runtime changes. +2. wp1: bounded quota, version-guidance and recovery-diagnostic changes; independent source/security review and structural checks. Runtime verification deferred explicitly to wp2. +3. wp2: publish ordinary PR chain, run final cumulative hosted CI, resolve findings, admin merge bottom-up and verify dev ancestry. Lower CI only if final CI fails. + +## Delivery contract +The owner explicitly requests a manual delivery chain even where units are independent: quota -> CLI guidance -> recovery reasons, with each layer carrying its own tests and credit. This order is an integration order, not a fabricated runtime dependency. No native registration. Lower commits carry [skip ci] to defer duplicate workflow runs; final head does not. Skipped lower runs are never called passing. No local tests/typecheck/build suites and no hook-triggered suites; task pushes use --no-verify. Hosted ci.yml on the final head must cover all changed runtime/tests; lower-level runs are diagnostic only after final failure. Merge with --admin under the explicit owner exception; preserve original commits/trailers with merge commits, retarget each child to dev, and check integration trees against final evidence. Concurrent dev changes require fresh combined verification. + +## Work boundaries +- Quota: src/providers/quota.ts, src/oauth/anthropic-routing.ts, src/oauth/health.ts, src/server/responses/core.ts, src/images/loop.ts, src/web-search/loop.ts, focused quota tests/layout, provider documentation. +- CLI: src/cli/version-skew.ts and relevant status/doctor consumers, tests/cli/cli-version-skew.test.ts, troubleshooting documentation. No service restart or repair behavior changes. +- Recovery: src/server/responses/agent-task-recovery.ts, agent-task-recovery-cache.ts, src/lib/bounded-body.ts and existing focused tests, Responses error projection if needed, recovery documentation. No expanded admission/retry. +- Main owns shared core.ts integration and test-layout files. Workers must not touch each other's paths or git index. + +## Verification and acceptance +No local suite commands are executed. Source mapping, git diff --check and documentation structural checks are local evidence only. Hosted Cross-platform CI at final head provides runtime/typecheck/privacy and affected platform proof; inspect jobs for skipped coverage. Build completion is provisional until that run and independent audit succeed. Original PR author(s) must be named in commit Co-authored-by trailers, sourced from original commits/API; report authors may also be acknowledged accurately. Source-of-truth sync uses relevant existing structure and docs-site pages. diff --git a/devlog/_plan/260907_axis1_bugfixes/010_roadmap.md b/devlog/_plan/260907_axis1_bugfixes/010_roadmap.md new file mode 100644 index 0000000000..75e07478c0 --- /dev/null +++ b/devlog/_plan/260907_axis1_bugfixes/010_roadmap.md @@ -0,0 +1,3 @@ +# wp0: scope roadmap + +Read current source, prior issue disposition and PR #3809 before choosing changes. Independent Astra high reviewers map each bounded issue. Confirm existing launcher behavior and bounded recovery reasons are already in dev; plan only residual fixes. Record exact file boundaries and acceptance scenarios in 020. Success: all three slices have verifiable requirements, main-owned shared files, original author anchors and explicit policy exclusions. Local evidence is documentation and source inspection; no runtime claim. diff --git a/devlog/_plan/260907_axis1_bugfixes/011_audit.md b/devlog/_plan/260907_axis1_bugfixes/011_audit.md new file mode 100644 index 0000000000..cc1cb1d51e --- /dev/null +++ b/devlog/_plan/260907_axis1_bugfixes/011_audit.md @@ -0,0 +1,5 @@ +# wp0 audit disposition + +Independent Astra high reviewer Hooke: VERDICT: GO-WITH-FIXES (blockers=1). Shared-flight failure propagation was the blocker. Accepted: 000/020 now assign cache and bounded-body ownership and define shared typed outcomes, success-only cache, caller-local cancellation and capacity semantics. Source scouts independently identified and confirmed these requirements. Fixed stale CLI test path. Windows runtime proof requires final workflow_dispatch, now explicit in 030. + +No runtime code changed. Documentation source/ownership inspection and git diff --check are the wp0 evidence. Runtime verification remains wp2. diff --git a/devlog/_plan/260907_axis1_bugfixes/012_roadmap_lock.md b/devlog/_plan/260907_axis1_bugfixes/012_roadmap_lock.md new file mode 100644 index 0000000000..cf2bf0afce --- /dev/null +++ b/devlog/_plan/260907_axis1_bugfixes/012_roadmap_lock.md @@ -0,0 +1,5 @@ +# Roadmap lock + +The second independent audit returned VERDICT: PASS with no remaining blockers. The three accepted slices are ready for scoped implementation. Original quota author: Éverton Toffanetto (everton-dgn), commit identity from 4f3779c04753 and 3ef0ade296c3. Issue reporters: garysassano (10464497) and Hu9956 (282876394). Reporter acknowledgement is separate from code authorship. + +Preserve raw unequal version diagnostics. Detailed recovery outcomes must travel in the shared flight, not caller-local closures. Quota observations use immutable dispatch identity. Final verification is hosted workflow_dispatch for full Windows coverage; local suites remain prohibited. diff --git a/devlog/_plan/260907_axis1_bugfixes/020_bounded_fixes.md b/devlog/_plan/260907_axis1_bugfixes/020_bounded_fixes.md new file mode 100644 index 0000000000..836f743a73 --- /dev/null +++ b/devlog/_plan/260907_axis1_bugfixes/020_bounded_fixes.md @@ -0,0 +1,20 @@ +# wp1: implement bounded bug fixes + +## Quota +Carry only the source PR diff onto current dev, with original-author trailer. Header utilization fraction -> percentage; reset epoch -> timestamp. Creation: parser; serialization: account quota cache; deserialization: existing hydration; consumers: account ranking/health and management reading. Account-bound writer generation is captured with serving credentials, including retry/sidecar/continuation rebinds. Header observations merge model-specific windows and cannot indefinitely postpone probes. Existing 429 eligibility and retry count stay unchanged. Explicit reset evidence must not be truncated by an invented six-hour policy; any unresolved policy piece is deferred. +Scenarios: 200 and 429 on main/sidecar/continuation attribute only the serving account; generation invalidation discards writes; partial/malformed headers preserve known fields; no prior probe means model-window probe is still due; weekly rejected reset outlasts five-hour reset; absent evidence retains existing fallback. Verify with focused tests included in final hosted CI. + +## Version guidance +Compare CLI and running proxy using existing semantic-version utilities if present. CLI newer points to service restart; proxy newer points to upgrading/PATH resolution of CLI; equal/unknown retain suppression; incomparable differing builds use neutral wording. status and doctor share advice. Preserve whether requests are allowed and do not perform repair. Test both directions, prereleases, placeholders, malformed versions and consumer projection. + +## Recovery reasons +Keep existing public wrapper returning boolean and typed detailed result. Classify actual upstream HTTP refusal, transport error, timeout/caller cancellation, response-body/decode failures with a bounded vocabulary. Creation: request/collector; propagation: detailed recovery result; consumers: existing response reason projection/tests/docs. No raw upstream body/errors/tokens/ciphertext in output. Strict admission, one attempt, same credential and unchanged request mutation guarantees. Exercise each failure branch, cancellation races, malformed terminal output and successful recovery in final hosted CI. + +Main owns src/server/responses/core.ts and layout metadata. Source/security review must check public boundaries and negative cases, not only implementation-mirroring tests. Source-only C evidence does not claim runtime correctness; wp2 is mandatory. + +## Source-map clarification from independent #3464 research +Use src/lib/strict-semver.ts unchanged. Raw unequal versions remain skewed; equal precedence with different build metadata and invalid/whitespace/v-prefixed values get neutral wording, not normalization or a guessed direction. Placeholder suppression is unchanged. src/cli/doctor.ts must not call suppressed placeholders a confirmed match. Focused files: tests/cli/cli-version-skew.test.ts, tests/cli/cli-status-json.test.ts, tests/codex-integration/doctor.test.ts. Documentation: reference/cli/lifecycle.md and directly affected Korean/Russian pages. Existing launcher landed via #3616 (4e2246c32); no service runtime changes. + +## Audit refinements +Quota: observe physical responses at the existing oauthDispatch boundary before any main/continuation replacement or return. Use immutable request binding to pair response with selected account; skip when final authorization headers do not prove that bearer or credentialGeneration has changed. An active-account switch alone does not invalidate another account's in-flight observation. Native Claude passthrough and single-account expansion remain outside #3809 carry. Preserve Retry-After precedence; only reject nonfinite/unrepresentable deadlines rather than invent an anomaly ceiling. Header-only rows are probe-due; hydrated Anthropic observations must be probe-due unless probe time is proven. Failed probes settle with the most recent committed observation for all joiners. +Recovery: worker owns agent-task-recovery-cache.ts and bounded-body.ts narrow decode discriminator alongside focused tests. Shared flight carries typed outcome, cache retains only success plaintext, cancelled waiters remain local. Recognized caller cancellation precedes owned timeout, which precedes decode/transport classification. Fatal UTF-8 discriminator must identify actual decoder exceptions without reclassifying fetch/body-reader TypeErrors. Rejected-response cancellation is nonblocking best effort. Keep current public wrappers and combo error projection. Update documented reason lists in structure/04_transports-and-sidecars.md and docs-site/reference/architecture.md. diff --git a/devlog/_plan/260907_axis1_bugfixes/030_delivery.md b/devlog/_plan/260907_axis1_bugfixes/030_delivery.md new file mode 100644 index 0000000000..be851f530d --- /dev/null +++ b/devlog/_plan/260907_axis1_bugfixes/030_delivery.md @@ -0,0 +1,7 @@ +# wp2: hosted proof and manual-stack landing + +Publish task-owned branches with --no-verify. Standard PR template, source links, truthful skipped-local/lower-CI disclosure and contributor trailers. Lower layers use [skip ci], final cumulative head runs existing Cross-platform CI; never modify shared workflow filters or fabricate checks. On final failure inspect failing jobs, fix owned defects, and only then use lower CI to localize ambiguity. Leave unrelated/unresolvable slices unmerged with evidence. + +Before admin merge: source/security review findings resolved, final CI SHA/run pinned, current PR head and manual membership inspected. Record owner-authorized admin review/lower-CI exception. Merge bottom-up with original commits preserved; do not delete parent branches while children depend on them. Retarget child to dev after parent landing. Reconcile concurrent dev before claiming final integrated proof. Verify every merge SHA is ancestor of refreshed origin/dev. Close #3809 only after its accepted replacement scope lands; keep #3661 open for multipart/retry and #3464 open if broader original acceptance remains unresolved. No release/deploy. + +Final full platform evidence uses workflow_dispatch ci.yml on the final cumulative branch, because ordinary PR CI excludes the Windows runtime job. Cancel only duplicate task-owned PR CI runs; skipped/cancelled runs are not passing evidence. From 58fcb0961d7d955cc272f672290c9d2c53ae3722 Mon Sep 17 00:00:00 2001 From: JUN <243035832+lidge-jun@users.noreply.github.com> Date: Mon, 7 Sep 2026 07:36:51 +0900 Subject: [PATCH 004/412] fix(claude): preserve reasoning and tool result envelopes Carry PR #3815 through 76e07d181c48dca8c80167878381e1edb5642395. Preserve original contributor work and its bounded retention, signature-only reasoning and documentation follow-ups. Remote combined validation follows; local suites intentionally not run under maintainer instruction. Co-authored-by: SB Yoon <44089734+yansigit@users.noreply.github.com> Co-authored-by: Yumi --- .../src/content/docs/fr/guides/claude-code.md | 4 +- .../src/content/docs/guides/claude-code.md | 4 +- .../src/content/docs/ja/guides/claude-code.md | 4 +- .../src/content/docs/ko/guides/claude-code.md | 4 +- .../src/content/docs/ru/guides/claude-code.md | 4 +- .../src/content/docs/tr/guides/claude-code.md | 4 +- .../content/docs/zh-cn/guides/claude-code.md | 4 +- .../content/docs/zh-tw/guides/claude-code.md | 4 +- scripts/test-layout/layout.json | 2 + src/claude/inbound.ts | 28 +++++-- src/claude/outbound.ts | 83 ++++++++++++++---- src/responses/reasoning-envelope.ts | 5 +- ...laude-code-thought-signature-scope.test.ts | 12 +++ .../claude-integration/claude-inbound.test.ts | 12 +-- .../claude-outbound.test.ts | 84 +++++++++++++++++++ .../claude-source-envelope.test.ts | 30 +++++++ tests/fixtures/test-layout-expected.json | 2 + tests/responses/reasoning-envelope.test.ts | 79 +++++++++++++++++ 18 files changed, 324 insertions(+), 45 deletions(-) create mode 100644 tests/claude-integration/claude-source-envelope.test.ts create mode 100644 tests/responses/reasoning-envelope.test.ts diff --git a/docs-site/src/content/docs/fr/guides/claude-code.md b/docs-site/src/content/docs/fr/guides/claude-code.md index 5c13e041b6..ffc3ad6e88 100644 --- a/docs-site/src/content/docs/fr/guides/claude-code.md +++ b/docs-site/src/content/docs/fr/guides/claude-code.md @@ -500,7 +500,7 @@ Le proxy traduit chaque requête Anthropic Messages API au format Codex Response | Texte assistant | `output_text` | | Assistant `tool_use` | `function_call` (`input` → JSON-stringifié `arguments`) | | Utilisateur `tool_result` | `function_call_output` (`is_error` → préfixe `[tool error]`) | -| Relecture de `thinking` / `redacted_thinking` | Ignorée | +| Relecture de `thinking` / `redacted_thinking` | Éléments `reasoning` avec enveloppes `ocxr1` bornées pour les signatures et les contenus masqués | | Outils fonctionnels | `{type: "function"}` (`web_search*` → `{type: "web_search"}`) | | `tool_choice` | `auto`→`auto`, `none`→`none`, `any`→`required`, fonction nommée→`{type:"function",name}`, hébergée WebSearch/web_search→`{type:"web_search"}` | | `max_tokens` | `max_output_tokens` | @@ -516,7 +516,7 @@ Le proxy traduit chaque requête Anthropic Messages API au format Codex Response | `response.created` | `message_start` + `ping` | | Battement de coeur | `ping` | | Deltas de texte | `content_block_start` → `content_block_delta` (texte) → `content_block_stop` | -| Résumé ou texte de raisonnement | Bloc `thinking` avec signature synthétique | +| Résumé ou texte de raisonnement | Bloc `thinking` avec la signature relue, ou une enveloppe de secours `ocxr1` bornée | | Trames d'appel de fonction | Bloc `tool_use` avec `input_json_delta` | | Événement terminal | `message_delta` → `message_stop` | | EOF avant la borne | style 502 `api_error` | diff --git a/docs-site/src/content/docs/guides/claude-code.md b/docs-site/src/content/docs/guides/claude-code.md index 5ed946c72a..b237955adb 100644 --- a/docs-site/src/content/docs/guides/claude-code.md +++ b/docs-site/src/content/docs/guides/claude-code.md @@ -513,7 +513,7 @@ The proxy translates every Anthropic Messages API request into the Codex Respons | Assistant text | `output_text` | | Assistant `tool_use` | `function_call` (`input` → JSON-stringified `arguments`) | | User `tool_result` | `function_call_output` (`is_error` → `[tool error]` prefix) | -| `thinking` / `redacted_thinking` replay | Dropped | +| `thinking` / `redacted_thinking` replay | `reasoning` items with bounded `ocxr1` envelopes for signatures and redacted payloads | | Function tools | `{type: "function"}` (`web_search*` → `{type: "web_search"}`) | | `tool_choice` | `auto`→`auto`, `none`→`none`, `any`→`required`, named function→`{type:"function",name}`, hosted WebSearch/web_search→`{type:"web_search"}` | | `max_tokens` | `max_output_tokens` | @@ -530,7 +530,7 @@ name. | `response.created` | `message_start` + `ping` | | Heartbeat | `ping` | | Text deltas | `content_block_start` → `content_block_delta` (text) → `content_block_stop` | -| Reasoning summary/text | `thinking` block with synthetic signature | +| Reasoning summary/text | `thinking` block with the replayed signature, or a bounded `ocxr1` fallback envelope | | Function-call frames | `tool_use` block with `input_json_delta` | | Terminal event | `message_delta` → `message_stop` | | EOF before terminal | 502-style `api_error` | diff --git a/docs-site/src/content/docs/ja/guides/claude-code.md b/docs-site/src/content/docs/ja/guides/claude-code.md index 8c9f433956..43b8bcee24 100644 --- a/docs-site/src/content/docs/ja/guides/claude-code.md +++ b/docs-site/src/content/docs/ja/guides/claude-code.md @@ -368,7 +368,7 @@ Claude Code の `/effort` 設定はアダプターでも維持されます。 | Assistant テキスト | `output_text` | | Assistant `tool_use` | `function_call`(`input` → JSON 文字列に変換した `arguments`) | | ユーザー `tool_result` | `function_call_output`(`is_error` → `[tool error]` 接頭辞) | -| `thinking` / `redacted_thinking` 再生 | 破棄 | +| `thinking` / `redacted_thinking` 再生 | シグネチャと秘匿ペイロードを境界付き `ocxr1` エンベロープに保持した `reasoning` 項目 | | Function ツール | `{type: "function"}`(`web_search*` → `{type: "web_search"}`) | | `tool_choice` | `auto`→`auto`、`none`→`none`、`any`→`required`、名前指定関数→`{type:"function",name}`、ホスト型 WebSearch/web_search→`{type:"web_search"}` | | `max_tokens` | `max_output_tokens` | @@ -384,7 +384,7 @@ role、`tool_use_id` のない `tool_result`、id/name のない `tool_use`、na | `response.created` | `message_start` + `ping` | | Heartbeat | `ping` | | テキスト delta | `content_block_start` → `content_block_delta`(text) → `content_block_stop` | -| 推論要約/テキスト | 合成シグネチャ付きの `thinking` ブロック | +| 推論要約/テキスト | 再生されたシグネチャ、または境界付き `ocxr1` フォールバックを持つ `thinking` ブロック | | Function-call フレーム | `input_json_delta` を持つ `tool_use` ブロック | | 終了イベント | `message_delta` → `message_stop` | | 終了前に EOF | 502 形式 `api_error` | diff --git a/docs-site/src/content/docs/ko/guides/claude-code.md b/docs-site/src/content/docs/ko/guides/claude-code.md index 1368cf5698..0964f2ff49 100644 --- a/docs-site/src/content/docs/ko/guides/claude-code.md +++ b/docs-site/src/content/docs/ko/guides/claude-code.md @@ -406,7 +406,7 @@ Claude Code의 `/effort` 설정은 어댑터에서도 유지돼요. | Assistant 텍스트 | `output_text` | | Assistant `tool_use` | `function_call`(`input` → JSON 문자열로 변환한 `arguments`) | | 사용자 `tool_result` | `function_call_output`(`is_error` → `[tool error]` 접두사) | -| `thinking` / `redacted_thinking` 재생 | 버려요 | +| `thinking` / `redacted_thinking` 재생 | 서명과 비공개 페이로드를 제한된 `ocxr1` 봉투에 담은 `reasoning` 항목 | | Function 도구 | `{type: "function"}`(`web_search*` → `{type: "web_search"}`) | | `tool_choice` | `auto`→`auto`, `none`→`none`, `any`→`required`, 이름 지정 함수→`{type:"function",name}`, 호스팅 WebSearch/web_search→`{type:"web_search"}` | | `max_tokens` | `max_output_tokens` | @@ -422,7 +422,7 @@ role, `tool_use_id` 없는 `tool_result`, id/name 없는 `tool_use`, name 없는 | `response.created` | `message_start` + `ping` | | Heartbeat | `ping` | | 텍스트 delta | `content_block_start` → `content_block_delta`(text) → `content_block_stop` | -| 추론 요약/텍스트 | 합성 signature가 있는 `thinking` 블록 | +| 추론 요약/텍스트 | 재생된 서명 또는 제한된 `ocxr1` 폴백이 있는 `thinking` 블록 | | Function-call 프레임 | `input_json_delta`가 있는 `tool_use` 블록 | | 종료 이벤트 | `message_delta` → `message_stop` | | 종료 전에 EOF | 502 형식 `api_error` | diff --git a/docs-site/src/content/docs/ru/guides/claude-code.md b/docs-site/src/content/docs/ru/guides/claude-code.md index 3f6c07a4aa..1769642bd7 100644 --- a/docs-site/src/content/docs/ru/guides/claude-code.md +++ b/docs-site/src/content/docs/ru/guides/claude-code.md @@ -393,7 +393,7 @@ Claude Code — это лишь учётные данные для доступ | Текст ассистента | `output_text` | | `tool_use` ассистента | `function_call` (`input` → `arguments` в виде JSON-строки) | | `tool_result` пользователя | `function_call_output` (`is_error` → префикс `[tool error]`) | -| Повтор `thinking` / `redacted_thinking` | Отбрасывается | +| Повтор `thinking` / `redacted_thinking` | Элементы `reasoning` с ограниченными конвертами `ocxr1` для подписей и скрытых данных | | Function-инструменты | `{type: "function"}` (`web_search*` → `{type: "web_search"}`) | | `tool_choice` | `auto`→`auto`, `none`→`none`, `any`→`required`, именованная функция→`{type:"function",name}`, размещённый WebSearch/web_search→`{type:"web_search"}` | | `max_tokens` | `max_output_tokens` | @@ -410,7 +410,7 @@ id/name; именованный `tool_choice` без имени. | `response.created` | `message_start` + `ping` | | Heartbeat | `ping` | | Текстовые дельты | `content_block_start` → `content_block_delta` (text) → `content_block_stop` | -| Резюме/текст рассуждений | Блок `thinking` с синтетической подписью | +| Резюме/текст рассуждений | Блок `thinking` с повторно переданной подписью или ограниченным резервным конвертом `ocxr1` | | Кадры function-call | Блок `tool_use` с `input_json_delta` | | Завершающее событие | `message_delta` → `message_stop` | | EOF до завершающего события | `api_error` в стиле 502 | diff --git a/docs-site/src/content/docs/tr/guides/claude-code.md b/docs-site/src/content/docs/tr/guides/claude-code.md index 5450d6b748..29d96506ac 100644 --- a/docs-site/src/content/docs/tr/guides/claude-code.md +++ b/docs-site/src/content/docs/tr/guides/claude-code.md @@ -582,7 +582,7 @@ dönüştürür: | Asistan metni | `output_text` | | Asistan `tool_use` | `function_call` (`input` → JSON dizgeleştirilmiş `arguments`) | | Kullanıcı `tool_result` | `function_call_output` (`is_error` → `[tool error]` öneki) | -| `thinking` / `redacted_thinking` tekrarı | Bırakılır | +| `thinking` / `redacted_thinking` tekrarı | İmzaları ve gizli yükleri sınırlı `ocxr1` zarflarında taşıyan `reasoning` öğeleri | | Fonksiyon araçları | `{type: "function"}` (`web_search*` → `{type: "web_search"}`) | | `tool_choice` | `auto`→`auto`, `none`→`none`, `any`→`required`, adlandırılmış fonksiyon→`{type:"function",name}`, barındırılan WebSearch/web_search→`{type:"web_search"}` | | `max_tokens` | `max_output_tokens` | @@ -599,7 +599,7 @@ kimlik/ad içermeyen `tool_use`; ad içermeyen adlandırılmış `tool_choice`. | `response.created` | `message_start` + `ping` | | Kalp atışı (Heartbeat) | `ping` | | Metin farkları | `content_block_start` → `content_block_delta` (metin) → `content_block_stop` | -| Akıl yürütme özeti/metni | Sentetik imzalı `thinking` bloğu | +| Akıl yürütme özeti/metni | Tekrarlanan imzayı veya sınırlı bir `ocxr1` yedeğini taşıyan `thinking` bloğu | | Fonksiyon çağrısı çerçeveleri | `input_json_delta` ile `tool_use` bloğu | | Terminal olayı | `message_delta` → `message_stop` | | Terminalden önce EOF | 502 tarzı `api_error` | diff --git a/docs-site/src/content/docs/zh-cn/guides/claude-code.md b/docs-site/src/content/docs/zh-cn/guides/claude-code.md index 3bbe49646b..3e2824d3e9 100644 --- a/docs-site/src/content/docs/zh-cn/guides/claude-code.md +++ b/docs-site/src/content/docs/zh-cn/guides/claude-code.md @@ -344,7 +344,7 @@ Claude Code 的 `/effort` 设置会完整保留并传递给适配器: | Assistant 文本 | `output_text` | | Assistant `tool_use` | `function_call`(`input` → JSON 字符串化的 `arguments`) | | 用户 `tool_result` | `function_call_output`(`is_error` → `[tool error]` 前缀) | -| 重放 `thinking` / `redacted_thinking` | 丢弃 | +| 重放 `thinking` / `redacted_thinking` | `reasoning` 项;签名和脱敏载荷保存在有界 `ocxr1` 信封中 | | Function 工具 | `{type: "function"}`(`web_search*` → `{type: "web_search"}`) | | `tool_choice` | `auto`→`auto`,`none`→`none`,`any`→`required`,指定函数→`{type:"function",name}`,托管 WebSearch/web_search→`{type:"web_search"}` | | `max_tokens` | `max_output_tokens` | @@ -361,7 +361,7 @@ role;`tool_result` 缺少 `tool_use_id`;`tool_use` 缺少 id/name;指定 | `response.created` | `message_start` + `ping` | | 心跳 | `ping` | | 文本增量 | `content_block_start` → `content_block_delta`(文本)→ `content_block_stop` | -| 推理摘要/文本 | 带合成签名的 `thinking` 块 | +| 推理摘要/文本 | 带重放签名或有界 `ocxr1` 回退信封的 `thinking` 块 | | Function-call 帧 | 带 `input_json_delta` 的 `tool_use` 块 | | 终止事件 | `message_delta` → `message_stop` | | 在终止事件前 EOF | 502 风格的 `api_error` | diff --git a/docs-site/src/content/docs/zh-tw/guides/claude-code.md b/docs-site/src/content/docs/zh-tw/guides/claude-code.md index ccfb3b9ddd..5a6fbf3a86 100644 --- a/docs-site/src/content/docs/zh-tw/guides/claude-code.md +++ b/docs-site/src/content/docs/zh-tw/guides/claude-code.md @@ -420,7 +420,7 @@ Claude Code 的 `/effort` 設定會完整保留並傳遞給適配器: | Assistant 文字 | `output_text` | | Assistant `tool_use` | `function_call`(`input` → JSON 字串化的 `arguments`) | | 使用者 `tool_result` | `function_call_output`(`is_error` → `[tool error]` 字首) | -| 重放 `thinking` / `redacted_thinking` | 丟棄 | +| 重放 `thinking` / `redacted_thinking` | `reasoning` 項目;簽名與遮蔽載荷保存在有界 `ocxr1` 信封中 | | Function 工具 | `{type: "function"}`(`web_search*` → `{type: "web_search"}`) | | `tool_choice` | `auto`→`auto`,`none`→`none`,`any`→`required`,指定名稱 function→`{type:"function",name}`,hosted WebSearch/web_search→`{type:"web_search"}` | | `max_tokens` | `max_output_tokens` | @@ -437,7 +437,7 @@ role;`tool_result` 缺少 `tool_use_id`;`tool_use` 缺少 id/name;指定 | `response.created` | `message_start` + `ping` | | 心跳 | `ping` | | 文字增量 | `content_block_start` → `content_block_delta`(文字)→ `content_block_stop` | -| 推理摘要/文字 | 帶合成簽名的 `thinking` 塊 | +| 推理摘要/文字 | 帶重播簽名或有界 `ocxr1` 備援信封的 `thinking` 塊 | | Function-call 幀 | 帶 `input_json_delta` 的 `tool_use` 塊 | | 終止事件 | `message_delta` → `message_stop` | | 在終止事件前 EOF | 502 風格的 `api_error` | diff --git a/scripts/test-layout/layout.json b/scripts/test-layout/layout.json index d309073a3f..255c78e916 100644 --- a/scripts/test-layout/layout.json +++ b/scripts/test-layout/layout.json @@ -312,6 +312,7 @@ "claude-outbound.test.ts": "claude-integration", "claude-shell-hook.test.ts": "claude-integration", "claude-sidecar-override.test.ts": "claude-integration", + "claude-source-envelope.test.ts": "claude-integration", "claude-system-env-auto.test.ts": "claude-integration", "cleanup-orphaned-workflows.test.ts": "ci-workflows", "clearable-deadline.test.ts": "lib", @@ -999,6 +1000,7 @@ "rate-limit-reset-credits.test.ts": "gui", "rate-limit-retry.test.ts": "providers", "reasoning-effort.test.ts": "codex-integration", + "reasoning-envelope.test.ts": "responses", "reasoning-replay-identity.test.ts": "adapters", "reasoning-replay-robustness.test.ts": "adapters", "reasoning-replay-scope-source.test.ts": "lib", diff --git a/src/claude/inbound.ts b/src/claude/inbound.ts index 3ac4731385..5e876ca6cb 100644 --- a/src/claude/inbound.ts +++ b/src/claude/inbound.ts @@ -4,8 +4,8 @@ * Design (devlog/260711_claude_inbound/010, 003_evidence.md): * - translate-and-replay: the produced body MUST pass the real responsesRequestSchema * parse so routing/OAuth/pool/failover are inherited unchanged. - * - thinking/redacted_thinking blocks on replay are DROPPED (v1 policy) — routed - * providers carry reasoning in Responses items/ocxr1 envelopes instead. + * - thinking/redacted_thinking replay is preserved in Responses reasoning items; + * signatures and redacted payloads travel in bounded ocxr1 envelopes. * - thinking.budget_tokens is NEVER forwarded raw; it maps to an effort tier. * - top_k is accepted and silently dropped (no Responses equivalent, CCR parity). */ @@ -17,6 +17,7 @@ export { resolveInboundModel, effortForThinkingBudget, effortFromOutputConfig, e import { AnthropicRequestError, isRec, type Rec } from "./inbound-records"; import { resolveInboundModel, effortForThinkingBudget, effortFromOutputConfig, formatFromOutputConfig } from "./inbound-model-options"; import { systemToInstructions, toolsToResponses, toolChoiceToResponses } from "./inbound-content-options"; +import { decodeReasoningEnvelope, encodeReasoningEnvelope, OCX_REASONING_PREFIX } from "../responses/reasoning-envelope"; @@ -234,9 +235,26 @@ function assistantMessageToItems(content: unknown, input: Rec[]): void { input.push({ type: "function_call", call_id: raw.id, name: raw.name, arguments: JSON.stringify(raw.input ?? {}) }); break; } - case "thinking": - case "redacted_thinking": - break; // v1 policy: dropped on replay (003 evidence — safe for routed providers) + case "thinking": { + flush(); + const thinking = typeof raw.thinking === "string" ? raw.thinking : ""; + const signature = typeof raw.signature === "string" ? raw.signature : ""; + if (signature.startsWith(OCX_REASONING_PREFIX)) { + const owned = decodeReasoningEnvelope(signature); + if (!owned) throw new AnthropicRequestError("malformed ocxr1 reasoning signature"); + if (Object.hasOwn(owned, "sig")) throw new AnthropicRequestError("OpenCodex reasoning continuity cannot be replayed as an Anthropic signature"); + } + const encrypted = signature.length === 0 ? undefined : signature.startsWith(OCX_REASONING_PREFIX) ? signature : encodeReasoningEnvelope({ sig: signature }); + if (thinking.length === 0 && !encrypted) break; + input.push({ type: "reasoning", id: `rs_${crypto.randomUUID().replace(/-/g, "")}`, summary: thinking.length > 0 ? [{ type: "summary_text", text: thinking }] : [], ...(encrypted ? { encrypted_content: encrypted } : {}) }); + break; + } + case "redacted_thinking": { + flush(); + const data = typeof raw.data === "string" ? raw.data : ""; + if (data.length > 0) input.push({ type: "reasoning", id: `rs_${crypto.randomUUID().replace(/-/g, "")}`, summary: [], encrypted_content: encodeReasoningEnvelope({ red: [data] }) }); + break; + } default: break; } diff --git a/src/claude/outbound.ts b/src/claude/outbound.ts index 48bb06c15a..8c0db5b7b8 100644 --- a/src/claude/outbound.ts +++ b/src/claude/outbound.ts @@ -5,8 +5,8 @@ * - Transport-only `ping` events may appear at any point, including before * message_start. Semantic framing stays message_start -> * (content_block_start -> deltas -> content_block_stop)* -> message_delta -> message_stop. - * - thinking blocks get thinking_delta(s) then ONE synthetic signature_delta just - * before content_block_stop (CCR precedent: Claude Code does not verify signatures). + * - thinking blocks get thinking_delta(s), then one signature_delta containing the + * genuine replay signature or a bounded ocxr1 fallback envelope. * - message_delta.usage is cumulative; message_start embeds a full message snapshot. * - errors: {type:"error", error:{type,message}}; may arrive mid-stream after HTTP 200. */ @@ -20,6 +20,7 @@ import { type TranslatorBudget, } from "../lib/translator-budget"; import { sseFieldOffset, sseFieldValue } from "../lib/sse-decoder"; +import { decodeReasoningEnvelope, encodeReasoningEnvelope } from "../responses/reasoning-envelope"; type Rec = Record; @@ -214,6 +215,9 @@ interface OpenBlock { callId?: string; /** Last fixed-size reasoning identity (item + summary/content index) seen by this block. */ reasoningPartKey?: string; + thinkingBuf?: string; + thinkingBufBytes?: number; + reasoningSig?: string; } /** Streaming: Responses SSE bytes -> Anthropic Messages SSE bytes. */ @@ -253,6 +257,11 @@ export function responsesSseToAnthropicSse( const bytes = queuedLiveFrameBytes.shift(); if (bytes !== undefined) translatorBudget.releaseRetained(bytes, { kind: "live_transient" }); }; + const releaseThinkingBuffer = (block: OpenBlock | null | undefined) => { + if (block?.kind !== "thinking") return; + translatorBudget.releaseRetained(block.thinkingBufBytes ?? 0, { kind: "reasoning" }); + block.thinkingBufBytes = 0; + }; return new ReadableStream({ start(controller) { @@ -296,13 +305,14 @@ export function responsesSseToAnthropicSse( open.webSearchArgsEmitted = true; } if (open.kind === "thinking") { - // Synthetic signature: Claude Code accepts it (003 E6); inbound drops replays anyway. + const signature = open.reasoningSig ?? encodeReasoningEnvelope({ txt: open.thinkingBuf ?? "" }); emit("content_block_delta", { type: "content_block_delta", index: open.index, - delta: { type: "signature_delta", signature: `ocx${Date.now()}` }, + delta: { type: "signature_delta", signature }, }); } emit("content_block_stop", { type: "content_block_stop", index: open.index }); + releaseThinkingBuffer(open); if (open.callId) translatorBudget.closeCall(open.callId); open = null; }; @@ -315,7 +325,7 @@ export function responsesSseToAnthropicSse( ? { type: "text", text: "" } : { type: "thinking", thinking: "", signature: "" }; emit("content_block_start", { type: "content_block_start", index, content_block: contentBlock }); - open = { kind, index }; + open = { kind, index, thinkingBuf: "", thinkingBufBytes: 0 }; }; const finish = (stopReason: string, usage: unknown) => { if (terminated) return; @@ -339,6 +349,7 @@ export function responsesSseToAnthropicSse( if (terminated) return; terminated = true; if (code === "translation_buffer_limit") { + releaseThinkingBuffer(open); if (open?.callId) translatorBudget.closeCall(open.callId); open = null; // No normal close frames are valid after overflow. Emit exactly one bounded @@ -374,8 +385,10 @@ export function responsesSseToAnthropicSse( case "response.output_text.delta": { if (typeof data.delta !== "string" || data.delta.length === 0) break; ensureBlock("text"); + const active = open; + if (!active || active.kind !== "text") break; emit("content_block_delta", { - type: "content_block_delta", index: open!.index, + type: "content_block_delta", index: active.index, delta: { type: "text_delta", text: data.delta }, }); break; @@ -384,6 +397,8 @@ export function responsesSseToAnthropicSse( case "response.reasoning_text.delta": { if (typeof data.delta !== "string" || data.delta.length === 0) break; ensureBlock("thinking"); + const active = open; + if (!active || active.kind !== "thinking") break; // The JSON path joins reasoning summary/content parts with "\n\n" // (responsesJsonToAnthropicMessage); mirror that at part and item boundaries // so multi-part summaries do not glue into one run-on paragraph. Frames @@ -395,15 +410,32 @@ export function responsesSseToAnthropicSse( // components while retaining item and part equality, rather than dropping item_id and // accidentally joining distinct malformed reasoning items. const partKey = `${boundedReasoningIdentity(data.item_id)}:${slot}`; - if (open!.reasoningPartKey !== undefined && open!.reasoningPartKey !== partKey) { + const needsPartSeparator = active.reasoningPartKey !== undefined + && active.reasoningPartKey !== partKey; + const appended = `${needsPartSeparator ? "\n\n" : ""}${data.delta}`; + const previous = active.thinkingBuf ?? ""; + const previousBytes = active.thinkingBufBytes ?? 0; + const nextBytes = appendedUtf8Bytes(previous, previousBytes, appended); + const scope = { kind: "reasoning" } as const; + const reservation = translatorBudget.reserveTransient(nextBytes, scope); + try { + active.thinkingBuf = previous + appended; + active.thinkingBufBytes = nextBytes; + reservation.commitRetained(); + translatorBudget.releaseRetained(previousBytes, scope); + } catch (error) { + reservation.release(); + throw error; + } + if (needsPartSeparator) { emit("content_block_delta", { - type: "content_block_delta", index: open!.index, + type: "content_block_delta", index: active.index, delta: { type: "thinking_delta", thinking: "\n\n" }, }); } - open!.reasoningPartKey = partKey; + active.reasoningPartKey = partKey; emit("content_block_delta", { - type: "content_block_delta", index: open!.index, + type: "content_block_delta", index: active.index, delta: { type: "thinking_delta", thinking: data.delta }, }); break; @@ -499,10 +531,9 @@ export function responsesSseToAnthropicSse( if (pair.completed) webSearchRequests++; break; } - if (!open) break; // Close the matching open block (message/reasoning items close implicitly on // the next block; function_call items must close here so tool input parses). - if (open.kind === "tool_use" && item.type === "function_call") { + if (open && open.kind === "tool_use" && item.type === "function_call") { if (open.bufferWebSearchArgs && !open.webSearchArgsEmitted) { const rawArgs = typeof item.arguments === "string" && item.arguments.length > 0 ? item.arguments @@ -518,8 +549,23 @@ export function responsesSseToAnthropicSse( } closeOpenBlock(); } - else if (open.kind === "text" && item.type === "message") closeOpenBlock(); - else if (open.kind === "thinking" && item.type === "reasoning") closeOpenBlock(); + else if (open && open.kind === "text" && item.type === "message") closeOpenBlock(); + else if (item.type === "reasoning") { + const encrypted = typeof item.encrypted_content === "string" ? item.encrypted_content : ""; + const env = encrypted ? decodeReasoningEnvelope(encrypted) : null; + const red = env?.red ?? []; + if (env?.sig && open?.kind !== "thinking") ensureBlock("thinking"); + if (open?.kind === "thinking") { + if (env?.sig) open.reasoningSig = env.sig; + closeOpenBlock(); + } + if (red.length > 0) ensureStarted(); + for (const data of red) { + const idx = blockIndex++; + emit("content_block_start", { type: "content_block_start", index: idx, content_block: { type: "redacted_thinking", data } }); + emit("content_block_stop", { type: "content_block_stop", index: idx }); + } + } break; } case "response.completed": { @@ -704,6 +750,7 @@ export function responsesSseToAnthropicSse( fail(413, "upstream translation buffer exceeded the safe limit", false, "translation_buffer_limit"); } else fail(500, err instanceof Error ? err.message : String(err)); } finally { + releaseThinkingBuffer(open); translatorBudget.releaseRetained(bufferBytes, { kind: "live_transient" }); if (pingTimer !== undefined) clearInterval(pingTimer); reader.releaseLock(); @@ -717,6 +764,7 @@ export function responsesSseToAnthropicSse( cancel(reason) { cancelled = true; while (queuedLiveFrameBytes.length > 0) releaseDeliveredFrame(); + releaseThinkingBuffer(open); if (open?.callId) translatorBudget.closeCall(open.callId); if (pingTimer !== undefined) clearInterval(pingTimer); return reader?.cancel(reason); @@ -756,9 +804,12 @@ export function responsesJsonToAnthropicMessage(json: unknown, model: string): R if (isRec(s) && typeof s.text === "string" && s.text.length > 0) parts.push(s.text); } } - if (parts.length > 0) { - content.push({ type: "thinking", thinking: parts.join("\n\n"), signature: `ocx${Date.now()}` }); + const encrypted = typeof raw.encrypted_content === "string" ? raw.encrypted_content : ""; + const env = encrypted ? decodeReasoningEnvelope(encrypted) : null; + if (parts.length > 0 || env?.sig) { + content.push({ type: "thinking", thinking: parts.join("\n\n"), signature: env?.sig ?? encodeReasoningEnvelope({ txt: parts.join("\n\n") }) }); } + for (const data of env?.red ?? []) content.push({ type: "redacted_thinking", data }); break; } case "function_call": { diff --git a/src/responses/reasoning-envelope.ts b/src/responses/reasoning-envelope.ts index 1735f775fb..2a56563578 100644 --- a/src/responses/reasoning-envelope.ts +++ b/src/responses/reasoning-envelope.ts @@ -50,10 +50,11 @@ export function decodeReasoningEnvelope(encryptedContent: string): ReasoningEnve if (red.length > 0) envelope.red = red; } const txt = (parsed as { txt?: unknown }).txt; - if (typeof txt === "string" && txt.length > 0) envelope.txt = txt; + const hasTxt = typeof txt === "string"; + if (hasTxt) envelope.txt = txt; const krc = (parsed as { krc?: unknown }).krc; if (typeof krc === "string" && krc.length > 0) envelope.krc = krc; - return envelope.sig || envelope.red || envelope.txt || envelope.krc ? envelope : null; + return envelope.sig || envelope.red || hasTxt || envelope.krc ? envelope : null; } catch { return null; } diff --git a/tests/claude-integration/claude-code-thought-signature-scope.test.ts b/tests/claude-integration/claude-code-thought-signature-scope.test.ts index eb544dce97..b3d981c327 100644 --- a/tests/claude-integration/claude-code-thought-signature-scope.test.ts +++ b/tests/claude-integration/claude-code-thought-signature-scope.test.ts @@ -125,4 +125,16 @@ describe("Claude Code Anthropic inbound reasoning-replay scope", () => { const parsed = await drive({ promptCacheKey: " ", promptCacheKeyIsSharedCohort: false }); expect(parsed._reasoningReplayScope).toBeUndefined(); }); + + test("distinct session identities remain distinct and bounded", async () => { + const first = await drive({ promptCacheKey: "session-a", promptCacheKeyIsSharedCohort: false }); + const second = await drive({ promptCacheKey: "session-b", promptCacheKeyIsSharedCohort: false }); + const a = first._reasoningReplayScope?.clientThreadId; + const b = second._reasoningReplayScope?.clientThreadId; + expect(a).toBeDefined(); + expect(b).toBeDefined(); + expect(a).not.toBe(b); + expect(a).toBe("session-a"); + expect(b).toBe("session-b"); + }); }); diff --git a/tests/claude-integration/claude-inbound.test.ts b/tests/claude-integration/claude-inbound.test.ts index 32207c9019..7227bbf2f1 100644 --- a/tests/claude-integration/claude-inbound.test.ts +++ b/tests/claude-integration/claude-inbound.test.ts @@ -84,12 +84,12 @@ describe("claude inbound translation", () => { expect(tools[1]).toEqual({ type: "web_search" }); const input = body.input as Record[]; - // user text, assistant text (thinking dropped), function_call, function_call_output, user tail - expect(input.map(i => i.type ?? i.role)).toEqual(["message", "message", "function_call", "function_call_output", "message"]); - expect(input[1].content).toEqual([{ type: "output_text", text: "Reading it now." }]); - expect(input[2]).toMatchObject({ call_id: "toolu_01", name: "Read", arguments: JSON.stringify({ file_path: "/README.md" }) }); - expect(input[3]).toMatchObject({ call_id: "toolu_01", output: [{ type: "input_text", text: "# hello" }] }); - const tail = input[4].content as Record[]; + // user text, reasoning, assistant text, function_call, function_call_output, user tail + expect(input.map(i => i.type ?? i.role)).toEqual(["message", "reasoning", "message", "function_call", "function_call_output", "message"]); + expect(input[2].content).toEqual([{ type: "output_text", text: "Reading it now." }]); + expect(input[3]).toMatchObject({ call_id: "toolu_01", name: "Read", arguments: JSON.stringify({ file_path: "/README.md" }) }); + expect(input[4]).toMatchObject({ call_id: "toolu_01", output: [{ type: "input_text", text: "# hello" }] }); + const tail = input[5].content as Record[]; expect(tail[0]).toEqual({ type: "input_text", text: "now summarize" }); expect(tail[1]).toEqual({ type: "input_image", image_url: "data:image/png;base64,aWc=" }); }); diff --git a/tests/claude-integration/claude-outbound.test.ts b/tests/claude-integration/claude-outbound.test.ts index 299ce5135d..e78cc529d3 100644 --- a/tests/claude-integration/claude-outbound.test.ts +++ b/tests/claude-integration/claude-outbound.test.ts @@ -13,6 +13,7 @@ import { TRANSLATOR_MAX_CALL_ARGUMENT_BYTES, type TranslatorBudget, } from "../../src/lib/translator-budget"; +import { decodeReasoningEnvelope, encodeReasoningEnvelope } from "../../src/responses/reasoning-envelope"; const streamBudgets = new WeakMap, TranslatorBudget>(); @@ -274,6 +275,8 @@ describe("claude outbound SSE", () => { "**A**\n\nOne.\n\n**B**\n\nTwo.", "Three.", ]); + expect(decodeReasoningEnvelope(thinkingBlocks[0].signature)?.txt) + .toBe("**A**\n\nOne.\n\n**B**\n\nTwo."); // Parity: the non-streaming translator joins the same summary parts identically. const json = responsesJsonToAnthropicMessage({ @@ -286,6 +289,59 @@ describe("claude outbound SSE", () => { expect(jsonThinking.thinking).toBe("**A**\n\nOne.\n\n**B**\n\nTwo."); }); + test("reasoning fallback buffering is bounded and releases its retained budget", async () => { + const budget = createTestTranslatorBudget({ maxTurnBytes: 8 * 1024 }); + let reasoningCommitted = 0; + let reasoningReleased = 0; + const trackedBudget: TranslatorBudget = { + openCall: id => budget.openCall(id), + closeCall: id => budget.closeCall(id), + reserveTransient(bytes, scope) { + const reservation = budget.reserveTransient(bytes, scope); + return { + commitRetained() { + reservation.commitRetained(); + if (scope.kind === "reasoning") reasoningCommitted += bytes; + }, + release: () => reservation.release(), + }; + }, + chargeRetained(bytes, scope) { + budget.chargeRetained(bytes, scope); + if (scope.kind === "reasoning") reasoningCommitted += bytes; + }, + releaseRetained(bytes, scope) { + budget.releaseRetained(bytes, scope); + if (scope.kind === "reasoning") reasoningReleased += bytes; + }, + observeAcceptedRequestCopy: bytes => budget.observeAcceptedRequestCopy(bytes), + observeExternallyCapped: (kind, bytes) => budget.observeExternallyCapped(kind, bytes), + snapshot: () => budget.snapshot(), + dispose: () => budget.dispose(), + }; + const frames = [ + sse("response.created", { response: { id: "resp_1", status: "in_progress" } }), + ...Array.from({ length: 32 }, (_, index) => sse("response.reasoning_text.delta", { + item_id: "rs_1", + content_index: 0, + delta: `${index}:` + "x".repeat(512), + })), + ]; + const events = await collectEvents(responsesSseToAnthropicSse( + streamFromChunks(frames), + "m", + { translatorBudget: trackedBudget }, + )); + + expect(events.at(-1)).toMatchObject({ + name: "error", + data: { error: { type: "request_too_large", code: "translation_buffer_limit" } }, + }); + expect(budget.snapshot().overflows).toBe(1); + expect(reasoningCommitted).toBeGreaterThan(0); + expect(reasoningReleased).toBe(reasoningCommitted); + }); + test("same-part deltas and index-free reasoning frames never get a separator", async () => { const samePart = [ sse("response.created", { response: { id: "resp_1", status: "in_progress" } }), @@ -1109,4 +1165,32 @@ describe("sanitizeWebSearchInput (#381)", () => { data: { error: { type: "request_too_large", code: "translation_buffer_limit" } }, }); }, 60_000); + + test("redacted-only reasoning emits a standalone redacted_thinking block", async () => { + const events = await collectEvents(responsesSseToAnthropicSse(streamFrom([ + sse("response.output_item.done", { + item: { type: "reasoning", id: "rs_red", encrypted_content: encodeReasoningEnvelope({ red: ["opaque"] }) }, + }), + sse("response.completed", { response: { status: "completed", usage: {} } }), + ].join("")), "m")); + expect(events.map(event => event.name)).toEqual([ + "message_start", "ping", "content_block_start", "content_block_stop", "message_delta", "message_stop", + ]); + expect(events[2].data.content_block).toEqual({ type: "redacted_thinking", data: "opaque" }); + }); + + test("signature-only reasoning emits an empty thinking block with the genuine signature", async () => { + const events = await collectEvents(responsesSseToAnthropicSse(streamFrom([ + sse("response.output_item.done", { + item: { type: "reasoning", id: "rs_sig", encrypted_content: encodeReasoningEnvelope({ sig: "sig-only" }) }, + }), + sse("response.completed", { response: { status: "completed", usage: {} } }), + ].join("")), "m")); + expect(events.map(event => event.name)).toEqual([ + "message_start", "ping", "content_block_start", "content_block_delta", "content_block_stop", + "message_delta", "message_stop", + ]); + expect(events[2].data.content_block).toEqual({ type: "thinking", thinking: "", signature: "" }); + expect(events[3].data.delta).toEqual({ type: "signature_delta", signature: "sig-only" }); + }); }); diff --git a/tests/claude-integration/claude-source-envelope.test.ts b/tests/claude-integration/claude-source-envelope.test.ts new file mode 100644 index 0000000000..a78c9f1a15 --- /dev/null +++ b/tests/claude-integration/claude-source-envelope.test.ts @@ -0,0 +1,30 @@ +import { describe, expect, test } from "bun:test"; +import { anthropicToResponsesBody } from "../../src/claude/inbound"; + +describe("Claude source envelope boundaries", () => { + test("nested tool results retain only bounded structured content", () => { + const body = anthropicToResponsesBody({ + model: "m", + messages: [ + { role: "assistant", content: [{ type: "tool_use", id: "call-1", name: "lookup", input: { q: "x" } }] }, + { role: "user", content: [{ type: "tool_result", tool_use_id: "call-1", content: [ + { type: "text", text: "ok" }, + { type: "document", title: "report" }, + { type: "future_block", payload: "secret-payload" }, + ] }] }, + ], + }) as any; + expect(body.input.map((item: any) => item.type)).toEqual(["function_call", "function_call_output"]); + expect(body.input[1].output).toEqual([ + { type: "input_text", text: "ok" }, + { type: "input_text", text: "[document: report]" }, + ]); + expect(JSON.stringify(body)).not.toContain("secret-payload"); + }); + + test("malformed tool results fail closed instead of becoming an unpaired output", () => { + expect(() => anthropicToResponsesBody({ + model: "m", messages: [{ role: "user", content: [{ type: "tool_result", content: "secret-payload" }] }], + })).toThrow(/unknown|unpaired|tool/i); + }); +}); diff --git a/tests/fixtures/test-layout-expected.json b/tests/fixtures/test-layout-expected.json index 6565f12821..928752d213 100644 --- a/tests/fixtures/test-layout-expected.json +++ b/tests/fixtures/test-layout-expected.json @@ -125,6 +125,7 @@ "claude-authmode-migration.test.ts": "claude-integration", "claude-cli.test.ts": "claude-integration", "claude-code-thought-signature-scope.test.ts": "claude-integration", + "claude-source-envelope.test.ts": "claude-integration", "claude-compatibility.test.ts": "claude-integration", "claude-context-windows.test.ts": "claude-integration", "claude-desktop-1m.test.ts": "claude-integration", @@ -1020,6 +1021,7 @@ "test-home-guard.test.ts": "ci-workflows", "test-runner.test.ts": "ci-workflows", "thought-signature-credential-scope.test.ts": "responses", + "reasoning-envelope.test.ts": "responses", "token-estimate.test.ts": "lib", "token-guardian.test.ts": "codex-integration", "tool-argument-integers.test.ts": "adapters", diff --git a/tests/responses/reasoning-envelope.test.ts b/tests/responses/reasoning-envelope.test.ts new file mode 100644 index 0000000000..75c51994f2 --- /dev/null +++ b/tests/responses/reasoning-envelope.test.ts @@ -0,0 +1,79 @@ +import { describe, expect, test } from "bun:test"; +import { anthropicToResponsesBody } from "../../src/claude/inbound"; +import { decodeReasoningEnvelope, encodeReasoningEnvelope } from "../../src/responses/reasoning-envelope"; +import { responsesJsonToAnthropicMessage } from "../../src/claude/outbound"; + +describe("reasoning and tool/result envelopes", () => { + test("preserves ordered thinking blocks and genuine signatures", () => { + const body = anthropicToResponsesBody({ + model: "m", messages: [{ role: "assistant", content: [ + { type: "thinking", thinking: "first", signature: "sig-first" }, + { type: "tool_use", id: "call-1", name: "Read", input: {} }, + { type: "thinking", thinking: "second", signature: "sig-second" }, + ] }], + }) as any; + expect(body.input.map((item: any) => item.type)).toEqual(["reasoning", "function_call", "reasoning"]); + expect(body.input[0].encrypted_content).toBe(encodeReasoningEnvelope({ sig: "sig-first" })); + expect(body.input[2].encrypted_content).toBe(encodeReasoningEnvelope({ sig: "sig-second" })); + }); + + test("rejects malformed or nested OpenCodex signatures", () => { + for (const signature of [ + "ocxr1:not-base64!!!", + encodeReasoningEnvelope({ sig: "nested" }), + encodeReasoningEnvelope({ sig: "", txt: "nested-empty-signature" }), + ]) { + expect(() => anthropicToResponsesBody({ + model: "m", messages: [{ role: "assistant", content: [{ type: "thinking", thinking: "x", signature }] }], + })).toThrow(); + } + }); + + test("round-trips redacted thinking without exposing it as a genuine signature", () => { + const encoded = encodeReasoningEnvelope({ sig: "sig", red: ["red-a", "red-b"] }); + const message = responsesJsonToAnthropicMessage({ + output: [{ type: "reasoning", summary: [{ type: "summary_text", text: "visible" }], encrypted_content: encoded }], + }, "m") as any; + expect(message.content[0]).toMatchObject({ type: "thinking", signature: "sig" }); + expect(message.content.slice(1)).toEqual([ + { type: "redacted_thinking", data: "red-a" }, + { type: "redacted_thinking", data: "red-b" }, + ]); + }); + + test("owned fallback is bounded and decodable", () => { + const message = responsesJsonToAnthropicMessage({ + output: [{ type: "reasoning", summary: [{ type: "summary_text", text: "think" }] }], + }, "m") as any; + const signature = message.content[0].signature as string; + expect(signature.startsWith("ocxr1:")).toBe(true); + expect(decodeReasoningEnvelope(signature)).toEqual({ txt: "think" }); + }); + + test("preserves an explicitly empty fallback text", () => { + expect(decodeReasoningEnvelope(encodeReasoningEnvelope({ txt: "" }))).toEqual({ txt: "" }); + }); + + test("inbound preserves redacted-only reasoning when visible text is empty", () => { + const body = anthropicToResponsesBody({ + model: "m", messages: [{ role: "assistant", content: [{ type: "redacted_thinking", data: "opaque" }] }], + }) as any; + expect(body.input).toHaveLength(1); + expect(body.input[0].type).toBe("reasoning"); + expect(decodeReasoningEnvelope(body.input[0].encrypted_content)?.red).toEqual(["opaque"]); + }); + + test("drops an empty unsigned thinking block", () => { + const body = anthropicToResponsesBody({ + model: "m", messages: [{ role: "assistant", content: [{ type: "thinking", thinking: "", signature: "" }] }], + }) as any; + expect(body.input).toEqual([]); + }); + + test("preserves signature-only reasoning in JSON output", () => { + const message = responsesJsonToAnthropicMessage({ + output: [{ type: "reasoning", summary: [], encrypted_content: encodeReasoningEnvelope({ sig: "sig-only" }) }], + }, "m") as any; + expect(message.content).toEqual([{ type: "thinking", thinking: "", signature: "sig-only" }]); + }); +}); From b2703f87017fd36789bac6689b1ec86ca00d9950 Mon Sep 17 00:00:00 2001 From: JUN <243035832+lidge-jun@users.noreply.github.com> Date: Mon, 7 Sep 2026 07:37:03 +0900 Subject: [PATCH 005/412] fix(grok): filter Codex control frames for strict Responses clients Carry PR #3816 at d5e0a9a2069ac5655dc208c7261981cd8c59112d. Keep original frames on the proxy inspection branch and scope projection to the existing Grok HTTP/SSE client marker. Co-authored-by: Danh Thanh --- src/server/grok-responses-control-frame.ts | 38 +++++++++++ src/server/responses/core.ts | 10 ++- .../responses-snapshot-repair-server.test.ts | 64 ++++++++++++++++++- 3 files changed, 106 insertions(+), 6 deletions(-) create mode 100644 src/server/grok-responses-control-frame.ts diff --git a/src/server/grok-responses-control-frame.ts b/src/server/grok-responses-control-frame.ts new file mode 100644 index 0000000000..cb572acee9 --- /dev/null +++ b/src/server/grok-responses-control-frame.ts @@ -0,0 +1,38 @@ +import { sseDataPayload, type SseBlockRewrite } from "./sse-payload-rewrite"; + +const GROK_CONTROL_FRAME_TYPES: Record = { + "codex.rate_limits": true, + "codex.response.metadata": true, +}; + +/** + * Hide Codex-only control frames from Grok's strict Responses decoder. + * + * The inspection branch still sees these frames before this client-facing + * rewrite, so quota accounting and response metadata remain available to the + * proxy while Grok receives only its declared Responses event variants. + */ +export function createGrokResponsesControlFrameBlockRewrite(): SseBlockRewrite { + return (block) => { + const eventName = block + .split(/\r?\n/) + .find(line => line.startsWith("event:")) + ?.slice("event:".length) + .trim(); + if (GROK_CONTROL_FRAME_TYPES[eventName ?? ""] === true) return []; + + const payload = sseDataPayload(block); + if (payload === null || payload === "[DONE]") return [block]; + + let event: unknown; + try { + event = JSON.parse(payload); + } catch { + return [block]; + } + if (!event || typeof event !== "object" || Array.isArray(event) || !("type" in event)) return [block]; + return typeof event.type === "string" && GROK_CONTROL_FRAME_TYPES[event.type] === true + ? [] + : [block]; + }; +} diff --git a/src/server/responses/core.ts b/src/server/responses/core.ts index 3c539c6d8e..e87136b67a 100644 --- a/src/server/responses/core.ts +++ b/src/server/responses/core.ts @@ -374,6 +374,7 @@ import { type UpstreamHostAdmissionLease, } from "../../codex/upstream-host-health"; import { createGrokResponsesSparseTerminalBlockRewrite } from "../grok-responses-snapshot-repair"; +import { createGrokResponsesControlFrameBlockRewrite } from "../grok-responses-control-frame"; import { createResponsesSnapshotBlockRewrite, hasResponsesSnapshotRepair, @@ -5494,9 +5495,9 @@ async function handleResponsesInner( // Grok Build renders deltas live but reconstructs its durable assistant // turn from the completed response snapshot. Native Responses streams // may instead carry the complete items in output_item.done, so the - // explicit Grok compatibility marker enables strict terminal-only repair. + // explicit Grok compatibility marker enables strict client compatibility rewrites. // The provider's broader snapshot/lifecycle repair remains opt-in. - const grokClientSnapshotRepairEnabled = logCtx.surface === "grok"; + const grokClientCompatibilityEnabled = logCtx.surface === "grok"; const snapshotRepairEnabled = hasResponsesSnapshotRepair(route.provider.responsesSnapshotRepair); const githubCopilotRepairEnabled = route.providerName === "github-copilot"; const responseModelRewrite = parsed._responseModelId !== undefined @@ -5545,7 +5546,10 @@ async function handleResponsesInner( githubCopilotRepairEnabled ? createGithubCopilotResponsesBlockRewrite(translatorBudget) : undefined, - grokClientSnapshotRepairEnabled + grokClientCompatibilityEnabled + ? createGrokResponsesControlFrameBlockRewrite() + : undefined, + grokClientCompatibilityEnabled ? createGrokResponsesSparseTerminalBlockRewrite(translatorBudget) : undefined, snapshotRepairEnabled diff --git a/tests/responses/responses-snapshot-repair-server.test.ts b/tests/responses/responses-snapshot-repair-server.test.ts index 214806b141..a7f3ec167c 100644 --- a/tests/responses/responses-snapshot-repair-server.test.ts +++ b/tests/responses/responses-snapshot-repair-server.test.ts @@ -58,12 +58,26 @@ const CODEX_SPARSE_TERMINAL_EVENTS = [ }, ]; -function sparseSseBody(events: readonly Record[] = SPARSE_EVENTS): ReadableStream { +const GROK_CONTROL_FRAME_EVENTS = [ + { + type: "codex.rate_limits", + rate_limits: { primary: { used_percent: 12, window_minutes: 60, reset_at: 123 } }, + }, + { type: "codex.response.metadata", headers: { "x-models-etag": "fixture" } }, + { type: "response.created", response: { id: "resp_control" } }, + { type: "response.completed", response: { id: "resp_control", status: "completed", output: [] } }, +]; + +function sparseSseBody( + events: readonly Record[] = SPARSE_EVENTS, + includeEventNames = false, +): ReadableStream { return new ReadableStream({ start(controller) { const encoder = new TextEncoder(); for (const event of events) { - controller.enqueue(encoder.encode(`data: ${JSON.stringify(event)}\n\n`)); + const eventLine = includeEventNames ? `event: ${event.type}\n` : ""; + controller.enqueue(encoder.encode(`${eventLine}data: ${JSON.stringify(event)}\n\n`)); } controller.enqueue(encoder.encode("data: [DONE]\n\n")); controller.close(); @@ -74,6 +88,7 @@ function sparseSseBody(events: readonly Record[] = SPARSE_EVENT function stubSparseGateway( origin: string, events: readonly Record[] = SPARSE_EVENTS, + includeEventNames = false, ): void { globalThis.fetch = (async (input: RequestInfo | URL, init?: RequestInit) => { const requestUrl = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url; @@ -82,7 +97,7 @@ function stubSparseGateway( return Response.json({ data: [] }); } if (url.origin === origin && url.pathname.endsWith("/responses")) { - return new Response(sparseSseBody(events), { + return new Response(sparseSseBody(events, includeEventNames), { status: 200, headers: { "content-type": "text/event-stream" }, }); @@ -326,6 +341,49 @@ describe("responsesSnapshotRepair through /v1/responses", () => { await server.stop(true); } }); + test("the Grok marker filters Codex control frames at the client boundary", async () => { + const gateway = "https://grok-control-frame.example.test"; + stubSparseGateway(gateway, GROK_CONTROL_FRAME_EVENTS, true); + saveConfig({ + port: 0, + defaultProvider: "sparse", + providers: { + sparse: { + adapter: "openai-responses", + baseUrl: `${gateway}/v1`, + authMode: "key", + apiKey: "test-key", + }, + }, + } as OcxConfig); + + const server = startServer(0); + try { + const request = (grokMarker: boolean) => originalFetch(new URL("/v1/responses", server.url), { + method: "POST", + headers: { + "content-type": "application/json", + ...(grokMarker ? { "x-opencodex-grok": "1" } : {}), + }, + body: JSON.stringify({ model: "sparse-model", input: "hi", stream: true }), + }); + + const grokResponse = await request(true); + expect(grokResponse.status).toBe(200); + const grokText = await grokResponse.text(); + expect(grokText).not.toContain("codex.rate_limits"); + expect(grokText).not.toContain("codex.response.metadata"); + expect(grokText).toContain('"type":"response.completed"'); + + const ordinaryResponse = await request(false); + expect(ordinaryResponse.status).toBe(200); + const ordinaryText = await ordinaryResponse.text(); + expect(ordinaryText).toContain("codex.rate_limits"); + expect(ordinaryText).toContain("codex.response.metadata"); + } finally { + await server.stop(true); + } + }); }); test("sparse JSON completion inference precedes function repair in client output and replay", async () => { From 0d42efa2845505224f9e1eff5f73f0b9bc46bf78 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 07:37:44 +0900 Subject: [PATCH 006/412] docs(plan): define axis five display and CLI delivery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Record source-delta audits, manual PR delivery and final-head CI strategy. Co-authored-by: Éverton Toffanetto Co-authored-by: Zig Zag Co-authored-by: 투린 --- .../260907_axis5_display_cli/000_plan.md | 33 +++++++++++++++++ .../001_roadmap_audit.md | 11 ++++++ .../260907_axis5_display_cli/010_delivery.md | 37 +++++++++++++++++++ 3 files changed, 81 insertions(+) create mode 100644 devlog/_plan/260907_axis5_display_cli/000_plan.md create mode 100644 devlog/_plan/260907_axis5_display_cli/001_roadmap_audit.md create mode 100644 devlog/_plan/260907_axis5_display_cli/010_delivery.md diff --git a/devlog/_plan/260907_axis5_display_cli/000_plan.md b/devlog/_plan/260907_axis5_display_cli/000_plan.md new file mode 100644 index 0000000000..222ef89899 --- /dev/null +++ b/devlog/_plan/260907_axis5_display_cli/000_plan.md @@ -0,0 +1,33 @@ +# Axis 5: display names and provider automation + +Date: 2026-09-07. Class C3, scoped satisfy-spec HOTL loop requested by owner. +Goal: deliver feasible unique changes from #3627, #2716, #3780 on dev with original author trailers. +Scope: display-only catalog metadata, discovered-model editor, optional JSONL CLI output, regression coverage and their docs. No auth/default/routing changes, native stacks, releases, or edits to existing dirty work. +Resources: existing repository/GitHub credentials and Astra high leaf agents; no user-set time/token cap. Isolated checkout /tmp/ocx-axis5-01a078d6. Owner authorizes no-verify push and admin merge. All local suites are prohibited; typecheck/build/test evidence will come from final combined GitHub CI. No invented lower-layer CI successes. +Terminal: merged, proven already delivered, or evidence-backed deferred when infeasible; finish after verifying all dispositions. New product decisions are isolated and deferred rather than guessed. +Records: this unit, .tmp/axis5-evidence, and session-bound .codexclaw goalplan. + +## Roadmap + +WP0: documentation-only source-delta and delivery plan, independent plan audit and document validation. +WP1: implement three scoped source carries with individual credited commits, publish ordinary manual PR chain, audit final tree, validate final combined head, merge verified layers bottom-up, and record dev ancestry. +The three layers are a user-requested review/integration sequence, not a claimed runtime dependency: native catalog -> JSONL CLI -> discovered editor. Source PR branches are never rewritten. +Read 010_delivery.md for diff-level scope and activation scenarios. + +## Sources + +- https://github.com/lidge-jun/opencodex/pull/3627 +- https://github.com/lidge-jun/opencodex/pull/2716 +- https://github.com/lidge-jun/opencodex/pull/3780 +- Base dev: 137d6a7270e7ecfb1c791993800a17c0e30022d9 +- Existing API display-name contract from #3212 is already on dev; only missing UI is carried. + +## CI and merge + +.github/workflows/ci.yml has pull_request triggers on all bases and workflow_dispatch lane=all for complete coverage. Pushes to feature branches do not independently trigger it. Defer/cancel only this task's lower-layer expensive runs as authorized, recording cancellation as cancellation. Dispatch all on final head; only if final CI fails use lower-layer runs to isolate. Do not edit shared workflow policy or fabricate check statuses. +Use merge commits and retain parent branches so commit identity and author trailers survive bottom-up merges. Retarget a child only after its parent lands. If dev moves concurrently, integrate the new dev into the top and refresh exact combined CI before shipping the resulting changed tree. +Review-ready requirements remain visible; local suite prohibition is explicitly documented instead of ticking a false local attestation. Admin waiver applies to the requested merge, not to truthful evidence. + +CI scope refinement: the discovered editor is the final layer so the final commit and PR diff include gui/**, activating GUI lint/build/artifact jobs. ci.yml gates always run GUI tests; docs deployment is NOT dispatched because it publishes. Public docs receive static source consistency inspection here, with docs build explicitly unverified unless an existing build-only remote path is available. + +CI scheduling refinement: lower-layer head commits may use GitHub documented [skip ci] to avoid push/pull_request suite launches; this yields missing/pending evidence, NOT green. Final head has no skip marker and receives lane=all workflow_dispatch. Source: https://docs.github.com/en/actions/how-tos/manage-workflow-runs/skip-workflow-runs (opened 2026-09-07). Admin merge records this explicit owner-requested lower-layer waiver. Do not propagate skip markers into integration merge messages. diff --git a/devlog/_plan/260907_axis5_display_cli/001_roadmap_audit.md b/devlog/_plan/260907_axis5_display_cli/001_roadmap_audit.md new file mode 100644 index 0000000000..2e4b740b4d --- /dev/null +++ b/devlog/_plan/260907_axis5_display_cli/001_roadmap_audit.md @@ -0,0 +1,11 @@ +# Roadmap audit closure + +WP0 documentation implementation, 2026-09-07. +Independent Astra high reviewers: Carver (#3627), Godel (#2716), Anscombe (#3780 and integrated roadmap). + +The integrated verdict was GO-WITH-FIXES (four blockers). The plan now distinguishes lower-layer waived CI from final combined passing evidence; removes the unreachable empty-provider CLI acceptance; requires confirmed-persistence reconciliation after GUI refresh failure; and requires timeout reachability analysis against the installed bounded-fetch wrapper before adding any timeout logic. + +Source heads: native f699ec7f998d56bf205db96762b821cd8c228a35; editor 93ed44053b68a9707f8271981d5f7e4bc25e9b70; JSONL 9b873e6f7519a022dd4658db4d1cb92689bb4663. +The physical manual chain is native -> JSONL -> GUI, enabling final GUI CI jobs. It is owner-requested integration ordering, not a claimed runtime dependency. +Native external-name preservation is qualified by existing pinned Astra normalization; existing policy remains intact. +No product tests, typecheck or build ran. WP0 checks only roadmap structure, source paths, explicit acceptance and credit records. Product verification remains WP1 remote CI. diff --git a/devlog/_plan/260907_axis5_display_cli/010_delivery.md b/devlog/_plan/260907_axis5_display_cli/010_delivery.md new file mode 100644 index 0000000000..b9cc7e2c4d --- /dev/null +++ b/devlog/_plan/260907_axis5_display_cli/010_delivery.md @@ -0,0 +1,37 @@ +# WP1: reconcile, deliver, verify and merge axis 5 + +Depends on WP0 roadmap audit. Source baseline dev 137d6a727. Previous D must confirm roadmap-only completion before production patches. + +## Layer 1 — #3627 native display names + +MODIFY src/codex/catalog/sync.ts: introduce reversible native label overlay at observed-state merge, restore original label before metadata normalization, strip marker from template clones, apply configured label to supported bare native rows only. MODIFY src/codex/convergence.ts: supply the same modelDisplayNames map as retained sync. MODIFY tests/codex-integration/codex-catalog.test.ts and provider configuration docs (English, Japanese, Korean, Simplified Chinese). +Field chain: existing providers.openai.modelDisplayNames config -> both merge call sites -> nativeDisplayNames argument -> display_name plus catalog-only opencodex_native_display_name {slug,original,applied} -> JSON catalog serialization -> restoration before next normalization. Clone consumers must remove overlay markers; source inputs remain immutable. +Activation: configured label replaces native name; removing/blanking restores owned original; external Sol rename is preserved; Astra remains subject to existing pinned-metadata normalization and docs/tests state that exception; newer native metadata upgrades after reset; repeated serialized cycles stable; account-qualified/combo/pro/custom rows unchanged. Exact model IDs and capabilities unchanged. +Credit: Co-authored-by: Éverton Toffanetto . + +## Layer 2 — #2716 discovered name editor + +NEW gui/src/components/ModelDisplayNameDialog.tsx and gui/tests/models-display-name-editor.test.tsx from source PR after current API contract comparison. MODIFY gui/src/pages/Models.tsx, models-shared.ts, gui/src/styles.css, all nine locale modules, English provider configuration docs. +Field chain: existing /api/models displayNameOverride/displayNameSource -> ModelRow optional fields -> Name action/dialog -> existing display-name save/reset endpoint -> persisted provider modelDisplayNames -> reload /api/models. No new persisted field or endpoint is needed. +Activation: save/reset/unchanged cancel; blank/too long/slash/control input; one submit under double click; save failure retains dialog; reload failure remains recoverable; focus returns after close; original selector always visible and alias action remains separate. +Credit: Co-authored-by: Zig Zag . +Browser smoke: render real isolated app, open Name dialog and observe screenshot; use mocked management responses or isolated disposable home, never mutate personal config. GUI tests/build/i18n/lint and docs build are remote CI obligations; not run locally. + +## Layer 3 — #3780 provider JSONL + +MODIFY src/cli/provider.ts and src/cli/capabilities.ts to accept --jsonl, emit existing configured-array objects one per line, reject combined --json/--jsonl before reading config. MODIFY tests/cli/cli-provider.test.ts, public CLI docs and skills/ocx/references/01_management_surface.md, 02_json_shapes.md, 03_recipes.md. Regenerate or reconcile derived surface with generator source; no unrelated output. +Field chain: argv -> consumeFlag -> output choice; no config serialization changes. JSONL entries use exactly existing JSON configured fields; no credentials added. The real config loader seeds providers; a zero-provider CLI scenario is not a reachable acceptance claim. Preserve existing loader behavior. Extend source tests to compare every emitted object with --json.configured for multiple registry/custom providers, ensure empty stdout on both conflicting flag orders, and verify escaping. Update all seven translated CLI provider tables and describe consumer-side line processing without claiming producer streaming. +Activation: multiple providers including custom names -> one parseable record each; default human and --json unchanged; both flags rejected; unknown args still rejected; conflicting flags -> empty stdout before config loading. +Credit: Co-authored-by: 투린 . + +## Verification and disposition + +Static git diff --check and independent source audits throughout. Existing focused test paths are reviewed for target coverage, but ALL LOCAL SUITES NOT RUN by owner instruction. Final ci.yml workflow_dispatch lane=all on published final SHA supplies typecheck, full tests and platform results; inspect actual job conclusions and head SHA. Add missing coverage within source scope if audit identifies a contract gap. Inspect GUI workflow coverage and obtain remote GUI/build evidence if not present in final dispatch. +Source-of-truth: provider configuration and CLI docs above; update structure/03_catalog-and-subagents.md only for native overlay contract. No new enforcement layer; tests/CI are evidence, admin bypass is owner-authorized and recorded. +Before merging: fresh heads and native membership, independent review dispositions, final CI proof, original author trailers, screenshot for GUI PR. If infeasible, record concrete cause and leave only that layer unmerged. After each merge: verify mergeCommit SHA and inclusion on fetched dev. Close superseded original PR only once its delivery is on dev and preserve attribution. + +Audit amendment: native label restoration preserves an external edit only subject to existing metadata normalization, notably pinned Astra replacement. Do not change native normalization policy. Add the Astra external-edit regression and qualify the promise consistently in all four affected docs. The native feature must preserve metadata including capabilities; English/Japanese wording is explicit. Final physical branch order is native -> JSONL -> GUI to activate final GUI gates; numeric sections above identify features, not alternate dependency claims. + +GUI audit amendment: confirmed persisted save/reset must reconcile editor snapshot and draft even when reload fails. A saved:true error is distinct from an unpersisted error. Stalled requests must not lock every dialog exit indefinitely: use existing UI request cancellation/deadline conventions, and represent uncertain write outcome without claiming rollback. Add focused source tests for first-save/reset plus reload failure, saved:true errors, duplicate protection and stalled cancellation. + +Plan audit synthesis (Astra high Anscombe): GO-WITH-FIXES, four blockers folded. (1) Lower layer CI is explicitly waived/deferred, never labeled passing; fresh head/base checks plus resulting tree equivalence tie admin merges to final combined evidence. (2) Removed unreachable empty-provider CLI scenario; loader behavior preserved. (3) Confirmed-persistence vs refresh state and tests required. (4) First rederive stalled-request reachability through installed global createBoundedFetch; reuse existing bound if it already applies, add no duplicate budget. Any remaining timeout scenario must be production-reachable. From ef54e8275d6fe00afbfa1039a79379dcf9041f68 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 07:38:00 +0900 Subject: [PATCH 007/412] docs: describe BigModel and Raycast integration contracts Carry architecture context for #3641 and #3733. Live BigModel discovery remains deferred; local suites are not run. Co-authored-by: jamespan Co-authored-by: Chanhee Lee --- structure/01_runtime.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/structure/01_runtime.md b/structure/01_runtime.md index 7fb1c00997..1601e5762b 100644 --- a/structure/01_runtime.md +++ b/structure/01_runtime.md @@ -166,6 +166,22 @@ OAuth presets resolve discovery against the same canonical registry transport as before any adapter-specific transport override, so a stale configured `baseUrl` cannot receive an OAuth bearer token. +The BigModel Coding Plan Responses preset uses the separately documented +`https://open.bigmodel.cn/api/v1` transport and a static catalog. Its provider row +disables live discovery: a local Codex `models.json` example does not establish an +authenticated HTTP models endpoint. Its static context and reasoning metadata are +kept in the canonical registry, including an explicit empty selectable effort +ladder for `glm-5-turbo`. + +Raycast is a managed client export, not an upstream model provider. Its YAML +contribution owns only the unique `providers/[id=opencodex]` entry, with the +existing manifest and fingerprint checks protecting user-owned provider values. +Ambiguous selector matches and incompatible containers cannot be adopted or +mutated. Catalog refresh uses the existing owned-integration activation check; +an unowned client remains disconnected. OpenCodex omits Raycast API-key fields +and exports only to eligible local targets. Pro detection is an advisory hint, +not an authentication or entitlement decision. + ## Remote Hub hardening ownership `src/remote/protocol.ts` owns pure interval/feature negotiation. `src/client/hub-client.ts` owns bounded, schema-validated remote catalog consumption and key-id probes. `src/client/hub-relay.ts` is a fixed-authority management relay with URL, header, body, redirect, and stream bounds. The public data listener remains the direct client→hub path; the loopback management ingress never serves data-plane routes. From 6a51f048e7e4eea7861f331f84dc241e61db035a Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 07:38:22 +0900 Subject: [PATCH 008/412] test(oauth): drain ACL flights before fixture teardown [skip ci] Carry the remaining teardown fix from #3383 (51726d2c7) and verify cleanup ordering with a held asynchronous runner. Final combined CI will validate the stack; no local suite was run. Co-authored-by: x3M3x --- tests/oauth/oauth-store-multi.test.ts | 86 +++++++++++++++++++++++---- 1 file changed, 73 insertions(+), 13 deletions(-) diff --git a/tests/oauth/oauth-store-multi.test.ts b/tests/oauth/oauth-store-multi.test.ts index 6cd3f21dbe..02d8f8024f 100644 --- a/tests/oauth/oauth-store-multi.test.ts +++ b/tests/oauth/oauth-store-multi.test.ts @@ -4,10 +4,14 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs"; import { join } from "node:path"; import * as atomicWrite from "../../src/config/atomic-write"; import * as oauthStore from "../../src/oauth/store"; +import { flushConfigDirHardeningForTests } from "../../src/config/paths"; import { resetHardenedStateForTests, + setAsyncIcaclsRunnerForTests, setIcaclsRunnerForTests, + setPlatformForTests, } from "../../src/lib/windows-secret-acl"; +import { setSyntheticWindowsPrincipalForTests } from "../../src/lib/windows-user-principal"; import { getAccountCredential, getAccountSet, @@ -35,6 +39,17 @@ import { removeTreeWithRetry } from "../helpers/remove-tree"; const TEST_DIR = join(import.meta.dir, ".tmp-oauth-store-multi-test"); let previousOpencodexHome: string | undefined; +const ICACLS_OK = { success: true, exitCode: 0, timedOut: false, stdout: "" }; + +async function cleanupOAuthStoreFixture(): Promise { + await flushConfigDirHardeningForTests(); + setIcaclsRunnerForTests(null); + setAsyncIcaclsRunnerForTests(null); + resetHardenedStateForTests(); + if (previousOpencodexHome === undefined) delete process.env.OPENCODEX_HOME; + else process.env.OPENCODEX_HOME = previousOpencodexHome; + if (existsSync(TEST_DIR)) removeTreeWithRetry(TEST_DIR); +} const cred = (over: Partial = {}): OAuthCredentials => ({ access: "access-1", @@ -61,21 +76,66 @@ describe("multi-account auth store", () => { mkdirSync(TEST_DIR, { recursive: true }); process.env.OPENCODEX_HOME = TEST_DIR; resetHardenedStateForTests(); - setIcaclsRunnerForTests(() => ({ - success: true, - exitCode: 0, - timedOut: false, - stdout: "", - })); + setIcaclsRunnerForTests(() => ICACLS_OK); + setAsyncIcaclsRunnerForTests(async () => ICACLS_OK); }); - afterEach(() => { - setIcaclsRunnerForTests(null); - resetHardenedStateForTests(); - if (previousOpencodexHome === undefined) delete process.env.OPENCODEX_HOME; - else process.env.OPENCODEX_HOME = previousOpencodexHome; - if (existsSync(TEST_DIR)) removeTreeWithRetry(TEST_DIR); - }); + afterEach(cleanupOAuthStoreFixture); + + test("fixture cleanup waits for a held config-directory ACL flight before restoring home or deleting files", async () => { + let release!: () => void; + const held = new Promise(resolve => { release = resolve; }); + let markStarted!: () => void; + const started = new Promise(resolve => { markStarted = resolve; }); + let deadlineTimer: ReturnType | undefined; + let cleaning: Promise | undefined; + let cleanupSettled = false; + setPlatformForTests("win32"); + // Keep SID discovery hermetic on Windows as well as on forced POSIX lanes. + setSyntheticWindowsPrincipalForTests("*S-1-5-21-1-2-3-1001"); + setAsyncIcaclsRunnerForTests(async () => { + markStarted(); + await held; + return ICACLS_OK; + }); + try { + // A real store read starts the production-tracked directory hardening flight. + expect(getAccountSet("xai")).toBeNull(); + await Promise.race([ + started, + new Promise((_, reject) => { + deadlineTimer = setTimeout(() => reject(new Error("ACL runner did not start")), INTERNAL_DEADLINE_MS); + }), + ]); + clearTimeout(deadlineTimer); + cleaning = cleanupOAuthStoreFixture().then( + () => { cleanupSettled = true; return null; }, + (error: unknown) => { cleanupSettled = true; return error; }, + ); + // An event-loop checkpoint lets an incorrectly unawaited cleanup finish; no sleep oracle. + await new Promise(resolve => setImmediate(resolve)); + expect(cleanupSettled).toBe(false); + expect(process.env.OPENCODEX_HOME).toBe(TEST_DIR); + expect(existsSync(TEST_DIR)).toBe(true); + + release(); + expect(await cleaning).toBeNull(); + expect(cleanupSettled).toBe(true); + expect(process.env.OPENCODEX_HOME).toBe(previousOpencodexHome); + expect(existsSync(TEST_DIR)).toBe(false); + } finally { + if (deadlineTimer !== undefined) clearTimeout(deadlineTimer); + // Even a broken cleanup must not release the held flight into the real runner. + setAsyncIcaclsRunnerForTests(async () => ICACLS_OK); + release(); + try { + await cleaning; + await flushConfigDirHardeningForTests(); + } finally { + setPlatformForTests(null); + } + } + }, STORE_BUDGET_MS); test("legacy single-credential auth.json normalizes and round-trips without losing login", async () => { const authPath = join(TEST_DIR, "auth.json"); From 336c621a35b63e4dec5bff235f897f92adeae2c7 Mon Sep 17 00:00:00 2001 From: JUN <243035832+lidge-jun@users.noreply.github.com> Date: Mon, 7 Sep 2026 07:38:20 +0900 Subject: [PATCH 009/412] fix(grok): honor SSE event order and empty resets Use the last event field and preserve significant whitespace while retaining independent JSON control-type filtering. Add discriminator, order, reset, and preservation regressions to the existing Responses test file. Tests were authored but not run; validation is delegated to final combined remote CI. Co-authored-by: Danh Thanh --- src/server/grok-responses-control-frame.ts | 17 ++++-- .../responses-snapshot-repair-server.test.ts | 60 ++++++++++++++++++- 2 files changed, 69 insertions(+), 8 deletions(-) diff --git a/src/server/grok-responses-control-frame.ts b/src/server/grok-responses-control-frame.ts index cb572acee9..e910daf99d 100644 --- a/src/server/grok-responses-control-frame.ts +++ b/src/server/grok-responses-control-frame.ts @@ -14,12 +14,17 @@ const GROK_CONTROL_FRAME_TYPES: Record = { */ export function createGrokResponsesControlFrameBlockRewrite(): SseBlockRewrite { return (block) => { - const eventName = block - .split(/\r?\n/) - .find(line => line.startsWith("event:")) - ?.slice("event:".length) - .trim(); - if (GROK_CONTROL_FRAME_TYPES[eventName ?? ""] === true) return []; + let eventName = ""; + // SSE overwrites the event type on every event field, including empty resets. + // Like sseDataPayload, remove only one optional ASCII space after the colon. + for (const line of block.split(/\r?\n/)) { + if (line === "event") eventName = ""; + else if (line.startsWith("event:")) { + const value = line.slice("event:".length); + eventName = value.startsWith(" ") ? value.slice(1) : value; + } + } + if (GROK_CONTROL_FRAME_TYPES[eventName] === true) return []; const payload = sseDataPayload(block); if (payload === null || payload === "[DONE]") return [block]; diff --git a/tests/responses/responses-snapshot-repair-server.test.ts b/tests/responses/responses-snapshot-repair-server.test.ts index a7f3ec167c..f6e4ac0e92 100644 --- a/tests/responses/responses-snapshot-repair-server.test.ts +++ b/tests/responses/responses-snapshot-repair-server.test.ts @@ -6,6 +6,7 @@ import { saveConfig } from "../../src/config"; import { startServer } from "../../src/server"; import { handleResponses } from "../../src/server/responses"; import { isEagerRelaySseResponse } from "../../src/server/relay"; +import { createGrokResponsesControlFrameBlockRewrite } from "../../src/server/grok-responses-control-frame"; import type { OcxConfig } from "../../src/types"; import { installIsolatedCodexHome, type IsolatedCodexHome } from "../helpers/isolated-codex-home"; import { removeTreeWithRetry } from "../helpers/remove-tree"; @@ -118,6 +119,61 @@ afterEach(async () => { removeTreeWithRetry(TEST_DIR); }); +for (const controlType of ["codex.rate_limits", "codex.response.metadata"]) { + describe(`Grok control frame ${controlType}`, () => { + test.each(["{}", "not-json"])("filters an event-only discriminator with payload %s", payload => { + const rewrite = createGrokResponsesControlFrameBlockRewrite(); + expect(rewrite(`event: ${controlType}\ndata: ${payload}`)).toEqual([]); + }); + + test("filters a data-only discriminator without an event field", () => { + const rewrite = createGrokResponsesControlFrameBlockRewrite(); + expect(rewrite(`data: {"type":"${controlType}"}`)).toEqual([]); + }); + + test.each(["{}", "not-json"])("filters the last event field with payload %s", payload => { + const rewrite = createGrokResponsesControlFrameBlockRewrite(); + expect(rewrite(`event: message\nevent: ${controlType}\ndata: ${payload}`)).toEqual([]); + }); + + test("preserves completion when the last event field overrides a control type", () => { + const block = `event: ${controlType}\nevent: response.completed\ndata: {"type":"response.completed","response":{"id":"r1","status":"completed","output":[]}}`; + expect(createGrokResponsesControlFrameBlockRewrite()(block)).toEqual([block]); + }); + + test.each(["event:", "event: ", "event"])("honors the empty reset %s", reset => { + const block = `event: ${controlType}\n${reset}\ndata: {}`; + expect(createGrokResponsesControlFrameBlockRewrite()(block)).toEqual([block]); + }); + + test("still filters the JSON type after an empty event reset", () => { + const block = `event: ${controlType}\nevent:\ndata: {"type":"${controlType}"}`; + expect(createGrokResponsesControlFrameBlockRewrite()(block)).toEqual([]); + }); + + test.each([`event: ${controlType}`, `event:\t${controlType}`, `event: ${controlType} `])( + "preserves significant event-value whitespace in %s", + eventLine => { + const block = `${eventLine}\ndata: {}`; + expect(createGrokResponsesControlFrameBlockRewrite()(block)).toEqual([block]); + }, + ); + + test("recognizes a CRLF event field without an optional space", () => { + expect(createGrokResponsesControlFrameBlockRewrite()(`event:message\r\nevent:${controlType}\r\ndata: {}`)).toEqual([]); + }); + + test("does not retain the event type across blocks or consume ordinary content", () => { + const rewrite = createGrokResponsesControlFrameBlockRewrite(); + expect(rewrite(`event: ${controlType}\ndata: {}`)).toEqual([]); + for (const block of ["data: {}", "data: not-json", ": heartbeat", "data: [DONE]", + `data: {"type":"response.output_text.delta","delta":"${controlType}"}`]) { + expect(rewrite(block)).toEqual([block]); + } + }); + }); +} + describe("responsesSnapshotRepair through /v1/responses", () => { test.skipIf(process.platform !== "darwin")( "Darwin eager-relay applies snapshot repair inline before bytes reach the client", @@ -341,9 +397,9 @@ describe("responsesSnapshotRepair through /v1/responses", () => { await server.stop(true); } }); - test("the Grok marker filters Codex control frames at the client boundary", async () => { + test.each([true, false])("the Grok marker filters Codex control frames at the client boundary (event names: %s)", async includeEventNames => { const gateway = "https://grok-control-frame.example.test"; - stubSparseGateway(gateway, GROK_CONTROL_FRAME_EVENTS, true); + stubSparseGateway(gateway, GROK_CONTROL_FRAME_EVENTS, includeEventNames); saveConfig({ port: 0, defaultProvider: "sparse", From 9cde6e735294f4605e2a8655dda4aaac195beb04 Mon Sep 17 00:00:00 2001 From: JUN <243035832+lidge-jun@users.noreply.github.com> Date: Mon, 7 Sep 2026 07:38:27 +0900 Subject: [PATCH 010/412] test(responses): cover established task delivery and compaction Add one synthetic complete send_message_to_thread envelope after a real tool pair. Cover ordinary responses, stored-ID continuation, v2 compaction_trigger and v1 compact; assert upstream content, order and pairing plus compact output contracts. Coverage motivated by issue #3807 reports from @DaveW001 and @stephen-drew, using the narrowed envelope contract documented in #3735. These are synthetic fixtures, not captured reporter requests; no original source patch is copied. Validation: git diff --check passed. Tests, typecheck and build NOT RUN by explicit instruction. Production code and missing-call-id guards are unchanged. --- .../responses-compaction-routing.test.ts | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/tests/responses/responses-compaction-routing.test.ts b/tests/responses/responses-compaction-routing.test.ts index 8e92f28715..8faca32bef 100644 --- a/tests/responses/responses-compaction-routing.test.ts +++ b/tests/responses/responses-compaction-routing.test.ts @@ -1776,6 +1776,130 @@ describe("external task-input envelopes (#3735)", () => { } }); +describe("established-history external task input (#3807)", () => { + // Synthetic complete envelope from the #3735 contract; #3807's history rendering + // is not a captured outbound request. Keep the real tool pair distinct from delivery. + const deliveryText = " Follow up on the earlier tool result.\n"; + const acknowledged = "Delivery acknowledged."; + const continuationText = "Continue the established task."; + const summary = "Earlier tool returned 7; follow-up delivery is pending."; + const history = () => [ + { type: "message", role: "user", content: "Read the earlier value." }, + { type: "function_call", call_id: "call_history", name: "read_value", arguments: "{}" }, + { type: "function_call_output", call_id: "call_history", output: "earlier value: 7" }, + { type: "message", role: "assistant", content: "Earlier result recorded." }, + { + type: "function_call_output", id: "fco_external_followup", + name: "send_message_to_thread", namespace: "codex_app", output: deliveryText, + }, + ]; + const requestBody = () => ({ + model: "gw/model", stream: false, store: false, input: history(), + tools: [{ type: "function", name: "read_value", parameters: { type: "object", properties: {} } }], + }); + const wireHistory = [ + { role: "user", content: "Read the earlier value." }, + { role: "assistant", tool_calls: [{ id: "call_history", type: "function", function: { name: "read_value", arguments: "{}" } }] }, + { role: "tool", tool_call_id: "call_history", content: "earlier value: 7" }, + { role: "assistant", content: "Earlier result recorded." }, + { role: "user", content: deliveryText }, + ]; + + function captureChat(text: string): Array> { + const captured: Array> = []; + globalThis.fetch = (async (_url: unknown, init?: RequestInit) => { + captured.push(JSON.parse(String(init?.body))); + return jsonResponse({ + choices: [{ index: 0, message: { role: "assistant", content: text }, finish_reason: "stop" }], + usage: { prompt_tokens: 10, completion_tokens: 5 }, + }); + }) as typeof fetch; + return captured; + } + + function expectHistory(sent: Record, tail: Array> = []) { + const messages = sent.messages as Array>; + expect(messages).toHaveLength(wireHistory.length + tail.length); + expect(messages).toMatchObject([...wireHistory, ...tail]); + // Exactly one original pair: delivery must not acquire a synthesized tool identity. + expect(messages.flatMap(message => message.tool_calls ?? [])).toEqual(wireHistory[1]!.tool_calls); + expect(messages.filter(message => message.role === "tool")).toEqual([wireHistory[2]]); + expect(JSON.stringify(sent)).not.toContain("[tool output for unknown call]"); + } + + test("ordinary response preserves inter-task delivery after an established tool pair", async () => { + const captured = captureChat(acknowledged); + const res = await handleResponses(compactionRequest(requestBody()), + keyProviderConfig({ adapter: "openai-chat" }), { model: "", provider: "" }); + expect(res.status).toBe(200); + const json = await res.json() as { status?: string }; + expect(json.status).toBe("completed"); + expect(captured).toHaveLength(1); + expectHistory(captured[0]!); + }); + + test("stored-ID continuation replays the established tool pair and inter-task delivery in order", async () => { + const captured = captureChat(acknowledged); + const config = keyProviderConfig({ adapter: "openai-chat" }); + const first = await handleResponses(compactionRequest({ ...requestBody(), store: true }), + config, { model: "", provider: "" }); + expect(first.status).toBe(200); + const saved = await first.json() as { id: string; status?: string }; + expect(saved.status).toBe("completed"); + expect(typeof saved.id).toBe("string"); + expect(saved.id.length).toBeGreaterThan(0); + expect(captured).toHaveLength(1); + expectHistory(captured[0]!); + + // Send only the new user turn: the handler must retrieve the previous raw history. + const res = await handleResponses(compactionRequest({ + ...requestBody(), previous_response_id: saved.id, + input: [{ type: "message", role: "user", content: continuationText }], + }), config, { model: "", provider: "" }); + expect(res.status).toBe(200); + const json = await res.json() as { status?: string }; + expect(json.status).toBe("completed"); + expect(captured).toHaveLength(2); + expectHistory(captured[1]!, [ + { role: "assistant", content: acknowledged }, + { role: "user", content: continuationText }, + ]); + }); + + for (const version of ["v2 trigger", "v1 compact"] as const) { + test(`${version} preserves established-history delivery and pairing before summarization`, async () => { + const captured = captureChat(summary); + const config = keyProviderConfig({ adapter: "openai-chat" }); + const res = version === "v2 trigger" + ? await handleResponses(compactionRequest({ + ...requestBody(), input: [...history(), { type: "compaction_trigger" }], + }), config, { model: "", provider: "" }) + : await handleResponsesCompact(new Request("http://localhost/v1/responses/compact", { + method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(requestBody()), + }), config, { model: "", provider: "" }); + expect(res.status).toBe(200); + const json = await res.json() as { output: Array> }; + expect(captured).toHaveLength(1); + expectHistory(captured[0]!, [ + { role: "user", content: expect.stringContaining("CONTEXT CHECKPOINT COMPACTION") }, + ]); + expect(captured[0]!.tools).toBeUndefined(); + expect(JSON.stringify(captured)).not.toContain("compaction_trigger"); + if (version === "v2 trigger") { + expect(json.output.filter(item => item.type === "compaction")).toEqual([{ + type: "compaction", id: expect.stringMatching(/^cmp_/), + encrypted_content: `ocx1:${Buffer.from(summary, "utf8").toString("base64")}`, + }]); + } else { + expect(json.output).toEqual([ + { type: "message", role: "user", content: [{ type: "input_text", text: "Read the earlier value." }] }, + { type: "message", role: "user", content: [{ type: "input_text", text: expect.stringContaining(`\n${summary}`) }] }, + ]); + } + }); + } +}); + describe("unpaired tool result boundary (#3259)", () => { function unpairedBody(item: Record): Record { return { From cb8ac02b96eb7ae055c1faab9d7ba85fac1f9412 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 07:39:36 +0900 Subject: [PATCH 011/412] fix(diagnostics): distinguish inbound size measurement provenance [skip ci] Report declared wire length, observed lower bounds, and decoded sizes without reading rejected payloads further or changing admission and retry policy. Follow up on #3573; thanks to @nowhere1975 for the content-free incident measurements. The issue remains open for exact compact-attempt evidence. Independent source review passed; final remote CI pending. --- .../content/docs/reference/proxy-formats.md | 25 +++- src/server/request-decompress.ts | 42 ++++-- tests/usage/request-decompress.test.ts | 127 ++++++++++++++++-- 3 files changed, 172 insertions(+), 22 deletions(-) diff --git a/docs-site/src/content/docs/reference/proxy-formats.md b/docs-site/src/content/docs/reference/proxy-formats.md index 7008194e19..cb97ad7076 100644 --- a/docs-site/src/content/docs/reference/proxy-formats.md +++ b/docs-site/src/content/docs/reference/proxy-formats.md @@ -409,7 +409,30 @@ default provider is enabled and is not itself an OpenAI-family entry; account-qu such as `side/gpt-5.6-sol` still fail closed. The proxy logs one notice per provider when this fallback engages. Configurations with an enabled canonical `openai` provider are unchanged. -Native compact responses are buffered with a 32 MiB maximum, including responses whose declared +Inbound bodies on both `/v1/responses` and `/v1/responses/compact` retain the shared 256 MiB +wire/decompression admission limit. Application-level size rejection returns HTTP 413 with +`type` and `code` both `invalid_request_error`. Its message includes a bounded diagnostic suffix, +for example: + +```text +Decompressed request body exceeds 268435456 bytes [measurement=decoded_lower_bound; bytes=268435457] +``` + +| Measurement | Meaning of `bytes` | +| --- | --- | +| `declared_wire` | Numeric `Content-Length` declared by the sender; rejected before reading, not a measured decoded size | +| `observed_wire_lower_bound` | Wire bytes encountered when reading stopped; the complete body may be larger | +| `decoded_exact` | Exact size of the buffer supplied to the identity decoder or returned by a decoder | +| `decoded_lower_bound` | Admission limit plus one after inflation aborts; a lower bound, never the exact decoded size | + +The suffix contains only a fixed category and a finite numeric byte value. Rejected bodies are +not read or inflated further, parsed for item counts, or retained for diagnostics. Legacy errors +without measurement provenance retain the limit-only message. Bun's listener can reject an +oversized wire body before application diagnostics run, so not every 413 carries this suffix. +A lower-bound diagnostic cannot establish the complete compact payload size. The admission +limit and retry behavior are unchanged. + +Native compact responses are buffered with a separate 32 MiB maximum, including responses whose declared `Content-Length` already exceeds the limit. The compact-specific failures include: | Status | Type or code | Meaning | diff --git a/src/server/request-decompress.ts b/src/server/request-decompress.ts index 0710470346..297c77a9d1 100644 --- a/src/server/request-decompress.ts +++ b/src/server/request-decompress.ts @@ -27,14 +27,39 @@ export class UnsupportedContentEncodingError extends Error { } } +export type BodySizeMeasurement = + | "declared_wire" + | "observed_wire_lower_bound" + | "decoded_exact" + | "decoded_lower_bound"; + export class DecompressedBodyTooLargeError extends Error { - constructor(readonly bytes: number, limit: number = MAX_DECOMPRESSED_BODY_BYTES) { - super(`Decompressed request body exceeds ${limit} bytes`); + readonly measurement: BodySizeMeasurement | null; + + constructor( + readonly bytes: number, + readonly limit: number = MAX_DECOMPRESSED_BODY_BYTES, + measurement: BodySizeMeasurement | null = null, + ) { + // Legacy callers supply no provenance. Only fixed categories and finite + // numbers may reach the public message, including calls from untyped code. + const category = measurement === "declared_wire" || measurement === "observed_wire_lower_bound" + || measurement === "decoded_exact" || measurement === "decoded_lower_bound" + ? measurement : null; + const suffix = category !== null && Number.isFinite(bytes) && bytes >= 0 + && Number.isFinite(limit) && limit >= 0 + ? ` [measurement=${category}; bytes=${bytes}]` : ""; + super(`Decompressed request body exceeds ${Number.isFinite(limit) ? limit : "unknown"} bytes${suffix}`); + this.measurement = category; } } -function assertBodySizeWithinLimit(body: Uint8Array, maxBytes: number): Uint8Array { - if (body.byteLength > maxBytes) throw new DecompressedBodyTooLargeError(body.byteLength, maxBytes); +function assertBodySizeWithinLimit( + body: Uint8Array, + maxBytes: number, + measurement: BodySizeMeasurement = "decoded_exact", +): Uint8Array { + if (body.byteLength > maxBytes) throw new DecompressedBodyTooLargeError(body.byteLength, maxBytes, measurement); return body; } @@ -112,7 +137,7 @@ async function readRequestBodyBytesCapped( if (!value || value.byteLength === 0) continue; if (value.byteLength > maxBytes - retainedBytes) { - const error = new DecompressedBodyTooLargeError(retainedBytes + value.byteLength, maxBytes); + const error = new DecompressedBodyTooLargeError(retainedBytes + value.byteLength, maxBytes, "observed_wire_lower_bound"); cancel(error); throw error; } @@ -173,7 +198,8 @@ export function decodeRequestBody( else throw new UnsupportedContentEncodingError(encoding); } catch (err) { if ((err as NodeJS.ErrnoException | null)?.code === "ERR_BUFFER_TOO_LARGE") { - throw new DecompressedBodyTooLargeError(maxBytes + 1, maxBytes); + // Inflation stopped at the cap; the full decoded size was never measured. + throw new DecompressedBodyTooLargeError(maxBytes + 1, maxBytes, "decoded_lower_bound"); } throw err; } @@ -198,7 +224,7 @@ export async function readBoundedJsonRequestBody( // Reject an honest oversized declaration before reading. Missing, malformed, // and dishonest declarations remain bounded by the streaming reader below. if (declaredLength !== null && declaredLength > maxBytes) { - const error = new DecompressedBodyTooLargeError(declaredLength, maxBytes); + const error = new DecompressedBodyTooLargeError(declaredLength, maxBytes, "declared_wire"); cancelStreamWithoutWaiting(req.body, error); throw error; } @@ -211,7 +237,7 @@ export async function readBoundedJsonRequestBody( } finally { releaseReservation?.(); } - assertBodySizeWithinLimit(raw, maxBytes); + assertBodySizeWithinLimit(raw, maxBytes, "observed_wire_lower_bound"); const releaseRaw = budget?.observeAcceptedRequestCopy(raw.byteLength); let releaseDecoded: (() => void) | undefined; let releaseText: (() => void) | undefined; diff --git a/tests/usage/request-decompress.test.ts b/tests/usage/request-decompress.test.ts index 7a536600cc..96a8f5a67a 100644 --- a/tests/usage/request-decompress.test.ts +++ b/tests/usage/request-decompress.test.ts @@ -1,4 +1,5 @@ import { describe, expect, test } from "bun:test"; +import { deflateRawSync, deflateSync } from "node:zlib"; import { DecompressedBodyTooLargeError, decodeRequestBody, @@ -9,11 +10,35 @@ import { } from "../../src/server/request-decompress"; import { MANAGEMENT_JSON_BODY_MAX_BYTES } from "../../src/server/management/body"; import { handleManagementAPI } from "../../src/server/management-api"; +import { decodeRequestErrorResponse } from "../../src/server/responses/core"; import type { OcxConfig } from "../../src/types"; const PAYLOAD = { model: "gpt-5.5", input: "hello", stream: true }; const PAYLOAD_BYTES = new TextEncoder().encode(JSON.stringify(PAYLOAD)); +async function captureBodyTooLarge(run: () => unknown): Promise { + try { + await run(); + } catch (error) { + if (!(error instanceof DecompressedBodyTooLargeError)) throw error; + return error; + } + throw new Error("Expected body admission to reject"); +} + +async function expectBodyLimitResponse(error: DecompressedBodyTooLargeError, message: string): Promise { + expect(error.message).toBe(message); + expect(message.length).toBeLessThan(200); + for (const label of ["responses", "responses-compact"]) { + const response = decodeRequestErrorResponse(error, label); + expect(response.status).toBe(413); + expect(response.headers.get("retry-after")).toBeNull(); + expect(await response.json()).toEqual({ + error: { message, type: "invalid_request_error", code: "invalid_request_error" }, + }); + } +} + interface TrackedBodyStats { pulls: number; cancelled: number; @@ -48,6 +73,36 @@ function trackedBodyStream( return { body, stats }; } +describe("DecompressedBodyTooLargeError", () => { + test("preserves one- and two-argument constructors without guessing measurement provenance", async () => { + const legacy = new DecompressedBodyTooLargeError(268435457); + expect(legacy).toMatchObject({ bytes: 268435457, limit: 268435456, measurement: null }); + await expectBodyLimitResponse(legacy, "Decompressed request body exceeds 268435456 bytes"); + const custom = new DecompressedBodyTooLargeError(6, 5); + expect(custom).toMatchObject({ bytes: 6, limit: 5, measurement: null }); + await expectBodyLimitResponse(custom, "Decompressed request body exceeds 5 bytes"); + }); + + test("keeps untyped categories and non-finite numbers out of the message", async () => { + const untyped: DecompressedBodyTooLargeError = Reflect.construct(DecompressedBodyTooLargeError, [ + 6, 5, "private-header-context window".repeat(100), + ]); + expect(untyped.measurement).toBeNull(); + await expectBodyLimitResponse(untyped, "Decompressed request body exceeds 5 bytes"); + for (const bytes of [NaN, Infinity, -Infinity, -1]) { + const error = new DecompressedBodyTooLargeError(bytes, 5, "declared_wire"); + await expectBodyLimitResponse(error, "Decompressed request body exceeds 5 bytes"); + } + for (const limit of [NaN, Infinity, -Infinity]) { + const error = new DecompressedBodyTooLargeError(6, limit, "declared_wire"); + await expectBodyLimitResponse(error, "Decompressed request body exceeds unknown bytes"); + } + const huge = new DecompressedBodyTooLargeError(Number.MAX_VALUE, 5, "declared_wire"); + await expectBodyLimitResponse(huge, + "Decompressed request body exceeds 5 bytes [measurement=declared_wire; bytes=1.7976931348623157e+308]"); + }); +}); + describe("decodeRequestBody", () => { test("passes identity and absent encodings through untouched", () => { expect(decodeRequestBody(PAYLOAD_BYTES, null)).toBe(PAYLOAD_BYTES); @@ -78,10 +133,11 @@ describe("decodeRequestBody", () => { expect(new TextDecoder().decode(decodeRequestBody(compressed, "x-gzip"))).toBe(JSON.stringify(PAYLOAD)); }); - test("round-trips deflate", () => { - const compressed = Bun.deflateSync(PAYLOAD_BYTES); - expect(new TextDecoder().decode(decodeRequestBody(compressed, "deflate"))).toBe(JSON.stringify(PAYLOAD)); - }); + for (const [label, compress] of [["wrapped", deflateSync], ["raw", deflateRawSync], ["Bun raw", Bun.deflateSync]] as const) { + test(`round-trips ${label} deflate`, () => { + expect(new TextDecoder().decode(decodeRequestBody(compress(PAYLOAD_BYTES), "deflate"))).toBe(JSON.stringify(PAYLOAD)); + }); + } test("is case/whitespace tolerant on the encoding token", () => { const compressed = Bun.zstdCompressSync(PAYLOAD_BYTES); @@ -104,15 +160,39 @@ describe("decodeRequestBody", () => { expect(() => decodeRequestBody(compressed, "zstd")).toThrow(DecompressedBodyTooLargeError); }); - test("aborts DURING inflation via maxOutputLength — activation per codec (injected cap)", () => { + test("reports exact identity size at the decoder boundary", async () => { + for (const encoding of [null, "", "identity"]) { + const error = await captureBodyTooLarge(() => decodeRequestBody(Uint8Array.of(1, 2, 3, 4, 5, 6), encoding, 5)); + expect(error).toMatchObject({ bytes: 6, limit: 5, measurement: "decoded_exact" }); + await expectBodyLimitResponse(error, "Decompressed request body exceeds 5 bytes [measurement=decoded_exact; bytes=6]"); + } + }); + + test("aborts DURING inflation and reports only a decoded lower bound for every codec", async () => { // Review finding (PR #96): the cap must fire inside zlib, not after full allocation. // A small injected cap keeps the test cheap while exercising the exact // ERR_BUFFER_TOO_LARGE -> DecompressedBodyTooLargeError path. const CAP = 1024; const inflates64k = new Uint8Array(64 * 1024); - expect(() => decodeRequestBody(Bun.zstdCompressSync(inflates64k), "zstd", CAP)).toThrow(DecompressedBodyTooLargeError); - expect(() => decodeRequestBody(Bun.gzipSync(inflates64k), "gzip", CAP)).toThrow(DecompressedBodyTooLargeError); - expect(() => decodeRequestBody(Bun.deflateSync(inflates64k), "deflate", CAP)).toThrow(DecompressedBodyTooLargeError); + for (const [encoding, compressed] of [ + ["zstd", Bun.zstdCompressSync(inflates64k)], + ["gzip", Bun.gzipSync(inflates64k)], + ["x-gzip", Bun.gzipSync(inflates64k)], + ["deflate", deflateSync(inflates64k)], + ["deflate", deflateRawSync(inflates64k)], + ["deflate", Bun.deflateSync(inflates64k)], + ] as const) { + expect(compressed.byteLength).toBeLessThan(CAP); + // Exercise the streaming reader too: these invalid-JSON bytes must be + // rejected by inflation before text decoding or JSON parsing. + const req = new Request("http://localhost/v1/responses/compact", { + method: "POST", headers: { "content-encoding": encoding }, body: compressed, + }); + const error = await captureBodyTooLarge(() => readBoundedJsonRequestBody(req, CAP)); + expect(error).toMatchObject({ bytes: 1025, limit: 1024, measurement: "decoded_lower_bound" }); + await expectBodyLimitResponse(error, + "Decompressed request body exceeds 1024 bytes [measurement=decoded_lower_bound; bytes=1025]"); + } }); test("injected cap still admits bodies within the limit", () => { @@ -134,6 +214,20 @@ describe("decodeRequestBody", () => { }); describe("readJsonRequestBody", () => { + test("reports a compressed declaration without reading or echoing request metadata", async () => { + const { body, stats } = trackedBodyStream([Bun.gzipSync(PAYLOAD_BYTES)]); + const req = new Request("http://localhost/v1/responses/compact?private-query", { + method: "POST", + headers: { "content-length": "00001025", "content-encoding": "gzip", "x-private-marker": "private-header" }, + body, + }); + const error = await captureBodyTooLarge(() => readBoundedJsonRequestBody(req, 1024)); + expect(error).toMatchObject({ bytes: 1025, limit: 1024, measurement: "declared_wire" }); + await expectBodyLimitResponse(error, + "Decompressed request body exceeds 1024 bytes [measurement=declared_wire; bytes=1025]"); + expect(stats).toEqual({ pulls: 0, cancelled: 1, sentinelPulled: false }); + }); + test("rejects and cancels declared over-cap bodies before reading", async () => { const { body, stats } = trackedBodyStream([PAYLOAD_BYTES]); const req = new Request("http://localhost/v1/responses", { @@ -142,7 +236,10 @@ describe("readJsonRequestBody", () => { body, }); - await expect(readJsonRequestBody(req)).rejects.toBeInstanceOf(DecompressedBodyTooLargeError); + const error = await captureBodyTooLarge(() => readJsonRequestBody(req)); + expect(error).toMatchObject({ bytes: 268435457, limit: 268435456, measurement: "declared_wire" }); + await expectBodyLimitResponse(error, + "Decompressed request body exceeds 268435456 bytes [measurement=declared_wire; bytes=268435457]"); expect(stats.pulls).toBe(0); expect(stats.cancelled).toBe(1); }); @@ -160,8 +257,10 @@ describe("readJsonRequestBody", () => { ], { sentinel }); const req = new Request("http://localhost/api/optional", { method: "POST", headers, body }); - await expect(readBoundedJsonRequestBody(req, 5, undefined, { emptyBodyFallback: {} })) - .rejects.toBeInstanceOf(DecompressedBodyTooLargeError); + const error = await captureBodyTooLarge(() => readBoundedJsonRequestBody(req, 5, undefined, { emptyBodyFallback: {} })); + expect(error).toMatchObject({ bytes: 6, limit: 5, measurement: "observed_wire_lower_bound" }); + await expectBodyLimitResponse(error, + "Decompressed request body exceeds 5 bytes [measurement=observed_wire_lower_bound; bytes=6]"); expect(stats).toEqual({ pulls: 2, cancelled: 1, sentinelPulled: false }); }); } @@ -252,8 +351,10 @@ describe("readJsonRequestBody", () => { body: oversizedWireBody, }); expect(req.headers.get("content-length")).toBeNull(); - await expect(readBoundedJsonRequestBody(req, 1024, undefined, { emptyBodyFallback: {} })) - .rejects.toBeInstanceOf(DecompressedBodyTooLargeError); + const error = await captureBodyTooLarge(() => readBoundedJsonRequestBody(req, 1024, undefined, { emptyBodyFallback: {} })); + expect(error).toMatchObject({ bytes: oversizedWireBody.byteLength, limit: 1024, measurement: "observed_wire_lower_bound" }); + await expectBodyLimitResponse(error, + `Decompressed request body exceeds 1024 bytes [measurement=observed_wire_lower_bound; bytes=${oversizedWireBody.byteLength}]`); }); test("parses an uncompressed request without touching arrayBuffer path", async () => { From c7f6ba730f6146ef1b7737157f81311fff304796 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 07:39:31 +0900 Subject: [PATCH 012/412] feat(providers): carry static BigModel Responses preset from #3641 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Narrowed carry of jamespan’s PR #3641, source origin/axis2-source-3641 at b675d832bff9249701ba8575ad1a23196be8f156. Reconstruct the separate Responses preset using only the two models in the official Codex example: https://docs.bigmodel.cn/cn/coding-plan/tool/codex.md (checked 2026-09-07). Keep liveModels false and preserve custom destinations and Responses reasoning replay. Map exact context windows, effort ladders, max defaults, summary support, and text modalities. Do not carry model-discovery.ts or envelopeKey/idKey; Flash Responses metadata and live discovery remain unverified. Add consumer metadata and custom-transport collision regressions; document the static roster and existing Codex export policy (compatibility ultra on GLM-5.3, omitted default field on Turbo’s empty ladder). Validation: git diff --check passed. Tests, typecheck, lint, and builds intentionally not run per worker scope; parent final CI owns execution. Co-authored-by: jamespan --- .../src/content/docs/fr/guides/providers.md | 3 +- .../src/content/docs/guides/providers.md | 27 +++++- .../src/content/docs/ja/guides/providers.md | 3 +- .../src/content/docs/ko/guides/providers.md | 3 +- .../docs/reference/configuration/providers.md | 6 ++ .../src/content/docs/ru/guides/providers.md | 3 +- .../src/content/docs/tr/guides/providers.md | 3 +- .../content/docs/zh-cn/guides/providers.md | 3 +- .../content/docs/zh-tw/guides/providers.md | 3 +- src/providers/registry.ts | 29 +++++++ .../provider-registry-parity.test.ts | 85 ++++++++++++++++++- 11 files changed, 159 insertions(+), 9 deletions(-) diff --git a/docs-site/src/content/docs/fr/guides/providers.md b/docs-site/src/content/docs/fr/guides/providers.md index 988ca03cf7..89b3a7c626 100644 --- a/docs-site/src/content/docs/fr/guides/providers.md +++ b/docs-site/src/content/docs/fr/guides/providers.md @@ -312,6 +312,7 @@ promotionnels de Cline ne sont accessibles que dans l'IDE ou la CLI Cline, pas p | NVIDIA NIM | `https://integrate.api.nvidia.com/v1` | | Z.AI (GLM Coding) | `https://api.z.ai/api/coding/paas/v4` | | Zhipu AI (BigModel) | `https://open.bigmodel.cn/api/paas/v4` | +| [BigModel Coding Plan — Responses (liste statique)](/guides/providers/#bigmodel-coding-plan-over-responses) | `https://open.bigmodel.cn/api/v1` | | Qwen Cloud | Forfait à jetons (par défaut) : `https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1` · Facturation à l'usage : `https://dashscope.aliyuncs.com/compatible-mode/v1` · ou personnalisé | | Tencent Cloud Coding Plan | `https://api.lkeap.cloud.tencent.com/coding/v3` | | SiliconFlow | `https://api.siliconflow.cn/v1` | @@ -495,7 +496,7 @@ une barre trompeuse. > programmation interactifs. L'automatisation générale par API, les services applicatifs personnalisés et les > traitements par lots non interactifs sont interdits et peuvent entraîner la suspension de la clé du forfait. -> **Deux routes GLM :** `zai` correspond à l'abonnement international Z.AI Coding Plan ; `zhipu-bigmodel` +> **Facturation GLM :** `zai` correspond à l'abonnement international Z.AI Coding Plan ; `zhipu-bigmodel` > correspond au point de terminaison national BigModel de Zhipu, facturé à l'usage. Les hôtes, les clés et la > facturation diffèrent : une clé émise pour l'un ne permet pas de s'authentifier auprès de l'autre. diff --git a/docs-site/src/content/docs/guides/providers.md b/docs-site/src/content/docs/guides/providers.md index 05f586a816..f5c4ddc190 100644 --- a/docs-site/src/content/docs/guides/providers.md +++ b/docs-site/src/content/docs/guides/providers.md @@ -367,6 +367,7 @@ free-experimentation model. | NVIDIA NIM | `https://integrate.api.nvidia.com/v1` | | Z.AI (GLM Coding) | `https://api.z.ai/api/coding/paas/v4` | | Zhipu AI (BigModel) | `https://open.bigmodel.cn/api/paas/v4` | +| BigModel Coding Plan (Responses, static roster) | `https://open.bigmodel.cn/api/v1` | | Qwen Cloud | Token plan (default): `https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1` · Pay as you go: `https://dashscope.aliyuncs.com/compatible-mode/v1` · or Custom | | Tencent Cloud Coding Plan | `https://api.lkeap.cloud.tencent.com/coding/v3` | | SiliconFlow | `https://api.siliconflow.cn/v1` | @@ -582,10 +583,34 @@ negative, or internally inconsistent billing totals produce no report rather tha > interactive coding tools only. General API automation, custom application backends, and > non-interactive batch use are prohibited and may cause the plan key to be suspended. -> **Two GLM routes:** `zai` is the Z.AI international coding-plan subscription; `zhipu-bigmodel` +> **GLM billing routes:** `zai` is the Z.AI international coding-plan subscription; `zhipu-bigmodel` > is Zhipu's domestic BigModel pay-as-you-go endpoint. Different hosts, different keys, different > billing — a key issued for one will not authenticate against the other. +### BigModel Coding Plan over Responses + +Select **Zhipu AI — BigModel Coding Plan (Responses)** (`zhipu-bigmodel-responses`) +for the `openai-responses` endpoint `https://open.bigmodel.cn/api/v1`. This is separate +from `zhipu-bigmodel-coding`, which uses Chat Completions at `/api/coding/paas/v4`. + +The preset uses a **static roster** (`liveModels: false`) taken from the +[official BigModel Codex example](https://docs.bigmodel.cn/cn/coding-plan/tool/codex.md): + +| Model | Context tokens | Upstream selectable effort | Default effort | Reasoning summaries | +| --- | ---: | --- | --- | --- | +| `glm-5.3` | 1,048,576 | `low`, `high`, `max` | `max` | Supported | +| `glm-5-turbo` | 204,800 | None (empty list) | `max` | Supported | + +Both entries declare text input. The default model is `glm-5.3`; Responses reasoning +content is preserved on replay. The existing Codex export adds its compatibility +`ultra` tier to GLM-5.3 and omits Turbo's default-effort field because Turbo has no +selectable ladder; the provider metadata still records `max` for both models. + +The example's `models.json` is a local catalog file, not a documented HTTP model-list +response. This preset does not perform live model discovery. `glm-5.3-flash` is not +seeded here because its exact Responses metadata is not verified. An existing custom +provider with the same name keeps its configured destination and metadata. + ### Multiple API keys Key-based providers can also keep multiple keys. Adding a key through the Providers page stores it diff --git a/docs-site/src/content/docs/ja/guides/providers.md b/docs-site/src/content/docs/ja/guides/providers.md index 33be9fc694..ae692e1e2c 100644 --- a/docs-site/src/content/docs/ja/guides/providers.md +++ b/docs-site/src/content/docs/ja/guides/providers.md @@ -216,6 +216,7 @@ Cline IDE/CLI のみで API からは使えません。`minimax/minimax-m2.5` | NVIDIA NIM | `https://integrate.api.nvidia.com/v1` | | Z.AI (GLM Coding) | `https://api.z.ai/api/coding/paas/v4` | | Zhipu AI (BigModel) | `https://open.bigmodel.cn/api/paas/v4` | +| [BigModel Coding Plan — Responses (静的モデル一覧)](/guides/providers/#bigmodel-coding-plan-over-responses) | `https://open.bigmodel.cn/api/v1` | | Qwen Cloud | トークンプラン(デフォルト): `https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1` · 従量課金: `https://dashscope.aliyuncs.com/compatible-mode/v1` · またはカスタム | | Tencent Cloud Coding Plan | `https://api.lkeap.cloud.tencent.com/coding/v3` | | SiliconFlow | `https://api.siliconflow.cn/v1` | @@ -338,7 +339,7 @@ model ごとに capability が異なるため、provider 全体の parallel tool > コーディングツール専用としています。一般的な API 自動化、カスタムアプリのバックエンド、 > 非対話型バッチ利用は禁止されており、プランキーが停止される場合があります。 -> **GLM の経路は 2 つあります:** `zai` は Z.AI の国際コーディングプラン契約、`zhipu-bigmodel` +> **GLM の課金経路:** `zai` は Z.AI の国際コーディングプラン契約、`zhipu-bigmodel` > は Zhipu の中国国内向け BigModel 従量課金エンドポイントです。ホストもキーも課金も別で、 > 一方で発行したキーはもう一方では認証されません。 diff --git a/docs-site/src/content/docs/ko/guides/providers.md b/docs-site/src/content/docs/ko/guides/providers.md index 7781cc4f52..c49ede4ec6 100644 --- a/docs-site/src/content/docs/ko/guides/providers.md +++ b/docs-site/src/content/docs/ko/guides/providers.md @@ -216,6 +216,7 @@ Cline IDE/CLI에서만 제공되며 API로는 사용할 수 없습니다. `minim | NVIDIA NIM | `https://integrate.api.nvidia.com/v1` | | Z.AI (GLM Coding) | `https://api.z.ai/api/coding/paas/v4` | | Zhipu AI (BigModel) | `https://open.bigmodel.cn/api/paas/v4` | +| [BigModel Coding Plan — Responses (정적 모델 목록)](/guides/providers/#bigmodel-coding-plan-over-responses) | `https://open.bigmodel.cn/api/v1` | | Qwen Cloud | Token plan(기본): `https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1` · 종량제: `https://dashscope.aliyuncs.com/compatible-mode/v1` · 또는 사용자 지정 | | Tencent Cloud Coding Plan | `https://api.lkeap.cloud.tencent.com/coding/v3` | | SiliconFlow | `https://api.siliconflow.cn/v1` | @@ -328,7 +329,7 @@ provider 전체 parallel tool call이나 OpenAI `reasoning_effort`를 광고하 > 안내합니다. 일반 API 자동화, 사용자 애플리케이션 백엔드 및 비대화형 일괄 호출은 금지되며 > 플랜 키가 정지될 수 있습니다. -> **GLM 경로는 두 개입니다:** `zai`는 Z.AI 국제 코딩 플랜 구독이고, `zhipu-bigmodel`은 +> **GLM 과금 경로:** `zai`는 Z.AI 국제 코딩 플랜 구독이고, `zhipu-bigmodel`은 > Zhipu의 중국 내수 BigModel 종량제 엔드포인트입니다. 호스트도 키도 과금도 다르며, 한쪽에서 > 발급한 키는 다른 쪽에서 인증되지 않습니다. diff --git a/docs-site/src/content/docs/reference/configuration/providers.md b/docs-site/src/content/docs/reference/configuration/providers.md index 02d5ba4323..85a9ba6903 100644 --- a/docs-site/src/content/docs/reference/configuration/providers.md +++ b/docs-site/src/content/docs/reference/configuration/providers.md @@ -747,6 +747,12 @@ container usually has no unlocked keychain session, so requests would fail close `${ENV_VAR}` reference in the service environment there instead. Env references are left untouched by `store`. +The `zhipu-bigmodel-responses` preset seeds `glm-5.3` and `glm-5-turbo` with +`liveModels: false` for `https://open.bigmodel.cn/api/v1`. Its static roster and +per-model context, effort, and summary metadata come from the +[BigModel Responses guide](/guides/providers/#bigmodel-coding-plan-over-responses). +The official local `models.json` example does not establish a live `/models` API. + With `liveModels: false`, an empty or omitted `models` list seeds the configured `defaultModel` first, followed by `retainModels`; duplicate ids are removed while preserving first occurrence. A nonempty explicit `models` list instead seeds `models` followed by `retainModels`, without diff --git a/docs-site/src/content/docs/ru/guides/providers.md b/docs-site/src/content/docs/ru/guides/providers.md index b057cf77c6..e680f1bd91 100644 --- a/docs-site/src/content/docs/ru/guides/providers.md +++ b/docs-site/src/content/docs/ru/guides/providers.md @@ -229,6 +229,7 @@ opencodex поставляется с 79 встроенными пресетам | NVIDIA NIM | `https://integrate.api.nvidia.com/v1` | | Z.AI (GLM Coding) | `https://api.z.ai/api/coding/paas/v4` | | Zhipu AI (BigModel) | `https://open.bigmodel.cn/api/paas/v4` | +| [BigModel Coding Plan — Responses (статический список)](/guides/providers/#bigmodel-coding-plan-over-responses) | `https://open.bigmodel.cn/api/v1` | | Qwen Cloud | Token plan (по умолчанию): `https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1` · Pay as you go: `https://dashscope.aliyuncs.com/compatible-mode/v1` · или Custom | | Tencent Cloud Coding Plan | `https://api.lkeap.cloud.tencent.com/coding/v3` | | SiliconFlow | `https://api.siliconflow.cn/v1` | @@ -367,7 +368,7 @@ plan. Ключ создаётся в [дашборде Featherless](https://feat > в интерактивных инструментах программирования. Автоматизация общего API, серверы пользовательских > приложений и неинтерактивные пакетные вызовы запрещены и могут привести к блокировке ключа плана. -> **Два маршрута GLM:** `zai` — это международная подписка Z.AI на coding-план, а `zhipu-bigmodel` — +> **Тарификация GLM:** `zai` — это международная подписка Z.AI на coding-план, а `zhipu-bigmodel` — > внутренняя китайская конечная точка BigModel с оплатой по факту использования. Разные хосты, > разные ключи, разная тарификация: ключ от одного сервиса не подойдёт к другому. diff --git a/docs-site/src/content/docs/tr/guides/providers.md b/docs-site/src/content/docs/tr/guides/providers.md index c5564e74a1..6ff4f1c038 100644 --- a/docs-site/src/content/docs/tr/guides/providers.md +++ b/docs-site/src/content/docs/tr/guides/providers.md @@ -355,6 +355,7 @@ yalnızca Cline IDE/CLI içinde mevcuttur; `minimax/minimax-m2.5` belgelenmiş A | NVIDIA NIM | `https://integrate.api.nvidia.com/v1` | | Z.AI (GLM Kodlama) | `https://api.z.ai/api/coding/paas/v4` | | Zhipu AI (BigModel) | `https://open.bigmodel.cn/api/paas/v4` | +| [BigModel Coding Plan — Responses (statik model listesi)](/guides/providers/#bigmodel-coding-plan-over-responses) | `https://open.bigmodel.cn/api/v1` | | Qwen Cloud | Token planı (varsayılan): `https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1` · Kullandıkça öde: `https://dashscope.aliyuncs.com/compatible-mode/v1` · veya Özel | | Tencent Cloud Coding Plan | `https://api.lkeap.cloud.tencent.com/coding/v3` | | SiliconFlow | `https://api.siliconflow.cn/v1` | @@ -537,7 +538,7 @@ tutarsız faturalandırma toplamları yanıltıcı bir çubuk yerine hiçbir rap > **Tencent Cloud Coding Plan kullanım kısıtlaması:** Tencent bu aboneliği yalnızca etkileşimli kodlama araçları için belgeler. Genel API otomasyonu, özel uygulama arka uçları ve etkileşimsiz toplu kullanım yasaktır ve plan anahtarının askıya alınmasına neden olabilir. -> **İki GLM rotası:** `zai`, Z.AI uluslararası kodlama planı aboneliğidir; `zhipu-bigmodel`, Zhipu'nun yerel BigModel kullandıkça öde uç noktasıdır. Farklı ana bilgisayarlar, farklı anahtarlar, farklı faturalandırma — biri için verilen bir anahtar diğerine karşı kimlik doğrulaması yapmaz. +> **GLM faturalandırma rotaları:** `zai`, Z.AI uluslararası kodlama planı aboneliğidir; `zhipu-bigmodel`, Zhipu'nun yerel BigModel kullandıkça öde uç noktasıdır. Farklı ana bilgisayarlar, farklı anahtarlar, farklı faturalandırma — biri için verilen bir anahtar diğerine karşı kimlik doğrulaması yapmaz. ### Birden fazla API anahtarı diff --git a/docs-site/src/content/docs/zh-cn/guides/providers.md b/docs-site/src/content/docs/zh-cn/guides/providers.md index 3fb72a4e6a..b4010cdae5 100644 --- a/docs-site/src/content/docs/zh-cn/guides/providers.md +++ b/docs-site/src/content/docs/zh-cn/guides/providers.md @@ -205,6 +205,7 @@ Cline IDE/CLI 中提供,不能通过 API 使用;`minimax/minimax-m2.5` 是 | NVIDIA NIM | `https://integrate.api.nvidia.com/v1` | | Z.AI (GLM Coding) | `https://api.z.ai/api/coding/paas/v4` | | 智谱 AI (BigModel) | `https://open.bigmodel.cn/api/paas/v4` | +| [BigModel Coding Plan — Responses (静态模型列表)](/guides/providers/#bigmodel-coding-plan-over-responses) | `https://open.bigmodel.cn/api/v1` | | Qwen Cloud | Token plan(默认): `https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1` · 按量付费: `https://dashscope.aliyuncs.com/compatible-mode/v1` · 或自定义 | | 腾讯云 Coding Plan | `https://api.lkeap.cloud.tencent.com/coding/v3` | | SiliconFlow | `https://api.siliconflow.cn/v1` | @@ -316,7 +317,7 @@ Bearer key。公开模型列表只保留同时报告 `model_type: chat` 和 `cha > **腾讯云 Coding Plan 使用限制:**腾讯将此订阅限定为交互式编程工具使用。禁止通用 API > 自动化、自定义应用后端和非交互式批量调用;违规使用可能导致套餐密钥被停用。 -> **两条 GLM 线路:**`zai` 是 Z.AI 的国际 coding plan 订阅,`zhipu-bigmodel` 是智谱国内 +> **GLM 计费线路:**`zai` 是 Z.AI 的国际 coding plan 订阅,`zhipu-bigmodel` 是智谱国内 > BigModel 的按量付费端点。二者主机、密钥与计费均不同,为其中一方签发的密钥无法在另一方通过鉴权。 ### 多个 API 密钥 diff --git a/docs-site/src/content/docs/zh-tw/guides/providers.md b/docs-site/src/content/docs/zh-tw/guides/providers.md index 96cf91ccfb..d26d093b7e 100644 --- a/docs-site/src/content/docs/zh-tw/guides/providers.md +++ b/docs-site/src/content/docs/zh-tw/guides/providers.md @@ -273,6 +273,7 @@ IDE/CLI,不透過 API;`minimax/minimax-m2.5` 是文件列出的 API 免費 | NVIDIA NIM | `https://integrate.api.nvidia.com/v1` | | Z.AI (GLM Coding) | `https://api.z.ai/api/coding/paas/v4` | | Zhipu AI (BigModel) | `https://open.bigmodel.cn/api/paas/v4` | +| [BigModel Coding Plan — Responses (靜態模型清單)](/guides/providers/#bigmodel-coding-plan-over-responses) | `https://open.bigmodel.cn/api/v1` | | Qwen Cloud | Token plan(預設):`https://token-plan.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1` · pay as you go:`https://dashscope.aliyuncs.com/compatible-mode/v1` · 或 Custom | | Tencent Cloud Coding Plan | `https://api.lkeap.cloud.tencent.com/coding/v3` | | SiliconFlow | `https://api.siliconflow.cn/v1` | @@ -418,7 +419,7 @@ quota probe 只會把 active key 傳送到 canonical A6API host,並拒絕 redi > **Tencent Cloud Coding Plan 使用限制:** Tencent 文件將此訂閱限定為互動式 coding tool。一般 API > automation、自訂 application backend 與非互動 batch 使用都被禁止,並可能造成 plan key 被停用。 -> **兩條 GLM 路徑:** `zai` 是 Z.AI 國際 Coding Plan 訂閱;`zhipu-bigmodel` 是智譜國內 BigModel +> **GLM 計費路徑:** `zai` 是 Z.AI 國際 Coding Plan 訂閱;`zhipu-bigmodel` 是智譜國內 BigModel > pay-as-you-go endpoint。兩者 host、key 與 billing 都不同;其中一邊發出的 key 無法在另一邊通過認證。 ### 多個 API 金鑰 diff --git a/src/providers/registry.ts b/src/providers/registry.ts index 82f70a6a6a..1c3396a48a 100644 --- a/src/providers/registry.ts +++ b/src/providers/registry.ts @@ -2544,6 +2544,35 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ // yields an empty picker at runtime. note: "Domestic BigModel Coding Plan endpoint (open.bigmodel.cn)", }, + // Narrowed carry of #3641: the official Codex example declares a local static catalog, + // not an HTTP /models contract. Keep Responses separate from the Chat endpoint above. + // Source: https://docs.bigmodel.cn/cn/coding-plan/tool/codex.md (checked 2026-09-07). + { + id: "zhipu-bigmodel-responses", + label: "Zhipu AI — BigModel Coding Plan (Responses)", + baseUrl: "https://open.bigmodel.cn/api/v1", + adapter: "openai-responses", + authKind: "key", + dashboardUrl: "https://bigmodel.cn/console/usercenter/apikeys", + defaultModel: "glm-5.3", + models: ["glm-5.3", "glm-5-turbo"], + liveModels: false, + jawcodeBundle: "zai", + // A pre-existing same-named custom provider must retain its destination and key boundary. + preserveCustomDestination: true, + modelContextWindows: { "glm-5.3": 1_048_576, "glm-5-turbo": 204_800 }, + modelInputModalities: { "glm-5.3": ["text"], "glm-5-turbo": ["text"] }, + modelReasoningEfforts: { + "glm-5.3": ZAI_GLM_53_REASONING_EFFORTS, + // Explicitly empty: Turbo must not inherit the generic selectable effort ladder. + "glm-5-turbo": [], + }, + modelDefaultReasoningEfforts: { "glm-5.3": "max", "glm-5-turbo": "max" }, + modelSupportsReasoningSummaries: { "glm-5.3": true, "glm-5-turbo": true }, + // Responses replay uses this provider-level flag, not the Chat-path model list. + preserveResponsesReasoningContent: true, + note: "Domestic BigModel Coding Plan Responses endpoint; static model roster", + }, { id: "nanogpt", label: "NanoGPT", baseUrl: "https://nano-gpt.com/api/v1", adapter: "openai-chat", authKind: "key", dashboardUrl: "https://nano-gpt.com/api" }, { id: "synthetic", label: "Synthetic", baseUrl: "https://api.synthetic.new/openai/v1", adapter: "openai-chat", authKind: "key", dashboardUrl: "https://synthetic.new" }, // SiliconFlow publishes an OpenAI-compatible chat endpoint and a dynamic model catalog. Do not diff --git a/tests/providers/provider-registry-parity.test.ts b/tests/providers/provider-registry-parity.test.ts index be84701e0b..0d935d12a2 100644 --- a/tests/providers/provider-registry-parity.test.ts +++ b/tests/providers/provider-registry-parity.test.ts @@ -11,6 +11,7 @@ import { deriveJawcodeAliases, deriveKeyLoginMap, deriveProviderPresets, + enrichProviderFromRegistry, providerConfigSeed, } from "../../src/providers/derive"; import { PROVIDER_REGISTRY } from "../../src/providers/registry"; @@ -33,7 +34,7 @@ function nativeTemplate(): Record { const EXPECTED_KEY_PROVIDER_IDS = [ "anthropic-apikey", "openai-apikey", "meta-model", "umans", "opencode-go", "neuralwatt", "openrouter", "cline-pass", "cline", "orcarouter", "bizrouter", "groq", "google", "google-vertex", "azure-openai", "deepseek", "cerebras", "chutes", "deepinfra", "hyperbolic", "nscale", "vultr", "baseten", "commandcode", "sambanova", "nebius", "digitalocean", "scaleway", "featherless", "novita", "together", "fireworks", "firepass", "moonshot", - "huggingface", "nvidia", "venice", "zai", "zhipu-bigmodel", "zhipu-bigmodel-coding", "nanogpt", "synthetic", "siliconflow", "qwen-cloud", "tencent-coding-plan", + "huggingface", "nvidia", "venice", "zai", "zhipu-bigmodel", "zhipu-bigmodel-coding", "zhipu-bigmodel-responses", "nanogpt", "synthetic", "siliconflow", "qwen-cloud", "tencent-coding-plan", "volcengine", "volcengine-coding-plan", "volcengine-agent-plan", "qianfan", "alibaba", "alibaba-token-plan", "alibaba-token-plan-intl", "parallel", "zenmux", "litellm", "ollama-cloud", "mistral", "minimax", "minimax-cn", "kimi-code", "opencode-zen", "vercel-ai-gateway", "opencode-free", "xiaomi", "xiaomi-mimo", "kilo", "mimo-free", "mimo", "cloudflare-ai-gateway", "cloudflare-workers-ai", "gitlab-duo", @@ -440,6 +441,87 @@ describe("provider registry parity", () => { expect(glm53Entry?.default_reasoning_level).toBe("max"); }); + test("BigModel Responses exports only the officially documented static Codex models", () => { + // Independent oracle: https://docs.bigmodel.cn/cn/coding-plan/tool/codex.md, + // local models.json example checked 2026-09-07; not an authenticated /models response. + const id = "zhipu-bigmodel-responses"; + const registry = PROVIDER_REGISTRY.find(entry => entry.id === id)!; + expect(registry).toMatchObject({ + adapter: "openai-responses", + baseUrl: "https://open.bigmodel.cn/api/v1", + authKind: "key", + defaultModel: "glm-5.3", + models: ["glm-5.3", "glm-5-turbo"], + liveModels: false, + preserveCustomDestination: true, + preserveResponsesReasoningContent: true, + }); + expect(registry.modelDiscovery).toBeUndefined(); + expect(registry.preserveReasoningContentModels).toBeUndefined(); + expect(KEY_LOGIN_PROVIDERS[id]).toMatchObject({ + models: ["glm-5.3", "glm-5-turbo"], liveModels: false, + }); + const provider = providerConfigSeed(registry); + enrichProviderFromRegistry(id, provider); + expect(provider.liveModels).toBe(false); + expect(provider.preserveResponsesReasoningContent).toBe(true); + const models = provider.models!.map(modelId => applyProviderConfigHints(id, provider, { + provider: id, id: modelId, + })); + expect(models).toMatchObject([ + { id: "glm-5.3", contextWindow: 1_048_576, reasoningEfforts: ["low", "high", "max"], + defaultReasoningEffort: "max", supportsReasoningSummaries: true, inputModalities: ["text"] }, + { id: "glm-5-turbo", contextWindow: 204_800, reasoningEfforts: [], + defaultReasoningEffort: "max", supportsReasoningSummaries: true, inputModalities: ["text"] }, + ]); + const entries = buildCatalogEntries(nativeTemplate(), [], models); + for (const [modelId, window, efforts] of [ + ["glm-5.3", 1_048_576, ["low", "high", "max", "ultra"]], + ["glm-5-turbo", 204_800, []], + ] as const) { + const entry = entries.find(row => row.slug === `${id}/${modelId}`); + expect(entry).toMatchObject({ + context_window: window, supports_reasoning_summaries: true, + }); + // Existing export policy adds a compatibility ultra tier and omits the default + // for empty ladders. The provider/CatalogModel defaults above remain official max. + expect(entry?.default_reasoning_level).toBe(modelId === "glm-5-turbo" ? undefined : "max"); + expect((entry?.supported_reasoning_levels as Array<{ effort: string }>).map(row => row.effort)) + .toEqual([...efforts]); + } + expect(entries.some(entry => String(entry.slug).includes("glm-5.3-flash"))).toBe(false); + }); + + test("BigModel Responses name collisions preserve custom transport and metadata", () => { + const id = "zhipu-bigmodel-responses"; + // Exercise both a different destination on the same wire and the canonical URL on + // another wire. Neither may acquire this preset's transport or per-model defaults. + for (const transport of [ + { adapter: "openai-responses", baseUrl: "https://custom.example.test/api/v1" }, + { adapter: "openai-chat", baseUrl: "https://open.bigmodel.cn/api/v1" }, + ]) { + const provider: OcxProviderConfig = { + ...transport, authMode: "key", apiKey: "test-custom-key", liveModels: true, + models: ["glm-5.3"], modelContextWindows: { "glm-5.3": 32_768 }, + modelReasoningEfforts: { "glm-5.3": ["medium"] }, + modelDefaultReasoningEfforts: { "glm-5.3": "medium" }, + modelSupportsReasoningSummaries: { "glm-5.3": false }, + }; + const enriched = structuredClone(provider); + enrichProviderFromRegistry(id, enriched); + expect(enriched).toEqual(provider); + const config: OcxConfig = { port: 10100, defaultProvider: id, providers: { [id]: provider } }; + const routed = routeModel(config, `${id}/glm-5.3`); + expect(routed.provider).toMatchObject(provider); + expect(routed.provider.modelContextWindows).toEqual({ "glm-5.3": 32_768 }); + expect(routed.provider.modelReasoningEfforts).toEqual({ "glm-5.3": ["medium"] }); + expect(routed.provider.modelDefaultReasoningEfforts).toEqual({ "glm-5.3": "medium" }); + expect(routed.provider.modelSupportsReasoningSummaries).toEqual({ "glm-5.3": false }); + expect(routed.provider.preserveResponsesReasoningContent).toBeUndefined(); + expect(routed.modelId).toBe("glm-5.3"); + } + }); + test("Anthropic API-key provider mirrors the OAuth entry's models on the key flow", () => { const anthropicOauth = PROVIDER_REGISTRY.find(entry => entry.id === "anthropic"); expect(KEY_LOGIN_PROVIDERS["anthropic-apikey"]).toMatchObject({ @@ -948,6 +1030,7 @@ describe("provider registry parity", () => { "minimax-cn": "minimax", "zhipu-bigmodel": "zai", "zhipu-bigmodel-coding": "zai", + "zhipu-bigmodel-responses": "zai", }); expect(resolveMetadataProvider("gemini")).toBe("google"); expect(resolveMetadataProvider("minimax-cn")).toBe("minimax"); From 130be8dbd2b52db21f0bcced61259940b4b9246f Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 07:39:43 +0900 Subject: [PATCH 013/412] feat(catalog): carry native display labels with normalization contract [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Carry PR #3627 from f699ec7f998d56bf205db96762b821cd8c228a35, using merge base cf9f662190c4c6770697c45c870941509cc98f9c. Keep the source runtime changes and existing Astra normalization intact. Qualify external-name restoration in all four provider docs and catalog SOT. Add Astra external-edit coverage and real retained/convergence writer coverage. Local tests, typecheck and builds NOT RUN by owner mandate. Static diff inspection and git diff --check passed; remote CI belongs to parent. Co-authored-by: Éverton Toffanetto --- .../ja/reference/configuration/providers.md | 8 + .../ko/reference/configuration/providers.md | 8 + .../docs/reference/configuration/providers.md | 10 + .../reference/configuration/providers.md | 8 + src/codex/catalog/sync.ts | 46 +++- src/codex/convergence.ts | 7 + structure/03_catalog-and-subagents.md | 12 + tests/codex-integration/codex-catalog.test.ts | 210 +++++++++++++++++- 8 files changed, 306 insertions(+), 3 deletions(-) diff --git a/docs-site/src/content/docs/ja/reference/configuration/providers.md b/docs-site/src/content/docs/ja/reference/configuration/providers.md index d4bfc49a6f..ddbb22d666 100644 --- a/docs-site/src/content/docs/ja/reference/configuration/providers.md +++ b/docs-site/src/content/docs/ja/reference/configuration/providers.md @@ -370,6 +370,14 @@ Vercel AI Gateway は、1 つのモデルを複数の基盤となる推論プロ 表示名には `modelDisplayNames` を使用します。優先順位は、運用者が設定した `modelDisplayNames`、プロバイダーカタログのメタデータ、通常の `provider/model` 表示の順です。キーはこのプロバイダー内の正確なネイティブモデル ID です。例えば `xai/grok-4.6` のキーは `grok-4.6` です。ラベルは表示専用で、正確なルーティング ID や上流モデル ID を変更しません。`config.json` の既存プロバイダー設定にこのフィールドだけを追加し、他のすべてのフィールドを残してください。`PUT /api/providers/:provider/model-display-names` に `{ "modelId": "grok-4.6", "displayName": "Grok 4.6" }` を送ると保存され、`displayName: null` を送るとその名前だけがリセットされます。 +ローカル Codex カタログでサポートされるプレフィックスなしのネイティブ GPT 行にも、 +`providers.openai.modelDisplayNames` で正確な表示名を指定できます。例えば `"gpt-6-astra": "GPT 6 Astra"` です。 +起動時の同期とローカルカタログの収束処理は、どちらもこれらの名前を再適用します。名前の設定を削除すると、行の現在の表示名が +適用済みの上書きとまだ一致する場合にのみ、元のネイティブ名が復元されます。外部で変更された表示名にも既存のネイティブメタデータ正規化が適用されます。 +例えば Astra (`gpt-6-astra`) では、固定されたネイティブ名と異なる名前は引き続きその固定名に置き換えられます。 +表示名の上書きによってモデル ID、メタデータ(機能を含む)、順序、ルーティングされたコンボのエイリアス、アカウント修飾付きの行は変更されません。 +このローカルカタログの上書きは、HTTP のモデル一覧や仮想 `*-pro` 行の表示名には適用されません。 + プレビュー GPT-5.6 フォールバック エントリは同じメカニズムを使用します。 OpenAI API キー プリセットは、ベース ID と Pro ID にコンテキスト `922000` と最大入力 `922000` をシードします。 OpenRouter は、コンテキスト `922000` を持つ `openai/gpt-5.6-sol`、`openai/gpt-5.6-terra`、および `openai/gpt-5.6-luna` をシードします。プール/ダイレクトは `922000` をアドバタイズします。同期されたカタログは、`xhigh` を区別しつつ、`max` をアドバタイズします。 ```json diff --git a/docs-site/src/content/docs/ko/reference/configuration/providers.md b/docs-site/src/content/docs/ko/reference/configuration/providers.md index c9c4de5ede..160d313be3 100644 --- a/docs-site/src/content/docs/ko/reference/configuration/providers.md +++ b/docs-site/src/content/docs/ko/reference/configuration/providers.md @@ -377,6 +377,14 @@ Vercel AI Gateway는 하나의 모델을 여러 기반 추론 공급자에 걸 표시 이름은 `modelDisplayNames`로 설정합니다. 우선순위는 운영자가 설정한 `modelDisplayNames`, 공급자 카탈로그 메타데이터, 일반 `provider/model` 표시 순서입니다. 키는 이 공급자 안의 정확한 네이티브 모델 id입니다. 예를 들어 `xai/grok-4.6`의 키는 `grok-4.6`입니다. 이름은 표시 전용이며 정확한 라우팅 id나 업스트림 모델 id를 바꾸지 않습니다. `config.json`의 기존 공급자 설정에 이 필드만 추가하고 다른 모든 필드는 유지하세요. `PUT /api/providers/:provider/model-display-names`에 `{ "modelId": "grok-4.6", "displayName": "Grok 4.6" }`를 보내 저장하고, `displayName: null`을 보내 해당 이름만 초기화합니다. +로컬 Codex 카탈로그에서 지원되는 접두사 없는 네이티브 GPT 항목에도 +`providers.openai.modelDisplayNames`로 정확한 표시 이름을 지정할 수 있습니다. 예를 들어 `"gpt-6-astra": "GPT 6 Astra"`를 사용합니다. +시작 시 동기화와 로컬 카탈로그 수렴은 모두 이 이름을 다시 적용합니다. 이름 설정을 삭제하면 항목의 현재 표시 이름이 +적용된 재정의와 여전히 일치할 때만 원래 네이티브 이름을 복원합니다. 외부에서 변경된 표시 이름도 기존 네이티브 메타데이터 정규화 규칙을 따릅니다. +예를 들어 Astra (`gpt-6-astra`)는 고정된 네이티브 이름과 다른 이름을 여전히 그 고정 이름으로 교체합니다. +표시 이름 재정의는 모델 ID, 기능을 포함한 메타데이터, 정렬 순서, 라우팅된 콤보 별칭 및 계정 선택자가 붙은 항목을 바꾸지 않습니다. +이 로컬 카탈로그 재정의는 HTTP 모델 목록이나 가상 `*-pro` 항목의 이름을 바꾸지 않습니다. + 프리뷰 GPT-5.6 폴백 항목도 같은 메커니즘을 사용합니다. OpenAI API 키 프리셋은 base와 Pro id에 컨텍스트 `922000`, 최대 입력 `922000`을 채웁니다. OpenRouter는 `openai/gpt-5.6-sol`, `openai/gpt-5.6-terra`, `openai/gpt-5.6-luna`에 컨텍스트 `922000`을 채웁니다. Pool/Direct는 `922000`을 노출하고, 동기화된 카탈로그는 `xhigh`를 구분한 채 `max`를 노출합니다. ```json diff --git a/docs-site/src/content/docs/reference/configuration/providers.md b/docs-site/src/content/docs/reference/configuration/providers.md index 02d5ba4323..9bd558be44 100644 --- a/docs-site/src/content/docs/reference/configuration/providers.md +++ b/docs-site/src/content/docs/reference/configuration/providers.md @@ -230,6 +230,16 @@ all other provider settings. The example includes the surrounding required field } ``` +Supported bare native GPT rows in the local Codex catalog also accept exact labels in +`providers.openai.modelDisplayNames`, for example `"gpt-6-astra": "GPT 6 Astra"`. +Both startup synchronization and local catalog convergence reapply these labels. Removing a label +restores the original native name only when the row's display name still matches the applied +override. A newer external display name is preserved subject to existing native metadata normalization; +for example, Astra (`gpt-6-astra`) still replaces a non-pinned name with its pinned native name. +The label overlay leaves model IDs, metadata (including capabilities), ordering, +routed combo aliases, and account-qualified rows unchanged. This local catalog override does +not relabel the HTTP model listings or virtual `*-pro` rows. + The effective label order is operator `modelDisplayNames`, then provider catalog metadata, then the normal `provider/model` fallback. The routed selector remains `xai/grok-4.6`, while the upstream wire model remains `grok-4.6`. Labels are display only. They do not change authentication, adapter diff --git a/docs-site/src/content/docs/zh-cn/reference/configuration/providers.md b/docs-site/src/content/docs/zh-cn/reference/configuration/providers.md index b7339cd4c2..f121d67bc0 100644 --- a/docs-site/src/content/docs/zh-cn/reference/configuration/providers.md +++ b/docs-site/src/content/docs/zh-cn/reference/configuration/providers.md @@ -371,6 +371,14 @@ Vercel AI Gateway 可以在多个底层推理提供者之间路由一个模型 请使用 `modelDisplayNames` 设置显示名称。优先顺序是操作者设置的 `modelDisplayNames`、提供者目录元数据,然后是普通的 `provider/model` 显示。键是此提供者内精确的原生模型 id,例如 `xai/grok-4.6` 的键是 `grok-4.6`。名称只改变显示,不会改变精确路由 id 或上游模型 id。请只把此字段加入 `config.json` 中现有的提供者设置,并保留所有其他字段。向 `PUT /api/providers/:provider/model-display-names` 发送 `{ "modelId": "grok-4.6", "displayName": "Grok 4.6" }` 可保存名称,发送 `displayName: null` 只重置该名称。 +本地 Codex 目录中受支持的不带前缀的原生 GPT 条目也可以通过 +`providers.openai.modelDisplayNames` 设置精确的显示名称, 例如 `"gpt-6-astra": "GPT 6 Astra"`。 +启动时同步和本地目录收敛都会重新应用这些名称。删除名称设置时, 只有条目的当前显示名称仍与已应用的覆盖值一致, +才会恢复原始原生名称。外部更改的显示名称仍受现有原生元数据规范化规则约束。 +例如,Astra (`gpt-6-astra`) 仍会将不同于固定原生名称的名称替换为该固定名称。 +显示名称覆盖不会改变模型 ID、元数据(包括能力)、排序、路由组合别名和带账户限定的条目。 +此本地目录覆盖不会重命名 HTTP 模型列表中的条目或虚拟 `*-pro` 条目。 + 预览版 GPT-5.6 回退条目使用相同机制。OpenAI API key 预设会为基础和 Pro id 设定 `922000` 上下文和 `922000` 最大输入;OpenRouter 会为 `openai/gpt-5.6-sol`、`openai/gpt-5.6-terra` 和 `openai/gpt-5.6-luna` 设定 `922000` 上下文。Pool/Direct 会声明 `922000`;同步后的目录会声明 `max`,同时保留 `xhigh` 的独立性。 ```json diff --git a/src/codex/catalog/sync.ts b/src/codex/catalog/sync.ts index 22d235dbcc..972b6d74c6 100644 --- a/src/codex/catalog/sync.ts +++ b/src/codex/catalog/sync.ts @@ -307,6 +307,11 @@ function routedDisplayName(slug: string, model?: CatalogModel, config?: Pick; + if (recoverableNativeSlug(entry) === label.slug + && typeof label.original === "string" && entry.display_name === label.applied) { + entry.display_name = label.original; + } + } + return entry; +} + /** Append missing supported native rows from trusted catalog sources only. */ export function mergeCatalogModelsWithNativeRecovery( primaryCatalogModels: readonly RawEntry[], @@ -862,6 +882,8 @@ export interface ObservedCatalogMergeInput { readonly suppressedBareNativeSlugs?: ReadonlySet; readonly policy: ObservedCatalogMergePolicy; readonly openaiContextCap?: NativeContextLimitsInput; + /** Exact display-only labels for bare native OpenAI models. */ + readonly nativeDisplayNames?: Readonly>; } /** @@ -896,12 +918,14 @@ export function mergeCatalogEntriesFromObservedState({ suppressedBareNativeSlugs = new Set(), policy, openaiContextCap, + nativeDisplayNames, }: ObservedCatalogMergeInput): RawEntry[] { // Raw catalog rows contain nested arrays/objects that normalization mutates. Detach every row at // the observed-core boundary so callers can safely retain evidence objects or repeat the merge. - const detachedCatalogModels = catalogModels.map(entry => structuredClone(entry) as RawEntry); + const detachedCatalogModels = catalogModels + .map(entry => restoreNativeDisplayName(structuredClone(entry) as RawEntry)); const detachedBaselineCatalogModels = baselineCatalogModels - .map(entry => structuredClone(entry) as RawEntry); + .map(entry => restoreNativeDisplayName(structuredClone(entry) as RawEntry)); const detachedRoutedEntries = routedEntries.map(entry => structuredClone(entry) as RawEntry); // Track this invocation's generated custom rows, not ownership markers read from disk. // Their builder already finalized exact native ladders and ordinary routed mock tiers. @@ -1256,6 +1280,17 @@ export function mergeCatalogEntriesFromObservedState({ ); applyFullModelPickerOrder(versionedEntries, modelPickerOrder); for (const entry of versionedEntries) { + // Templates and account clones must not inherit the native row's overlay marker. + delete entry.opencodex_native_display_name; + const slug = recoverableNativeSlug(entry); + if (slug !== null) { + const label = nativeDisplayNames && Object.hasOwn(nativeDisplayNames, slug) + ? nativeDisplayNames[slug]?.trim() : undefined; + if (label && label !== entry.display_name) { + entry.opencodex_native_display_name = { slug, original: entry.display_name, applied: label }; + entry.display_name = label; + } + } const kind = entry.opencodex_catalog_kind; if (trustedAccountBoundNativeCatalogSlug(entry) === undefined && kind !== CODEX_CUSTOM_MODEL_CATALOG_KIND @@ -1659,6 +1694,12 @@ export function finalizeAutoReviewModelOverride( return applyAutoReviewModelOverride(models, readConfiguredAutoReviewModel(), sourceModels); } +/** + * Mescla o catálogo retido com os modelos visíveis e as configurações atuais, + * incluindo os nomes nativos. Tenta preservar o backup original e usa a permissão + * de escrita para publicar o resultado apenas se os bytes mudarem, retornando + * a contagem de entradas roteadas e por conta, o caminho e o estado da gravação. + */ function writeRetainedCatalogSync({ config, goModels, @@ -1880,6 +1921,7 @@ function writeRetainedCatalogSync({ accountBoundEntries, suppressedBareNativeSlugs, openaiContextCap, + nativeDisplayNames: config.providers[OPENAI_CODEX_PROVIDER_ID]?.modelDisplayNames, policy: { ...CANONICAL_NATIVE_CATALOG_CONTENT_POLICY, nativeBackfillSlugs: [...availableBareNativeSlugs, ...observedNativeSlugs], diff --git a/src/codex/convergence.ts b/src/codex/convergence.ts index 8b30bb9eb2..2b8a8512c6 100644 --- a/src/codex/convergence.ts +++ b/src/codex/convergence.ts @@ -226,6 +226,12 @@ function bindGatherPaths( }; } +/** + * Prepara um candidato de catálogo para convergência sem gravá-lo em disco. + * Clona a fonte e mescla as observações nativas, os modelos roteados e por conta, + * aplicando a configuração, inclusive nomes nativos, e os limites de raciocínio + * observados no runtime antes de retornar o catálogo resultante. + */ function prepareCatalog( config: Readonly, source: Extract, @@ -366,6 +372,7 @@ function prepareCatalog( accountBoundEntries, suppressedBareNativeSlugs, openaiContextCap, + nativeDisplayNames: config.providers[OPENAI_CODEX_PROVIDER_ID]?.modelDisplayNames, policy: { ...CANONICAL_NATIVE_CATALOG_CONTENT_POLICY, nativeBackfillSlugs: [...availableBareNativeSlugs, ...observedNativeSlugs], diff --git a/structure/03_catalog-and-subagents.md b/structure/03_catalog-and-subagents.md index f9f46a0653..86aa4a81a7 100644 --- a/structure/03_catalog-and-subagents.md +++ b/structure/03_catalog-and-subagents.md @@ -145,6 +145,18 @@ then trusted catalog metadata such as a configured qualified provider/model alia This overlay never changes route identity or the upstream wire model, and its catalog fingerprint makes a label edit refresh Codex output. +Supported bare native GPT rows also consume `providers.openai.modelDisplayNames`. Retained sync +and convergence pass the same map to the observed-state merge. After native normalization and +ordering, the merge applies the exact nonblank trimmed label and saves +`opencodex_native_display_name: { slug, original, applied }` in the local catalog only. The next +merge detaches its inputs, removes that marker, and restores `original` only if the native slug +still matches and the current name equals `applied`. Removing or blanking the override therefore +restores the owned name before normal native metadata upgrades. Divergent external names remain +subject to those upgrades: Astra still replaces non-pinned names with its pinned native name. +Template-derived rows discard the marker. The overlay leaves model IDs, metadata (including +capabilities), ordering, routed combo aliases, custom rows and account-qualified rows unchanged; +it does not relabel HTTP model listings or virtual `*-pro` rows. + ## Native passthrough Astra has its own pinned native row: 272,000 default context, 872,000 opt-in ceiling, diff --git a/tests/codex-integration/codex-catalog.test.ts b/tests/codex-integration/codex-catalog.test.ts index 5820edc6dd..bb3c8a880f 100644 --- a/tests/codex-integration/codex-catalog.test.ts +++ b/tests/codex-integration/codex-catalog.test.ts @@ -1,5 +1,5 @@ import { afterEach, describe, expect, spyOn, test } from "bun:test"; -import { existsSync, mkdtempSync, readFileSync} from "node:fs"; +import { chmodSync, existsSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { codexAccountGatedCanonicalWireModel } from "../../src/server/responses/core"; @@ -53,9 +53,17 @@ import { import { CANONICAL_NATIVE_CATALOG_CONTENT_POLICY, mergeCatalogEntriesFromObservedState, + syncCatalogModels, type ObservedCatalogMergeInput, } from "../../src/codex/catalog/sync"; import { removeTreeWithRetry } from "../helpers/remove-tree"; +import { saveConfig } from "../../src/config"; +import { SUBAGENT_MODELS_VERSION } from "../../src/config/subagent-models"; +import { captureCatalogAdmissionSnapshot } from "../../src/codex/catalog-admission"; +import { convergeCodexCatalog } from "../../src/codex/convergence"; +import { resetCodexRuntimeResolveCacheForTests } from "../../src/codex/runtime"; +import { resolveCodexCatalogSerializationDatabasePath, resolveEffectiveUserIdentity } from "../../src/codex/user-identity"; +import { CODEX_FORWARD_BASE_URL } from "../../src/providers/openai-tiers"; const originalFetch = globalThis.fetch; @@ -3045,7 +3053,207 @@ function mergeObservedForTest( }); } +// Exercise both production callers: removing either caller's nativeDisplayNames argument +// must fail the persisted-label assertion, even if the pure merge tests still pass. +test.each(["retained", "convergence"] as const)("%s persists and restores native labels through the catalog writer", async writer => { + const envKeys = ["CODEX_HOME", "OPENCODEX_HOME", "CODEX_CLI_PATH"] as const; + const previousEnv = envKeys.map(key => process.env[key]); + const previousFetch = globalThis.fetch; + const root = realpathSync.native(mkdtempSync(join(tmpdir(), "ocx-native-label-writer-"))); + const codexHome = join(root, "codex"); + const catalogPath = join(codexHome, "custom-catalog.json"); + let fetchCalls = 0; + try { + mkdirSync(codexHome); + mkdirSync(join(root, "ocx")); + process.env.CODEX_HOME = codexHome; + process.env.OPENCODEX_HOME = join(root, "ocx"); + writeFileSync(join(codexHome, "config.toml"), 'model_catalog_json = "custom-catalog.json"\n'); + const catalog = { models: [{ ...nativeTemplate(), slug: "gpt-5.6-sol", display_name: "Fixture Sol" }] }; + // Reuse the executable-fixture protocol from catalog-full-picker-order.test.ts so + // admission and a forced runtime refresh observe the same version and bundled rows. + const script = join(root, "fixture-codex.js"); + writeFileSync(script, [ + 'if (process.argv.includes("--version")) console.log("codex-cli 0.145.0");', + `else process.stdout.write(${JSON.stringify(JSON.stringify(catalog))});`, + ].join("\n")); + if (process.platform === "win32") { + process.env.CODEX_CLI_PATH = join(root, "fixture-codex.cmd"); + writeFileSync(process.env.CODEX_CLI_PATH, `@echo off\r\n"${process.execPath}" "${script}" %*\r\n`); + } else { + process.env.CODEX_CLI_PATH = join(root, "fixture-codex"); + const quote = (value: string) => `'${value.replaceAll("'", "'\\''")}'`; + writeFileSync(process.env.CODEX_CLI_PATH, `#!/bin/sh\nexec ${quote(process.execPath)} ${quote(script)} "$@"\n`); + chmodSync(process.env.CODEX_CLI_PATH, 0o755); + } + resetCatalogRuntimeStateForTests(); + resetCodexRuntimeResolveCacheForTests(); + resetCodexModelEntitlementCacheForTests(); + expect(loadBundledCodexCatalog()?.models?.[0]?.slug).toBe("gpt-5.6-sol"); + writeFileSync(catalogPath, JSON.stringify(catalog)); + globalThis.fetch = (async () => { + fetchCalls += 1; + throw new Error("native label writer fixture must not make a network request"); + }) as typeof fetch; + const config: OcxConfig = { + port: 10100, defaultProvider: "openai", + subagentModels: [], subagentModelsVersion: SUBAGENT_MODELS_VERSION, + providers: { + openai: { adapter: "openai-responses", baseUrl: CODEX_FORWARD_BASE_URL, authMode: "forward" }, + }, + }; + const write = async (labels?: Record) => { + if (labels) config.providers.openai!.modelDisplayNames = labels; + else delete config.providers.openai!.modelDisplayNames; + saveConfig(config); + if (writer === "convergence") { + const result = await convergeCodexCatalog(captureCatalogAdmissionSnapshot(config), { + action: "converge", scope: "catalog", reason: "management-mutation", mode: "explicit", deadlineMs: 5_000, + }); + expect(result.catalogRefresh.status).toBe("committed"); + } else { + const result = await syncCatalogModels(config); + expect(result.path).toBe(catalogPath); + expect(result.skippedReason).toBeUndefined(); + } + return (JSON.parse(readFileSync(catalogPath, "utf8")) as { models: Record[] }).models; + }; + const original = await write(); + const renamed = await write({ "gpt-5.6-sol": "Custom Sol" }); + const renamedBytes = readFileSync(catalogPath, "utf8"); + const native = renamed.find(row => row.slug === "gpt-5.6-sol")!; + expect(native.display_name).toBe("Custom Sol"); + expect(native.opencodex_native_display_name).toEqual({ + slug: "gpt-5.6-sol", original: "Fixture Sol", applied: "Custom Sol", + }); + const { opencodex_native_display_name: marker, ...withoutMarker } = native; + expect(marker).toBeDefined(); + expect({ ...withoutMarker, display_name: "Fixture Sol" }) + .toEqual(original.find(row => row.slug === "gpt-5.6-sol")!); + expect(await write({ "gpt-5.6-sol": "Custom Sol" })).toEqual(renamed); + expect(readFileSync(catalogPath, "utf8")).toBe(renamedBytes); + expect((await write({ "gpt-5.6-sol": "Changed Sol" })).find(row => row.slug === "gpt-5.6-sol")?.display_name) + .toBe("Changed Sol"); + expect(await write()).toEqual(original); + expect(fetchCalls).toBe(0); + } finally { + try { + const database = resolveCodexCatalogSerializationDatabasePath(resolveEffectiveUserIdentity(), codexHome); + for (const suffix of ["", "-journal", "-wal", "-shm"]) rmSync(`${database}${suffix}`, { force: true }); + } finally { + globalThis.fetch = previousFetch; + envKeys.forEach((key, index) => { + const value = previousEnv[index]; + if (value === undefined) delete process.env[key]; + else process.env[key] = value; + }); + resetCatalogRuntimeStateForTests(); + resetCodexRuntimeResolveCacheForTests(); + resetCodexModelEntitlementCacheForTests(); + removeTreeWithRetry(root); + } + } +}, 30_000); + describe("Codex catalog routed normalization", () => { + test("reapplies native display names after repeated catalog merges without changing model metadata", () => { + const input = { + catalogModels: [{ ...nativeTemplate(), slug: "gpt-5.6-sol" }], + routedEntries: [], + }; + const original = mergeObservedForTest(input); + const labels = { "gpt-5.6-sol": "GPT 5.6 Sol" }; + const renamed = mergeObservedForTest({ ...input, nativeDisplayNames: labels }); + const row = renamed.find(entry => entry.slug === "gpt-5.6-sol")!; + expect(row.display_name).toBe("GPT 5.6 Sol"); + expect({ ...row, display_name: undefined, opencodex_native_display_name: undefined }).toEqual({ + ...original.find(entry => entry.slug === "gpt-5.6-sol"), display_name: undefined, + }); + const regenerated = mergeObservedForTest({ + ...input, catalogModels: renamed, nativeDisplayNames: labels, + }); + expect(regenerated.find(entry => entry.slug === "gpt-5.6-sol")?.display_name).toBe("GPT 5.6 Sol"); + const changed = mergeObservedForTest({ + ...input, catalogModels: regenerated, + nativeDisplayNames: { "gpt-5.6-sol": " Sol 5.6 " }, + }); + expect(changed.find(entry => entry.slug === "gpt-5.6-sol")?.display_name).toBe("Sol 5.6"); + expect(JSON.stringify(regenerated)).toBe(JSON.stringify(renamed)); + for (const nativeDisplayNames of [undefined, {}, { "gpt-5.6-sol": " " }]) { + const restored = mergeObservedForTest({ ...input, catalogModels: changed, nativeDisplayNames }); + expect(restored).toEqual(original); + } + }); + + test("native display names preserve external label changes when clearing the overlay", () => { + const renamed = mergeObservedForTest({ + catalogModels: [{ ...nativeTemplate(), slug: "gpt-5.6-sol" }], routedEntries: [], + nativeDisplayNames: { "gpt-5.6-sol": "Custom Sol" }, + }); + renamed.find(entry => entry.slug === "gpt-5.6-sol")!.display_name = "Updated upstream Sol"; + const restored = mergeObservedForTest({ catalogModels: renamed, routedEntries: [] }); + const row = restored.find(entry => entry.slug === "gpt-5.6-sol")!; + expect(row.display_name).toBe("Updated upstream Sol"); + expect(row.opencodex_native_display_name).toBeUndefined(); + }); + + test("native display names preserve pinned metadata upgrades and restore pinned names", () => { + for (const slug of ["gpt-5.6-sol", "gpt-6-astra"]) { + const input = { catalogModels: [{ ...nativeTemplate(), slug, display_name: slug }], routedEntries: [] }; + const original = mergeObservedForTest(input); + const renamed = mergeObservedForTest({ ...input, nativeDisplayNames: { [slug]: "Custom name" } }); + expect(renamed.find(entry => entry.slug === slug)?.display_name).toBe("Custom name"); + expect(mergeObservedForTest({ catalogModels: renamed, routedEntries: [] })).toEqual(original); + } + }); + + test("clearing a native label keeps Astra external edits subject to pinned metadata normalization", () => { + const original = mergeObservedForTest({ + catalogModels: [{ ...nativeTemplate(), slug: "gpt-6-astra", display_name: "gpt-6-astra" }], + routedEntries: [], + }); + const renamed = mergeObservedForTest({ + catalogModels: original, routedEntries: [], + nativeDisplayNames: { "gpt-6-astra": "Custom Astra" }, + }); + const external = JSON.parse(JSON.stringify(renamed)) as Record[]; + const astra = external.find(entry => entry.slug === "gpt-6-astra")!; + astra.display_name = "External Astra name"; + astra.context_window = 123; + const restored = mergeObservedForTest({ catalogModels: external, routedEntries: [] }); + const row = restored.find(entry => entry.slug === "gpt-6-astra")!; + expect(row).toEqual(original.find(entry => entry.slug === "gpt-6-astra")!); + expect(row.display_name).not.toBe("External Astra name"); + expect(row.context_window).toBe(272_000); + expect(row.opencodex_native_display_name).toBeUndefined(); + expect(astra.display_name).toBe("External Astra name"); + expect(astra.opencodex_native_display_name).toBeDefined(); + }); + + test("native display names do not leak overlay markers through catalog templates", () => { + const template = { + ...nativeTemplate(), + opencodex_native_display_name: { slug: "gpt-5.6-sol", original: "Sol", applied: "Custom" }, + }; + const entries = buildCatalogEntries(template, ["gpt-5.5"], [{ provider: "local", id: "qwen3-coder" }]); + expect(entries.length).toBeGreaterThanOrEqual(2); + for (const entry of entries) expect(entry.opencodex_native_display_name).toBeUndefined(); + expect(template.opencodex_native_display_name).toBeDefined(); + }); + + test("native display names do not relabel a routed combo occupying a native slug", () => { + const routed = { + ...nativeTemplate(), slug: "gpt-5.6-sol", display_name: "My combo", + owned_by: "combo", description: "Routed via opencodex → combo (combo).", + opencodex_catalog_kind: CODEX_NATIVE_ALIAS_CATALOG_KIND, + }; + const rows = mergeObservedForTest({ + catalogModels: [], routedEntries: [routed], + nativeDisplayNames: { "gpt-5.6-sol": "GPT 5.6 Sol" }, + }); + expect(rows.find(entry => entry.slug === "gpt-5.6-sol")?.display_name).toBe("My combo"); + }); + test("pending re-registration cannot recover ON rows from a degraded old catalog", () => { const old = { ...nativeTemplate(), slug: "vendor/model-0", owned_by: "vendor", opencodex_catalog_kind: CODEX_PROVIDER_MODEL_CATALOG_KIND }; const input = { From 1ee829d2c541a36272d40d4b0fcddc017e7ee819 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 07:38:34 +0900 Subject: [PATCH 014/412] feat(cli): carry provider list JSONL output [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Carry the net diff of #3780 at 9b873e6f7519a022dd4658db4d1cb92689bb4663. Strengthen multi-record JSON parity, escaping, and conflicting-flag coverage; synchronize all seven translated CLI pages and clarify consumer-side processing. Local tests, typecheck, and builds NOT RUN by owner mandate. Regenerated the capability surface and inspected the static diff. Lower-layer CI is owner-requested deferred evidence, not passing evidence; final combined CI belongs to the integration owner. Co-authored-by: 투린 --- .../fr/reference/cli/providers-accounts.md | 5 +- .../ja/reference/cli/providers-accounts.md | 5 +- .../ko/reference/cli/providers-accounts.md | 5 +- .../docs/reference/cli/providers-accounts.md | 8 +- .../ru/reference/cli/providers-accounts.md | 5 +- .../tr/reference/cli/providers-accounts.md | 5 +- .../zh-cn/reference/cli/providers-accounts.md | 5 +- .../zh-tw/reference/cli/providers-accounts.md | 5 +- .../ocx/references/01_management_surface.md | 1 + skills/ocx/references/02_json_shapes.md | 5 ++ skills/ocx/references/03_recipes.md | 1 + src/cli/capabilities.ts | 5 +- src/cli/provider.ts | 42 +++++++---- tests/cli/cli-provider.test.ts | 74 +++++++++++++++++++ 14 files changed, 147 insertions(+), 24 deletions(-) diff --git a/docs-site/src/content/docs/fr/reference/cli/providers-accounts.md b/docs-site/src/content/docs/fr/reference/cli/providers-accounts.md index 284c8c20c3..ac4e42bbc2 100644 --- a/docs-site/src/content/docs/fr/reference/cli/providers-accounts.md +++ b/docs-site/src/content/docs/fr/reference/cli/providers-accounts.md @@ -14,7 +14,7 @@ Gestion des fournisseurs non interactive. Les entrées de registre sont classée | Sous-commande | Drapeaux pris en charge | Actions | | --- | --- | --- | -| `list` | `--json` | Répertoriez les fournisseurs configurés et les entrées de registre restantes. | +| `list` | `--json`, `--jsonl` | Répertoriez les fournisseurs configurés et les entrées de registre restantes. `--jsonl` émet un objet JSON par fournisseur configuré et par ligne. | | `add ` | `--adapter `, `--base-url `, `--api-key `, `--default-model `, `--set-default`, `--force`, `--json`, `--sync` | Ajoutez un fournisseur registry/custom. `--force` écrase ; `--sync` actualise un proxy en cours d'exécution en mode sortie humaine. | | `edit ` | indicateurs de champ du fournisseur, `--headers `, `--json` | Modifiez les champs de fournisseur en direct validés sans remplacer les pools de clés. `--headers` fusionne les en-têtes de requête personnalisés ; passez `{}` ou `-` pour les effacer. | | `test ` | `--json` | Sondez le véritable point de terminaison du modèle en amont. | @@ -28,6 +28,7 @@ Gestion des fournisseurs non interactive. Les entrées de registre sont classée ```bash ocx provider list --json +ocx provider list --jsonl ocx provider test ark ocx provider add anthropic --api-key sk-ant-... --set-default --sync ocx provider add local-dev --adapter openai-chat --base-url http://localhost:11434/v1 @@ -36,6 +37,8 @@ ocx models --provider anthropic --json ocx models live --provider ark --json ``` +`--jsonl` écrit uniquement les fournisseurs configurés, un objet JSON par ligne. Chaque objet contient les mêmes champs qu’un élément du tableau `configured` de `--json`, sans le résumé `registryCount`. Les scripts peuvent traiter les objets ligne par ligne. `--json` et `--jsonl` ne peuvent pas être combinés. + :::caution[Les en-têtes personnalisés ne sont pas un canal d'identification] `--headers` est destiné aux métadonnées de requête non secrètes : conseils de routage, locataire ou sélecteurs de projets, identifiants de traçage. Ce n'est **pas** un endroit pour mettre l'authentification diff --git a/docs-site/src/content/docs/ja/reference/cli/providers-accounts.md b/docs-site/src/content/docs/ja/reference/cli/providers-accounts.md index d20483a8a2..594d1fc30e 100644 --- a/docs-site/src/content/docs/ja/reference/cli/providers-accounts.md +++ b/docs-site/src/content/docs/ja/reference/cli/providers-accounts.md @@ -13,7 +13,7 @@ description: プロバイダー構成、資格情報、クォータ、および |サブコマンド |サポートされているフラグ |アクション | | --- | --- | --- | -| `list` | `--json` |構成されたプロバイダーと残りのレジストリ エントリを一覧表示します。 | +| `list` | `--json`, `--jsonl` |構成されたプロバイダーと残りのレジストリ エントリを一覧表示します。 `--jsonl` は設定済みプロバイダーごとに1行の JSON オブジェクトを出力します。 | | `add ` | `--adapter `、`--base-url `、`--api-key `、`--default-model `、`--set-default`、`--force`、`--json`、`--sync` |レジストリ/カスタムプロバイダーを追加します。 `--force` は上書きします。 `--sync` は、実行中のプロキシを人間出力モードで更新します。 | | `edit ` |プロバイダーフィールドフラグ、`--headers `、`--json` |キー プールを置き換えずに、検証済みのライブ プロバイダー フィールドを編集します。`--headers` はカスタム要求ヘッダーをマージします。`{}` または `-` を渡すとクリアします。 | | `test ` | `--json` |実際の上流モデルのエンドポイントを調査します。 | @@ -27,6 +27,7 @@ description: プロバイダー構成、資格情報、クォータ、および ```bash ocx provider list --json +ocx provider list --jsonl ocx provider test ark ocx provider add anthropic --api-key sk-ant-... --set-default --sync ocx provider add local-dev --adapter openai-chat --base-url http://localhost:11434/v1 @@ -35,6 +36,8 @@ ocx models --provider anthropic --json ocx models live --provider ark --json ``` +`--jsonl` は設定済みプロバイダーのみを、1行につき1つの JSON オブジェクトとして出力します。各オブジェクトのフィールドは `--json` の `configured` 配列の要素と同じで、`registryCount` の集計は含みません。スクリプトは各行のオブジェクトを順に処理できます。`--json` と `--jsonl` は同時に指定できません。 + :::caution[カスタムヘッダーは認証情報の経路ではありません] `--headers` は秘密ではないリクエストメタデータ用です — ルーティングヒント、テナントや プロジェクトのセレクター、トレース ID など。認証情報を入れる場所ではなく、バリデーターは diff --git a/docs-site/src/content/docs/ko/reference/cli/providers-accounts.md b/docs-site/src/content/docs/ko/reference/cli/providers-accounts.md index 250b3d7b1b..ed3c6a565d 100644 --- a/docs-site/src/content/docs/ko/reference/cli/providers-accounts.md +++ b/docs-site/src/content/docs/ko/reference/cli/providers-accounts.md @@ -13,7 +13,7 @@ description: 제공자 설정, 자격 증명, 할당량, 모델 카탈로그 명 | 하위 명령 | 지원 플래그 | 동작 | | --- | --- | --- | -| `list` | `--json` | 설정된 제공자와 남아 있는 레지스트리 항목을 나열합니다. | +| `list` | `--json`, `--jsonl` | 설정된 제공자와 남아 있는 레지스트리 항목을 나열합니다. `--jsonl`은 설정된 제공자마다 JSON 객체를 한 줄씩 출력합니다. | | `add ` | `--adapter `, `--base-url `, `--api-key `, `--default-model `, `--set-default`, `--force`, `--json`, `--sync` | 레지스트리/사용자 지정 제공자를 추가합니다. `--force`는 덮어쓰고, `--sync`는 사람이 읽는 출력 모드에서 실행 중인 프록시를 새로 고칩니다. | | `edit ` | 제공자 필드 플래그, `--headers `, `--json` | 키 풀을 바꾸지 않고 검증된 실시간 제공자 필드를 수정합니다. `--headers`는 사용자 지정 요청 헤더를 병합하며, `{}` 또는 `-`로 지울 수 있습니다. | | `test ` | `--json` | 실제 상위 모델 엔드포인트를 확인합니다. | @@ -27,6 +27,7 @@ description: 제공자 설정, 자격 증명, 할당량, 모델 카탈로그 명 ```bash ocx provider list --json +ocx provider list --jsonl ocx provider test ark ocx provider add anthropic --api-key sk-ant-... --set-default --sync ocx provider add local-dev --adapter openai-chat --base-url http://localhost:11434/v1 @@ -35,6 +36,8 @@ ocx models --provider anthropic --json ocx models live --provider ark --json ``` +`--jsonl`은 설정된 제공자만 JSON 객체 하나당 한 줄로 출력합니다. 각 객체의 필드는 `--json`의 `configured` 배열 항목과 같으며, `registryCount` 요약은 포함하지 않습니다. 스크립트에서 각 줄의 객체를 순서대로 처리할 수 있습니다. `--json`과 `--jsonl`은 함께 사용할 수 없습니다. + :::caution[커스텀 헤더는 자격증명 통로가 아닙니다] `--headers`는 비밀이 아닌 요청 메타데이터용입니다 — 라우팅 힌트, 테넌트나 프로젝트 선택자, 추적 id 같은 것들이요. 인증 정보를 넣는 자리가 아니고, 검증기는 표준 자격증명 diff --git a/docs-site/src/content/docs/reference/cli/providers-accounts.md b/docs-site/src/content/docs/reference/cli/providers-accounts.md index b31c0f3159..3d602799bb 100644 --- a/docs-site/src/content/docs/reference/cli/providers-accounts.md +++ b/docs-site/src/content/docs/reference/cli/providers-accounts.md @@ -14,7 +14,7 @@ both `--adapter` and `--base-url`. | Subcommand | Supported flags | Action | | --- | --- | --- | -| `list` | `--json` | List configured providers and the remaining registry entries. | +| `list` | `--json`, `--jsonl` | List configured providers and the remaining registry entries; `--jsonl` emits one configured provider object per line. | | `add ` | `--adapter `, `--base-url `, `--api-key `, `--default-model `, `--set-default`, `--force`, `--json`, `--sync` | Add a registry/custom provider. `--force` overwrites; `--sync` refreshes a running proxy in human-output mode. | | `edit ` | provider field flags, `--headers `, `--json` | Edit validated live provider fields without replacing key pools. `--headers` merges custom request headers; pass `{}` or `-` to clear them. | | `test ` | `--json` | Probe the real upstream model endpoint. | @@ -29,6 +29,7 @@ both `--adapter` and `--base-url`. ```bash ocx provider list --json +ocx provider list --jsonl # one configured provider object per line ocx provider test ark ocx provider add anthropic --api-key sk-ant-... --set-default --sync ocx provider add local-dev --adapter openai-chat --base-url http://localhost:11434/v1 @@ -37,6 +38,11 @@ ocx models --provider anthropic --json ocx models live --provider ark --json ``` +`--jsonl` writes only configured providers, one JSON object per line, and omits the +`registryCount` summary from `--json`. Each object has the same fields as an item in the `configured` array. +Use it for scripts that process one configured provider object per line. +`--json` and `--jsonl` cannot be combined. + :::caution[Custom headers are not a credential channel] `--headers` is for non-secret request metadata — routing hints, tenant or project selectors, tracing ids. It is **not** a place to put authentication diff --git a/docs-site/src/content/docs/ru/reference/cli/providers-accounts.md b/docs-site/src/content/docs/ru/reference/cli/providers-accounts.md index 56bde92668..4ae2bc7b5f 100644 --- a/docs-site/src/content/docs/ru/reference/cli/providers-accounts.md +++ b/docs-site/src/content/docs/ru/reference/cli/providers-accounts.md @@ -15,7 +15,7 @@ pool'ами и контролируют каталог моделей, кото | Подкоманда | Поддерживаемые флаги | Действие | | --- | --- | --- | -| `list` | `--json` | Показать настроенных провайдеров и оставшиеся записи registry. | +| `list` | `--json`, `--jsonl` | Показать настроенных провайдеров и оставшиеся записи registry. `--jsonl` выводит по одному JSON-объекту настроенного провайдера на строку. | | `add ` | `--adapter `, `--base-url `, `--api-key `, `--default-model `, `--set-default`, `--force`, `--json`, `--sync` | Добавить registry/custom-провайдера. `--force` перезаписывает; `--sync` обновляет живой прокси в human-output mode. | | `edit ` | provider field flags, `--headers `, `--json` | Изменить валидированные live-поля провайдера, не заменяя key-pool'ы. `--headers` объединяет пользовательские request-header'ы; передайте `{}` или `-`, чтобы очистить их. | | `test ` | `--json` | Пробный запрос к реальному upstream model-endpoint'у. | @@ -29,6 +29,7 @@ pool'ами и контролируют каталог моделей, кото ```bash ocx provider list --json +ocx provider list --jsonl ocx provider test ark ocx provider add anthropic --api-key sk-ant-... --set-default --sync ocx provider add local-dev --adapter openai-chat --base-url http://localhost:11434/v1 @@ -37,6 +38,8 @@ ocx models --provider anthropic --json ocx models live --provider ark --json ``` +`--jsonl` выводит только настроенных провайдеров: один JSON-объект на строку. Поля каждого объекта совпадают с полями элемента массива `configured` в `--json`; сводка `registryCount` не включается. Скрипты могут обрабатывать объекты построчно. Флаги `--json` и `--jsonl` нельзя использовать вместе. + :::caution[Пользовательские заголовки — не канал для учётных данных] `--headers` предназначен для несекретных метаданных запроса — подсказок маршрутизации, селекторов тенанта или проекта, идентификаторов трассировки. Это не diff --git a/docs-site/src/content/docs/tr/reference/cli/providers-accounts.md b/docs-site/src/content/docs/tr/reference/cli/providers-accounts.md index f611d7be73..2d58adae3b 100644 --- a/docs-site/src/content/docs/tr/reference/cli/providers-accounts.md +++ b/docs-site/src/content/docs/tr/reference/cli/providers-accounts.md @@ -16,7 +16,7 @@ bir ad hem `--adapter` hem de `--base-url` gerektirir. | Alt komut | Desteklenen bayraklar | Eylem | | --- | --- | --- | -| `list` | `--json` | Yapılandırılmış sağlayıcıları ve kalan kayıt defteri girdilerini listeleyin. | +| `list` | `--json`, `--jsonl` | Yapılandırılmış sağlayıcıları ve kalan kayıt defteri girdilerini listeleyin. `--jsonl`, yapılandırılmış her sağlayıcı için satır başına bir JSON nesnesi üretir. | | `add ` | `--adapter `, `--base-url `, `--api-key `, `--default-model `, `--set-default`, `--force`, `--json`, `--sync` | Bir kayıt defteri/özel sağlayıcı ekleyin. `--force` üzerine yazar; `--sync`, insan çıktısı modunda çalışan bir proxy'yi yeniler. | | `edit ` | sağlayıcı alan bayrakları, `--headers `, `--json` | Anahtar havuzlarını değiştirmeden doğrulanmış canlı sağlayıcı alanlarını düzenleyin. `--headers` özel istek başlıklarını birleştirir; temizlemek için `{}` veya `-` iletin. | | `test ` | `--json` | Gerçek yukarı akış model uç noktasını araştırın. | @@ -30,6 +30,7 @@ bir ad hem `--adapter` hem de `--base-url` gerektirir. ```bash ocx provider list --json +ocx provider list --jsonl ocx provider test ark ocx provider add anthropic --api-key sk-ant-... --set-default --sync ocx provider add local-dev --adapter openai-chat --base-url http://localhost:11434/v1 @@ -38,6 +39,8 @@ ocx models --provider anthropic --json ocx models live --provider ark --json ``` +`--jsonl` yalnızca yapılandırılmış sağlayıcıları, her satırda bir JSON nesnesi olacak şekilde yazar. Her nesne, `--json` çıktısındaki `configured` dizisinin bir öğesiyle aynı alanları içerir; `registryCount` özeti eklenmez. Betikler nesneleri satır satır işleyebilir. `--json` ve `--jsonl` birlikte kullanılamaz. + :::caution[Özel başlıklar bir kimlik bilgisi kanalı değildir] `--headers`, gizli olmayan istek meta verileri içindir — yönlendirme ipuçları, kiracı veya proje seçicileri, izleme kimlikleri. Kimlik doğrulama materyali diff --git a/docs-site/src/content/docs/zh-cn/reference/cli/providers-accounts.md b/docs-site/src/content/docs/zh-cn/reference/cli/providers-accounts.md index 85633f54f5..a6fe332390 100644 --- a/docs-site/src/content/docs/zh-cn/reference/cli/providers-accounts.md +++ b/docs-site/src/content/docs/zh-cn/reference/cli/providers-accounts.md @@ -14,7 +14,7 @@ description: 提供方配置、凭据、配额,以及模型目录命令。 | 子命令 | 支持的标志 | 操作 | | --- | --- | --- | -| `list` | `--json` | 列出已配置的提供方以及剩余的注册表条目。 | +| `list` | `--json`, `--jsonl` | 列出已配置的提供方以及剩余的注册表条目。 `--jsonl` 为每个已配置的提供方输出一行 JSON 对象。 | | `add ` | `--adapter `, `--base-url `, `--api-key `, `--default-model `, `--set-default`, `--force`, `--json`, `--sync` | 添加一个注册表/自定义提供方。`--force` 会覆盖;`--sync` 会在有人类输出模式运行的代理上刷新配置。 | | `edit ` | 提供方字段标志,`--headers `,`--json` | 在不替换密钥池的情况下,编辑经过校验的在线提供方字段。`--headers` 会合并自定义请求头;传入 `{}` 或 `-` 可清空。 | | `test ` | `--json` | 探测真实的上游模型端点。 | @@ -28,6 +28,7 @@ description: 提供方配置、凭据、配额,以及模型目录命令。 ```bash ocx provider list --json +ocx provider list --jsonl ocx provider test ark ocx provider add anthropic --api-key sk-ant-... --set-default --sync ocx provider add local-dev --adapter openai-chat --base-url http://localhost:11434/v1 @@ -36,6 +37,8 @@ ocx models --provider anthropic --json ocx models live --provider ark --json ``` +`--jsonl` 仅输出已配置的提供方,每行一个 JSON 对象。每个对象的字段与 `--json` 输出中 `configured` 数组的元素相同,不包含 `registryCount` 汇总。脚本可以逐行处理这些对象。`--json` 与 `--jsonl` 不能同时使用。 + :::caution[自定义请求头不是凭据通道] `--headers` 用于非机密的请求元数据 —— 路由提示、租户或项目选择器、追踪 ID 等。它不是 存放认证信息的地方,校验器会拒绝标准凭据请求头名称(`Authorization`、`X-Api-Key`、 diff --git a/docs-site/src/content/docs/zh-tw/reference/cli/providers-accounts.md b/docs-site/src/content/docs/zh-tw/reference/cli/providers-accounts.md index c50a6d54ae..fbf1ff186c 100644 --- a/docs-site/src/content/docs/zh-tw/reference/cli/providers-accounts.md +++ b/docs-site/src/content/docs/zh-tw/reference/cli/providers-accounts.md @@ -13,7 +13,7 @@ description: 供應商設定、憑證、配額與模型目錄指令。 | 子指令 | 支援的旗標 | 動作 | | --- | --- | --- | -| `list` | `--json` | 列出已設定的供應商與剩餘的 registry 項目。 | +| `list` | `--json`, `--jsonl` | 列出已設定的供應商與剩餘的 registry 項目。 `--jsonl` 為每個已設定的供應商輸出一行 JSON 物件。 | | `add ` | `--adapter `, `--base-url `, `--api-key `, `--default-model `, `--set-default`, `--force`, `--json`, `--sync` | 新增 registry/自訂供應商。`--force` 覆寫;`--sync` 在人類輸出模式下重新整理執行中的代理。 | | `edit ` | 供應商欄位旗標, `--json` | 編輯已驗證的即時供應商欄位而不替換金鑰池。 | | `test ` | `--json` | 探測真實上游模型端點。 | @@ -27,6 +27,7 @@ description: 供應商設定、憑證、配額與模型目錄指令。 ```bash ocx provider list --json +ocx provider list --jsonl ocx provider test ark ocx provider add anthropic --api-key sk-ant-... --set-default --sync ocx provider add local-dev --adapter openai-chat --base-url http://localhost:11434/v1 @@ -35,6 +36,8 @@ ocx models --provider anthropic --json ocx models live --provider ark --json ``` +`--jsonl` 僅輸出已設定的供應商,每行一個 JSON 物件。每個物件的欄位與 `--json` 輸出中 `configured` 陣列的元素相同,不包含 `registryCount` 摘要。指令碼可以逐行處理這些物件。`--json` 與 `--jsonl` 不能同時使用。 + ## 認證 ### `ocx login ` diff --git a/skills/ocx/references/01_management_surface.md b/skills/ocx/references/01_management_surface.md index d5711f3cac..10b0cd9e89 100644 --- a/skills/ocx/references/01_management_surface.md +++ b/skills/ocx/references/01_management_surface.md @@ -67,6 +67,7 @@ Drives no management route. | Flag | Value | Meaning | |---|---|---| | `--json` | boolean | Emit the provider list as JSON. | +| `--jsonl` | boolean | Emit one configured provider per JSON line. | JSON mode: `envelope`. diff --git a/skills/ocx/references/02_json_shapes.md b/skills/ocx/references/02_json_shapes.md index a91e35a2e1..261c8be5a2 100644 --- a/skills/ocx/references/02_json_shapes.md +++ b/skills/ocx/references/02_json_shapes.md @@ -52,6 +52,11 @@ to `requestedModel` is how you get a wrong answer about which provider served it `displayMetrics.cost.estimate.estimateReasons` lists why — for example `usage_estimated`, `cache_detail_missing`, `expected_price_overlay`. +## `ocx provider list --jsonl` + +One configured provider per line. Each object has the same fields as an item in the +`configured` array from `ocx provider list --json`; the `registryCount` summary is omitted. + ## `ocx logs explain ` ```json diff --git a/skills/ocx/references/03_recipes.md b/skills/ocx/references/03_recipes.md index 424ad34a53..9159751424 100644 --- a/skills/ocx/references/03_recipes.md +++ b/skills/ocx/references/03_recipes.md @@ -157,6 +157,7 @@ exist for them — do not attribute usage to either. ```bash ocx provider list --json +ocx provider list --jsonl # one configured provider per line ocx provider add --json # registry providers auto-configure by name ocx provider test --json ocx provider set-default --json diff --git a/src/cli/capabilities.ts b/src/cli/capabilities.ts index 1b5cfd6283..ff1f5fb9a2 100644 --- a/src/cli/capabilities.ts +++ b/src/cli/capabilities.ts @@ -148,7 +148,10 @@ export const CAPABILITIES: readonly Capability[] = [ summary: "Configured providers with connectivity and selected models.", // Local config + PROVIDER_REGISTRY. Does not call GET /api/providers. routes: [], - flags: [{ name: "--json", value: "boolean", summary: "Emit the provider list as JSON." }], + flags: [ + { name: "--json", value: "boolean", summary: "Emit the provider list as JSON." }, + { name: "--jsonl", value: "boolean", summary: "Emit one configured provider per JSON line." }, + ], mutates: false, json: "envelope", details: ["Reads local config; drives no management API route."], diff --git a/src/cli/provider.ts b/src/cli/provider.ts index 55c654d8d7..47f23fee62 100644 --- a/src/cli/provider.ts +++ b/src/cli/provider.ts @@ -79,26 +79,37 @@ function validateAndSave(config: ReturnType): void { function handleList(args: string[]): void { const wantsJson = consumeFlag(args, "--json"); - rejectUnknownArgs(args, "Usage: ocx provider list [--json]"); + const wantsJsonl = consumeFlag(args, "--jsonl"); + rejectUnknownArgs(args, "Usage: ocx provider list [--json|--jsonl]"); + + if (wantsJson && wantsJsonl) { + console.error("Use only one of --json or --jsonl."); + process.exit(1); + } const config = loadConfig(); const configured = Object.keys(config.providers); + const entries = configured.map(name => { + const prov = config.providers[name]; + const registryEntry = getProviderRegistryEntry(name); + return { + name, + adapter: prov.adapter, + baseUrl: prov.baseUrl, + authMode: prov.authMode ?? "key", + defaultModel: prov.defaultModel ?? null, + isDefault: name === config.defaultProvider, + source: registryEntry ? "registry" : "custom", + models: prov.models ?? [], + }; + }); + + if (wantsJsonl) { + for (const entry of entries) console.log(JSON.stringify(entry)); + return; + } if (wantsJson) { - const entries = configured.map(name => { - const prov = config.providers[name]; - const registryEntry = getProviderRegistryEntry(name); - return { - name, - adapter: prov.adapter, - baseUrl: prov.baseUrl, - authMode: prov.authMode ?? "key", - defaultModel: prov.defaultModel ?? null, - isDefault: name === config.defaultProvider, - source: registryEntry ? "registry" : "custom", - models: prov.models ?? [], - }; - }); console.log(JSON.stringify({ configured: entries, registryCount: PROVIDER_REGISTRY.length }, null, 2)); return; } @@ -444,6 +455,7 @@ Subcommands: Examples: ocx provider list + ocx provider list --jsonl ocx provider add anthropic --api-key sk-ant-... ocx provider add my-ollama --adapter openai-chat --base-url http://localhost:11434/v1 ocx provider show anthropic --json diff --git a/tests/cli/cli-provider.test.ts b/tests/cli/cli-provider.test.ts index b83bc8d514..ea29c5535f 100644 --- a/tests/cli/cli-provider.test.ts +++ b/tests/cli/cli-provider.test.ts @@ -109,6 +109,80 @@ describe("ocx provider", () => { } }); + test("provider list --jsonl matches JSON configured records with escaped model values", () => { + const escapedModel = 'model-"quoted"\\path\nnext\r\ttab-한글'; + const { dir } = freshConfig({ + providers: { + openai: { + adapter: "openai-responses", + baseUrl: "https://chatgpt.com/backend-api/codex", + authMode: "forward", + }, + "custom.models-1": { + adapter: "openai-chat", + baseUrl: "https://models.example.test/v1", + defaultModel: escapedModel, + models: ["plain-model", escapedModel], + }, + }, + defaultProvider: "custom.models-1", + }); + try { + const result = runCli(["provider", "list", "--jsonl"], { OPENCODEX_HOME: dir }); + const json = runCli(["provider", "list", "--json"], { OPENCODEX_HOME: dir }); + expect(result.status).toBe(0); + expect(json.status).toBe(0); + // Keep every physical line: embedded newlines must be escaped, and only + // the final record terminator may produce an empty split element. + const lines = result.stdout.split(/\r?\n/); + expect(lines.pop()).toBe(""); + expect(lines).toHaveLength(2); + const records = lines.map(line => JSON.parse(line)); + const envelope = JSON.parse(json.stdout); + expect(records).toEqual(envelope.configured); + expect(envelope.registryCount).toBeGreaterThan(0); + expect(records).toEqual([ + { + name: "openai", + adapter: "openai-responses", + baseUrl: "https://chatgpt.com/backend-api/codex", + authMode: "forward", + defaultModel: null, + isDefault: false, + source: "registry", + models: [], + }, + { + name: "custom.models-1", + adapter: "openai-chat", + baseUrl: "https://models.example.test/v1", + authMode: "key", + defaultModel: escapedModel, + isDefault: true, + source: "custom", + models: ["plain-model", escapedModel], + }, + ]); + } finally { + removeTreeWithRetry(dir); + } + }); + + test.each([ + ["--json", "--jsonl"], + ["--jsonl", "--json"], + ])("provider list rejects %s %s without stdout", (first, second) => { + const { dir } = freshConfig(); + try { + const result = runCli(["provider", "list", first, second], { OPENCODEX_HOME: dir }); + expect(result.status).toBe(1); + expect(result.stdout).toBe(""); + expect(result.stderr).toContain("Use only one of --json or --jsonl"); + } finally { + removeTreeWithRetry(dir); + } + }); + test("provider add registry provider seeds config", () => { const { dir } = freshConfig(); try { From e00d5c341778b81cc09dca7cef56e20d776316ee Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 07:41:25 +0900 Subject: [PATCH 015/412] test(container): verify build startup and volume recreation [skip ci] Exercise the source-build contract from #3421/#3604 and separate-home persistence from #3747 using disposable Docker resources. Preserve original token and both named volumes through container replacement; verify admission without upstream inference. Independent source/security review completed; actual Docker networking and runtime acceptance remain pending final CI. Co-authored-by: Buseong Kim Co-authored-by: Ingwannu --- scripts/ci/docker-smoke.ts | 338 +++++++++++++++++++++++++++++++++++++ 1 file changed, 338 insertions(+) create mode 100644 scripts/ci/docker-smoke.ts diff --git a/scripts/ci/docker-smoke.ts b/scripts/ci/docker-smoke.ts new file mode 100644 index 0000000000..0745f6bd9e --- /dev/null +++ b/scripts/ci/docker-smoke.ts @@ -0,0 +1,338 @@ +/** Hosted Linux Docker acceptance only; never uses provider credentials or inference. */ +import { spawn } from "node:child_process"; +import { createHash, randomBytes } from "node:crypto"; +import { chmodSync, existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, rmSync, rmdirSync, utimesSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join, resolve } from "node:path"; + +const root = resolve(import.meta.dir, "../.."); +const project = `ocx-smoke-${randomBytes(12).toString("hex")}`; +const image = `${project}:local`; +const cancelled = new AbortController(); +const outputLimit = 8 * 1024 * 1024; +let stage = "initialization"; +let scratch = ""; +let composeArgs: string[] = []; +let env: Record = {}; + +class SmokeFailure extends Error {} + +function check(ok: unknown, message: string): asserts ok { + if (!ok) throw new SmokeFailure(message); +} + +// Do not include arguments, child output, HTTP bodies, or arbitrary error messages in diagnostics. +function progress(name: string): void { + stage = name; + console.log(`docker-smoke: ${name}`); +} + +async function run(args: string[], input?: string, timeout = 30_000, cleanup = false) { + if (!cleanup) cancelled.signal.throwIfAborted(); + return await new Promise<{ code: number | null; out: string }>((accept, reject) => { + const child = spawn(args[0]!, args.slice(1), { + cwd: root, env, detached: true, stdio: ["pipe", "pipe", "pipe"], + }); + const chunks: Buffer[] = []; + let bytes = 0; + let failed = false; + let killTimer: ReturnType | undefined; + let reapTimer: ReturnType | undefined; + const killGroup = (signal: NodeJS.Signals) => { + if (child.pid) { + try { process.kill(-child.pid, signal); } catch { /* already exited */ } + } + }; + const stop = () => { + if (failed) return; + failed = true; + killGroup("SIGTERM"); + killTimer = setTimeout(() => killGroup("SIGKILL"), 1_000); + // A daemon/plugin retaining a pipe must not keep the harness alive indefinitely. + reapTimer = setTimeout(() => { + child.stdout.destroy(); child.stderr.destroy(); child.stdin.destroy(); + finish(); + child.unref(); + reject(new SmokeFailure("child did not close within the termination deadline")); + }, 4_000); + }; + const timer = setTimeout(stop, timeout); + const finish = () => { + clearTimeout(timer); clearTimeout(killTimer); clearTimeout(reapTimer); + cancelled.signal.removeEventListener("abort", stop); + }; + if (!cleanup) cancelled.signal.addEventListener("abort", stop, { once: true }); + const collect = (data: Buffer, stdout: boolean) => { + bytes += data.length; + if (bytes > outputLimit) stop(); + else if (stdout) chunks.push(data); + }; + child.stdout.on("data", (data: Buffer) => collect(data, true)); + child.stderr.on("data", (data: Buffer) => collect(data, false)); + child.stdin.on("error", () => { /* EPIPE is possible on the refused bootstrap. */ }); + child.on("error", () => { finish(); reject(new SmokeFailure("child could not start")); }); + child.on("close", code => { + // A terminated CLI can close its pipes before its plugin exits. + if (failed) killGroup("SIGKILL"); + finish(); + if (failed) reject(new SmokeFailure("child exceeded time/output limit or was cancelled")); + else accept({ code, out: Buffer.concat(chunks).toString("utf8") }); + }); + child.stdin.end(input); + }); +} + +async function command(args: string[], input?: string, timeout?: number, cleanup = false) { + const result = await run(args, input, timeout, cleanup); + check(result.code === 0, `command exited ${result.code ?? "by signal"}`); + return result.out.trim(); +} + +function compose(args: string[], input?: string, timeout?: number, cleanup = false) { + return command(["docker", ...composeArgs, ...args], input, timeout, cleanup); +} + +async function build() { + const directory = join(root, "src/generated"); + const manifest = join(directory, "compatibility-version.json"); + const directoryStat = lstatSync(directory, { throwIfNoEntry: false }); + const hadDirectory = directoryStat !== undefined; + check(!directoryStat || directoryStat.isDirectory(), "unsafe generated directory"); + const originalStat = lstatSync(manifest, { throwIfNoEntry: false }); + check(!originalStat || originalStat.isFile(), "unsafe existing manifest"); + check(!originalStat || originalStat.size <= 8 * 1024 * 1024, "existing manifest exceeds limit"); + const original = originalStat ? readFileSync(manifest) : undefined; + try { + progress("generate compatibility manifest"); + await command([process.execPath, "scripts/generate-compatibility-version.ts"]); + progress("build Docker image"); + await compose(["build", "hub"], undefined, 600_000); + } finally { + if (original && originalStat) { + writeFileSync(manifest, original); + chmodSync(manifest, originalStat.mode & 0o777); + utimesSync(manifest, originalStat.atime, originalStat.mtime); + } else { + rmSync(manifest, { force: true }); + } + if (!hadDirectory && existsSync(directory)) rmdirSync(directory); + } +} + +const fixture = JSON.stringify({ models: [{ + slug: "smoke/synthetic", display_name: "Smoke fixture", description: "Synthetic catalog only", + priority: 1, visibility: "list", base_instructions: "Synthetic", input_modalities: ["text"], +}] }); +const token = randomBytes(32).toString("hex"); +const replacement = randomBytes(32).toString("hex"); +const sha256 = (value: string) => createHash("sha256").update(value).digest("hex"); + +interface Container { + Id: string; + State: { Running: boolean; Health?: { Status: string } }; + HostConfig: { ReadonlyRootfs: boolean; CapDrop: string[]; SecurityOpt: string[]; Privileged: boolean }; + Config: { Image: string; Labels: Record }; + NetworkSettings: { Ports: Record | null> }; + Mounts: Array<{ Type: string; Name?: string; Destination: string; RW: boolean }>; +} + +async function inspect() { + const id = await compose(["ps", "-q", "hub"]); + check(/^[a-f0-9]{64}$/.test(id), "expected exactly one container"); + const rows = JSON.parse(await command(["docker", "inspect", id])) as Container[]; + check(rows.length === 1, "unexpected inspect result"); + const container = rows[0]!; + check(container.Id === id && container.Config.Image === image + && container.Config.Labels["com.docker.compose.project"] === project, "container identity mismatch"); + check(container.State.Running && container.State.Health?.Status === "healthy", "container not healthy"); + check(container.HostConfig.ReadonlyRootfs && !container.HostConfig.Privileged + && container.HostConfig.CapDrop.includes("ALL") + && container.HostConfig.SecurityOpt.some(value => /^no-new-privileges(?::true)?$/.test(value)), "restrictions missing"); + const ports = Object.entries(container.NetworkSettings.Ports).filter(([, entries]) => entries?.length); + check(ports.length === 1 && ports[0]![0] === "10100/tcp", "unexpected published port"); + const bindings = ports[0]![1]!; + check(bindings.length === 1 && bindings[0]!.HostIp === "127.0.0.1", "non-loopback publication"); + const port = Number(bindings[0]!.HostPort); + check(Number.isInteger(port) && port > 0 && port <= 65535, "invalid host port"); + const volumes = [".opencodex", ".codex"].map(home => { + const mounts = container.Mounts.filter(mount => mount.Destination === `/home/bun/${home}`); + check(mounts.length === 1, "missing home mount"); + const mount = mounts[0]!; + check(mount.Type === "volume" && mount.RW && mount.Name?.startsWith(`${project}_`), "unexpected home volume"); + return mount.Name; + }); + check(volumes[0] !== volumes[1], "homes share a volume"); + return { id, volumes, url: `http://127.0.0.1:${port}` }; +} + +// This runs as the image's user. Only hashes/metadata leave the container, never file bytes. +const stateProbe = ` + import { readFileSync, statSync, writeFileSync } from 'node:fs'; + import { createHash } from 'node:crypto'; + const homes = ['/home/bun/.opencodex', '/home/bun/.codex']; + const uid = process.getuid(); + if (uid === 0) throw new Error('root user'); + const status = readFileSync('/proc/self/status', 'utf8'); + if (!/^CapEff:\\s+0+$/m.test(status) || !/^NoNewPrivs:\\s+1$/m.test(status)) throw new Error('effective restrictions'); + for (const home of homes) { + const s = statSync(home); + if (s.uid !== uid || (s.mode & 0o777) !== 0o700) throw new Error('home permissions'); + } + try { writeFileSync('/home/bun/app/.smoke-root-write', 'x'); throw new Error('writable root'); } + catch (e) { if (e.code !== 'EROFS') throw e; } + const paths = [homes[0] + '/config.json', homes[0] + '/service-api-token', homes[1] + '/opencodex-catalog.json']; + const hashes = paths.map(path => { + const s = statSync(path); + if (s.uid !== uid || (s.mode & 0o777) !== 0o600 || s.size > 65536) throw new Error('file permissions/size'); + return createHash('sha256').update(readFileSync(path)).digest('hex'); + }); + console.log(JSON.stringify(hashes)); +`; + +async function state() { + const hashes = JSON.parse(await compose(["exec", "-T", "hub", "bun", "-e", stateProbe])) as string[]; + check(hashes.length === 3 && hashes.every(hash => /^[a-f0-9]{64}$/.test(hash)), "invalid state evidence"); + check(hashes[1] === sha256(`${token}\n`) && hashes[2] === sha256(fixture), "token/catalog changed"); + return JSON.stringify(hashes); +} + +async function request(url: string, path: string, secret?: string) { + const controller = new AbortController(); + const abort = () => controller.abort(); + cancelled.signal.throwIfAborted(); + cancelled.signal.addEventListener("abort", abort, { once: true }); + const timer = setTimeout(abort, 5_000); + try { + const post = path !== "/healthz" && path !== "/readyz" && path !== "/v1/catalog"; + const response = await fetch(`${url}${path}`, { + method: post ? "POST" : "GET", redirect: "error", signal: controller.signal, + headers: { ...(secret ? { "x-opencodex-api-key": secret } : {}), ...(post ? { "content-type": "application/json" } : {}) }, + // Never send an authorized inference request, even with synthetic input. + body: post ? '{"model":"smoke/synthetic","input":[]}' : undefined, + }); + const reader = response.body?.getReader(); + const chunks: Uint8Array[] = []; + let size = 0; + try { + while (reader) { + const next = await reader.read(); + if (next.done) break; + size += next.value.length; + check(size <= 64 * 1024, "HTTP body exceeds limit"); + chunks.push(next.value); + } + } finally { controller.abort(); reader?.releaseLock(); } + return { status: response.status, body: Buffer.concat(chunks).toString("utf8") }; + } finally { + clearTimeout(timer); + cancelled.signal.removeEventListener("abort", abort); + } +} + +async function acceptance(url: string) { + check((await request(url, "/healthz")).status === 200, "liveness failed"); + const deadline = Date.now() + 60_000; + while (true) { + const ready = await request(url, "/readyz"); + const body = JSON.parse(ready.body) as { status?: string }; + if (ready.status === 200 && body.status === "ready") break; + check(ready.status === 503 && body.status === "pending" && Date.now() < deadline, "readiness failed"); + await Bun.sleep(500); + } + for (const path of ["/v1/catalog", "/v1/responses", "/v1/responses/compact"]) { + for (const secret of [undefined, replacement]) { + const result = await request(url, path, secret); + check(result.status === 401, `${path} ${secret ? "wrong" : "missing"} token returned ${result.status}, expected 401`); + } + } + const catalog = await request(url, "/v1/catalog", token); + check(catalog.status === 200 && catalog.body === fixture, "catalog not served exactly"); +} + +async function cleanup() { + let failed = false; + const attempt = async (action: () => Promise) => { + try { await action(); } catch { failed = true; } + }; + if (composeArgs.length) { + await attempt(() => compose(["down", "--volumes", "--remove-orphans", "--timeout", "10"], undefined, 45_000, true)); + for (const kind of ["container", "volume", "network"]) { + await attempt(async () => { + const remaining = await command(["docker", kind, "ls", "-q", ...(kind === "container" ? ["-a"] : []), + "--filter", `label=com.docker.compose.project=${project}`], undefined, 15_000, true); + check(!remaining, "project resources remain"); + }); + } + await attempt(async () => { + const ids = await command(["docker", "image", "ls", "-q", "--filter", `reference=${image}`], undefined, 15_000, true); + if (ids) await command(["docker", "image", "rm", image], undefined, 30_000, true); + check(!await command(["docker", "image", "ls", "-q", "--filter", `reference=${image}`], undefined, 15_000, true), "image remains"); + }); + } + try { if (scratch) rmSync(scratch, { recursive: true, force: true, maxRetries: 0 }); } catch { failed = true; } + check(!failed, "cleanup incomplete"); +} + +async function main() { + check(process.platform === "linux", "requires a disposable Linux Docker runner"); + scratch = mkdtempSync(join(tmpdir(), `${project}-`)); + mkdirSync(join(scratch, "docker"), { mode: 0o700 }); + writeFileSync(join(scratch, "empty.env"), "", { mode: 0o600 }); + writeFileSync(join(scratch, "override.json"), JSON.stringify({ + services: { hub: { image, restart: "no" } }, + // Block upstream egress even if an admission regression reaches a provider path. + networks: { default: { internal: true } }, + }), { mode: 0o600 }); + env = { + PATH: process.env.PATH ?? "/usr/local/bin:/usr/bin:/bin", TMPDIR: scratch, + DOCKER_CONFIG: join(scratch, "docker"), DOCKER_HOST: "unix:///var/run/docker.sock", + COMPOSE_DISABLE_ENV_FILE: "1", OPENCODEX_BIND_ADDRESS: "127.0.0.1", OPENCODEX_PORT: "0", + }; + composeArgs = ["compose", "--project-name", project, "--project-directory", root, + "--env-file", join(scratch, "empty.env"), "-f", join(root, "compose.yaml"), "-f", join(scratch, "override.json")]; + progress("validate and build"); + await compose(["config", "--quiet"]); + await build(); + progress("bootstrap and seed synthetic catalog"); + await compose(["run", "--rm", "-T", "--no-deps", "hub", "bun", "run", "docker/bootstrap-token.ts"], `${token}\n`); + await compose(["run", "--rm", "-T", "--no-deps", "hub", "bun", "-e", + "import { writeFileSync } from 'node:fs'; writeFileSync('/home/bun/.codex/opencodex-catalog.json', await Bun.stdin.text(), { mode: 0o600, flag: 'wx' });"], fixture); + progress("start and check admission"); + await compose(["up", "--no-build", "--wait", "--wait-timeout", "120", "hub"], undefined, 150_000); + const first = await inspect(); + await acceptance(first.url); + const before = await state(); + progress("refuse token replacement"); + const refused = await run(["docker", ...composeArgs, "run", "--rm", "-T", "--no-deps", "hub", + "bun", "run", "docker/bootstrap-token.ts"], `${replacement}\n`); + check(refused.code === 1, "bootstrap did not refuse replacement"); + check(await state() === before, "state changed after refused bootstrap"); + await acceptance(first.url); + progress("replace container and verify persistence"); + await compose(["up", "--no-build", "--force-recreate", "--wait", "--wait-timeout", "120", "hub"], undefined, 150_000); + const second = await inspect(); + check(second.id !== first.id && JSON.stringify(second.volumes) === JSON.stringify(first.volumes), "replacement/volume identity failed"); + check(await state() === before, "persistent state changed"); + await acceptance(second.url); +} + +const abort = () => cancelled.abort(); +process.once("SIGINT", abort); +process.once("SIGTERM", abort); +const deadline = setTimeout(abort, 16 * 60_000); +try { + await main(); +} catch (error) { + const reason = error instanceof SmokeFailure ? error.message : "unexpected failure; details suppressed"; + console.error(`docker-smoke: failed at ${stage}: ${reason}`); + process.exitCode = 1; +} finally { + clearTimeout(deadline); + try { await cleanup(); } catch { + console.error("docker-smoke: cleanup incomplete"); + process.exitCode = 1; + } + process.removeListener("SIGINT", abort); + process.removeListener("SIGTERM", abort); +} +if (!process.exitCode) console.log("docker-smoke: build/start/recreate acceptance passed; cleanup complete"); From 92c95fafa0eb5605ae8414274af493a51e55ee06 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 07:40:59 +0900 Subject: [PATCH 016/412] feat(gui): carry discovered model name editor with recoverable saves Carry the net diff from PR #2716 at 93ed44053b68a9707f8271981d5f7e4bc25e9b70. Reconcile confirmed saved/reset receipts, including saved:true errors, with the editor draft, current label and reset availability. Preserve reset intent on retry and retry only the list read after a successful mutation and failed read. Reuse createBoundedFetch for a single 60-second write-and-refresh budget. Timeouts retain the draft, release the modal lock and leave persistence unknown; retry reads current state before another mutation. Keep global fetch unchanged. Add focused regression coverage, nine-locale recovery copy and workflow docs. Local tests, typecheck, build and browser smoke NOT RUN by owner mandate. Static diff inspection only; parent owns remote CI and browser verification. Co-authored-by: Zig Zag --- .../docs/reference/configuration/providers.md | 14 + gui/src/components/ModelDisplayNameDialog.tsx | 172 +++++ gui/src/i18n/de.ts | 23 + gui/src/i18n/en.ts | 23 + gui/src/i18n/fr.ts | 23 + gui/src/i18n/ja.ts | 23 + gui/src/i18n/ko.ts | 23 + gui/src/i18n/ru.ts | 23 + gui/src/i18n/tr.ts | 23 + gui/src/i18n/zh-TW.ts | 23 + gui/src/i18n/zh.ts | 23 + gui/src/pages/Models.tsx | 161 ++++- gui/src/pages/models-shared.ts | 24 +- gui/src/styles.css | 46 ++ gui/tests/models-display-name-editor.test.tsx | 657 ++++++++++++++++++ 15 files changed, 1276 insertions(+), 5 deletions(-) create mode 100644 gui/src/components/ModelDisplayNameDialog.tsx create mode 100644 gui/tests/models-display-name-editor.test.tsx diff --git a/docs-site/src/content/docs/reference/configuration/providers.md b/docs-site/src/content/docs/reference/configuration/providers.md index 9bd558be44..78d97cd79c 100644 --- a/docs-site/src/content/docs/reference/configuration/providers.md +++ b/docs-site/src/content/docs/reference/configuration/providers.md @@ -249,6 +249,20 @@ label. A management client can set or reset one label with `{ "modelId": "grok-4.6", "displayName": "Grok 4.6" }`; send `displayName: null` to reset it. Provider `PATCH` does not edit this map. Use this dedicated `PUT` endpoint to change or remove labels. +The dashboard exposes the same durable setting on **Models**. Expand the provider, find a +discovered model, and choose **Name**. The dialog keeps the exact `provider/model` selector visible +while you save a friendly label. Choose **Reset name** to return to provider metadata or the normal +selector fallback. **Name** changes presentation only; the separate alias pencil changes the +short routing alias and is not a display name editor. Native OpenAI and custom model rows keep their +existing controls. + +If the change is saved but refreshing fails, the dialog reflects the saved override and keeps +**Retry** available. Retry repeats catalog convergence when the server reported it failed, or +reloads the list when only the list request failed. Reset recovery keeps the reset operation; +it does not restore the old name. Requests have a 60-second deadline covering the write and its +follow-up list refresh. A timeout does not undo a write: use **Retry** to check the current name +before making another change. + ## Codex catalog and root `config.toml` settings These settings belong in the root of `$CODEX_HOME/config.toml`, alongside diff --git a/gui/src/components/ModelDisplayNameDialog.tsx b/gui/src/components/ModelDisplayNameDialog.tsx new file mode 100644 index 0000000000..c24b6612d7 --- /dev/null +++ b/gui/src/components/ModelDisplayNameDialog.tsx @@ -0,0 +1,172 @@ +import { useEffect, useId, useRef, useState } from "react"; +import { useT, type TKey } from "../i18n/shared"; +import { + modelDisplayNameValidationKey, + type ModelRow, +} from "../pages/models-shared"; + +interface ModelDisplayNameDialogProps { + model: ModelRow; + saving: boolean; + requestError: string | null; + currentNamePending?: boolean; + onRetry?: () => void; + onEdit?: () => void; + onSave: (displayName: string) => void; + onReset: () => void; + onClose: () => void; +} + +const SOURCE_LABEL_KEYS: Record, TKey> = { + operator: "models.displayNameSourceOperator", + provider: "models.displayNameSourceProvider", + fallback: "models.displayNameSourceFallback", +}; + +export default function ModelDisplayNameDialog({ + model, + saving, + requestError, + currentNamePending = false, + onRetry, + onEdit, + onSave, + onReset, + onClose, +}: ModelDisplayNameDialogProps) { + const t = useT(); + const dialogRef = useRef(null); + const inputRef = useRef(null); + const wasSavingRef = useRef(saving); + const titleId = useId(); + const helpId = useId(); + const errorId = useId(); + const [draft, setDraft] = useState(model.displayNameOverride ?? ""); + const [validationKey, setValidationKey] = useState(null); + + useEffect(() => { + const dialog = dialogRef.current; + if (dialog && !dialog.open) dialog.showModal(); + inputRef.current?.focus(); + return () => { if (dialog?.open) dialog.close(); }; + }, []); + + useEffect(() => { + const saveFailed = wasSavingRef.current && !saving && Boolean(requestError); + wasSavingRef.current = saving; + if (saveFailed) inputRef.current?.focus(); + }, [requestError, saving]); + + // Parent replaces this snapshot only after a confirmed mutation, not catalog polling. + useEffect(() => { + setDraft(model.displayNameOverride ?? ""); + setValidationKey(null); + }, [model]); + + const validationError = validationKey ? t(validationKey) : null; + const visibleError = validationError ?? requestError; + const sourceKey = model.displayNameSource + ? SOURCE_LABEL_KEYS[model.displayNameSource] + : "models.displayNameSourceFallback"; + + const requestClose = () => { + if (!saving) onClose(); + }; + + return ( + { + event.preventDefault(); + requestClose(); + }} + > + + + +
+ {t("models.displayNameModelId")} + {model.namespaced} +
+ +
+ {t("models.displayNameCurrent")} + {currentNamePending ? t("models.displayNameCurrentUnavailable") : model.displayName ?? model.namespaced} + {!currentNamePending && {t(sourceKey)}} +
+ + + { + onEdit?.(); + setDraft(event.target.value); + setValidationKey(null); + }} + /> +

+ {t("models.displayNameHelp", { model: model.namespaced })} +

+ {visibleError && ( + + )} + +
+ + + +
+ +
+ ); +} diff --git a/gui/src/i18n/de.ts b/gui/src/i18n/de.ts index 9086c9bf42..817034bed6 100644 --- a/gui/src/i18n/de.ts +++ b/gui/src/i18n/de.ts @@ -2548,4 +2548,27 @@ export const de: Record = { "integrations.cursor.colReasoning": "Reasoning-Aufwand", "integrations.cursor.colContext": "Kontext", "integrations.cursor.guide": "Anleitung zu Cursor Private Inference öffnen", + "models.displayNameSavedRefreshFailed": "Die Änderung wurde gespeichert, aber die Modellliste konnte nicht aktualisiert werden. Versuchen Sie es erneut.", + "models.displayNameOutcomeUnknown": "Die Anfrage wurde nicht abgeschlossen. Die Änderung wurde möglicherweise gespeichert. Prüfen Sie den aktuellen Namen durch erneutes Versuchen, bevor Sie ihn weiter ändern.", + "models.displayNameCurrentUnavailable": "Aktueller Name erst nach Aktualisierung verfügbar", + "models.displayNameReloaded": "Modellliste aktualisiert", + "models.displayNameAction": "Name", + "models.displayNameActionLabel": "Anzeigenamen für {model} bearbeiten", + "models.displayNameTitle": "Anzeigename", + "models.displayNameModelId": "Modell-ID", + "models.displayNameCurrent": "Aktueller Name", + "models.displayNameSourceOperator": "Ihr Name", + "models.displayNameSourceProvider": "Anbietername", + "models.displayNameSourceFallback": "Modell-ID als Ersatz", + "models.displayNameField": "Anzeigename", + "models.displayNamePlaceholder": "z. B. Grok 4.6", + "models.displayNameHelp": "Ändert nur die Anzeige. Das Routing bleibt {model}.", + "models.displayNameReset": "Name zurücksetzen", + "models.displayNameSaved": "Anzeigename gespeichert", + "models.displayNameResetDone": "Anzeigename zurückgesetzt", + "models.displayNameSaveFailed": "Anzeigename konnte nicht gespeichert werden", + "models.displayNameRequired": "Geben Sie einen Anzeigenamen ein oder verwenden Sie Name zurücksetzen.", + "models.displayNameTooLong": "Der Anzeigename darf höchstens 128 Zeichen lang sein.", + "models.displayNameNoSlash": "Der Anzeigename darf kein / enthalten.", + "models.displayNameNoControl": "Der Anzeigename darf keine Steuerzeichen enthalten.", }; diff --git a/gui/src/i18n/en.ts b/gui/src/i18n/en.ts index 0d2f1d05d4..a5ba86e2dd 100644 --- a/gui/src/i18n/en.ts +++ b/gui/src/i18n/en.ts @@ -2582,6 +2582,29 @@ export const en = { "usage.scope.machine": "This machine", "usage.scope.hub": "Hub-wide", "usage.hubOffline": "Hub usage is unavailable. Local usage was not substituted.", + "models.displayNameSavedRefreshFailed": "The change was saved, but the model list could not be refreshed. Retry to refresh it.", + "models.displayNameOutcomeUnknown": "The request did not finish. The change may have been saved. Retry to check the current name before making another change.", + "models.displayNameCurrentUnavailable": "Current name unavailable until refresh", + "models.displayNameReloaded": "Model list refreshed", + "models.displayNameAction": "Name", + "models.displayNameActionLabel": "Edit friendly name for {model}", + "models.displayNameTitle": "Friendly name", + "models.displayNameModelId": "Model ID", + "models.displayNameCurrent": "Current name", + "models.displayNameSourceOperator": "Your name", + "models.displayNameSourceProvider": "Provider name", + "models.displayNameSourceFallback": "Model ID fallback", + "models.displayNameField": "Friendly name", + "models.displayNamePlaceholder": "e.g. Grok 4.6", + "models.displayNameHelp": "Changes presentation only. Routing remains {model}.", + "models.displayNameReset": "Reset name", + "models.displayNameSaved": "Display name saved", + "models.displayNameResetDone": "Display name reset", + "models.displayNameSaveFailed": "Failed to save display name", + "models.displayNameRequired": "Enter a friendly name, or use Reset name.", + "models.displayNameTooLong": "Friendly name must be 128 characters or fewer.", + "models.displayNameNoSlash": "Friendly name cannot contain /.", + "models.displayNameNoControl": "Friendly name cannot contain control characters.", } as const; export type TKey = keyof typeof en; diff --git a/gui/src/i18n/fr.ts b/gui/src/i18n/fr.ts index b6eb03f0b0..fecc7ca243 100644 --- a/gui/src/i18n/fr.ts +++ b/gui/src/i18n/fr.ts @@ -2535,4 +2535,27 @@ export const fr: Record = { "integrations.cursor.colReasoning": "Raisonnement", "integrations.cursor.colContext": "Contexte", "integrations.cursor.guide": "Ouvrir le guide de Cursor Private Inference", + "models.displayNameSavedRefreshFailed": "La modification a été enregistrée, mais la liste des modèles n’a pas pu être actualisée. Réessayez.", + "models.displayNameOutcomeUnknown": "La requête n’a pas abouti. La modification a peut-être été enregistrée. Réessayez pour vérifier le nom actuel avant toute autre modification.", + "models.displayNameCurrentUnavailable": "Nom actuel indisponible avant actualisation", + "models.displayNameReloaded": "Liste des modèles actualisée", + "models.displayNameAction": "Nom", + "models.displayNameActionLabel": "Modifier le nom d’affichage de {model}", + "models.displayNameTitle": "Nom d’affichage", + "models.displayNameModelId": "ID du modèle", + "models.displayNameCurrent": "Nom actuel", + "models.displayNameSourceOperator": "Votre nom d’affichage", + "models.displayNameSourceProvider": "Nom du fournisseur", + "models.displayNameSourceFallback": "ID du modèle par défaut", + "models.displayNameField": "Nom d’affichage", + "models.displayNamePlaceholder": "p. ex. Grok 4.6", + "models.displayNameHelp": "Modifie uniquement l’affichage. Le routage reste {model}.", + "models.displayNameReset": "Réinitialiser le nom", + "models.displayNameSaved": "Nom d’affichage enregistré", + "models.displayNameResetDone": "Nom d’affichage réinitialisé", + "models.displayNameSaveFailed": "Impossible d’enregistrer le nom d’affichage", + "models.displayNameRequired": "Saisissez un nom d’affichage ou utilisez Réinitialiser le nom.", + "models.displayNameTooLong": "Le nom d’affichage doit contenir au maximum 128 caractères.", + "models.displayNameNoSlash": "Le nom d’affichage ne peut pas contenir /.", + "models.displayNameNoControl": "Le nom d’affichage ne peut pas contenir de caractères de contrôle.", }; diff --git a/gui/src/i18n/ja.ts b/gui/src/i18n/ja.ts index 4b16912324..cf2a3df5a8 100644 --- a/gui/src/i18n/ja.ts +++ b/gui/src/i18n/ja.ts @@ -2569,4 +2569,27 @@ export const ja: Record = { "integrations.cursor.colReasoning": "推論", "integrations.cursor.colContext": "コンテキスト", "integrations.cursor.guide": "Cursor Private Inference のガイドを開く", + "models.displayNameSavedRefreshFailed": "変更は保存されましたが、モデル一覧を更新できませんでした。再試行してください。", + "models.displayNameOutcomeUnknown": "リクエストが完了しませんでした。変更が保存されている可能性があります。再度変更する前に再試行して現在の名前を確認してください。", + "models.displayNameCurrentUnavailable": "更新するまで現在の名前を確認できません", + "models.displayNameReloaded": "モデル一覧を更新しました", + "models.displayNameAction": "名前", + "models.displayNameActionLabel": "{model} の表示名を編集", + "models.displayNameTitle": "表示名", + "models.displayNameModelId": "モデル ID", + "models.displayNameCurrent": "現在の名前", + "models.displayNameSourceOperator": "設定した名前", + "models.displayNameSourceProvider": "プロバイダー名", + "models.displayNameSourceFallback": "モデル ID の既定値", + "models.displayNameField": "表示名", + "models.displayNamePlaceholder": "例: Grok 4.6", + "models.displayNameHelp": "表示だけを変更します。ルーティングは {model} のままです。", + "models.displayNameReset": "名前をリセット", + "models.displayNameSaved": "表示名を保存しました", + "models.displayNameResetDone": "表示名をリセットしました", + "models.displayNameSaveFailed": "表示名を保存できませんでした", + "models.displayNameRequired": "表示名を入力するか、名前をリセットしてください。", + "models.displayNameTooLong": "表示名は 128 文字以内にしてください。", + "models.displayNameNoSlash": "表示名に / は使用できません。", + "models.displayNameNoControl": "表示名に制御文字は使用できません。", }; diff --git a/gui/src/i18n/ko.ts b/gui/src/i18n/ko.ts index a87bf608e5..3c1d0b1497 100644 --- a/gui/src/i18n/ko.ts +++ b/gui/src/i18n/ko.ts @@ -2570,4 +2570,27 @@ export const ko: Record = { "integrations.cursor.colReasoning": "추론", "integrations.cursor.colContext": "컨텍스트", "integrations.cursor.guide": "Cursor Private Inference 가이드 열기", + "models.displayNameSavedRefreshFailed": "변경 사항은 저장되었지만 모델 목록을 새로 고치지 못했습니다. 다시 시도해 주세요.", + "models.displayNameOutcomeUnknown": "요청이 완료되지 않았습니다. 변경 사항이 저장되었을 수 있습니다. 다시 변경하기 전에 재시도하여 현재 이름을 확인하세요.", + "models.displayNameCurrentUnavailable": "새로 고침 전까지 현재 이름을 확인할 수 없음", + "models.displayNameReloaded": "모델 목록을 새로 고쳤습니다", + "models.displayNameAction": "이름", + "models.displayNameActionLabel": "{model}의 표시 이름 편집", + "models.displayNameTitle": "표시 이름", + "models.displayNameModelId": "모델 ID", + "models.displayNameCurrent": "현재 이름", + "models.displayNameSourceOperator": "운영자 지정 이름", + "models.displayNameSourceProvider": "프로바이더 제공 이름", + "models.displayNameSourceFallback": "모델 ID 기본값", + "models.displayNameField": "표시 이름", + "models.displayNamePlaceholder": "예: Grok 4.6", + "models.displayNameHelp": "표시 방식만 변경합니다. 라우팅은 {model}로 유지됩니다.", + "models.displayNameReset": "이름 초기화", + "models.displayNameSaved": "표시 이름이 저장되었습니다", + "models.displayNameResetDone": "표시 이름이 초기화되었습니다", + "models.displayNameSaveFailed": "표시 이름을 저장하지 못했습니다", + "models.displayNameRequired": "표시 이름을 입력하거나 이름 초기화를 사용하세요.", + "models.displayNameTooLong": "표시 이름은 128자 이하여야 합니다.", + "models.displayNameNoSlash": "표시 이름에 /를 사용할 수 없습니다.", + "models.displayNameNoControl": "표시 이름에 제어 문자를 사용할 수 없습니다.", }; diff --git a/gui/src/i18n/ru.ts b/gui/src/i18n/ru.ts index 70eb364002..b7f02bdf50 100644 --- a/gui/src/i18n/ru.ts +++ b/gui/src/i18n/ru.ts @@ -2571,4 +2571,27 @@ export const ru: Record = { "integrations.cursor.colReasoning": "Рассуждения", "integrations.cursor.colContext": "Контекст", "integrations.cursor.guide": "Открыть руководство по Cursor Private Inference", + "models.displayNameSavedRefreshFailed": "Изменение сохранено, но список моделей не удалось обновить. Повторите попытку.", + "models.displayNameOutcomeUnknown": "Запрос не завершён. Изменение могло сохраниться. Повторите попытку, чтобы проверить текущее имя перед следующим изменением.", + "models.displayNameCurrentUnavailable": "Текущее имя недоступно до обновления", + "models.displayNameReloaded": "Список моделей обновлён", + "models.displayNameAction": "Имя", + "models.displayNameActionLabel": "Изменить понятное имя для {model}", + "models.displayNameTitle": "Понятное имя", + "models.displayNameModelId": "ID модели", + "models.displayNameCurrent": "Текущее имя", + "models.displayNameSourceOperator": "Ваше имя", + "models.displayNameSourceProvider": "Имя провайдера", + "models.displayNameSourceFallback": "ID модели по умолчанию", + "models.displayNameField": "Понятное имя", + "models.displayNamePlaceholder": "например, Grok 4.6", + "models.displayNameHelp": "Меняет только отображение. Маршрут остаётся {model}.", + "models.displayNameReset": "Сбросить имя", + "models.displayNameSaved": "Понятное имя сохранено", + "models.displayNameResetDone": "Понятное имя сброшено", + "models.displayNameSaveFailed": "Не удалось сохранить понятное имя", + "models.displayNameRequired": "Введите понятное имя или используйте Сбросить имя.", + "models.displayNameTooLong": "Понятное имя должно содержать не более 128 символов.", + "models.displayNameNoSlash": "Понятное имя не может содержать /.", + "models.displayNameNoControl": "Понятное имя не может содержать управляющие символы.", }; diff --git a/gui/src/i18n/tr.ts b/gui/src/i18n/tr.ts index ca233f452e..b18d1cb360 100644 --- a/gui/src/i18n/tr.ts +++ b/gui/src/i18n/tr.ts @@ -2571,4 +2571,27 @@ export const tr: Record = { "integrations.cursor.colReasoning": "Akıl yürütme", "integrations.cursor.colContext": "Bağlam", "integrations.cursor.guide": "Cursor Private Inference kılavuzunu aç", + "models.displayNameSavedRefreshFailed": "Değişiklik kaydedildi ancak model listesi yenilenemedi. Yenilemek için tekrar deneyin.", + "models.displayNameOutcomeUnknown": "İstek tamamlanmadı. Değişiklik kaydedilmiş olabilir. Başka bir değişiklik yapmadan önce geçerli adı kontrol etmek için tekrar deneyin.", + "models.displayNameCurrentUnavailable": "Geçerli ad yenilemeye kadar kullanılamıyor", + "models.displayNameReloaded": "Model listesi yenilendi", + "models.displayNameAction": "Ad", + "models.displayNameActionLabel": "{model} için görünen adı düzenle", + "models.displayNameTitle": "Görünen ad", + "models.displayNameModelId": "Model kimliği", + "models.displayNameCurrent": "Geçerli ad", + "models.displayNameSourceOperator": "Sizin adınız", + "models.displayNameSourceProvider": "Sağlayıcı adı", + "models.displayNameSourceFallback": "Model kimliği varsayılanı", + "models.displayNameField": "Görünen ad", + "models.displayNamePlaceholder": "örn. Grok 4.6", + "models.displayNameHelp": "Yalnızca görünümü değiştirir. Yönlendirme {model} olarak kalır.", + "models.displayNameReset": "Adı sıfırla", + "models.displayNameSaved": "Görünen ad kaydedildi", + "models.displayNameResetDone": "Görünen ad sıfırlandı", + "models.displayNameSaveFailed": "Görünen ad kaydedilemedi", + "models.displayNameRequired": "Bir görünen ad girin veya Adı sıfırla seçeneğini kullanın.", + "models.displayNameTooLong": "Görünen ad en fazla 128 karakter olabilir.", + "models.displayNameNoSlash": "Görünen ad / içeremez.", + "models.displayNameNoControl": "Görünen ad denetim karakterleri içeremez.", }; diff --git a/gui/src/i18n/zh-TW.ts b/gui/src/i18n/zh-TW.ts index 2b7e6ac6ba..463c2c88e5 100644 --- a/gui/src/i18n/zh-TW.ts +++ b/gui/src/i18n/zh-TW.ts @@ -2533,4 +2533,27 @@ export const zhTW: Record = { "integrations.cursor.colReasoning": "推理", "integrations.cursor.colContext": "上下文", "integrations.cursor.guide": "開啟 Cursor Private Inference 指南", + "models.displayNameSavedRefreshFailed": "變更已儲存,但無法重新整理模型清單。請重試。", + "models.displayNameOutcomeUnknown": "請求未完成。變更可能已儲存。再次變更之前,請重試以檢查目前名稱。", + "models.displayNameCurrentUnavailable": "重新整理之前無法取得目前名稱", + "models.displayNameReloaded": "模型清單已重新整理", + "models.displayNameAction": "名稱", + "models.displayNameActionLabel": "編輯 {model} 的友善名稱", + "models.displayNameTitle": "友善名稱", + "models.displayNameModelId": "模型 ID", + "models.displayNameCurrent": "目前名稱", + "models.displayNameSourceOperator": "你的名稱", + "models.displayNameSourceProvider": "供應商名稱", + "models.displayNameSourceFallback": "模型 ID 預設值", + "models.displayNameField": "友善名稱", + "models.displayNamePlaceholder": "例如 Grok 4.6", + "models.displayNameHelp": "只變更顯示方式。路由仍為 {model}。", + "models.displayNameReset": "重設名稱", + "models.displayNameSaved": "友善名稱已儲存", + "models.displayNameResetDone": "友善名稱已重設", + "models.displayNameSaveFailed": "無法儲存友善名稱", + "models.displayNameRequired": "請輸入友善名稱,或使用重設名稱。", + "models.displayNameTooLong": "友善名稱不能超過 128 個字元。", + "models.displayNameNoSlash": "友善名稱不能包含 /。", + "models.displayNameNoControl": "友善名稱不能包含控制字元。", }; diff --git a/gui/src/i18n/zh.ts b/gui/src/i18n/zh.ts index 42ac3941d4..1c6694fc8b 100644 --- a/gui/src/i18n/zh.ts +++ b/gui/src/i18n/zh.ts @@ -2569,4 +2569,27 @@ export const zh: Record = { "integrations.cursor.colReasoning": "推理", "integrations.cursor.colContext": "上下文", "integrations.cursor.guide": "打开 Cursor Private Inference 指南", + "models.displayNameSavedRefreshFailed": "更改已保存,但无法刷新模型列表。请重试以刷新。", + "models.displayNameOutcomeUnknown": "请求未完成。更改可能已保存。再次更改之前,请重试以检查当前名称。", + "models.displayNameCurrentUnavailable": "刷新之前无法获取当前名称", + "models.displayNameReloaded": "模型列表已刷新", + "models.displayNameAction": "名称", + "models.displayNameActionLabel": "编辑 {model} 的友好名称", + "models.displayNameTitle": "友好名称", + "models.displayNameModelId": "模型 ID", + "models.displayNameCurrent": "当前名称", + "models.displayNameSourceOperator": "你的名称", + "models.displayNameSourceProvider": "提供商名称", + "models.displayNameSourceFallback": "模型 ID 默认值", + "models.displayNameField": "友好名称", + "models.displayNamePlaceholder": "例如 Grok 4.6", + "models.displayNameHelp": "仅更改显示方式。路由仍为 {model}。", + "models.displayNameReset": "重置名称", + "models.displayNameSaved": "友好名称已保存", + "models.displayNameResetDone": "友好名称已重置", + "models.displayNameSaveFailed": "无法保存友好名称", + "models.displayNameRequired": "请输入友好名称,或使用重置名称。", + "models.displayNameTooLong": "友好名称不能超过 128 个字符。", + "models.displayNameNoSlash": "友好名称不能包含 /。", + "models.displayNameNoControl": "友好名称不能包含控制字符。", }; diff --git a/gui/src/pages/Models.tsx b/gui/src/pages/Models.tsx index 22ea51bc20..b7b3a0e285 100644 --- a/gui/src/pages/Models.tsx +++ b/gui/src/pages/Models.tsx @@ -1,4 +1,5 @@ import { CodexStaleBanner } from "../components/codex-stale-banner"; +import ModelDisplayNameDialog from "../components/ModelDisplayNameDialog"; import { fetchCodexAppServerState } from "../codex-app-server-state"; import type { AppServerStateOutcome } from "../codex-app-server-state"; import { useCodexRestart } from "../use-codex-restart"; @@ -8,7 +9,7 @@ import { IconChevron, IconBoxes, IconInfo, IconCheck, IconAlert, IconRefresh, Ic import { useT } from "../i18n/shared"; import type { TFn, TKey } from "../i18n/shared"; import { modelLabel } from "../model-display"; -import { formatNamespacedModelId, formatProviderDisplayName, providerDisplaySlug } from "../provider-icons"; +import { formatProviderDisplayName, providerDisplaySlug } from "../provider-icons"; import { readJsonIfOk, readJsonOrThrow } from "../fetch-json"; import { describeIntegrationRefusalParts } from "./integrations/refusal-copy"; import { readSessionListCache, writeSessionListCache } from "../session-list-cache"; @@ -328,6 +329,22 @@ export default function Models({ apiBase, restartEpoch = 0 }: { apiBase: string; const [showThreadsCustom, setShowThreadsCustom] = useState(false); const [v2HelpOpen, setV2HelpOpen] = useState(false); const [customModalOpen, setCustomModalOpen] = useState(false); + const [displayNameModel, setDisplayNameModel] = useState(null); + const [displayNameSaving, setDisplayNameSaving] = useState(false); + const [displayNameRequestError, setDisplayNameRequestError] = useState(null); + const [displayNameRecovery, setDisplayNameRecovery] = useState<{ + value: string | null | undefined; + confirmed: boolean; + } | null>(null); + const [displayNameCurrentPending, setDisplayNameCurrentPending] = useState(false); + const displayNameRequestRef = useRef(null); + const displayNameSavingRef = useRef(false); + useEffect(() => () => { + displayNameRequestRef.current?.controller.abort(); + displayNameRequestRef.current?.clear(); + displayNameRequestRef.current = null; + }, []); + const displayNameTriggerRef = useRef(null); const reloadAliases = useCallback(async (signal?: AbortSignal) => { const response = await fetch(`${apiBase}/api/aliases`, { signal }); @@ -535,12 +552,12 @@ export default function Models({ apiBase, restartEpoch = 0 }: { apiBase: string; ); const catalogState = catalogResource.state; - const load = useCallback(async (force = false): Promise => { + const load = useCallback(async (force = false, signal?: AbortSignal): Promise => { if (loadPendingRef.current && !force) return false; loadPendingRef.current = true; const generation = ++loadGenerationRef.current; try { - const next = await fetchCatalog(new AbortController().signal); + const next = await fetchCatalog(signal ?? new AbortController().signal); if (!shouldApplyLoadGeneration(generation, loadGenerationRef.current)) return false; applyCatalog(next); // Follow-up mutation refreshes retain their existing awaitable contract while publishing @@ -557,6 +574,106 @@ export default function Models({ apiBase, restartEpoch = 0 }: { apiBase: string; } }, [applyCatalog, cacheKey, fetchCatalog, pickerResource.refresh]); + const finishDisplayNameEdit = useCallback(() => { + const trigger = displayNameTriggerRef.current; + setDisplayNameModel(null); + setDisplayNameRequestError(null); + setDisplayNameRecovery(null); + setDisplayNameCurrentPending(false); + window.setTimeout(() => { + if (trigger?.isConnected) trigger.focus(); + }, 0); + }, []); + + const closeDisplayNameEdit = useCallback(() => { + if (!displayNameSavingRef.current) finishDisplayNameEdit(); + }, [finishDisplayNameEdit]); + + // undefined retries only the read after a confirmed write or an unknown outcome. + const saveDisplayName = useCallback(async (displayName: string | null | undefined) => { + const model = displayNameModel; + if (!model || displayNameSavingRef.current) return; + const bounded = createBoundedFetch(60_000); + displayNameRequestRef.current = bounded; + displayNameSavingRef.current = true; + setDisplayNameSaving(true); + setDisplayNameRequestError(null); + let confirmed = displayName === undefined && displayNameRecovery?.confirmed === true; + let refreshOnly = displayName === undefined; + try { + if (displayName !== undefined) { + const response = await fetch( + `${apiBase}/api/providers/${encodeURIComponent(model.provider)}/model-display-names`, + { + method: "PUT", + headers: { "content-type": "application/json" }, + body: JSON.stringify({ modelId: model.id, displayName }), + signal: bounded.signal, + }, + ); + // The route can persist the value and return 503 when catalog convergence fails. + // Keep that receipt instead of throwing away saved:true with the error body. + type DisplayNameReceipt = { + saved?: boolean; + error?: string; + displayName?: string; + displayNameOverride?: string | null; + displayNameSource?: ModelRow["displayNameSource"]; + }; + const result: DisplayNameReceipt | undefined = response.ok + ? await readJsonOrThrow(response, t("models.displayNameSaveFailed")) + : await response.json(); + bounded.signal.throwIfAborted(); + if (!result) throw new Error(t("models.displayNameSaveFailed")); + confirmed = response.ok || result.saved === true; + if (confirmed) { + const override = result.displayNameOverride === null ? undefined + : result.displayNameOverride ?? displayName ?? undefined; + const fields: Pick = { + displayName: result.displayName ?? override, + displayNameOverride: override, + displayNameSource: result.displayNameSource ?? (override ? "operator" : undefined), + }; + setModels(current => current.map(row => row.namespaced === model.namespaced ? { ...row, ...fields } : row)); + setDisplayNameModel({ ...model, ...fields }); + // A saved:true reset receipt omits the provider's effective fallback label. + setDisplayNameCurrentPending(fields.displayName === undefined); + } + if (!response.ok) { + throw new Error(result.error || t("models.displayNameSaveFailed")); + } + refreshOnly = true; + } + if (!await load(true, bounded.signal)) throw new Error(t("models.loadFail")); + bounded.signal.throwIfAborted(); + publishFeedback(true, confirmed + ? t(displayName === null || (displayName === undefined && displayNameRecovery?.value === null) + ? "models.displayNameResetDone" : "models.displayNameSaved") + : t("models.displayNameReloaded")); + finishDisplayNameEdit(); + } catch (error) { + if (displayNameRequestRef.current !== bounded) return; + if (bounded.signal.aborted && !confirmed) setDisplayNameCurrentPending(true); + setDisplayNameRecovery(confirmed || bounded.signal.aborted || refreshOnly + ? { value: refreshOnly || bounded.signal.aborted ? undefined : displayName, confirmed } + : null); + setDisplayNameRequestError(confirmed + ? t("models.displayNameSavedRefreshFailed") + : bounded.signal.aborted || refreshOnly + ? t("models.displayNameOutcomeUnknown") + : error instanceof Error && error.message + ? error.message + : t("models.displayNameSaveFailed")); + } finally { + bounded.clear(); + if (displayNameRequestRef.current === bounded) { + displayNameRequestRef.current = null; + displayNameSavingRef.current = false; + setDisplayNameSaving(false); + } + } + }, [apiBase, displayNameModel, displayNameRecovery, finishDisplayNameEdit, load, t]); + // Shadow/v2 controls must not wait on the models catalog (live discovery can be slow). useEffect(() => { // Both belong to the catalog tab; a hidden panel polling /api/v2 every ten seconds @@ -1537,9 +1654,31 @@ export default function Models({ apiBase, restartEpoch = 0 }: { apiBase: string; void applyVisibility("models", provider, [{ id: m.id, native: m.native === true }], off)} disabled={busy || m.initialSelectionPending} label={m.native ? m.id : m.namespaced} /> {m.initialSelectionPending && {t("models.initialSelectionPending")}} {aliases.models[provider]?.[m.id] && {aliases.models[provider][m.id].alias}} - {m.native ? modelLabel(m.id) : formatNamespacedModelId(m.namespaced, t)} + + {m.native ? modelLabel(m.id) : m.namespaced} + {!m.native && m.displayName?.trim() && m.displayName.trim() !== m.namespaced && ( + {m.displayName.trim()} + )} + {aliases.models[provider]?.[m.id]?.source === "builtin" && {t("models.aliasAuto")}} + {!m.native && !m.custom && ( + + )} {m.custom && ( {t("models.customBadge")} @@ -2485,6 +2624,20 @@ export default function Models({ apiBase, restartEpoch = 0 }: { apiBase: string; )} + + {displayNameModel && ( + void saveDisplayName(displayNameRecovery.value) : undefined} + onEdit={() => setDisplayNameRecovery(null)} + onSave={value => void saveDisplayName(value)} + onReset={() => void saveDisplayName(null)} + onClose={closeDisplayNameEdit} + /> + )} ); diff --git a/gui/src/pages/models-shared.ts b/gui/src/pages/models-shared.ts index fdc487301c..1f5ef7786b 100644 --- a/gui/src/pages/models-shared.ts +++ b/gui/src/pages/models-shared.ts @@ -1,4 +1,4 @@ -import type { TFn } from "../i18n/shared"; +import type { TFn, TKey } from "../i18n/shared"; import type { ProviderDiscoverySummary } from "../models-groups"; import { modelVisible, type ProviderModelMap } from "../model-visibility"; import { formatNamespacedModelId } from "../provider-icons"; @@ -35,6 +35,8 @@ export interface ModelRow { custom?: boolean; customId?: string; displayName?: string; + displayNameOverride?: string; + displayNameSource?: "operator" | "provider" | "fallback"; inputModalities?: string[]; contextWindow?: number; contextCap?: number; @@ -43,6 +45,26 @@ export interface ModelRow { reasoningEfforts?: string[]; } +function containsDisplayNameControlCharacter(value: string): boolean { + return [...value].some(character => { + const codePoint = character.codePointAt(0)!; + return codePoint <= 0x1f + || (codePoint >= 0x7f && codePoint <= 0x9f) + || codePoint === 0x2028 + || codePoint === 0x2029; + }); +} + +/** Mirror the server display-name contract for immediate form feedback. */ +export function modelDisplayNameValidationKey(value: string): TKey | null { + const trimmed = value.trim(); + if (!trimmed) return "models.displayNameRequired"; + if (trimmed.length > 128) return "models.displayNameTooLong"; + if (trimmed.includes("/")) return "models.displayNameNoSlash"; + if (containsDisplayNameControlCharacter(trimmed)) return "models.displayNameNoControl"; + return null; +} + /** * Reasoning-effort labels offered in the custom-model dialog. The full set of real * `reasoning_effort` values (none, minimal, low, medium, high, xhigh, max). Deliberately diff --git a/gui/src/styles.css b/gui/src/styles.css index b0bbc0a6ff..630882006f 100644 --- a/gui/src/styles.css +++ b/gui/src/styles.css @@ -2639,6 +2639,52 @@ button.prov-account-row.active { cursor: default; } /* ---- model row hover tooltip ---- */ .model-row-wrap { position: relative; } +.models-model-identity { + display: inline-flex; + min-width: 0; + flex-direction: column; + align-items: flex-start; + gap: 1px; +} +.models-model-friendly { + max-width: min(42vw, 420px); + overflow: hidden; + color: var(--muted); + text-overflow: ellipsis; + white-space: nowrap; +} +.models-display-name-trigger { flex-shrink: 0; } +.model-display-name-dialog { max-width: 460px; } +.model-display-name-identity, +.model-display-name-current { + display: grid; + gap: 5px; + margin-bottom: 16px; +} +.model-display-name-identity code { + overflow-wrap: anywhere; + color: var(--text); +} +.model-display-name-current { + grid-template-columns: 1fr auto; + align-items: center; +} +.model-display-name-current > .text-label { grid-column: 1 / -1; } +.model-display-name-current strong { min-width: 0; overflow-wrap: anywhere; } +.model-display-name-dialog > .input { margin-bottom: 6px; } +.model-display-name-error { + margin-top: 8px; + color: var(--red); + font-size: var(--text-label); + line-height: var(--leading-body); +} +@media (max-width: 560px) { + .models-model-friendly { max-width: 58vw; } + .model-display-name-current { grid-template-columns: 1fr; } + .model-display-name-current > .text-label { grid-column: auto; } + .model-display-name-dialog .modal-actions { align-items: stretch; flex-direction: column; } + .model-display-name-dialog .modal-actions .btn { width: 100%; } +} .model-tip { z-index: 10; background: var(--surface); diff --git a/gui/tests/models-display-name-editor.test.tsx b/gui/tests/models-display-name-editor.test.tsx new file mode 100644 index 0000000000..be64333944 --- /dev/null +++ b/gui/tests/models-display-name-editor.test.tsx @@ -0,0 +1,657 @@ +import { afterEach, beforeEach, describe, expect, jest, test } from "bun:test"; +import { Window } from "happy-dom"; +import { act } from "react"; +import type { Root } from "react-dom/client"; +import ModelDisplayNameDialog from "../src/components/ModelDisplayNameDialog"; +import { clearClientResourceStoresForTests } from "../src/client-resource"; +import { LanguageProvider } from "../src/i18n/provider"; +import { installApiAuthFetch, resetApiAuthFetchForTests } from "../src/api"; +import Models from "../src/pages/Models"; +import type { ModelRow } from "../src/pages/models-shared"; +import { modelDisplayNameValidationKey } from "../src/pages/models-shared"; + +describe("discovered model display name validation", () => { + test("accepts a safe label at both ordinary and maximum length", () => { + expect(modelDisplayNameValidationKey("Grok 4.6")).toBeNull(); + expect(modelDisplayNameValidationKey("A".repeat(128))).toBeNull(); + expect(modelDisplayNameValidationKey("모델 이름")).toBeNull(); + expect(modelDisplayNameValidationKey("🚀".repeat(64))).toBeNull(); + expect(modelDisplayNameValidationKey("🚀".repeat(65))).toBe("models.displayNameTooLong"); + }); + + test("rejects values that the management API cannot persist", () => { + expect(modelDisplayNameValidationKey(" ")).toBe("models.displayNameRequired"); + expect(modelDisplayNameValidationKey("Grok/4.6")).toBe("models.displayNameNoSlash"); + for (const control of ["\n", "\u0000", "\u007f", "\u0085", "\u2028", "\u2029"]) { + expect(modelDisplayNameValidationKey(`Grok${control}4.6`)).toBe("models.displayNameNoControl"); + } + expect(modelDisplayNameValidationKey("A".repeat(129))).toBe("models.displayNameTooLong"); + }); +}); + +describe("discovered model display name responsive styles", () => { + test("keeps the narrow action order aligned with keyboard navigation", async () => { + const styles = await Bun.file(new URL("../src/styles.css", import.meta.url)).text(); + + expect(styles).toContain( + ".model-display-name-dialog .modal-actions { align-items: stretch; flex-direction: column; }", + ); + expect(styles).not.toContain( + ".model-display-name-dialog .modal-actions { align-items: stretch; flex-direction: column-reverse; }", + ); + }); +}); + +describe("Models dashboard discovered display name integration", () => { + const globals = [ + "document", "window", "navigator", "localStorage", "sessionStorage", + "IS_REACT_ACT_ENVIRONMENT", "fetch", "setInterval", "clearInterval", + ] as const; + let previousGlobals: Record<(typeof globals)[number], PropertyDescriptor | undefined>; + let testWindow: Window; + let container: HTMLElement; + let root: Root | null; + let mutationBodies: Array<{ modelId: string; displayName: string | null }>; + let mutationFailure: string | null; + let savedFailure: boolean; + let mutationGate: Promise | null; + let modelFetches: number; + let modelFetchFailure: string | null; + let currentModels: ModelRow[]; + + const routedModel = (): ModelRow => ({ + provider: "xai-demo", + id: "grok-4.6", + namespaced: "xai-demo/grok-4.6", + disabled: false, + displayName: "Grok 4.6", + displayNameOverride: "Grok 4.6", + displayNameSource: "operator", + }); + + beforeEach(() => { + clearClientResourceStoresForTests(); + previousGlobals = Object.fromEntries( + globals.map(key => [key, Object.getOwnPropertyDescriptor(globalThis, key)]), + ) as typeof previousGlobals; + testWindow = new Window({ url: "http://localhost/#models" }); + Object.defineProperties(globalThis, { + document: { configurable: true, value: testWindow.document }, + window: { configurable: true, value: testWindow }, + navigator: { configurable: true, value: testWindow.navigator }, + localStorage: { configurable: true, value: testWindow.localStorage }, + sessionStorage: { configurable: true, value: testWindow.sessionStorage }, + IS_REACT_ACT_ENVIRONMENT: { configurable: true, value: true }, + setInterval: { configurable: true, value: () => 1 }, + clearInterval: { configurable: true, value: () => {} }, + }); + currentModels = [ + routedModel(), + { + provider: "command-code", + id: "deepseek-deepseek-v4-flash", + namespaced: "command-code/deepseek-deepseek-v4-flash", + disabled: false, + displayName: "DeepSeek V4 Flash", + displayNameSource: "provider", + }, + { provider: "openai", id: "gpt-5.5", namespaced: "openai/gpt-5.5", disabled: false, native: true }, + { + provider: "xai-demo", id: "custom-one", namespaced: "xai-demo/custom-one", + disabled: false, custom: true, customId: "custom-1", displayName: "Custom One", + }, + ]; + mutationBodies = []; + mutationFailure = null; + savedFailure = false; + resetApiAuthFetchForTests(); + mutationGate = null; + modelFetches = 0; + modelFetchFailure = null; + testWindow.localStorage.setItem("ocx-models-collapsed:v2", JSON.stringify([])); + testWindow.sessionStorage.setItem("ocx.models.catalog.v1:http://localhost", JSON.stringify({ + models: currentModels, + providers: [ + { name: "xai-demo", liveModels: false, models: ["grok-4.6", "custom-one"] }, + { name: "command-code", liveModels: false, models: ["deepseek-deepseek-v4-flash"] }, + { name: "openai", liveModels: false, models: ["gpt-5.5"] }, + ], + selectedModels: {}, + disabled: [], + contextCaps: {}, + contextCapValue: 350_000, + })); + + globalThis.fetch = (async (input, init) => { + const url = String(input); + if (url.endsWith("/api/models")) { + modelFetches += 1; + if (modelFetchFailure) { + return Response.json({ error: modelFetchFailure }, { status: 500 }); + } + return Response.json(currentModels); + } + if (url.endsWith("/api/providers")) return Response.json([ + { name: "xai-demo", liveModels: false, models: ["grok-4.6", "custom-one"] }, + { name: "command-code", liveModels: false, models: ["deepseek-deepseek-v4-flash"] }, + { name: "openai", liveModels: false, models: ["gpt-5.5"] }, + ]); + if (url.endsWith("/api/selected-models")) return Response.json({ selected: {} }); + if (url.endsWith("/api/provider-context-caps")) return Response.json({ caps: {} }); + if (url.endsWith("/api/aliases")) return Response.json({ providers: {}, models: {}, defaults: { global: false, providers: {} } }); + if (url.endsWith("/api/combos")) return Response.json({ combos: [] }); + if (url.endsWith("/api/shadow-call-settings")) return Response.json({ enabled: false, model: "" }); + if (url.endsWith("/api/v2")) return Response.json({ enabled: false, agentsMaxThreadsConflict: false, multiAgentMode: "default" }); + if (url.includes("/api/providers/xai-demo/model-display-names") && init?.method === "PUT") { + const body = JSON.parse(String(init.body)) as { modelId: string; displayName: string | null }; + mutationBodies.push(body); + if (mutationGate) await mutationGate; + if (mutationFailure && !savedFailure) return Response.json({ error: mutationFailure }, { status: 500 }); + currentModels = currentModels.map(row => row.namespaced !== "xai-demo/grok-4.6" ? row : { + ...row, + displayName: body.displayName ?? "xai-demo/grok-4.6", + displayNameOverride: body.displayName ?? undefined, + displayNameSource: body.displayName ? "operator" : "fallback", + }); + if (savedFailure) return Response.json({ + error: "model display name saved but catalog refresh failed", + saved: true, + displayNameOverride: body.displayName, + }, { status: 503 }); + const row = currentModels.find(model => model.namespaced === "xai-demo/grok-4.6")!; + return Response.json({ + ok: true, + displayName: row.displayName, + displayNameOverride: row.displayNameOverride ?? null, + displayNameSource: row.displayNameSource, + }); + } + return new Response(null, { status: 404 }); + }) as typeof fetch; + + container = testWindow.document.createElement("div"); + testWindow.document.body.appendChild(container as never); + root = null; + }); + + afterEach(async () => { + resetApiAuthFetchForTests(); + clearClientResourceStoresForTests(); + if (root) { + const mounted = root; + await act(async () => mounted.unmount()); + } + testWindow.close(); + for (const key of globals) { + const descriptor = previousGlobals[key]; + if (descriptor) Object.defineProperty(globalThis, key, descriptor); + else Reflect.deleteProperty(globalThis, key); + } + }); + + async function flush() { + await act(async () => { + await new Promise(resolve => testWindow.setTimeout(resolve, 0)); + await Promise.resolve(); + }); + } + + async function mountModels() { + const { createRoot } = await import("react-dom/client"); + await act(async () => { + root = createRoot(container); + root.render(); + }); + await flush(); + } + + function nameTrigger(): HTMLButtonElement { + return container.querySelector( + '[aria-label="Edit friendly name for xai-demo/grok-4.6"]', + )!; + } + + function dialogInput(): HTMLInputElement { + return container.querySelector("dialog")! + .querySelector("input")!; + } + + function setInputValue(input: HTMLInputElement, value: string) { + Object.getOwnPropertyDescriptor(testWindow.HTMLInputElement.prototype, "value")! + .set!.call(input, value); + input.dispatchEvent(new testWindow.Event("input", { bubbles: true })); + } + + function dialogButton(label: string): HTMLButtonElement { + return [...container.querySelectorAll("dialog button")] + .find(button => button.textContent === label)!; + } + + test("only discovered rows expose Name while showing friendly and exact identities", async () => { + await mountModels(); + + expect(nameTrigger()).not.toBeNull(); + expect(container.querySelectorAll('[aria-label^="Edit friendly name for "]')).toHaveLength(2); + expect(container.querySelector('[aria-label="Edit friendly name for openai/gpt-5.5"]')).toBeNull(); + expect(container.querySelector('[aria-label="Edit friendly name for xai-demo/custom-one"]')).toBeNull(); + expect(container.textContent).toContain("Grok 4.6"); + expect(container.textContent).toContain("xai-demo/grok-4.6"); + expect([...container.querySelectorAll("code")].some(code => + code.textContent === "command-code/deepseek-deepseek-v4-flash" + )).toBe(true); + expect(container.textContent).toContain("Custom One"); + }); + + test("save and reset send exact payloads, reload the catalog, and restore trigger focus", async () => { + await mountModels(); + const trigger = nameTrigger(); + const fetchesBeforeSave = modelFetches; + + await act(async () => trigger.click()); + await act(async () => { + setInputValue(dialogInput(), " Grok Fast "); + dialogButton("Save").click(); + }); + await flush(); + + expect(mutationBodies).toEqual([{ modelId: "grok-4.6", displayName: "Grok Fast" }]); + expect(modelFetches).toBeGreaterThan(fetchesBeforeSave); + expect(container.querySelector("dialog")).toBeNull(); + expect(container.textContent).toContain("Grok Fast"); + expect(testWindow.document.activeElement).toBe(trigger); + + await act(async () => nameTrigger().click()); + await act(async () => dialogButton("Reset name").click()); + await flush(); + + expect(mutationBodies[1]).toEqual({ modelId: "grok-4.6", displayName: null }); + expect(container.querySelector("dialog")).toBeNull(); + expect(container.textContent).toContain("xai-demo/grok-4.6"); + }); + + test("a server failure keeps the dialog and edited draft available for retry", async () => { + mutationFailure = "Catalog refresh failed"; + await mountModels(); + await act(async () => nameTrigger().click()); + await act(async () => { + setInputValue(dialogInput(), "Retry Name"); + dialogButton("Save").click(); + }); + await flush(); + + expect(mutationBodies).toEqual([{ modelId: "grok-4.6", displayName: "Retry Name" }]); + expect(container.querySelector("dialog")).not.toBeNull(); + expect(dialogInput().value).toBe("Retry Name"); + expect(container.textContent).toContain("Catalog refresh failed"); + expect(testWindow.document.activeElement).toBe(dialogInput()); + mutationFailure = null; + await act(async () => dialogButton("Save").click()); + await flush(); + expect(mutationBodies).toHaveLength(2); + expect(currentModels[0]!.displayNameOverride).toBe("Retry Name"); + expect(container.querySelector("dialog")).toBeNull(); + }); + + test("a failed catalog reload after save keeps the dialog available for retry", async () => { + await mountModels(); + modelFetchFailure = "Catalog reload failed"; + await act(async () => nameTrigger().click()); + await act(async () => { + setInputValue(dialogInput(), "Retry Reload"); + dialogButton("Save").click(); + }); + await flush(); + + expect(mutationBodies).toEqual([{ modelId: "grok-4.6", displayName: "Retry Reload" }]); + expect(container.querySelector("dialog")).not.toBeNull(); + expect(dialogInput().value).toBe("Retry Reload"); + expect(container.textContent).toContain("The change was saved, but the model list could not be refreshed."); + expect(testWindow.document.activeElement).toBe(dialogInput()); + }); + + function currentNameText(): string { + return container.querySelector(".model-display-name-current")!.textContent ?? ""; + } + + test("first save followed by failed reload updates the snapshot and enables Reset", async () => { + await mountModels(); + await act(async () => nameTrigger().click()); + await act(async () => dialogButton("Reset name").click()); + await flush(); + mutationBodies = []; + await act(async () => nameTrigger().click()); + expect(dialogButton("Reset name").disabled).toBe(true); + modelFetchFailure = "reload failed"; + await act(async () => { + setInputValue(dialogInput(), " First Name "); + dialogButton("Save").click(); + }); + await flush(); + expect(dialogInput().value).toBe("First Name"); + expect(currentNameText()).toContain("First Name"); + expect(currentNameText()).toContain("Your name"); + expect(dialogButton("Reset name").disabled).toBe(false); + + modelFetchFailure = null; + await act(async () => dialogButton("Retry").click()); + await flush(); + expect(mutationBodies).toEqual([{ modelId: "grok-4.6", displayName: "First Name" }]); + expect(container.querySelector("dialog")).toBeNull(); + }); + + test("reset followed by failed reload clears the draft and Enter retries only the read", async () => { + await mountModels(); + await act(async () => nameTrigger().click()); + modelFetchFailure = "reload failed"; + await act(async () => dialogButton("Reset name").click()); + await flush(); + expect(dialogInput().value).toBe(""); + expect(currentNameText()).toContain("xai-demo/grok-4.6"); + expect(currentNameText()).not.toContain("Your name"); + expect(dialogButton("Reset name").disabled).toBe(true); + + modelFetchFailure = null; + await act(async () => container.querySelector("dialog form")!.dispatchEvent( + new testWindow.Event("submit", { bubbles: true, cancelable: true }), + )); + await flush(); + expect(mutationBodies).toEqual([{ modelId: "grok-4.6", displayName: null }]); + expect(container.querySelector("dialog")).toBeNull(); + expect(currentModels[0]!.displayNameOverride).toBeUndefined(); + }); + + for (const value of ["Saved Name", null]) { + test(`saved:true failure reconciles ${value === null ? "reset" : "save"} and retries the same operation`, async () => { + await mountModels(); + await act(async () => nameTrigger().click()); + savedFailure = true; + await act(async () => { + if (value === null) dialogButton("Reset name").click(); + else { + setInputValue(dialogInput(), value); + dialogButton("Save").click(); + } + }); + await flush(); + expect(dialogInput().value).toBe(value ?? ""); + expect(dialogButton("Reset name").disabled).toBe(value === null); + expect(currentNameText()).toContain(value ?? "Current name unavailable until refresh"); + expect(currentNameText()).not.toContain(value === null ? "Your name" : "Model ID fallback"); + expect(container.textContent).toContain("The change was saved"); + savedFailure = false; + await act(async () => dialogButton("Retry").click()); + await flush(); + expect(mutationBodies).toEqual([ + { modelId: "grok-4.6", displayName: value }, + { modelId: "grok-4.6", displayName: value }, + ]); + expect(container.querySelector("dialog")).toBeNull(); + }); + } + + test("editing after a saved receipt explicitly starts a new save", async () => { + await mountModels(); + await act(async () => nameTrigger().click()); + savedFailure = true; + await act(async () => dialogButton("Reset name").click()); + await flush(); + savedFailure = false; + await act(async () => setInputValue(dialogInput(), "New intention")); + await act(async () => dialogButton("Save").click()); + await flush(); + expect(mutationBodies.map(body => body.displayName)).toEqual([null, "New intention"]); + }); + + // Exercise the real global auth wrapper over an abort-aware transport. Only + // the deadline clock is controlled; the operation must supply its own signal. + for (const stage of ["mutation", "reload"] as const) { + test(`stalled ${stage} through installed API fetch releases the editor and retries a read`, async () => { + await mountModels(); + const descriptor = Object.getOwnPropertyDescriptor(AbortSignal, "timeout"); + const deadline = new AbortController(); + const budgets: number[] = []; + const seenSignals: Array = []; + let stall = true; + const transport = globalThis.fetch; + Object.defineProperty(AbortSignal, "timeout", { + configurable: true, + value: (ms: number) => { budgets.push(ms); return deadline.signal; }, + }); + const boundedTransport = (async (input: RequestInfo | URL, init?: RequestInit) => { + if (String(input).includes("model-display-names") || String(input).endsWith("/api/models")) { + seenSignals.push(init?.signal); + } + if (stall && (stage === "mutation" + ? init?.method === "PUT" && String(input).includes("model-display-names") + : String(input).endsWith("/api/models"))) { + // Persist the write before losing its response: abort is not rollback. + if (stage === "mutation") await transport(input, init); + return new Promise((_resolve, reject) => { + const signal = init?.signal; + if (signal?.aborted) reject(signal.reason); + else signal?.addEventListener("abort", () => reject(signal.reason), { once: true }); + }); + } + return transport(input, init); + }) as typeof fetch; + Object.defineProperty(window, "fetch", { configurable: true, value: boundedTransport }); + installApiAuthFetch(); + globalThis.fetch = window.fetch; + try { + const trigger = nameTrigger(); + await act(async () => trigger.click()); + await act(async () => { + setInputValue(dialogInput(), "Possibly saved"); + dialogButton("Save").click(); + }); + await flush(); + expect(budgets).toEqual([60_000]); + expect(seenSignals.every(signal => signal != null)).toBe(true); + if (stage === "reload") expect(seenSignals[1]).toBe(seenSignals[0]); + await act(async () => deadline.abort(new DOMException("Timed out", "TimeoutError"))); + await flush(); + expect(dialogInput().disabled).toBe(false); + expect(dialogButton("Cancel").disabled).toBe(false); + expect(dialogInput().value).toBe("Possibly saved"); + expect(container.textContent).toContain(stage === "mutation" + ? "The change may have been saved" : "The change was saved"); + expect(testWindow.document.activeElement).toBe(dialogInput()); + stall = false; + if (descriptor) Object.defineProperty(AbortSignal, "timeout", descriptor); + await act(async () => dialogButton("Retry").click()); + await flush(); + expect(mutationBodies).toHaveLength(1); + expect(currentModels[0]!.displayNameOverride).toBe("Possibly saved"); + expect(container.querySelector("dialog")).toBeNull(); + expect(testWindow.document.activeElement).toBe(trigger); + } finally { + if (descriptor) Object.defineProperty(AbortSignal, "timeout", descriptor); + else Reflect.deleteProperty(AbortSignal, "timeout"); + } + }); + } + + test("a pending save blocks duplicate mutations", async () => { + let releaseMutation!: () => void; + mutationGate = new Promise(resolve => { releaseMutation = resolve; }); + await mountModels(); + await act(async () => nameTrigger().click()); + const save = dialogButton("Save"); + + await act(async () => { + setInputValue(dialogInput(), "Grok Once"); + save.click(); + save.click(); + await Promise.resolve(); + }); + expect(mutationBodies).toEqual([{ modelId: "grok-4.6", displayName: "Grok Once" }]); + expect(save.disabled).toBe(true); + + releaseMutation(); + await flush(); + expect(container.querySelector("dialog")).toBeNull(); + }); + + test("Cancel closes without mutation and restores focus to Name", async () => { + await mountModels(); + const trigger = nameTrigger(); + await act(async () => trigger.click()); + await act(async () => dialogButton("Cancel").click()); + await flush(); + + expect(mutationBodies).toHaveLength(0); + expect(container.querySelector("dialog")).toBeNull(); + expect(testWindow.document.activeElement).toBe(trigger); + }); +}); + +describe("discovered model display name dialog", () => { + const globals = ["document", "window", "navigator", "localStorage", "IS_REACT_ACT_ENVIRONMENT"] as const; + let previousGlobals: Record<(typeof globals)[number], PropertyDescriptor | undefined>; + let testWindow: Window; + let container: HTMLElement; + let root: Root | null; + + const model: ModelRow = { + provider: "xai-demo", + id: "grok-4.6", + namespaced: "xai-demo/grok-4.6", + disabled: false, + displayName: "Grok 4.6", + displayNameOverride: "Grok 4.6", + displayNameSource: "operator", + }; + + beforeEach(() => { + previousGlobals = Object.fromEntries( + globals.map(key => [key, Object.getOwnPropertyDescriptor(globalThis, key)]), + ) as typeof previousGlobals; + testWindow = new Window({ url: "http://localhost/" }); + Object.defineProperties(globalThis, { + document: { configurable: true, value: testWindow.document }, + window: { configurable: true, value: testWindow }, + navigator: { configurable: true, value: testWindow.navigator }, + localStorage: { configurable: true, value: testWindow.localStorage }, + IS_REACT_ACT_ENVIRONMENT: { configurable: true, value: true }, + }); + container = testWindow.document.createElement("div"); + testWindow.document.body.appendChild(container as never); + root = null; + }); + + afterEach(async () => { + if (root) { + const mounted = root; + await act(async () => mounted.unmount()); + } + testWindow.close(); + for (const key of globals) { + const descriptor = previousGlobals[key]; + if (descriptor) Object.defineProperty(globalThis, key, descriptor); + else Reflect.deleteProperty(globalThis, key); + } + }); + + async function renderDialog(options: { + saving?: boolean; + requestError?: string | null; + onSave?: (value: string) => void; + onReset?: () => void; + onClose?: () => void; + } = {}) { + const { createRoot } = await import("react-dom/client"); + await act(async () => { + root ??= createRoot(container); + root.render( + + {})} + onReset={options.onReset ?? (() => {})} + onClose={options.onClose ?? (() => {})} + /> + , + ); + }); + } + + function setInputValue(input: HTMLInputElement, value: string) { + Object.getOwnPropertyDescriptor(testWindow.HTMLInputElement.prototype, "value")! + .set!.call(input, value); + input.dispatchEvent(new testWindow.Event("input", { bubbles: true })); + } + + test("opens with immutable identity and only the operator override in the input", async () => { + await renderDialog(); + + const dialog = container.querySelector("dialog")!; + const input = container.querySelector("input")!; + expect(dialog.open).toBe(true); + expect(dialog.textContent).toContain("xai-demo/grok-4.6"); + expect(dialog.textContent).toContain("Grok 4.6"); + expect(dialog.textContent).toContain("Your name"); + expect(input.value).toBe("Grok 4.6"); + expect(testWindow.document.activeElement).toBe(input); + }); + + test("validates before save and sends the trimmed safe draft", async () => { + const onSave = jest.fn(); + await renderDialog({ onSave }); + const input = container.querySelector("input")!; + const save = [...container.querySelectorAll("button")] + .find(button => button.textContent === "Save")!; + + await act(async () => { + setInputValue(input, "Bad/Name"); + save.click(); + }); + expect(container.textContent).toContain("Friendly name cannot contain /."); + expect(onSave).not.toHaveBeenCalled(); + + await act(async () => { + setInputValue(input, " Grok Fast "); + save.click(); + }); + expect(onSave).toHaveBeenCalledTimes(1); + expect(onSave).toHaveBeenCalledWith("Grok Fast"); + }); + + test("keeps request errors visible and locks every closing action while saving", async () => { + const onClose = jest.fn(); + const onReset = jest.fn(); + await renderDialog({ saving: true, requestError: "Catalog refresh failed", onClose, onReset }); + + expect(container.textContent).toContain("Catalog refresh failed"); + const actionButtons = [...container.querySelectorAll("button")]; + expect(actionButtons.filter(button => button.tabIndex !== -1).every(button => button.disabled)).toBe(true); + + const dialog = container.querySelector("dialog")!; + await act(async () => { + dialog.dispatchEvent(new testWindow.Event("cancel", { bubbles: false, cancelable: true })); + container.querySelector(".modal-backdrop-dismiss")!.click(); + }); + expect(onClose).not.toHaveBeenCalled(); + expect(onReset).not.toHaveBeenCalled(); + }); + + test("a request failure does not mark a valid display name as invalid", async () => { + await renderDialog({ requestError: "Catalog refresh failed" }); + + const input = container.querySelector("input")!; + expect(input.getAttribute("aria-invalid")).toBeNull(); + expect(testWindow.document.activeElement).toBe(input); + }); + + test("focus returns to the editable name after a pending save fails", async () => { + await renderDialog({ saving: true }); + testWindow.document.body.tabIndex = -1; + testWindow.document.body.focus(); + expect(testWindow.document.activeElement).toBe(testWindow.document.body); + + await renderDialog({ requestError: "Catalog refresh failed" }); + + expect(testWindow.document.activeElement).toBe(container.querySelector("input")); + }); +}); From f215f79b4562735029ad5672a68bc6104e534b98 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 07:41:57 +0900 Subject: [PATCH 017/412] fix(anthropic): attribute quota headers and honor measured reset deadlines [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Carry and refine #3809: observe each request-bound physical response, preserve probe clocks and model-specific windows, and retain valid multi-day upstream reset deadlines. Preserve credential ownership and skip unprovable observations. Runtime checks are deferred to the final cumulative hosted CI at owner request; no local suite was run. Co-authored-by: Éverton Toffanetto --- .../src/content/docs/guides/claude-code.md | 13 +- .../docs/reference/configuration/providers.md | 20 +- scripts/test-layout/layout.json | 2 + src/images/loop.ts | 12 +- src/oauth/anthropic-routing.ts | 73 ++- src/oauth/health.ts | 3 + src/providers/quota.ts | 77 ++- src/server/responses/core.ts | 35 +- src/web-search/loop.ts | 12 +- .../anthropic-quota-dispatch.test.ts | 283 ++++++++++ .../anthropic-ratelimit-headers.test.ts | 528 ++++++++++++++++++ ...anthropic-sidecar-account-failover.test.ts | 55 +- tests/fixtures/test-layout-expected.json | 2 + 13 files changed, 1074 insertions(+), 41 deletions(-) create mode 100644 tests/adapters/anthropic/anthropic-quota-dispatch.test.ts create mode 100644 tests/adapters/anthropic/anthropic-ratelimit-headers.test.ts diff --git a/docs-site/src/content/docs/guides/claude-code.md b/docs-site/src/content/docs/guides/claude-code.md index 5ed946c72a..2e841e205c 100644 --- a/docs-site/src/content/docs/guides/claude-code.md +++ b/docs-site/src/content/docs/guides/claude-code.md @@ -27,9 +27,16 @@ rotation does not protect against provider enforcement. Operational contract when enabled: -- Upstream **429** cools that account using `Retry-After` when present (else a default backoff), - clears its affinities, and may rotate to another eligible account within the same request - (bounded). +- Upstream **429** cools that account, clears its affinities, and may rotate to another eligible + account within the same request (bounded). The cooldown uses a usable `Retry-After` when present, + otherwise the latest valid reset time among windows Anthropic marks `rejected`, including + weekly windows. Valid upstream deadlines are not shortened to a fixed cooldown ceiling. + A refusal with no usable deadline falls back to a default backoff. +- Responses report the serving account's 5-hour and weekly utilization, and whichever of those + two the response carries is recorded for that account — each window independently, and a + refusal counts as well as a success. Usage-aware selection works from ordinary traffic, + without waiting for a dashboard poll. Headers preserve model-specific quota windows and do + not postpone usage probes or clear a failed usage probe's unavailable status. - Affinity is **process-local** (lost on proxy restart). - **401/403** credential failures quarantine the account (`needsReauth`) so it is excluded from selection until re-authenticated. diff --git a/docs-site/src/content/docs/reference/configuration/providers.md b/docs-site/src/content/docs/reference/configuration/providers.md index 02d5ba4323..c80176868e 100644 --- a/docs-site/src/content/docs/reference/configuration/providers.md +++ b/docs-site/src/content/docs/reference/configuration/providers.md @@ -430,14 +430,26 @@ rotation may trigger provider restrictions. | `anthropicAccountPool.enabled?` | `boolean` | `false` | Enable sticky session affinity and quota-ranked new-session selection. **429 failover is not gated here**: it activates whenever two or more usable accounts are stored, exactly like every other multi-credential provider, and cannot be switched off. | | `anthropicAccountPool.autoSwitchThreshold?` | `number` | `80` | For new sessions, when the active account reaches this threshold, choose the lowest known cached usage in the configured window; the account chosen does not itself have to be at or above the threshold. `0` disables **proactive** usage-based switching only — new-session selection and routing recovery after an eligible 429 still consult `quotaWindow`. | | `anthropicAccountPool.strategy?` | `"quota" \| "round-robin" \| "fill-first"` | `"quota"` | New-session strategy; `quota` ranks accounts by the window set by `quotaWindow`, and `fill-first` evaluates its drain threshold in that same window. | -| `anthropicAccountPool.quotaWindow?` | `"five-hour" \| "weekly" \| "max-utilization"` | `"five-hour"` | The cached provider-reported utilization bar used for usage-aware account selection. `five-hour` keeps the original behavior. `weekly` scores the weekly bar and skips accounts whose 5-hour bar is exhausted while another eligible account remains, but falls back to exhausted candidates when none do. `max-utilization` scores the highest known bar, so it can use 5-hour usage before weekly usage is available; if neither is known, the account follows unknown-usage ordering. Known usage ranks before unknown usage under the opt-in `weekly` and `max-utilization` windows only; an omitted or explicit `five-hour` preserves the legacy ordering. If every eligible account is unknown, selection still returns one in eligible order. After the documented lower-5-hour tie-break, exact ties preserve eligible order. A healthy affinity-bound session is not proactively rebalanced. For new-session assignment and routing recovery after an eligible 429 replacement, `quota` ranks eligible candidates directly with this window; `fill-first` advances in stable order using this window's threshold and exhaustion rules; `round-robin` ignores it. Cooldown, failover limits, and reauthentication eligibility remain separate local state. Per-account weekly bars are only known once the dashboard Providers page has polled them. | +| `anthropicAccountPool.quotaWindow?` | `"five-hour" \| "weekly" \| "max-utilization"` | `"five-hour"` | The cached provider-reported utilization bar used for usage-aware account selection. `five-hour` keeps the original behavior. `weekly` scores the weekly bar and skips accounts whose 5-hour bar is exhausted while another eligible account remains, but falls back to exhausted candidates when none do. `max-utilization` scores the highest known bar, so it can use 5-hour usage before weekly usage is available; if neither is known, the account follows unknown-usage ordering. Known usage ranks before unknown usage under the opt-in `weekly` and `max-utilization` windows only; an omitted or explicit `five-hour` preserves the legacy ordering. If every eligible account is unknown, selection still returns one in eligible order. After the documented lower-5-hour tie-break, exact ties preserve eligible order. A healthy affinity-bound session is not proactively rebalanced. For new-session assignment and routing recovery after an eligible 429 replacement, `quota` ranks eligible candidates directly with this window; `fill-first` advances in stable order using this window's threshold and exhaustion rules; `round-robin` ignores it. Cooldown, failover limits, and reauthentication eligibility remain separate local state. Per-account weekly bars come from usage probes or observed response headers. | | `anthropicAccountPool.stickyLimit?` | `number` | `1` | Successful new-session binds retained on one round-robin selection. Range 1–100. | -When enabled, 429 records bounded cooldown from `Retry-After` or a default backoff and may rotate -within the request. Affinity is process-local and size-bounded. Credential 401/403 marks the account -as needing reauthentication. If all eligible accounts are cooling, clients receive 429 with +When enabled, 429 records a cooldown and may rotate within the request. The cooldown length comes +from a usable `Retry-After`, otherwise from the latest valid reset time among rate-limit windows +Anthropic reports as `rejected`, including weekly windows. Valid upstream deadlines are not +shortened to a fixed cooldown ceiling; non-finite or unrepresentable deadlines are ignored. +A refusal with no usable deadline falls back to a short default backoff. Affinity is process-local +and size-bounded. Credential 401/403 marks the account as needing reauthentication. If all eligible accounts are cooling, clients receive 429 with `Retry-After` when known, not an authentication error. +Anthropic responses also report the serving account's 5-hour and weekly utilization, and whichever +of those two a given response carries is recorded against that account — each window independently, +on refusals as well as successes. Usage-aware selection therefore works from the accounts you +actually use, without waiting for the dashboard Providers page to poll them. These readings refresh +the existing row rather than replacing it, so the model-scoped weekly bars that only the usage +endpoint reports are preserved. Header observations do not postpone usage probes or clear a failed +probe's unavailable status. After restart, cached Anthropic observations remain available while +the next quota read probes again, because the saved observations do not include the probe clock. + :::caution[Experimental] Leave this disabled unless you understand Anthropic account policy risk. Prefer manual `ocx account use anthropic ` switching when unsure. diff --git a/scripts/test-layout/layout.json b/scripts/test-layout/layout.json index d309073a3f..f560dffeb5 100644 --- a/scripts/test-layout/layout.json +++ b/scripts/test-layout/layout.json @@ -204,6 +204,8 @@ "anthropic-image-retry.test.ts": "adapters/anthropic", "anthropic-pool-toggle-copy.test.ts": "adapters/anthropic", "anthropic-quorum-cache.test.ts": "routing", + "anthropic-quota-dispatch.test.ts": "adapters/anthropic", + "anthropic-ratelimit-headers.test.ts": "adapters/anthropic", "anthropic-reasoning.test.ts": "adapters/anthropic", "anthropic-sidecar-account-failover.test.ts": "adapters/anthropic", "anthropic-stream-hardening.test.ts": "adapters/anthropic", diff --git a/src/images/loop.ts b/src/images/loop.ts index e3a7f8252f..7d4855f91b 100644 --- a/src/images/loop.ts +++ b/src/images/loop.ts @@ -263,8 +263,16 @@ export interface ImageBridgeDeps { * Optional 429 failover for the routed (non-xAI) model. Return a rebuilt adapter for the * rotated credential, or null when the pool is exhausted. Async hooks support OAuth refresh; * existing synchronous key-pool hooks remain valid. + * + * `responseHeaders` carries the whole refusal, not just Retry-After, because an Anthropic + * 429 states the window's reset epoch even when it omits Retry-After -- and a rotation that + * cannot see it cools the drained account for the short default instead of until the window + * actually reopens. Optional so existing callers keep compiling. */ - on429?: (retryAfterHeader: string | null) => ProviderAdapter | null | Promise; + on429?: ( + retryAfterHeader: string | null, + responseHeaders?: Headers, + ) => ProviderAdapter | null | Promise; /** Opt-in same-target 429 policy (key-auth providers). When present, 429 replays on the SAME key before on429 rotation. */ retryOn429Policy?: Required | null; /** Called when the bridged Responses stream completes (parity with runTurn / routed paths). */ @@ -579,7 +587,7 @@ export async function runWithImageBridge(deps: ImageBridgeDeps): Promise {}); } catch { /* already closed */ } adapter = rotated; diff --git a/src/oauth/anthropic-routing.ts b/src/oauth/anthropic-routing.ts index a029207be5..6b2eea5a3b 100644 --- a/src/oauth/anthropic-routing.ts +++ b/src/oauth/anthropic-routing.ts @@ -10,9 +10,10 @@ * Intentionally narrower than the Codex pool: no mid-session quota rotation, * soft-avoid ladders, or probe leases. Anthropic OAuth is ToS-sensitive. * - * Affinity is process-local (lost on restart). Cooldown uses Retry-After when present, - * otherwise a default backoff. 401/403 credential failures should set needsReauth on the - * store (existing OAuth path) so the account is excluded from eligibility. + * Affinity is process-local (lost on restart). Cooldown uses Retry-After when present, else + * the reset time of whichever rate-limit window upstream reports as rejected, else a default + * backoff. 401/403 credential failures should set needsReauth on the store (existing OAuth + * path) so the account is excluded from eligibility. */ import { createHash } from "node:crypto"; import { captureOAuthAccountSelection, commitOAuthAccountSelection, credentialGeneration, getAccountSet, getAccountCredential, getAccountCredentialWithStatus } from "./store"; @@ -33,9 +34,16 @@ import type { OcxAccountPoolQuotaWindow, OcxAccountPoolRotationStrategy, OcxConf import { sweepExpiredOnWrite } from "../lib/state-store-sweeper"; import { retainedUtf8Bytes } from "../lib/admission"; +/** + * The read side of a `Headers` object, so a caller can pass the live upstream response's + * headers without this module importing anything from the server layer -- and so a test can + * hand it a plain `new Headers({...})`. + */ +export type AnthropicRateLimitHeaders = Pick; + const PROVIDER = "anthropic"; +/** Backoff only when upstream supplies no usable deadline. */ const DEFAULT_COOLDOWN_MS = 60_000; -const MAX_COOLDOWN_MS = 15 * 60_000; const AFFINITY_IDLE_TTL_MS = 24 * 60 * 60_000; const MAX_AFFINITY_ENTRIES = 2_000; const MAX_AFFINITY_COMPONENT_BYTES = 512; @@ -58,9 +66,19 @@ export interface AnthropicAccountPoolConfig { quotaWindow?: OcxAccountPoolQuotaWindow; } +/** + * Where a cooldown's length came from. Same vocabulary as `CodexCooldownSource`, because it + * answers the same question for the same reason: `retry-after` is upstream answering THIS + * refusal, `reset-derived` is upstream stating when the spent window reopens, and `default` + * is our own guess. The dashboard renders the first as a rate limit and the rest as quota, + * which is exactly the distinction a reset-derived cooldown carries -- collapsing it into + * `retry-after` would report a drained five-hour window as request-rate throttling. + */ +type AnthropicCooldownSource = "retry-after" | "reset-derived" | "default"; + interface AccountHealth { cooldownUntil: number; - cooldownSource: "retry-after" | "default"; + cooldownSource: AnthropicCooldownSource; } interface AffinityEntry { @@ -112,19 +130,38 @@ export function anthropicQuotaWindow(config: AnthropicAccountPoolConfig): OcxAcc return normalizeAccountPoolQuotaWindow(config.quotaWindow); } +/** Accept upstream deadlines within the runtime's date range, without a policy ceiling. */ +function delayUntil(timestamp: number, now: number): number | undefined { + const delay = timestamp - now; + return Number.isFinite(new Date(timestamp).getTime()) && Number.isFinite(delay) && delay > 0 + ? delay : undefined; +} + function parseRetryAfterMs(value: string | null | undefined, now: number): number | undefined { const text = value?.trim(); if (!text) return undefined; if (/^\d+(?:\.\d+)?$/.test(text)) { const seconds = Number(text); - if (Number.isFinite(seconds) && seconds > 0) { - return Math.min(Math.max(Math.ceil(seconds * 1000), 1), MAX_COOLDOWN_MS); - } + if (!Number.isFinite(seconds) || seconds <= 0) return undefined; + return delayUntil(now + Math.max(Math.ceil(seconds * 1000), 1), now); } - const timestamp = Date.parse(text); - if (!Number.isFinite(timestamp)) return undefined; - const delay = timestamp - now; - return delay > 0 ? Math.min(delay, MAX_COOLDOWN_MS) : undefined; + return delayUntil(Date.parse(text), now); +} + +/** Only rejected windows constrain recovery; all must reopen, so take the latest reset. */ +function parseRateLimitResetMs(headers: AnthropicRateLimitHeaders | null | undefined, now: number): number | undefined { + if (!headers) return undefined; + let latest: number | undefined; + for (const window of ["5h", "7d"] as const) { + if (headers.get(`anthropic-ratelimit-unified-${window}-status`)?.trim() !== "rejected") continue; + const resetSeconds = Number(headers.get(`anthropic-ratelimit-unified-${window}-reset`)?.trim()); + if (!Number.isFinite(resetSeconds) || resetSeconds <= 0) continue; + const resetAt = resetSeconds * 1000; + if (delayUntil(resetAt, now) === undefined) continue; + if (latest === undefined || resetAt > latest) latest = resetAt; + } + if (latest === undefined) return undefined; + return latest - now; } export function getAnthropicAccountHealthSnapshot( @@ -669,6 +706,7 @@ export function rotateAnthropicAccountOn429( retryAfterHeader: string | null | undefined, sessionKey?: string | null, now = Date.now(), + rateLimitHeaders?: AnthropicRateLimitHeaders | null, ): string | null { // Reactive 429 failover is NOT gated on the pool flag. That flag buys PROACTIVE routing -- // session affinity, quota-ranked new-session selection, autoSwitchThreshold, strategy -- all @@ -678,11 +716,18 @@ export function rotateAnthropicAccountOn429( // Presence is the activation rule, the same one an apiKeyPool of two keys already uses. if (!isAnthropicAccountPoolEnabled(config) && !hasAnthropicFailoverQuorum(now)) return null; + // Retry-After first: it is the header written FOR this decision. The rejected window's + // reset is the fallback, because a 429 that omits Retry-After still carries it -- and + // without that fallback such a refusal cools for the 60s default and the exhausted + // account is back in the rotation a minute later. const parsedRetry = parseRetryAfterMs(retryAfterHeader, now); - const cooldownMs = parsedRetry ?? DEFAULT_COOLDOWN_MS; + const resetDerived = parsedRetry === undefined ? parseRateLimitResetMs(rateLimitHeaders, now) : undefined; + const cooldownMs = parsedRetry ?? resetDerived ?? DEFAULT_COOLDOWN_MS; upstreamHealth.set(failedAccountId, { cooldownUntil: now + cooldownMs, - cooldownSource: parsedRetry ? "retry-after" : "default", + cooldownSource: parsedRetry !== undefined + ? "retry-after" + : resetDerived !== undefined ? "reset-derived" : "default", }); sweepExpiredOnWrite(now); clearAnthropicSessionAffinityForAccount(failedAccountId); diff --git a/src/oauth/health.ts b/src/oauth/health.ts index 4c997c47cc..011ebd8f41 100644 --- a/src/oauth/health.ts +++ b/src/oauth/health.ts @@ -184,6 +184,9 @@ export function projectStoredOAuthAccountHealth( needsReauth: account.needsReauth === true, reauthReason: account.needsReauth === true ? "refresh_failed" : undefined, cooldownUntilMs: anthropicSnap?.cooldownUntil, + // Same mapping as the Codex pool's `cooldownReasonFromSource`: only a Retry-After is + // request-rate throttling. A reset-derived cooldown means a usage window is spent, which + // is quota, and reporting it as a rate limit would tell the operator to retry shortly. cooldownReason: anthropicSnap?.cooldownSource === "retry-after" ? "rate_limit" : anthropicSnap ? "quota" : undefined, warningReason: detectOAuthWarning(provider, account, opts.observeOnly === true, now), now, diff --git a/src/providers/quota.ts b/src/providers/quota.ts index 7136cd3c70..dbdb6699f7 100644 --- a/src/providers/quota.ts +++ b/src/providers/quota.ts @@ -1568,7 +1568,10 @@ function hydrateAccountQuotaCache(): void { if (diskHydrated) return; diskHydrated = true; for (const [key, quota] of readPersistedAccountQuotas()) { - if (!accountQuotaCache.has(key)) accountQuotaCache.set(key, { ts: quota.updatedAt, quota }); + // Disk stores observation time, not the Anthropic usage probe's clock. + if (!accountQuotaCache.has(key)) { + accountQuotaCache.set(key, { ts: key.startsWith("anthropic\u0000") ? 0 : quota.updatedAt, quota }); + } } } @@ -1642,6 +1645,66 @@ export function setCachedProviderAccountQuotaForTests( accountQuotaCache.set(key, { ts: Date.now(), quota }); } +/** Unified headers report utilization fractions and epoch-second reset times. */ +function anthropicHeaderResetAt(value: string | null): number | undefined { + const seconds = toFiniteNumber(value); + if (seconds === undefined || seconds <= 0) return undefined; + const timestamp = seconds * 1000; + return Number.isFinite(new Date(timestamp).getTime()) ? timestamp : undefined; +} + +export function parseAnthropicRateLimitHeaders(headers: Headers): ProviderQuota | null { + const fiveHourPercent = normalizeUtilizationFraction(headers.get("anthropic-ratelimit-unified-5h-utilization")); + const weeklyPercent = normalizeUtilizationFraction(headers.get("anthropic-ratelimit-unified-7d-utilization")); + if (fiveHourPercent === undefined && weeklyPercent === undefined) return null; + const fiveHourResetAt = anthropicHeaderResetAt(headers.get("anthropic-ratelimit-unified-5h-reset")); + const weeklyResetAt = anthropicHeaderResetAt(headers.get("anthropic-ratelimit-unified-7d-reset")); + return { + ...(fiveHourPercent !== undefined ? { fiveHourPercent } : {}), + ...(fiveHourResetAt !== undefined ? { fiveHourResetAt } : {}), + ...(weeklyPercent !== undefined ? { weeklyPercent } : {}), + ...(weeklyResetAt !== undefined ? { weeklyResetAt } : {}), + updatedAt: Date.now(), + }; +} + +/** Reject unknown scales; round fraction conversion for persisted/displayed percentages. */ +function normalizeUtilizationFraction(value: string | null): number | undefined { + const numeric = toFiniteNumber(value); + if (numeric === undefined || numeric < 0 || numeric > 1) return undefined; + return Math.round(numeric * 10_000) / 100; +} + +/** + * Merge serving-account observations without advancing the usage probe's clock or + * erasing model-specific windows. The caller owns credential attribution; this guard + * prevents a retired account key from being revived by an older config generation. + */ +export function recordAnthropicAccountQuotaFromHeaders( + accountId: string, + headers: Headers, + writerGeneration: number, +): void { + if (!accountId) return; + const observed = parseAnthropicRateLimitHeaders(headers); + if (!observed) return; + const key = accountCacheKey("anthropic", accountId); + if (!mayCommitAccountQuotaKey(key, writerGeneration)) return; + // Hydrate before writing, for the same reason `recordPassiveAccountQuota` does: this write + // arrives unprompted from the request path, and `persistAccountQuotaCache` serializes the + // whole map. Landing before any reader has hydrated would persist this single row and erase + // every other provider's saved row. + hydrateAccountQuotaCache(); + const previous = accountQuotaCache.get(key); + accountQuotaCache.set(key, { + ...previous, + // Headers do not prove that the last usage probe succeeded. + ts: previous?.ts ?? 0, + quota: { ...(previous?.quota ?? {}), ...observed }, + }); + persistAccountQuotaCache(); +} + /** * Providers whose per-account quota is OBSERVED in-band, never probed. * @@ -1714,7 +1777,11 @@ export function readPassiveProviderAccountQuotas(provider: string): ProviderAcco export function sweepExpiredProviderAccountQuotaRows(now = Date.now()): number { let removed = 0; for (const [key, entry] of accountQuotaCache) { - if (entry.ts + ACCOUNT_QUOTA_TTL_MS > now) continue; + // Anthropic observations extend retention, never the usage probe's eligibility clock. + const retainedAt = key.startsWith("anthropic\u0000") + ? Math.max(entry.ts, entry.quota?.updatedAt ?? 0) + : entry.ts; + if (retainedAt + ACCOUNT_QUOTA_TTL_MS > now) continue; accountQuotaCache.delete(key); removed += 1; } @@ -1907,6 +1974,7 @@ async function fetchAccountQuota( ): Promise { if (!supportsPerAccountQuota(provider)) return { ts: Date.now(), quota: null, unavailable: true }; if (explicitAccountReader(provider)) return fetchExplicitAccountQuota(provider, accountId, forceRefresh, providerConfig); + if (provider === "anthropic") hydrateAccountQuotaCache(); const key = accountCacheKey(provider, accountId); const writerGeneration = captureConfigGeneration(); const cached = accountQuotaCache.get(key); @@ -1947,7 +2015,8 @@ async function fetchAccountQuota( // negative-cache instead of re-probing on every GUI poll. const entry: AccountQuotaCacheEntry = { ts: Date.now(), - quota: cached?.quota ?? null, + // Settle once for all joiners against observations committed during the probe. + quota: (provider === "anthropic" ? accountQuotaCache.get(key)?.quota : cached?.quota) ?? null, unavailable: true, }; if (mayCommitAccountQuotaKey(key, writerGeneration)) { @@ -1969,7 +2038,7 @@ async function fetchAccountQuota( } catch { const entry: AccountQuotaCacheEntry = { ts: Date.now(), - quota: cached?.quota ?? null, + quota: (provider === "anthropic" ? accountQuotaCache.get(key)?.quota : cached?.quota) ?? null, unavailable: true, }; if (mayCommitAccountQuotaKey(key, writerGeneration)) { diff --git a/src/server/responses/core.ts b/src/server/responses/core.ts index 3c539c6d8e..fc2195f427 100644 --- a/src/server/responses/core.ts +++ b/src/server/responses/core.ts @@ -230,7 +230,7 @@ import { } from "../../providers/request-pacing"; import { slugsEquivalent } from "../../providers/slug-codec"; import { isMuseSubscriptionUsagePayload, parseMuseSubscriptionUsage } from "../../providers/muse-subscription-usage"; -import { hasPassiveAccountQuota, recordPassiveAccountQuota } from "../../providers/quota"; +import { hasPassiveAccountQuota, recordAnthropicAccountQuotaFromHeaders, recordPassiveAccountQuota } from "../../providers/quota"; import { captureConfigGeneration } from "../../lib/state-store-sweeper"; import { applyOpenAiVirtualModel, resolveOpenAiCompactModel } from "../../providers/openai-virtual-models"; import { isUsageDebugEnabled } from "../../usage/debug"; @@ -3946,7 +3946,27 @@ async function handleResponsesInner( for (let attempt = 0; attempt < 3; attempt++) { if (selectionIsCurrent(requestBindings.get(wireRequest))) { const fetchImpl = (route.provider as OcxProviderConfig & { fetch?: typeof globalThis.fetch }).fetch ?? execute; - return fetchImpl(destination, dispatchInit); + const binding = requestBindings.get(wireRequest); + const snapshot = route.providerName === "anthropic" && anthropicPoolAccountId && binding?.kind === "oauth" + ? binding.snapshot : undefined; + const writerGeneration = snapshot ? captureConfigGeneration() : 0; + const sentHeaders = snapshot ? new Headers(dispatchInit.headers) : undefined; + const ownsBearer = snapshot !== undefined + && sentHeaders?.get("authorization") === `Bearer ${snapshot.accessToken}` + && !sentHeaders?.has("x-api-key"); + const response = await fetchImpl(destination, dispatchInit); + // Observe each physical response before retries replace it. The binding belongs to + // this dispatch, so a manual switch cannot file A's headers against B. Header + // overrides and credential replacement make ownership unprovable: skip those writes. + if (ownsBearer && snapshot) { + try { + const current = getAccountCredentialWithStatus("anthropic", snapshot.accountId); + if (current && !current.needsReauth && credentialGeneration(current.credential) === snapshot.generation) { + recordAnthropicAccountQuotaFromHeaders(snapshot.accountId, response.headers, writerGeneration); + } + } catch { /* best-effort observation cannot fail the response */ } + } + return response; } const nextAdapter = await refreshDispatchAdapter(requestParsed); const rebuilt = await nextAdapter.buildRequest(requestParsed, { @@ -5956,7 +5976,10 @@ async function handleResponsesInner( const imgPlan = !routedCompaction ? await planImageBridge(config, parsed, route.provider) : undefined; const vidPlan = !routedCompaction ? await planVideoBridge(config, parsed, route.provider) : undefined; const canRunWebSearch = !!wsPlan && !adapter.runTurn; - const rotateSidecarProviderOn429 = async (retryAfter: string | null): Promise => { + const rotateSidecarProviderOn429 = async ( + retryAfter: string | null, + responseHeaders?: Headers, + ): Promise => { const rotated = rotateProviderTransportOn429(config, route.providerName, route.provider, { retryAfter, now: Date.now(), @@ -6000,6 +6023,8 @@ async function handleResponsesInner( anthropicPoolAccountId, retryAfter, anthropicSessionKey, + Date.now(), + responseHeaders, ); if (!nextAccountId) return null; try { @@ -7032,6 +7057,8 @@ async function handleResponsesInner( anthropicPoolAccountId, upstreamResponse.headers.get("retry-after"), anthropicSessionKey, + Date.now(), + upstreamResponse.headers, ); if (!nextAccountId) break; try { void upstreamResponse.body?.cancel().catch(() => {}); } catch { /* already consumed/closed */ } @@ -7445,6 +7472,8 @@ async function handleResponsesInner( anthropicPoolAccountId, response.headers.get("retry-after"), anthropicSessionKey, + Date.now(), + response.headers, ); if (nextAccountId) { try { void response.body?.cancel().catch(() => {}); } catch { /* already closed */ } diff --git a/src/web-search/loop.ts b/src/web-search/loop.ts index 3a2c5e99b4..0c957e1c17 100644 --- a/src/web-search/loop.ts +++ b/src/web-search/loop.ts @@ -309,8 +309,16 @@ export interface WebSearchLoopDeps { * 429 failover hook: rotate the provider's active credential and return a rebuilt adapter, * or null when the pool is exhausted. Async hooks support OAuth refresh; existing synchronous * key-pool hooks remain valid. + * + * `responseHeaders` carries the whole refusal, not just Retry-After, because an Anthropic + * 429 states the window's reset epoch even when it omits Retry-After -- and a rotation that + * cannot see it cools the drained account for the short default instead of until the window + * actually reopens. Optional so existing callers keep compiling. */ - on429?: (retryAfterHeader: string | null) => ProviderAdapter | null | Promise; + on429?: ( + retryAfterHeader: string | null, + responseHeaders?: Headers, + ) => ProviderAdapter | null | Promise; /** Opt-in same-target 429 policy (key-auth providers). When present, 429 replays on the SAME key before on429 rotation. */ retryOn429Policy?: Required | null; /** Called only when the final bridged Responses stream reaches completed or incomplete. */ @@ -521,7 +529,7 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise }[]; + +beforeEach(() => { + home = mkdtempSync(join(tmpdir(), "ocx-anthropic-quota-dispatch-")); + process.env.OPENCODEX_HOME = home; + sent = []; + clearAnthropicAccountPoolState(); + forgetAnthropicFailoverQuorum(); + clearGenericFailoverHealth(); + clearAccountQuotaCache(); + resetProviderQuotaReconcileStateForTests(); + clearResponseStateForTests(); +}); + +afterEach(() => { + clearAnthropicAccountPoolState(); + forgetAnthropicFailoverQuorum(); + clearGenericFailoverHealth(); + // Cancel the debounced persistence before restoring the real home. + clearAccountQuotaCache(); + resetProviderQuotaReconcileStateForTests(); + clearResponseStateForTests(); + if (originalHome === undefined) delete process.env.OPENCODEX_HOME; + else process.env.OPENCODEX_HOME = originalHome; + removeTreeWithRetry(home); +}); + +function credential(index: number) { + return { + access: `synthetic-anthropic-access-${index}`, + refresh: `synthetic-anthropic-refresh-${index}`, + expires: Date.now() + 3_600_000, + accountId: `synthetic-account-${index}`, + }; +} + +async function seed(count = 2): Promise { + for (let index = 0; index < count; index++) { + await saveCredential("anthropic", credential(index)); + } + const ids = getAccountSet("anthropic")!.accounts.map(account => account.id); + await setActiveAccount("anthropic", ids[0]!); + return ids; +} + +function quotaHeaders(fiveHour: string, weekly: string): Record { + return { + "anthropic-ratelimit-unified-5h-utilization": fiveHour, + "anthropic-ratelimit-unified-7d-utilization": weekly, + }; +} + +function limited(fiveHour = "1", weekly = "0.61"): Response { + return Response.json({ type: "error", error: { type: "rate_limit_error", message: "synthetic quota exhausted" } }, { + status: 429, + headers: { ...quotaHeaders(fiveHour, weekly), "retry-after": "30" }, + }); +} + +function answer(stream: boolean, fiveHour = "0.23", weekly = "0.47", text = "The answer is complete."): Response { + const usage = { input_tokens: 8, output_tokens: 6 }; + const message = { id: "msg_synthetic", type: "message", role: "assistant", model: "claude-sonnet-4-5", content: [{ type: "text", text }], stop_reason: "end_turn", usage }; + if (!stream) return Response.json(message, { headers: quotaHeaders(fiveHour, weekly) }); + const frames = [ + { type: "message_start", message: { ...message, content: [], stop_reason: null } }, + { type: "content_block_start", index: 0, content_block: { type: "text", text: "" } }, + { type: "content_block_delta", index: 0, delta: { type: "text_delta", text } }, + { type: "content_block_stop", index: 0 }, + { type: "message_delta", delta: { stop_reason: "end_turn" }, usage }, + { type: "message_stop" }, + ]; + return new Response(frames.map(frame => `event: ${frame.type}\ndata: ${JSON.stringify(frame)}\n\n`).join(""), { + headers: { ...quotaHeaders(fiveHour, weekly), "content-type": "text/event-stream" }, + }); +} + +function configFor(reply: (body: Record) => Response | Promise, headers?: Record): OcxConfig { + const transport = (async (_input, init) => { + const wireHeaders = new Headers(init?.headers); + const body = JSON.parse(String(init?.body)) as Record; + sent.push({ authorization: wireHeaders.get("authorization"), apiKey: wireHeaders.get("x-api-key"), body }); + return reply(body); + }) as typeof fetch; + const provider: OcxProviderConfig & { fetch: typeof fetch } = { + adapter: "anthropic", baseUrl: "https://anthropic-quota.test", authMode: "oauth", + models: ["claude-sonnet-4-5"], fetch: transport, ...(headers ? { headers } : {}), + }; + return { + port: 0, defaultProvider: "anthropic", + anthropicAccountPool: { enabled: false, strategy: "round-robin" }, + providers: { anthropic: provider }, + }; +} + +function post(config: OcxConfig, body: Record = {}) { + return handleResponses(new Request("http://localhost/v1/responses", { + method: "POST", headers: { "content-type": "application/json" }, + body: JSON.stringify({ model: "anthropic/claude-sonnet-4-5", input: "Answer briefly", stream: false, ...body }), + }), config, { model: "", provider: "" }); +} + +function expectQuota(id: string, fiveHourPercent: number, weeklyPercent: number) { + expect(getCachedProviderAccountQuota("anthropic", id)).toMatchObject({ fiveHourPercent, weeklyPercent }); +} + +function deferred() { + let resolve!: (value: T) => void; + const promise = new Promise(done => { resolve = done; }); + return { promise, resolve }; +} + +test("main A429 -> B200 records both physical responses against their sending accounts", async () => { + const [a, b] = await seed(); + const config = configFor(body => { + if (sent.length === 1) return limited(); + expect(sent.length).toBe(2); + // A must already be measured before the replacement response exists. + expectQuota(a!, 100, 61); + expect(getCachedProviderAccountQuota("anthropic", b!)).toBeNull(); + return answer(body.stream === true); + }); + const response = await post(config); + expect(response.status).toBe(200); + expect(await response.text()).toContain("The answer is complete."); + expect(sent.map(row => row.authorization)).toEqual([`Bearer ${credential(0).access}`, `Bearer ${credential(1).access}`]); + expectQuota(a!, 100, 61); + expectQuota(b!, 23, 47); +}); + +test("terminal 429 after both accounts are exhausted records both refused physical responses", async () => { + const [a, b] = await seed(); + const response = await post(configFor(() => { + if (sent.length === 1) return limited(); + expect(sent.length).toBe(2); + expectQuota(a!, 100, 61); + return limited("0.89", "1"); + })); + expect(response.status).toBe(429); + await response.text(); + expect(sent.map(row => row.authorization)).toEqual([`Bearer ${credential(0).access}`, `Bearer ${credential(1).access}`]); + expectQuota(a!, 100, 61); + expectQuota(b!, 89, 100); +}); + +test("manual active switch while A is pending keeps A's measurement off B", async () => { + const [a, b] = await seed(); + const entered = deferred(); + const returned = deferred(); + const config = configFor(() => { entered.resolve(); return returned.promise; }); + const pending = post(config); + await entered.promise; + try { + expect(sent[0]!.authorization).toBe(`Bearer ${credential(0).access}`); + expect(await setActiveAccount("anthropic", b!)).toBe(true); + } finally { + returned.resolve(answer(false, "0.37", "0.53")); + } + const response = await pending; + expect(response.status).toBe(200); + await response.text(); + expect(sent).toHaveLength(1); + expect(getAccountSet("anthropic")!.activeAccountId).toBe(b!); + expectQuota(a!, 37, 53); + expect(getCachedProviderAccountQuota("anthropic", b!)).toBeNull(); +}); + +test("credential replacement while A is pending skips its old-generation response", async () => { + const [a, b] = await seed(); + const entered = deferred(); + const returned = deferred(); + const pending = post(configFor(() => { entered.resolve(); return returned.promise; })); + await entered.promise; + try { + expect(sent[0]!.authorization).toBe(`Bearer ${credential(0).access}`); + await saveAccountCredential("anthropic", a!, { ...credential(0), access: "synthetic-replacement-access", refresh: "synthetic-replacement-refresh" }); + } finally { + returned.resolve(answer(false)); + } + const response = await pending; + expect(response.status).toBe(200); + await response.text(); + expect(sent).toHaveLength(1); + expect(getAccountSet("anthropic")!.accounts.find(row => row.id === a)!.credential.access).toBe("synthetic-replacement-access"); + expect(getCachedProviderAccountQuota("anthropic", a!)).toBeNull(); + expect(getCachedProviderAccountQuota("anthropic", b!)).toBeNull(); +}); + +const overriddenHeaders: { label: string; headers: Record; authorization: string; apiKey: string | null }[] = [ + { label: "overridden bearer", headers: { Authorization: "Bearer synthetic-override" }, authorization: "Bearer synthetic-override", apiKey: null }, + { label: "additional x-api-key", headers: { "x-api-key": "synthetic-api-key" }, authorization: `Bearer ${credential(0).access}`, apiKey: "synthetic-api-key" }, +]; +test.each(overriddenHeaders)("$label skips quota attribution even when a selected OAuth account exists", async ({ headers, authorization, apiKey }) => { + const ids = await seed(); + const response = await post(configFor(body => answer(body.stream === true), headers)); + expect(response.status).toBe(200); + await response.text(); + expect(sent).toHaveLength(1); + expect(sent[0]).toMatchObject({ authorization, apiKey }); + for (const id of ids) expect(getCachedProviderAccountQuota("anthropic", id)).toBeNull(); +}); + +test("real web-search routed loop records A429 and B200 through fetchForRequest", async () => { + const [a, b] = await seed(); + const config = configFor(body => { + // The search loop forces upstream streaming although the client asks for JSON. + expect(body.stream).toBe(true); + if (sent.length === 1) return limited(); + expect(sent.length).toBe(2); + expectQuota(a!, 100, 61); + return answer(true); + }); + config.webSearchSidecar = { backend: "anthropic", enabled: true }; + const response = await post(config, { tools: [{ type: "web_search" }] }); + expect(response.status).toBe(200); + expect(await response.text()).toContain("The answer is complete."); + expect(sent.map(row => row.authorization)).toEqual([`Bearer ${credential(0).access}`, `Bearer ${credential(1).access}`]); + expectQuota(a!, 100, 61); + expectQuota(b!, 23, 47); +}); + +test("real terminal continuation records A429 before retrying the continuation on B", async () => { + const [a, b] = await seed(); + const config = configFor(body => { + // The real guard recognizes an actionable request plus a short execution announcement, + // with available tools and no tool call. A normal completed answer does not trigger it. + if (sent.length === 1) return answer(body.stream === true, "0.11", "0.31", "I will modify the file now."); + if (sent.length === 2) { + expectQuota(a!, 11, 31); + return limited(); + } + expect(sent.length).toBe(3); + expectQuota(a!, 100, 61); + return answer(body.stream === true); + }); + const response = await post(config, { + input: "Please modify the file now", + tools: [{ type: "function", name: "read_file", description: "read a file", parameters: { type: "object" } }], + }); + expect(response.status).toBe(200); + expect(await response.text()).toContain("The answer is complete."); + expect(sent.map(row => row.authorization)).toEqual([`Bearer ${credential(0).access}`, `Bearer ${credential(0).access}`, `Bearer ${credential(1).access}`]); + expectQuota(a!, 100, 61); + expectQuota(b!, 23, 47); +}); + +test("real image bridge routed loop records A429 and B200 through fetchForRequest", async () => { + const [a, b] = await seed(); + const config = configFor(body => { + expect(body.stream).toBe(true); + // Only the bridge installs this synthetic tool for the hosted image_generation input. + expect(body.tools).toEqual(expect.arrayContaining([expect.objectContaining({ name: "custom_image_gen" })])); + if (sent.length === 1) return limited(); + expect(sent.length).toBe(2); + expectQuota(a!, 100, 61); + return answer(true); + }); + config.images = { bridgeEnabled: true }; + config.providers.xai = { + adapter: "openai-chat", baseUrl: "https://api.x.ai/v1", authMode: "key", apiKey: "synthetic-image-key", + }; + const response = await post(config, { stream: true, tools: [{ type: "image_generation" }] }); + expect(response.status).toBe(200); + expect(await response.text()).toContain("The answer is complete."); + expect(sent.map(row => row.authorization)).toEqual([`Bearer ${credential(0).access}`, `Bearer ${credential(1).access}`]); + expectQuota(a!, 100, 61); + expectQuota(b!, 23, 47); +}); diff --git a/tests/adapters/anthropic/anthropic-ratelimit-headers.test.ts b/tests/adapters/anthropic/anthropic-ratelimit-headers.test.ts new file mode 100644 index 0000000000..21ae2d8489 --- /dev/null +++ b/tests/adapters/anthropic/anthropic-ratelimit-headers.test.ts @@ -0,0 +1,528 @@ +/** Anthropic response observations must preserve account usage and probe semantics. */ +import { afterEach, beforeEach, describe, expect, test } from "bun:test"; +import { mkdtempSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { + clearAnthropicAccountCooldown, + clearAnthropicAccountPoolState, + forgetAnthropicFailoverQuorum, + getAnthropicAccountHealthSnapshot, + rotateAnthropicAccountOn429, +} from "../../../src/oauth/anthropic-routing"; +import { projectStoredOAuthAccountHealth } from "../../../src/oauth/health"; +import { + clearAccountQuotaCache, + fetchProviderAccountQuotas, + getCachedProviderAccountQuota, + parseAnthropicRateLimitHeaders, + recordAnthropicAccountQuotaFromHeaders, + reconcileProviderAccountQuotaRows, + resetProviderQuotaReconcileStateForTests, + setCachedProviderAccountQuotaForTests, + sweepExpiredProviderAccountQuotaRows, +} from "../../../src/providers/quota"; +import { getAccountSet, saveCredential } from "../../../src/oauth/store"; +import { clearPoolRotationState } from "../../../src/codex/pool-rotation"; +import { removeTreeWithRetry } from "../../helpers/remove-tree"; +import type { OcxConfig } from "../../../src/types"; + +const originalHome = process.env.OPENCODEX_HOME; +const originalFetch = globalThis.fetch; +const originalNow = Date.now; +let home: string; + +beforeEach(() => { + globalThis.fetch = (async () => { throw new Error("Unexpected network request in quota test"); }) as typeof fetch; + home = mkdtempSync(join(tmpdir(), "ocx-anthropic-ratelimit-")); + process.env.OPENCODEX_HOME = home; + clearAnthropicAccountPoolState(); + clearPoolRotationState(); + clearAccountQuotaCache(); + // `lastReconciledGeneration` is module-global and survives a cache clear, so the fence case + // below would otherwise raise the floor for every test that runs after it in this file. + resetProviderQuotaReconcileStateForTests(); + forgetAnthropicFailoverQuorum(); +}); + +afterEach(() => { + globalThis.fetch = originalFetch; + Date.now = originalNow; + clearAnthropicAccountPoolState(); + clearPoolRotationState(); + // The argument-less form, deliberately: only it calls cancelPendingAccountQuotaPersist. + // The observer ends in a 250ms-debounced write that resolves OPENCODEX_HOME at fire time, + // so a provider-scoped clear would leave that write to land in whatever home is current a + // quarter second later — the next test's sandbox, or the developer's real one. + clearAccountQuotaCache(); + resetProviderQuotaReconcileStateForTests(); + forgetAnthropicFailoverQuorum(); + if (originalHome === undefined) delete process.env.OPENCODEX_HOME; + else process.env.OPENCODEX_HOME = originalHome; + removeTreeWithRetry(home); +}); + +/** The store assigns its own slot ids, so the seeded `accountId` is never the cache key. */ +async function seed(count: number): Promise { + for (let i = 0; i < count; i++) { + await saveCredential("anthropic", { + access: `access-${i}`, + refresh: `refresh-${i}`, + expires: Date.now() + 3_600_000, + accountId: `uuid-${i}`, + email: `user${i}@example.test`, + } as never); + } + return getAccountSet("anthropic")?.accounts.map(a => a.id) ?? []; +} + +function poolEnabled(): OcxConfig { + return { + port: 0, + defaultProvider: "anthropic", + providers: { + anthropic: { adapter: "anthropic", baseUrl: "https://api.anthropic.com", authMode: "oauth" }, + }, + anthropicAccountPool: { enabled: true }, + } as OcxConfig; +} + +/** A real 429 from a drained five-hour window, captured from api.anthropic.com. */ +function drainedFiveHour(resetEpochSeconds: number): Headers { + return new Headers({ + "anthropic-ratelimit-unified-status": "rejected", + "anthropic-ratelimit-unified-5h-status": "rejected", + "anthropic-ratelimit-unified-5h-reset": String(resetEpochSeconds), + "anthropic-ratelimit-unified-5h-utilization": "1.0", + "anthropic-ratelimit-unified-7d-status": "allowed", + "anthropic-ratelimit-unified-7d-reset": String(resetEpochSeconds + 86_400), + "anthropic-ratelimit-unified-7d-utilization": "0.36", + }); +} + +describe("Anthropic cooldown honours the stated window", () => { + test("a multi-hour Retry-After is not truncated to the guessed-backoff ceiling", async () => { + const start = Date.now(); + const ids = await seed(2); + // 7999s is what a drained five-hour window actually answers; the old 15-minute clamp + // turned a single refusal into sixteen wasted retries before the window reopened. + rotateAnthropicAccountOn429(poolEnabled(), ids[0]!, "7999", null, start); + const health = getAnthropicAccountHealthSnapshot(ids[0]!, start); + expect(health?.cooldownUntil).toBe(start + 7_999_000); + expect(health?.cooldownSource).toBe("retry-after"); + }); + + test("a week-long Retry-After retains its stated deadline", async () => { + const start = Date.now(); + const ids = await seed(2); + rotateAnthropicAccountOn429(poolEnabled(), ids[0]!, "604800", null, start); + expect(getAnthropicAccountHealthSnapshot(ids[0]!, start)?.cooldownUntil) + .toBe(start + 604_800_000); + }); + + test("an HTTP-date Retry-After is honoured beyond six hours", async () => { + const start = Date.now(); + const ids = await seed(2); + // RFC 9110 allows either form, and both are upstream STATING when it will serve again -- + // the date branch had its own clamp and would have kept the 15-minute truncation. + rotateAnthropicAccountOn429(poolEnabled(), ids[0]!, new Date(start + 2 * 60 * 60_000).toUTCString(), null, start); + const cooldown = getAnthropicAccountHealthSnapshot(ids[0]!, start)?.cooldownUntil; + // toUTCString drops sub-second precision, so the deadline lands within a second of target. + expect(cooldown).toBeGreaterThan(start + 2 * 60 * 60_000 - 1_000); + expect(cooldown).toBeLessThanOrEqual(start + 2 * 60 * 60_000); + + const reset = Math.floor(start / 1000) * 1000 + 48 * 60 * 60_000; + rotateAnthropicAccountOn429(poolEnabled(), ids[1]!, new Date(reset).toUTCString(), null, start); + expect(getAnthropicAccountHealthSnapshot(ids[1]!, start)?.cooldownUntil).toBe(reset); + }); + + test("a 429 without Retry-After cools until the rejected window reopens", async () => { + const start = Date.now(); + const ids = await seed(2); + // The wire carries whole seconds, so the reset is built from an epoch second and the + // expectation is derived from the same value rather than from `start + 90min` — an + // assertion on the un-truncated millisecond would be testing the fixture, not the code. + const resetEpochSeconds = Math.floor((start + 90 * 60_000) / 1000); + // Retry-After is not guaranteed on an Anthropic 429; the rejected window's reset is. + // Without reading it this refusal cooled for the 60s default and the drained account + // was back in the rotation a minute later. + rotateAnthropicAccountOn429(poolEnabled(), ids[0]!, null, null, start, drainedFiveHour(resetEpochSeconds)); + const health = getAnthropicAccountHealthSnapshot(ids[0]!, start); + expect(health?.cooldownUntil).toBe(resetEpochSeconds * 1000); + // Its own source, not "retry-after": the dashboard renders that one as request-rate + // throttling, and a spent five-hour window is quota. Same vocabulary the Codex pool uses. + expect(health?.cooldownSource).toBe("reset-derived"); + }); + + test("an ALLOWED window's reset never cools the account", async () => { + const start = Date.now(); + const ids = await seed(2); + // Every response names when the current period ends, including a healthy one. Treating + // that as a cooldown would bench an account with 4% used for the rest of its window. + const healthy = new Headers({ + "anthropic-ratelimit-unified-status": "allowed", + "anthropic-ratelimit-unified-5h-status": "allowed", + "anthropic-ratelimit-unified-5h-reset": String(Math.floor((start + 3 * 60 * 60_000) / 1000)), + "anthropic-ratelimit-unified-5h-utilization": "0.04", + }); + rotateAnthropicAccountOn429(poolEnabled(), ids[0]!, null, null, start, healthy); + const health = getAnthropicAccountHealthSnapshot(ids[0]!, start); + expect(health?.cooldownUntil).toBe(start + 60_000); + expect(health?.cooldownSource).toBe("default"); + }); + + test("both windows rejected cools until the LAST one reopens", async () => { + const start = Date.now(); + const ids = await seed(2); + // The limiter is AND-composed: upstream refuses while ANY window rejects. An account whose + // 5-hour bucket rolls in three minutes is still refused for the days its weekly window + // needs, so cooling to the earliest reset would re-offer it every three minutes until the + // weekly window finally reopens -- the exact loop this path exists to end. + const fiveHourReset = Math.floor((start + 3 * 60_000) / 1000); + const weeklyReset = Math.floor((start + 5 * 24 * 60 * 60_000) / 1000); + const bothDrained = new Headers({ + "anthropic-ratelimit-unified-status": "rejected", + "anthropic-ratelimit-unified-5h-status": "rejected", + "anthropic-ratelimit-unified-5h-reset": String(fiveHourReset), + "anthropic-ratelimit-unified-7d-status": "rejected", + "anthropic-ratelimit-unified-7d-reset": String(weeklyReset), + }); + rotateAnthropicAccountOn429(poolEnabled(), ids[0]!, null, null, start, bothDrained); + expect(getAnthropicAccountHealthSnapshot(ids[0]!, start)?.cooldownUntil).toBe(weeklyReset * 1000); + }); + + test("a reset-derived cooldown surfaces as quota, a Retry-After as a rate limit", async () => { + const start = Date.now(); + const ids = await seed(2); + const account = getAccountSet("anthropic")!.accounts.find(a => a.id === ids[0]!)!; + // The distinction is not cosmetic: the dashboard tells an operator to wait out a rate + // limit and to switch accounts on spent quota. A drained five-hour window is the second. + rotateAnthropicAccountOn429( + poolEnabled(), + ids[0]!, + null, + null, + start, + drainedFiveHour(Math.floor((start + 90 * 60_000) / 1000)), + ); + expect(projectStoredOAuthAccountHealth("anthropic", account, start)).toMatchObject({ + status: "cooldown", + reason: "quota", + }); + + clearAnthropicAccountCooldown(ids[0]!); + rotateAnthropicAccountOn429(poolEnabled(), ids[0]!, "300", null, start); + expect(projectStoredOAuthAccountHealth("anthropic", account, start)).toMatchObject({ + status: "cooldown", + reason: "rate_limit", + }); + }); + + test("Retry-After wins over the header reset", async () => { + const start = Date.now(); + const ids = await seed(2); + // Retry-After is written for this decision; the reset epoch is a fallback for the + // refusals that omit it. A disagreement must not silently prefer the fallback. + rotateAnthropicAccountOn429( + poolEnabled(), + ids[0]!, + "120", + null, + start, + drainedFiveHour(Math.floor((start + 4 * 60 * 60_000) / 1000)), + ); + expect(getAnthropicAccountHealthSnapshot(ids[0]!, start)?.cooldownUntil).toBe(start + 120_000); + }); +}); + +describe("Anthropic rate-limit headers feed the routing cache", () => { + test("utilization is read as a fraction, not as a percent", () => { + // The header sends 0.74 for a 74%-spent window while the probe endpoint sends 74.0 for + // the same account. Passing the header value through unscaled would file the emptiest + // account as the freshest and route every new session straight at it. + const quota = parseAnthropicRateLimitHeaders(new Headers({ + "anthropic-ratelimit-unified-5h-utilization": "0.42", + "anthropic-ratelimit-unified-7d-utilization": "0.74", + })); + expect(quota?.fiveHourPercent).toBe(42); + expect(quota?.weeklyPercent).toBe(74); + }); + + test("reset epochs are promoted from seconds to milliseconds", () => { + const quota = parseAnthropicRateLimitHeaders(new Headers({ + "anthropic-ratelimit-unified-5h-utilization": "0.5", + "anthropic-ratelimit-unified-5h-reset": "1788717000", + })); + expect(quota?.fiveHourResetAt).toBe(1_788_717_000_000); + }); + + test("a header set with no utilization yields no measurement", () => { + // A renamed or dropped header must degrade to "unmeasured", which the router already + // has a defined behaviour for -- never to a fabricated zero, which reads as a fresh + // account and would pull traffic toward whichever account stopped reporting. + expect(parseAnthropicRateLimitHeaders(new Headers({ + "anthropic-ratelimit-unified-5h-reset": "1788717000", + }))).toBeNull(); + }); + + test("a utilization above 1 is rejected rather than clamped", () => { + // Above one is a wire change, not a full window. Inventing 100 from it would cool a + // healthy account on a misread. + expect(parseAnthropicRateLimitHeaders(new Headers({ + "anthropic-ratelimit-unified-5h-utilization": "42", + }))).toBeNull(); + }); + + test("an observed turn makes the serving account's usage known to the router", async () => { + const ids = await seed(2); + // Before the observation the account has no reading at all, which is what left a + // two-account pool scoring both at UNKNOWN_USAGE_SCORE and picking between them blind. + expect(getCachedProviderAccountQuota("anthropic", ids[0]!)).toBeNull(); + recordAnthropicAccountQuotaFromHeaders(ids[0]!, drainedFiveHour(Math.floor(Date.now() / 1000) + 3600), 0); + expect(getCachedProviderAccountQuota("anthropic", ids[0]!)?.fiveHourPercent).toBe(100); + // The other account stays unmeasured: an observation is attributed to the account that + // served the turn, never spread across the roster. + expect(getCachedProviderAccountQuota("anthropic", ids[1]!)).toBeNull(); + }); + + test("headers with nothing parseable leave the previous reading intact", async () => { + const ids = await seed(1); + recordAnthropicAccountQuotaFromHeaders(ids[0]!, new Headers({ + "anthropic-ratelimit-unified-5h-utilization": "0.25", + }), 0); + recordAnthropicAccountQuotaFromHeaders(ids[0]!, new Headers({ "content-type": "application/json" }), 0); + // A response that says nothing about quota is not evidence that the quota is gone. + expect(getCachedProviderAccountQuota("anthropic", ids[0]!)?.fiveHourPercent).toBe(25); + }); + + test("an empty account id writes nothing", () => { + // API-key providers and single-account installs below failover quorum reach the observer + // with no account to attribute; that is an ordinary state, not an error. Asserting only + // that it does not throw would pass with the guard deleted -- an empty-string cache key + // is perfectly writable -- so this asserts the absence of the row instead. + recordAnthropicAccountQuotaFromHeaders("", drainedFiveHour(Math.floor(Date.now() / 1000) + 3600), 0); + expect(getCachedProviderAccountQuota("anthropic", "")).toBeNull(); + }); + + test("a stale writer generation is refused", async () => { + const ids = await seed(1); + // The fence exists because a turn is a long await: an account or config change that lands + // mid-turn must not be overwritten by a measurement taken before it. Every other test here + // passes 0, which a fresh worker always accepts, so without this case the parameter is + // carried but never actually exercised as a fence. + reconcileProviderAccountQuotaRows({ + generation: 5, + providerNames: new Set(), + comboIds: new Set(), + comboTargets: new Set(), + codexAccountIds: new Set(), + oauthAccountKeys: new Set(), + configRoots: new Set(), + }); + recordAnthropicAccountQuotaFromHeaders(ids[0]!, new Headers({ + "anthropic-ratelimit-unified-5h-utilization": "0.5", + }), 1); + expect(getCachedProviderAccountQuota("anthropic", ids[0]!)).toBeNull(); + }); + + test("an observation keeps the model-scoped bars the probe filled", async () => { + const ids = await seed(1); + // The probe reports per-model weekly limits (Opus, Sonnet, Fable) that no header carries. + // They are read by the manual-preference exhaustion check and by `headroomOf`, so a + // wholesale replace would not merely blank the dashboard: it would route an Opus request + // to an account whose Opus allowance is spent. + setCachedProviderAccountQuotaForTests("anthropic", ids[0]!, { + fiveHourPercent: 10, + weeklyPercent: 20, + customWindows: [{ label: "Opus", percent: 96 }], + updatedAt: Date.now(), + }); + recordAnthropicAccountQuotaFromHeaders(ids[0]!, new Headers({ + "anthropic-ratelimit-unified-5h-utilization": "0.41", + }), 0); + const quota = getCachedProviderAccountQuota("anthropic", ids[0]!); + expect(quota?.fiveHourPercent).toBe(41); + // Untouched by this observation, not erased by it. + expect(quota?.weeklyPercent).toBe(20); + expect(quota?.customWindows).toEqual([{ label: "Opus", percent: 96 }]); + }); + + test("a percent that is not exactly representable is rounded, not left as an artifact", () => { + // `0.29 * 100` is 28.999999999999996 in binary floating point, and the CLI interpolates the + // percent raw. A user reading `5h 28.999999999999996%` would reasonably file a bug. + expect(parseAnthropicRateLimitHeaders(new Headers({ + "anthropic-ratelimit-unified-5h-utilization": "0.29", + }))?.fiveHourPercent).toBe(29); + }); +}); + +describe("Anthropic observation and probe clocks", () => { + function observe(accountId: string, percent = "0.41"): void { + recordAnthropicAccountQuotaFromHeaders(accountId, new Headers({ + "anthropic-ratelimit-unified-5h-utilization": percent, + }), 0); + } + + function usageResponse(): Response { + return Response.json({ five_hour: { utilization: 12 }, seven_day_opus: { utilization: 63 } }); + } + + test("a cold header-only row does not defer the first usage probe", async () => { + const [id] = await seed(1); + let calls = 0; + globalThis.fetch = (async () => { calls++; return usageResponse(); }) as typeof fetch; + observe(id!); + expect(getCachedProviderAccountQuota("anthropic", id!)?.fiveHourPercent).toBe(41); + const [row] = await fetchProviderAccountQuotas("anthropic"); + expect(calls).toBe(1); + expect(row?.quota).toMatchObject({ fiveHourPercent: 12, customWindows: [{ label: "Opus", percent: 63 }] }); + expect(row?.unavailable).toBeUndefined(); + }); + + test("fresh header observations survive sweeping until their own TTL expires", async () => { + const [id] = await seed(1); + const observedAt = originalNow(); + Date.now = () => observedAt; + observe(id!); + expect(sweepExpiredProviderAccountQuotaRows(observedAt + 1)).toBe(0); + expect(getCachedProviderAccountQuota("anthropic", id!)?.fiveHourPercent).toBe(41); + expect(sweepExpiredProviderAccountQuotaRows(observedAt + 10 * 60_000 - 1)).toBe(0); + expect(sweepExpiredProviderAccountQuotaRows(observedAt + 10 * 60_000)).toBe(1); + expect(getCachedProviderAccountQuota("anthropic", id!)).toBeNull(); + }); + + test("headers preserve the probe TTL instead of renewing it", async () => { + const [id] = await seed(1); + let now = originalNow(); + Date.now = () => now; + let calls = 0; + globalThis.fetch = (async () => { calls++; return usageResponse(); }) as typeof fetch; + await fetchProviderAccountQuotas("anthropic"); + now += 9 * 60_000; + observe(id!); + expect((await fetchProviderAccountQuotas("anthropic"))[0]?.quota?.fiveHourPercent).toBe(41); + expect(calls).toBe(1); + now += 60_001; + await fetchProviderAccountQuotas("anthropic"); + expect(calls).toBe(2); + }); + + for (const observeAfterRestart of [false, true]) { + test(`restart keeps Anthropic probes due with new headers: ${observeAfterRestart}`, async () => { + const [id] = await seed(1); + const updatedAt = Date.now(); + const saved = { fiveHourPercent: 41, customWindows: [{ label: "Opus", percent: 63 }], updatedAt }; + writeFileSync(join(home, "provider-account-quota-cache.json"), JSON.stringify({ + version: 1, + rows: { [`anthropic\u0000${id}`]: saved, "kiro\u0000other": { monthlyPercent: 17, updatedAt } }, + })); + clearAccountQuotaCache(); + // Cover both dashboard-first and response-first hydration after restart. + if (observeAfterRestart) observe(id!, "0.52"); + let calls = 0; + globalThis.fetch = (async () => { calls++; return new Response("busy", { status: 429 }); }) as typeof fetch; + const [row] = await fetchProviderAccountQuotas("anthropic"); + expect(calls).toBe(1); + expect(row?.quota).toMatchObject({ fiveHourPercent: observeAfterRestart ? 52 : 41, customWindows: saved.customWindows }); + expect(getCachedProviderAccountQuota("kiro", "other")?.monthlyPercent).toBe(17); + expect(row?.unavailable).toBe(true); + }); + } + + for (const [failure, warm] of [["http", true], ["network", true], ["http", false]] as const) { + test(`joined ${failure} probe failures preserve in-flight headers (warm cache: ${warm})`, async () => { + const [id] = await seed(1); + if (warm) setCachedProviderAccountQuotaForTests("anthropic", id!, { + fiveHourPercent: 10, weeklyPercent: 20, customWindows: [{ label: "Opus", percent: 63 }], updatedAt: Date.now(), + }); + let started!: () => void; + const dispatched = new Promise(resolve => { started = resolve; }); + let finish!: (response: Response) => void; + let fail!: (error: Error) => void; + const response = new Promise((resolve, reject) => { finish = resolve; fail = reject; }); + let calls = 0; + globalThis.fetch = (async () => { calls++; started(); return response; }) as typeof fetch; + const first = fetchProviderAccountQuotas("anthropic", true); + await dispatched; + const second = fetchProviderAccountQuotas("anthropic", true); + observe(id!); + const latest = getCachedProviderAccountQuota("anthropic", id!); + if (failure === "http") finish(new Response("busy", { status: 429 })); + else fail(new Error("offline")); + const [a, b] = await Promise.all([first, second]); + expect(calls).toBe(1); + expect(a).toEqual(b); + expect(a[0]?.quota).toEqual(latest); + expect(a[0]?.quota?.fiveHourPercent).toBe(41); + if (warm) expect(a[0]?.quota).toMatchObject({ weeklyPercent: 20, customWindows: [{ label: "Opus", percent: 63 }] }); + expect(a[0]?.unavailable).toBe(true); + expect(getCachedProviderAccountQuota("anthropic", id!)).toEqual(latest); + // A later partial observation cannot claim that the failed usage probe succeeded. + observe(id!, "0.53"); + const [cached] = await fetchProviderAccountQuotas("anthropic"); + expect(cached?.unavailable).toBe(true); + expect(cached?.quota?.fiveHourPercent).toBe(53); + expect(calls).toBe(1); + globalThis.fetch = (async () => usageResponse()) as typeof fetch; + expect((await fetchProviderAccountQuotas("anthropic", true))[0]?.unavailable).toBeUndefined(); + }); + } +}); + +describe("Anthropic malformed deadlines and partial windows", () => { + for (const invalid of ["NaN", "Infinity", "1e309", "1e308", "8640000000001", "not-a-date", "-1", "0"]) { + test(`invalid reset ${invalid} cannot establish a cooldown deadline`, async () => { + const start = Date.now(); + const [id] = await seed(1); + const headers = new Headers({ + "anthropic-ratelimit-unified-7d-status": "rejected", + "anthropic-ratelimit-unified-7d-reset": invalid, + "anthropic-ratelimit-unified-7d-utilization": "0.74", + }); + rotateAnthropicAccountOn429(poolEnabled(), id!, null, null, start, headers); + expect(getAnthropicAccountHealthSnapshot(id!, start)).toMatchObject({ + cooldownUntil: start + 60_000, cooldownSource: "default", + }); + expect(parseAnthropicRateLimitHeaders(headers)?.weeklyResetAt).toBeUndefined(); + }); + } + + test("overflowing Retry-After falls back to a valid rejected reset", async () => { + const start = Date.now(); + const [id] = await seed(1); + const reset = Math.floor(start / 1000) + 432_000; + for (const invalid of ["9".repeat(400), "8640000000001", "invalid-date"]) { + rotateAnthropicAccountOn429(poolEnabled(), id!, invalid, null, start, drainedFiveHour(reset)); + expect(getAnthropicAccountHealthSnapshot(id!, start)).toMatchObject({ + cooldownUntil: reset * 1000, cooldownSource: "reset-derived", + }); + } + }); + + test("a malformed weekly deadline cannot hide a valid five-hour reset", async () => { + const start = Date.now(); + const [id] = await seed(1); + const reset = Math.floor(start / 1000) + 180; + const headers = drainedFiveHour(reset); + headers.set("anthropic-ratelimit-unified-7d-status", "rejected"); + headers.set("anthropic-ratelimit-unified-7d-reset", "1e308"); + rotateAnthropicAccountOn429(poolEnabled(), id!, null, null, start, headers); + expect(getAnthropicAccountHealthSnapshot(id!, start)?.cooldownUntil).toBe(reset * 1000); + }); + + test("partial zero utilization preserves other and model-specific windows", async () => { + const [id] = await seed(1); + const customWindows = [{ label: "Opus", percent: 63 }]; + setCachedProviderAccountQuotaForTests("anthropic", id!, { + fiveHourPercent: 10, weeklyPercent: 20, weeklyResetAt: 1_800_000_000_000, customWindows, updatedAt: Date.now(), + }); + recordAnthropicAccountQuotaFromHeaders(id!, new Headers({ + "anthropic-ratelimit-unified-5h-utilization": "0", + "anthropic-ratelimit-unified-7d-utilization": "NaN", + "anthropic-ratelimit-unified-7d-reset": "1e308", + }), 0); + expect(getCachedProviderAccountQuota("anthropic", id!)).toMatchObject({ + fiveHourPercent: 0, weeklyPercent: 20, weeklyResetAt: 1_800_000_000_000, customWindows, + }); + }); +}); diff --git a/tests/adapters/anthropic/anthropic-sidecar-account-failover.test.ts b/tests/adapters/anthropic/anthropic-sidecar-account-failover.test.ts index 31b2389fb8..8d094db631 100644 --- a/tests/adapters/anthropic/anthropic-sidecar-account-failover.test.ts +++ b/tests/adapters/anthropic/anthropic-sidecar-account-failover.test.ts @@ -8,10 +8,11 @@ import { afterAll, afterEach, beforeAll, beforeEach, expect, mock, test } from " import { mkdtempSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; -import type { ProviderAdapter } from "../../../src/adapters/base"; +import type { AdapterRequest, IncomingMeta, ProviderAdapter } from "../../../src/adapters/base"; import { clearAnthropicAccountPoolState } from "../../../src/oauth/anthropic-routing"; import { clearGenericFailoverHealth } from "../../../src/oauth/generic-account-failover"; import { getAccountSet, saveCredential, setActiveAccount } from "../../../src/oauth/store"; +import { clearAccountQuotaCache, getCachedProviderAccountQuota, resetProviderQuotaReconcileStateForTests } from "../../../src/providers/quota"; import type { OcxConfig, OcxParsedRequest, OcxProviderConfig } from "../../../src/types"; import { removeTreeWithRetry } from "../../helpers/remove-tree"; @@ -66,15 +67,24 @@ beforeAll(async () => { runWithWebSearch: async (args: { parsed: OcxParsedRequest; adapter: ProviderAdapter; + incomingMeta: IncomingMeta; + fetchForRequest: (request: AdapterRequest, parsed: OcxParsedRequest) => typeof fetch; on429?: (retryAfter: string | null) => Promise; }) => { - const first = await args.adapter.buildRequest(args.parsed); - observedKeys.push(new Headers(first.headers).get("authorization") ?? ""); - const rotated = await args.on429?.("30"); + // This is a dispatch seam test. The real loop is covered in anthropic-quota-dispatch. + const first = await args.adapter.buildRequest(args.parsed, args.incomingMeta); + const refused = await args.fetchForRequest(first, args.parsed)(first.url, { + method: first.method, headers: first.headers, body: first.body, + }); + expect(refused.status).toBe(429); + const retryAfter = refused.headers.get("retry-after"); + await refused.body?.cancel(); + const rotated = await args.on429?.(retryAfter); if (!rotated) throw new Error("Anthropic sidecar did not rotate after 429"); - const second = await rotated.buildRequest(args.parsed); - observedKeys.push(new Headers(second.headers).get("authorization") ?? ""); - return new Response("sidecar-ok", { status: 200 }); + const second = await rotated.buildRequest(args.parsed, args.incomingMeta); + return args.fetchForRequest(second, args.parsed)(second.url, { + method: second.method, headers: second.headers, body: second.body, + }); }, })); @@ -88,11 +98,15 @@ beforeEach(() => { sidecarMode = false; clearAnthropicAccountPoolState(); clearGenericFailoverHealth(); + clearAccountQuotaCache(); + resetProviderQuotaReconcileStateForTests(); }); afterEach(() => { clearAnthropicAccountPoolState(); clearGenericFailoverHealth(); + clearAccountQuotaCache(); + resetProviderQuotaReconcileStateForTests(); removeTreeWithRetry(testHome); }); @@ -102,7 +116,7 @@ afterAll(() => { mock.restore(); }); -test("Anthropic web-search sidecar rotates on 429 when proactive pooling is disabled", async () => { +test("Anthropic sidecar dispatch seam records A429 and B200 when proactive pooling is disabled", async () => { sidecarMode = true; for (let index = 0; index < 2; index += 1) { await saveCredential("anthropic", { @@ -110,7 +124,7 @@ test("Anthropic web-search sidecar rotates on 429 when proactive pooling is disa refresh: `anthropic-refresh-${index}`, expires: Date.now() + 3_600_000, accountId: `anthropic-account-${index}`, - } as never, { addAccount: true }); + }); } const ids = getAccountSet("anthropic")!.accounts.map(account => account.id); await setActiveAccount("anthropic", ids[0]!); @@ -125,6 +139,27 @@ test("Anthropic web-search sidecar rotates on 429 when proactive pooling is disa baseUrl: "https://anthropic-sidecar.test/v1", authMode: "oauth", models: ["model"], + fetch: (async (_input, init) => { + observedKeys.push(new Headers(init?.headers).get("authorization") ?? ""); + if (observedKeys.length === 1) { + return new Response("rate limited", { + status: 429, + headers: { + "retry-after": "30", + "anthropic-ratelimit-unified-5h-utilization": "1", + "anthropic-ratelimit-unified-7d-utilization": "0.61", + }, + }); + } + expect(observedKeys).toHaveLength(2); + expect(getCachedProviderAccountQuota("anthropic", ids[0]!)).toMatchObject({ fiveHourPercent: 100, weeklyPercent: 61 }); + return new Response("sidecar-ok", { + headers: { + "anthropic-ratelimit-unified-5h-utilization": "0.23", + "anthropic-ratelimit-unified-7d-utilization": "0.47", + }, + }); + }) as typeof fetch, }, }, } as unknown as OcxConfig; @@ -146,4 +181,6 @@ test("Anthropic web-search sidecar rotates on 429 when proactive pooling is disa "Bearer anthropic-access-0", "Bearer anthropic-access-1", ]); + expect(getCachedProviderAccountQuota("anthropic", ids[0]!)).toMatchObject({ fiveHourPercent: 100, weeklyPercent: 61 }); + expect(getCachedProviderAccountQuota("anthropic", ids[1]!)).toMatchObject({ fiveHourPercent: 23, weeklyPercent: 47 }); }); diff --git a/tests/fixtures/test-layout-expected.json b/tests/fixtures/test-layout-expected.json index 6565f12821..2a1cac7ec3 100644 --- a/tests/fixtures/test-layout-expected.json +++ b/tests/fixtures/test-layout-expected.json @@ -39,6 +39,8 @@ "anthropic-image-retry.test.ts": "adapters/anthropic", "anthropic-pool-toggle-copy.test.ts": "adapters/anthropic", "anthropic-quorum-cache.test.ts": "routing", + "anthropic-quota-dispatch.test.ts": "adapters/anthropic", + "anthropic-ratelimit-headers.test.ts": "adapters/anthropic", "anthropic-reasoning.test.ts": "adapters/anthropic", "anthropic-sidecar-account-failover.test.ts": "adapters/anthropic", "anthropic-stream-hardening.test.ts": "adapters/anthropic", From 12b174ebc90e980970024445825f6b49a374154c Mon Sep 17 00:00:00 2001 From: JUN <243035832+lidge-jun@users.noreply.github.com> Date: Mon, 7 Sep 2026 07:42:22 +0900 Subject: [PATCH 018/412] fix(claude): preserve signed and opaque replay block boundaries Preserve empty signed and redacted-only replay items, keep signature updates within their source thinking block, and emit opaque blocks in order. Retain hidden-summary policy and document deferred Claude hidden-text replay and live/cache claims. Add exact-array synthetic round-trip coverage; local tests and typecheck intentionally not run, pending parent combined remote CI. Co-authored-by: SB Yoon <44089734+yansigit@users.noreply.github.com> Co-authored-by: Yumi --- .../src/content/docs/fr/guides/claude-code.md | 2 + .../src/content/docs/guides/claude-code.md | 2 + .../src/content/docs/ja/guides/claude-code.md | 2 + .../src/content/docs/ko/guides/claude-code.md | 2 + .../src/content/docs/ru/guides/claude-code.md | 2 + .../src/content/docs/tr/guides/claude-code.md | 2 + .../content/docs/zh-cn/guides/claude-code.md | 2 + .../content/docs/zh-tw/guides/claude-code.md | 2 + src/adapters/anthropic.ts | 11 +- src/bridge.ts | 34 +++- src/claude/outbound.ts | 11 +- src/responses/parser.ts | 19 +- .../anthropic-thinking-signature.test.ts | 188 +++++++++++++++++- .../claude-outbound.test.ts | 17 ++ tests/responses/reasoning-envelope.test.ts | 4 +- 15 files changed, 277 insertions(+), 23 deletions(-) diff --git a/docs-site/src/content/docs/fr/guides/claude-code.md b/docs-site/src/content/docs/fr/guides/claude-code.md index ffc3ad6e88..7f1c0a54aa 100644 --- a/docs-site/src/content/docs/fr/guides/claude-code.md +++ b/docs-site/src/content/docs/fr/guides/claude-code.md @@ -506,6 +506,8 @@ Le proxy traduit chaque requête Anthropic Messages API au format Codex Response | `max_tokens` | `max_output_tokens` | | `stop_sequences` | `stop` | +Sur l’adaptateur Anthropic prévu, les blocs signés non masqués (y compris thinking vide) et les blocs redacted opaques sont préservés. `hideThinkingSummary` reste inchangé : le texte signé masqué localement n’est pas exposé aux clients Claude ; sa relecture sans perte via cette frontière reste non établie. Les anciennes enveloppes combinées ne permettent pas de rétablir l’ordre après émission du texte en streaming. `claudeCode.compatibility: "enforce"` refuse toujours la relecture thinking. Cela ne prouve ni l’acceptation réelle par Anthropic ni une amélioration du cache ; [#3719](https://github.com/lidge-jun/opencodex/issues/3719) reste ouvert. + **Cas d'erreur (400) :** JSON mal formé ; `model` absent ou vide ; `messages` absent ou vide ; rôle non pris en charge ; `tool_result` sans `tool_use_id` ; `tool_use` sans identifiant ni nom ; `tool_choice` nommé sans nom. diff --git a/docs-site/src/content/docs/guides/claude-code.md b/docs-site/src/content/docs/guides/claude-code.md index b237955adb..f1c1bfbfe1 100644 --- a/docs-site/src/content/docs/guides/claude-code.md +++ b/docs-site/src/content/docs/guides/claude-code.md @@ -519,6 +519,8 @@ The proxy translates every Anthropic Messages API request into the Codex Respons | `max_tokens` | `max_output_tokens` | | `stop_sequences` | `stop` | +Replay preserves non-hidden signed blocks (including empty thinking) and opaque redacted blocks on the intended Anthropic adapter. `hideThinkingSummary` remains unchanged: locally hidden signed text is not exposed to Claude clients, and lossless replay through that hidden Claude boundary is not established. Older combined reasoning envelopes cannot recover original block order once streaming text has been emitted. `claudeCode.compatibility: "enforce"` still rejects thinking replay. This does not establish live Anthropic acceptance or cache-hit improvements; [#3719](https://github.com/lidge-jun/opencodex/issues/3719) remains open. + **Error cases (400):** malformed JSON; missing/empty `model`; missing/empty `messages`; unsupported role; `tool_result` without `tool_use_id`; `tool_use` without id/name; named `tool_choice` without name. diff --git a/docs-site/src/content/docs/ja/guides/claude-code.md b/docs-site/src/content/docs/ja/guides/claude-code.md index 43b8bcee24..2445e7fa3a 100644 --- a/docs-site/src/content/docs/ja/guides/claude-code.md +++ b/docs-site/src/content/docs/ja/guides/claude-code.md @@ -374,6 +374,8 @@ Claude Code の `/effort` 設定はアダプターでも維持されます。 | `max_tokens` | `max_output_tokens` | | `stop_sequences` | `stop` | +意図した Anthropic アダプターでは、非表示でない署名付きブロック(空の thinking を含む)と不透明な redacted ブロックを保持します。`hideThinkingSummary` は変更しません。ローカルで隠した署名付きテキストは Claude クライアントに公開せず、この非表示境界での無損失再生は未確認です。旧形式の結合エンベロープは、テキスト送信後に元のブロック順を復元できません。`claudeCode.compatibility: "enforce"` は引き続き thinking 再生を拒否します。実際の Anthropic 受理やキャッシュ改善の証明ではなく、[#3719](https://github.com/lidge-jun/opencodex/issues/3719) は未解決です。 + **エラー条件(400):** 不正な JSON、欠落または空の `model`、欠落または空の `messages`、未サポートの role、`tool_use_id` のない `tool_result`、id/name のない `tool_use`、name のない名前指定 `tool_choice` です。 diff --git a/docs-site/src/content/docs/ko/guides/claude-code.md b/docs-site/src/content/docs/ko/guides/claude-code.md index 0964f2ff49..4e3535d821 100644 --- a/docs-site/src/content/docs/ko/guides/claude-code.md +++ b/docs-site/src/content/docs/ko/guides/claude-code.md @@ -412,6 +412,8 @@ Claude Code의 `/effort` 설정은 어댑터에서도 유지돼요. | `max_tokens` | `max_output_tokens` | | `stop_sequences` | `stop` | +의도한 Anthropic 어댑터에서는 숨기지 않은 서명 블록(빈 thinking 포함)과 불투명 redacted 블록을 보존해요. `hideThinkingSummary` 정책은 유지돼요. 로컬에서 숨긴 서명 텍스트를 Claude 클라이언트에 노출하지 않으며, 이 숨김 경계를 통한 무손실 재생은 아직 보장하지 않아요. 이전 결합 봉투는 스트리밍 텍스트가 이미 전송됐다면 원래 블록 순서를 복원할 수 없어요. `claudeCode.compatibility: "enforce"`는 여전히 thinking 재생을 거절해요. 실제 Anthropic 수락이나 캐시 적중 개선을 증명한 것은 아니며 [#3719](https://github.com/lidge-jun/opencodex/issues/3719)는 열어 둬요. + **오류 조건(400):** 잘못된 JSON, 누락되거나 빈 `model`, 누락되거나 빈 `messages`, 지원하지 않는 role, `tool_use_id` 없는 `tool_result`, id/name 없는 `tool_use`, name 없는 이름 지정 `tool_choice`예요. diff --git a/docs-site/src/content/docs/ru/guides/claude-code.md b/docs-site/src/content/docs/ru/guides/claude-code.md index 1769642bd7..847e79964a 100644 --- a/docs-site/src/content/docs/ru/guides/claude-code.md +++ b/docs-site/src/content/docs/ru/guides/claude-code.md @@ -399,6 +399,8 @@ Claude Code — это лишь учётные данные для доступ | `max_tokens` | `max_output_tokens` | | `stop_sequences` | `stop` | +На выбранном адаптере Anthropic сохраняются нескрытые подписанные блоки (включая пустой thinking) и непрозрачные блоки redacted. Политика `hideThinkingSummary` не меняется: локально скрытый подписанный текст не раскрывается клиентам Claude, а воспроизведение без потерь через эту границу пока не подтверждено. Старые объединённые конверты не восстанавливают порядок после отправки потокового текста. `claudeCode.compatibility: "enforce"` по-прежнему отклоняет thinking replay. Приём реальным Anthropic и улучшение кеша не доказаны; [#3719](https://github.com/lidge-jun/opencodex/issues/3719) остаётся открытым. + **Случаи ошибок (400):** некорректный JSON; отсутствующий или пустой `model`; отсутствующий или пустой `messages`; неподдерживаемая роль; `tool_result` без `tool_use_id`; `tool_use` без id/name; именованный `tool_choice` без имени. diff --git a/docs-site/src/content/docs/tr/guides/claude-code.md b/docs-site/src/content/docs/tr/guides/claude-code.md index 29d96506ac..f1c7fca438 100644 --- a/docs-site/src/content/docs/tr/guides/claude-code.md +++ b/docs-site/src/content/docs/tr/guides/claude-code.md @@ -588,6 +588,8 @@ dönüştürür: | `max_tokens` | `max_output_tokens` | | `stop_sequences` | `stop` | +Hedeflenen Anthropic adaptöründe gizlenmemiş imzalı bloklar (boş thinking dahil) ve opak redacted blokları korunur. `hideThinkingSummary` değişmez: yerel olarak gizlenen imzalı metin Claude istemcilerine gösterilmez; bu sınır üzerinden kayıpsız yeniden oynatma doğrulanmamıştır. Eski birleşik zarflarda metin akışla gönderildikten sonra özgün blok sırası geri getirilemez. `claudeCode.compatibility: "enforce"` thinking yeniden oynatmasını hâlâ reddeder. Bu, gerçek Anthropic kabulünü veya önbellek iyileşmesini kanıtlamaz; [#3719](https://github.com/lidge-jun/opencodex/issues/3719) açık kalır. + **Hata durumları (400):** hatalı biçimlendirilmiş JSON; eksik/boş `model`; eksik/boş `messages`; desteklenmeyen rol; `tool_use_id` içermeyen `tool_result`; kimlik/ad içermeyen `tool_use`; ad içermeyen adlandırılmış `tool_choice`. diff --git a/docs-site/src/content/docs/zh-cn/guides/claude-code.md b/docs-site/src/content/docs/zh-cn/guides/claude-code.md index 3e2824d3e9..2b8c0bfa98 100644 --- a/docs-site/src/content/docs/zh-cn/guides/claude-code.md +++ b/docs-site/src/content/docs/zh-cn/guides/claude-code.md @@ -350,6 +350,8 @@ Claude Code 的 `/effort` 设置会完整保留并传递给适配器: | `max_tokens` | `max_output_tokens` | | `stop_sequences` | `stop` | +在预期的 Anthropic 适配器上,保留未隐藏的签名块(包括空 thinking)和不透明的 redacted 块。`hideThinkingSummary` 策略不变:不会向 Claude 客户端公开本地隐藏的签名文本,尚未证明经过此隐藏边界的无损重放。旧版组合信封在流式文本发出后无法恢复原始块顺序。`claudeCode.compatibility: "enforce"` 仍拒绝 thinking 重放。这不证明真实 Anthropic 接受请求或缓存命中改善;[#3719](https://github.com/lidge-jun/opencodex/issues/3719) 仍未关闭。 + **错误情况(400):**JSON 格式错误;缺少/空的 `model`;缺少/空的 `messages`;不支持的 role;`tool_result` 缺少 `tool_use_id`;`tool_use` 缺少 id/name;指定名称的 `tool_choice` 缺少 name。 diff --git a/docs-site/src/content/docs/zh-tw/guides/claude-code.md b/docs-site/src/content/docs/zh-tw/guides/claude-code.md index 5a6fbf3a86..db1c779145 100644 --- a/docs-site/src/content/docs/zh-tw/guides/claude-code.md +++ b/docs-site/src/content/docs/zh-tw/guides/claude-code.md @@ -426,6 +426,8 @@ Claude Code 的 `/effort` 設定會完整保留並傳遞給適配器: | `max_tokens` | `max_output_tokens` | | `stop_sequences` | `stop` | +在預期的 Anthropic 適配器上,保留未隱藏的簽名區塊(包括空 thinking)和不透明的 redacted 區塊。`hideThinkingSummary` 政策不變:不會向 Claude 用戶端公開本地隱藏的簽名文字,尚未證明經過此隱藏邊界的無損重播。舊版組合信封在串流文字發出後無法恢復原始區塊順序。`claudeCode.compatibility: "enforce"` 仍拒絕 thinking 重播。這不證明真實 Anthropic 接受請求或快取命中改善;[#3719](https://github.com/lidge-jun/opencodex/issues/3719) 仍未關閉。 + **錯誤情況(400):**JSON 格式錯誤;缺少/空的 `model`;缺少/空的 `messages`;不支援的 role;`tool_result` 缺少 `tool_use_id`;`tool_use` 缺少 id/name;指定名稱的 `tool_choice` 缺少 name。 diff --git a/src/adapters/anthropic.ts b/src/adapters/anthropic.ts index 6eea4764a1..a9a8279198 100644 --- a/src/adapters/anthropic.ts +++ b/src/adapters/anthropic.ts @@ -1118,9 +1118,14 @@ export function createAnthropicAdapter(provider: OcxProviderConfig, cacheRetenti break; } case "content_block_start": { - const block = data.content_block as { type: string; id?: string; name?: string; data?: string } | undefined; + const block = data.content_block as { type: string; id?: string; name?: string; data?: string; thinking?: string } | undefined; if (!block) break; currentBlockType = block.type; + if (block.type === "thinking") { + // Preserve even a display:omitted block boundary. The bridge can then + // distinguish consecutive empty signed blocks from signature updates. + yield { type: "thinking_delta", thinking: typeof block.thinking === "string" ? block.thinking : "" }; + } if (block.type === "tool_use") { currentToolCallId = usableToolUseId(block.id); currentToolCallName = toolNames.fromWire(block.name ?? ""); @@ -1151,8 +1156,8 @@ export function createAnthropicAdapter(provider: OcxProviderConfig, cacheRetenti // later text blocks independent. yield { type: "thinking_delta", thinking: delta.reasoning }; } else if (delta.type === "signature_delta" && typeof delta.signature === "string" && (currentBlockType === "thinking" || currentBlockType === "reasoning")) { - // Arrives once, just before the thinking block's content_block_stop; block-scoped - // so a stray signature on a non-thinking block can never be captured. + // Anthropic SDKs replace the signature with this value. Forward updates + // within the block; the bridge closes on the next semantic boundary. yield { type: "thinking_signature", signature: delta.signature }; } else if (delta.type === "input_json_delta" && typeof delta.partial_json === "string" && currentBlockType === "tool_use") { // Forwarded immediately: the bridge maps each delta to a client-visible diff --git a/src/bridge.ts b/src/bridge.ts index 645dfff8e7..ff044a5e52 100644 --- a/src/bridge.ts +++ b/src/bridge.ts @@ -945,6 +945,13 @@ export function bridgeToResponsesSSE( } if (event.type !== "done" && event.type !== "incomplete" && event.type !== "error") continue; } + // Anthropic signature_delta supplies the latest signature, not an append-only + // fragment (anthropic-sdk-typescript MessageStream). Keep consecutive updates + // together; the next semantic event belongs to the following block. + if (pendingSignature !== undefined && event.type !== "thinking_signature" && event.type !== "heartbeat") { + if (currentReasoning) closeCurrentReasoning(); + else flushHiddenReasoningEnvelope(); + } switch (event.type) { case "assistant_boundary": { // A guarded continuation starts a fresh assistant output item while keeping the @@ -1054,15 +1061,21 @@ export function bridgeToResponsesSSE( case "thinking_signature": { pendingSignatureBytes = replaceRetainedString(pendingSignatureBytes, event.signature, "reasoning"); pendingSignature = event.signature; - // Signature arrives at the end of the thinking block. With a visible reasoning item - // open, closeCurrentReasoning attaches the envelope; hidden/suppressed blocks flush - // an envelope-only reasoning item now. - if (!currentReasoning) flushHiddenReasoningEnvelope(); + // Delay closing until the next semantic event so a signature update cannot + // create another block or become attached to the following thinking text. break; } case "redacted_thinking": { + if (currentMsg) closeCurrentMessage("commentary"); + if (currentReasoning) closeCurrentReasoning(); + if (currentRawReasoning) closeCurrentRawReasoning(); + flushHiddenRawReasoning(); + if (currentToolCall) closeCurrentToolCall(); budget?.chargeRetained(bytesOf(event.data), { kind: "reasoning" }); pendingRedacted.push(event.data); + // A redacted block is complete at content_block_start. Emit it here, + // not with a later thinking block or after a tool call at turn end. + flushHiddenReasoningEnvelope(); break; } case "kiro_redacted_reasoning": { @@ -1816,6 +1829,9 @@ function buildResponseJSONWithBudget( if (budget) releaseTranslatedEvent(e, budget); continue; } + if (batchSignature !== undefined && e.type !== "thinking_signature" && e.type !== "heartbeat") { + flushSummaryReasoning(); + } switch (e.type) { case "assistant_boundary": flushText("commentary"); @@ -1860,19 +1876,23 @@ function buildResponseJSONWithBudget( } break; case "thinking_signature": - // End of the current thinking block — flush it WITH the signature envelope so the - // block/signature pairing survives multi-block turns. + // Like streaming, retain the latest signature update until the next semantic + // event. Flushing every update would manufacture signature-only siblings. batchSignatureBytes = replaceBatchRetainedString(batchSignatureBytes, e.signature, "reasoning"); batchSignature = e.signature; - flushSummaryReasoning(); break; case "redacted_thinking": + flushText("commentary"); + flushSummaryReasoning(); + flushRawReasoning(); + flushToolCall(); { const dataBytes = bytesOf(e.data); budget?.chargeRetained(dataBytes, { kind: "reasoning" }); batchRedactedBytes += dataBytes; } batchRedacted.push(e.data); + flushSummaryReasoning(); break; case "kiro_redacted_reasoning": // Stash only — pushed after the trailing flushes. One blob per turn, so last wins. diff --git a/src/claude/outbound.ts b/src/claude/outbound.ts index 8c0db5b7b8..4dcdaa0eb7 100644 --- a/src/claude/outbound.ts +++ b/src/claude/outbound.ts @@ -559,7 +559,10 @@ export function responsesSseToAnthropicSse( if (env?.sig) open.reasoningSig = env.sig; closeOpenBlock(); } - if (red.length > 0) ensureStarted(); + if (red.length > 0) { + ensureStarted(); + closeOpenBlock(); + } for (const data of red) { const idx = blockIndex++; emit("content_block_start", { type: "content_block_start", index: idx, content_block: { type: "redacted_thinking", data } }); @@ -806,10 +809,14 @@ export function responsesJsonToAnthropicMessage(json: unknown, model: string): R } const encrypted = typeof raw.encrypted_content === "string" ? raw.encrypted_content : ""; const env = encrypted ? decodeReasoningEnvelope(encrypted) : null; + // Legacy combined envelopes place redacted blocks before the signed block, + // matching the Anthropic adapter. New bridge output uses separate items. + for (const data of env?.red ?? []) content.push({ type: "redacted_thinking", data }); + // env.txt may be locally hidden text. Do not expose it here or manufacture + // a new signed continuity carrier; hidden-summary replay remains limited. if (parts.length > 0 || env?.sig) { content.push({ type: "thinking", thinking: parts.join("\n\n"), signature: env?.sig ?? encodeReasoningEnvelope({ txt: parts.join("\n\n") }) }); } - for (const data of env?.red ?? []) content.push({ type: "redacted_thinking", data }); break; } case "function_call": { diff --git a/src/responses/parser.ts b/src/responses/parser.ts index a81a693a4a..396f2170b2 100644 --- a/src/responses/parser.ts +++ b/src/responses/parser.ts @@ -126,6 +126,12 @@ export function parseRequest( } return holder; }; + const preservePendingReplay = () => { + const replay = pendingReasoning.filter(entry => entry.envelopeSigned || entry.part.redacted?.length); + if (replay.length > 0) { + ensureAssistantPlaceholder(messages, data.model, now).content.push(...replay.map(entry => entry.part)); + } + }; // Tool specs surfaced by a prior tool_search (deferred tools, e.g. subagents). Codex does not // re-list these in `tools`, but chat models can only call listed tools — so we re-inject them. const loadedToolSpecs: unknown[] = []; @@ -148,6 +154,12 @@ export function parseRequest( const effectiveType = (item as { type?: string }).type ?? ("role" in item ? "message" : undefined); const itemRole = (item as { role?: string }).role; const externalTaskInput = effectiveType === "function_call_output" ? externalTaskInputContent(item) : undefined; + // A signed/opaque assistant-only turn still owns its replay blocks, even + // without a following assistant text or tool call to drain the pending list. + if (effectiveType === "agent_message" || externalTaskInput !== undefined + || (effectiveType === "message" && ["user", "developer", "system"].includes(itemRole ?? ""))) { + preservePendingReplay(); + } // Raw protocol items do not map one-to-one onto context messages. Capture the boundary while // both representations are available so later metadata can stay before conversation in both. if ( @@ -269,7 +281,7 @@ export function parseRequest( const envelope = typeof reasoning.encrypted_content === "string" ? decodeReasoningEnvelope(reasoning.encrypted_content) : null; - const thinkingText = envelope?.txt || text; + const thinkingText = envelope?.txt ?? text; // Kiro reasoning round-trip: a krc-only item carries nothing renderable — it is provider // state for the assistant turn that ALREADY closed, because Kiro emits its @@ -285,7 +297,7 @@ export function parseRequest( // Native/non-ocxr1 encrypted-only reasoning is opaque here. Do not create a detached // assistant turn or invent replayable plaintext/signatures from the encrypted payload. - if (thinkingText.length > 0) { + if (thinkingText.length > 0 || envelope?.sig || envelope?.red?.length) { const part: OcxThinkingContent = { type: "thinking", thinking: thinkingText, @@ -296,7 +308,7 @@ export function parseRequest( const envelopeSigned = typeof envelope?.sig === "string"; const previous = pendingReasoning[pendingReasoning.length - 1]; - if (!envelopeSigned && previous && !previous.envelopeSigned) { + if (!envelopeSigned && !part.redacted && previous && !previous.envelopeSigned && !previous.part.redacted) { previous.part = { ...part, thinking: `${previous.part.thinking}\n${part.thinking}`, @@ -466,6 +478,7 @@ export function parseRequest( } } } + preservePendingReplay(); if (data.previous_response_id && continuationConversationMessageIndex === undefined) { continuationConversationMessageIndex = messages.length; } diff --git a/tests/adapters/anthropic/anthropic-thinking-signature.test.ts b/tests/adapters/anthropic/anthropic-thinking-signature.test.ts index 68c972a742..db8f489c4f 100644 --- a/tests/adapters/anthropic/anthropic-thinking-signature.test.ts +++ b/tests/adapters/anthropic/anthropic-thinking-signature.test.ts @@ -4,7 +4,12 @@ import { createAnthropicAdapter as createAnthropicAdapterProduction } from "../. import { parseRequest } from "../../../src/responses/parser"; import { encodeReasoningEnvelope, decodeReasoningEnvelope, OCX_REASONING_PREFIX } from "../../../src/responses/reasoning-envelope"; import type { AdapterEvent, OcxProviderConfig, OcxThinkingContent } from "../../../src/types"; -import { withTestTranslatorBudget } from "../../helpers/translator-budget"; +import { createTestTranslatorBudget, withTestTranslatorBudget } from "../../helpers/translator-budget"; + +import { anthropicToResponsesBody } from "../../../src/claude/inbound"; +import { collectAnthropicMessage, responsesSseToAnthropicSse, responsesJsonToAnthropicMessage } from "../../../src/claude/outbound"; +import { createGoogleAdapter } from "../../../src/adapters/google"; +import { sanitizeReasoningInputContent } from "../../../src/adapters/openai-responses"; const createAnthropicAdapter = (...args: Parameters) => withTestTranslatorBudget(createAnthropicAdapterProduction(...args)); @@ -127,11 +132,11 @@ describe("bridge ocxr1 envelope emission", () => { ...baseEvents, ], "claude-x"); const output = response.output as Record[]; - const reasoning = output.find(i => i.type === "reasoning"); - expect(reasoning).toBeDefined(); - const env = decodeReasoningEnvelope(reasoning!.encrypted_content as string); - expect(env?.sig).toBe("RealSig1234567890=="); - expect(env?.red).toEqual(["RED1"]); + const reasoning = output.filter(i => i.type === "reasoning"); + expect(reasoning.map(item => decodeReasoningEnvelope(item.encrypted_content as string))).toEqual([ + { red: ["RED1"] }, + { sig: "RealSig1234567890==" }, + ]); }); test("redacted-only turn still emits an envelope reasoning item (SSE)", async () => { @@ -326,3 +331,174 @@ describe("passthrough scrub of ocxr1 envelopes", () => { expect(req.body ?? "").toContain('"rs_1"'); // reasoning item itself survives }); }); + + +describe("Claude / Responses / intended Anthropic replay fidelity", () => { + // Synthetic fixtures prove transport fidelity only, never upstream signature validity. + const first = { type: "thinking", thinking: "first\nexact", signature: "FirstSyntheticSignature123456==" }; + const second = { type: "thinking", thinking: "second", signature: "SecondSyntheticSignature123456==" }; + const empty = { type: "thinking", thinking: "", signature: "EmptySyntheticSignature123456==" }; + const before = { type: "redacted_thinking", data: "opaque-before" }; + const middle = { type: "redacted_thinking", data: "opaque-middle" }; + const after = { type: "redacted_thinking", data: "opaque-after" }; + const tool = { type: "tool_use", id: "toolu_replay", name: "lookup", input: { q: "x" } }; + const cases = [ + { name: "consecutive signed blocks", blocks: [first, second, tool] }, + { name: "opaque blocks in source order", blocks: [before, first, middle, second, after, tool] }, + { name: "empty signed block", blocks: [empty, tool] }, + { name: "consecutive empty signed blocks", blocks: [empty, { ...empty, signature: "OtherEmptySyntheticSignature123456==" }, tool] }, + { name: "redacted-only tool turn", blocks: [before, after, tool] }, + ]; + + for (const fixture of cases) { + for (const streaming of [true, false]) { + test(`${fixture.name}: ${streaming ? "SSE" : "JSON"} full chain preserves exact blocks`, async () => { + const adapter = createAnthropicAdapter(provider, "none"); + let events: AdapterEvent[]; + if (streaming) { + const frames = [frame("message_start", { message: { usage: { input_tokens: 1, output_tokens: 0 } } })]; + fixture.blocks.forEach((block, index) => { + frames.push(frame("content_block_start", { index, content_block: block.type === "thinking" + ? { type: "thinking", thinking: "", signature: "" } + : block.type === "tool_use" ? { ...tool, input: {} } : block })); + if ("thinking" in block) { + // Omitted thinking has no thinking_delta on the actual wire. + if (block.thinking) frames.push(frame("content_block_delta", { index, delta: { type: "thinking_delta", thinking: block.thinking } })); + frames.push(frame("content_block_delta", { index, delta: { type: "signature_delta", signature: block.signature } })); + } else if (block.type === "tool_use") { + frames.push(frame("content_block_delta", { index, delta: { type: "input_json_delta", partial_json: JSON.stringify(tool.input) } })); + } + frames.push(frame("content_block_stop", { index })); + }); + frames.push(frame("message_delta", { delta: { stop_reason: "tool_use" }, usage: { output_tokens: 1 } }), frame("message_stop", {})); + events = await collect(adapter.parseStream(sseResponse(frames))); + } else { + events = await adapter.parseResponse!(new Response(JSON.stringify({ + id: "msg_fixture", type: "message", role: "assistant", model: "claude-x", + content: fixture.blocks, stop_reason: "tool_use", usage: { input_tokens: 1, output_tokens: 1 }, + }))); + } + let message: Record; + if (streaming) { + async function* upstream() { yield* events; } + const budget = createTestTranslatorBudget(); + message = await collectAnthropicMessage(responsesSseToAnthropicSse( + bridgeToResponsesSSE(upstream(), "claude-x"), "claude-x", { translatorBudget: budget }, + ), "claude-x", budget); + } else { + message = responsesJsonToAnthropicMessage(buildResponseJSON(events, "claude-x"), "claude-x"); + } + expect(message.content).toEqual(fixture.blocks); + const parsed = parseRequest(anthropicToResponsesBody({ + model: "anthropic/claude-x", messages: [ + { role: "user", content: "question" }, + { role: "assistant", content: message.content }, + { role: "user", content: [{ type: "tool_result", tool_use_id: tool.id, content: "result" }] }, + ], + })); + const request = await adapter.buildRequest(parsed); + const replay = JSON.parse(request.body as string) as { messages: Array<{ role: string; content: unknown }> }; + expect(replay.messages).toEqual([ + { role: "user", content: [{ type: "text", text: "question" }] }, + { role: "assistant", content: fixture.blocks }, + { role: "user", content: [{ type: "tool_result", tool_use_id: tool.id, content: "result" }] }, + ]); + }); + } + } + + test("signature updates replace rather than concatenate, across heartbeats", async () => { + // Both official SDKs assign signature_delta.signature instead of appending it: + // anthropic-sdk-typescript/src/lib/MessageStream.ts and + // anthropic-sdk-python/src/anthropic/lib/streaming/_messages.py. + const adapter = createAnthropicAdapter(provider); + const events = await collect(adapter.parseStream(sseResponse([ + frame("content_block_start", { index: 0, content_block: { type: "thinking", thinking: "", signature: "" } }), + frame("content_block_delta", { index: 0, delta: { type: "thinking_delta", thinking: "first" } }), + frame("content_block_delta", { index: 0, delta: { type: "signature_delta", signature: "old" } }), + ": heartbeat\n\n", + frame("content_block_delta", { index: 0, delta: { type: "signature_delta", signature: "FirstSyntheticSignature123456==" } }), + frame("content_block_stop", { index: 0 }), + frame("content_block_start", { index: 1, content_block: { type: "thinking", thinking: "", signature: "" } }), + frame("content_block_delta", { index: 1, delta: { type: "thinking_delta", thinking: "second" } }), + frame("content_block_delta", { index: 1, delta: { type: "signature_delta", signature: "SecondSyntheticSignature123456==" } }), + frame("content_block_stop", { index: 1 }), + frame("message_stop", {}), + ]))); + async function* upstream() { yield* events; } + const streamed = sseItems(await drainSse(bridgeToResponsesSSE(upstream(), "claude-x"))); + const buffered = buildResponseJSON(events, "claude-x").output as Record[]; + for (const items of [streamed, buffered]) { + expect(items.map(item => ({ summary: item.summary, envelope: decodeReasoningEnvelope(item.encrypted_content as string) }))).toEqual([ + { summary: [{ type: "summary_text", text: "first" }], envelope: { sig: "FirstSyntheticSignature123456==" } }, + { summary: [{ type: "summary_text", text: "second" }], envelope: { sig: "SecondSyntheticSignature123456==" } }, + ]); + } + }); + + test("signed/opaque-only assistant turns survive a user boundary and end of input", () => { + for (const continuation of [[], [{ role: "user", content: "next" }]]) { + const parsed = parseRequest(anthropicToResponsesBody({ model: "anthropic/claude-x", messages: [ + { role: "assistant", content: [empty, before, after] }, ...continuation, + ] })); + const assistant = parsed.context.messages.find(message => message.role === "assistant"); + expect(assistant?.content).toEqual([ + expect.objectContaining({ type: "thinking", thinking: "", signature: empty.signature }), + expect.objectContaining({ type: "thinking", thinking: "", redacted: [before.data] }), + expect.objectContaining({ type: "thinking", thinking: "", redacted: [after.data] }), + ]); + } + }); + + test("locally hidden signed text remains exact on Responses replay without being exposed to Claude", async () => { + const events: AdapterEvent[] = [ + { type: "thinking_delta", thinking: "hidden exact\ntext" }, + { type: "thinking_signature", signature: first.signature }, + { type: "text_delta", text: "answer" }, + { type: "done", usage: { inputTokens: 1, outputTokens: 1 } }, + ]; + async function* upstream() { yield* events; } + const items = sseItems(await drainSse(bridgeToResponsesSSE(upstream(), "claude-x", undefined, undefined, undefined, undefined, 2000, { hideThinkingSummary: true }))); + const response = buildResponseJSON(events, "claude-x", { hideThinkingSummary: true }); + for (const output of [items, response.output as Record[]]) { + const reasoning = output.find(item => item.type === "reasoning")!; + expect(reasoning.summary).toEqual([]); + expect(decodeReasoningEnvelope(reasoning.encrypted_content as string)).toEqual({ sig: first.signature, txt: "hidden exact\ntext" }); + const request = await createAnthropicAdapter(provider, "none").buildRequest(parseRequest({ model: "anthropic/claude-x", input: output })); + const replay = JSON.parse(request.body as string) as { messages: Array<{ content: unknown }> }; + expect(replay.messages[0].content).toEqual([ + { type: "thinking", thinking: "hidden exact\ntext", signature: first.signature }, + { type: "text", text: "answer" }, + ]); + // Deliberate existing limitation: no new signed carrier and no hidden-text disclosure. + expect(JSON.stringify(responsesJsonToAnthropicMessage({ output }, "claude-x"))).not.toContain("hidden exact"); + } + expect(() => anthropicToResponsesBody({ model: "m", messages: [{ role: "assistant", content: [ + { type: "thinking", thinking: "", signature: encodeReasoningEnvelope({ sig: first.signature, txt: "hidden exact" }) }, + ] }] })).toThrow(/continuity/); + }); + + test("explicitly empty signed envelope text does not fall back to a different summary", () => { + const parsed = parseRequest({ model: "m", input: [ + { type: "reasoning", summary: [{ type: "summary_text", text: "different summary" }], encrypted_content: encodeReasoningEnvelope({ sig: empty.signature, txt: "" }) }, + ] }); + expect(parsed.context.messages[0]?.content).toEqual([ + { type: "thinking", thinking: "", signature: empty.signature }, + ]); + }); + + test("opaque Anthropic payloads do not become Google signatures or native Responses encryption", async () => { + const body = anthropicToResponsesBody({ model: "google/gemini-test", messages: [ + { role: "assistant", content: [empty, before, tool] }, + { role: "user", content: [{ type: "tool_result", tool_use_id: tool.id, content: "result" }] }, + ] }); + const google = withTestTranslatorBudget(createGoogleAdapter({ adapter: "google", baseUrl: "https://generativelanguage.googleapis.com", apiKey: "synthetic" })); + const request = await google.buildRequest(parseRequest(body)); + for (const output of [request.body as string, JSON.stringify(sanitizeReasoningInputContent(body))]) { + expect(output).not.toContain(empty.signature); + expect(output).not.toContain(before.data); + expect(output).not.toContain("ocxr1:"); + } + expect(parseRequest({ model: "m", input: [{ type: "reasoning", summary: [], encrypted_content: "native-opaque" }] }).context.messages).toEqual([]); + }); +}); diff --git a/tests/claude-integration/claude-outbound.test.ts b/tests/claude-integration/claude-outbound.test.ts index e78cc529d3..33faa2e839 100644 --- a/tests/claude-integration/claude-outbound.test.ts +++ b/tests/claude-integration/claude-outbound.test.ts @@ -1179,6 +1179,23 @@ describe("sanitizeWebSearchInput (#381)", () => { expect(events[2].data.content_block).toEqual({ type: "redacted_thinking", data: "opaque" }); }); + test("redacted reasoning closes an open text block before opening its opaque block", async () => { + const events = await collectEvents(responsesSseToAnthropicSse(streamFrom([ + sse("response.output_text.delta", { delta: "text" }), + sse("response.output_item.done", { + item: { type: "reasoning", id: "rs_red", encrypted_content: encodeReasoningEnvelope({ red: ["opaque"] }) }, + }), + sse("response.completed", { response: { status: "completed", usage: {} } }), + ].join("")), "m")); + expect(events.filter(event => event.name === "content_block_start" || event.name === "content_block_stop") + .map(event => ({ name: event.name, index: event.data.index }))).toEqual([ + { name: "content_block_start", index: 0 }, + { name: "content_block_stop", index: 0 }, + { name: "content_block_start", index: 1 }, + { name: "content_block_stop", index: 1 }, + ]); + }); + test("signature-only reasoning emits an empty thinking block with the genuine signature", async () => { const events = await collectEvents(responsesSseToAnthropicSse(streamFrom([ sse("response.output_item.done", { diff --git a/tests/responses/reasoning-envelope.test.ts b/tests/responses/reasoning-envelope.test.ts index 75c51994f2..2469b8e46b 100644 --- a/tests/responses/reasoning-envelope.test.ts +++ b/tests/responses/reasoning-envelope.test.ts @@ -34,8 +34,8 @@ describe("reasoning and tool/result envelopes", () => { const message = responsesJsonToAnthropicMessage({ output: [{ type: "reasoning", summary: [{ type: "summary_text", text: "visible" }], encrypted_content: encoded }], }, "m") as any; - expect(message.content[0]).toMatchObject({ type: "thinking", signature: "sig" }); - expect(message.content.slice(1)).toEqual([ + expect(message.content[2]).toMatchObject({ type: "thinking", signature: "sig" }); + expect(message.content.slice(0, 2)).toEqual([ { type: "redacted_thinking", data: "red-a" }, { type: "redacted_thinking", data: "red-b" }, ]); From 8f8790e31cdaf6d9c0083324aa01d6f778410e98 Mon Sep 17 00:00:00 2001 From: JUN <243035832+lidge-jun@users.noreply.github.com> Date: Mon, 7 Sep 2026 07:43:23 +0900 Subject: [PATCH 019/412] docs(devlog): record axis three protocol delivery plan --- .../_plan/260907_axis3_protocol/000_plan.md | 13 ++++++ .../260907_axis3_protocol/001_roadmap_lock.md | 3 ++ .../010_prepare_and_verify.md | 42 +++++++++++++++++++ .../260907_axis3_protocol/011_candidate.md | 9 ++++ .../260907_axis3_protocol/020_delivery.md | 7 ++++ 5 files changed, 74 insertions(+) create mode 100644 devlog/_plan/260907_axis3_protocol/000_plan.md create mode 100644 devlog/_plan/260907_axis3_protocol/001_roadmap_lock.md create mode 100644 devlog/_plan/260907_axis3_protocol/010_prepare_and_verify.md create mode 100644 devlog/_plan/260907_axis3_protocol/011_candidate.md create mode 100644 devlog/_plan/260907_axis3_protocol/020_delivery.md diff --git a/devlog/_plan/260907_axis3_protocol/000_plan.md b/devlog/_plan/260907_axis3_protocol/000_plan.md new file mode 100644 index 0000000000..36cfe95772 --- /dev/null +++ b/devlog/_plan/260907_axis3_protocol/000_plan.md @@ -0,0 +1,13 @@ +# Axis 3 protocol fidelity roadmap + +Mode: satisfy-spec HOTL, requested by the maintainer on 2026-09-07. Deliver source-grounded dispositions for #3815, #3816, #3807, #3719 and land accepted fixes with original authors credited in commits. No local suites or typecheck; verification is remote exact final-head CI, with lower-layer CI only on final failure. Ordinary manual PR chain only; admin merge authorized. No explicit token or wall-time limit was requested; agents use bounded tasks and waits. Do not invoke private provider accounts or spend inference credits. Tools: local Git/files, GitHub gh, Astra high leaf agents. Writes confined to task worktrees and this axis's GitHub branches/PRs. Preserve unrelated dirty work. + +Scope: ordered Claude thinking/redacted/tool-result envelope fidelity; Grok strict-client control frame projection; valid task-seed diagnosis. Exclude new auth/routing/default policies, fabricated provider signatures or tool pairing IDs (new Responses reasoning item IDs are permitted transport identities), cache savings claims, unrelated axes, deployment/release. Unknown field/runtime reports receive explicit deferred dispositions per user direction. + +Work phases: wp0 roadmap audit and lock; wp1 prepare two independently reviewable source layers and any justified contract regressions, then remote final combined verification; wp2 publish/merge ordinary PRs bottom-up and record final ancestry/dispositions. The two source fixes are independent; the manual chain is the user's requested integration/CI grouping, not a runtime dependency. + +Success: roadmap verified, accepted changes reviewed and remotely validated, commits credit SB Yoon (yansigit) and Yumi for #3815 and Danh Thanh (dt418) for #3816, landed SHA proven ancestor of refreshed dev; uncertain #3807/#3719 runtime or cache claims remain open. Stop only after accepted delivery and explicit dispositions. Escalate only an unavoidable owner-policy choice; defer that portion and continue the rest. + +Acceptance: (1) thinking then text/tool then result retains order and genuine signatures; opaque blocks remain bounded and malformed/nested signatures fail closed. (2) Grok user agent receives ordinary Responses data without codex.rate_limits/codex.response.metadata, while proxy inspection and normal clients retain metadata. (3) valid external task seeds preserve text/order; absent metadata invalid tool outputs still reject. (4) no credential, admission, cache-retention default, provider/routing policy mutation. (5) final CI must really run relevant tests/typecheck, not skip/cancel or fabricate success. No local suite was run. Final failure permits lower-layer CI for localization; unrelated failures may defer delivery, never count as success. + +Sources: PRs https://github.com/lidge-jun/opencodex/pull/3815 and /pull/3816; issues /issues/3807 and /issues/3719. Current dev 137d6a727. Evidence snapshots under .tmp/axis3. Public notes contain no unreleased vulnerability detail; any new security investigation stays in scratch. diff --git a/devlog/_plan/260907_axis3_protocol/001_roadmap_lock.md b/devlog/_plan/260907_axis3_protocol/001_roadmap_lock.md new file mode 100644 index 0000000000..115f8c3dfa --- /dev/null +++ b/devlog/_plan/260907_axis3_protocol/001_roadmap_lock.md @@ -0,0 +1,3 @@ +# Roadmap lock + +Independent Astra high reviewer Pauli passed the amended wp0 roadmap. Transport reasoning IDs are permitted; fabricated tool pairing IDs remain prohibited. Claude fallback retention must be bounded or removed and checked remotely. Grok parser must follow SSE last-field/reset semantics. No runtime was changed in wp0. Next: wp1 carries source layers, adds justified regression coverage and verifies the final combined head remotely. diff --git a/devlog/_plan/260907_axis3_protocol/010_prepare_and_verify.md b/devlog/_plan/260907_axis3_protocol/010_prepare_and_verify.md new file mode 100644 index 0000000000..c278f094bf --- /dev/null +++ b/devlog/_plan/260907_axis3_protocol/010_prepare_and_verify.md @@ -0,0 +1,42 @@ +# Prepare and verify combined protocol candidate + +Reverify base/source heads before build. Carry exact source deltas from the scratch diff snapshots, fold independently confirmed review fixes only. Each commit contains verified contributor trailers. Do not include upstream planning notes or unrelated changes. + +Layer 1 MODIFY: +scripts/test-layout/layout.json +src/claude/inbound.ts +src/claude/outbound.ts +src/responses/reasoning-envelope.ts +tests/claude-integration/claude-code-thought-signature-scope.test.ts +tests/claude-integration/claude-inbound.test.ts +tests/claude-integration/claude-outbound.test.ts +tests/claude-integration/claude-source-envelope.test.ts +tests/fixtures/test-layout-expected.json +tests/responses/reasoning-envelope.test.ts + +Preserve genuine signatures; encode bounded unsigned/redacted fallback; keep structured tool results. Layer 2 NEW src/server/grok-responses-control-frame.ts and MODIFY: +src/server/grok-responses-control-frame.ts +src/server/responses/core.ts +tests/responses/responses-snapshot-repair-server.test.ts + +Separate strict-client filtering from internal inspection. On a Grok metadata frame, forward no incompatible client frame; on ordinary delta, preserve unchanged; ordinary clients remain unchanged. No shared account/routing changes. + +Potential follow-up tests belong only in existing responses/Claude test files after diagnosis, with independent expected values. If no valid unhandled #3807 input is established, leave production guards unchanged. #3719 cache-hit and true Anthropic signed replay cannot be certified by codec fixtures. + +SoT: update docs-site/src/content/docs/guides/claude-code.md and existing translated counterparts only if #3815 makes their drop-policy statements stale. Read docs-site/AGENTS.md first. No global retention change. + +Verification: user prohibits local suites/typecheck (NOT RUN). Inspect source and diff-check locally. Push task branches with --no-verify. Dispatch existing Cross-platform CI workflow on final combined head, lane all. Confirm workflow head SHA, jobs, conclusion, test/typecheck execution from logs. Final CI failure permits lower-layer CI. Keep workflow/protection configuration unchanged; suppress only task-owned redundant automatic runs when needed for requested top-first scheduling, reporting cancelled runs honestly. No real accounts are used. + +## Audit amendments + +New rs_ reasoning IDs are normal transport identity, not fabricated tool call pairing. Do not synthesize tool-call IDs to bypass #3807 validation. + +Before acceptance, remove unbounded thinkingBuf retention introduced by #3815 or charge it to the existing TranslatorBudget retained bytes with normal fail-closed overflow. Use the established budget and error event; no silent truncation or new policy default. Cover multi-part text exactness, empty continuity fallback, and overflow with a small injected existing budget in remote regression tests. Decoder/consumer traces must prove any compact continuity marker still replays the original summary. + +#3816 must use SSE last-event-field-wins semantics, including colonless/empty resets and removal of only one optional leading space. Test event-only, data-only, repeated event fields in both orders, and preservation of ordinary completion data. Keep downstream Grok WebSocket support deferred because the existing surface marker is absent there; do not claim this HTTP/SSE patch solves it. + +## WP1 source refresh and scoped hardening + +Previous D: roadmap locked; execute reviewed source preparation. PR #3815 advanced to 76e07d181c48dca8c80167878381e1edb5642395 during investigation, including budget fixes and translated guide changes; carry fresh source, not old snapshots. Add a third dependent hardening layer only for source-proven preservation faults. MODIFY src/responses/parser.ts: retain recognized redacted-only and empty signed envelopes even when text is empty, preserving real boundary grouping. MODIFY src/bridge.ts: preserve signed block boundaries and redacted block positions identically in streaming/buffered output; signature fragments must be assembled at owning adapter boundary. MODIFY src/claude/outbound.ts only for exact block order/text restoration where current contract permits; do not invent a new signed continuity carrier or change hide-thinking policy. If hidden signed replay needs a new policy/carrier, explicitly defer that part rather than widening scope. Existing budget/guard contracts remain. + +Tests: existing tests/responses/anthropic-thinking-signature.test.ts or matching current domain file and Claude envelope tests get exact block-array roundtrip oracles; no fixture claims a live genuine signature. tests/responses/responses-compaction-routing.test.ts gets an established-history complete send_message_to_thread envelope across normal response, stored-ID continuation, v2 compaction_trigger and v1 compact endpoint, preserving real pairing and task content. If current fixture support makes a case impractical, record exact gap; no runtime seed repair. diff --git a/devlog/_plan/260907_axis3_protocol/011_candidate.md b/devlog/_plan/260907_axis3_protocol/011_candidate.md new file mode 100644 index 0000000000..7edc9aa1ce --- /dev/null +++ b/devlog/_plan/260907_axis3_protocol/011_candidate.md @@ -0,0 +1,9 @@ +# Combined candidate + +Source baseline: dev 137d6a727. Foundation carries #3815 through 76e07d181 with SB Yoon/Yumi commit trailers. Grok carries #3816 d5e0a9a2 and corrects SSE event overwrite/reset semantics, with Danh Thanh trailers. Added established-history external-task HTTP/continuation/compact fixtures without changing the missing-ID guard. Replay hardening preserves signed/opaque-only inputs and block ordering; signature updates replace previous values according to the SDK accumulator contract, and block closure waits for the next semantic event. + +Independent source reviews: Pauli scoped foundation PASS (18/18 files); Faraday Grok/seed PASS. Final Claude combined source audit and remote CI pending. Local suites/typecheck/build not run under user instruction. No live accounts invoked. + +Deferred: #3807 lacks raw failing current-version input; #3719 still needs live intended-Anthropic acceptance and controlled cache comparisons. Locally hidden text through Claude and legacy combined-envelope streaming order recovery are not claimed supported. Existing compatibility enforcement, hidden presentation, credential/admission and retention policies remain. + +Ordinary PR chain is an integration grouping requested by owner, with final combined CI first. Lower-layer runs only if it fails. Admin merge is authorized after accepted evidence. No GitHub native stack or fabricated check status. diff --git a/devlog/_plan/260907_axis3_protocol/020_delivery.md b/devlog/_plan/260907_axis3_protocol/020_delivery.md new file mode 100644 index 0000000000..050cc76d54 --- /dev/null +++ b/devlog/_plan/260907_axis3_protocol/020_delivery.md @@ -0,0 +1,7 @@ +# Publish and deliver verified manual chain + +Prerequisite: wp1 accepted-source review and successful final-head remote validation, or source-grounded defer outcome. Publish ordinary PRs targeting dev then the parent branch, using every repository template section. Bodies name source PRs, own layer-only diff, exact final combined CI evidence and explicit lower-layer CI deferral per owner instruction. Do not attest local CI. Preserve original contributor trailers in commits; admin merge with merge commits preserves their identity. + +Read live native-stack membership and head/base identity before merge. Never register a native stack. Parent merges to dev first; retain its branch, retarget child to dev, verify current head and ancestry. If integration tree changes materially, refresh final combined CI before landing. Use --admin and --match-head-commit exact guard. Do not merge into the parent branch by mistake. Refresh origin/dev and prove each merge SHA ancestor. Close superseded source PRs only after equivalent fix is actually landed, with credit and replacement link. Keep #3807 and #3719 open if real reproduction/cache acceptance remains unmet. No release or deployment. + +Record final PR URLs, source-to-delivery mapping, commit authors/trailers, CI run and exact SHA, review verdicts, remaining limitations and preserved dirty-work evidence. No fabricated status checks. Completion: every candidate has an honest disposition, accepted work is landed, unresolved diagnostics explicitly deferred under user direction. From 9d775faccce38d9e16e5d544bdba0b451d170333 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 07:44:48 +0900 Subject: [PATCH 020/412] fix(gui): preserve display name receipts across recovery failures Keep an earlier confirmed save/reset receipt when retrying the same value and convergence fails with an ordinary HTTP error. Do not replace the saved snapshot from an unconfirmed response; retain the pending reset intent for another retry. Treat transport and response-body failures without a usable receipt as unknown outcomes, hide the stale current name, and make Retry/Enter read-only. Keep known unpersisted HTTP failures on the existing editable-draft path. Add regressions for reset -> saved:true -> HTTP failure -> success and persisted save/reset followed by rejected transport or response-body reads without abort. Local tests/typecheck/build NOT RUN by owner mandate; static diff check only. Co-authored-by: Zig Zag --- gui/src/pages/Models.tsx | 28 +++++--- gui/tests/models-display-name-editor.test.tsx | 72 +++++++++++++++++++ 2 files changed, 92 insertions(+), 8 deletions(-) diff --git a/gui/src/pages/Models.tsx b/gui/src/pages/Models.tsx index b7b3a0e285..c342866d7e 100644 --- a/gui/src/pages/Models.tsx +++ b/gui/src/pages/Models.tsx @@ -598,7 +598,11 @@ export default function Models({ apiBase, restartEpoch = 0 }: { apiBase: string; displayNameSavingRef.current = true; setDisplayNameSaving(true); setDisplayNameRequestError(null); - let confirmed = displayName === undefined && displayNameRecovery?.confirmed === true; + // A failed convergence retry cannot invalidate an earlier persistence receipt + // for the same value. Editing the draft clears recovery and starts a new intent. + let confirmed = displayNameRecovery?.confirmed === true + && (displayName === undefined || displayName === displayNameRecovery.value); + let receivedReceipt = displayName === undefined; let refreshOnly = displayName === undefined; try { if (displayName !== undefined) { @@ -624,9 +628,14 @@ export default function Models({ apiBase, restartEpoch = 0 }: { apiBase: string; ? await readJsonOrThrow(response, t("models.displayNameSaveFailed")) : await response.json(); bounded.signal.throwIfAborted(); - if (!result) throw new Error(t("models.displayNameSaveFailed")); - confirmed = response.ok || result.saved === true; - if (confirmed) { + if (!result || typeof result !== "object" || Array.isArray(result) + || (!response.ok && result.saved !== true && typeof result.error !== "string")) { + throw new Error(t("models.displayNameSaveFailed")); + } + receivedReceipt = true; + const receiptConfirmed = response.ok || result.saved === true; + confirmed = confirmed || receiptConfirmed; + if (receiptConfirmed) { const override = result.displayNameOverride === null ? undefined : result.displayNameOverride ?? displayName ?? undefined; const fields: Pick = { @@ -653,13 +662,16 @@ export default function Models({ apiBase, restartEpoch = 0 }: { apiBase: string; finishDisplayNameEdit(); } catch (error) { if (displayNameRequestRef.current !== bounded) return; - if (bounded.signal.aborted && !confirmed) setDisplayNameCurrentPending(true); - setDisplayNameRecovery(confirmed || bounded.signal.aborted || refreshOnly - ? { value: refreshOnly || bounded.signal.aborted ? undefined : displayName, confirmed } + // A dropped connection or unreadable body can hide a committed write just + // like a timeout. Reconcile by reading; never replay an unchanged old draft. + const unknownOutcome = !receivedReceipt || bounded.signal.aborted; + if (unknownOutcome && !confirmed) setDisplayNameCurrentPending(true); + setDisplayNameRecovery(confirmed || unknownOutcome || refreshOnly + ? { value: refreshOnly || unknownOutcome ? undefined : displayName, confirmed } : null); setDisplayNameRequestError(confirmed ? t("models.displayNameSavedRefreshFailed") - : bounded.signal.aborted || refreshOnly + : unknownOutcome || refreshOnly ? t("models.displayNameOutcomeUnknown") : error instanceof Error && error.message ? error.message diff --git a/gui/tests/models-display-name-editor.test.tsx b/gui/tests/models-display-name-editor.test.tsx index be64333944..b0656391ed 100644 --- a/gui/tests/models-display-name-editor.test.tsx +++ b/gui/tests/models-display-name-editor.test.tsx @@ -389,6 +389,78 @@ describe("Models dashboard discovered display name integration", () => { }); } + test("confirmed reset survives an ordinary convergence retry error before success", async () => { + await mountModels(); + await act(async () => nameTrigger().click()); + savedFailure = true; + await act(async () => dialogButton("Reset name").click()); + await flush(); + savedFailure = false; + mutationFailure = "Temporary server failure"; + await act(async () => dialogButton("Retry").click()); + await flush(); + expect(dialogInput().value).toBe(""); + expect(dialogButton("Reset name").disabled).toBe(true); + expect(dialogButton("Retry").disabled).toBe(false); + expect(container.textContent).toContain("The change was saved"); + expect(currentNameText()).not.toContain("Your name"); + expect(currentModels[0]!.displayNameOverride).toBeUndefined(); + + mutationFailure = null; + await act(async () => container.querySelector("dialog form")!.dispatchEvent( + new testWindow.Event("submit", { bubbles: true, cancelable: true }), + )); + await flush(); + expect(mutationBodies.map(body => body.displayName)).toEqual([null, null, null]); + expect(container.querySelector("dialog")).toBeNull(); + expect(currentModels[0]!.displayNameOverride).toBeUndefined(); + }); + + for (const failure of ["transport", "body"] as const) { + for (const value of ["Saved despite disconnect", null]) { + test(`persisted ${value === null ? "reset" : "save"} with ${failure} failure retries only a read`, async () => { + await mountModels(); + const transport = globalThis.fetch; + let failedSignal: AbortSignal | null | undefined; + globalThis.fetch = (async (input: RequestInfo | URL, init?: RequestInit) => { + const response = await transport(input, init); + if (init?.method === "PUT" && String(input).includes("model-display-names")) { + failedSignal = init.signal; + if (failure === "transport") throw new TypeError("Connection closed"); + Object.defineProperty(response, "text", { + value: async () => { throw new TypeError("Response body interrupted"); }, + }); + } + return response; + }) as typeof fetch; + await act(async () => nameTrigger().click()); + await act(async () => { + if (value === null) dialogButton("Reset name").click(); + else { + setInputValue(dialogInput(), value); + dialogButton("Save").click(); + } + }); + await flush(); + expect(failedSignal?.aborted).toBe(false); + expect(currentModels[0]!.displayNameOverride).toBe(value ?? undefined); + expect(dialogInput().value).toBe(value ?? "Grok 4.6"); + expect(currentNameText()).toContain("Current name unavailable until refresh"); + expect(currentNameText()).not.toContain("Your name"); + expect(container.textContent).toContain("The change may have been saved"); + expect(dialogButton("Retry").disabled).toBe(false); + expect(dialogButton("Cancel").disabled).toBe(false); + await act(async () => container.querySelector("dialog form")!.dispatchEvent( + new testWindow.Event("submit", { bubbles: true, cancelable: true }), + )); + await flush(); + expect(mutationBodies).toEqual([{ modelId: "grok-4.6", displayName: value }]); + expect(currentModels[0]!.displayNameOverride).toBe(value ?? undefined); + expect(container.querySelector("dialog")).toBeNull(); + }); + } + } + test("editing after a saved receipt explicitly starts a new save", async () => { await mountModels(); await act(async () => nameTrigger().click()); From d52399070f098865394500398862b05ef95261c6 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 07:46:19 +0900 Subject: [PATCH 021/412] fix(providers): repair static BigModel login and Responses effort Skip undocumented HTTP model-list validation through the existing unknown key-validation policy. Add a zero-fetch regression. For explicitly empty model/provider effort ladders, omit only the Responses effort field and retain reasoning summaries. Preserve omitted requests, nonempty model override precedence, unknown/non-rankable ladders, and forward behavior. Keep the documented Turbo max metadata without adding a selectable tier or injecting a wire default. Existing __omit__ mappings and noReasoningModels policy are unchanged. Add outbound serialization cases for omitted, max and ultra effort, summary preservation, input immutability, and unchanged consumer paths. Regenerate model metadata; the generated delta is only the BigModel Responses to zai alias. Validation: bun run generate:model-metadata and git diff --check passed. No tests, typecheck, lint or builds run; commit hooks skipped to honor that restriction. Main final CI and separate independent review remain required. Co-authored-by: jamespan --- .../src/content/docs/guides/providers.md | 5 ++ src/adapters/openai-responses.ts | 7 +++ src/generated/model-metadata.ts | 1 + src/providers/registry.ts | 2 + .../provider-registry-parity.test.ts | 17 ++++-- .../openai-responses-passthrough.test.ts | 52 +++++++++++++++++++ 6 files changed, 81 insertions(+), 3 deletions(-) diff --git a/docs-site/src/content/docs/guides/providers.md b/docs-site/src/content/docs/guides/providers.md index f5c4ddc190..081dced988 100644 --- a/docs-site/src/content/docs/guides/providers.md +++ b/docs-site/src/content/docs/guides/providers.md @@ -605,11 +605,16 @@ Both entries declare text input. The default model is `glm-5.3`; Responses reaso content is preserved on replay. The existing Codex export adds its compatibility `ultra` tier to GLM-5.3 and omits Turbo's default-effort field because Turbo has no selectable ladder; the provider metadata still records `max` for both models. +For Turbo, outgoing Responses requests omit `reasoning.effort`, including a caller's +`max` or `ultra`, while preserving requested reasoning summaries. This leaves effort +selection to the upstream default; opencodex does not inject a selectable or wire `max`. The example's `models.json` is a local catalog file, not a documented HTTP model-list response. This preset does not perform live model discovery. `glm-5.3-flash` is not seeded here because its exact Responses metadata is not verified. An existing custom provider with the same name keeps its configured destination and metadata. +CLI key login also skips the undocumented `/models` probe and reports validation as +unknown; successful key authentication is established by a subsequent inference request. ### Multiple API keys diff --git a/src/adapters/openai-responses.ts b/src/adapters/openai-responses.ts index 07c0556d5e..1b8c1b076e 100644 --- a/src/adapters/openai-responses.ts +++ b/src/adapters/openai-responses.ts @@ -630,6 +630,13 @@ function mapRoutedResponsesReasoningEffort( if (provider.authMode === "forward") return body; if (configuredReasoningEfforts(provider, modelId) === undefined) return body; if (!isPlainObject(body) || !isPlainObject(body.reasoning)) return body; + const declaredEfforts = modelRecordValue(provider.modelReasoningEfforts, modelId) ?? provider.reasoningEfforts; + // An explicitly empty ladder means no effort control, not no reasoning output. + // Omit only effort so the upstream default applies; unknown/non-rankable ladders stay untouched. + if (declaredEfforts?.length === 0 && Object.hasOwn(body.reasoning, "effort")) { + const { effort: _effort, ...reasoning } = body.reasoning; + return { ...body, reasoning: Object.keys(reasoning).length > 0 ? reasoning : undefined }; + } const requested = body.reasoning.effort; if (typeof requested !== "string") return body; diff --git a/src/generated/model-metadata.ts b/src/generated/model-metadata.ts index 662cf6f1a7..7220aa7509 100644 --- a/src/generated/model-metadata.ts +++ b/src/generated/model-metadata.ts @@ -31,6 +31,7 @@ const PROVIDER_ALIASES: Record = { "moonshot": "moonshot", "zhipu-bigmodel": "zai", "zhipu-bigmodel-coding": "zai", + "zhipu-bigmodel-responses": "zai", "minimax": "minimax", "minimax-cn": "minimax" } as const; diff --git a/src/providers/registry.ts b/src/providers/registry.ts index 1c3396a48a..ef7cb59e00 100644 --- a/src/providers/registry.ts +++ b/src/providers/registry.ts @@ -2557,6 +2557,8 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ defaultModel: "glm-5.3", models: ["glm-5.3", "glm-5-turbo"], liveModels: false, + // The local Codex catalog does not establish an authenticated HTTP /models contract. + apiKeyValidation: "unknown", jawcodeBundle: "zai", // A pre-existing same-named custom provider must retain its destination and key boundary. preserveCustomDestination: true, diff --git a/tests/providers/provider-registry-parity.test.ts b/tests/providers/provider-registry-parity.test.ts index 0d935d12a2..e2083646a5 100644 --- a/tests/providers/provider-registry-parity.test.ts +++ b/tests/providers/provider-registry-parity.test.ts @@ -1,10 +1,10 @@ -import { describe, expect, test } from "bun:test"; +import { describe, expect, spyOn, test } from "bun:test"; import { buildCatalogEntries } from "../../src/codex/catalog"; import { CURSOR_NO_VISION_MODELS } from "../../src/adapters/cursor/discovery"; import { getModelMetadata, resolveMetadataProvider } from "../../src/generated/model-metadata"; import { buildInitProviders } from "../../src/cli/init"; import { OAUTH_PROVIDERS } from "../../src/oauth"; -import { enrichProviderFromCatalog, KEY_LOGIN_PROVIDERS } from "../../src/oauth/key-providers"; +import { enrichProviderFromCatalog, KEY_LOGIN_PROVIDERS, validateApiKey } from "../../src/oauth/key-providers"; import { deriveFeaturedProviderIds, deriveInitProviders, @@ -459,7 +459,7 @@ describe("provider registry parity", () => { expect(registry.modelDiscovery).toBeUndefined(); expect(registry.preserveReasoningContentModels).toBeUndefined(); expect(KEY_LOGIN_PROVIDERS[id]).toMatchObject({ - models: ["glm-5.3", "glm-5-turbo"], liveModels: false, + models: ["glm-5.3", "glm-5-turbo"], liveModels: false, apiKeyValidation: "unknown", }); const provider = providerConfigSeed(registry); enrichProviderFromRegistry(id, provider); @@ -492,6 +492,17 @@ describe("provider registry parity", () => { expect(entries.some(entry => String(entry.slug).includes("glm-5.3-flash"))).toBe(false); }); + test("BigModel Responses key login does not probe an undocumented models endpoint", async () => { + const fetchSpy = spyOn(globalThis, "fetch").mockImplementation(async () => new Response(null, { status: 403 })); + try { + const id = "zhipu-bigmodel-responses"; + expect(await validateApiKey(id, KEY_LOGIN_PROVIDERS[id], "test-bigmodel-key")).toBe("unknown"); + expect(fetchSpy).not.toHaveBeenCalled(); + } finally { + fetchSpy.mockRestore(); + } + }); + test("BigModel Responses name collisions preserve custom transport and metadata", () => { const id = "zhipu-bigmodel-responses"; // Exercise both a different destination on the same wire and the canonical URL on diff --git a/tests/responses/openai-responses-passthrough.test.ts b/tests/responses/openai-responses-passthrough.test.ts index 0277da71d4..7e97217dc2 100644 --- a/tests/responses/openai-responses-passthrough.test.ts +++ b/tests/responses/openai-responses-passthrough.test.ts @@ -569,6 +569,58 @@ describe("DeepSeek Responses endpoint contract", () => { } }); + test.each([undefined, "max", "ultra"])("BigModel Turbo omits outbound effort %s and preserves summary requests", (effort) => { + const id = "zhipu-bigmodel-responses"; + const config: OcxConfig = { + port: 10100, + defaultProvider: id, + providers: { [id]: providerConfigSeed(getProviderRegistryEntry(id)!) }, + }; + const route = routeModel(config, `${id}/glm-5-turbo`); + for (const withSummary of [false, true]) { + const raw = { + model: route.modelId, + input: "ping", + ...(effort !== undefined || withSummary ? { + reasoning: { + ...(effort !== undefined ? { effort } : {}), + ...(withSummary ? { summary: "auto" } : {}), + }, + } : {}), + }; + const before = structuredClone(raw); + const request = createResponsesPassthroughAdapter(route.provider).buildRequest(parseRequest(raw)); + const wire = JSON.parse(request.body); + expect(request.url).toBe("https://open.bigmodel.cn/api/v1/responses"); + if (withSummary) expect(wire.reasoning).toEqual({ summary: "auto" }); + else expect(wire).not.toHaveProperty("reasoning"); + expect(raw).toEqual(before); + } + }); + + test("a provider-wide empty ladder removes even non-string raw effort", () => { + const keyed = { adapter: "openai-responses", baseUrl: "https://example.test/v1", authMode: "key" as const }; + const raw = { model: "model", input: "ping", reasoning: { effort: 123, summary: "auto" } }; + const wire = JSON.parse(createResponsesPassthroughAdapter({ ...keyed, reasoningEfforts: [] }) + .buildRequest(parseRequest(raw)).body); + expect(wire.reasoning).toEqual({ summary: "auto" }); + expect(raw.reasoning.effort).toBe(123); + }); + + test("empty-ladder repair preserves unknown, non-rankable and native forward effort behavior", () => { + const keyed = { adapter: "openai-responses", baseUrl: "https://example.test/v1", authMode: "key" as const }; + for (const unchanged of [keyed, { ...keyed, reasoningEfforts: ["enabled"] }, { ...provider, reasoningEfforts: [] }]) { + const raw = { model: "gpt-5.6-sol", input: "ping", reasoning: { effort: "ultra" } }; + const wire = JSON.parse(createResponsesPassthroughAdapter(unchanged).buildRequest(parseRequest(raw)).body); + expect(wire.reasoning.effort).toBe("ultra"); + } + // A model-specific nonempty ladder overrides a provider-wide empty declaration. + const wire = JSON.parse(createResponsesPassthroughAdapter({ + ...keyed, reasoningEfforts: [], modelReasoningEfforts: { model: ["low", "high", "max"] }, + }).buildRequest(parseRequest({ model: "model", input: "ping", reasoning: { effort: "ultra" } })).body); + expect(wire.reasoning.effort).toBe("max"); + }); + test("a config saved before the fix is backfilled, and a hand-set path is preserved", () => { const saved = { adapter: "openai-chat", baseUrl: "https://api.deepseek.com", apiKey: "sk-test" } as Parameters[1]; enrichProviderFromRegistry("deepseek", saved); From 9336a27ffeed3023500de914654b85b1e889fb81 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 07:47:39 +0900 Subject: [PATCH 022/412] test(providers): distinguish BigModel upstream and bridge modalities First CI run 34064726690 reports text,image rather than text for both BigModel models at provider-registry-parity.test.ts:471; the Turbo effort array remains empty. Source tracing confirms applyProviderConfigHints uses isModelVisionSidecarConsumer, also used by the runtime vision planner, to expose image attachment support for configured text-only models. Keep the official text-only registry declarations and assert them independently before checking the bridge-enriched model and final catalog modalities. Preserve exact Turbo empty effort expectations and all generic modality behavior. Clarify that image handling requires the existing available, enabled vision sidecar rather than native BigModel image support. Validation: supplied CI failure log and source contract reviewed; git diff --check passed. No local tests, typecheck, lint or builds run. Commit hooks skipped per execution restriction. Main final CI and independent review remain required. Co-authored-by: jamespan --- docs-site/src/content/docs/guides/providers.md | 9 +++++++-- tests/providers/provider-registry-parity.test.ts | 10 ++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/docs-site/src/content/docs/guides/providers.md b/docs-site/src/content/docs/guides/providers.md index 081dced988..5e46979816 100644 --- a/docs-site/src/content/docs/guides/providers.md +++ b/docs-site/src/content/docs/guides/providers.md @@ -601,8 +601,13 @@ The preset uses a **static roster** (`liveModels: false`) taken from the | `glm-5.3` | 1,048,576 | `low`, `high`, `max` | `max` | Supported | | `glm-5-turbo` | 204,800 | None (empty list) | `max` | Supported | -Both entries declare text input. The default model is `glm-5.3`; Responses reasoning -content is preserved on replay. The existing Codex export adds its compatibility +Both entries declare upstream text-only input. The Codex catalog advertises text and +image because opencodex's existing vision sidecar can describe images for text-only +models. Image handling requires an available, enabled vision sidecar; this does not +declare native BigModel image support. + +The default model is `glm-5.3`; Responses reasoning content is preserved on replay. +The existing Codex export adds its compatibility `ultra` tier to GLM-5.3 and omits Turbo's default-effort field because Turbo has no selectable ladder; the provider metadata still records `max` for both models. For Turbo, outgoing Responses requests omit `reasoning.effort`, including a caller's diff --git a/tests/providers/provider-registry-parity.test.ts b/tests/providers/provider-registry-parity.test.ts index e2083646a5..238a5808ea 100644 --- a/tests/providers/provider-registry-parity.test.ts +++ b/tests/providers/provider-registry-parity.test.ts @@ -458,6 +458,8 @@ describe("provider registry parity", () => { }); expect(registry.modelDiscovery).toBeUndefined(); expect(registry.preserveReasoningContentModels).toBeUndefined(); + const upstreamModalities = { "glm-5.3": ["text"], "glm-5-turbo": ["text"] }; + expect(registry.modelInputModalities).toEqual(upstreamModalities); expect(KEY_LOGIN_PROVIDERS[id]).toMatchObject({ models: ["glm-5.3", "glm-5-turbo"], liveModels: false, apiKeyValidation: "unknown", }); @@ -468,11 +470,14 @@ describe("provider registry parity", () => { const models = provider.models!.map(modelId => applyProviderConfigHints(id, provider, { provider: id, id: modelId, })); + // The official upstream declaration stays text-only. Catalog hints add image for the + // existing vision sidecar (vision/eligibility.ts), not native BigModel image support. + expect(provider.modelInputModalities).toEqual(upstreamModalities); expect(models).toMatchObject([ { id: "glm-5.3", contextWindow: 1_048_576, reasoningEfforts: ["low", "high", "max"], - defaultReasoningEffort: "max", supportsReasoningSummaries: true, inputModalities: ["text"] }, + defaultReasoningEffort: "max", supportsReasoningSummaries: true, inputModalities: ["text", "image"] }, { id: "glm-5-turbo", contextWindow: 204_800, reasoningEfforts: [], - defaultReasoningEffort: "max", supportsReasoningSummaries: true, inputModalities: ["text"] }, + defaultReasoningEffort: "max", supportsReasoningSummaries: true, inputModalities: ["text", "image"] }, ]); const entries = buildCatalogEntries(nativeTemplate(), [], models); for (const [modelId, window, efforts] of [ @@ -482,6 +487,7 @@ describe("provider registry parity", () => { const entry = entries.find(row => row.slug === `${id}/${modelId}`); expect(entry).toMatchObject({ context_window: window, supports_reasoning_summaries: true, + input_modalities: ["text", "image"], }); // Existing export policy adds a compatibility ultra tier and omits the default // for empty ladders. The provider/CatalogModel defaults above remain official max. From e352ede9f6ad2e2a5fa58d982315968c5f4520e6 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 07:48:54 +0900 Subject: [PATCH 023/412] fix(gui): balance name editor helper text on narrow screens Browser review found an isolated Korean ending at 390px. Balance the short helper sentence without fixed line breaks or changing the existing layout. Co-authored-by: Zig Zag --- gui/src/styles.css | 1 + 1 file changed, 1 insertion(+) diff --git a/gui/src/styles.css b/gui/src/styles.css index 630882006f..a5838be7e4 100644 --- a/gui/src/styles.css +++ b/gui/src/styles.css @@ -2672,6 +2672,7 @@ button.prov-account-row.active { cursor: default; } .model-display-name-current > .text-label { grid-column: 1 / -1; } .model-display-name-current strong { min-width: 0; overflow-wrap: anywhere; } .model-display-name-dialog > .input { margin-bottom: 6px; } +.model-display-name-dialog > .small { text-wrap: balance; } .model-display-name-error { margin-top: 8px; color: var(--red); From c721b94494a9c6f12e059aec9f9c77f0a0ce0380 Mon Sep 17 00:00:00 2001 From: JUN <243035832+lidge-jun@users.noreply.github.com> Date: Mon, 7 Sep 2026 07:48:43 +0900 Subject: [PATCH 024/412] fix(claude): report terminal closure buffer overflow once Distinguish termination entry from terminal delivery so closure-time overflow can release thinking and emit the bounded error without retrying closure. Prioritize collected errors over unfinished block serialization. Add eight real-budget closure-only overflow cases for EOF, failure, completion and incomplete terminals, including shared-budget collection. Tests and typecheck intentionally not run; parent owns final combined remote CI. Co-authored-by: SB Yoon <44089734+yansigit@users.noreply.github.com> Co-authored-by: Yumi --- src/claude/outbound.ts | 16 +++- .../claude-outbound.test.ts | 84 +++++++++++++++++++ 2 files changed, 97 insertions(+), 3 deletions(-) diff --git a/src/claude/outbound.ts b/src/claude/outbound.ts index 4dcdaa0eb7..ac06afac2d 100644 --- a/src/claude/outbound.ts +++ b/src/claude/outbound.ts @@ -234,6 +234,9 @@ export function responsesSseToAnthropicSse( let bufferBytes = 0; let started = false; let terminated = false; + // Starting termination can still throw while closing a block or emitting its + // terminal frame. Only a delivered terminal forbids the bounded overflow error. + let terminalDelivered = false; let cancelled = false; let blockIndex = 0; let open: OpenBlock | null = null; @@ -338,6 +341,7 @@ export function responsesSseToAnthropicSse( usage: anthropicUsage(usage, webSearchRequests), }); emit("message_stop", { type: "message_stop" }); + terminalDelivered = true; }; // upstreamDerived: transient upstream statuses become overloaded_error so the // Anthropic-SDK client retries with backoff; proxy-internal exceptions stay @@ -346,12 +350,15 @@ export function responsesSseToAnthropicSse( // resets reach the reader catch (no failed-tail relay) and stay api_error — // same as today, deliberate residual. const fail = (status: number, message: string, upstreamDerived = false, code?: string) => { - if (terminated) return; + // finish/fail sets terminated before closeOpenBlock. A closure-time + // allocation failure must still emit one error, without retrying closure. + if (terminated && (code !== "translation_buffer_limit" || terminalDelivered)) return; terminated = true; if (code === "translation_buffer_limit") { releaseThinkingBuffer(open); if (open?.callId) translatorBudget.closeCall(open.callId); open = null; + terminalDelivered = true; // No normal close frames are valid after overflow. Emit exactly one bounded // typed terminal without consulting the exhausted budget. controller.enqueue(encoder.encode(sseFrame("error", anthropicErrorBody( @@ -368,10 +375,12 @@ export function responsesSseToAnthropicSse( // Do not manufacture message_start before the terminal error. Earlier transport-only // pings remain valid and do not turn the failure into a partial message. emit("error", anthropicErrorBody(status, message, type, code)); + terminalDelivered = true; return; } closeOpenBlock(); emit("error", anthropicErrorBody(status, message, type, code)); + terminalDelivered = true; }; const handleFrame = (eventName: string, data: Rec) => { @@ -981,9 +990,10 @@ export async function collectAnthropicMessage( } finally { reader.releaseLock(); } - closeBlock(); - + // Error is authoritative. In particular, do not allocate another copy of an + // unfinished thinking block after the translator reported closure overflow. if (error) return error; + closeBlock(); return { id: `msg_${uuid()}`, type: "message", diff --git a/tests/claude-integration/claude-outbound.test.ts b/tests/claude-integration/claude-outbound.test.ts index 33faa2e839..78fcf0879c 100644 --- a/tests/claude-integration/claude-outbound.test.ts +++ b/tests/claude-integration/claude-outbound.test.ts @@ -342,6 +342,90 @@ describe("claude outbound SSE", () => { expect(reasoningReleased).toBe(reasoningCommitted); }); + for (const terminal of ["eof", "failed", "completed", "incomplete"] as const) { + for (const buffered of [false, true]) { + test(`closure-only reasoning overflow: ${terminal}, ${buffered ? "collector" : "stream"}`, async () => { + // All small deltas fit, including replacement reservations. Closing needs + // the retained 32 KiB text PLUS its base64 signature frame. For the + // collector allow its additional retained text in the same real budget. + const budget = createTestTranslatorBudget({ maxTurnBytes: (buffered ? 102 : 70) * 1024 }); + let reasoningBytes = 0; + let maxReasoningBytes = 0; + let reasoningBytesAtOverflow = -1; + const trackedBudget: TranslatorBudget = { + openCall: id => budget.openCall(id), + closeCall: id => budget.closeCall(id), + reserveTransient(bytes, scope) { + let reservation: ReturnType; + try { reservation = budget.reserveTransient(bytes, scope); } + catch (error) { reasoningBytesAtOverflow = reasoningBytes; throw error; } + return { + commitRetained() { + reservation.commitRetained(); + if (scope.kind === "reasoning") { + reasoningBytes += bytes; + maxReasoningBytes = Math.max(maxReasoningBytes, reasoningBytes); + } + }, + release: () => reservation.release(), + }; + }, + chargeRetained: (bytes, scope) => budget.chargeRetained(bytes, scope), + releaseRetained(bytes, scope) { + if (scope.kind === "reasoning") reasoningBytes -= bytes; + budget.releaseRetained(bytes, scope); + }, + observeAcceptedRequestCopy: bytes => budget.observeAcceptedRequestCopy(bytes), + observeExternallyCapped: (kind, bytes) => budget.observeExternallyCapped(kind, bytes), + snapshot: () => budget.snapshot(), + dispose: () => budget.dispose(), + }; + const text = "x".repeat(32 * 1024); + const frames = Array.from({ length: 128 }, () => sse("response.reasoning_text.delta", { + item_id: "rs_closure", content_index: 0, delta: text.slice(0, 256), + })); + if (terminal !== "eof") { + frames.push(sse(`response.${terminal}`, { response: terminal === "failed" + ? { error: { message: "upstream failure", status: 502 } } + : terminal === "incomplete" + ? { status: "incomplete", incomplete_details: { reason: "max_output_tokens" }, usage: {} } + : { status: "completed", usage: {} } })); + // Neither a repeated completion nor a later failure may add a terminal. + frames.push(sse("response.completed", { response: { status: "completed", usage: {} } })); + frames.push(sse("response.failed", { response: { error: { message: "late failure" } } })); + } + const stream = responsesSseToAnthropicSse(streamFromChunks(frames), "m", { + translatorBudget: trackedBudget, pingIntervalMs: 0, + }); + if (buffered) { + const message = await collectAnthropicMessage(stream, "m", trackedBudget); + expect(message).toMatchObject({ type: "error", error: { + type: "request_too_large", code: "translation_buffer_limit", + } }); + expect(message).not.toHaveProperty("content"); + expect(message).not.toHaveProperty("stop_reason"); + } else { + const events = await collectEvents(stream); + const deltas = events.filter(event => event.data.delta?.type === "thinking_delta"); + expect(deltas.map(event => event.data.delta.thinking).join("")).toBe(text); + expect(events.filter(event => event.name === "error")).toHaveLength(1); + expect(events.at(-1)).toMatchObject({ name: "error", data: { type: "error", error: { + type: "request_too_large", code: "translation_buffer_limit", + } } }); + expect(JSON.stringify(events.at(-1)).length).toBeLessThan(1024); + expect(events.some(event => event.name === "message_stop" || event.name === "message_delta" || event.name === "content_block_stop")).toBe(false); + expect(events.some(event => event.data.delta?.type === "signature_delta")).toBe(false); + } + // These prove failure happened after all text was retained, not while + // ingesting a delta, and the error path released the thinking reservation. + expect(reasoningBytesAtOverflow).toBe(text.length); + expect(maxReasoningBytes).toBeGreaterThanOrEqual(text.length); + expect(reasoningBytes).toBe(0); + expect(budget.snapshot().overflows).toBe(1); + }); + } + } + test("same-part deltas and index-free reasoning frames never get a separator", async () => { const samePart = [ sse("response.created", { response: { id: "resp_1", status: "in_progress" } }), From 513391e8fa94716867ac127821beaa003ddbf48f Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 07:49:57 +0900 Subject: [PATCH 025/412] test(container): isolate synthetic inference without internal networking [skip ci] CI run 34064754947 built and started the image, then proved internal-only networking suppressed host port publication. Keep actual Compose networking and seed a checked loopback-only provider into disposable state before startup. Verify loaded configuration and hashes through recreation. Co-authored-by: Buseong Kim Co-authored-by: Ingwannu --- scripts/ci/docker-smoke.ts | 46 +++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/scripts/ci/docker-smoke.ts b/scripts/ci/docker-smoke.ts index 0745f6bd9e..6bcf56f164 100644 --- a/scripts/ci/docker-smoke.ts +++ b/scripts/ci/docker-smoke.ts @@ -126,6 +126,20 @@ const fixture = JSON.stringify({ models: [{ const token = randomBytes(32).toString("hex"); const replacement = randomBytes(32).toString("hex"); const sha256 = (value: string) => createHash("sha256").update(value).digest("hex"); +let seededConfigHash = ""; + +// Check the loader, including its schema-repair/default-provider fallback, before server startup +// and again in each running container. This isolates synthetic inference, not all process egress. +const fixtureConfigCheck = ` + const { loadConfig } = await import('./src/config.ts'); + const effective = loadConfig(); + const provider = effective.providers.smoke; + if (Object.keys(effective.providers).join(',') !== 'smoke' || effective.defaultProvider !== 'smoke' + || provider?.adapter !== 'openai-responses' || provider?.authMode !== 'local' + || provider?.baseUrl !== 'http://127.0.0.1:9/v1' || provider?.codexAccountMode !== undefined || provider?.apiKey + || effective.runtimeRole !== 'hub' || effective.hostname !== '0.0.0.0' || effective.port !== 10100 + || effective.codexAutoStart !== false || effective.codexShimAutoRestore !== false) throw new Error('unsafe effective fixture config'); +`; interface Container { Id: string; @@ -169,6 +183,7 @@ async function inspect() { const stateProbe = ` import { readFileSync, statSync, writeFileSync } from 'node:fs'; import { createHash } from 'node:crypto'; + ${fixtureConfigCheck} const homes = ['/home/bun/.opencodex', '/home/bun/.codex']; const uid = process.getuid(); if (uid === 0) throw new Error('root user'); @@ -192,6 +207,7 @@ const stateProbe = ` async function state() { const hashes = JSON.parse(await compose(["exec", "-T", "hub", "bun", "-e", stateProbe])) as string[]; check(hashes.length === 3 && hashes.every(hash => /^[a-f0-9]{64}$/.test(hash)), "invalid state evidence"); + check(hashes[0] === seededConfigHash, "seeded config changed"); check(hashes[1] === sha256(`${token}\n`) && hashes[2] === sha256(fixture), "token/catalog changed"); return JSON.stringify(hashes); } @@ -280,8 +296,6 @@ async function main() { writeFileSync(join(scratch, "empty.env"), "", { mode: 0o600 }); writeFileSync(join(scratch, "override.json"), JSON.stringify({ services: { hub: { image, restart: "no" } }, - // Block upstream egress even if an admission regression reaches a provider path. - networks: { default: { internal: true } }, }), { mode: 0o600 }); env = { PATH: process.env.PATH ?? "/usr/local/bin:/usr/bin:/bin", TMPDIR: scratch, @@ -293,10 +307,32 @@ async function main() { progress("validate and build"); await compose(["config", "--quiet"]); await build(); - progress("bootstrap and seed synthetic catalog"); + progress("verify shipped config and seed loopback-only fixture"); + seededConfigHash = await compose(["run", "--rm", "-T", "--no-deps", "hub", "bun", "-e", + ` + import { readFileSync, writeFileSync } from 'node:fs'; + import { createHash } from 'node:crypto'; + import { atomicWriteFile } from './src/config/atomic-write.ts'; + const { shipped, catalog } = JSON.parse(await Bun.stdin.text()); + const path = '/home/bun/.opencodex/config.json'; + if (readFileSync(path, 'utf8') !== shipped || readFileSync('docker/config.json', 'utf8') !== shipped) { + throw new Error('shipped config mismatch'); + } + const config = JSON.parse(shipped); + if (config.runtimeRole !== 'hub' || config.hostname !== '0.0.0.0' || config.port !== 10100 + || config.codexAutoStart !== false || config.codexShimAutoRestore !== false) throw new Error('shipped runtime contract'); + // Port 9 has no listener in this image. Replace all provider routes before any server starts; + // even an admission regression cannot send these synthetic requests to a real provider. + config.providers = { smoke: { adapter: 'openai-responses', baseUrl: 'http://127.0.0.1:9/v1', authMode: 'local' } }; + config.defaultProvider = 'smoke'; + atomicWriteFile(path, JSON.stringify(config) + '\\n'); + ${fixtureConfigCheck} + writeFileSync('/home/bun/.codex/opencodex-catalog.json', catalog, { mode: 0o600, flag: 'wx' }); + console.log(createHash('sha256').update(readFileSync(path)).digest('hex')); + `], JSON.stringify({ shipped: readFileSync(join(root, "docker/config.json"), "utf8"), catalog: fixture })); + check(/^[a-f0-9]{64}$/.test(seededConfigHash), "invalid seeded config evidence"); + progress("bootstrap throwaway token"); await compose(["run", "--rm", "-T", "--no-deps", "hub", "bun", "run", "docker/bootstrap-token.ts"], `${token}\n`); - await compose(["run", "--rm", "-T", "--no-deps", "hub", "bun", "-e", - "import { writeFileSync } from 'node:fs'; writeFileSync('/home/bun/.codex/opencodex-catalog.json', await Bun.stdin.text(), { mode: 0o600, flag: 'wx' });"], fixture); progress("start and check admission"); await compose(["up", "--no-build", "--wait", "--wait-timeout", "120", "hub"], undefined, 150_000); const first = await inspect(); From 76e667fbb6e06b58d84a92e45481b9f0db27a298 Mon Sep 17 00:00:00 2001 From: JUN <243035832+lidge-jun@users.noreply.github.com> Date: Mon, 7 Sep 2026 07:59:20 +0900 Subject: [PATCH 026/412] test(responses): account for ordinary tool catalog guidance Combined Linux CI at c721b94494a9c6f12e059aec9f9c77f0a0ce0380 reported six messages where the seed fixtures expected five. Non-OpenAI chat translation prepends system tool-catalog guidance while compaction removes context.tools first. Explicitly require one system prefix advertising read_value on ordinary and stored-ID turns, and none on compact turns. Keep exact total length, ordered history content, original tool pairing and compact output assertions. Follow-up to synthetic #3807 coverage motivated by @DaveW001 and @stephen-drew; no original source patch copied. Source-only review and git diff --check passed. Local tests, typecheck and build NOT RUN by instruction. --- .../responses-compaction-routing.test.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/tests/responses/responses-compaction-routing.test.ts b/tests/responses/responses-compaction-routing.test.ts index 8faca32bef..a787024d95 100644 --- a/tests/responses/responses-compaction-routing.test.ts +++ b/tests/responses/responses-compaction-routing.test.ts @@ -1817,10 +1817,20 @@ describe("established-history external task input (#3807)", () => { return captured; } - function expectHistory(sent: Record, tail: Array> = []) { + function expectHistory( + sent: Record, + tail: Array> = [], + withToolCatalog = true, + ) { const messages = sent.messages as Array>; - expect(messages).toHaveLength(wireHistory.length + tail.length); - expect(messages).toMatchObject([...wireHistory, ...tail]); + // Ordinary non-OpenAI chat turns prepend catalog guidance; compaction removes + // context.tools before translation. Require that exact prefix, not arbitrary extras. + const prefix = withToolCatalog ? [{ + role: "system", + content: expect.stringContaining("Valid tool names for this turn are exactly `read_value`."), + }] : []; + expect(messages).toHaveLength(prefix.length + wireHistory.length + tail.length); + expect(messages).toMatchObject([...prefix, ...wireHistory, ...tail]); // Exactly one original pair: delivery must not acquire a synthesized tool identity. expect(messages.flatMap(message => message.tool_calls ?? [])).toEqual(wireHistory[1]!.tool_calls); expect(messages.filter(message => message.role === "tool")).toEqual([wireHistory[2]]); @@ -1882,7 +1892,7 @@ describe("established-history external task input (#3807)", () => { expect(captured).toHaveLength(1); expectHistory(captured[0]!, [ { role: "user", content: expect.stringContaining("CONTEXT CHECKPOINT COMPACTION") }, - ]); + ], false); expect(captured[0]!.tools).toBeUndefined(); expect(JSON.stringify(captured)).not.toContain("compaction_trigger"); if (version === "v2 trigger") { From 9b5b670db3e24ae5522c5d61e74c071c71257a26 Mon Sep 17 00:00:00 2001 From: JUN <243035832+lidge-jun@users.noreply.github.com> Date: Mon, 7 Sep 2026 08:00:29 +0900 Subject: [PATCH 027/412] test(claude): correct replay and closure overflow oracles Match the canonical user string observed at parent combined head c721b9449 while preserving exact assistant block arrays. Capture closure-overflow output before collecting under the same unreset budget, separating concurrent ingestion pressure from closure-only failure. Assert all text, one bounded error, no success terminal, exact 32768-byte overflow boundary and no second overflow. No local tests or typecheck run. Co-authored-by: SB Yoon <44089734+yansigit@users.noreply.github.com> Co-authored-by: Yumi --- .../anthropic-thinking-signature.test.ts | 2 +- .../claude-outbound.test.ts | 41 +++++++++++-------- 2 files changed, 26 insertions(+), 17 deletions(-) diff --git a/tests/adapters/anthropic/anthropic-thinking-signature.test.ts b/tests/adapters/anthropic/anthropic-thinking-signature.test.ts index db8f489c4f..86ca82b412 100644 --- a/tests/adapters/anthropic/anthropic-thinking-signature.test.ts +++ b/tests/adapters/anthropic/anthropic-thinking-signature.test.ts @@ -399,7 +399,7 @@ describe("Claude / Responses / intended Anthropic replay fidelity", () => { const request = await adapter.buildRequest(parsed); const replay = JSON.parse(request.body as string) as { messages: Array<{ role: string; content: unknown }> }; expect(replay.messages).toEqual([ - { role: "user", content: [{ type: "text", text: "question" }] }, + { role: "user", content: "question" }, { role: "assistant", content: fixture.blocks }, { role: "user", content: [{ type: "tool_result", tool_use_id: tool.id, content: "result" }] }, ]); diff --git a/tests/claude-integration/claude-outbound.test.ts b/tests/claude-integration/claude-outbound.test.ts index 78fcf0879c..67380bb44a 100644 --- a/tests/claude-integration/claude-outbound.test.ts +++ b/tests/claude-integration/claude-outbound.test.ts @@ -346,9 +346,11 @@ describe("claude outbound SSE", () => { for (const buffered of [false, true]) { test(`closure-only reasoning overflow: ${terminal}, ${buffered ? "collector" : "stream"}`, async () => { // All small deltas fit, including replacement reservations. Closing needs - // the retained 32 KiB text PLUS its base64 signature frame. For the - // collector allow its additional retained text in the same real budget. - const budget = createTestTranslatorBudget({ maxTurnBytes: (buffered ? 102 : 70) * 1024 }); + // the retained 32 KiB text PLUS its base64 signature frame. Capture the + // generated stream before collection: concurrent collector retention can + // exceed a shared budget during ingestion instead of exercising closure. + // Collection below reuses this SAME budget, without resetting it. + const budget = createTestTranslatorBudget({ maxTurnBytes: 70 * 1024 }); let reasoningBytes = 0; let maxReasoningBytes = 0; let reasoningBytesAtOverflow = -1; @@ -397,24 +399,31 @@ describe("claude outbound SSE", () => { const stream = responsesSseToAnthropicSse(streamFromChunks(frames), "m", { translatorBudget: trackedBudget, pingIntervalMs: 0, }); - if (buffered) { - const message = await collectAnthropicMessage(stream, "m", trackedBudget); + const captured = buffered ? await new Response(stream).text() : undefined; + const capturedFrames = captured?.split("\n\n").filter(Boolean).map(frame => `${frame}\n\n`); + const events = await collectEvents(capturedFrames ? streamFromChunks(capturedFrames) : stream); + const deltas = events.filter(event => event.data.delta?.type === "thinking_delta"); + expect(deltas.map(event => event.data.delta.thinking).join("")).toBe(text); + expect(events.filter(event => event.name === "error")).toHaveLength(1); + expect(events.at(-1)).toMatchObject({ name: "error", data: { type: "error", error: { + type: "request_too_large", code: "translation_buffer_limit", + } } }); + expect(JSON.stringify(events.at(-1)).length).toBeLessThan(1024); + expect(events.some(event => event.name === "message_stop" || event.name === "message_delta" || event.name === "content_block_stop")).toBe(false); + expect(events.some(event => event.data.delta?.type === "signature_delta")).toBe(false); + if (capturedFrames) { + expect(capturedFrames.join("")).toBe(captured); + expect(reasoningBytesAtOverflow).toBe(text.length); + expect(reasoningBytes).toBe(0); + expect(budget.snapshot().overflows).toBe(1); + // Feed the actual generated frames, without inventing an error event or + // collecting one huge chunk that introduces a different buffer limit. + const message = await collectAnthropicMessage(streamFromChunks(capturedFrames), "m", trackedBudget); expect(message).toMatchObject({ type: "error", error: { type: "request_too_large", code: "translation_buffer_limit", } }); expect(message).not.toHaveProperty("content"); expect(message).not.toHaveProperty("stop_reason"); - } else { - const events = await collectEvents(stream); - const deltas = events.filter(event => event.data.delta?.type === "thinking_delta"); - expect(deltas.map(event => event.data.delta.thinking).join("")).toBe(text); - expect(events.filter(event => event.name === "error")).toHaveLength(1); - expect(events.at(-1)).toMatchObject({ name: "error", data: { type: "error", error: { - type: "request_too_large", code: "translation_buffer_limit", - } } }); - expect(JSON.stringify(events.at(-1)).length).toBeLessThan(1024); - expect(events.some(event => event.name === "message_stop" || event.name === "message_delta" || event.name === "content_block_stop")).toBe(false); - expect(events.some(event => event.data.delta?.type === "signature_delta")).toBe(false); } // These prove failure happened after all text was retained, not while // ingesting a delta, and the error path released the thinking reservation. From 619f7a7b0ecfdc3dd32cf8b399dd2851e3002f10 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 08:01:39 +0900 Subject: [PATCH 028/412] test(container): declare the synthetic loopback destination [skip ci] The Docker diagnostic failed because loadConfig correctly rejects private destinations unless explicitly allowed. A bounded remote fixture reproduced the fallback and passed with the test-only flag. Validate the fixture before startup and report fixed seed-phase codes without exposing child errors. Co-authored-by: Buseong Kim Co-authored-by: Ingwannu --- scripts/ci/docker-smoke.ts | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/scripts/ci/docker-smoke.ts b/scripts/ci/docker-smoke.ts index 6bcf56f164..eb488cf3b1 100644 --- a/scripts/ci/docker-smoke.ts +++ b/scripts/ci/docker-smoke.ts @@ -136,6 +136,7 @@ const fixtureConfigCheck = ` const provider = effective.providers.smoke; if (Object.keys(effective.providers).join(',') !== 'smoke' || effective.defaultProvider !== 'smoke' || provider?.adapter !== 'openai-responses' || provider?.authMode !== 'local' + || provider?.allowPrivateNetwork !== true || provider?.baseUrl !== 'http://127.0.0.1:9/v1' || provider?.codexAccountMode !== undefined || provider?.apiKey || effective.runtimeRole !== 'hub' || effective.hostname !== '0.0.0.0' || effective.port !== 10100 || effective.codexAutoStart !== false || effective.codexShimAutoRestore !== false) throw new Error('unsafe effective fixture config'); @@ -308,13 +309,18 @@ async function main() { await compose(["config", "--quiet"]); await build(); progress("verify shipped config and seed loopback-only fixture"); - seededConfigHash = await compose(["run", "--rm", "-T", "--no-deps", "hub", "bun", "-e", + const seeded = await run(["docker", ...composeArgs, "run", "--rm", "-T", "--no-deps", "hub", "bun", "-e", ` import { readFileSync, writeFileSync } from 'node:fs'; import { createHash } from 'node:crypto'; - import { atomicWriteFile } from './src/config/atomic-write.ts'; + // Exit codes are fixed diagnostic markers; never serialize the caught exception. + let seedStage = 70; + try { + const { atomicWriteFile } = await import('./src/config/atomic-write.ts'); + seedStage = 71; const { shipped, catalog } = JSON.parse(await Bun.stdin.text()); const path = '/home/bun/.opencodex/config.json'; + seedStage = 72; if (readFileSync(path, 'utf8') !== shipped || readFileSync('docker/config.json', 'utf8') !== shipped) { throw new Error('shipped config mismatch'); } @@ -323,13 +329,27 @@ async function main() { || config.codexAutoStart !== false || config.codexShimAutoRestore !== false) throw new Error('shipped runtime contract'); // Port 9 has no listener in this image. Replace all provider routes before any server starts; // even an admission regression cannot send these synthetic requests to a real provider. - config.providers = { smoke: { adapter: 'openai-responses', baseUrl: 'http://127.0.0.1:9/v1', authMode: 'local' } }; + config.providers = { smoke: { adapter: 'openai-responses', baseUrl: 'http://127.0.0.1:9/v1', authMode: 'local', allowPrivateNetwork: true } }; config.defaultProvider = 'smoke'; + seedStage = 73; + const { validateConfigCandidate } = await import('./src/config.ts'); + if (!validateConfigCandidate(config).ok) throw new Error('invalid fixture'); + seedStage = 74; atomicWriteFile(path, JSON.stringify(config) + '\\n'); + seedStage = 75; ${fixtureConfigCheck} + seedStage = 76; writeFileSync('/home/bun/.codex/opencodex-catalog.json', catalog, { mode: 0o600, flag: 'wx' }); + seedStage = 77; console.log(createHash('sha256').update(readFileSync(path)).digest('hex')); + } catch { process.exitCode = seedStage; } `], JSON.stringify({ shipped: readFileSync(join(root, "docker/config.json"), "utf8"), catalog: fixture })); + const seedFailures: Record = { + 70: "imports", 71: "input", 72: "shipped config contract", 73: "fixture validation", + 74: "atomic config write", 75: "effective config", 76: "catalog write", 77: "config hash", + }; + check(seeded.code === 0, `seed failed: ${seedFailures[seeded.code ?? -1] ?? "unclassified child failure"} (exit ${seeded.code ?? "signal"})`); + seededConfigHash = seeded.out.trim(); check(/^[a-f0-9]{64}$/.test(seededConfigHash), "invalid seeded config evidence"); progress("bootstrap throwaway token"); await compose(["run", "--rm", "-T", "--no-deps", "hub", "bun", "run", "docker/bootstrap-token.ts"], `${token}\n`); From 4c1d9afaa6152b6a84c5f5a929aefbae52adc595 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 08:05:11 +0900 Subject: [PATCH 029/412] fix(gui): reconcile display name draft during snapshot render Replace effect-driven draft synchronization with a guarded render-state adjustment when the parent supplies a new confirmed model snapshot. Keep the dialog mounted, retaining focus refs, pending state and request errors. Ordinary typing and catalog polling do not replace the editor snapshot. Local tests, lint, typecheck and build NOT RUN by owner mandate. Static diff inspection only; final CI and independent review remain parent-owned. Co-authored-by: Zig Zag --- gui/src/components/ModelDisplayNameDialog.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/gui/src/components/ModelDisplayNameDialog.tsx b/gui/src/components/ModelDisplayNameDialog.tsx index c24b6612d7..2a57ff8279 100644 --- a/gui/src/components/ModelDisplayNameDialog.tsx +++ b/gui/src/components/ModelDisplayNameDialog.tsx @@ -41,6 +41,7 @@ export default function ModelDisplayNameDialog({ const titleId = useId(); const helpId = useId(); const errorId = useId(); + const [draftSnapshot, setDraftSnapshot] = useState(model); const [draft, setDraft] = useState(model.displayNameOverride ?? ""); const [validationKey, setValidationKey] = useState(null); @@ -57,11 +58,13 @@ export default function ModelDisplayNameDialog({ if (saveFailed) inputRef.current?.focus(); }, [requestError, saving]); - // Parent replaces this snapshot only after a confirmed mutation, not catalog polling. - useEffect(() => { + // Parent replaces this snapshot only after a confirmed mutation, not typing or polling. + // Adjust before committing children, preserving the mounted dialog and its focus refs. + if (draftSnapshot !== model) { + setDraftSnapshot(model); setDraft(model.displayNameOverride ?? ""); setValidationKey(null); - }, [model]); + } const validationError = validationKey ? t(validationKey) : null; const visibleError = validationError ?? requestError; From d6cf8764ff2758c9ab0aca63cb0dda07a0ccae2c Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 07:36:59 +0900 Subject: [PATCH 030/412] feat(integrations): carry Raycast client from #3733 Carry source fa8b488dce0aa661653b0ef4c61d33b6a76249ff onto current dev. Local test, typecheck, lint and build execution deferred to combined remote CI per task scope. Co-authored-by: Chanhee Lee --- .../260904_raycast_integration/000_plan.md | 121 ++++++++ .../pr-screenshots/raycast-integration.png | Bin 0 -> 282997 bytes .../content/docs/fr/guides/integrations.md | 36 ++- .../content/docs/fr/reference/cli/agents.md | 15 +- .../src/content/docs/guides/integrations.md | 39 ++- .../content/docs/ja/reference/cli/agents.md | 7 +- .../content/docs/ko/reference/cli/agents.md | 7 +- .../src/content/docs/reference/cli/agents.md | 14 +- .../content/docs/ru/reference/cli/agents.md | 15 +- .../content/docs/tr/guides/integrations.md | 40 ++- .../content/docs/tr/reference/cli/agents.md | 16 +- .../docs/zh-cn/reference/cli/agents.md | 7 +- .../content/docs/zh-tw/guides/integrations.md | 31 +- .../docs/zh-tw/reference/cli/agents.md | 7 +- gui/public/provider-icons/README.md | 13 + gui/public/provider-icons/raycast.svg | 3 + gui/src/app-routing.ts | 1 + .../client-config-clients.ts | 5 +- gui/src/components/integration-marks.ts | 1 + gui/src/i18n/de.ts | 6 + gui/src/i18n/en.ts | 6 + gui/src/i18n/fr.ts | 6 + gui/src/i18n/ja.ts | 6 + gui/src/i18n/ko.ts | 6 + gui/src/i18n/ru.ts | 6 + gui/src/i18n/tr.ts | 6 + gui/src/i18n/zh-TW.ts | 6 + gui/src/i18n/zh.ts | 6 + .../integrations/FileIntegrationPage.tsx | 5 + .../pages/integrations/RaycastPlanNotice.tsx | 32 +++ gui/src/pages/integrations/integration-api.ts | 15 + .../pages/integrations/integration-tabs.ts | 2 + .../pages/integrations/overview-clients.ts | 1 + gui/tests/client-config-panel.test.tsx | 4 +- gui/tests/fr-localization.test.ts | 2 + gui/tests/integration-marks.test.ts | 9 +- gui/tests/integrations-api.test.ts | 4 +- gui/tests/integrations-overview-rows.test.ts | 7 +- gui/tests/locale-parity.test.ts | 2 + gui/tests/raycast-plan-notice.test.tsx | 51 ++++ scripts/test-layout/layout.json | 3 + src/cli/dispatch.ts | 2 +- src/cli/help.ts | 2 +- src/cli/index.ts | 38 ++- src/cli/integrations.ts | 35 ++- src/cli/registry.ts | 4 +- src/clients/config-export.ts | 36 +++ src/clients/config-export/contracts.ts | 3 +- src/clients/config-export/raycast.ts | 86 ++++++ src/clients/model-presentation.ts | 61 ++++ src/integrations/catalog-refresh.ts | 2 +- src/integrations/merge.ts | 183 ++++++++++-- src/integrations/raycast-detect.ts | 110 +++++++ src/integrations/registry.ts | 18 ++ src/integrations/state.ts | 74 ++++- src/integrations/writer.ts | 69 +++-- src/server/management/config-routes.ts | 8 +- src/server/management/integration-routes.ts | 31 +- tests/clients/integrations-merge.test.ts | 268 +++++++++++++++++ tests/clients/integrations-state.test.ts | 4 +- tests/clients/raycast-client.test.ts | 271 ++++++++++++++++++ tests/clients/raycast-detect.test.ts | 82 ++++++ .../clients/sync-client-integrations.test.ts | 18 +- .../client-config-export-new-clients.test.ts | 12 +- tests/config/client-config-export.test.ts | 6 +- .../config/client-config-new-clients.test.ts | 12 +- tests/fixtures/test-layout-expected.json | 3 + tests/gui/integrations-invariants.test.ts | 39 ++- .../management-integration-routes.test.ts | 26 ++ 69 files changed, 1904 insertions(+), 168 deletions(-) create mode 100644 devlog/_plan/260904_raycast_integration/000_plan.md create mode 100644 docs-site/public/pr-screenshots/raycast-integration.png create mode 100644 gui/public/provider-icons/raycast.svg create mode 100644 gui/src/pages/integrations/RaycastPlanNotice.tsx create mode 100644 gui/tests/raycast-plan-notice.test.tsx create mode 100644 src/clients/config-export/raycast.ts create mode 100644 src/clients/model-presentation.ts create mode 100644 src/integrations/raycast-detect.ts create mode 100644 tests/clients/integrations-merge.test.ts create mode 100644 tests/clients/raycast-client.test.ts create mode 100644 tests/clients/raycast-detect.test.ts diff --git a/devlog/_plan/260904_raycast_integration/000_plan.md b/devlog/_plan/260904_raycast_integration/000_plan.md new file mode 100644 index 0000000000..c98701a2cd --- /dev/null +++ b/devlog/_plan/260904_raycast_integration/000_plan.md @@ -0,0 +1,121 @@ +# Raycast Custom Providers integration — plan + +Raycast (Pro-only) reads `~/.config/raycast/ai/providers.yaml` and watches it, so a +file-toggle client is the right shape. Spec: https://manual.raycast.com/ai/custom-providers. + +Decisions taken with the maintainer: + +1. Install signal is `~/.config/raycast/ai` (the directory Raycast creates on + "Reveal Providers Config"), not `Raycast.app`. +2. A non-Pro plan is a warning in status/GUI, never a refusal. +3. Every exported model declares `tools: supported: true` (same stance as Hermes: + every routed model is tool-capable). +4. Array ownership goes into the shared merge/classifier layer as a path-segment + selector rather than a Raycast-only patcher. `structure/09_client-integrations.md` + forbids a special case that lives only in the writer or only in status; a + selector segment that `readPath`/`setPath`/`deletePath` all understand is the + one way both keep agreeing. + +## Raycast file shape + +```yaml +providers: + - id: opencodex # <- our one owned sequence item + name: OpenCodex + base_url: http://127.0.0.1:10100/v1 + models: + - id: anthropic/claude-opus-5 + name: Claude Opus 5 + context: 200000 + abilities: + temperature: { supported: true } + vision: { supported: true } + system_message: { supported: true } + tools: { supported: true } + reasoning_effort: { supported: false } +``` + +No `api_keys`: loopback is unauthenticated and the file has no env interpolation, +so the client is `loopbackOnly: true`. + +## Pro signal (macOS) + +`defaults read com.raycast.macos.v1 subscriptions_active` → `1` / `0`. Read via +`Bun.spawnSync`, not by parsing the binary plist (cfprefsd caches). Windows: `unknown`. + +## Work packages (disjoint files, run in parallel) + +| WP | Files | +|---|---| +| 1 merge selector | `src/integrations/merge.ts`, `src/integrations/state.ts`, `tests/integrations-merge.test.ts` | +| 2 client | `src/clients/config-export.ts`, `src/integrations/registry.ts`, `src/cli/registry.ts`, `src/cli/help.ts`, `tests/raycast-client.test.ts`, list-assertion tests | +| 3 sync fan-out | `src/integrations/owned-refresh.ts`, `src/cli/dispatch.ts`, `src/server/management/config-routes.ts`, `src/cli/index.ts`, `tests/sync-client-integrations.test.ts` | +| 4 detect + API + GUI | `src/integrations/raycast-detect.ts`, `src/server/management/integration-routes.ts`, `src/cli/integrations.ts`, `gui/**`, i18n | +| 5 docs | `docs-site/**` | + +### WP1 — `[field=value]` path segment + +```ts +// merge.ts +const ARRAY_SELECTOR = /^\[([A-Za-z_][A-Za-z0-9_]*)=([^\]]+)\]$/u; +export type PathSegment = { kind: "key"; key: string } | { kind: "select"; field: string; value: string }; +export function parseSegment(raw: string): PathSegment; +export class AmbiguousSelectorError extends Error {} +``` + +- `setPath`: a `select` segment addresses the element of an array whose + `item[field] === value`. Missing parent → `[]` is created (recorded by + `createdContainerPaths`). Match found → replace in place; none → push; ≥2 → + throw `AmbiguousSelectorError` (writer maps it to `unsafe` alongside + `UnserializableValueError`). +- `deletePath`: splice the match; an emptied array we created is pruned by the + existing `createdContainers` walk. +- `state.ts readPath`: `select` → `Array.prototype.find`. Because the classifier + and the writer share this one function, status and mutation cannot disagree. +- `blockedContainerPath`: a non-array, non-undefined value where a `select` + segment expects an array is blocked (`providers: {}` written by the user). +- `createdContainerPaths`: unchanged join rule; a `select` segment is never a + container prefix on its own. +- A key-only path is byte-for-byte the old behaviour; the twelve existing clients + do not change. + +### WP2 — client registration + +`config-export.ts`: `"raycast"` in `ExportClientId`; `raycastAiDir(env, home)` = +`join(home, ".config", "raycast", "ai")` (Raycast ignores XDG; same path on Windows); +`raycastConfigPath` = `…/providers.yaml`; types `RaycastAbility`, +`RaycastModelEntry`, `RaycastProviderEntry`, `RaycastGeneratedConfig`; +`buildRaycastClientConfig(ctx)` over `normalizeExportModels(ctx.models)` with +`exportModelLabel(model)` as `name`, `contextWindow` → `context`, abilities: +`temperature: !(reasoningEfforts?.length)`, `vision: inputModalities?.includes("image") ?? false`, +`system_message: true`, `tools: true`, `reasoning_effort: (reasoningEfforts?.length ?? 0) > 0`. +`buildRaycastContribution` = `singleFragment("raycast", ["providers", "[id=opencodex]"], providers[0])`. +`summarizeRaycast` finds the `opencodex` item. `EXPORT_CLIENTS.raycast`: +`filename: "raycast-providers.yaml"`, `format: "yaml"`, `apiKeyEnv: ""`, `loopbackOnly: true`. + +`registry.ts`: `configPath: raycastConfigPath`, `detectDir: raycastAiDir`, no +`sourcePreservingYaml` (that patcher handles block-map leaves only), no `writerLock`. + +### WP3 — sync fan-out + +Raycast joins the shared `refreshOwnedCatalogIntegrations` coordinator. Model +selection changes use its default `["pi", "aside", "raycast"]` set; +`POST /api/sync` uses `["mcode", "pi", "aside", "raycast"]`; direct CLI sync +updates `["mcode", "pi", "raycast"]` locally and keeps Aside behind its +server-owned multi-profile route. Startup and ensure refresh the owned Raycast +catalog after the Codex catalog publishes, using the live port. + +### WP4 — detection, API, GUI + +`raycast-detect.ts` mirrors `cursor-detect.ts` (injectable deps, read-only): +`RaycastPlan = "pro" | "free" | "unknown"`, `detectRaycast(deps)` → +`{ appPath, aiDirPresent, plan }`. `GET /api/client-integrations/raycast` +adds `raycast: { plan, appPath, aiDirPresent }` to the envelope (only for this +client). `ocx integration client status --client raycast` prints `plan`. GUI: +every surface in `devlog/_fin/260831_aside_client_and_integrations_ux/002_registration_checklist.md` +plus one `RaycastPlanNotice` shown when `plan !== "pro"` or `!aiDirPresent`. + +### WP5 — docs + +`guides/integrations.md` row + paragraph (Pro, reveal-first), `reference/cli/agents.md`, +translated locales, `bun run build` in `docs-site`. diff --git a/docs-site/public/pr-screenshots/raycast-integration.png b/docs-site/public/pr-screenshots/raycast-integration.png new file mode 100644 index 0000000000000000000000000000000000000000..e17261c158d64cab5ce5f8112000ffbb3cb3500a GIT binary patch literal 282997 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

Ba>p$xU-%CZ15eSXiGGY@+Ad1CW%9 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%0DYP=M4x*Sq0Ks2}hf7Oo=n+dCXl5zSJW~oZja| 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%0DEd-b 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 z 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

A0+6Mo1P(PAj7!Qi250`_gDOyCJRWxN-CLFYa6 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%0A7UdBS})4ht_ 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 z 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 BVSoSt literal 0 HcmV?d00001 diff --git a/docs-site/src/content/docs/fr/guides/integrations.md b/docs-site/src/content/docs/fr/guides/integrations.md index c65531a4d3..c70d471f39 100644 --- a/docs-site/src/content/docs/fr/guides/integrations.md +++ b/docs-site/src/content/docs/fr/guides/integrations.md @@ -1,10 +1,10 @@ --- title: Intégrations -description: Connectez opencodex à OpenCode, Pi, OMP, Hermes, OpenClaw, Kimi Code, Gajae Code, DeepSeek Harness et MiniMax Code depuis le tableau de bord — un commutateur par client, avec une sauvegarde avant chaque écriture. +description: Connectez opencodex à OpenCode, Pi, OMP, Hermes, OpenClaw, Kimi Code, Gajae Code, DeepSeek Harness, MiniMax Code et Raycast depuis le tableau de bord — un commutateur par client, avec une sauvegarde avant chaque écriture. --- L'onglet **Intégrations** écrit le bloc fournisseur d'opencodex dans le fichier de configuration du client, -puis peut le retirer. Neuf clients fonctionnent ainsi, chacun avec son propre commutateur : +puis peut le retirer. Dix clients fonctionnent ainsi, chacun avec son propre commutateur : | Client | Fichier de configuration | Format | Prise d'effet de la modification | Identifiant | |---|---|---|---|---| @@ -17,6 +17,7 @@ puis peut le retirer. Neuf clients fonctionnent ainsi, chacun avec son propre co | Gajae Code | `~/.gjc/agent/models.yml` | YAML | dans les nouvelles sessions ou à l'ouverture de `/model` |`OPENCODEX_GAJAE_API_KEY` | | DeepSeek Harness (DSH) | `$DSH_HOME/settings.yaml` (`~/.dsh/settings.yaml` par défaut) | YAML | rechargement à chaud | jeton porteur fictif et non secret pour le bouclage | | MiniMax Code | `~/.minimax/config.yaml` | YAML | dans les nouvelles sessions ou après l’ouverture du sélecteur de modèles | valeur fictive de bouclage | +| Raycast | `~/.config/raycast/ai/providers.yaml` | YAML | immédiatement à l'enregistrement — Raycast surveille le fichier | aucun — bouclage uniquement | La prise en charge gérée de DSH exige au minimum **DSH 0.1.0-rc.6**. OpenCodex ne possède que le fragment `llm-pi-ai.providers.opencodex` : **Appliquer** et **Actualiser** remplacent ce fragment, **Désactiver** ne @@ -33,6 +34,27 @@ L’actualisation de l’intégration met également à jour les fenêtres de co d’effort de raisonnement faisant autorité ; les capacités inconnues sont omises et l’effort courant, qui appartient à la session MCode, est préservé. +Raycast a deux prérequis. Les fournisseurs personnalisés (Custom Providers) sont une fonctionnalité +**Raycast Pro** : avec un forfait gratuit, le fichier est tout de même écrit, mais +`ocx integration client status --client raycast` et la page Intégrations signalent un avertissement, +car Raycast ne le lira pas. Et Raycast ne crée son dossier `ai` que lorsque vous ouvrez une fois +Raycast → Settings → AI → **Reveal Providers Config** ; opencodex utilise ce dossier comme signal +d'installation et indique que le client n'est pas installé tant qu'il n'existe pas. Raycast lit +`~/.config/raycast/ai/providers.yaml` aussi bien sur macOS que sur Windows et n'honore pas +`XDG_CONFIG_HOME` ; ce chemin ne peut donc pas être déplacé. + +Le bloc géré est un seul élément, `id: opencodex`, dans la séquence `providers` du fichier : +`name: OpenCodex`, `base_url: http://:/v1`, et chaque modèle routé avec ses `abilities` — +`tools` et `system_message` sont toujours pris en charge, `vision` suit les modalités d'entrée du +catalogue, `reasoning_effort` est défini lorsque le modèle dispose d'une échelle d'effort, et +`temperature` est désactivé pour les modèles de raisonnement. Les autres fournisseurs du fichier sont +préservés, et la désactivation ne retire que l'élément OpenCodex. Raycast prend en compte la +modification dès l'enregistrement du fichier, sans redémarrage ; les modèles apparaissent dans le +sélecteur de modèles de Raycast regroupés sous **OpenCodex**. Le fichier n'a aucun emplacement pour +un identifiant, ce client est donc limité au bouclage : aucune entrée `api_keys` n'est écrite et une +liaison hors bouclage est refusée. Le format est documenté sur +[manual.raycast.com/ai/custom-providers](https://manual.raycast.com/ai/custom-providers). + Les chemins respectent les variables de remplacement propres à chaque client, lorsqu'elles existent. Pour OMP, la présence de `OMP_PROFILE` l'emporte sur `PI_PROFILE`, même si sa valeur est explicitement vide. Un profil nommé emploie `PI_CONFIG_DIR` comme nom de répertoire relatif au dossier personnel de l'utilisateur @@ -93,7 +115,7 @@ niveaux. Dans ces cas, le commutateur est verrouillé afin que rien ne soit modi **OMP** n'est pas affecté non plus par les modifications voisines, mais pour une autre raison : son outil d'écriture ne modifie, octet par octet, que sa propre plage `providers.opencodex` ; le reste du fichier n'est jamais réécrit. Pour les autres formats susceptibles de contenir des commentaires (Hermes, OpenClaw, -Kimi Code, Gajae Code et MiniMax Code — documents YAML, JSON5 et TOML réécrits en entier), ou lorsque les propres entrées +Kimi Code, Gajae Code, MiniMax Code et Raycast — documents YAML, JSON5 et TOML réécrits en entier), ou lorsque les propres entrées d'opencodex ont été modifiées, le commutateur se verrouille et la désactivation est refusée plutôt que de deviner quelles modifications vous appartiennent. @@ -169,9 +191,11 @@ ocx integration client enable --client mcode ocx mcode ``` -Une fois l’intégration connectée, `ocx sync` actualise également le bloc MCode géré avec les fenêtres de -contexte et les niveaux d’effort de raisonnement actuels. Les blocs absents, modifiés par un tiers, non sûrs -ou jamais gérés restent intacts ; réactivez explicitement l’intégration lorsque vous souhaitez la reconnecter. +Une fois l’intégration connectée, `ocx sync` et `POST /api/sync` actualisent les catalogues MCode, +Pi, Aside et Raycast gérés. Le démarrage du proxy actualise aussi le catalogue Raycast géré. +Les changements de visibilité, de fournisseur ou de préréglage actualisent Pi, Aside et Raycast. +Les blocs absents, modifiés par un tiers, non sûrs ou supprimés manuellement restent intacts ; +réactivez explicitement l’intégration lorsque vous souhaitez la reconnecter. Le CLI distinct de la plateforme MiniMax (`mmx`) n’est pas une intégration à commutateur de fichier. Ses commandes textuelles utilisent le point de terminaison compatible avec Anthropic de MiniMax ; OpenCodex diff --git a/docs-site/src/content/docs/fr/reference/cli/agents.md b/docs-site/src/content/docs/fr/reference/cli/agents.md index e1501048c6..749119f70a 100644 --- a/docs-site/src/content/docs/fr/reference/cli/agents.md +++ b/docs-site/src/content/docs/fr/reference/cli/agents.md @@ -164,7 +164,7 @@ Gérez et appliquez la clôture du modèle Grok Build. ## Exportation de la configuration client -### `ocx export --client ` +### `ocx export --client ` Imprimez une configuration client connectée au proxy en cours d'exécution. La commande sérialise le bloc fournisseur `opencodex` — URL de base, liste de modèles et référence d’identifiant du client @@ -175,7 +175,7 @@ les modèles Codex peuvent actuellement voir. | Option | Actions | | --- | --- | -| `--client ` | Requis. Sélectionne le dialecte de configuration client. | +| `--client ` | Requis. Sélectionne le dialecte de configuration client. | | `--json` | Imprimez le document généré en tant que JSON sur la sortie standard pour les scripts. Il s'agit de JSON même lorsque le format natif du client sélectionné est YAML, TOML ou JSON5. | | `--out ` | Écrivez le format de configuration natif du client dans ``. Refuse de remplacer un fichier existant. | | `--force` | Autoriser `--out` à remplacer un fichier existant. | @@ -205,6 +205,17 @@ propres valeurs par défaut à ces lignes. | `mcode` | `~/.minimax/config.yaml` (`MINIMAX_DATA_DIR`, puis l'ancien `MAVIS_DATA_DIR`, l'emportent une fois définis ; une valeur relative est refusée) | `mcode-config.yaml` | aucun — espace réservé de bouclage | | `zcode` | `~/.zcode/v2/config.json` (`ZCODE_DATA_DIR` l'emporte une fois défini ; une valeur relative est refusée) | `config.json` | aucun — espace réservé de bouclage | | `prime` | `~/.prime/agent/models.json` (`PRIME_AGENT_CODING_AGENT_DIR` l'emporte une fois défini ; une valeur relative est refusée) | `prime-models.json` | aucun — espace réservé de bouclage | +| `raycast` | `~/.config/raycast/ai/providers.yaml`, sur macOS comme sur Windows (Raycast n'honore pas `XDG_CONFIG_HOME`) | `raycast-providers.yaml` | aucun — bouclage uniquement, aucune entrée `api_keys` n'est écrite | + +L'exportation Raycast est un document `providers.yaml` autonome contenant un seul élément `id: opencodex` +dans la séquence `providers` : `name: OpenCodex`, l'URL de base `/v1` du proxy et chaque modèle routé avec +ses `abilities` (`tools` et `system_message` toujours pris en charge, `vision` d'après les modalités d'entrée +du catalogue, `reasoning_effort` lorsque le modèle dispose d'une échelle d'effort, `temperature` désactivé +pour les modèles de raisonnement). Les fournisseurs personnalisés sont une fonctionnalité Raycast Pro, et +Raycast surveille le fichier : une modification enregistrée prend effet sans redémarrage. Le format est +documenté sur [manual.raycast.com/ai/custom-providers](https://manual.raycast.com/ai/custom-providers). +Aucune entrée `api_keys` n'est écrite ; cette exportation est donc limitée au bouclage et une liaison hors +bouclage est refusée. L'exportation DSH gérée nécessite DSH 0.1.0-rc.6 ou plus récent et ne possède que `llm-pi-ai.providers.opencodex`. DSH recharge à chaud ce fournisseur ; le modèle par défaut de l'utilisateur et diff --git a/docs-site/src/content/docs/guides/integrations.md b/docs-site/src/content/docs/guides/integrations.md index 0c95908206..bb8cea7001 100644 --- a/docs-site/src/content/docs/guides/integrations.md +++ b/docs-site/src/content/docs/guides/integrations.md @@ -1,10 +1,10 @@ --- title: Integrations -description: Connect opencodex to OpenCode, Pi, OMP, Hermes, OpenClaw, Kimi Code, Gajae Code, DeepSeek Harness, MiniMax Code, ZCode, Prime Agent and Aside from the dashboard — one switch per client, with a backup taken before every write. +description: Connect opencodex to OpenCode, Pi, OMP, Hermes, OpenClaw, Kimi Code, Gajae Code, DeepSeek Harness, MiniMax Code, ZCode, Prime Agent, Aside and Raycast from the dashboard — one switch per client, with a backup taken before every write. --- The **Integrations** tab writes opencodex's provider block into a client's own config -file, and removes it again. Twelve clients work this way, each with a switch: +file, and removes it again. Thirteen clients work this way, each with a switch: | Client | Config file | Format | When the change takes effect | Credential | |---|---|---|---|---| @@ -20,6 +20,7 @@ file, and removes it again. Twelve clients work this way, each with a switch: | Prime Agent | `~/.prime/agent/models.json` | JSON | new sessions | loopback placeholder | | ZCode | `~/.zcode/v2/config.json` | JSON | on restart | loopback placeholder | | Aside | `~/.aside/u//models.json` | JSON | after fully quitting and reopening Aside | loopback placeholder | +| Raycast | `~/.config/raycast/ai/providers.yaml` | YAML | immediately on save — Raycast watches the file | none — loopback only | Generated catalogs include only enabled models from each provider selection. This applies to both downloads and managed integrations, including Pi and Aside. The management model list still shows @@ -61,6 +62,28 @@ One caveat specific to Aside: the running app rewrites `models.json` itself, so fully quit and reopen Aside after applying, the same way Claude Desktop needs a restart. Aside's block is loopback-only and never carries a real credential. +Raycast has two prerequisites. Custom Providers is a **Raycast Pro** feature: on a +free plan the file is still written, but `ocx integration client status --client +raycast` and the Integrations page report a warning, because Raycast will not +read it. And Raycast only creates its `ai` folder when you open Raycast → +Settings → AI → **Reveal Providers Config** once; opencodex uses that folder as +the install signal and reports the client as not installed until then. Raycast +reads `~/.config/raycast/ai/providers.yaml` on macOS and Windows alike and does +not honor `XDG_CONFIG_HOME`, so that path is not relocatable. + +The managed block is one element, `id: opencodex`, in the file's `providers` +sequence: `name: OpenCodex`, `base_url: http://:/v1`, and every +routed model with its `abilities` — `tools` and `system_message` are always +supported, `vision` follows the catalog's input modalities, `reasoning_effort` +is set when the model has an effort ladder, and `temperature` is turned off for +reasoning models. Other providers in the file are preserved, and disable removes +only the OpenCodex element. Raycast picks up the change as soon as the file is +saved, no restart needed; the models appear in Raycast's model picker grouped +under **OpenCodex**. The file has no place for a credential, so this client is +loopback-only: no `api_keys` entry is written and a non-loopback bind is refused. +The format is documented at +[manual.raycast.com/ai/custom-providers](https://manual.raycast.com/ai/custom-providers). + Cursor has a tab but is not one of these switches. Regular Cursor calls custom endpoints from its own backend, so a loopback proxy is unreachable without a public tunnel, and Cursor's separate Private Inference build is configured inside Cursor. The **Cursor** tab is read-only: @@ -130,7 +153,7 @@ than 1000 levels — which locks the switch instead, so nothing is silently chan **OMP** is unaffected by sibling edits too, for a different reason: its writer patches only its own `providers.opencodex` range byte-wise, so the rest of the file is never rewritten. For the remaining formats that can carry comments -(Hermes, OpenClaw, Kimi Code, Gajae Code, MiniMax Code — YAML, JSON5 and TOML +(Hermes, OpenClaw, Kimi Code, Gajae Code, MiniMax Code, Raycast — YAML, JSON5 and TOML written as whole documents), or whenever our own entries were edited, the switch locks and disable refuses rather than guessing which edits were yours. @@ -216,10 +239,12 @@ ocx integration client enable --client mcode ocx mcode ``` -Once connected, `ocx sync` refreshes owned MCode, Pi, and Aside catalogs with the current -model selection, context windows, and reasoning-effort ladders. Changes to model visibility, -provider selection, or presets also refresh connected Pi and Aside catalogs. Foreign-edited -or unsafe blocks stay untouched, as do previously owned blocks you removed manually. +Once connected, `ocx sync` and `POST /api/sync` refresh owned MCode, Pi, Aside, and +Raycast catalogs with the current model selection, context windows, and reasoning-effort +ladders. Proxy startup refreshes an owned Raycast catalog. Changes to model visibility, +provider selection, or presets also refresh connected Pi, Aside, and Raycast catalogs. +Missing, foreign-edited, or unsafe blocks stay untouched, as do previously owned blocks +you removed manually. An enabled Aside profile is an exception to the usual owned-only refresh: if its account directory exists and it has never had an owned block, sync may create its first block when that slot is empty. A prior Aside connection enables this behavior for all registered diff --git a/docs-site/src/content/docs/ja/reference/cli/agents.md b/docs-site/src/content/docs/ja/reference/cli/agents.md index cd1b4fa30f..a223362a56 100644 --- a/docs-site/src/content/docs/ja/reference/cli/agents.md +++ b/docs-site/src/content/docs/ja/reference/cli/agents.md @@ -125,7 +125,7 @@ Grok Build モデル フェンスを管理および適用します。 ## クライアント設定のエクスポート -### `ocx export --client ` +### `ocx export --client ` 実行中のプロキシに接続するクライアント設定を出力します。このコマンドは、ベース URL、モデル一覧、およびクライアントに応じた認証情報参照または `opencodex-loopback` プレースホルダーを含む `opencodex` プロバイダーブロックを、選択したクライアントのネイティブ形式でシリアル化します。 @@ -133,7 +133,7 @@ Grok Build モデル フェンスを管理および適用します。 |旗 |アクション | | --- | --- | -| `--client ` |必須。クライアントの設定形式を選択します。 | +| `--client ` |必須。クライアントの設定形式を選択します。 | | `--json` |構成 JSON のみを標準出力に出力するため、リダイレクトはバイト正確な出力をキャプチャします。 `--out` 書き込みメモを含むすべての診断は stderr に送られます。 | | `--out ` |設定を `` に書き込みます。既存のファイルの置き換えを拒否します。 | | `--force` | `--out` が既存のファイルを置き換えることを許可します。 | @@ -160,6 +160,9 @@ ocx export --client opencode --out ~/opencodex-opencode.json | `mcode` | `~/.minimax/config.yaml` (`MINIMAX_DATA_DIR`、次に旧 `MAVIS_DATA_DIR` が設定時に優先。相対値は拒否されます) | `mcode-config.yaml` | なし — loopback placeholder | | `zcode` | `~/.zcode/v2/config.json` (`ZCODE_DATA_DIR` が設定時に優先。相対値は拒否されます) | `config.json` | なし — loopback placeholder | | `prime` | `~/.prime/agent/models.json` (`PRIME_AGENT_CODING_AGENT_DIR` が設定時に優先。相対値は拒否されます) | `prime-models.json` | なし — loopback placeholder | +| `raycast` | `~/.config/raycast/ai/providers.yaml` (macOS と Windows で同じ。Raycast は `XDG_CONFIG_HOME` を尊重しません) | `raycast-providers.yaml` | なし — loopback のみ。`api_keys` エントリは書き込まれません | + +Raycast のエクスポートは、`providers` シーケンスに `id: opencodex` 要素を 1 つだけ持つ独立した `providers.yaml` 文書です。内容は `name: OpenCodex`、プロキシの `/v1` ベース URL、および `abilities` 付きのルーティング済み全モデルです (`tools` と `system_message` は常にサポート、`vision` はカタログの入力モダリティから、`reasoning_effort` はモデルに effort ラダーがある場合、`temperature` は推論モデルではオフ)。Custom Providers は Raycast Pro の機能で、Raycast はこのファイルを監視しているため、保存した変更は再起動なしで反映されます。形式は [manual.raycast.com/ai/custom-providers](https://manual.raycast.com/ai/custom-providers) に記載されています。`api_keys` エントリは書き込まれないため、このエクスポートは loopback 専用で、loopback 以外のバインドは拒否されます。 opencode は `{env:OPENCODEX_OPENCODE_API_KEY}` を補間します。opencodex が生成する Pi のエクスポートには環境変数が不要で、リテラルのプレースホルダー `opencodex-loopback` が入ります。この値は必須です。Pi はモデル リストを構築する際に `apiKey` を解決し、既存の設定に未設定の環境変数参照がある場合はプロバイダー全体を隠すためです。ループバックでは、生成されたプレースホルダーをプロキシが検査することはありません。 diff --git a/docs-site/src/content/docs/ko/reference/cli/agents.md b/docs-site/src/content/docs/ko/reference/cli/agents.md index a229551a83..3624a2a803 100644 --- a/docs-site/src/content/docs/ko/reference/cli/agents.md +++ b/docs-site/src/content/docs/ko/reference/cli/agents.md @@ -131,7 +131,7 @@ Grok Build model fence를 관리하고 적용합니다. ## 클라이언트 설정 내보내기 -### `ocx export --client ` +### `ocx export --client ` 실행 중인 프록시에 연결할 client config를 출력합니다. 이 명령은 base URL, model list, 그리고 client에 따라 credential reference 또는 `opencodex-loopback` placeholder를 포함한 `opencodex` provider block을 선택한 client의 네이티브 형식으로 직렬화합니다. @@ -139,7 +139,7 @@ Grok Build model fence를 관리하고 적용합니다. | 플래그 | 동작 | | --- | --- | -| `--client ` | 필수입니다. 클라이언트 설정 형식을 선택합니다. | +| `--client ` | 필수입니다. 클라이언트 설정 형식을 선택합니다. | | `--json` | config JSON만 stdout에 출력하므로, redirect가 byte-exact 출력을 캡처합니다. `--out` write note를 포함한 모든 진단 메시지는 stderr로 갑니다. | | `--out ` | config를 ``에 씁니다. 기존 파일이 있으면 덮어쓰지 않습니다. | | `--force` | `--out`이 기존 파일을 덮어쓰도록 허용합니다. | @@ -166,6 +166,9 @@ ocx export --client opencode --out ~/opencodex-opencode.json | `mcode` | `~/.minimax/config.yaml` (`MINIMAX_DATA_DIR`, 그다음 레거시 `MAVIS_DATA_DIR`가 설정되면 우선. 상대 경로는 거부됩니다) | `mcode-config.yaml` | 없음 — loopback placeholder | | `zcode` | `~/.zcode/v2/config.json` (`ZCODE_DATA_DIR`가 설정되면 우선. 상대 경로는 거부됩니다) | `config.json` | 없음 — loopback placeholder | | `prime` | `~/.prime/agent/models.json` (`PRIME_AGENT_CODING_AGENT_DIR`가 설정되면 우선. 상대 경로는 거부됩니다) | `prime-models.json` | 없음 — loopback placeholder | +| `raycast` | `~/.config/raycast/ai/providers.yaml` (macOS와 Windows 모두 동일. Raycast는 `XDG_CONFIG_HOME`을 따르지 않습니다) | `raycast-providers.yaml` | 없음 — loopback 전용. `api_keys` 항목은 쓰지 않습니다 | + +Raycast 내보내기는 `providers` 시퀀스에 `id: opencodex` 요소 하나만 담은 독립 `providers.yaml` 문서입니다. 내용은 `name: OpenCodex`, proxy의 `/v1` base URL, 그리고 `abilities`가 붙은 라우팅된 모든 모델입니다(`tools`와 `system_message`는 항상 지원, `vision`은 카탈로그의 입력 모달리티를 따름, `reasoning_effort`는 모델에 effort 사다리가 있을 때, `temperature`는 추론 모델에서 꺼짐). Custom Providers는 Raycast Pro 기능이며, Raycast가 이 파일을 감시하므로 저장한 변경은 재시작 없이 적용됩니다. 형식은 [manual.raycast.com/ai/custom-providers](https://manual.raycast.com/ai/custom-providers)에 문서화되어 있습니다. `api_keys` 항목은 쓰지 않으므로 이 내보내기는 loopback 전용이며, loopback이 아닌 bind는 거부됩니다. opencode는 `{env:OPENCODEX_OPENCODE_API_KEY}`를 보간합니다. opencodex가 생성한 Pi 블록에는 환경 변수가 필요 없으며, 리터럴 placeholder인 `opencodex-loopback`이 들어갑니다. 이 값은 필수입니다. Pi는 모델 목록을 만들 때 `apiKey`를 해석하고, 기존 config에 설정되지 않은 env 참조가 있으면 provider 전체를 숨기기 때문입니다. 루프백에서 proxy는 생성된 placeholder를 검사하지 않습니다. diff --git a/docs-site/src/content/docs/reference/cli/agents.md b/docs-site/src/content/docs/reference/cli/agents.md index e6470eae0e..300bb7d5e2 100644 --- a/docs-site/src/content/docs/reference/cli/agents.md +++ b/docs-site/src/content/docs/reference/cli/agents.md @@ -207,7 +207,7 @@ Manage and apply the Grok Build model fence. ## Client config export -### `ocx export --client ` +### `ocx export --client ` Print a client config wired to the running proxy. The command serializes the `opencodex` provider block — base URL, model list, and the client's credential @@ -218,7 +218,7 @@ models Codex can currently see. | Flag | Action | | --- | --- | -| `--client ` | Required. Selects the client config dialect. | +| `--client ` | Required. Selects the client config dialect. | | `--json` | Print the generated document as JSON on stdout for scripts. This is JSON even when the selected client's native format is YAML, TOML, or JSON5. | | `--out ` | Write the client's native config format to ``. Refuses to replace an existing file. | | `--force` | Allow `--out` to replace an existing file. | @@ -248,6 +248,7 @@ client applies its own defaults for those). | `zcode` | `~/.zcode/v2/config.json` (`ZCODE_DATA_DIR` wins when set; a relative value is refused) | `config.json` | none — loopback placeholder | | `prime` | `~/.prime/agent/models.json` (`PRIME_AGENT_CODING_AGENT_DIR` wins when set; a relative value is refused) | `prime-models.json` | none — loopback placeholder | | `aside` | `~/.aside/u//models.json` for the account Aside's own `accounts.json` names as current; an unreadable manifest is refused rather than defaulting to an account | `aside-models.json` | none — loopback placeholder | +| `raycast` | `~/.config/raycast/ai/providers.yaml` on macOS and Windows alike (Raycast does not honor `XDG_CONFIG_HOME`) | `raycast-providers.yaml` | none — loopback only, no `api_keys` entry is written | The managed DSH export requires DSH 0.1.0-rc.6 or newer and owns only `llm-pi-ai.providers.opencodex`. DSH hot reloads that provider; the user's default model and @@ -260,6 +261,15 @@ hide the whole provider when an existing config contains an unset env reference. checks the generated placeholder on loopback. OMP supports provider-level headers, but this initial integration deliberately remains loopback-only; remote `x-opencodex-api-key` wiring is deferred. +The Raycast export is a standalone `providers.yaml` document with one `id: opencodex` element +in the `providers` sequence: `name: OpenCodex`, the proxy's `/v1` base URL, and every routed model +with its `abilities` (`tools` and `system_message` always supported, `vision` from the catalog's +input modalities, `reasoning_effort` when the model has an effort ladder, `temperature` off for +reasoning models). Custom Providers is a Raycast Pro feature, and Raycast watches the file, so a +saved change takes effect without a restart. The format is documented at +[manual.raycast.com/ai/custom-providers](https://manual.raycast.com/ai/custom-providers). No +`api_keys` entry is written, so this export is loopback-only and a non-loopback bind is refused. + The MCode, ZCode and Prime exports are loopback-only for the same reason and likewise carry the `opencodex-loopback` placeholder rather than a real credential. Prime Agent reads the same `models.json` contract Pi does, so the two exports produce the same document; only the destination diff --git a/docs-site/src/content/docs/ru/reference/cli/agents.md b/docs-site/src/content/docs/ru/reference/cli/agents.md index b49162dbc6..8df8175173 100644 --- a/docs-site/src/content/docs/ru/reference/cli/agents.md +++ b/docs-site/src/content/docs/ru/reference/cli/agents.md @@ -152,7 +152,7 @@ override, но файлы на диске никогда не меняются. ## Экспорт client config -### `ocx export --client ` +### `ocx export --client ` Печатает client config, направленный на работающий прокси. Команда сериализует блок провайдера `opencodex` в нативном формате выбранного клиента: base URL, список моделей и, @@ -163,7 +163,7 @@ override, но файлы на диске никогда не меняются. | Флаг | Действие | | --- | --- | -| `--client ` | Обязателен. Выбирает формат конфигурации клиента. | +| `--client ` | Обязателен. Выбирает формат конфигурации клиента. | | `--json` | Печатать только JSON-конфиг в stdout, чтобы redirect сохранял побайтно точный вывод. Вся диагностика, включая заметку о записи через `--out`, идёт в stderr. | | `--out ` | Записать конфиг в ``. Перезаписывать существующий файл не позволит. | | `--force` | Разрешить `--out` заменить существующий файл. | @@ -193,6 +193,17 @@ ocx export --client opencode --out ~/opencodex-opencode.json | `mcode` | `~/.minimax/config.yaml` (`MINIMAX_DATA_DIR`, затем устаревшая `MAVIS_DATA_DIR`, имеют приоритет, если заданы; относительное значение отклоняется) | `mcode-config.yaml` | нет — loopback placeholder | | `zcode` | `~/.zcode/v2/config.json` (`ZCODE_DATA_DIR` имеет приоритет, если задана; относительное значение отклоняется) | `config.json` | нет — loopback placeholder | | `prime` | `~/.prime/agent/models.json` (`PRIME_AGENT_CODING_AGENT_DIR` имеет приоритет, если задана; относительное значение отклоняется) | `prime-models.json` | нет — loopback placeholder | +| `raycast` | `~/.config/raycast/ai/providers.yaml` одинаково на macOS и Windows (Raycast не учитывает `XDG_CONFIG_HOME`) | `raycast-providers.yaml` | нет — только loopback, запись `api_keys` не создаётся | + +Экспорт для Raycast — это отдельный документ `providers.yaml` с одним элементом `id: opencodex` в +последовательности `providers`: `name: OpenCodex`, базовый URL прокси с `/v1` и каждая маршрутизируемая +модель с её `abilities` (`tools` и `system_message` поддерживаются всегда, `vision` берётся из входных +модальностей каталога, `reasoning_effort` задаётся, когда у модели есть шкала усилий, `temperature` +отключена для рассуждающих моделей). Custom Providers — функция Raycast Pro, а Raycast следит за файлом, +поэтому сохранённое изменение вступает в силу без перезапуска. Формат описан на +[manual.raycast.com/ai/custom-providers](https://manual.raycast.com/ai/custom-providers). Запись +`api_keys` не создаётся, поэтому этот экспорт работает только через loopback, а привязка вне loopback +отклоняется. opencode интерполирует `{env:OPENCODEX_OPENCODE_API_KEY}`. Сгенерированный opencodex экспорт для Pi не требует переменной окружения и несёт литеральную заглушку `opencodex-loopback`. Это значение diff --git a/docs-site/src/content/docs/tr/guides/integrations.md b/docs-site/src/content/docs/tr/guides/integrations.md index fea4b37dd4..ff0dcaa41e 100644 --- a/docs-site/src/content/docs/tr/guides/integrations.md +++ b/docs-site/src/content/docs/tr/guides/integrations.md @@ -1,10 +1,10 @@ --- title: Entegrasyonlar -description: Kontrol panelinden OpenCode, Pi, OMP, Hermes, OpenClaw, Kimi Code, Gajae Code, DeepSeek Harness ve MiniMax Code'u opencodex'e bağlayın — istemci başına tek bir anahtar ve her yazmadan önce alınan bir yedek. +description: Kontrol panelinden OpenCode, Pi, OMP, Hermes, OpenClaw, Kimi Code, Gajae Code, DeepSeek Harness, MiniMax Code ve Raycast'i opencodex'e bağlayın — istemci başına tek bir anahtar ve her yazmadan önce alınan bir yedek. --- **Entegrasyonlar** sekmesi, opencodex'in sağlayıcı bloğunu istemcinin kendi -yapılandırma dosyasına yazar ve tekrar kaldırır. Dokuz istemci bu şekilde +yapılandırma dosyasına yazar ve tekrar kaldırır. On istemci bu şekilde çalışır, her biri bir anahtarla: | İstemci | Yapılandırma dosyası | Format | Değişiklik ne zaman geçerli olur? | Kimlik bilgisi | @@ -18,6 +18,7 @@ yapılandırma dosyasına yazar ve tekrar kaldırır. Dokuz istemci bu şekilde | Gajae Code | `~/.gjc/agent/models.yml` | YAML | yeni oturumlarda veya `/model` açtığınızda | `OPENCODEX_GAJAE_API_KEY` | | DeepSeek Harness (DSH) | `$DSH_HOME/settings.yaml` (varsayılan `~/.dsh/settings.yaml`) | YAML | çalışırken yeniden yükleme | gizli olmayan geri döngü bearer yer tutucusu | | MiniMax Code | `~/.minimax/config.yaml` | YAML | yeni oturumlarda veya model seçici açıldıktan sonra | geri döngü (loopback) yer tutucusu | +| Raycast | `~/.config/raycast/ai/providers.yaml` | YAML | kaydedildiği anda — Raycast dosyayı izler | yok — yalnızca geri döngü | Yönetilen DSH desteğinin en düşük uyumlu sürümü **DSH 0.1.0-rc.6**'dır. OpenCodex yalnızca `llm-pi-ai.providers.opencodex` bölümünü yönetir: Uygula ve Yenile bu bölümü değiştirir, Devre Dışı @@ -35,6 +36,29 @@ Entegrasyon yenilendiğinde model başına doğrulanmış bağlam pencereleri ve çabası seçenekleri de yenilenir; bilinmeyen yetenekler atlanır ve MCode oturumunun yönettiği geçerli çaba seçimi korunur. +Raycast'in iki ön koşulu vardır. Özel sağlayıcılar (Custom Providers) bir **Raycast Pro** +özelliğidir: ücretsiz planda dosya yine yazılır, ancak Raycast onu okumayacağı için +`ocx integration client status --client raycast` ve Entegrasyonlar sayfası bir uyarı +bildirir. Ayrıca Raycast `ai` klasörünü yalnızca Raycast → Settings → AI → +**Reveal Providers Config** seçeneğini bir kez açtığınızda oluşturur; opencodex bu +klasörü kurulum sinyali olarak kullanır ve klasör var olana kadar istemciyi kurulu değil +olarak bildirir. Raycast, `~/.config/raycast/ai/providers.yaml` dosyasını macOS ve +Windows'ta aynı şekilde okur ve `XDG_CONFIG_HOME` değerini dikkate almaz; bu nedenle bu +yol taşınamaz. + +Yönetilen blok, dosyanın `providers` dizisindeki tek bir öğedir: `id: opencodex`, +`name: OpenCodex`, `base_url: http://:/v1` ve `abilities` alanıyla birlikte +yönlendirilen her model — `tools` ve `system_message` her zaman destekli, `vision` +kataloğun giriş modalitelerini izler, `reasoning_effort` modelin bir çaba merdiveni +varsa ayarlanır ve `temperature` akıl yürütme modelleri için kapatılır. Dosyadaki diğer +sağlayıcılar korunur ve devre dışı bırakma yalnızca OpenCodex öğesini kaldırır. Raycast +değişikliği dosya kaydedilir kaydedilmez, yeniden başlatma gerekmeden alır; modeller +Raycast'in model seçicisinde **OpenCodex** altında gruplanmış olarak görünür. Dosyada +kimlik bilgisi için bir yer yoktur, bu yüzden bu istemci yalnızca geri döngü içindir: +hiçbir `api_keys` girdisi yazılmaz ve geri döngü dışı bir bağlama reddedilir. Format +[manual.raycast.com/ai/custom-providers](https://manual.raycast.com/ai/custom-providers) +adresinde belgelenmiştir. + Yollar, varsa her istemcinin kendi ortam geçersiz kılmalarını dikkate alır. OMP için `OMP_PROFILE`, açıkça boş olduğunda bile varlığıyla `PI_PROFILE`'a üstün gelir. Adlandırılmış bir profil, `PI_CONFIG_DIR`'i kullanıcının ev dizinine göre @@ -112,7 +136,7 @@ hiçbir şey sessizce değiştirilmez veya düşürülmez. **OMP** de yanındaki düzenlemelerden etkilenmez, ama başka bir nedenle: writer'ı yalnızca kendi `providers.opencodex` aralığını bayt bayt yamalar, dosyanın geri kalanı hiçbir zaman yeniden yazılmaz. Yorum taşıyabilen diğer biçimlerde (Hermes, OpenClaw, -Kimi Code, Gajae Code, MiniMax Code — bütün belge olarak yazılan YAML, JSON5 ve TOML) veya +Kimi Code, Gajae Code, MiniMax Code, Raycast — bütün belge olarak yazılan YAML, JSON5 ve TOML) veya kendi girdilerimiz düzenlenmişse, anahtar kilitlenir ve hangi düzenlemelerin size ait olduğunu tahmin etmek yerine devre dışı bırakmayı reddeder. @@ -192,10 +216,12 @@ ocx integration client enable --client mcode ocx mcode ``` -Bağlandıktan sonra `ocx sync`, yönetilen MCode bloğunu güncel bağlam pencereleri ve -akıl yürütme çabası seçenekleriyle de yeniler. Eksik, dışarıdan düzenlenmiş, güvenli -olmayan veya hiç sahiplenilmemiş bloklara dokunmaz; yeniden bağlamak istediğinizde -entegrasyonu açıkça yeniden etkinleştirin. +Bağlandıktan sonra `ocx sync` ve `POST /api/sync`, yönetilen MCode, Pi, Aside ve +Raycast kataloglarını yeniler. Proxy başlangıcı da yönetilen Raycast kataloğunu +yeniler. Model görünürlüğü, sağlayıcı veya ön ayar değişiklikleri Pi, Aside ve +Raycast kataloglarını günceller. Eksik, dışarıdan düzenlenmiş, güvenli olmayan +veya elle kaldırılmış bloklara dokunmaz; yeniden bağlamak istediğinizde +entegrasyonu açıkça etkinleştirin. Ayrı MiniMax platform CLI'si (`mmx`) bir dosya anahtarı entegrasyonu değildir. Metin komutları MiniMax'ın Anthropic uyumlu uç noktasını kullandığı için OpenCodex, diff --git a/docs-site/src/content/docs/tr/reference/cli/agents.md b/docs-site/src/content/docs/tr/reference/cli/agents.md index a3e184661d..04e72a766c 100644 --- a/docs-site/src/content/docs/tr/reference/cli/agents.md +++ b/docs-site/src/content/docs/tr/reference/cli/agents.md @@ -191,7 +191,7 @@ Grok Build model çitini yönetin ve uygulayın. ## İstemci yapılandırma dışa aktarma -### `ocx export --client ` +### `ocx export --client ` Çalışan proxy'ye bağlı bir istemci yapılandırmasını yazdırın. Komut, `opencodex` sağlayıcı bloğunu — temel URL, model listesi ve istemcinin kimlik bilgisi @@ -203,7 +203,7 @@ yalnızca Codex'in şu anda görebildiği modelleri yayınlar. | Bayrak | Eylem | | --- | --- | -| `--client ` | Gerekli. İstemci yapılandırma lehçesini seçer. | +| `--client ` | Gerekli. İstemci yapılandırma lehçesini seçer. | | `--json` | Betikler için stdout üzerinde oluşturulan belgeyi JSON olarak yazdırın. Bu, seçilen istemcinin yerel formatı YAML, TOML veya JSON5 olsa bile JSON'dur. | | `--out ` | İstemcinin yerel yapılandırma formatını `` konumuna yazın. Mevcut bir dosyanın üzerine yazmayı reddeder. | | `--force` | `--out`'un mevcut bir dosyanın üzerine yazmasına izin verin. | @@ -233,6 +233,18 @@ için kendi varsayılanlarını uygular) gelir. | `mcode` | `~/.minimax/config.yaml` (ayarlandığında `MINIMAX_DATA_DIR`, ardından eski `MAVIS_DATA_DIR` öncelikli; göreli değer reddedilir) | `mcode-config.yaml` | yok — geri döngü yer tutucusu | | `zcode` | `~/.zcode/v2/config.json` (ayarlandığında `ZCODE_DATA_DIR` öncelikli; göreli değer reddedilir) | `config.json` | yok — geri döngü yer tutucusu | | `prime` | `~/.prime/agent/models.json` (ayarlandığında `PRIME_AGENT_CODING_AGENT_DIR` öncelikli; göreli değer reddedilir) | `prime-models.json` | yok — geri döngü yer tutucusu | +| `raycast` | `~/.config/raycast/ai/providers.yaml`, macOS ve Windows'ta aynı (Raycast `XDG_CONFIG_HOME` değerini dikkate almaz) | `raycast-providers.yaml` | yok — yalnızca geri döngü, `api_keys` girdisi yazılmaz | + +Raycast dışa aktarımı, `providers` dizisinde tek bir `id: opencodex` öğesi içeren bağımsız +bir `providers.yaml` belgesidir: `name: OpenCodex`, proxy'nin `/v1` temel URL'si ve +`abilities` alanıyla birlikte yönlendirilen her model (`tools` ve `system_message` her +zaman destekli, `vision` kataloğun giriş modalitelerinden, `reasoning_effort` modelin bir +çaba merdiveni varsa, `temperature` akıl yürütme modelleri için kapalı). Özel sağlayıcılar +bir Raycast Pro özelliğidir ve Raycast dosyayı izlediği için kaydedilen bir değişiklik +yeniden başlatma gerekmeden etkili olur. Format +[manual.raycast.com/ai/custom-providers](https://manual.raycast.com/ai/custom-providers) +adresinde belgelenmiştir. Hiçbir `api_keys` girdisi yazılmaz; bu yüzden bu dışa aktarım +yalnızca geri döngü içindir ve geri döngü dışı bir bağlama reddedilir. opencode `{env:OPENCODEX_OPENCODE_API_KEY}` değerini enterpole eder. Üretilen Pi ve OMP dışa aktarımları bir ortam değişkeni gerektirmez: her biri değişmez diff --git a/docs-site/src/content/docs/zh-cn/reference/cli/agents.md b/docs-site/src/content/docs/zh-cn/reference/cli/agents.md index 11e1c38ee1..89203420e9 100644 --- a/docs-site/src/content/docs/zh-cn/reference/cli/agents.md +++ b/docs-site/src/content/docs/zh-cn/reference/cli/agents.md @@ -132,7 +132,7 @@ ocx claude desktop import [--apply] Validate and import JSON ## Client config export -### `ocx export --client ` +### `ocx export --client ` 输出连接到正在运行代理的客户端配置。此命令会以所选客户端的原生格式序列化 `opencodex` provider 块,其中包含基础 URL、模型列表,以及该客户端适用的凭据引用或 `opencodex-loopback` 占位值。 @@ -140,7 +140,7 @@ ocx claude desktop import [--apply] Validate and import JSON | 标志 | 动作 | | --- | --- | -| `--client ` | 必需。选择客户端配置格式。 | +| `--client ` | 必需。选择客户端配置格式。 | | `--json` | 仅在 stdout 打印配置 JSON,这样重定向即可捕获字节级精确输出。包括 `--out` 写入提示在内的所有诊断信息都会输出到 stderr。 | | `--out ` | 将配置写入 ``。拒绝替换已存在的文件。 | | `--force` | 允许 `--out` 替换已存在的文件。 | @@ -167,6 +167,9 @@ ocx export --client opencode --out ~/opencodex-opencode.json | `mcode` | `~/.minimax/config.yaml` (设置后 `MINIMAX_DATA_DIR` 优先,其次是旧的 `MAVIS_DATA_DIR`;相对路径会被拒绝) | `mcode-config.yaml` | 无 — loopback placeholder | | `zcode` | `~/.zcode/v2/config.json` (设置后 `ZCODE_DATA_DIR` 优先;相对路径会被拒绝) | `config.json` | 无 — loopback placeholder | | `prime` | `~/.prime/agent/models.json` (设置后 `PRIME_AGENT_CODING_AGENT_DIR` 优先;相对路径会被拒绝) | `prime-models.json` | 无 — loopback placeholder | +| `raycast` | `~/.config/raycast/ai/providers.yaml`(macOS 与 Windows 相同;Raycast 不遵循 `XDG_CONFIG_HOME`) | `raycast-providers.yaml` | 无 — 仅限回环,不会写入 `api_keys` 条目 | + +Raycast 导出是一份独立的 `providers.yaml` 文档,在 `providers` 序列中只有一个 `id: opencodex` 元素:`name: OpenCodex`、代理的 `/v1` 基础 URL,以及每个已路由模型及其 `abilities`(`tools` 与 `system_message` 始终支持,`vision` 取自目录的输入模态,`reasoning_effort` 在模型有 effort 阶梯时设置,`temperature` 对推理模型关闭)。Custom Providers 是 Raycast Pro 功能,且 Raycast 会监视该文件,因此保存后的更改无需重启即可生效。格式见 [manual.raycast.com/ai/custom-providers](https://manual.raycast.com/ai/custom-providers)。不会写入任何 `api_keys` 条目,所以该导出仅限回环,非回环绑定会被拒绝。 opencode 会插值 `{env:OPENCODEX_OPENCODE_API_KEY}`。opencodex 生成的 Pi 导出不需要环境变量,而是携带字面占位值 `opencodex-loopback`。这个值是必需的:Pi 在构建模型列表时会解析 `apiKey`,如果已有配置包含未设置的环境变量引用,它就会隐藏整个 provider。回环上的代理从不校验生成的占位值。 diff --git a/docs-site/src/content/docs/zh-tw/guides/integrations.md b/docs-site/src/content/docs/zh-tw/guides/integrations.md index 54751d5620..ebf2e6f0de 100644 --- a/docs-site/src/content/docs/zh-tw/guides/integrations.md +++ b/docs-site/src/content/docs/zh-tw/guides/integrations.md @@ -1,9 +1,9 @@ --- title: 整合 -description: 從儀表板把 opencodex 連接到 OpenCode、Pi、OMP、Hermes、OpenClaw、Kimi Code、Gajae Code、DeepSeek Harness 與 MiniMax Code——每個客戶端一個開關,每次寫入前都會先備份。 +description: 從儀表板把 opencodex 連接到 OpenCode、Pi、OMP、Hermes、OpenClaw、Kimi Code、Gajae Code、DeepSeek Harness、MiniMax Code 與 Raycast——每個客戶端一個開關,每次寫入前都會先備份。 --- -**整合(Integrations)** 分頁會把 opencodex 的 provider 區塊寫入客戶端自己的設定檔,也會把它移除。共有九個客戶端以這種方式運作,每個都有一個開關: +**整合(Integrations)** 分頁會把 opencodex 的 provider 區塊寫入客戶端自己的設定檔,也會把它移除。共有十個客戶端以這種方式運作,每個都有一個開關: | 客戶端 | 設定檔 | 格式 | 變更生效時機 | 憑證 | |---|---|---|---|---| @@ -16,6 +16,7 @@ description: 從儀表板把 opencodex 連接到 OpenCode、Pi、OMP、Hermes、 | Gajae Code | `~/.gjc/agent/models.yml` | YAML | 新 sessions,或當你開啟 `/model` 時 | `OPENCODEX_GAJAE_API_KEY` | | DeepSeek Harness (DSH) | `$DSH_HOME/settings.yaml`(預設 `~/.dsh/settings.yaml`) | YAML | 熱重載 | 非秘密的 loopback bearer 佔位符 | | MiniMax Code | `~/.minimax/config.yaml` | YAML | 新 sessions,或開啟模型選擇器後 | loopback 佔位符 | +| Raycast | `~/.config/raycast/ai/providers.yaml` | YAML | 儲存後立即生效——Raycast 會監看該檔案 | 無——僅限 loopback | 受管理 DSH 支援的相容性下限是 **DSH 0.1.0-rc.6**。OpenCodex 只擁有 `llm-pi-ai.providers.opencodex`:Apply 與 Refresh 會取代該片段,Disable 只移除該片段, @@ -30,6 +31,22 @@ MiniMax Code 依序遵循 `MINIMAX_DATA_DIR`、`MAVIS_DATA_DIR`,最後才回 逐模型 context window 與 reasoning-effort 選項;未知能力會省略,而 MCode session 目前選取的 effort 不會被覆寫。 +Raycast 有兩個前提。Custom Providers 是 **Raycast Pro** 功能:免費方案下檔案仍會被寫入,但 +`ocx integration client status --client raycast` 與整合頁面會回報警告,因為 Raycast 不會讀取它。 +另外,Raycast 只有在你開啟一次 Raycast → Settings → AI → **Reveal Providers Config** 後才會建立 +`ai` 資料夾;opencodex 以該資料夾作為安裝訊號,在它存在之前都會回報客戶端尚未安裝。Raycast 在 +macOS 與 Windows 上同樣讀取 `~/.config/raycast/ai/providers.yaml`,且不遵循 `XDG_CONFIG_HOME`, +所以該路徑無法搬移。 + +受管理區塊是檔案 `providers` 序列中的單一元素 `id: opencodex`:`name: OpenCodex`、 +`base_url: http://:/v1`,以及每個路由模型及其 `abilities`——`tools` 與 +`system_message` 一律支援,`vision` 依目錄的輸入模態而定,`reasoning_effort` 在模型有 effort +階梯時設定,`temperature` 對推理模型關閉。檔案中的其他 provider 會被保留,停用只移除 OpenCodex +元素。檔案一儲存 Raycast 就會套用變更,不需重新啟動;模型會在 Raycast 的模型選擇器中歸在 +**OpenCodex** 群組下。該檔案沒有存放憑證的位置,因此此客戶端僅限 loopback:不會寫入任何 +`api_keys` 項目,非 loopback 的 bind 會被拒絕。格式說明見 +[manual.raycast.com/ai/custom-providers](https://manual.raycast.com/ai/custom-providers)。 + 路徑遵循客戶端自己的環境覆寫(environment override)。對 OMP 而言,`OMP_PROFILE` 以存在與否優先於 `PI_PROFILE`,即使明確為空也一樣。具名 profile 會把 `PI_CONFIG_DIR` 當作相對於使用者家目錄的目錄名稱,並忽略 `PI_CODING_AGENT_DIR`;沒有具名 profile 時,`PI_CODING_AGENT_DIR` 勝出。OMP 支援 provider 層級的 headers,但這個最初的整合刻意只支援 loopback;遠端 `x-opencodex-api-key` 的連線設定被延後。搬移過的 `HERMES_HOME`、`KIMI_CODE_HOME` 與 `XDG_CONFIG_HOME` 路徑同樣會被遵循,而非猜測。表格列出每個客戶端的預設值。 對原生 OpenAI 模型,產生的 OMP 區塊會選用其模型層級的 Responses API,保留圖片輸入與 reasoning-effort 控制。路由模型則維持 provider 的 Chat Completions 方言,讓它們既有的 adapters 保持相容。 @@ -52,7 +69,7 @@ opencodex 從自己的環境讀取這些變數。如果你的 gateway 以 profil - **Restore this point…** 會出現在較舊的操作上,或當檔案在那次操作之後有變更時。跨過這樣的變更做回復會再詢問一次,才覆蓋你的較新編輯——並且也會備份它們,所以那次的回復本身也可以復原。 - 每個客戶端保留十份備份。超過之後,最舊的快照檔案會被移除,其歷史列顯示為 **Backup expired**。 -停用只移除 opencodex 記錄為自己寫入的條目。如果你的檔案在我們寫入之後有變更,後續行為取決於我們自己的條目是否完好,以及檔案的格式。對於嚴格 JSON 設定檔(OpenCode、Pi),在我們的區塊**旁邊**進行的編輯——例如新增 MCP 伺服器或你自己的 provider——會顯示為**需要更新**:重新整理會在保留你的條目的前提下合併寫入,但格式可能會被正規化。例外情況是 JSON 無法精確重寫的內容——例如 `1e999` 這類非有限數字、重寫會被四捨五入的數字(極大的整數,或小到會塌縮成零的數字)、`-0`、同一個物件裡重複出現的鍵,或巢狀層數超過 1000 層——此時開關會鎖定,確保沒有任何值被悄悄改動或刪除。**OMP** 同樣不受旁邊編輯影響,但原因不同:它的 writer 只逐位元組修補自己的 `providers.opencodex` 範圍,檔案其餘部分從不會被重寫。至於其餘可以包含註解的格式(Hermes、OpenClaw、Kimi Code、Gajae Code、MiniMax Code——以整份文件寫出的 YAML、JSON5 與 TOML),或當我們自己的條目被編輯過時,開關會鎖定,停用會拒絕執行,而不是猜測哪些編輯是你的。 +停用只移除 opencodex 記錄為自己寫入的條目。如果你的檔案在我們寫入之後有變更,後續行為取決於我們自己的條目是否完好,以及檔案的格式。對於嚴格 JSON 設定檔(OpenCode、Pi),在我們的區塊**旁邊**進行的編輯——例如新增 MCP 伺服器或你自己的 provider——會顯示為**需要更新**:重新整理會在保留你的條目的前提下合併寫入,但格式可能會被正規化。例外情況是 JSON 無法精確重寫的內容——例如 `1e999` 這類非有限數字、重寫會被四捨五入的數字(極大的整數,或小到會塌縮成零的數字)、`-0`、同一個物件裡重複出現的鍵,或巢狀層數超過 1000 層——此時開關會鎖定,確保沒有任何值被悄悄改動或刪除。**OMP** 同樣不受旁邊編輯影響,但原因不同:它的 writer 只逐位元組修補自己的 `providers.opencodex` 範圍,檔案其餘部分從不會被重寫。至於其餘可以包含註解的格式(Hermes、OpenClaw、Kimi Code、Gajae Code、MiniMax Code、Raycast——以整份文件寫出的 YAML、JSON5 與 TOML),或當我們自己的條目被編輯過時,開關會鎖定,停用會拒絕執行,而不是猜測哪些編輯是你的。 ## 誠實的預期 @@ -98,9 +115,11 @@ ocx integration client enable --client mcode ocx mcode ``` -完成一次連接後,`ocx sync` 也會以目前的 context window 與 reasoning-effort 階梯更新 -OpenCodex 已擁有的 MCode 區塊。若區塊已刪除、遭外部修改、不安全或從未由 OpenCodex -建立,sync 會保持原檔不動;只有在你確定要重新連接時才再次執行 enable。 +完成一次連接後,`ocx sync` 與 `POST /api/sync` 會更新 OpenCodex 已擁有的 +MCode、Pi、Aside 與 Raycast 目錄。proxy 啟動也會更新已擁有的 Raycast 目錄。 +模型可見性、provider 或 preset 變更會更新 Pi、Aside 與 Raycast。若區塊已刪除、 +遭外部修改、不安全或由你手動移除,sync 會保持原檔不動;只有在你確定要重新 +連接時才再次執行 enable。 另一個 MiniMax 平台 CLI(`mmx`)不是檔案開關整合。其文字命令使用 MiniMax 的 Anthropic 相容端點,因此 OpenCodex 提供憑證隔離、僅限 loopback 的 launcher: diff --git a/docs-site/src/content/docs/zh-tw/reference/cli/agents.md b/docs-site/src/content/docs/zh-tw/reference/cli/agents.md index 497d2e4252..d04c099ebf 100644 --- a/docs-site/src/content/docs/zh-tw/reference/cli/agents.md +++ b/docs-site/src/content/docs/zh-tw/reference/cli/agents.md @@ -130,7 +130,7 @@ ocx claude desktop import [--apply] 驗證並匯入 JSON ## 客戶端設定匯出 -### `ocx export --client ` +### `ocx export --client ` 印出連接到執行中代理的客戶端設定。此指令會用所選客戶端的原生格式,序列化含有 base URL、模型清單,以及適用的環境變數參考或 loopback 佔位符的 `opencodex` provider 區塊。 @@ -138,7 +138,7 @@ ocx claude desktop import [--apply] 驗證並匯入 JSON | 旗標 | 動作 | | --- | --- | -| `--client ` | 必填。選擇客戶端設定格式。 | +| `--client ` | 必填。選擇客戶端設定格式。 | | `--json` | 僅在 stdout 印出設定 JSON,使重導向能擷取逐位元組輸出。所有診斷訊息(含 `--out` 寫入提示)皆送至 stderr。 | | `--out ` | 將設定寫入 ``。拒絕覆寫既有檔案。 | | `--force` | 允許 `--out` 覆寫既有檔案。 | @@ -165,6 +165,9 @@ ocx export --client opencode --out ~/opencodex-opencode.json | `mcode` | `~/.minimax/config.yaml` (設定後 `MINIMAX_DATA_DIR` 優先,其次為舊的 `MAVIS_DATA_DIR`;相對路徑會被拒絕) | `mcode-config.yaml` | 無——loopback 佔位符 | | `zcode` | `~/.zcode/v2/config.json` (設定後 `ZCODE_DATA_DIR` 優先;相對路徑會被拒絕) | `config.json` | 無——loopback 佔位符 | | `prime` | `~/.prime/agent/models.json` (設定後 `PRIME_AGENT_CODING_AGENT_DIR` 優先;相對路徑會被拒絕) | `prime-models.json` | 無——loopback 佔位符 | +| `raycast` | `~/.config/raycast/ai/providers.yaml`(macOS 與 Windows 相同;Raycast 不遵循 `XDG_CONFIG_HOME`) | `raycast-providers.yaml` | 無——僅限 loopback,不會寫入 `api_keys` 項目 | + +Raycast 匯出是一份獨立的 `providers.yaml` 文件,在 `providers` 序列中只有一個 `id: opencodex` 元素:`name: OpenCodex`、proxy 的 `/v1` base URL,以及每個路由模型及其 `abilities`(`tools` 與 `system_message` 一律支援,`vision` 依目錄的輸入模態而定,`reasoning_effort` 在模型有 effort 階梯時設定,`temperature` 對推理模型關閉)。Custom Providers 是 Raycast Pro 功能,且 Raycast 會監看該檔案,因此儲存後的變更不需重新啟動即可生效。格式說明見 [manual.raycast.com/ai/custom-providers](https://manual.raycast.com/ai/custom-providers)。不會寫入任何 `api_keys` 項目,所以此匯出僅限 loopback,非 loopback 的 bind 會被拒絕。 opencode 會插值 `{env:OPENCODEX_OPENCODE_API_KEY}`。Pi 與 OMP 的匯出不需要環境變數, 而是帶有字面值 `opencodex-loopback`。DSH 匯出需要 DSH 0.1.0-rc.6 或更新版本,且只擁有 diff --git a/gui/public/provider-icons/README.md b/gui/public/provider-icons/README.md index 1fc7c57857..f5e64b568b 100644 --- a/gui/public/provider-icons/README.md +++ b/gui/public/provider-icons/README.md @@ -47,6 +47,16 @@ Export-client marks (used by the API tab's connect rows, not the provider list): on the web (`aside.com/favicon.svg` is a 404), so the shipping application is the first-party source. +- `raycast.svg` — fetched 2026-09-04 from + `https://fz1sd71lwhbqy6sh.public.blob.vercel-storage.com/press/images/logo/raycast-logo-dark.svg`, + the "Logo (dark)" download Raycast's own press kit (`raycast.com/press`) links. + `raycast.com/favicon.svg` and the other conventional paths are 404s, so the + press kit is the first-party source. Path data and the `#FF6363` fill are + verbatim; the fixed `width`/`height` are dropped in favour of the `viewBox`, + and the `` wrapper — a full-frame white `` the export tool left + behind — is removed because the path never leaves the frame and the rect + would read as a second ink to the mark tooling here. + - `minimax.svg` — fetched 2026-08-31 from `https://raw.githubusercontent.com/MiniMax-AI/MiniMax-01/main/figures/minimax.svg`, MiniMax's own symbol as committed in their own model repository. The API-docs @@ -135,6 +145,9 @@ Decisions that are not obvious from looking at the file: - `aside.svg` **is masked.** It already paints with `currentColor`, so it would follow the theme either way; masking keeps it consistent with the other silhouettes rather than depending on inherited color. +- `raycast.svg` **is not masked.** One ink, but that ink is #FF6363 — Raycast + red, the same case as `openai.svg` and `deepseek-harness.svg`. Legible on both + surfaces as an image. Both directions are enforced in `gui/tests/integration-marks.test.ts`, including a luminance check that fails any single-ink near-neutral mark left as an image. That diff --git a/gui/public/provider-icons/raycast.svg b/gui/public/provider-icons/raycast.svg new file mode 100644 index 0000000000..b6a40c7ba2 --- /dev/null +++ b/gui/public/provider-icons/raycast.svg @@ -0,0 +1,3 @@ + + + diff --git a/gui/src/app-routing.ts b/gui/src/app-routing.ts index bab41b1eee..c5971ffb6b 100644 --- a/gui/src/app-routing.ts +++ b/gui/src/app-routing.ts @@ -100,6 +100,7 @@ export const INTEGRATION_TAB_HASHES = [ "integrations/zcode", "integrations/prime", "integrations/aside", + "integrations/raycast", ] as const; export function hashBelongsToPage(rawHash: string, page: Page): boolean { diff --git a/gui/src/components/apikeys-workspace/client-config-clients.ts b/gui/src/components/apikeys-workspace/client-config-clients.ts index c7c42d3e56..afd4484551 100644 --- a/gui/src/components/apikeys-workspace/client-config-clients.ts +++ b/gui/src/components/apikeys-workspace/client-config-clients.ts @@ -8,7 +8,7 @@ * with EXPORT_CLIENT_IDS by hand; adding a client server-side renders no row * until this tuple changes. */ -export const CLIENTS = ["opencode", "pi", "omp", "hermes", "openclaw", "kimi", "gajae", "dsh", "mcode", "zcode", "prime", "aside"] as const; +export const CLIENTS = ["opencode", "pi", "omp", "hermes", "openclaw", "kimi", "gajae", "dsh", "mcode", "zcode", "prime", "aside", "raycast"] as const; export type ExportClientId = (typeof CLIENTS)[number]; export const CLIENT_LABEL_KEYS = { @@ -24,6 +24,7 @@ export const CLIENT_LABEL_KEYS = { zcode: "api.clientConfig.clientZcode", prime: "api.clientConfig.clientPrime", aside: "api.clientConfig.clientAside", + raycast: "api.clientConfig.clientRaycast", } as const; /** @@ -70,6 +71,8 @@ export const CLIENT_MARKS: Partial> = { zcode: "/provider-icons/zcode.svg", prime: "/provider-icons/prime-agent.svg", aside: "/provider-icons/aside.svg", + // Raycast red (#FF6363) is the brand, so like `dsh` it stays an image. + raycast: "/provider-icons/raycast.svg", }; /** diff --git a/gui/src/components/integration-marks.ts b/gui/src/components/integration-marks.ts index e8786224ec..eca38510bd 100644 --- a/gui/src/components/integration-marks.ts +++ b/gui/src/components/integration-marks.ts @@ -57,6 +57,7 @@ export const INTEGRATION_MARKS: Record = { zcode: CLIENT_MARKS.zcode ?? null, prime: CLIENT_MARKS.prime ?? null, aside: CLIENT_MARKS.aside ?? null, + raycast: CLIENT_MARKS.raycast ?? null, }; /** diff --git a/gui/src/i18n/de.ts b/gui/src/i18n/de.ts index 9086c9bf42..af5546775a 100644 --- a/gui/src/i18n/de.ts +++ b/gui/src/i18n/de.ts @@ -1093,6 +1093,7 @@ export const de: Record = { "integrations.tab.zcode": "ZCode", "integrations.tab.prime": "Prime Agent", "integrations.tab.aside": "Aside", + "integrations.tab.raycast": "Raycast", "integrations.aside.profilesTitle": "Aside-Profile", "integrations.aside.profilesHint": "Wähle, welche Profile die ausgewählten Modelle erhalten. Das aktive Aside-Profil bleibt unverändert.", "integrations.aside.all": "Alle Profile synchronisieren", @@ -1252,6 +1253,10 @@ export const de: Record = { "integrations.semantics.zcode": "Verwaltet nur provider.opencodex in ~/.zcode/v2/config.json. Z.ai-Anmeldung und andere Provider bleiben unverändert. ZCode nach Änderungen neu starten.", "integrations.semantics.prime": "Verwaltet nur providers.opencodex in der models.json von Prime Agent — ~/.prime/agent, sofern PRIME_AGENT_CODING_AGENT_DIR sie nicht umleitet. Andere Provider und Modell-Overrides bleiben unverändert. Gilt für neue Sitzungen.", "integrations.semantics.aside": "Verwaltet nur providers.opencodex in der ~/.aside/u//models.json dieses Profils. Andere Provider bleiben unverändert. Beende Aside nach dem Anwenden vollständig und öffne es erneut.", + "integrations.semantics.raycast": "Fügt einen OpenCodex-Provider-Eintrag in die providers.yaml von Raycast ein, damit jedes geroutete Modell in der Modellauswahl von Raycast AI erscheint. Raycast Pro erforderlich.", + "integrations.raycast.proRequired": "Custom Providers ist eine Funktion von Raycast Pro. Die Datei wird geschrieben, aber Raycast ignoriert sie, bis ein Pro-Abonnement aktiv ist.", + "integrations.raycast.planUnknown": "Der Abonnementstatus von Raycast konnte nicht gelesen werden; Custom Providers erfordert Raycast Pro.", + "integrations.raycast.revealConfig": "Öffnen Sie Raycast → Einstellungen → AI und klicken Sie einmal auf „Reveal Providers Config“, damit der Providers-Ordner existiert.", "codexAuth.mainAccount": "Hauptkonto", "codexAuth.logLabel": "Log-Kennung", "codexAuth.codexApp": "Codex App", @@ -1580,6 +1585,7 @@ export const de: Record = { "api.clientConfig.clientZcode": "ZCode", "api.clientConfig.clientPrime": "Prime Agent", "api.clientConfig.clientAside": "Aside", + "api.clientConfig.clientRaycast": "Raycast", "api.clientConfig.copy": "Konfiguration kopieren", "api.clientConfig.download": "Herunterladen", "api.clientConfig.loading": "Client-Konfiguration wird erstellt…", diff --git a/gui/src/i18n/en.ts b/gui/src/i18n/en.ts index 0d2f1d05d4..71bfd5e2c3 100644 --- a/gui/src/i18n/en.ts +++ b/gui/src/i18n/en.ts @@ -1600,6 +1600,7 @@ export const en = { "integrations.tab.zcode": "ZCode", "integrations.tab.prime": "Prime Agent", "integrations.tab.aside": "Aside", + "integrations.tab.raycast": "Raycast", "integrations.aside.profilesTitle": "Aside profiles", "integrations.aside.profilesHint": "Choose which profiles receive the selected models. Aside’s active profile stays unchanged.", "integrations.aside.all": "Sync all profiles", @@ -1799,6 +1800,10 @@ export const en = { "integrations.semantics.zcode": "Manages only provider.opencodex in ~/.zcode/v2/config.json. Your Z.ai login and other providers stay unchanged. Restart ZCode after changes.", "integrations.semantics.prime": "Manages only providers.opencodex in Prime Agent's models.json — ~/.prime/agent unless PRIME_AGENT_CODING_AGENT_DIR redirects it. Your other providers and model overrides stay unchanged. Applies to new sessions.", "integrations.semantics.aside": "Manages only providers.opencodex in this profile’s ~/.aside/u//models.json. Your other providers stay unchanged. Fully quit and reopen Aside after applying.", + "integrations.semantics.raycast": "Adds an OpenCodex provider entry to Raycast's providers.yaml so every routed model appears in the Raycast AI model picker. Raycast Pro required.", + "integrations.raycast.proRequired": "Custom Providers is a Raycast Pro feature. The file will be written, but Raycast ignores it until a Pro subscription is active.", + "integrations.raycast.planUnknown": "Could not read the Raycast subscription state; Custom Providers requires Raycast Pro.", + "integrations.raycast.revealConfig": "Open Raycast → Settings → AI and click Reveal Providers Config once so the providers folder exists.", "codexAuth.mainAccount": "Main Account", "codexAuth.logLabel": "Log label", "codexAuth.codexApp": "Codex App", @@ -2138,6 +2143,7 @@ export const en = { "api.clientConfig.clientZcode": "ZCode", "api.clientConfig.clientPrime": "Prime Agent", "api.clientConfig.clientAside": "Aside", + "api.clientConfig.clientRaycast": "Raycast", "api.clientConfig.copy": "Copy config", "api.clientConfig.download": "Download", "api.clientConfig.loading": "Building client config…", diff --git a/gui/src/i18n/fr.ts b/gui/src/i18n/fr.ts index b6eb03f0b0..028e910bc3 100644 --- a/gui/src/i18n/fr.ts +++ b/gui/src/i18n/fr.ts @@ -1572,6 +1572,7 @@ export const fr: Record = { "integrations.tab.zcode": "ZCode", "integrations.tab.prime": "Prime Agent", "integrations.tab.aside": "Aside", + "integrations.tab.raycast": "Raycast", "integrations.aside.profilesTitle": "Profils Aside", "integrations.aside.profilesHint": "Choisissez les profils qui recevront les modèles sélectionnés. Le profil actif dans Aside reste inchangé.", "integrations.aside.all": "Synchroniser tous les profils", @@ -1731,6 +1732,10 @@ export const fr: Record = { "integrations.semantics.zcode": "Gère uniquement provider.opencodex dans ~/.zcode/v2/config.json. Votre connexion Z.ai et les autres fournisseurs restent inchangés. Redémarrez ZCode après toute modification.", "integrations.semantics.prime": "Gère uniquement providers.opencodex dans le models.json de Prime Agent — ~/.prime/agent, sauf si PRIME_AGENT_CODING_AGENT_DIR le redirige. Vos autres fournisseurs et surcharges de modèles restent inchangés. S'applique aux nouvelles sessions.", "integrations.semantics.aside": "Gère uniquement providers.opencodex dans le fichier ~/.aside/u//models.json de ce profil. Vos autres fournisseurs restent inchangés. Quittez complètement Aside et relancez-le après application.", + "integrations.semantics.raycast": "Ajoute une entrée de fournisseur OpenCodex dans le providers.yaml de Raycast afin que chaque modèle routé apparaisse dans le sélecteur de modèles de Raycast AI. Raycast Pro requis.", + "integrations.raycast.proRequired": "Custom Providers est une fonctionnalité Raycast Pro. Le fichier sera écrit, mais Raycast l'ignore tant qu'un abonnement Pro n'est pas actif.", + "integrations.raycast.planUnknown": "Impossible de lire l'état de l'abonnement Raycast ; Custom Providers nécessite Raycast Pro.", + "integrations.raycast.revealConfig": "Ouvrez Raycast → Réglages → AI et cliquez une fois sur « Reveal Providers Config » pour que le dossier des fournisseurs existe.", "codexAuth.mainAccount": "Compte principal", "codexAuth.logLabel": "Libellé du journal", "codexAuth.codexApp": "Application Codex", @@ -2057,6 +2062,7 @@ export const fr: Record = { "api.clientConfig.clientZcode": "ZCode", "api.clientConfig.clientPrime": "Prime Agent", "api.clientConfig.clientAside": "Aside", + "api.clientConfig.clientRaycast": "Raycast", "api.clientConfig.copy": "Copier la configuration", "api.clientConfig.download": "Télécharger", "api.clientConfig.loading": "Génération de la configuration du client…", diff --git a/gui/src/i18n/ja.ts b/gui/src/i18n/ja.ts index 4b16912324..864b498483 100644 --- a/gui/src/i18n/ja.ts +++ b/gui/src/i18n/ja.ts @@ -1513,6 +1513,7 @@ export const ja: Record = { "integrations.tab.zcode": "ZCode", "integrations.tab.prime": "Prime Agent", "integrations.tab.aside": "Aside", + "integrations.tab.raycast": "Raycast", "integrations.aside.profilesTitle": "Asideのプロファイル", "integrations.aside.profilesHint": "選択したモデルを同期するプロファイルを選んでください。Asideで使用中のプロファイルは変わりません。", "integrations.aside.all": "すべてのプロファイルを同期", @@ -1672,6 +1673,10 @@ export const ja: Record = { "integrations.semantics.zcode": "~/.zcode/v2/config.json の provider.opencodex のみを管理します。Z.ai ログインと他のプロバイダーは変更しません。変更後は ZCode を再起動してください。", "integrations.semantics.prime": "Prime Agent の models.json 内の providers.opencodex のみを管理します。場所は ~/.prime/agent ですが、PRIME_AGENT_CODING_AGENT_DIR が設定されている場合はそちらが優先されます。他のプロバイダーとモデルオーバーライドは変更しません。新しいセッションから適用されます。", "integrations.semantics.aside": "このプロファイルの ~/.aside/u//models.json 内の providers.opencodex のみを管理します。他のプロバイダーは変更しません。適用後は Aside を完全に終了してから開き直してください。", + "integrations.semantics.raycast": "Raycast の providers.yaml に OpenCodex のプロバイダーエントリを追加し、ルーティングされたすべてのモデルを Raycast AI のモデル選択に表示します。Raycast Pro が必要です。", + "integrations.raycast.proRequired": "Custom Providers は Raycast Pro の機能です。ファイルは書き込まれますが、Pro サブスクリプションが有効になるまで Raycast はこれを無視します。", + "integrations.raycast.planUnknown": "Raycast のサブスクリプション状態を読み取れませんでした。Custom Providers には Raycast Pro が必要です。", + "integrations.raycast.revealConfig": "Raycast → 設定 → AI を開き、「Reveal Providers Config」を一度クリックして providers フォルダを作成してください。", "codexAuth.mainAccount": "メインアカウント", "codexAuth.logLabel": "ログラベル", "codexAuth.codexApp": "Codex App", @@ -2005,6 +2010,7 @@ export const ja: Record = { "api.clientConfig.clientZcode": "ZCode", "api.clientConfig.clientPrime": "Prime Agent", "api.clientConfig.clientAside": "Aside", + "api.clientConfig.clientRaycast": "Raycast", "api.clientConfig.copy": "設定をコピー", "api.clientConfig.download": "ダウンロード", "api.clientConfig.loading": "クライアント設定を生成中…", diff --git a/gui/src/i18n/ko.ts b/gui/src/i18n/ko.ts index a87bf608e5..364805943e 100644 --- a/gui/src/i18n/ko.ts +++ b/gui/src/i18n/ko.ts @@ -1117,6 +1117,7 @@ export const ko: Record = { "integrations.tab.zcode": "ZCode", "integrations.tab.prime": "Prime Agent", "integrations.tab.aside": "Aside", + "integrations.tab.raycast": "Raycast", "integrations.aside.profilesTitle": "Aside 프로필", "integrations.aside.profilesHint": "선택한 모델을 동기화할 프로필을 고르세요. Aside에서 사용 중인 프로필은 바뀌지 않습니다.", "integrations.aside.all": "모든 프로필 동기화", @@ -1276,6 +1277,10 @@ export const ko: Record = { "integrations.semantics.zcode": "~/.zcode/v2/config.json의 provider.opencodex만 관리하며 Z.ai 로그인과 다른 프로바이더는 변경하지 않습니다. 변경 후 ZCode를 재시작하세요.", "integrations.semantics.prime": "Prime Agent의 models.json에서 providers.opencodex만 관리합니다. 위치는 ~/.prime/agent이며 PRIME_AGENT_CODING_AGENT_DIR가 설정되면 그쪽이 우선합니다. 다른 프로바이더와 모델 오버라이드는 변경하지 않습니다. 새 세션부터 적용됩니다.", "integrations.semantics.aside": "이 프로필의 ~/.aside/u//models.json에서 providers.opencodex만 관리합니다. 다른 프로바이더는 그대로 유지됩니다. 적용 후 Aside를 완전히 종료하고 다시 여세요.", + "integrations.semantics.raycast": "Raycast의 providers.yaml에 OpenCodex 프로바이더 항목을 추가해 라우팅된 모든 모델이 Raycast AI 모델 선택기에 표시되도록 합니다. Raycast Pro가 필요합니다.", + "integrations.raycast.proRequired": "Custom Providers는 Raycast Pro 기능입니다. 파일은 기록되지만 Pro 구독이 활성화될 때까지 Raycast는 이를 무시합니다.", + "integrations.raycast.planUnknown": "Raycast 구독 상태를 읽을 수 없습니다. Custom Providers에는 Raycast Pro가 필요합니다.", + "integrations.raycast.revealConfig": "Raycast → 설정 → AI를 열고 「Reveal Providers Config」를 한 번 클릭해 providers 폴더를 만드세요.", "codexAuth.mainAccount": "메인 계정", "codexAuth.logLabel": "로그 라벨", "codexAuth.codexApp": "Codex App", @@ -1607,6 +1612,7 @@ export const ko: Record = { "api.clientConfig.clientZcode": "ZCode", "api.clientConfig.clientPrime": "Prime Agent", "api.clientConfig.clientAside": "Aside", + "api.clientConfig.clientRaycast": "Raycast", "api.clientConfig.copy": "설정 복사", "api.clientConfig.download": "다운로드", "api.clientConfig.loading": "클라이언트 설정 생성 중…", diff --git a/gui/src/i18n/ru.ts b/gui/src/i18n/ru.ts index 70eb364002..bfd6e0182e 100644 --- a/gui/src/i18n/ru.ts +++ b/gui/src/i18n/ru.ts @@ -1583,6 +1583,7 @@ export const ru: Record = { "integrations.tab.zcode": "ZCode", "integrations.tab.prime": "Prime Agent", "integrations.tab.aside": "Aside", + "integrations.tab.raycast": "Raycast", "integrations.aside.profilesTitle": "Профили Aside", "integrations.aside.profilesHint": "Выберите профили, в которые будут добавлены выбранные модели. Активный профиль Aside не изменится.", "integrations.aside.all": "Синхронизировать все профили", @@ -1742,6 +1743,10 @@ export const ru: Record = { "integrations.semantics.zcode": "Управляет только provider.opencodex в ~/.zcode/v2/config.json. Вход Z.ai и другие провайдеры не меняются. Перезапустите ZCode после изменений.", "integrations.semantics.prime": "Управляет только providers.opencodex в models.json Prime Agent — ~/.prime/agent, если PRIME_AGENT_CODING_AGENT_DIR не переопределяет путь. Другие провайдеры и переопределения моделей не меняются. Применяется к новым сессиям.", "integrations.semantics.aside": "Управляет только providers.opencodex в файле ~/.aside/u//models.json этого профиля. Другие провайдеры остаются без изменений. После применения полностью закройте и снова откройте Aside.", + "integrations.semantics.raycast": "Добавляет запись провайдера OpenCodex в providers.yaml Raycast, чтобы каждая маршрутизируемая модель появилась в выборе моделей Raycast AI. Требуется Raycast Pro.", + "integrations.raycast.proRequired": "Custom Providers — функция Raycast Pro. Файл будет записан, но Raycast игнорирует его, пока не активна подписка Pro.", + "integrations.raycast.planUnknown": "Не удалось прочитать состояние подписки Raycast; для Custom Providers требуется Raycast Pro.", + "integrations.raycast.revealConfig": "Откройте Raycast → Настройки → AI и один раз нажмите «Reveal Providers Config», чтобы папка провайдеров появилась.", "codexAuth.mainAccount": "Основной аккаунт", "codexAuth.logLabel": "Метка журнала", "codexAuth.codexApp": "Codex App", @@ -2075,6 +2080,7 @@ export const ru: Record = { "api.clientConfig.clientZcode": "ZCode", "api.clientConfig.clientPrime": "Prime Agent", "api.clientConfig.clientAside": "Aside", + "api.clientConfig.clientRaycast": "Raycast", "api.clientConfig.copy": "Копировать конфигурацию", "api.clientConfig.download": "Скачать", "api.clientConfig.loading": "Формируется конфигурация клиента…", diff --git a/gui/src/i18n/tr.ts b/gui/src/i18n/tr.ts index ca233f452e..83ad09002b 100644 --- a/gui/src/i18n/tr.ts +++ b/gui/src/i18n/tr.ts @@ -1590,6 +1590,7 @@ export const tr: Record = { "integrations.tab.zcode": "ZCode", "integrations.tab.prime": "Prime Agent", "integrations.tab.aside": "Aside", + "integrations.tab.raycast": "Raycast", "integrations.aside.profilesTitle": "Aside profilleri", "integrations.aside.profilesHint": "Seçili modellerin hangi profillere aktarılacağını seçin. Aside’ın etkin profili değişmez.", "integrations.aside.all": "Tüm profilleri eşitle", @@ -1748,6 +1749,10 @@ export const tr: Record = { "integrations.semantics.zcode": "Yalnızca ~/.zcode/v2/config.json içindeki provider.opencodex bölümünü yönetir. Z.ai oturumu ve diğer sağlayıcılar değişmez. Değişikliklerden sonra ZCode'u yeniden başlatın.", "integrations.semantics.prime": "Yalnızca Prime Agent'ın models.json dosyasındaki providers.opencodex bölümünü yönetir — PRIME_AGENT_CODING_AGENT_DIR ayarlı değilse ~/.prime/agent. Diğer sağlayıcılar ve model geçersiz kılmaları değişmez. Yeni oturumlarda geçerli olur.", "integrations.semantics.aside": "Yalnızca bu profilin ~/.aside/u//models.json dosyasındaki providers.opencodex bölümünü yönetir. Diğer sağlayıcılarınız değişmez. Uyguladıktan sonra Aside’ı tamamen kapatıp yeniden açın.", + "integrations.semantics.raycast": "Raycast'in providers.yaml dosyasına bir OpenCodex sağlayıcı girdisi ekler; böylece yönlendirilen her model Raycast AI model seçicisinde görünür. Raycast Pro gerekir.", + "integrations.raycast.proRequired": "Custom Providers bir Raycast Pro özelliğidir. Dosya yazılır, ancak bir Pro aboneliği etkin olana kadar Raycast bunu yok sayar.", + "integrations.raycast.planUnknown": "Raycast abonelik durumu okunamadı; Custom Providers için Raycast Pro gerekir.", + "integrations.raycast.revealConfig": "Raycast → Ayarlar → AI bölümünü açıp sağlayıcı klasörünün oluşması için „Reveal Providers Config“ seçeneğine bir kez tıklayın.", "integrations.semantics.omp": "Kataloğu yüklemek için OMP'yi yeniden başlatın.", "codexAuth.mainAccount": "Ana Hesap", "codexAuth.logLabel": "Günlük etiketi", @@ -2082,6 +2087,7 @@ export const tr: Record = { "api.clientConfig.clientZcode": "ZCode", "api.clientConfig.clientPrime": "Prime Agent", "api.clientConfig.clientAside": "Aside", + "api.clientConfig.clientRaycast": "Raycast", "api.clientConfig.copy": "JSON Kopyala", "api.clientConfig.download": "İndir", "api.clientConfig.loading": "İstemci konfigürasyonu oluşturuluyor…", diff --git a/gui/src/i18n/zh-TW.ts b/gui/src/i18n/zh-TW.ts index 2b7e6ac6ba..4e137ebdd6 100644 --- a/gui/src/i18n/zh-TW.ts +++ b/gui/src/i18n/zh-TW.ts @@ -2178,6 +2178,7 @@ export const zhTW: Record = { "integrations.tab.zcode": "ZCode", "integrations.tab.prime": "Prime Agent", "integrations.tab.aside": "Aside", + "integrations.tab.raycast": "Raycast", "integrations.aside.profilesTitle": "Aside 設定檔", "integrations.aside.profilesHint": "選擇要接收所選模型的設定檔。Aside 目前使用的設定檔不會改變。", "integrations.aside.all": "同步所有設定檔", @@ -2337,6 +2338,10 @@ export const zhTW: Record = { "integrations.semantics.zcode": "僅管理 ~/.zcode/v2/config.json 中的 provider.opencodex,不會變更 Z.ai 登入狀態或其他供應商。變更後請重新啟動 ZCode。", "integrations.semantics.prime": "僅管理 Prime Agent 的 models.json 中的 providers.opencodex;預設位於 ~/.prime/agent,若設定 PRIME_AGENT_CODING_AGENT_DIR 則以其為準。不會變更其他供應商或模型覆寫設定。對新工作階段生效。", "integrations.semantics.aside": "僅管理此設定檔的 ~/.aside/u//models.json 中的 providers.opencodex。其他供應商維持不變。套用後請完全結束並重新開啟 Aside。", + "integrations.semantics.raycast": "在 Raycast 的 providers.yaml 中新增一個 OpenCodex 供應商項目,讓所有已路由的模型出現在 Raycast AI 模型選擇器中。需要 Raycast Pro。", + "integrations.raycast.proRequired": "Custom Providers 是 Raycast Pro 功能。檔案會被寫入,但在 Pro 訂閱生效之前 Raycast 會忽略它。", + "integrations.raycast.planUnknown": "無法讀取 Raycast 訂閱狀態;Custom Providers 需要 Raycast Pro。", + "integrations.raycast.revealConfig": "開啟 Raycast → 設定 → AI,點一次「Reveal Providers Config」,以便建立 providers 資料夾。", "codexAuth.pinned": "已固定", "codexAuth.pinnedHint": "你手動選取了此帳號,因此較高的選擇順序不會越過它。此固定會持續到該帳號用盡、你改選其他帳號,或你變更任一選擇順序為止。", "codexAuth.requestUserInput": "在 Default 模式中要求輸入", @@ -2378,6 +2383,7 @@ export const zhTW: Record = { "api.clientConfig.clientZcode": "ZCode", "api.clientConfig.clientPrime": "Prime Agent", "api.clientConfig.clientAside": "Aside", + "api.clientConfig.clientRaycast": "Raycast", "cws.tabsLabel": "Combo 詳細區段", "cws.field.nativeAlias": "原生 OpenAI 別名", "cws.field.nativeAliasHint": "讓此 combo 擁有受支援的未限定原生 OpenAI 模型 ID。帶有帳號或供應商限定的 OpenAI 路由仍保持獨立。", diff --git a/gui/src/i18n/zh.ts b/gui/src/i18n/zh.ts index 42ac3941d4..67400eaaea 100644 --- a/gui/src/i18n/zh.ts +++ b/gui/src/i18n/zh.ts @@ -1110,6 +1110,7 @@ export const zh: Record = { "integrations.tab.zcode": "ZCode", "integrations.tab.prime": "Prime Agent", "integrations.tab.aside": "Aside", + "integrations.tab.raycast": "Raycast", "integrations.aside.profilesTitle": "Aside 配置文件", "integrations.aside.profilesHint": "选择要接收所选模型的配置文件。Aside 当前使用的配置文件不会改变。", "integrations.aside.all": "同步所有配置文件", @@ -1269,6 +1270,10 @@ export const zh: Record = { "integrations.semantics.zcode": "仅管理 ~/.zcode/v2/config.json 中的 provider.opencodex,不会更改 Z.ai 登录状态或其他提供商。更改后请重启 ZCode。", "integrations.semantics.prime": "仅管理 Prime Agent 的 models.json 中的 providers.opencodex;默认位于 ~/.prime/agent,若设置 PRIME_AGENT_CODING_AGENT_DIR 则以其为准。不会更改其他提供商或模型覆盖设置。对新会话生效。", "integrations.semantics.aside": "仅管理此配置文件的 ~/.aside/u//models.json 中的 providers.opencodex。其他提供商保持不变。应用后请完全退出并重新打开 Aside。", + "integrations.semantics.raycast": "在 Raycast 的 providers.yaml 中添加一个 OpenCodex 提供商条目,让所有已路由的模型出现在 Raycast AI 模型选择器中。需要 Raycast Pro。", + "integrations.raycast.proRequired": "Custom Providers 是 Raycast Pro 功能。文件会被写入,但在 Pro 订阅生效之前 Raycast 会忽略它。", + "integrations.raycast.planUnknown": "无法读取 Raycast 订阅状态;Custom Providers 需要 Raycast Pro。", + "integrations.raycast.revealConfig": "打开 Raycast → 设置 → AI,点击一次“Reveal Providers Config”,以便创建 providers 文件夹。", "codexAuth.mainAccount": "主账号", "codexAuth.logLabel": "日志标签", "codexAuth.codexApp": "Codex App", @@ -1600,6 +1605,7 @@ export const zh: Record = { "api.clientConfig.clientZcode": "ZCode", "api.clientConfig.clientPrime": "Prime Agent", "api.clientConfig.clientAside": "Aside", + "api.clientConfig.clientRaycast": "Raycast", "api.clientConfig.copy": "复制配置", "api.clientConfig.download": "下载", "api.clientConfig.loading": "正在生成客户端配置…", diff --git a/gui/src/pages/integrations/FileIntegrationPage.tsx b/gui/src/pages/integrations/FileIntegrationPage.tsx index 51db75bd9f..2eef2c5cf0 100644 --- a/gui/src/pages/integrations/FileIntegrationPage.tsx +++ b/gui/src/pages/integrations/FileIntegrationPage.tsx @@ -8,6 +8,7 @@ import { markFor } from "../../components/integration-marks"; import IntegrationStateBadge from "./IntegrationStateBadge"; import ConsequenceDialog, { type ConsequenceCopy } from "./ConsequenceDialog"; import RestoreDialog from "./RestoreDialog"; +import RaycastPlanNotice from "./RaycastPlanNotice"; import { RollbackHistory } from "./RollbackHistory"; import { describeRefusal } from "./refusal-copy"; import { @@ -57,6 +58,7 @@ const SEMANTICS_KEY: Record = { zcode: "integrations.semantics.zcode", prime: "integrations.semantics.prime", aside: "integrations.semantics.aside", + raycast: "integrations.semantics.raycast", }; const TAB_LABEL_KEY: Record = { @@ -72,6 +74,7 @@ const TAB_LABEL_KEY: Record = { zcode: "integrations.tab.zcode", prime: "integrations.tab.prime", aside: "integrations.tab.aside", + raycast: "integrations.tab.raycast", }; export default function FileIntegrationPage({ @@ -261,6 +264,8 @@ export default function FileIntegrationPage({

{t(SEMANTICS_KEY[client])}

{status.configPath}

+ {/* Only the raycast envelope carries this; the guard is the field, not the id. */} + {status.raycast && } {status.appliedAt && (

diff --git a/gui/src/pages/integrations/RaycastPlanNotice.tsx b/gui/src/pages/integrations/RaycastPlanNotice.tsx new file mode 100644 index 0000000000..9f08446751 --- /dev/null +++ b/gui/src/pages/integrations/RaycastPlanNotice.tsx @@ -0,0 +1,32 @@ +import { useT } from "../../i18n/shared"; +import { Notice } from "../../ui"; +import type { RaycastInstall } from "./integration-api"; + +/* + * Raycast is the one file client whose `current` state can still mean + * "ignored": Custom Providers is a Pro feature, and the file is read from a + * folder Raycast only creates after a click in its own settings. Neither fact + * is a reason to refuse the write -- the user may be about to subscribe, or + * has already clicked and the folder is seconds old -- so the page writes and + * says so here instead of showing a green badge that overstates the result. + * + * `free` is a warning because it is a known blocker; `unknown` stays muted + * because on Linux and Windows there is no subscription signal to read, and a + * Pro user there must not be told they are not one. + */ +export default function RaycastPlanNotice({ install }: { install: RaycastInstall }) { + const t = useT(); + return ( + <> + {install.plan === "free" && ( + {t("integrations.raycast.proRequired")} + )} + {install.plan === "unknown" && ( +

{t("integrations.raycast.planUnknown")}

+ )} + {!install.aiDirPresent && ( +

{t("integrations.raycast.revealConfig")}

+ )} + + ); +} diff --git a/gui/src/pages/integrations/integration-api.ts b/gui/src/pages/integrations/integration-api.ts index 7a9139f436..38b0e0fe89 100644 --- a/gui/src/pages/integrations/integration-api.ts +++ b/gui/src/pages/integrations/integration-api.ts @@ -14,6 +14,7 @@ export const FILE_INTEGRATION_CLIENTS = [ "zcode", "prime", "aside", + "raycast", ] as const; export type FileIntegrationClientId = (typeof FILE_INTEGRATION_CLIENTS)[number]; @@ -36,6 +37,19 @@ export type IntegrationRefusalReason = | "snapshot_expired" | "write_failed"; +export type RaycastPlan = "pro" | "free" | "unknown"; + +/** + * Raycast's app-side facts, sent only on `/api/client-integrations/raycast`. + * Custom Providers is a Pro feature, so a `current` file can still be one + * Raycast ignores — this is what lets the page say so instead of showing green. + */ +export interface RaycastInstall { + plan: RaycastPlan; + appPath: string | null; + aiDirPresent: boolean; +} + export interface IntegrationStatus { clientId: FileIntegrationClientId; state: IntegrationState; @@ -49,6 +63,7 @@ export interface IntegrationStatus { /** Aside's explicit account-backed profile scope and desired sync state. */ profileId?: number; enabled?: boolean; + raycast?: RaycastInstall; } export interface IntegrationStateListEnvelope { diff --git a/gui/src/pages/integrations/integration-tabs.ts b/gui/src/pages/integrations/integration-tabs.ts index 33c4f04358..99502bde87 100644 --- a/gui/src/pages/integrations/integration-tabs.ts +++ b/gui/src/pages/integrations/integration-tabs.ts @@ -46,6 +46,7 @@ export const TABS: readonly TabDefinition[] = [ { id: "zcode", hash: "integrations/zcode", labelKey: "integrations.tab.zcode" }, { id: "prime", hash: "integrations/prime", labelKey: "integrations.tab.prime" }, { id: "aside", hash: "integrations/aside", labelKey: "integrations.tab.aside" }, + { id: "raycast", hash: "integrations/raycast", labelKey: "integrations.tab.raycast" }, ] as const; export const FILE_CLIENTS = new Set([ @@ -61,4 +62,5 @@ export const FILE_CLIENTS = new Set([ "zcode", "prime", "aside", + "raycast", ]); diff --git a/gui/src/pages/integrations/overview-clients.ts b/gui/src/pages/integrations/overview-clients.ts index 4dd347b90c..7932cf5648 100644 --- a/gui/src/pages/integrations/overview-clients.ts +++ b/gui/src/pages/integrations/overview-clients.ts @@ -152,6 +152,7 @@ const FILE_LABEL_KEY: Record = { zcode: "integrations.tab.zcode", prime: "integrations.tab.prime", aside: "integrations.tab.aside", + raycast: "integrations.tab.raycast", }; /** A file client's block is in the file for both `current` and `stale`. */ diff --git a/gui/tests/client-config-panel.test.tsx b/gui/tests/client-config-panel.test.tsx index 8acc44e9ee..ea8210e7e4 100644 --- a/gui/tests/client-config-panel.test.tsx +++ b/gui/tests/client-config-panel.test.tsx @@ -170,8 +170,8 @@ function rowButton(container: HTMLElement, name: string, label: string): HTMLBut .find(el => el.textContent?.trim() === label)!; } -test("the API download surface includes DSH, MiniMax Code and Aside as clients", () => { - expect(CLIENTS).toEqual(["opencode", "pi", "omp", "hermes", "openclaw", "kimi", "gajae", "dsh", "mcode", "zcode", "prime", "aside"]); +test("the API download surface includes DSH, MiniMax Code, Aside and Raycast as clients", () => { + expect(CLIENTS).toEqual(["opencode", "pi", "omp", "hermes", "openclaw", "kimi", "gajae", "dsh", "mcode", "zcode", "prime", "aside", "raycast"]); expect(CLIENT_LABEL_KEYS.dsh).toBe("api.clientConfig.clientDsh"); expect(CLIENT_LABEL_KEYS.mcode).toBe("api.clientConfig.clientMcode"); expect(CLIENT_LABEL_KEYS.zcode).toBe("api.clientConfig.clientZcode"); diff --git a/gui/tests/fr-localization.test.ts b/gui/tests/fr-localization.test.ts index 221de55d00..8c1ca29ada 100644 --- a/gui/tests/fr-localization.test.ts +++ b/gui/tests/fr-localization.test.ts @@ -118,6 +118,8 @@ const INTENTIONAL_ENGLISH = new Set([ "api.clientConfig.clientPrime", "integrations.tab.aside", "api.clientConfig.clientAside", + "integrations.tab.raycast", + "api.clientConfig.clientRaycast", "models.reasoningEffort.minimal", "models.reasoningEffort.max", "pws.pacingRpmUnit", diff --git a/gui/tests/integration-marks.test.ts b/gui/tests/integration-marks.test.ts index b964bc4ce1..b13387d1b6 100644 --- a/gui/tests/integration-marks.test.ts +++ b/gui/tests/integration-marks.test.ts @@ -61,15 +61,16 @@ test("no multi-color asset is masked", () => { /* * The inverse rule, and the one that cannot be derived from the file: a mark may * be a single ink and still not be a masking candidate, because that ink is the - * brand. openai.svg is #10A37F and deepseek-harness.svg is #4d6bfe; masking - * either repaints a trademark in the theme's text color. Pinned with their inks - * so a vendor changing its asset shows up here rather than silently satisfying - * the assertion. + * brand. openai.svg is #10A37F, deepseek-harness.svg is #4d6bfe and raycast.svg + * is #FF6363; masking any of them repaints a trademark in the theme's text + * color. Pinned with their inks so a vendor changing its asset shows up here + * rather than silently satisfying the assertion. */ test("a single-ink asset whose ink is a brand color is not masked", () => { for (const [src, ink] of [ ["/provider-icons/openai.svg", "#10a37f"], ["/provider-icons/deepseek-harness.svg", "#4d6bfe"], + ["/provider-icons/raycast.svg", "#ff6363"], ] as const) { expect(MASKED_MARKS.has(src), `${src} must not be masked`).toBe(false); expect([...inksOf(bodyOf(src))], `${src} ink changed upstream`).toEqual([ink]); diff --git a/gui/tests/integrations-api.test.ts b/gui/tests/integrations-api.test.ts index 4338d9ead8..eea7dcfa0c 100644 --- a/gui/tests/integrations-api.test.ts +++ b/gui/tests/integrations-api.test.ts @@ -16,9 +16,9 @@ import { const originalFetch = globalThis.fetch; -test("DSH and Aside are file integration clients", () => { +test("DSH, Aside and Raycast are file integration clients", () => { expect(FILE_INTEGRATION_CLIENTS).toEqual([ - "opencode", "pi", "omp", "hermes", "openclaw", "kimi", "gajae", "dsh", "mcode", "zcode", "prime", "aside", + "opencode", "pi", "omp", "hermes", "openclaw", "kimi", "gajae", "dsh", "mcode", "zcode", "prime", "aside", "raycast", ]); }); diff --git a/gui/tests/integrations-overview-rows.test.ts b/gui/tests/integrations-overview-rows.test.ts index 5bd673f849..54809a4422 100644 --- a/gui/tests/integrations-overview-rows.test.ts +++ b/gui/tests/integrations-overview-rows.test.ts @@ -290,12 +290,17 @@ test("every client counts toward the summary, not just the file clients", () => test("an unsettled file list renders unknown rows instead of dropping them", () => { const built = buildOverviewRows(sources({ clients: [], clientsSettled: false })); - expect(built.rows).toHaveLength(17); + expect(built.rows).toHaveLength(18); expect(rowById(built, "omp").state).toBe("unknown"); expect(rowById(built, "mcode").state).toBe("unknown"); expect(rowById(built, "zcode").state).toBe("unknown"); expect(rowById(built, "prime").state).toBe("unknown"); expect(rowById(built, "aside").state).toBe("unknown"); + expect(rowById(built, "raycast")).toMatchObject({ + hash: "integrations/raycast", + labelKey: "integrations.tab.raycast", + state: "unknown", + }); expect(rowById(built, "kimi").state).toBe("unknown"); expect(rowById(built, "dsh")).toMatchObject({ hash: "integrations/dsh", diff --git a/gui/tests/locale-parity.test.ts b/gui/tests/locale-parity.test.ts index 11976154c9..5ea6785493 100644 --- a/gui/tests/locale-parity.test.ts +++ b/gui/tests/locale-parity.test.ts @@ -130,6 +130,8 @@ const ZH_TW_KEEP_ENGLISH: ReadonlySet = new Set([ "api.clientConfig.clientPrime", "integrations.tab.aside", "api.clientConfig.clientAside", + "integrations.tab.raycast", + "api.clientConfig.clientRaycast", "integrations.codex.title", // Provider proper nouns kept in English "provider.name.commandCodeAuth", diff --git a/gui/tests/raycast-plan-notice.test.tsx b/gui/tests/raycast-plan-notice.test.tsx new file mode 100644 index 0000000000..4a8d44a77d --- /dev/null +++ b/gui/tests/raycast-plan-notice.test.tsx @@ -0,0 +1,51 @@ +import { expect, test } from "bun:test"; +import { createElement } from "react"; +import { renderToStaticMarkup } from "react-dom/server"; +import { I18nContext, type TFn } from "../src/i18n/shared"; +import RaycastPlanNotice from "../src/pages/integrations/RaycastPlanNotice"; +import type { RaycastInstall } from "../src/pages/integrations/integration-api"; + +/* + * Raycast reads providers.yaml only on a Pro plan and only from a folder it + * creates itself, so a `current` badge can be a lie. The notice is the one place + * that lie is corrected, and each of its three lines answers a different + * question; a regression that drops one leaves the page green and silent. + */ + +const echoT: TFn = key => key; + +function render(install: RaycastInstall): string { + return renderToStaticMarkup( + createElement( + I18nContext.Provider, + { value: { locale: "en", setLocale: () => {}, t: echoT } }, + createElement(RaycastPlanNotice, { install }), + ), + ); +} + +test("a Pro install with the ai folder renders nothing", () => { + expect(render({ plan: "pro", appPath: "/Applications/Raycast.app", aiDirPresent: true })).toBe(""); +}); + +test("a free plan is a warning notice, never a refusal", () => { + const markup = render({ plan: "free", appPath: "/Applications/Raycast.app", aiDirPresent: true }); + expect(markup).toContain("notice-warn"); + expect(markup).toContain("integrations.raycast.proRequired"); + expect(markup).not.toContain("notice-err"); + expect(markup).not.toContain("integrations.raycast.planUnknown"); +}); + +test("an unreadable plan stays muted, because non-macOS hosts have no signal", () => { + const markup = render({ plan: "unknown", appPath: null, aiDirPresent: true }); + expect(markup).toContain('data-raycast-plan="unknown"'); + expect(markup).toContain("integrations.raycast.planUnknown"); + expect(markup).not.toContain("notice-warn"); +}); + +test("a missing ai folder adds the reveal hint independently of the plan", () => { + const markup = render({ plan: "free", appPath: "/Applications/Raycast.app", aiDirPresent: false }); + expect(markup).toContain("integrations.raycast.proRequired"); + expect(markup).toContain('data-raycast-ai-dir="absent"'); + expect(markup).toContain("integrations.raycast.revealConfig"); +}); diff --git a/scripts/test-layout/layout.json b/scripts/test-layout/layout.json index d309073a3f..753b896416 100644 --- a/scripts/test-layout/layout.json +++ b/scripts/test-layout/layout.json @@ -690,6 +690,7 @@ "install-scripts.test.ts": "ci-workflows", "integrations-invariants.test.ts": "gui", "integrations-journal.test.ts": "clients", + "integrations-merge.test.ts": "clients", "integrations-serialize.test.ts": "clients", "integrations-state.test.ts": "clients", "integrations-writer.test.ts": "clients", @@ -998,6 +999,8 @@ "reserve-quota-scope.test.ts": "codex-integration", "rate-limit-reset-credits.test.ts": "gui", "rate-limit-retry.test.ts": "providers", + "raycast-client.test.ts": "clients", + "raycast-detect.test.ts": "clients", "reasoning-effort.test.ts": "codex-integration", "reasoning-replay-identity.test.ts": "adapters", "reasoning-replay-robustness.test.ts": "adapters", diff --git a/src/cli/dispatch.ts b/src/cli/dispatch.ts index 6d018536c7..c884bb2e5d 100644 --- a/src/cli/dispatch.ts +++ b/src/cli/dispatch.ts @@ -403,7 +403,7 @@ const commandRunners: Record = { }, config, port: live.port, - }, ["mcode", "pi"])); + }, ["mcode", "pi", "raycast"])); } catch (error) { console.warn(`Client integrations were not refreshed: ${error instanceof Error ? error.message : String(error)}`); } diff --git a/src/cli/help.ts b/src/cli/help.ts index 0b3652ab59..0cd6bec4dc 100644 --- a/src/cli/help.ts +++ b/src/cli/help.ts @@ -77,7 +77,7 @@ Usage: ocx memory [--json] Alias of ocx observe memory ocx api-key Alias of ocx access key ocx access External API keys and endpoint information - ocx export --client Print a client config wired to the running proxy (12 clients) + ocx export --client Print a client config wired to the running proxy (13 clients) ocx integration client Enable, disable, inspect or roll back a client integration ocx grok Grok Build model selection and apply ocx system Runtime settings, startup, sync, OpenCodex updates, and Codex CLI inspection diff --git a/src/cli/index.ts b/src/cli/index.ts index 7b863630b9..9d9f08951c 100755 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -92,6 +92,15 @@ import { grokSyncFailureMessage, reconcileEnsureDesiredIntegrations, } from "./ensure-desired-integrations"; +import { refreshOwnedCatalogIntegrations } from "../integrations/catalog-refresh"; +import { loadExportModels } from "../server/management/model-rows"; + +import { removeOwnedConfigAfterDesktopCleanup } from "./uninstall-client-state"; +import { withProcessRuntimeProvenance } from "../lib/bun-runtime"; +import { selfLaunchArgv } from "../lib/self-launch-argv"; +import { initializeNodeLauncherContext } from "./launcher-context"; +import { createLocalAttestationSecret } from "../lib/local-management-attestation"; +import { MEMORY_DRAIN_RESTART_MS, REPLACEMENT_READY_TIMEOUT_MS } from "../lib/system-restart-contract"; /** * A failed shell-hook reconcile is not cosmetic: a stale hook keeps sourcing @@ -105,13 +114,25 @@ function reportShellHookFailure(result: { state: "installed" | "absent" | "faile console.warn(" Check ~/.zshrc for the '# opencodex claude-env hook' block."); } - -import { removeOwnedConfigAfterDesktopCleanup } from "./uninstall-client-state"; -import { withProcessRuntimeProvenance } from "../lib/bun-runtime"; -import { selfLaunchArgv } from "../lib/self-launch-argv"; -import { initializeNodeLauncherContext } from "./launcher-context"; -import { createLocalAttestationSecret } from "../lib/local-management-attestation"; -import { MEMORY_DRAIN_RESTART_MS, REPLACEMENT_READY_TIMEOUT_MS } from "../lib/system-restart-contract"; +async function refreshOwnedRaycastCatalog( + config: ReturnType, + port: number, +): Promise { + try { + const outcomes = await refreshOwnedCatalogIntegrations({ + models: () => loadExportModels(config), + config, + port, + }, ["raycast"]); + for (const outcome of outcomes) { + if (!outcome.ok) { + console.error(`⚠️ Raycast integration was not refreshed: ${outcome.reason}`); + } + } + } catch (error) { + console.error(`⚠️ Raycast integration was not refreshed: ${error instanceof Error ? error.message : String(error)}`); + } +} initializeNodeLauncherContext(); @@ -493,6 +514,7 @@ async function handleStart(options: { block?: boolean } = {}) { }, ); if (!startupSync.ran) console.log(" Codex integration OFF; startup left Codex native."); + await refreshOwnedRaycastCatalog(config, port); // #1046: one warning per startup, after BOTH writes. The server's cache // invalidation happens first and the catalog sync second, so the mtime is only // final here — and neither write site warns on its own, or a boot that hits @@ -558,6 +580,7 @@ async function handleEnsure(options: { existingIsSuccess?: boolean } = {}): Prom return null; }); if (synced?.status === "skipped") console.log(" Codex integration OFF; startup left Codex native."); + await refreshOwnedRaycastCatalog(config, live.port); // Ensure env file exists for already-running proxy (may have been deleted or pre-dates this feature). const systemEnv = await injectSystemEnv(live.port, config).catch(() => ({ injected: false })); reportShellHookFailure(reconcileShellHook(systemEnv.injected)); @@ -602,6 +625,7 @@ async function handleEnsure(options: { existingIsSuccess?: boolean } = {}): Prom return null; }); if (synced?.status === "skipped") console.log(" Codex integration OFF; startup left Codex native."); + await refreshOwnedRaycastCatalog(config, port); // The child opens /healthz before its best-effort roster reconcile. Await the same idempotent // operation in the parent so `ocx ensure` cannot report success while stale ocx-*.md files are // still observable. Always use the live port, including fallback-port starts. diff --git a/src/cli/integrations.ts b/src/cli/integrations.ts index bcb87d5d18..89ab3ee046 100644 --- a/src/cli/integrations.ts +++ b/src/cli/integrations.ts @@ -161,6 +161,39 @@ export async function handleGrokCommand(argv: string[], deps: RuntimeApiDeps = { }); } +/** The Raycast-only block the single-client route adds; see IntegrationStateEnvelope. */ +interface RaycastStatusBlock { + plan: string; + aiDirPresent: boolean; +} + +function raycastBlock(result: unknown): RaycastStatusBlock | null { + if (!result || typeof result !== "object") return null; + const block = (result as { raycast?: unknown }).raycast; + if (!block || typeof block !== "object") return null; + const { plan, aiDirPresent } = block as Partial; + return typeof plan === "string" && typeof aiDirPresent === "boolean" ? { plan, aiDirPresent } : null; +} + +/** + * Text view of one client's status. + * + * Raycast carries an extra block, and the generic summary would print it as + * three dotted keys. A `current` file that Raycast ignores for want of a Pro + * subscription is the one fact this view must not bury, so `plan` gets its own + * line and a missing `ai` folder gets the instruction that creates it. + */ +function singleClientStatusLines(result: unknown): string[] { + const raycast = raycastBlock(result); + if (!raycast) return summaryLines(result); + const rest = Object.fromEntries(Object.entries(result as Record).filter(([key]) => key !== "raycast")); + const lines = [...summaryLines(rest), `plan: ${raycast.plan}`]; + if (!raycast.aiDirPresent) { + lines.push('Open Raycast → Settings → AI → "Reveal Providers Config" once so the ai folder exists.'); + } + return lines; +} + /** * The headless half of the client-integration toggle. * @@ -197,7 +230,7 @@ export async function handleClientIntegrationCommand( : [String((result as { error?: string }).error ?? "No Aside profiles found.")] : rows ? rows.map(row => `${String(row.clientId)}: ${String(row.state)}${row.installed ? "" : " (not installed)"}`) - : summaryLines(result)); + : singleClientStatusLines(result)); return; } diff --git a/src/cli/registry.ts b/src/cli/registry.ts index 00ff25ed52..467a0f7971 100644 --- a/src/cli/registry.ts +++ b/src/cli/registry.ts @@ -287,8 +287,8 @@ export const CLI_COMMANDS: CliCommandEntry[] = [ { name: "api-key", usage: "ocx api-key ...", summary: "Alias of ocx access key." }, { name: "export", - usage: "ocx export --client [--json] [--out ] [--force]", - summary: "Print a client config (OpenCode, Pi, OMP, Hermes, OpenClaw, Kimi Code, Gajae Code, DeepSeek Harness, MiniMax Code, ZCode, Prime Agent, Aside) wired to the running proxy.", + usage: "ocx export --client [--json] [--out ] [--force]", + summary: "Print a client config (OpenCode, Pi, OMP, Hermes, OpenClaw, Kimi Code, Gajae Code, DeepSeek Harness, MiniMax Code, ZCode, Prime Agent, Aside, Raycast) wired to the running proxy.", details: [ "--json prints the generated document as JSON on stdout; use --out for the client's native format.", "--out writes the native config there and refuses to replace an existing file without --force.", diff --git a/src/clients/config-export.ts b/src/clients/config-export.ts index 372abcc00e..8fb42f311d 100644 --- a/src/clients/config-export.ts +++ b/src/clients/config-export.ts @@ -37,6 +37,8 @@ export type { OmpModelEntry, OmpProviderBlock, OmpGeneratedConfig } from "./conf export type { ZcodeModelEntry, ZcodeProviderBlock, ZcodeGeneratedConfig } from "./config-export/zcode"; export type { DshReasoningEffort, DshWireReasoningEffort, DshModelEntry, DshProviderBlock, DshGeneratedConfig } from "./config-export/dsh"; export type { McodeProviderBlock, McodeModelEntry, McodeGeneratedConfig } from "./config-export/mcode"; +export type { RaycastAbility, RaycastAbilityName, RaycastModelEntry, RaycastProviderEntry, RaycastGeneratedConfig } from "./config-export/raycast"; +export { buildRaycastClientConfig, summarizeRaycast, buildRaycastContribution } from "./config-export/raycast"; import type { OpencodeLaunchEnv, OpencodeCatalogModel, ExportContext, PiModelEntry, ManagedContribution, ManagedFragment, ExportClientId, ExportClientSpec } from "./config-export/contracts"; import { OPENCODE_API_KEY_ENV_REF, OPENCODE_PROVIDER_BLOCK_DEFAULT_CONFIG, OPENCODE_CONFIG_SCHEMA, OPENCODE_PROVIDER_ID, PI_API_DIALECT, LOOPBACK_API_KEY_PLACEHOLDER, HERMES_API_KEY_ENV_REF, OPENCLAW_API_KEY_ENV_REF, GAJAE_API_KEY_ENV, OPENCODE_API_KEY_ENV, HERMES_API_KEY_ENV, OPENCLAW_API_KEY_ENV } from "./config-export/constants"; @@ -45,6 +47,7 @@ import { buildOmpClientConfig, summarizeOmp, buildOmpContribution } from "./conf import { buildDshClientConfig, summarizeDsh, buildDshContribution } from "./config-export/dsh"; import { buildMcodeClientConfig, summarizeMcode, buildMcodeContribution } from "./config-export/mcode"; import { buildZcodeClientConfig, summarizeZcode, buildZcodeContribution } from "./config-export/zcode"; +import { buildRaycastClientConfig, summarizeRaycast, buildRaycastContribution } from "./config-export/raycast"; @@ -533,6 +536,22 @@ export function asideConfigPath(env: OpencodeLaunchEnv = process.env, home: stri return join(asideAccountDir(env, home), "models.json"); } +/** + * Raycast's Custom Providers directory. Raycast hard-codes + * `~/.config/raycast/ai` on macOS AND Windows: it neither honors + * `XDG_CONFIG_HOME` nor ships a variable of its own that relocates the file, so + * unlike `opencodeGlobalConfigPath` there is no override to mirror and the env + * parameter exists only to keep the resolver signature uniform with the rest. + */ +export function raycastAiDir(_env: OpencodeLaunchEnv = process.env, home: string = homedir()): string { + return join(home, ".config", "raycast", "ai"); +} + +/** The providers file Raycast watches (manual.raycast.com/ai/custom-providers). */ +export function raycastConfigPath(env: OpencodeLaunchEnv = process.env, home: string = homedir()): string { + return join(raycastAiDir(env, home), "providers.yaml"); +} + /** Endpoint plus admission, identical for the V1 `options` and V2 `settings` field. */ function opencodeProviderConnection(baseURL: string, config: OcxConfig): OpencodeProviderConnection { const options: OpencodeProviderConnection = { baseURL }; @@ -1259,6 +1278,23 @@ export const EXPORT_CLIENTS: Record = { // bind would generate a config that 401s. loopbackOnly: true, }, + raycast: { + id: "raycast", + // Not a bare `providers.yaml`: same Downloads-folder collision argument as + // `aside-models.json`. + filename: "raycast-providers.yaml", + destination: env => raycastConfigPath(env), + apiKeyEnv: "", + exportHint: "Raycast reads providers.yaml with no api_keys entry; loopback needs no key.", + build: buildRaycastClientConfig, + format: "yaml", + summarize: summarizeRaycast, + buildContribution: buildRaycastContribution, + // Raycast's provider entry has no header field, and its `api_keys` value + // is read literally (no env interpolation), so the only way to admit a + // remote bind would be a plaintext secret on disk. Refuse instead. + loopbackOnly: true, + }, }; export const EXPORT_CLIENT_IDS: readonly ExportClientId[] = Object.keys(EXPORT_CLIENTS) as ExportClientId[]; diff --git a/src/clients/config-export/contracts.ts b/src/clients/config-export/contracts.ts index 039d7eaaf0..c888a4c257 100644 --- a/src/clients/config-export/contracts.ts +++ b/src/clients/config-export/contracts.ts @@ -93,7 +93,8 @@ export type ExportClientId = | "mcode" | "zcode" | "prime" - | "aside"; + | "aside" + | "raycast"; export interface ExportClientSpec { id: ExportClientId; diff --git a/src/clients/config-export/raycast.ts b/src/clients/config-export/raycast.ts new file mode 100644 index 0000000000..2cf9396ed5 --- /dev/null +++ b/src/clients/config-export/raycast.ts @@ -0,0 +1,86 @@ +import { exportPresentationLabel } from "../model-presentation"; +import { OPENCODE_PROVIDER_ID } from "./constants"; +import type { ExportContext, ManagedContribution } from "./contracts"; +import { authoritativeContextWindow, normalizeExportModels, singleFragment } from "./model-metadata"; + +export interface RaycastAbility { + supported: boolean; +} + +export type RaycastAbilityName = + | "temperature" + | "vision" + | "system_message" + | "tools" + | "reasoning_effort"; + +export interface RaycastModelEntry { + id: string; + name: string; + context?: number; + abilities: Record; +} + +export interface RaycastProviderEntry { + id: string; + name: string; + base_url: string; + models: RaycastModelEntry[]; +} + +export interface RaycastGeneratedConfig { + providers: RaycastProviderEntry[]; +} + +/** + * Raycast appends `/chat/completions` to `base_url`, so the proxy's `/v1` + * root is passed through unchanged. The format has no safe credential + * interpolation, which is why the registry exposes it only on loopback. + */ +export function buildRaycastClientConfig(ctx: ExportContext): RaycastGeneratedConfig { + const models: RaycastModelEntry[] = normalizeExportModels(ctx.models).map(model => { + const hasLadder = (model.reasoningEfforts?.length ?? 0) > 0; + const context = authoritativeContextWindow(model.contextWindow); + return { + id: model.namespaced, + name: exportPresentationLabel(model), + ...(context !== undefined ? { context } : {}), + abilities: { + temperature: { supported: !hasLadder }, + vision: { supported: model.inputModalities?.includes("image") ?? false }, + system_message: { supported: true }, + tools: { supported: true }, + reasoning_effort: { supported: hasLadder }, + }, + }; + }); + return { + providers: [ + { id: OPENCODE_PROVIDER_ID, name: "OpenCodex", base_url: ctx.baseUrl, models }, + ], + }; +} + +export function summarizeRaycast( + document: unknown, +): { modelCount: number; modelsWithoutLimits: number } { + const providers = (document as RaycastGeneratedConfig | undefined)?.providers ?? []; + const models = providers.find(provider => provider.id === OPENCODE_PROVIDER_ID)?.models ?? []; + return { + modelCount: models.length, + modelsWithoutLimits: models.filter(model => model.context === undefined).length, + }; +} + +/** + * Raycast stores providers in a sequence. The stable id selector owns only + * OpenCodex's element, preserving user-defined providers around it. + */ +export function buildRaycastContribution(ctx: ExportContext): ManagedContribution { + const doc = buildRaycastClientConfig(ctx); + return singleFragment( + "raycast", + ["providers", `[id=${OPENCODE_PROVIDER_ID}]`], + doc.providers[0]!, + ); +} diff --git a/src/clients/model-presentation.ts b/src/clients/model-presentation.ts new file mode 100644 index 0000000000..9a5f9ae3c3 --- /dev/null +++ b/src/clients/model-presentation.ts @@ -0,0 +1,61 @@ +import { CURSOR_CAPABILITIES } from "../adapters/cursor/catalog"; +import { nativeOpenAiCapabilityDisplayName } from "../codex/catalog/metadata"; +import type { ExportModel } from "./config-export/contracts"; + +const KNOWN_ACRONYMS = new Set(["gpt", "glm", "grok"]); + +function titleWord(word: string): string { + const lower = word.toLowerCase(); + if (KNOWN_ACRONYMS.has(lower)) return lower.toUpperCase(); + if (/^\d+\.\d+$/.test(word)) return word; + return lower.charAt(0).toUpperCase() + lower.slice(1); +} + +/** + * Last-resort label when no catalog or operator name exists. Joins dotted version + * tails (`5-1` → `5.1`, `2-5` → `2.5`) so Raycast reads like a product name + * instead of a slug. + */ +function humanizeModelSlug(modelId: string): string { + const parts = modelId.split("-"); + const words: string[] = []; + for (let index = 0; index < parts.length; index += 1) { + const part = parts[index]!; + const next = parts[index + 1]; + if (/^\d+$/.test(part) && next !== undefined && /^\d+$/.test(next)) { + words.push(`${part}.${next}`); + index += 1; + continue; + } + words.push(part); + } + return words.map(titleWord).join(" "); +} + +function wireModelId(model: ExportModel): string { + if (model.id?.trim()) return model.id.trim(); + const slash = model.namespaced.lastIndexOf("/"); + return slash >= 0 ? model.namespaced.slice(slash + 1) : model.namespaced; +} + +/** + * Human-facing model label for clients whose picker shows `name` verbatim. + * + * Raycast has no second column for provider, so the shared `exportModelLabel` + * suffix `(anthropic)` would be noise — and its fallback is the raw wire id + * because management slugs are deliberately withheld from ExportModel. Resolve + * operator labels first, then the canonical capability tables, then a slug + * humanizer. + */ +export function exportPresentationLabel(model: ExportModel): string { + const configured = model.displayName?.trim(); + if (configured) return configured; + const wireId = wireModelId(model); + const fromCursor = CURSOR_CAPABILITIES[wireId]?.displayName; + if (fromCursor) return fromCursor; + if (model.native) { + const native = nativeOpenAiCapabilityDisplayName(wireId); + if (native) return native; + } + return humanizeModelSlug(wireId); +} diff --git a/src/integrations/catalog-refresh.ts b/src/integrations/catalog-refresh.ts index 8efb990002..8b89762f30 100644 --- a/src/integrations/catalog-refresh.ts +++ b/src/integrations/catalog-refresh.ts @@ -10,7 +10,7 @@ import { /** Refresh only previously connected clients; a refused file never blocks its peers. */ export async function refreshOwnedCatalogIntegrations( input: Omit, - clientIds: readonly IntegrationClientId[] = ["pi", "aside"], + clientIds: readonly IntegrationClientId[] = ["pi", "aside", "raycast"], ): Promise { let models: Promise | undefined; const loadModels = () => models ??= Promise.resolve().then(() => diff --git a/src/integrations/merge.ts b/src/integrations/merge.ts index 4dccd48e50..768ddc755f 100644 --- a/src/integrations/merge.ts +++ b/src/integrations/merge.ts @@ -20,18 +20,103 @@ function clone(value: T): T { return value === undefined ? value : (JSON.parse(JSON.stringify(value)) as T); } -/** Write `value` at `path`, creating intermediate objects. Returns a new document. */ +/** + * `[field=value]` addresses the ONE element of a sequence whose `field` equals + * `value`. Raycast keeps its providers as a YAML list, so the element is the + * smallest thing we can own there; an index would move under us the moment + * the user reordered their own entries. Any other segment is a plain key. + */ +const ARRAY_SELECTOR = /^\[([A-Za-z_][A-Za-z0-9_]*)=([^\]]+)\]$/u; + +export type PathSegment = + | { kind: "key"; key: string } + | { kind: "select"; field: string; value: string }; + +export function parseSegment(raw: string): PathSegment { + const match = ARRAY_SELECTOR.exec(raw); + if (!match) return { kind: "key", key: raw }; + return { kind: "select", field: match[1]!, value: match[2]! }; +} + +/** + * Thrown when a selector matches more than one element. Picking either one + * would silently rewrite an entry the user may have written; the writer maps + * this to an `unsafe` refusal instead. + */ +export class AmbiguousSelectorError extends Error { + constructor(field: string, value: string) { + super(`more than one entry has ${field}=${value}`); + this.name = "AmbiguousSelectorError"; + } +} + +/** The index of the element a selector names, -1 when none matches. */ +function selectIndex(items: readonly unknown[], field: string, value: string): number { + const matches: number[] = []; + items.forEach((item, index) => { + if (isPlainRecord(item) && item[field] === value) matches.push(index); + }); + if (matches.length > 1) throw new AmbiguousSelectorError(field, value); + return matches[0] ?? -1; +} + +function assertNever(segment: never): never { + throw new Error(`unknown path segment ${JSON.stringify(segment)}`); +} + +/** + * Write `value` at `path`, creating intermediate containers. Returns a new document. + * + * A `key` segment descends through a record, creating `{}` where the slot is + * absent or holds something else. A `select` segment descends through an + * array the same way, creating `[]`; a missing element is pushed, a matching + * one is replaced in place so the user's ordering survives. + */ export function setPath(doc: unknown, path: readonly string[], value: unknown): unknown { if (path.length === 0) throw new Error("setPath needs a non-empty path"); - const root: Record = isPlainRecord(doc) ? clone(doc) : {}; - let cursor = root; - for (const key of path.slice(0, -1)) { - const next = cursor[key]; - if (!isPlainRecord(next)) cursor[key] = {}; - cursor = cursor[key] as Record; + /* + * `parent[slot]` is the position the segment just consumed addresses. The + * root sits in a one-key holder so the first segment needs no special case: + * a non-record document is replaced by `{}` exactly as before. + */ + const holder: Record = { root: isPlainRecord(doc) ? clone(doc) : {} }; + let parent: Record | unknown[] = holder; + let slot: string | number = "root"; + const read = (): unknown => (Array.isArray(parent) ? parent[slot as number] : parent[slot as string]); + const write = (next: unknown): void => { + if (Array.isArray(parent)) parent[slot as number] = next; + else parent[slot as string] = next; + }; + for (const raw of path) { + const segment = parseSegment(raw); + switch (segment.kind) { + case "key": { + if (!isPlainRecord(read())) write({}); + parent = read() as Record; + slot = segment.key; + break; + } + case "select": { + if (!Array.isArray(read())) write([]); + const items = read() as unknown[]; + const found = selectIndex(items, segment.field, segment.value); + parent = items; + if (found >= 0) { + slot = found; + } else { + // Seed the element so the selector stays true for whatever a deeper + // segment writes into it; a last-position select replaces it whole. + slot = items.length; + items.push({ [segment.field]: segment.value }); + } + break; + } + default: + return assertNever(segment); + } } - cursor[path[path.length - 1]!] = clone(value); - return root; + write(clone(value)); + return holder.root; } /** @@ -54,27 +139,53 @@ export function deletePath( ): { doc: unknown; removed: boolean } { if (!isPlainRecord(doc) || path.length === 0) return { doc, removed: false }; const root = clone(doc) as Record; - const chain: Record[] = [root]; - let cursor: Record = root; - for (const key of path.slice(0, -1)) { - const next = cursor[key]; - if (!isPlainRecord(next)) return { doc: root, removed: false }; - cursor = next; - chain.push(cursor); + // `chain[i]` is the container segment `i` is resolved against; `slots[i]` is + // the key or index it resolved to, so the prune walk can delete by position. + const chain: (Record | unknown[])[] = [root]; + const slots: (string | number)[] = []; + for (let depth = 0; depth < path.length; depth += 1) { + const container = chain[depth]!; + const segment = parseSegment(path[depth]!); + switch (segment.kind) { + case "key": { + if (Array.isArray(container) || !(segment.key in container)) return { doc: root, removed: false }; + slots.push(segment.key); + chain.push(container[segment.key] as Record | unknown[]); + break; + } + case "select": { + if (!Array.isArray(container)) return { doc: root, removed: false }; + const found = selectIndex(container, segment.field, segment.value); + if (found < 0) return { doc: root, removed: false }; + slots.push(found); + chain.push(container[found] as Record | unknown[]); + break; + } + default: + return assertNever(segment); + } + // Only the leaf may be a scalar; walking into one means the path is absent. + if (depth < path.length - 1) { + const next = chain[depth + 1]; + if (!isPlainRecord(next) && !Array.isArray(next)) return { doc: root, removed: false }; + } } - const leaf = path[path.length - 1]!; - if (!(leaf in cursor)) return { doc: root, removed: false }; - delete cursor[leaf]; + const remove = (container: Record | unknown[], slot: string | number): void => { + if (Array.isArray(container)) container.splice(slot as number, 1); + else delete container[slot as string]; + }; + remove(chain[path.length - 1]!, slots[path.length - 1]!); /* * Walk back up, pruning only containers this deletion emptied AND that we * created. The root is never pruned. */ - for (let index = chain.length - 1; index >= 1; index -= 1) { + for (let index = path.length - 1; index >= 1; index -= 1) { const container = chain[index]!; - if (Object.keys(container).length > 0) break; + const empty = Array.isArray(container) ? container.length === 0 : Object.keys(container).length === 0; + if (!empty) break; const containerPath = path.slice(0, index).join("\u0000"); if (!createdContainers.has(containerPath)) break; - delete chain[index - 1]![path[index - 1]!]; + remove(chain[index - 1]!, slots[index - 1]!); } return { doc: root, removed: true }; } @@ -121,9 +232,31 @@ export function createdContainerPaths( for (const fragment of contribution.fragments) { let cursor: unknown = doc; for (let depth = 0; depth < fragment.path.length - 1; depth += 1) { - const key = fragment.path[depth]!; - const next = isPlainRecord(cursor) ? cursor[key] : undefined; - if (!isPlainRecord(next)) { + const segment = parseSegment(fragment.path[depth]!); + let next: unknown; + switch (segment.kind) { + case "key": { + /* + * The container this key must hold is whatever the NEXT segment + * descends into: an array when that is a selector, a record + * otherwise. Either one is ours to create when absent. + */ + const nextSegment = parseSegment(fragment.path[depth + 1]!); + next = isPlainRecord(cursor) ? cursor[segment.key] : undefined; + if (nextSegment.kind === "select" ? !Array.isArray(next) : !isPlainRecord(next)) next = undefined; + break; + } + case "select": { + // A selector that matches nothing means setPath will push the element. + next = Array.isArray(cursor) + ? cursor.find(item => isPlainRecord(item) && item[segment.field] === segment.value) + : undefined; + break; + } + default: + return assertNever(segment); + } + if (next === undefined) { created.add(fragment.path.slice(0, depth + 1).join("\u0000")); cursor = undefined; continue; diff --git a/src/integrations/raycast-detect.ts b/src/integrations/raycast-detect.ts new file mode 100644 index 0000000000..5e79578f46 --- /dev/null +++ b/src/integrations/raycast-detect.ts @@ -0,0 +1,110 @@ +/** + * Detect a Raycast install and whether Custom Providers can take effect. + * + * Custom Providers is a Raycast Pro feature: Raycast reads + * `~/.config/raycast/ai/providers.yaml` only while a subscription is active, and + * the `ai` directory itself only exists once the user has clicked "Reveal + * Providers Config" in Settings > AI. Neither fact stops the writer — the plan + * (devlog/_plan/260904_raycast_integration/000_plan.md) makes a free plan a + * WARNING, never a refusal — so this module only answers what status and the + * GUI need to explain a file that is written but ignored. + * + * Detection is read-only and injectable, like cursor-detect.ts: nothing here + * touches the Raycast install or its preferences, and the tests run against + * stubbed deps rather than the machine they execute on. + */ +import { existsSync } from "node:fs"; +import { homedir } from "node:os"; +import { posix, win32 } from "node:path"; + +export type RaycastPlan = "pro" | "free" | "unknown"; + +export interface RaycastInstall { + /** The app bundle or install directory, or null when none of the well-known locations exist. */ + appPath: string | null; + /** `~/.config/raycast/ai` exists — the install signal the registry uses. */ + aiDirPresent: boolean; + plan: RaycastPlan; +} + +export interface RaycastDetectDeps { + platform: string; + homedir: string; + env: Record; + exists(path: string): boolean; + /** stdout of `defaults read ` trimmed, or null when the command fails / is unavailable. */ + readDefault(domain: string, key: string): string | null; +} + +/** + * The preference Raycast writes for its subscription state. Read through + * `defaults` rather than by parsing the plist: cfprefsd caches writes, so the + * file on disk can lag what the running app believes. + */ +const RAYCAST_DEFAULTS_DOMAIN = "com.raycast.macos.v1"; +const RAYCAST_SUBSCRIPTION_KEY = "subscriptions_active"; + +export function realRaycastDetectDeps(): RaycastDetectDeps { + return { + platform: process.platform, + homedir: homedir(), + env: process.env, + exists: path => { + try { + return existsSync(path); + } catch { + return false; + } + }, + readDefault: (domain, key) => { + // `defaults` is macOS-only; elsewhere the plan is simply unknown. + if (process.platform !== "darwin") return null; + try { + const result = Bun.spawnSync(["defaults", "read", domain, key], { stdout: "pipe", stderr: "pipe" }); + if (result.exitCode !== 0) return null; + return result.stdout.toString().trim(); + } catch { + return null; + } + }, + }; +} + +function appPathFor(deps: RaycastDetectDeps): string | null { + // Join with the target platform's separator so a test describing another OS + // gets that OS's paths, not the host's. + const { join } = deps.platform === "win32" ? win32 : posix; + if (deps.platform === "darwin") { + for (const candidate of ["/Applications/Raycast.app", join(deps.homedir, "Applications", "Raycast.app")]) { + if (deps.exists(candidate)) return candidate; + } + return null; + } + if (deps.platform === "win32") { + const local = deps.env.LOCALAPPDATA; + if (!local) return null; + const candidate = join(local, "Programs", "Raycast"); + return deps.exists(candidate) ? candidate : null; + } + return null; +} + +function planFor(deps: RaycastDetectDeps): RaycastPlan { + if (deps.platform !== "darwin") return "unknown"; + // Read once: `defaults` spawns a process, and the answer cannot change + // between two reads inside one detection. + const value = deps.readDefault(RAYCAST_DEFAULTS_DOMAIN, RAYCAST_SUBSCRIPTION_KEY); + if (value === "1") return "pro"; + if (value === "0") return "free"; + return "unknown"; +} + +export function detectRaycast(deps: RaycastDetectDeps = realRaycastDetectDeps()): RaycastInstall { + const { join } = deps.platform === "win32" ? win32 : posix; + return { + appPath: appPathFor(deps), + // Raycast ignores XDG and uses this path on every platform it ships on. + aiDirPresent: deps.exists(join(deps.homedir, ".config", "raycast", "ai")), + plan: planFor(deps), + }; +} diff --git a/src/integrations/registry.ts b/src/integrations/registry.ts index 13662d52d5..f5780f4f98 100644 --- a/src/integrations/registry.ts +++ b/src/integrations/registry.ts @@ -35,6 +35,8 @@ import { piConfigPath, primeAgentDir, primeConfigPath, + raycastAiDir, + raycastConfigPath, zcodeConfigPath, zcodeHomeDir, type ExportClientId, @@ -261,6 +263,22 @@ export const INTEGRATION_CLIENTS: Record join(asideHomeDir(env, home), "u"), }, + raycast: { + id: "raycast", + configPath: (env = process.env, home = homedir()) => raycastConfigPath(env, home), + /* + * The `ai` directory, not `Raycast.app`. Raycast creates it only when the + * user clicks "Reveal Providers Config" in Settings > AI, which is exactly + * the signal that Custom Providers is reachable on this install; an app + * bundle alone says nothing about the plan or the feature. + * + * No `sourcePreservingYaml`: that patcher handles block-map leaves only, + * and our entry is a SEQUENCE item, so the file is re-rendered through + * `renderYaml` (block style). The `[id=opencodex]` selector keeps the user's + * other providers in place across that re-render. + */ + detectDir: (env = process.env, home = homedir()) => raycastAiDir(env, home), + }, }; export const INTEGRATION_CLIENT_IDS: readonly IntegrationClientId[] = diff --git a/src/integrations/state.ts b/src/integrations/state.ts index 008f46fbf1..bb0e5b3567 100644 --- a/src/integrations/state.ts +++ b/src/integrations/state.ts @@ -12,6 +12,7 @@ import { ClientPathError, EXPORT_CLIENTS, opencodeProxyBaseUrl, type ExportModel import type { OcxConfig } from "../types"; import { PARSE_FAILED, loadTarget, parseConfig, type IntegrationIO } from "./config-io"; import { SNAPSHOT_RETENTION } from "./journal"; +import { parseSegment, type PathSegment } from "./merge"; import { canonicalContribution, fingerprint, semanticContribution, type OwnershipRecord } from "./ownership"; import { protectedContributionFingerprint, @@ -52,11 +53,41 @@ export interface IntegrationStatus { retentionDegraded: boolean; } +function isPlainRecord(value: unknown): value is Record { + return typeof value === "object" && value !== null && !Array.isArray(value); +} + +function assertNever(segment: never): never { + throw new Error(`unknown path segment ${JSON.stringify(segment)}`); +} + +/** The element a selector names, or `undefined` when none matches. */ +function selectElement(items: readonly unknown[], segment: PathSegment & { kind: "select" }): unknown { + return items.find(item => isPlainRecord(item) && item[segment.field] === segment.value); +} + +/** + * Same segment grammar as `setPath`: a plain key reads through a record, a + * `[field=value]` selector reads through an array. Because the classifier and + * the writer share this one function, status and mutation cannot disagree + * about which element is ours. + */ export function readPath(doc: unknown, path: readonly string[]): unknown { let cursor: unknown = doc; - for (const key of path) { - if (typeof cursor !== "object" || cursor === null || Array.isArray(cursor)) return undefined; - cursor = (cursor as Record)[key]; + for (const raw of path) { + const segment = parseSegment(raw); + switch (segment.kind) { + case "key": + if (!isPlainRecord(cursor)) return undefined; + cursor = cursor[segment.key]; + break; + case "select": + if (!Array.isArray(cursor)) return undefined; + cursor = selectElement(cursor, segment); + break; + default: + return assertNever(segment); + } if (cursor === undefined) return undefined; } return cursor; @@ -82,10 +113,35 @@ export function blockedContainerPath( doc: unknown, contribution: ManagedContribution, ): readonly string[] | null { + /* + * What a segment needs the value it walks through to BE: a record for a key, + * an array for a selector. `typeof null === "object"`, so null is excluded + * by both checks rather than walking straight into the dereference below. + */ + const holds = (segment: PathSegment, value: unknown): boolean => { + switch (segment.kind) { + case "key": + return isPlainRecord(value); + case "select": + return Array.isArray(value); + default: + return assertNever(segment); + } + }; + const step = (segment: PathSegment, value: unknown): unknown => { + switch (segment.kind) { + case "key": + return (value as Record)[segment.key]; + case "select": + return selectElement(value as readonly unknown[], segment); + default: + return assertNever(segment); + } + }; for (const fragment of contribution.fragments) { let cursor: unknown = doc; for (let depth = 0; depth < fragment.path.length - 1; depth += 1) { - const key = fragment.path[depth]!; + const segment = parseSegment(fragment.path[depth]!); /* * ONLY `undefined` means absent. A missing file parses as `{}`, so an * absent prefix reads `undefined` — but a parsed `null` is a value the @@ -94,14 +150,10 @@ export function blockedContainerPath( * "successful" apply. */ if (cursor === undefined) break; - // `typeof null === "object"`, so null has to be named explicitly or it - // walks straight into the dereference below. - if (cursor === null || typeof cursor !== "object" || Array.isArray(cursor)) { - return fragment.path.slice(0, depth); - } - const next = (cursor as Record)[key]; + if (!holds(segment, cursor)) return fragment.path.slice(0, depth); + const next = step(segment, cursor); if (next === undefined) break; - if (typeof next !== "object" || next === null || Array.isArray(next)) { + if (!holds(parseSegment(fragment.path[depth + 1]!), next)) { return fragment.path.slice(0, depth + 1); } cursor = next; diff --git a/src/integrations/writer.ts b/src/integrations/writer.ts index 23b3eaaad4..7ec543715a 100644 --- a/src/integrations/writer.ts +++ b/src/integrations/writer.ts @@ -27,7 +27,7 @@ import { refreshablePathsOf, semanticProtectedContributionFingerprint, } from "./ownership-policy"; -import { createdContainerPaths, mergeContribution, removeFragments } from "./merge"; +import { AmbiguousSelectorError, createdContainerPaths, mergeContribution, removeFragments } from "./merge"; import { INTEGRATION_CLIENTS, isLoopbackOnly, resolveIntegrationPaths, type IntegrationClientId } from "./registry"; import { classifyIntegration, exportContextOf } from "./state"; import type { IntegrationState } from "./state"; @@ -352,36 +352,39 @@ function applyOrRefreshIntegration( * concludes the user owns it, and the replacement record forgets we made it * — so a later disable strands it forever. */ - const base = classified.state === "stale" && record - ? removeFragments(parsed, record.fragmentPaths, new Set(record.createdContainers ?? [])).doc - : classified.state === "conflict" && record - /* - * A forced overwrite of a `foreign-edit` conflict drops what the previous - * record owned for the same reason a stale refresh does: the replacement - * record covers the paths we are about to write, so a path the old record - * owned and the new one does not would be stranded forever, unremovable by - * any later disable. - * - * With NO record -- an `unowned-key` conflict -- there is nothing to drop and - * the merge runs against the user's document directly. That is correct: - * createdContainerPaths then attributes every container they already had to - * them, so a later disable removes our leaves and leaves their structure - * standing. - */ - ? removeFragments(parsed, record.fragmentPaths, new Set(record.createdContainers ?? [])).doc - : parsed; - // Computed against the document as it stands BEFORE the merge: afterwards - // every container exists and "did we create this?" is unanswerable. - const created = createdContainerPaths(base, contribution); /* * A document can hold a value its own format cannot round-trip through our * renderers. That used to throw straight out of the writer and reach the * user as a 500 with no path and no advice; it is a refusal like any other, - * and the file is untouched because this happens before any write. + * and the file is untouched because this happens before any write. The + * removal and merge sit inside the same guard: a sequence holding two + * entries our selector matches is equally unwritable, and equally untouched. */ - const nextDocument = mergeContribution(base, contribution); + let created: string[]; let text: string; try { + const base = classified.state === "stale" && record + ? removeFragments(parsed, record.fragmentPaths, new Set(record.createdContainers ?? [])).doc + : classified.state === "conflict" && record + /* + * A forced overwrite of a `foreign-edit` conflict drops what the previous + * record owned for the same reason a stale refresh does: the replacement + * record covers the paths we are about to write, so a path the old record + * owned and the new one does not would be stranded forever, unremovable by + * any later disable. + * + * With NO record -- an `unowned-key` conflict -- there is nothing to drop and + * the merge runs against the user's document directly. That is correct: + * createdContainerPaths then attributes every container they already had to + * them, so a later disable removes our leaves and leaves their structure + * standing. + */ + ? removeFragments(parsed, record.fragmentPaths, new Set(record.createdContainers ?? [])).doc + : parsed; + // Computed against the document as it stands BEFORE the merge: afterwards + // every container exists and "did we create this?" is unanswerable. + created = createdContainerPaths(base, contribution); + const nextDocument = mergeContribution(base, contribution); if (spec.sourcePreservingYaml && before !== null) { const value = sourcePreservingFragmentValue(contribution, spec.sourcePreservingYaml.path); const patched = value === undefined @@ -401,6 +404,10 @@ function applyOrRefreshIntegration( text = serializeDocument(nextDocument, exportSpec.format); } } catch (error) { + if (error instanceof AmbiguousSelectorError) { + return refuse(clientId, "unsafe", "unsafe", + `${configPath} holds more than one entry matching ours, so it was left alone`); + } if (!(error instanceof UnserializableValueError)) throw error; return refuse(clientId, "unsafe", "unsafe", `${configPath} contains something opencodex cannot rewrite safely (${error.message}), so it was left alone`); @@ -527,11 +534,15 @@ export function disableIntegration(input: IntegrationWriteInput): WriteOutcome { return refuse(clientId, "unsafe", "unsafe", `${configPath} uses YAML source opencodex cannot patch without risking unrelated comments or formatting, so nothing was removed`); } - const { doc, removed } = removeFragments( - parsed, - record!.fragmentPaths, - new Set(prunableCreated), - ); + let doc: unknown; + let removed: boolean; + try { + ({ doc, removed } = removeFragments(parsed, record!.fragmentPaths, new Set(prunableCreated))); + } catch (error) { + if (!(error instanceof AmbiguousSelectorError)) throw error; + return refuse(clientId, "unsafe", "unsafe", + `${configPath} holds more than one entry matching ours, so nothing was removed`); + } if (!removed) { return { ok: true, changed: false, state: "absent", clientId, message: "nothing to remove" }; } diff --git a/src/server/management/config-routes.ts b/src/server/management/config-routes.ts index ac6929c968..4d551a886d 100644 --- a/src/server/management/config-routes.ts +++ b/src/server/management/config-routes.ts @@ -161,7 +161,7 @@ interface ClientIntegrationSyncOutcome { } /** - * Re-inject native clients that are switched ON and file integrations whose + * Re-inject native clients that are switched ON and every file integration whose * OpenCodex ownership record is the operator's durable opt-in. * * Only Codex used to run here, so a catalog change reached Codex and nothing else: a Grok @@ -169,6 +169,10 @@ interface ClientIntegrationSyncOutcome { * next `ocx start`. The startup path already gates each client on its own toggle * (`src/cli/index.ts`), and this is that same fan-out for the on-demand command. * + * File integrations use the catalog-refresh coordinator so owned blocks are + * updated without claiming unowned files. Aside remains on its multi-profile + * server-owned path inside that coordinator. + * * A client that is OFF or never connected is omitted from the result rather than reported as skipped — the * caller has to be able to tell "not touched" from "tried and failed". A client that fails * does not fail the sync: Codex is the one that matters for routing, and a broken Grok file @@ -233,7 +237,7 @@ export async function syncEnabledClientIntegrations( }, config, port, - }, ["mcode", "pi", "aside"])); + }, ["mcode", "pi", "aside", "raycast"])); return out; } diff --git a/src/server/management/integration-routes.ts b/src/server/management/integration-routes.ts index b332718e07..43c0e6a98c 100644 --- a/src/server/management/integration-routes.ts +++ b/src/server/management/integration-routes.ts @@ -22,6 +22,7 @@ import { isIntegrationClientId, type IntegrationClientId, } from "../../integrations/registry"; +import { detectRaycast, type RaycastInstall } from "../../integrations/raycast-detect"; import { readIntegrationState } from "../../integrations/state"; import { createIntegrationStateStore, type IntegrationStateStore } from "../../integrations/store"; import { @@ -58,6 +59,13 @@ type RestoreResult = Awaited>; export type IntegrationStateEnvelope = { clientId: IntegrationClientId; + /** + * Raycast only, and only on the single-client read. Custom Providers is a + * Pro feature, so a file that is `current` can still be one Raycast ignores; + * this is the fact that lets status and the GUI say so. It is not part of + * the shared `IntegrationStatus`, which describes the file, not the app. + */ + raycast?: RaycastInstall; } & IntegrationStateRecord; export interface IntegrationStateListEnvelope { @@ -141,6 +149,17 @@ export function setIntegrationPathTestHooks(hooks: { env?: NodeJS.ProcessEnv; ho integrationPathTestHooks = hooks; } +/** + * Raycast detection override for tests. The real detector spawns `defaults` and + * reads the developer's own subscription state, which is exactly the kind of + * host fact a route test must not depend on. + */ +let raycastDetectTestHook: (() => RaycastInstall) | null = null; + +export function setRaycastDetectTestHook(hook: (() => RaycastInstall) | null): void { + raycastDetectTestHook = hook; +} + /** The `env`/`home` overrides, spread into every registry-resolving call. */ function pathOverrides(): { env?: NodeJS.ProcessEnv; home?: string } { return { @@ -177,7 +196,10 @@ export function setIntegrationMutationFlightTestHooks( setIntegrationMutationFlightTestHook(hooks?.run ?? null); // Path overrides are part of the same isolation contract: clearing flights // while leaving a temp home bound would let the next suite write real files. - if (hooks === null) integrationPathTestHooks = null; + if (hooks === null) { + integrationPathTestHooks = null; + raycastDetectTestHook = null; + } } /** @@ -633,7 +655,12 @@ export async function handleIntegrationRoutes(ctx: ManagementContext): Promise { + test("a selector splits into field and value; anything else is a key", () => { + expect(parseSegment("[id=opencodex]")).toEqual({ kind: "select", field: "id", value: "opencodex" }); + expect(parseSegment("[model_id=anthropic/claude-opus-5]")) + .toEqual({ kind: "select", field: "model_id", value: "anthropic/claude-opus-5" }); + expect(parseSegment("providers")).toEqual({ kind: "key", key: "providers" }); + // Near misses stay keys: a client whose map literally has such a key keeps working. + expect(parseSegment("[id=]")).toEqual({ kind: "key", key: "[id=]" }); + expect(parseSegment("[=x]")).toEqual({ kind: "key", key: "[=x]" }); + expect(parseSegment("[id=x")).toEqual({ kind: "key", key: "[id=x" }); + }); +}); + +describe("setPath with a selector", () => { + test("replaces the matching element in place and keeps siblings and order", () => { + const doc = { providers: [THEIRS, { id: "opencodex", name: "old" }, { id: "other" }], keep: true }; + const next = setPath(doc, SELECT, OURS) as typeof doc; + expect(next.providers).toEqual([THEIRS, OURS, { id: "other" }]); + expect(next.keep).toBe(true); + // The input is not mutated. + expect(doc.providers[1]).toEqual({ id: "opencodex", name: "old" }); + }); + + test("pushes when no element matches", () => { + const next = setPath({ providers: [THEIRS] }, SELECT, OURS) as { providers: unknown[] }; + expect(next.providers).toEqual([THEIRS, OURS]); + }); + + test("creates the array when absent, and createdContainerPaths reports it", () => { + expect(createdContainerPaths({}, contribution(SELECT))).toEqual(["providers"]); + expect(createdContainerPaths({ providers: {} }, contribution(SELECT))).toEqual(["providers"]); + expect(createdContainerPaths({ providers: [THEIRS] }, contribution(SELECT))).toEqual([]); + expect(setPath({}, SELECT, OURS)).toEqual({ providers: [OURS] }); + // A record where the array belongs is replaced, exactly as a scalar under a key is. + expect(setPath({ providers: {} }, SELECT, OURS)).toEqual({ providers: [OURS] }); + }); + + test("descends into a matched element, seeding one when absent", () => { + const path = ["providers", "[id=opencodex]", "name"]; + expect(setPath({ providers: [THEIRS] }, path, "X")) + .toEqual({ providers: [THEIRS, { id: "opencodex", name: "X" }] }); + expect(setPath({ providers: [OURS, THEIRS] }, path, "X")) + .toEqual({ providers: [{ id: "opencodex", name: "X" }, THEIRS] }); + // The element the selector would create is recorded, the existing array is not. + expect(createdContainerPaths({ providers: [THEIRS] }, contribution(path, "X"))) + .toEqual(["providers\u0000[id=opencodex]"]); + expect(createdContainerPaths({ providers: [OURS] }, contribution(path, "X"))).toEqual([]); + }); + + test("throws AmbiguousSelectorError when two elements match", () => { + const doc = { providers: [OURS, THEIRS, { id: "opencodex", name: "dupe" }] }; + expect(() => setPath(doc, SELECT, OURS)).toThrow(AmbiguousSelectorError); + expect(() => deletePath(doc, SELECT)).toThrow(AmbiguousSelectorError); + }); +}); + +describe("deletePath with a selector", () => { + test("removes only the matching element and leaves siblings", () => { + const { doc, removed } = deletePath({ providers: [THEIRS, OURS, { id: "other" }], keep: 1 }, SELECT); + expect(removed).toBe(true); + expect(doc).toEqual({ providers: [THEIRS, { id: "other" }], keep: 1 }); + }); + + test("reports nothing removed when no element matches or the slot is not an array", () => { + expect(deletePath({ providers: [THEIRS] }, SELECT)).toEqual({ doc: { providers: [THEIRS] }, removed: false }); + expect(deletePath({ providers: {} }, SELECT)).toEqual({ doc: { providers: {} }, removed: false }); + expect(deletePath({}, SELECT)).toEqual({ doc: {}, removed: false }); + }); + + test("prunes an emptied array we created and keeps one we did not", () => { + const created = new Set(["providers"]); + expect(deletePath({ providers: [OURS], keep: 1 }, SELECT, created).doc).toEqual({ keep: 1 }); + expect(deletePath({ providers: [OURS], keep: 1 }, SELECT).doc).toEqual({ providers: [], keep: 1 }); + // A sibling keeps the array alive even when we created it. + expect(deletePath({ providers: [OURS, THEIRS] }, SELECT, created).doc).toEqual({ providers: [THEIRS] }); + }); + + test("a leaf inside a selected element is removed without touching the element", () => { + const path = ["providers", "[id=opencodex]", "name"]; + const created = new Set(["providers", "providers\u0000[id=opencodex]"]); + // The seeded element keeps its selector field, so it is never empty and the prune walk + // stops at it. No client owns a leaf inside a selected element today; when one does, it + // decides whether a `{ id }` husk is residue worth a dedicated rule. + expect(deletePath({ providers: [{ id: "opencodex", name: "X" }] }, path, created).doc) + .toEqual({ providers: [{ id: "opencodex" }] }); + expect(deletePath({ providers: [{ id: "opencodex", name: "X", extra: 1 }] }, path, created).doc) + .toEqual({ providers: [{ id: "opencodex", extra: 1 }] }); + }); +}); + +describe("readPath and blockedContainerPath with a selector", () => { + test("readPath finds the element through a selector", () => { + const doc = { providers: [THEIRS, OURS] }; + expect(readPath(doc, SELECT)).toEqual(OURS); + expect(readPath(doc, ["providers", "[id=opencodex]", "name"])).toBe("OpenCodex"); + expect(readPath(doc, ["providers", "[id=missing]"])).toBeUndefined(); + expect(readPath({ providers: {} }, SELECT)).toBeUndefined(); + expect(readPath({ providers: "x" }, SELECT)).toBeUndefined(); + }); + + test("blockedContainerPath blocks a non-array where the selector expects one", () => { + expect(blockedContainerPath({ providers: {} }, contribution(SELECT))).toEqual(["providers"]); + expect(blockedContainerPath({ providers: "x" }, contribution(SELECT))).toEqual(["providers"]); + expect(blockedContainerPath({ providers: null }, contribution(SELECT))).toEqual(["providers"]); + expect(blockedContainerPath({ providers: [THEIRS] }, contribution(SELECT))).toBeNull(); + expect(blockedContainerPath({}, contribution(SELECT))).toBeNull(); + // Reading through a matched element continues the walk: a scalar element is blocked, + // a record one is fine, an absent one is simply not there yet. + const deep = ["providers", "[id=opencodex]", "name"]; + expect(blockedContainerPath({ providers: [OURS] }, contribution(deep, "X"))).toBeNull(); + expect(blockedContainerPath({ providers: [THEIRS] }, contribution(deep, "X"))).toBeNull(); + expect(blockedContainerPath({ providers: [{ id: "opencodex", name: 1 }] }, contribution(["providers", "[id=opencodex]", "name", "leaf"], "X"))) + .toEqual(["providers", "[id=opencodex]", "name"]); + }); +}); + +describe("plain-key paths are unchanged", () => { + test("setPath, deletePath, readPath, createdContainerPaths and blockedContainerPath behave as before", () => { + const path = ["providers", "opencodex", "api_key"]; + expect(setPath({}, path, "k")).toEqual({ providers: { opencodex: { api_key: "k" } } }); + expect(setPath({ providers: "x" }, path, "k")).toEqual({ providers: { opencodex: { api_key: "k" } } }); + expect(setPath({ providers: [1] }, path, "k")).toEqual({ providers: { opencodex: { api_key: "k" } } }); + expect(setPath({ providers: { other: 1 } }, path, "k")) + .toEqual({ providers: { other: 1, opencodex: { api_key: "k" } } }); + expect(createdContainerPaths({}, contribution(path, "k"))).toEqual(["providers", "providers\u0000opencodex"]); + expect(createdContainerPaths({ providers: { other: 1 } }, contribution(path, "k"))).toEqual(["providers\u0000opencodex"]); + + const created = new Set(["providers", "providers\u0000opencodex"]); + expect(deletePath({ providers: { opencodex: { api_key: "k" } } }, path, created)).toEqual({ doc: {}, removed: true }); + expect(deletePath({ providers: { opencodex: { api_key: "k" } } }, path)).toEqual({ doc: { providers: { opencodex: {} } }, removed: true }); + expect(deletePath({ providers: { opencodex: { api_key: "k", other: 1 } }, x: 1 }, path, created)) + .toEqual({ doc: { providers: { opencodex: { other: 1 } }, x: 1 }, removed: true }); + expect(deletePath({ providers: {} }, path)).toEqual({ doc: { providers: {} }, removed: false }); + expect(deletePath({ providers: [] }, path)).toEqual({ doc: { providers: [] }, removed: false }); + expect(deletePath({ providers: { opencodex: "x" } }, path)).toEqual({ doc: { providers: { opencodex: "x" } }, removed: false }); + expect(deletePath({ providers: { opencodex: { api_key: null } } }, path, created)).toEqual({ doc: {}, removed: true }); + + expect(readPath({ providers: { opencodex: { api_key: "k" } } }, path)).toBe("k"); + expect(readPath({ providers: [OURS] }, ["providers", "0"])).toBeUndefined(); + expect(readPath({ providers: null }, path)).toBeUndefined(); + + expect(blockedContainerPath({ providers: ["x"] }, contribution(path, "k"))).toEqual(["providers"]); + expect(blockedContainerPath({ providers: { opencodex: null } }, contribution(path, "k"))).toEqual(["providers", "opencodex"]); + expect(blockedContainerPath(null, contribution(path, "k"))).toEqual([]); + expect(blockedContainerPath({ providers: { opencodex: {} } }, contribution(path, "k"))).toBeNull(); + expect(blockedContainerPath(undefined, contribution(path, "k"))).toBeNull(); + }); +}); + +/** + * End to end through the real writer: Raycast is the first client whose + * fragment path carries a selector, so this is where status and mutation are + * shown agreeing on which sequence element is ours. + */ +describe("raycast writer round trip", () => { + const TEST_ENV = {} as NodeJS.ProcessEnv; + const MODELS: ExportModel[] = [ + { namespaced: "anthropic/claude-opus-4-8", provider: "anthropic", id: "claude-opus-4-8", contextWindow: 200_000 }, + ]; + const CONFIG: OcxConfig = { + port: 10100, + hostname: "127.0.0.1", + defaultProvider: "mock", + providers: { mock: { adapter: "openai-chat", baseUrl: "http://127.0.0.1/v1" } }, + } as unknown as OcxConfig; + let home: string; + let store: IntegrationStateStore; + + beforeEach(() => { + const base = mkdtempSync(join(tmpdir(), "ocx-integrations-merge-")); + home = join(base, "home"); + mkdirSync(home, { recursive: true }); + store = createIntegrationStateStore(join(base, "store", "integrations")); + }); + + afterEach(() => { + removeTreeWithRetry(dirname(home)); + }); + + function installRaycast(): string { + const spec = INTEGRATION_CLIENTS.raycast; + mkdirSync(spec.detectDir(TEST_ENV, home), { recursive: true }); + const configPath = spec.configPath(TEST_ENV, home); + mkdirSync(dirname(configPath), { recursive: true }); + return configPath; + } + + function input(): IntegrationWriteInput { + return { clientId: "raycast", models: MODELS, config: CONFIG, port: 10100, env: TEST_ENV, home, store }; + } + + test("apply appends beside the user's provider, disable removes only ours", () => { + const configPath = installRaycast(); + writeFileSync(configPath, Bun.YAML.stringify({ providers: [THEIRS] })); + + expect(readIntegrationState(input())).toMatchObject({ state: "absent" }); + expect(applyIntegration(input())).toMatchObject({ ok: true, changed: true }); + const applied = Bun.YAML.parse(readFileSync(configPath, "utf8")) as { providers: Array<{ id: string }> }; + expect(applied.providers.map(item => item.id)).toEqual(["lmstudio", "opencodex"]); + expect(readIntegrationState(input())).toMatchObject({ state: "current" }); + + expect(disableIntegration(input())).toMatchObject({ ok: true, changed: true }); + // The user's array was there before us, so it survives with their entry intact. + expect(Bun.YAML.parse(readFileSync(configPath, "utf8"))).toEqual({ providers: [THEIRS] }); + expect(readIntegrationState(input())).toMatchObject({ state: "absent" }); + }); + + test("a providers map instead of a sequence is unsafe for status and writer alike", () => { + const configPath = installRaycast(); + writeFileSync(configPath, Bun.YAML.stringify({ providers: { opencodex: {} } })); + expect(readIntegrationState(input())).toMatchObject({ state: "unsafe", reason: "blocked-container" }); + expect(applyIntegration(input())).toMatchObject({ ok: false, reason: "unsafe" }); + expect(Bun.YAML.parse(readFileSync(configPath, "utf8"))).toEqual({ providers: { opencodex: {} } }); + }); + + test("two entries with our id refuse as unsafe and leave the file alone", () => { + const configPath = installRaycast(); + const text = Bun.YAML.stringify({ providers: [{ id: "opencodex", name: "a" }, { id: "opencodex", name: "b" }] }); + writeFileSync(configPath, text); + // Neither entry is ours on record, so status reads conflict and a plain apply refuses + // there. The explicit overwrite reaches the merge, which is where the ambiguity is + // detected: it must surface as an `unsafe` refusal, never as a thrown error. + expect(readIntegrationState(input())).toMatchObject({ state: "conflict" }); + expect(applyIntegration(input())).toMatchObject({ ok: false, reason: "conflict" }); + const result = overwriteIntegration(input()); + expect(result).toMatchObject({ ok: false, reason: "unsafe", state: "unsafe" }); + if (!result.ok) expect(result.message).toContain("more than one entry"); + expect(readFileSync(configPath, "utf8")).toBe(text); + expect(store.listOperations("raycast")).toHaveLength(0); + }); +}); diff --git a/tests/clients/integrations-state.test.ts b/tests/clients/integrations-state.test.ts index 872e9b3824..56093b3dd6 100644 --- a/tests/clients/integrations-state.test.ts +++ b/tests/clients/integrations-state.test.ts @@ -775,9 +775,9 @@ describe("installation detection is independent of config state", () => { * from. Rationale and the per-client table: 020 §1 amendment. */ describe("the loopback-only set is one fact, read through one seam", () => { - test("omp, pi, kimi, gajae, dsh, mcode, zcode, prime and aside are loopback-only and nobody else is", () => { + test("omp, pi, kimi, gajae, dsh, mcode, zcode, prime, aside and raycast are loopback-only and nobody else is", () => { const loopbackOnly = INTEGRATION_CLIENT_IDS.filter(id => isLoopbackOnly(id)); - expect(loopbackOnly).toEqual(["pi", "omp", "kimi", "gajae", "dsh", "mcode", "zcode", "prime", "aside"]); + expect(loopbackOnly).toEqual(["pi", "omp", "kimi", "gajae", "dsh", "mcode", "zcode", "prime", "aside", "raycast"]); }); test("the registry restates nothing — it reads the export spec", () => { diff --git a/tests/clients/raycast-client.test.ts b/tests/clients/raycast-client.test.ts new file mode 100644 index 0000000000..148f84babb --- /dev/null +++ b/tests/clients/raycast-client.test.ts @@ -0,0 +1,271 @@ +import { afterEach, beforeEach, describe, expect, test } from "bun:test"; +import { mkdirSync, mkdtempSync, readFileSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { + EXPORT_CLIENTS, + OPENCODE_PROVIDER_ID, + buildClientConfig, + buildClientConfigText, + buildClientContribution, + raycastAiDir, + raycastConfigPath, + type ExportContext, + type ExportModel, + type RaycastGeneratedConfig, +} from "../../src/clients/config-export"; +import { exportPresentationLabel } from "../../src/clients/model-presentation"; +import { refreshOwnedCatalogIntegrations } from "../../src/integrations/catalog-refresh"; +import { INTEGRATION_CLIENTS } from "../../src/integrations/registry"; +import { createIntegrationStateStore, type IntegrationStateStore } from "../../src/integrations/store"; +import { applyIntegration, disableIntegration, refreshIntegration } from "../../src/integrations/writer"; +import type { OcxConfig } from "../../src/types"; +import { removeTreeWithRetry } from "../helpers/remove-tree"; + +const CONFIG = { + port: 10100, + hostname: "127.0.0.1", + defaultProvider: "mock", + providers: { mock: { adapter: "openai-chat", baseUrl: "http://127.0.0.1/v1" } }, +} as OcxConfig; + +// One model per cell of the vision x reasoning matrix, so every ability +// branch is exercised by a row that differs from its neighbours in one axis. +const MODELS: ExportModel[] = [ + { namespaced: "anthropic/claude-opus-5", provider: "anthropic", id: "claude-opus-5", contextWindow: 200_000, inputModalities: ["text", "image"] }, + { namespaced: "openai/gpt-5.6-sol", provider: "openai", id: "gpt-5.6-sol", contextWindow: 922_000, reasoningEfforts: ["low", "medium", "high"] }, + { namespaced: "mystery/model", provider: "mystery", id: "model" }, + { namespaced: "google/gemini-3-pro", provider: "google", id: "gemini-3-pro", contextWindow: 1_048_576, inputModalities: ["text", "image"], reasoningEfforts: ["low", "high"] }, +]; + +function context(models: readonly ExportModel[] = MODELS): ExportContext { + return { baseUrl: "http://127.0.0.1:10100/v1", config: CONFIG, models }; +} + +// A provider the user wrote by hand: the merge must carry it through every +// apply, refresh and disable untouched. +const LMSTUDIO = { id: "lmstudio", name: "LM Studio", base_url: "http://localhost:1234/v1", models: [] }; +const USER_SEED = [ + "providers:", + " - id: lmstudio", + " name: LM Studio", + " base_url: http://localhost:1234/v1", + " models: []", + "", +].join(String.fromCharCode(10)); + +function ourProvider(document: RaycastGeneratedConfig) { + return document.providers.find(provider => provider.id === OPENCODE_PROVIDER_ID)!; +} + +function abilitiesOf(document: RaycastGeneratedConfig, id: string): Record { + const model = ourProvider(document).models.find(entry => entry.id === id)!; + return Object.fromEntries(Object.entries(model.abilities).map(([name, ability]) => [name, ability.supported])); +} + +let home: string; +let store: IntegrationStateStore; + +beforeEach(() => { + home = mkdtempSync(join(tmpdir(), "ocx-raycast-")); + store = createIntegrationStateStore(mkdtempSync(join(tmpdir(), "ocx-raycast-store-"))); +}); + +afterEach(() => { + removeTreeWithRetry(home); +}); + +/** Raycast "installed" for our purposes: the `ai` directory exists. */ +function installRaycast(seed?: string): string { + const spec = INTEGRATION_CLIENTS.raycast; + mkdirSync(spec.detectDir({}, home), { recursive: true }); + const configPath = spec.configPath({}, home); + if (seed !== undefined) writeFileSync(configPath, seed); + return configPath; +} + +function readProviders(configPath: string): RaycastGeneratedConfig { + return Bun.YAML.parse(readFileSync(configPath, "utf8")) as RaycastGeneratedConfig; +} + +function request(models: readonly ExportModel[] = MODELS) { + return { clientId: "raycast" as const, models, config: CONFIG, port: 10100, env: {}, home, store }; +} + +describe("Raycast client config", () => { + /* + * The shape is Raycast's, not ours: `providers` is a SEQUENCE, `base_url` + * ends in `/v1` without `/chat/completions`, and there is no `api_keys` at + * all because a loopback bind is unauthenticated. Every model carries all + * five abilities so Raycast never has to guess at a missing one. + */ + test("emits one provider element with the documented field vocabulary", () => { + const document = buildClientConfig("raycast", context()) as RaycastGeneratedConfig; + expect(Object.keys(document)).toEqual(["providers"]); + expect(document.providers.map(provider => provider.id)).toEqual([OPENCODE_PROVIDER_ID]); + + const provider = ourProvider(document); + expect(Object.keys(provider)).toEqual(["id", "name", "base_url", "models"]); + expect(provider.name).toBe("OpenCodex"); + expect(provider.base_url).toBe("http://127.0.0.1:10100/v1"); + expect(Object.keys(provider)).not.toContain("api_keys"); + + for (const model of provider.models) { + expect(Object.keys(model.abilities)).toEqual(["temperature", "vision", "system_message", "tools", "reasoning_effort"]); + } + const claude = provider.models.find(model => model.id === "anthropic/claude-opus-5")!; + // Raycast shows `name` verbatim with no provider suffix; capability tables + // supply the product label when ExportModel has no operator override. + expect(claude.name).toBe("Claude Opus 5"); + expect(claude.context).toBe(200_000); + // No authoritative window means the key is absent, not zero or null. + const unknown = provider.models.find(model => model.id === "mystery/model")!; + expect("context" in unknown).toBe(false); + }); + + test("uses product labels instead of raw slugs or provider suffixes", () => { + expect(exportPresentationLabel({ + namespaced: "anthropic/claude-fable-5-1", provider: "anthropic", id: "claude-fable-5-1", + })).toBe("Claude Fable 5.1"); + expect(exportPresentationLabel({ + namespaced: "cursor/composer-2.5", provider: "cursor", id: "composer-2.5", + })).toBe("Composer 2.5"); + expect(exportPresentationLabel({ + namespaced: "mystery/model", provider: "mystery", id: "model", displayName: "Custom Name", + })).toBe("Custom Name"); + }); + + /* + * Abilities follow the catalog row, not the vendor name. Temperature and + * reasoning_effort are the same bit inverted: Raycast's own template notes + * that reasoning models commonly reject temperature. system_message and + * tools are always on, the same stance as Hermes. + */ + test("maps vision and reasoning ladders onto abilities per model", () => { + const document = buildClientConfig("raycast", context()) as RaycastGeneratedConfig; + expect(abilitiesOf(document, "anthropic/claude-opus-5")).toEqual({ + temperature: true, vision: true, system_message: true, tools: true, reasoning_effort: false, + }); + expect(abilitiesOf(document, "openai/gpt-5.6-sol")).toEqual({ + temperature: false, vision: false, system_message: true, tools: true, reasoning_effort: true, + }); + expect(abilitiesOf(document, "mystery/model")).toEqual({ + temperature: true, vision: false, system_message: true, tools: true, reasoning_effort: false, + }); + expect(abilitiesOf(document, "google/gemini-3-pro")).toEqual({ + temperature: false, vision: true, system_message: true, tools: true, reasoning_effort: true, + }); + }); + + test("native YAML round-trips, leads with our element, and never carries a credential", () => { + const sentinel = ["sk", "live", "raycast", "sentinel"].join("-"); + const withKey = { ...CONFIG, apiKeys: [{ key: sentinel }] } as OcxConfig; + const built = buildClientConfigText("raycast", { ...context(), config: withKey }); + expect(built.format).toBe("yaml"); + expect(built.text.startsWith(["providers:", " - id: opencodex"].join(String.fromCharCode(10)))).toBe(true); + expect(Bun.YAML.parse(built.text)).toEqual(built.document as never); + expect(built.text).not.toContain(sentinel); + expect(built.text).not.toContain("api_keys"); + }); + + test("the contribution owns the providers element selected by our id", () => { + const contribution = buildClientContribution("raycast", context()); + expect(contribution.clientId).toBe("raycast"); + expect(contribution.fragments.map(fragment => fragment.path)).toEqual([["providers", `[id=${OPENCODE_PROVIDER_ID}]`]]); + expect((contribution.fragments[0]!.value as { id: string }).id).toBe(OPENCODE_PROVIDER_ID); + }); + + test("resolves under the home directory and ignores XDG_CONFIG_HOME", () => { + // Raycast hardcodes ~/.config/raycast on macOS and Windows alike; honoring + // XDG here would name a file Raycast never reads. + const env = { XDG_CONFIG_HOME: join(home, "elsewhere") }; + expect(raycastAiDir(env, home)).toBe(join(home, ".config", "raycast", "ai")); + expect(raycastConfigPath(env, home)).toBe(join(home, ".config", "raycast", "ai", "providers.yaml")); + expect(INTEGRATION_CLIENTS.raycast.configPath(env, home)).toBe(raycastConfigPath(env, home)); + expect(INTEGRATION_CLIENTS.raycast.detectDir(env, home)).toBe(raycastAiDir(env, home)); + }); + + test("ships as a loopback-only integration with no env var to export", () => { + const spec = EXPORT_CLIENTS.raycast; + // `api_keys` is read literally, so a remote bind would need a plaintext + // secret on disk; the spec refuses instead. + expect(spec.loopbackOnly).toBe(true); + expect(spec.apiKeyEnv).toBe(""); + expect(spec.format).toBe("yaml"); + // Not a bare providers.yaml: a download would collide with other clients'. + expect(spec.filename).toBe("raycast-providers.yaml"); + }); + + /* + * The whole point of the `[id=opencodex]` selector: the user's own element + * survives every operation, we replace only ours, and a disable leaves the + * sequence exactly as the user wrote it. + */ + test("apply, refresh and disable touch only our element of the sequence", () => { + const configPath = installRaycast(USER_SEED); + + const applied = applyIntegration(request()); + expect(applied.ok).toBe(true); + const afterApply = readProviders(configPath); + expect(new Set(afterApply.providers.map(provider => provider.id))).toEqual(new Set(["lmstudio", OPENCODE_PROVIDER_ID])); + expect(afterApply.providers.find(provider => provider.id === "lmstudio")).toEqual(LMSTUDIO); + expect(ourProvider(afterApply).models.map(model => model.id)).toEqual(MODELS.map(model => model.namespaced).sort()); + + // A smaller catalog rewrites our element in place and nothing else. + const fewer = MODELS.filter(model => model.namespaced !== "mystery/model"); + const refreshed = refreshIntegration(request(fewer)); + expect(refreshed.ok).toBe(true); + const afterRefresh = readProviders(configPath); + expect(afterRefresh.providers.map(provider => provider.id)).toEqual(afterApply.providers.map(provider => provider.id)); + expect(afterRefresh.providers.find(provider => provider.id === "lmstudio")).toEqual(LMSTUDIO); + expect(ourProvider(afterRefresh).models.map(model => model.id)).toEqual(fewer.map(model => model.namespaced).sort()); + + const disabled = disableIntegration(request(fewer)); + expect(disabled.ok).toBe(true); + const afterDisable = readProviders(configPath); + expect(afterDisable.providers).toEqual([LMSTUDIO]); + }); + + test("the default catalog refresh updates an owned Raycast provider", async () => { + const configPath = installRaycast(USER_SEED); + expect(applyIntegration(request()).ok).toBe(true); + const fewer = MODELS.filter(model => model.namespaced !== "mystery/model"); + let loads = 0; + + const outcomes = await refreshOwnedCatalogIntegrations({ + models: async () => { + loads += 1; + return fewer; + }, + config: CONFIG, + port: 10100, + env: {}, + home, + store, + }); + + expect(outcomes).toEqual([{ client: "raycast", ok: true, changed: true }]); + expect(loads).toBe(1); + expect(readProviders(configPath).providers.find(provider => provider.id === "lmstudio")).toEqual(LMSTUDIO); + expect(ourProvider(readProviders(configPath)).models.map(model => model.id)) + .toEqual(fewer.map(model => model.namespaced).sort()); + }); + + test("refuses a file whose providers is a map rather than a sequence", () => { + // `providers: {}` is a container we would have to REPLACE with `[]` to + // write our element, and replacing a user's container is never a success. + const configPath = installRaycast("providers: {}" + String.fromCharCode(10)); + const result = applyIntegration(request()); + expect(result.ok).toBe(false); + if (!result.ok) expect(result.reason).toBe("unsafe"); + expect(readFileSync(configPath, "utf8")).toBe("providers: {}" + String.fromCharCode(10)); + }); + + test("refuses when the ai directory does not exist yet", () => { + // The directory appears only after "Reveal Providers Config" in Raycast's + // AI settings, which is the signal that Custom Providers is reachable. + const result = applyIntegration(request()); + expect(result.ok).toBe(false); + if (!result.ok) expect(result.reason).toBe("not_installed"); + }); +}); diff --git a/tests/clients/raycast-detect.test.ts b/tests/clients/raycast-detect.test.ts new file mode 100644 index 0000000000..4e4268b29b --- /dev/null +++ b/tests/clients/raycast-detect.test.ts @@ -0,0 +1,82 @@ +import { describe, expect, test } from "bun:test"; +import { detectRaycast, type RaycastDetectDeps } from "../../src/integrations/raycast-detect"; + +/** + * Stubbed deps only. The real detector spawns `defaults` and reads the + * developer's subscription state, and this suite must pass identically on a + * machine with Raycast Pro, with the free tier, and with no Raycast at all. + */ +function fakeDeps( + platform: string, + existing: readonly string[], + options: { env?: Record; defaultValue?: string | null; homedir?: string } = {}, +): RaycastDetectDeps & { defaultsReads: number } { + const present = new Set(existing); + const deps = { + platform, + homedir: options.homedir ?? (platform === "win32" ? "C:\\Users\\u" : "/home/u"), + env: options.env ?? {}, + defaultsReads: 0, + exists: (path: string) => present.has(path), + readDefault: (domain: string, key: string) => { + deps.defaultsReads += 1; + expect(domain).toBe("com.raycast.macos.v1"); + expect(key).toBe("subscriptions_active"); + return options.defaultValue ?? null; + }, + }; + return deps; +} + +describe("detectRaycast", () => { + test("darwin: a Pro subscription, the app bundle and the revealed ai folder", () => { + const deps = fakeDeps("darwin", ["/Applications/Raycast.app", "/home/u/.config/raycast/ai"], { defaultValue: "1" }); + expect(detectRaycast(deps)).toEqual({ + appPath: "/Applications/Raycast.app", + aiDirPresent: true, + plan: "pro", + }); + // One process spawn per detection, not one per field. + expect(deps.defaultsReads).toBe(1); + }); + + test("darwin: the free tier is reported, not refused, and the user-local bundle is found", () => { + const deps = fakeDeps("darwin", ["/home/u/Applications/Raycast.app"], { defaultValue: "0" }); + expect(detectRaycast(deps)).toEqual({ + appPath: "/home/u/Applications/Raycast.app", + aiDirPresent: false, + plan: "free", + }); + }); + + test("darwin: a failed or unexpected defaults read is unknown, never free", () => { + expect(detectRaycast(fakeDeps("darwin", [], { defaultValue: null })).plan).toBe("unknown"); + expect(detectRaycast(fakeDeps("darwin", [], { defaultValue: "(null)" })).plan).toBe("unknown"); + expect(detectRaycast(fakeDeps("darwin", [], { defaultValue: "" })).plan).toBe("unknown"); + }); + + test("win32: LOCALAPPDATA\\Programs\\Raycast is the install path and the plan is unknown", () => { + const local = "C:\\Users\\u\\AppData\\Local"; + const deps = fakeDeps("win32", [`${local}\\Programs\\Raycast`, "C:\\Users\\u\\.config\\raycast\\ai"], { + env: { LOCALAPPDATA: local }, + defaultValue: "1", + }); + expect(detectRaycast(deps)).toEqual({ + appPath: `${local}\\Programs\\Raycast`, + aiDirPresent: true, + plan: "unknown", + }); + // `defaults` does not exist off macOS, so it is never asked. + expect(deps.defaultsReads).toBe(0); + }); + + test("win32: no LOCALAPPDATA means no app path rather than a guessed one", () => { + expect(detectRaycast(fakeDeps("win32", [])).appPath).toBeNull(); + }); + + test("linux: nothing is detected and nothing is spawned", () => { + const deps = fakeDeps("linux", [], { defaultValue: "1" }); + expect(detectRaycast(deps)).toEqual({ appPath: null, aiDirPresent: false, plan: "unknown" }); + expect(deps.defaultsReads).toBe(0); + }); +}); diff --git a/tests/clients/sync-client-integrations.test.ts b/tests/clients/sync-client-integrations.test.ts index 5661373642..9050eecd3b 100644 --- a/tests/clients/sync-client-integrations.test.ts +++ b/tests/clients/sync-client-integrations.test.ts @@ -65,7 +65,7 @@ describe("ocx sync fans out to enabled native clients and owned file integration expect(fn).toContain("grokIntegrationEnabled(config)"); expect(fn).toContain("claudeDesktopIntegrationEnabled(config)"); - expect(fn).toContain('["mcode", "pi", "aside"]'); + expect(fn).toContain('["mcode", "pi", "aside", "raycast"]'); expect(fn).toContain("refreshOwnedCatalogIntegrations"); // Native clients keep their catches; the owned catalog helper isolates file clients. expect(fn.match(/catch \(error\)/g)?.length).toBe(2); @@ -651,17 +651,29 @@ describe("owned Pi/Aside catalogs follow filtered model selections", () => { }); }); -test("the direct ocx sync command refreshes MCode, Pi and Aside instead of relying on /api/sync", async () => { +test("the direct ocx sync command refreshes MCode, Pi, Raycast and server-owned Aside", async () => { const src = await Bun.file(new URL("../../src/cli/dispatch.ts", import.meta.url)).text(); const start = src.indexOf("sync: async deps =>"); const command = src.slice(start, src.indexOf("v2: async deps =>", start)); expect(command).toContain("refreshOwnedCatalogIntegrations"); - expect(command).toContain('["mcode", "pi"]'); + expect(command).toContain('["mcode", "pi", "raycast"]'); expect(command).toContain("refreshAsideProfilesThroughServer"); expect(command.indexOf("syncModelsToCodex")).toBeLessThan(command.indexOf("refreshOwnedCatalogIntegrations")); expect(command).toContain('synced.status !== "refused"'); }); +test("startup and ensure refresh owned Raycast through the catalog coordinator", async () => { + const src = await Bun.file(new URL("../../src/cli/index.ts", import.meta.url)).text(); + const start = src.slice(src.indexOf("async function handleStart"), src.indexOf("function detachedStartEnvironment")); + const ensure = src.slice(src.indexOf("async function handleEnsure"), src.indexOf("async function handleTrayProxyStart")); + expect(src).toContain("refreshOwnedCatalogIntegrations"); + expect(src).toContain('}, ["raycast"]);'); + expect(start).toContain("await refreshOwnedRaycastCatalog(config, port)"); + expect(ensure).toContain("await refreshOwnedRaycastCatalog(config, live.port)"); + expect(ensure).toContain("await refreshOwnedRaycastCatalog(config, port)"); + expect(src).not.toContain("refreshAllOwnedIntegrations"); +}); + test("identical explicit mutation keys join but cannot swallow a different apply or disable", async () => { let release!: () => void; const gate = new Promise(resolve => { release = resolve; }); diff --git a/tests/config/client-config-export-new-clients.test.ts b/tests/config/client-config-export-new-clients.test.ts index 6b6b4c4e80..5a381d6237 100644 --- a/tests/config/client-config-export-new-clients.test.ts +++ b/tests/config/client-config-export-new-clients.test.ts @@ -58,12 +58,14 @@ function ctx(config: OcxConfig = LOOPBACK): ExportContext { describe("no secret reaches a client config", () => { test("the generated client support policy identifies every loopback-only integration", () => { - // Pi, Kimi, Gajae and Aside cannot emit the dedicated admission header -- - // Aside's observed provider block has four keys and none is `headers`. OMP - // and Prime can carry provider headers, but remote credential wiring is - // deliberately deferred from those initial generated integrations. + // Pi, Kimi, Gajae, Aside and Raycast cannot emit the dedicated admission + // header -- Aside's observed provider block has four keys and none is + // `headers`; Raycast's `api_keys` is read literally with no env + // interpolation. OMP and Prime can carry provider headers, but remote + // credential wiring is deliberately deferred from those initial generated + // integrations. const loopbackOnly = EXPORT_CLIENT_IDS.filter(id => EXPORT_CLIENTS[id].loopbackOnly); - expect(loopbackOnly).toEqual(["pi", "omp", "kimi", "gajae", "dsh", "mcode", "zcode", "prime", "aside"]); + expect(loopbackOnly).toEqual(["pi", "omp", "kimi", "gajae", "dsh", "mcode", "zcode", "prime", "aside", "raycast"]); }); test("every client that is not loopback-only carries the header on a remote bind", () => { diff --git a/tests/config/client-config-export.test.ts b/tests/config/client-config-export.test.ts index 707d6dd62c..6a71813e9f 100644 --- a/tests/config/client-config-export.test.ts +++ b/tests/config/client-config-export.test.ts @@ -32,6 +32,7 @@ import { normalizeExportModels as leafNormalizeExportModels } from "../../src/cl import * as omp from "../../src/clients/config-export/omp"; import * as dsh from "../../src/clients/config-export/dsh"; import * as mcode from "../../src/clients/config-export/mcode"; +import * as raycast from "../../src/clients/config-export/raycast"; import * as zcode from "../../src/clients/config-export/zcode"; /** @@ -100,6 +101,7 @@ describe("split config-export public facade", () => { ["dsh", dsh.buildDshClientConfig, dsh.summarizeDsh, dsh.buildDshContribution], ["mcode", mcode.buildMcodeClientConfig, mcode.summarizeMcode, mcode.buildMcodeContribution], ["zcode", zcode.buildZcodeClientConfig, zcode.summarizeZcode, zcode.buildZcodeContribution], + ["raycast", raycast.buildRaycastClientConfig, raycast.summarizeRaycast, raycast.buildRaycastContribution], ] as const; for (const [id, build, summarize, contribute] of leaves) { expect(EXPORT_CLIENTS[id].build).toBe(build); @@ -803,8 +805,8 @@ describe("hub-resolved Fast exports", () => { }); describe("EXPORT_CLIENTS registry", () => { - test("covers exactly the twelve file-toggle clients", () => { - expect(EXPORT_CLIENT_IDS).toEqual(["opencode", "pi", "omp", "hermes", "openclaw", "kimi", "gajae", "dsh", "mcode", "zcode", "prime", "aside"]); + test("covers exactly the thirteen file-toggle clients", () => { + expect(EXPORT_CLIENT_IDS).toEqual(["opencode", "pi", "omp", "hermes", "openclaw", "kimi", "gajae", "dsh", "mcode", "zcode", "prime", "aside", "raycast"]); for (const id of EXPORT_CLIENT_IDS) expect(isExportClientId(id)).toBe(true); // The exception clients keep their own surfaces and are not export clients. expect(isExportClientId("claude-desktop")).toBe(false); diff --git a/tests/config/client-config-new-clients.test.ts b/tests/config/client-config-new-clients.test.ts index 65b52727c9..7deb7fdb36 100644 --- a/tests/config/client-config-new-clients.test.ts +++ b/tests/config/client-config-new-clients.test.ts @@ -17,6 +17,7 @@ import { type OpenclawGeneratedConfig, } from "../../src/clients/config-export"; import { serializeDocument } from "../../src/integrations/serialize"; +import { readPath } from "../../src/integrations/state"; import type { OcxConfig } from "../../src/types"; /** @@ -159,14 +160,11 @@ describe("contributions describe what a writer would own", () => { test("every client's fragments point at real entries in its own document", () => { for (const clientId of EXPORT_CLIENT_IDS) { - const document = buildClientConfig(clientId, ctx()) as Record; + const document = buildClientConfig(clientId, ctx()); for (const fragment of EXPORT_CLIENTS[clientId].buildContribution(ctx()).fragments) { - let cursor: unknown = document; - for (const key of fragment.path) { - expect(cursor && typeof cursor === "object").toBe(true); - cursor = (cursor as Record)[key]; - } - expect(cursor).toEqual(fragment.value); + // Read through the writer's own segment grammar: Raycast's path holds + // a `[id=opencodex]` selector into a sequence, not a map key. + expect(readPath(document, fragment.path)).toEqual(fragment.value); } } }); diff --git a/tests/fixtures/test-layout-expected.json b/tests/fixtures/test-layout-expected.json index 6565f12821..a00407e89a 100644 --- a/tests/fixtures/test-layout-expected.json +++ b/tests/fixtures/test-layout-expected.json @@ -525,6 +525,7 @@ "install-scripts.test.ts": "ci-workflows", "integrations-invariants.test.ts": "gui", "integrations-journal.test.ts": "clients", + "integrations-merge.test.ts": "clients", "integrations-serialize.test.ts": "clients", "integrations-state.test.ts": "clients", "integrations-writer.test.ts": "clients", @@ -833,6 +834,8 @@ "reserve-quota-scope.test.ts": "codex-integration", "rate-limit-reset-credits.test.ts": "gui", "rate-limit-retry.test.ts": "providers", + "raycast-client.test.ts": "clients", + "raycast-detect.test.ts": "clients", "reasoning-effort.test.ts": "codex-integration", "reasoning-replay-identity.test.ts": "adapters", "reasoning-replay-robustness.test.ts": "adapters", diff --git a/tests/gui/integrations-invariants.test.ts b/tests/gui/integrations-invariants.test.ts index 33e7480f86..2353104311 100644 --- a/tests/gui/integrations-invariants.test.ts +++ b/tests/gui/integrations-invariants.test.ts @@ -6,7 +6,7 @@ import { EXPORT_CLIENTS, EXPORT_CLIENT_IDS, type ExportModel } from "../../src/c import { parseConfig } from "../../src/integrations/config-io"; import { INTEGRATION_CLIENTS, INTEGRATION_CLIENT_IDS, type IntegrationClientId } from "../../src/integrations/registry"; import { createIntegrationStateStore, type IntegrationStateStore } from "../../src/integrations/store"; -import { readIntegrationState } from "../../src/integrations/state"; +import { readIntegrationState, readPath } from "../../src/integrations/state"; import { applyIntegration, disableIntegration, restoreIntegration } from "../../src/integrations/writer"; import { printSubcommandUsage, printUsage } from "../../src/cli/help"; import type { OcxConfig } from "../../src/types"; @@ -78,9 +78,9 @@ afterEach(() => { }); describe("the client registries cannot drift apart", () => { - test("every list of clients holds exactly the same twelve ids", async () => { + test("every list of clients holds exactly the same thirteen ids", async () => { /* - * Five lists name the same twelve clients, and two of them are maintained by + * Five lists name the same thirteen clients, and two of them are maintained by * hand: the GUI cannot import the backend registry, because that would * pull node:os and node:path into the browser bundle. A client added * server-side renders no row until someone remembers the tuple, and the @@ -91,7 +91,7 @@ describe("the client registries cannot drift apart", () => { const guiRouting = await import("../../gui/src/app-routing"); const expected = [...EXPORT_CLIENT_IDS].sort(); - expect(expected).toHaveLength(12); + expect(expected).toHaveLength(13); expect([...INTEGRATION_CLIENT_IDS].sort()).toEqual(expected); expect([...gui.CLIENTS].sort()).toEqual(expected); @@ -170,6 +170,13 @@ describe("every client survives a full lifecycle", () => { prime: '{\n "providers": {\n "mine": { "api": "http://keep-me" }\n }\n}\n', // Aside reads the same models.json contract as Pi and Prime. aside: '{\n "providers": {\n "mine": { "api": "http://keep-me" }\n }\n}\n', + // Raycast's `providers` is a SEQUENCE keyed by `id`, so the user's entry is + // a sibling element rather than a sibling map key. + raycast: "providers:\n - id: lmstudio\n name: LM Studio\n base_url: http://localhost:1234/v1\n models: []\n", + }; + /** Where the seed's user-owned entry lives when the seed is a sequence. */ + const USER_ELEMENT: Partial> = { + raycast: ["providers", "[id=lmstudio]"], }; for (const clientId of INTEGRATION_CLIENT_IDS) { @@ -190,18 +197,22 @@ describe("every client survives a full lifecycle", () => { const afterApply = parseConfig(readFileSync(configPath, "utf8"), format); const record = store.readRecords()[clientId]!; expect(record.fragmentPaths.length).toBeGreaterThan(0); + // Read through the writer's own segment grammar: Raycast's path holds a + // `[id=opencodex]` selector into a sequence, not a map key. for (const path of record.fragmentPaths) { - let cursor: unknown = afterApply; - for (const segment of path) { - expect(cursor && typeof cursor === "object").toBe(true); - cursor = (cursor as Record)[segment]; - } - expect(cursor).toBeDefined(); + expect(readPath(afterApply, path)).toBeDefined(); + } + // …and the user's own entry is untouched. `toMatchObject` treats an + // array as exact-length, so a sequence-shaped seed is checked by the + // same selector the writer uses to find its own element. + const userElement = USER_ELEMENT[clientId]; + if (userElement) { + expect(readPath(afterApply, userElement)).toEqual(readPath(original, userElement)); + } else { + expect((afterApply as Record)).toMatchObject( + original as Record, + ); } - // …and the user's own entry is untouched. - expect((afterApply as Record)).toMatchObject( - original as Record, - ); const disabled = disableIntegration({ clientId, models: MODELS, config: CONFIG, port: 10100, diff --git a/tests/server/management-integration-routes.test.ts b/tests/server/management-integration-routes.test.ts index 1f8cba92a2..e0d6563aea 100644 --- a/tests/server/management-integration-routes.test.ts +++ b/tests/server/management-integration-routes.test.ts @@ -14,6 +14,7 @@ import { handleManagementAPI } from "../../src/server/management-api"; import { setIntegrationMutationFlightTestHooks, setIntegrationPathTestHooks, + setRaycastDetectTestHook, } from "../../src/server/management/integration-routes"; import type { OcxConfig } from "../../src/types"; import { catalogConvergenceFactory } from "../helpers/catalog-convergence"; @@ -274,6 +275,31 @@ describe("GET /api/client-integrations", () => { // A read is a read: it appends nothing. expect(store.listOperations()).toHaveLength(before); }); + + test("the raycast envelope carries the plan block; every other client's does not", async () => { + // Stubbed: the real detector spawns `defaults` and would report the + // developer's own subscription. + setRaycastDetectTestHook(() => ({ appPath: "/Applications/Raycast.app", aiDirPresent: false, plan: "free" })); + try { + const raycast = await api("/api/client-integrations/raycast"); + expect(raycast.status).toBe(200); + const body = await raycast.json() as { clientId: string; raycast?: { plan: string; appPath: string | null; aiDirPresent: boolean } }; + expect(body.clientId).toBe("raycast"); + expect(body.raycast).toEqual({ appPath: "/Applications/Raycast.app", aiDirPresent: false, plan: "free" }); + + installHermes(); + const hermes = await api("/api/client-integrations/hermes"); + expect(hermes.status).toBe(200); + expect("raycast" in (await hermes.json() as Record)).toBe(false); + + // The collection read describes files, not apps: no client gets the block there. + const list = await api("/api/client-integrations"); + const { clients } = await list.json() as { clients: Array> }; + expect(clients.some(client => "raycast" in client)).toBe(false); + } finally { + setRaycastDetectTestHook(null); + } + }); }); /** The models the route itself derives, so expectations cannot drift from it. */ From ea3d03aeccd1cd9ebf37508f81ae7ff113e140b0 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 07:40:03 +0900 Subject: [PATCH 031/412] fix(integrations): repair Raycast #3733 ownership and plan guidance Reject duplicate selectors before ownership classification with or without a record. Validate unknown summary shapes; repair French, Turkish and Traditional Chinese client catalogs and optional api_keys guidance. Clarify unknown Pro activity in all GUI locales and advisory-only private detection. Retain export capability conventions and document their limits. Add selector cardinality, malformed summaries, unowned refresh, admission refusal and Windows notice regressions. Tests, typecheck, lint and builds NOT RUN per worker scope; combined remote CI and rendered preview belong to main. git diff --check passed. Co-authored-by: Chanhee Lee --- .../content/docs/fr/guides/integrations.md | 21 ++++--- .../src/content/docs/guides/integrations.md | 16 +++-- .../content/docs/tr/guides/integrations.md | 19 ++++-- .../content/docs/zh-tw/guides/integrations.md | 16 +++-- gui/src/i18n/de.ts | 2 +- gui/src/i18n/en.ts | 2 +- gui/src/i18n/fr.ts | 2 +- gui/src/i18n/ja.ts | 2 +- gui/src/i18n/ko.ts | 2 +- gui/src/i18n/ru.ts | 2 +- gui/src/i18n/tr.ts | 2 +- gui/src/i18n/zh-TW.ts | 2 +- gui/src/i18n/zh.ts | 2 +- gui/src/pages/integrations/integration-api.ts | 1 + gui/tests/raycast-plan-notice.test.tsx | 18 ++++-- src/clients/config-export/raycast.ts | 26 +++++++- src/integrations/merge.ts | 4 +- src/integrations/raycast-detect.ts | 5 +- src/integrations/state.ts | 25 ++++++-- src/integrations/writer.ts | 8 ++- tests/clients/integrations-merge.test.ts | 63 ++++++++++++++----- tests/clients/raycast-client.test.ts | 49 ++++++++++++++- 22 files changed, 223 insertions(+), 66 deletions(-) diff --git a/docs-site/src/content/docs/fr/guides/integrations.md b/docs-site/src/content/docs/fr/guides/integrations.md index c70d471f39..6a0a6d0dd3 100644 --- a/docs-site/src/content/docs/fr/guides/integrations.md +++ b/docs-site/src/content/docs/fr/guides/integrations.md @@ -1,10 +1,10 @@ --- title: Intégrations -description: Connectez opencodex à OpenCode, Pi, OMP, Hermes, OpenClaw, Kimi Code, Gajae Code, DeepSeek Harness, MiniMax Code et Raycast depuis le tableau de bord — un commutateur par client, avec une sauvegarde avant chaque écriture. +description: Connectez opencodex à OpenCode, Pi, OMP, Hermes, OpenClaw, Kimi Code, Gajae Code, DeepSeek Harness, MiniMax Code, ZCode, Prime Agent, Aside et Raycast depuis le tableau de bord — un commutateur par client, avec une sauvegarde avant chaque écriture. --- L'onglet **Intégrations** écrit le bloc fournisseur d'opencodex dans le fichier de configuration du client, -puis peut le retirer. Dix clients fonctionnent ainsi, chacun avec son propre commutateur : +puis peut le retirer. Treize clients fonctionnent ainsi, chacun avec son propre commutateur : | Client | Fichier de configuration | Format | Prise d'effet de la modification | Identifiant | |---|---|---|---|---| @@ -17,6 +17,9 @@ puis peut le retirer. Dix clients fonctionnent ainsi, chacun avec son propre com | Gajae Code | `~/.gjc/agent/models.yml` | YAML | dans les nouvelles sessions ou à l'ouverture de `/model` |`OPENCODEX_GAJAE_API_KEY` | | DeepSeek Harness (DSH) | `$DSH_HOME/settings.yaml` (`~/.dsh/settings.yaml` par défaut) | YAML | rechargement à chaud | jeton porteur fictif et non secret pour le bouclage | | MiniMax Code | `~/.minimax/config.yaml` | YAML | dans les nouvelles sessions ou après l’ouverture du sélecteur de modèles | valeur fictive de bouclage | +| Prime Agent | `~/.prime/agent/models.json` | JSON | dans les nouvelles sessions | valeur fictive de bouclage | +| ZCode | `~/.zcode/v2/config.json` | JSON | au redémarrage | valeur fictive de bouclage | +| Aside | `~/.aside/u//models.json` | JSON | après avoir quitté complètement puis rouvert Aside | valeur fictive de bouclage | | Raycast | `~/.config/raycast/ai/providers.yaml` | YAML | immédiatement à l'enregistrement — Raycast surveille le fichier | aucun — bouclage uniquement | La prise en charge gérée de DSH exige au minimum **DSH 0.1.0-rc.6**. OpenCodex ne possède que le fragment @@ -45,14 +48,18 @@ d'installation et indique que le client n'est pas installé tant qu'il n'existe Le bloc géré est un seul élément, `id: opencodex`, dans la séquence `providers` du fichier : `name: OpenCodex`, `base_url: http://:/v1`, et chaque modèle routé avec ses `abilities` — -`tools` et `system_message` sont toujours pris en charge, `vision` suit les modalités d'entrée du +`tools` et `system_message` sont définis à `true` par convention d’export, `vision` suit les modalités d'entrée du catalogue, `reasoning_effort` est défini lorsque le modèle dispose d'une échelle d'effort, et `temperature` est désactivé pour les modèles de raisonnement. Les autres fournisseurs du fichier sont préservés, et la désactivation ne retire que l'élément OpenCodex. Raycast prend en compte la modification dès l'enregistrement du fichier, sans redémarrage ; les modèles apparaissent dans le -sélecteur de modèles de Raycast regroupés sous **OpenCodex**. Le fichier n'a aucun emplacement pour -un identifiant, ce client est donc limité au bouclage : aucune entrée `api_keys` n'est écrite et une -liaison hors bouclage est refusée. Le format est documenté sur +sélecteur de modèles de Raycast regroupés sous **OpenCodex**. Raycast accepte le champ facultatif +`api_keys`, mais OpenCodex l’omet volontairement et refuse les cibles hors bouclage ou exigeant +authentification : cette intégration ne fournit pas l’en-tête d’admission requis par OpenCodex. +Le signal Pro issu d’une préférence privée macOS est indicatif ; Windows ne la lit jamais et +renvoie un état inconnu. Il ne bloque pas l’écriture. Les métadonnées exportées ne prouvent pas +la prise en charge des outils pour chaque modèle. Les valeurs des autres fournisseurs sont +préservées, sans garantie pour les commentaires ou la mise en forme YAML. Le format est documenté sur [manual.raycast.com/ai/custom-providers](https://manual.raycast.com/ai/custom-providers). Les chemins respectent les variables de remplacement propres à chaque client, lorsqu'elles existent. Pour @@ -115,7 +122,7 @@ niveaux. Dans ces cas, le commutateur est verrouillé afin que rien ne soit modi **OMP** n'est pas affecté non plus par les modifications voisines, mais pour une autre raison : son outil d'écriture ne modifie, octet par octet, que sa propre plage `providers.opencodex` ; le reste du fichier n'est jamais réécrit. Pour les autres formats susceptibles de contenir des commentaires (Hermes, OpenClaw, -Kimi Code, Gajae Code, MiniMax Code et Raycast — documents YAML, JSON5 et TOML réécrits en entier), ou lorsque les propres entrées +Kimi Code, Gajae Code, MiniMax Code, ZCode, Prime Agent, Aside et Raycast — documents YAML, JSON5 et TOML réécrits en entier), ou lorsque les propres entrées d'opencodex ont été modifiées, le commutateur se verrouille et la désactivation est refusée plutôt que de deviner quelles modifications vous appartiennent. diff --git a/docs-site/src/content/docs/guides/integrations.md b/docs-site/src/content/docs/guides/integrations.md index bb8cea7001..e6230e4956 100644 --- a/docs-site/src/content/docs/guides/integrations.md +++ b/docs-site/src/content/docs/guides/integrations.md @@ -73,14 +73,22 @@ not honor `XDG_CONFIG_HOME`, so that path is not relocatable. The managed block is one element, `id: opencodex`, in the file's `providers` sequence: `name: OpenCodex`, `base_url: http://:/v1`, and every -routed model with its `abilities` — `tools` and `system_message` are always -supported, `vision` follows the catalog's input modalities, `reasoning_effort` +routed model with its `abilities` — the exporter sets `tools` and `system_message` to +`true` as a client-export convention, `vision` follows the catalog's input modalities, `reasoning_effort` is set when the model has an effort ladder, and `temperature` is turned off for reasoning models. Other providers in the file are preserved, and disable removes only the OpenCodex element. Raycast picks up the change as soon as the file is saved, no restart needed; the models appear in Raycast's model picker grouped -under **OpenCodex**. The file has no place for a credential, so this client is -loopback-only: no `api_keys` entry is written and a non-loopback bind is refused. +under **OpenCodex**. Raycast supports optional `api_keys`, but OpenCodex intentionally +omits them and refuses non-loopback or admission-authenticated targets; this integration +cannot supply OpenCodex's required admission header. + +The macOS private preference is only an advisory Pro hint; Windows never reads it and +reports the plan as unknown. Plan detection does not authorize or block a write. +The export metadata has no authoritative tool-support flag, so `tools: true` does not +prove every routed model supports tools. Vision and effort flags follow catalog metadata; +turning temperature off for an effort ladder is conservative export behavior. +Provider values are preserved; YAML formatting and comments are not guaranteed to survive. The format is documented at [manual.raycast.com/ai/custom-providers](https://manual.raycast.com/ai/custom-providers). diff --git a/docs-site/src/content/docs/tr/guides/integrations.md b/docs-site/src/content/docs/tr/guides/integrations.md index ff0dcaa41e..145cd8c6bc 100644 --- a/docs-site/src/content/docs/tr/guides/integrations.md +++ b/docs-site/src/content/docs/tr/guides/integrations.md @@ -1,10 +1,10 @@ --- title: Entegrasyonlar -description: Kontrol panelinden OpenCode, Pi, OMP, Hermes, OpenClaw, Kimi Code, Gajae Code, DeepSeek Harness, MiniMax Code ve Raycast'i opencodex'e bağlayın — istemci başına tek bir anahtar ve her yazmadan önce alınan bir yedek. +description: Kontrol panelinden OpenCode, Pi, OMP, Hermes, OpenClaw, Kimi Code, Gajae Code, DeepSeek Harness, MiniMax Code, ZCode, Prime Agent, Aside ve Raycast'i opencodex'e bağlayın — istemci başına tek bir anahtar ve her yazmadan önce alınan bir yedek. --- **Entegrasyonlar** sekmesi, opencodex'in sağlayıcı bloğunu istemcinin kendi -yapılandırma dosyasına yazar ve tekrar kaldırır. On istemci bu şekilde +yapılandırma dosyasına yazar ve tekrar kaldırır. On üç istemci bu şekilde çalışır, her biri bir anahtarla: | İstemci | Yapılandırma dosyası | Format | Değişiklik ne zaman geçerli olur? | Kimlik bilgisi | @@ -18,6 +18,9 @@ yapılandırma dosyasına yazar ve tekrar kaldırır. On istemci bu şekilde | Gajae Code | `~/.gjc/agent/models.yml` | YAML | yeni oturumlarda veya `/model` açtığınızda | `OPENCODEX_GAJAE_API_KEY` | | DeepSeek Harness (DSH) | `$DSH_HOME/settings.yaml` (varsayılan `~/.dsh/settings.yaml`) | YAML | çalışırken yeniden yükleme | gizli olmayan geri döngü bearer yer tutucusu | | MiniMax Code | `~/.minimax/config.yaml` | YAML | yeni oturumlarda veya model seçici açıldıktan sonra | geri döngü (loopback) yer tutucusu | +| Prime Agent | `~/.prime/agent/models.json` | JSON | yeni oturumlarda | geri döngü yer tutucusu | +| ZCode | `~/.zcode/v2/config.json` | JSON | yeniden başlatmada | geri döngü yer tutucusu | +| Aside | `~/.aside/u//models.json` | JSON | Aside tamamen kapatılıp yeniden açıldıktan sonra | geri döngü yer tutucusu | | Raycast | `~/.config/raycast/ai/providers.yaml` | YAML | kaydedildiği anda — Raycast dosyayı izler | yok — yalnızca geri döngü | Yönetilen DSH desteğinin en düşük uyumlu sürümü **DSH 0.1.0-rc.6**'dır. OpenCodex yalnızca @@ -48,14 +51,18 @@ yol taşınamaz. Yönetilen blok, dosyanın `providers` dizisindeki tek bir öğedir: `id: opencodex`, `name: OpenCodex`, `base_url: http://:/v1` ve `abilities` alanıyla birlikte -yönlendirilen her model — `tools` ve `system_message` her zaman destekli, `vision` +yönlendirilen her model — dışa aktarma kuralı olarak `tools` ve `system_message` değeri `true` olur, `vision` kataloğun giriş modalitelerini izler, `reasoning_effort` modelin bir çaba merdiveni varsa ayarlanır ve `temperature` akıl yürütme modelleri için kapatılır. Dosyadaki diğer sağlayıcılar korunur ve devre dışı bırakma yalnızca OpenCodex öğesini kaldırır. Raycast değişikliği dosya kaydedilir kaydedilmez, yeniden başlatma gerekmeden alır; modeller -Raycast'in model seçicisinde **OpenCodex** altında gruplanmış olarak görünür. Dosyada -kimlik bilgisi için bir yer yoktur, bu yüzden bu istemci yalnızca geri döngü içindir: -hiçbir `api_keys` girdisi yazılmaz ve geri döngü dışı bir bağlama reddedilir. Format +Raycast'in model seçicisinde **OpenCodex** altında gruplanmış olarak görünür. Raycast şeması +isteğe bağlı `api_keys` alanını destekler; OpenCodex bu alanı bilerek yazmaz ve geri döngü +dışı veya kimlik doğrulaması gerektiren hedefleri reddeder. Bu entegrasyon OpenCodex'in +zorunlu kabul başlığını sağlayamaz. macOS'taki özel tercih yalnızca bir Pro ipucudur; +Windows bu tercihi hiç okumaz ve durumu bilinmiyor olarak bildirir. Bu bilgi yazmayı engellemez. +Dışa aktarılan meta veriler her modelin araç desteğini doğrulamaz. Diğer sağlayıcıların +değerleri korunur; YAML biçimlendirmesi ve yorumlarının korunması garanti edilmez. Format [manual.raycast.com/ai/custom-providers](https://manual.raycast.com/ai/custom-providers) adresinde belgelenmiştir. diff --git a/docs-site/src/content/docs/zh-tw/guides/integrations.md b/docs-site/src/content/docs/zh-tw/guides/integrations.md index ebf2e6f0de..6a42ea8571 100644 --- a/docs-site/src/content/docs/zh-tw/guides/integrations.md +++ b/docs-site/src/content/docs/zh-tw/guides/integrations.md @@ -1,9 +1,9 @@ --- title: 整合 -description: 從儀表板把 opencodex 連接到 OpenCode、Pi、OMP、Hermes、OpenClaw、Kimi Code、Gajae Code、DeepSeek Harness、MiniMax Code 與 Raycast——每個客戶端一個開關,每次寫入前都會先備份。 +description: 從儀表板把 opencodex 連接到 OpenCode、Pi、OMP、Hermes、OpenClaw、Kimi Code、Gajae Code、DeepSeek Harness、MiniMax Code、ZCode、Prime Agent、Aside 與 Raycast——每個客戶端一個開關,每次寫入前都會先備份。 --- -**整合(Integrations)** 分頁會把 opencodex 的 provider 區塊寫入客戶端自己的設定檔,也會把它移除。共有十個客戶端以這種方式運作,每個都有一個開關: +**整合(Integrations)** 分頁會把 opencodex 的 provider 區塊寫入客戶端自己的設定檔,也會把它移除。共有十三個客戶端以這種方式運作,每個都有一個開關: | 客戶端 | 設定檔 | 格式 | 變更生效時機 | 憑證 | |---|---|---|---|---| @@ -16,6 +16,9 @@ description: 從儀表板把 opencodex 連接到 OpenCode、Pi、OMP、Hermes、 | Gajae Code | `~/.gjc/agent/models.yml` | YAML | 新 sessions,或當你開啟 `/model` 時 | `OPENCODEX_GAJAE_API_KEY` | | DeepSeek Harness (DSH) | `$DSH_HOME/settings.yaml`(預設 `~/.dsh/settings.yaml`) | YAML | 熱重載 | 非秘密的 loopback bearer 佔位符 | | MiniMax Code | `~/.minimax/config.yaml` | YAML | 新 sessions,或開啟模型選擇器後 | loopback 佔位符 | +| Prime Agent | `~/.prime/agent/models.json` | JSON | 新 sessions | loopback 佔位符 | +| ZCode | `~/.zcode/v2/config.json` | JSON | 重新啟動時 | loopback 佔位符 | +| Aside | `~/.aside/u//models.json` | JSON | 完全結束並重新開啟 Aside 後 | loopback 佔位符 | | Raycast | `~/.config/raycast/ai/providers.yaml` | YAML | 儲存後立即生效——Raycast 會監看該檔案 | 無——僅限 loopback | 受管理 DSH 支援的相容性下限是 **DSH 0.1.0-rc.6**。OpenCodex 只擁有 @@ -40,11 +43,14 @@ macOS 與 Windows 上同樣讀取 `~/.config/raycast/ai/providers.yaml`,且不 受管理區塊是檔案 `providers` 序列中的單一元素 `id: opencodex`:`name: OpenCodex`、 `base_url: http://:/v1`,以及每個路由模型及其 `abilities`——`tools` 與 -`system_message` 一律支援,`vision` 依目錄的輸入模態而定,`reasoning_effort` 在模型有 effort +`system_message` 依匯出慣例設為 `true`,`vision` 依目錄的輸入模態而定,`reasoning_effort` 在模型有 effort 階梯時設定,`temperature` 對推理模型關閉。檔案中的其他 provider 會被保留,停用只移除 OpenCodex 元素。檔案一儲存 Raycast 就會套用變更,不需重新啟動;模型會在 Raycast 的模型選擇器中歸在 -**OpenCodex** 群組下。該檔案沒有存放憑證的位置,因此此客戶端僅限 loopback:不會寫入任何 -`api_keys` 項目,非 loopback 的 bind 會被拒絕。格式說明見 +**OpenCodex** 群組下。Raycast 支援選填的 `api_keys`,但 OpenCodex 刻意省略該欄位,並拒絕 +非 loopback 或需要准入驗證的目標,因為此整合無法提供 OpenCodex 要求的准入標頭。 +macOS 私有偏好設定僅提供 Pro 狀態提示;Windows 完全不讀取該設定,狀態會是未知。 +此提示不會阻擋寫入。匯出中繼資料並未證實每個模型的工具能力。其他 provider 的值會保留, +但不保證 YAML 格式與註解不變。格式說明見 [manual.raycast.com/ai/custom-providers](https://manual.raycast.com/ai/custom-providers)。 路徑遵循客戶端自己的環境覆寫(environment override)。對 OMP 而言,`OMP_PROFILE` 以存在與否優先於 `PI_PROFILE`,即使明確為空也一樣。具名 profile 會把 `PI_CONFIG_DIR` 當作相對於使用者家目錄的目錄名稱,並忽略 `PI_CODING_AGENT_DIR`;沒有具名 profile 時,`PI_CODING_AGENT_DIR` 勝出。OMP 支援 provider 層級的 headers,但這個最初的整合刻意只支援 loopback;遠端 `x-opencodex-api-key` 的連線設定被延後。搬移過的 `HERMES_HOME`、`KIMI_CODE_HOME` 與 `XDG_CONFIG_HOME` 路徑同樣會被遵循,而非猜測。表格列出每個客戶端的預設值。 diff --git a/gui/src/i18n/de.ts b/gui/src/i18n/de.ts index af5546775a..85e5c90a25 100644 --- a/gui/src/i18n/de.ts +++ b/gui/src/i18n/de.ts @@ -1255,7 +1255,7 @@ export const de: Record = { "integrations.semantics.aside": "Verwaltet nur providers.opencodex in der ~/.aside/u//models.json dieses Profils. Andere Provider bleiben unverändert. Beende Aside nach dem Anwenden vollständig und öffne es erneut.", "integrations.semantics.raycast": "Fügt einen OpenCodex-Provider-Eintrag in die providers.yaml von Raycast ein, damit jedes geroutete Modell in der Modellauswahl von Raycast AI erscheint. Raycast Pro erforderlich.", "integrations.raycast.proRequired": "Custom Providers ist eine Funktion von Raycast Pro. Die Datei wird geschrieben, aber Raycast ignoriert sie, bis ein Pro-Abonnement aktiv ist.", - "integrations.raycast.planUnknown": "Der Abonnementstatus von Raycast konnte nicht gelesen werden; Custom Providers erfordert Raycast Pro.", + "integrations.raycast.planUnknown": "Es konnte nicht festgestellt werden, ob Raycast Pro aktiv ist; Custom Providers erfordert Raycast Pro.", "integrations.raycast.revealConfig": "Öffnen Sie Raycast → Einstellungen → AI und klicken Sie einmal auf „Reveal Providers Config“, damit der Providers-Ordner existiert.", "codexAuth.mainAccount": "Hauptkonto", "codexAuth.logLabel": "Log-Kennung", diff --git a/gui/src/i18n/en.ts b/gui/src/i18n/en.ts index 71bfd5e2c3..4d9514e4de 100644 --- a/gui/src/i18n/en.ts +++ b/gui/src/i18n/en.ts @@ -1802,7 +1802,7 @@ export const en = { "integrations.semantics.aside": "Manages only providers.opencodex in this profile’s ~/.aside/u//models.json. Your other providers stay unchanged. Fully quit and reopen Aside after applying.", "integrations.semantics.raycast": "Adds an OpenCodex provider entry to Raycast's providers.yaml so every routed model appears in the Raycast AI model picker. Raycast Pro required.", "integrations.raycast.proRequired": "Custom Providers is a Raycast Pro feature. The file will be written, but Raycast ignores it until a Pro subscription is active.", - "integrations.raycast.planUnknown": "Could not read the Raycast subscription state; Custom Providers requires Raycast Pro.", + "integrations.raycast.planUnknown": "Could not determine whether Raycast Pro is active; Custom Providers requires Raycast Pro.", "integrations.raycast.revealConfig": "Open Raycast → Settings → AI and click Reveal Providers Config once so the providers folder exists.", "codexAuth.mainAccount": "Main Account", "codexAuth.logLabel": "Log label", diff --git a/gui/src/i18n/fr.ts b/gui/src/i18n/fr.ts index 028e910bc3..3b370fa20d 100644 --- a/gui/src/i18n/fr.ts +++ b/gui/src/i18n/fr.ts @@ -1734,7 +1734,7 @@ export const fr: Record = { "integrations.semantics.aside": "Gère uniquement providers.opencodex dans le fichier ~/.aside/u//models.json de ce profil. Vos autres fournisseurs restent inchangés. Quittez complètement Aside et relancez-le après application.", "integrations.semantics.raycast": "Ajoute une entrée de fournisseur OpenCodex dans le providers.yaml de Raycast afin que chaque modèle routé apparaisse dans le sélecteur de modèles de Raycast AI. Raycast Pro requis.", "integrations.raycast.proRequired": "Custom Providers est une fonctionnalité Raycast Pro. Le fichier sera écrit, mais Raycast l'ignore tant qu'un abonnement Pro n'est pas actif.", - "integrations.raycast.planUnknown": "Impossible de lire l'état de l'abonnement Raycast ; Custom Providers nécessite Raycast Pro.", + "integrations.raycast.planUnknown": "Impossible de déterminer si Raycast Pro est actif ; Custom Providers nécessite Raycast Pro.", "integrations.raycast.revealConfig": "Ouvrez Raycast → Réglages → AI et cliquez une fois sur « Reveal Providers Config » pour que le dossier des fournisseurs existe.", "codexAuth.mainAccount": "Compte principal", "codexAuth.logLabel": "Libellé du journal", diff --git a/gui/src/i18n/ja.ts b/gui/src/i18n/ja.ts index 864b498483..2112788943 100644 --- a/gui/src/i18n/ja.ts +++ b/gui/src/i18n/ja.ts @@ -1675,7 +1675,7 @@ export const ja: Record = { "integrations.semantics.aside": "このプロファイルの ~/.aside/u//models.json 内の providers.opencodex のみを管理します。他のプロバイダーは変更しません。適用後は Aside を完全に終了してから開き直してください。", "integrations.semantics.raycast": "Raycast の providers.yaml に OpenCodex のプロバイダーエントリを追加し、ルーティングされたすべてのモデルを Raycast AI のモデル選択に表示します。Raycast Pro が必要です。", "integrations.raycast.proRequired": "Custom Providers は Raycast Pro の機能です。ファイルは書き込まれますが、Pro サブスクリプションが有効になるまで Raycast はこれを無視します。", - "integrations.raycast.planUnknown": "Raycast のサブスクリプション状態を読み取れませんでした。Custom Providers には Raycast Pro が必要です。", + "integrations.raycast.planUnknown": "Raycast Pro が有効かどうか確認できませんでした。Custom Providers には Raycast Pro が必要です。", "integrations.raycast.revealConfig": "Raycast → 設定 → AI を開き、「Reveal Providers Config」を一度クリックして providers フォルダを作成してください。", "codexAuth.mainAccount": "メインアカウント", "codexAuth.logLabel": "ログラベル", diff --git a/gui/src/i18n/ko.ts b/gui/src/i18n/ko.ts index 364805943e..2edc3de875 100644 --- a/gui/src/i18n/ko.ts +++ b/gui/src/i18n/ko.ts @@ -1279,7 +1279,7 @@ export const ko: Record = { "integrations.semantics.aside": "이 프로필의 ~/.aside/u//models.json에서 providers.opencodex만 관리합니다. 다른 프로바이더는 그대로 유지됩니다. 적용 후 Aside를 완전히 종료하고 다시 여세요.", "integrations.semantics.raycast": "Raycast의 providers.yaml에 OpenCodex 프로바이더 항목을 추가해 라우팅된 모든 모델이 Raycast AI 모델 선택기에 표시되도록 합니다. Raycast Pro가 필요합니다.", "integrations.raycast.proRequired": "Custom Providers는 Raycast Pro 기능입니다. 파일은 기록되지만 Pro 구독이 활성화될 때까지 Raycast는 이를 무시합니다.", - "integrations.raycast.planUnknown": "Raycast 구독 상태를 읽을 수 없습니다. Custom Providers에는 Raycast Pro가 필요합니다.", + "integrations.raycast.planUnknown": "Raycast Pro 활성 여부를 확인할 수 없습니다. Custom Providers에는 Raycast Pro가 필요합니다.", "integrations.raycast.revealConfig": "Raycast → 설정 → AI를 열고 「Reveal Providers Config」를 한 번 클릭해 providers 폴더를 만드세요.", "codexAuth.mainAccount": "메인 계정", "codexAuth.logLabel": "로그 라벨", diff --git a/gui/src/i18n/ru.ts b/gui/src/i18n/ru.ts index bfd6e0182e..a0675e554d 100644 --- a/gui/src/i18n/ru.ts +++ b/gui/src/i18n/ru.ts @@ -1745,7 +1745,7 @@ export const ru: Record = { "integrations.semantics.aside": "Управляет только providers.opencodex в файле ~/.aside/u//models.json этого профиля. Другие провайдеры остаются без изменений. После применения полностью закройте и снова откройте Aside.", "integrations.semantics.raycast": "Добавляет запись провайдера OpenCodex в providers.yaml Raycast, чтобы каждая маршрутизируемая модель появилась в выборе моделей Raycast AI. Требуется Raycast Pro.", "integrations.raycast.proRequired": "Custom Providers — функция Raycast Pro. Файл будет записан, но Raycast игнорирует его, пока не активна подписка Pro.", - "integrations.raycast.planUnknown": "Не удалось прочитать состояние подписки Raycast; для Custom Providers требуется Raycast Pro.", + "integrations.raycast.planUnknown": "Не удалось определить, активен ли Raycast Pro; для Custom Providers требуется Raycast Pro.", "integrations.raycast.revealConfig": "Откройте Raycast → Настройки → AI и один раз нажмите «Reveal Providers Config», чтобы папка провайдеров появилась.", "codexAuth.mainAccount": "Основной аккаунт", "codexAuth.logLabel": "Метка журнала", diff --git a/gui/src/i18n/tr.ts b/gui/src/i18n/tr.ts index 83ad09002b..8b8a9aa0c5 100644 --- a/gui/src/i18n/tr.ts +++ b/gui/src/i18n/tr.ts @@ -1751,7 +1751,7 @@ export const tr: Record = { "integrations.semantics.aside": "Yalnızca bu profilin ~/.aside/u//models.json dosyasındaki providers.opencodex bölümünü yönetir. Diğer sağlayıcılarınız değişmez. Uyguladıktan sonra Aside’ı tamamen kapatıp yeniden açın.", "integrations.semantics.raycast": "Raycast'in providers.yaml dosyasına bir OpenCodex sağlayıcı girdisi ekler; böylece yönlendirilen her model Raycast AI model seçicisinde görünür. Raycast Pro gerekir.", "integrations.raycast.proRequired": "Custom Providers bir Raycast Pro özelliğidir. Dosya yazılır, ancak bir Pro aboneliği etkin olana kadar Raycast bunu yok sayar.", - "integrations.raycast.planUnknown": "Raycast abonelik durumu okunamadı; Custom Providers için Raycast Pro gerekir.", + "integrations.raycast.planUnknown": "Raycast Pro’nun etkin olup olmadığı belirlenemedi; Custom Providers için Raycast Pro gerekir.", "integrations.raycast.revealConfig": "Raycast → Ayarlar → AI bölümünü açıp sağlayıcı klasörünün oluşması için „Reveal Providers Config“ seçeneğine bir kez tıklayın.", "integrations.semantics.omp": "Kataloğu yüklemek için OMP'yi yeniden başlatın.", "codexAuth.mainAccount": "Ana Hesap", diff --git a/gui/src/i18n/zh-TW.ts b/gui/src/i18n/zh-TW.ts index 4e137ebdd6..51369b8bca 100644 --- a/gui/src/i18n/zh-TW.ts +++ b/gui/src/i18n/zh-TW.ts @@ -2340,7 +2340,7 @@ export const zhTW: Record = { "integrations.semantics.aside": "僅管理此設定檔的 ~/.aside/u//models.json 中的 providers.opencodex。其他供應商維持不變。套用後請完全結束並重新開啟 Aside。", "integrations.semantics.raycast": "在 Raycast 的 providers.yaml 中新增一個 OpenCodex 供應商項目,讓所有已路由的模型出現在 Raycast AI 模型選擇器中。需要 Raycast Pro。", "integrations.raycast.proRequired": "Custom Providers 是 Raycast Pro 功能。檔案會被寫入,但在 Pro 訂閱生效之前 Raycast 會忽略它。", - "integrations.raycast.planUnknown": "無法讀取 Raycast 訂閱狀態;Custom Providers 需要 Raycast Pro。", + "integrations.raycast.planUnknown": "無法確認 Raycast Pro 是否已啟用;Custom Providers 需要 Raycast Pro。", "integrations.raycast.revealConfig": "開啟 Raycast → 設定 → AI,點一次「Reveal Providers Config」,以便建立 providers 資料夾。", "codexAuth.pinned": "已固定", "codexAuth.pinnedHint": "你手動選取了此帳號,因此較高的選擇順序不會越過它。此固定會持續到該帳號用盡、你改選其他帳號,或你變更任一選擇順序為止。", diff --git a/gui/src/i18n/zh.ts b/gui/src/i18n/zh.ts index 67400eaaea..0ec38172c5 100644 --- a/gui/src/i18n/zh.ts +++ b/gui/src/i18n/zh.ts @@ -1272,7 +1272,7 @@ export const zh: Record = { "integrations.semantics.aside": "仅管理此配置文件的 ~/.aside/u//models.json 中的 providers.opencodex。其他提供商保持不变。应用后请完全退出并重新打开 Aside。", "integrations.semantics.raycast": "在 Raycast 的 providers.yaml 中添加一个 OpenCodex 提供商条目,让所有已路由的模型出现在 Raycast AI 模型选择器中。需要 Raycast Pro。", "integrations.raycast.proRequired": "Custom Providers 是 Raycast Pro 功能。文件会被写入,但在 Pro 订阅生效之前 Raycast 会忽略它。", - "integrations.raycast.planUnknown": "无法读取 Raycast 订阅状态;Custom Providers 需要 Raycast Pro。", + "integrations.raycast.planUnknown": "无法确定 Raycast Pro 是否已激活;Custom Providers 需要 Raycast Pro。", "integrations.raycast.revealConfig": "打开 Raycast → 设置 → AI,点击一次“Reveal Providers Config”,以便创建 providers 文件夹。", "codexAuth.mainAccount": "主账号", "codexAuth.logLabel": "日志标签", diff --git a/gui/src/pages/integrations/integration-api.ts b/gui/src/pages/integrations/integration-api.ts index 38b0e0fe89..85ffdc7be4 100644 --- a/gui/src/pages/integrations/integration-api.ts +++ b/gui/src/pages/integrations/integration-api.ts @@ -26,6 +26,7 @@ export type IntegrationReason = | "foreign-edit" | "unowned-key" | "blocked-container" + | "ambiguous-selector" | "unresolvable-path"; export type IntegrationRefusalReason = diff --git a/gui/tests/raycast-plan-notice.test.tsx b/gui/tests/raycast-plan-notice.test.tsx index 4a8d44a77d..7f08550317 100644 --- a/gui/tests/raycast-plan-notice.test.tsx +++ b/gui/tests/raycast-plan-notice.test.tsx @@ -1,7 +1,7 @@ import { expect, test } from "bun:test"; import { createElement } from "react"; import { renderToStaticMarkup } from "react-dom/server"; -import { I18nContext, type TFn } from "../src/i18n/shared"; +import { DICTS, I18nContext, type TFn } from "../src/i18n/shared"; import RaycastPlanNotice from "../src/pages/integrations/RaycastPlanNotice"; import type { RaycastInstall } from "../src/pages/integrations/integration-api"; @@ -14,11 +14,11 @@ import type { RaycastInstall } from "../src/pages/integrations/integration-api"; const echoT: TFn = key => key; -function render(install: RaycastInstall): string { +function render(install: RaycastInstall, t: TFn = echoT): string { return renderToStaticMarkup( createElement( I18nContext.Provider, - { value: { locale: "en", setLocale: () => {}, t: echoT } }, + { value: { locale: "en", setLocale: () => {}, t } }, createElement(RaycastPlanNotice, { install }), ), ); @@ -36,7 +36,7 @@ test("a free plan is a warning notice, never a refusal", () => { expect(markup).not.toContain("integrations.raycast.planUnknown"); }); -test("an unreadable plan stays muted, because non-macOS hosts have no signal", () => { +test("an unknown plan stays muted, because non-macOS hosts have no signal", () => { const markup = render({ plan: "unknown", appPath: null, aiDirPresent: true }); expect(markup).toContain('data-raycast-plan="unknown"'); expect(markup).toContain("integrations.raycast.planUnknown"); @@ -49,3 +49,13 @@ test("a missing ai folder adds the reveal hint independently of the plan", () => expect(markup).toContain('data-raycast-ai-dir="absent"'); expect(markup).toContain("integrations.raycast.revealConfig"); }); + +test("a Windows install reports unknown Pro activity without claiming a preference read failed", () => { + const markup = render({ + plan: "unknown", appPath: "C:\\Users\\u\\AppData\\Local\\Programs\\Raycast", aiDirPresent: true, + }, key => DICTS.en[key]); + expect(markup).toContain("Could not determine whether Raycast Pro is active"); + expect(markup).not.toContain("Could not read"); + expect(markup).not.toContain("notice-warn"); + expect(markup).not.toContain(" { + return typeof value === "object" && value !== null && !Array.isArray(value); +} + export function summarizeRaycast( document: unknown, ): { modelCount: number; modelsWithoutLimits: number } { - const providers = (document as RaycastGeneratedConfig | undefined)?.providers ?? []; - const models = providers.find(provider => provider.id === OPENCODE_PROVIDER_ID)?.models ?? []; + const empty = { modelCount: 0, modelsWithoutLimits: 0 }; + if (!isRecord(document) || !Array.isArray(document.providers)) return empty; + const providers = document.providers.filter( + provider => isRecord(provider) && provider.id === OPENCODE_PROVIDER_ID, + ); + // An ambiguous managed provider has no meaningful summary either. + if (providers.length !== 1) return empty; + const provider: unknown = providers[0]; + if (!isRecord(provider) || !Array.isArray(provider.models)) return empty; + const models = provider.models.filter((model): model is Record => ( + isRecord(model) + && typeof model.id === "string" && model.id.trim().length > 0 + && typeof model.name === "string" && model.name.trim().length > 0 + )); return { modelCount: models.length, - modelsWithoutLimits: models.filter(model => model.context === undefined).length, + modelsWithoutLimits: models.filter(model => ( + typeof model.context !== "number" || authoritativeContextWindow(model.context) === undefined + )).length, }; } diff --git a/src/integrations/merge.ts b/src/integrations/merge.ts index 768ddc755f..ab2099b424 100644 --- a/src/integrations/merge.ts +++ b/src/integrations/merge.ts @@ -51,7 +51,7 @@ export class AmbiguousSelectorError extends Error { } /** The index of the element a selector names, -1 when none matches. */ -function selectIndex(items: readonly unknown[], field: string, value: string): number { +export function selectIndex(items: readonly unknown[], field: string, value: string): number { const matches: number[] = []; items.forEach((item, index) => { if (isPlainRecord(item) && item[field] === value) matches.push(index); @@ -249,7 +249,7 @@ export function createdContainerPaths( case "select": { // A selector that matches nothing means setPath will push the element. next = Array.isArray(cursor) - ? cursor.find(item => isPlainRecord(item) && item[segment.field] === segment.value) + ? cursor[selectIndex(cursor, segment.field, segment.value)] : undefined; break; } diff --git a/src/integrations/raycast-detect.ts b/src/integrations/raycast-detect.ts index 5e79578f46..7ae70edf46 100644 --- a/src/integrations/raycast-detect.ts +++ b/src/integrations/raycast-detect.ts @@ -10,7 +10,7 @@ * GUI need to explain a file that is written but ignored. * * Detection is read-only and injectable, like cursor-detect.ts: nothing here - * touches the Raycast install or its preferences, and the tests run against + * writes to the Raycast install or its preferences, and the tests run against * stubbed deps rather than the machine they execute on. */ import { existsSync } from "node:fs"; @@ -37,7 +37,8 @@ export interface RaycastDetectDeps { } /** - * The preference Raycast writes for its subscription state. Read through + * A private preference used only as an advisory subscription hint, not an + * entitlement API or a condition for writes. Read through * `defaults` rather than by parsing the plist: cfprefsd caches writes, so the * file on disk can lag what the running app believes. */ diff --git a/src/integrations/state.ts b/src/integrations/state.ts index bb0e5b3567..0249987027 100644 --- a/src/integrations/state.ts +++ b/src/integrations/state.ts @@ -12,7 +12,7 @@ import { ClientPathError, EXPORT_CLIENTS, opencodeProxyBaseUrl, type ExportModel import type { OcxConfig } from "../types"; import { PARSE_FAILED, loadTarget, parseConfig, type IntegrationIO } from "./config-io"; import { SNAPSHOT_RETENTION } from "./journal"; -import { parseSegment, type PathSegment } from "./merge"; +import { AmbiguousSelectorError, parseSegment, selectIndex, type PathSegment } from "./merge"; import { canonicalContribution, fingerprint, semanticContribution, type OwnershipRecord } from "./ownership"; import { protectedContributionFingerprint, @@ -36,6 +36,7 @@ export type StateReason = | "unowned-key" /** A container we would have to write through holds a non-object value. */ | "blocked-container" + | "ambiguous-selector" /** A path selector we cannot resolve, e.g. a relative OPENCLAW_CONFIG_PATH. */ | "unresolvable-path"; @@ -63,7 +64,7 @@ function assertNever(segment: never): never { /** The element a selector names, or `undefined` when none matches. */ function selectElement(items: readonly unknown[], segment: PathSegment & { kind: "select" }): unknown { - return items.find(item => isPlainRecord(item) && item[segment.field] === segment.value); + return items[selectIndex(items, segment.field, segment.value)]; } /** @@ -291,8 +292,24 @@ export function classifyIntegration(input: { * Checked BEFORE `absent`: our leaf is missing in exactly this case, so the * absent branch would authorize an apply that replaces the user's value. */ - if (blockedContainerPath(input.parsed, input.contribution)) { - return { state: "unsafe", reason: "blocked-container" }; + try { + if (blockedContainerPath(input.parsed, input.contribution)) { + return { state: "unsafe", reason: "blocked-container" }; + } + // Check every selector before presence/fingerprint short-circuits, including + // paths an older ownership record may remove during refresh or disable. + const paths = [ + ...input.contribution.fragments.map(fragment => fragment.path), + ...(input.record?.fragmentPaths ?? []), + ]; + for (const path of paths) { + if (Array.isArray(path) && path.every(key => typeof key === "string")) { + readPath(input.parsed, path); + } + } + } catch (error) { + if (!(error instanceof AmbiguousSelectorError)) throw error; + return { state: "unsafe", reason: "ambiguous-selector" }; } if (!hasOurFragments(input.parsed, input.contribution)) return { state: "absent" }; diff --git a/src/integrations/writer.ts b/src/integrations/writer.ts index 7ec543715a..514fbc3220 100644 --- a/src/integrations/writer.ts +++ b/src/integrations/writer.ts @@ -321,7 +321,9 @@ function applyOrRefreshIntegration( return refuse(clientId, "unsafe", "unsafe", classified.reason === "blocked-container" ? `${configPath} holds a value where opencodex would have to write a section, so applying would replace it` - : `${configPath} cannot be changed safely`); + : classified.reason === "ambiguous-selector" + ? `${configPath} has more than one entry matching a managed selector` + : `${configPath} cannot be changed safely`); } /* * An implicit catalog sync is refresh-only. Keeping this decision inside the @@ -511,7 +513,9 @@ export function disableIntegration(input: IntegrationWriteInput): WriteOutcome { return refuse(clientId, "unsafe", "unsafe", classified.reason === "blocked-container" ? `${configPath} holds a value where opencodex would have to read a section, so nothing can be removed safely` - : `${configPath} cannot be changed safely`); + : classified.reason === "ambiguous-selector" + ? `${configPath} has more than one entry matching a managed selector` + : `${configPath} cannot be changed safely`); } /* diff --git a/tests/clients/integrations-merge.test.ts b/tests/clients/integrations-merge.test.ts index 6bea116319..6585d9f1e9 100644 --- a/tests/clients/integrations-merge.test.ts +++ b/tests/clients/integrations-merge.test.ts @@ -17,6 +17,7 @@ import { applyIntegration, disableIntegration, overwriteIntegration, + refreshIntegration, type IntegrationWriteInput, } from "../../src/integrations/writer"; import type { OcxConfig } from "../../src/types"; @@ -88,6 +89,9 @@ describe("setPath with a selector", () => { const doc = { providers: [OURS, THEIRS, { id: "opencodex", name: "dupe" }] }; expect(() => setPath(doc, SELECT, OURS)).toThrow(AmbiguousSelectorError); expect(() => deletePath(doc, SELECT)).toThrow(AmbiguousSelectorError); + expect(() => readPath(doc, SELECT)).toThrow(AmbiguousSelectorError); + expect(() => createdContainerPaths(doc, contribution([...SELECT, "name"]))) + .toThrow(AmbiguousSelectorError); }); }); @@ -250,19 +254,48 @@ describe("raycast writer round trip", () => { expect(Bun.YAML.parse(readFileSync(configPath, "utf8"))).toEqual({ providers: { opencodex: {} } }); }); - test("two entries with our id refuse as unsafe and leave the file alone", () => { - const configPath = installRaycast(); - const text = Bun.YAML.stringify({ providers: [{ id: "opencodex", name: "a" }, { id: "opencodex", name: "b" }] }); - writeFileSync(configPath, text); - // Neither entry is ours on record, so status reads conflict and a plain apply refuses - // there. The explicit overwrite reaches the merge, which is where the ambiguity is - // detected: it must surface as an `unsafe` refusal, never as a thrown error. - expect(readIntegrationState(input())).toMatchObject({ state: "conflict" }); - expect(applyIntegration(input())).toMatchObject({ ok: false, reason: "conflict" }); - const result = overwriteIntegration(input()); - expect(result).toMatchObject({ ok: false, reason: "unsafe", state: "unsafe" }); - if (!result.ok) expect(result.message).toContain("more than one entry"); - expect(readFileSync(configPath, "utf8")).toBe(text); - expect(store.listOperations("raycast")).toHaveLength(0); - }); + for (const recorded of [false, true]) { + for (const count of [0, 1, 2]) { + test(`${count} matching rows with record=${recorded} agree across status and mutation`, () => { + const configPath = installRaycast(); + writeFileSync(configPath, Bun.YAML.stringify({ providers: [THEIRS] })); + let managed: unknown = OURS; + if (recorded) { + expect(applyIntegration(input())).toMatchObject({ ok: true }); + const applied = Bun.YAML.parse(readFileSync(configPath, "utf8")) as { providers: unknown[] }; + managed = applied.providers[1]; + } + // For one owned row retain the writer's exact bytes, so this exercises + // current rather than an unrelated whole-file formatting conflict. + if (!recorded || count !== 1) { + writeFileSync(configPath, Bun.YAML.stringify({ + providers: [THEIRS, ...Array.from({ length: count }, () => managed)], + })); + } + const text = readFileSync(configPath, "utf8"); + const records = store.readRecords(); + const operations = store.listOperations("raycast"); + const expected = count === 0 ? "absent" : count === 2 ? "unsafe" : recorded ? "current" : "conflict"; + expect(readIntegrationState(input()).state).toBe(expected); + if (count === 2) { + expect(readIntegrationState(input()).reason).toBe("ambiguous-selector"); + for (const mutate of [applyIntegration, refreshIntegration, disableIntegration, overwriteIntegration]) { + expect(mutate(input())).toMatchObject({ ok: false, state: "unsafe", reason: "unsafe" }); + expect(readFileSync(configPath, "utf8")).toBe(text); + expect(store.readRecords()).toEqual(records); + expect(store.listOperations("raycast")).toEqual(operations); + } + } else if (count === 0) { + expect(refreshIntegration(input())).toMatchObject({ ok: true, changed: false, state: "absent" }); + expect(readFileSync(configPath, "utf8")).toBe(text); + } else if (recorded) { + expect(applyIntegration(input())).toMatchObject({ ok: true, changed: false, state: "current" }); + } else { + expect(applyIntegration(input())).toMatchObject({ ok: false, reason: "conflict" }); + expect(disableIntegration(input())).toMatchObject({ ok: false, reason: "conflict" }); + expect(readFileSync(configPath, "utf8")).toBe(text); + } + }); + } + } }); diff --git a/tests/clients/raycast-client.test.ts b/tests/clients/raycast-client.test.ts index 148f84babb..d84123f458 100644 --- a/tests/clients/raycast-client.test.ts +++ b/tests/clients/raycast-client.test.ts @@ -10,6 +10,7 @@ import { buildClientContribution, raycastAiDir, raycastConfigPath, + summarizeRaycast, type ExportContext, type ExportModel, type RaycastGeneratedConfig, @@ -73,6 +74,7 @@ beforeEach(() => { afterEach(() => { removeTreeWithRetry(home); + removeTreeWithRetry(store.root); }); /** Raycast "installed" for our purposes: the `ai` directory exists. */ @@ -123,6 +125,25 @@ describe("Raycast client config", () => { expect("context" in unknown).toBe(false); }); + test("summarizes unknown file shapes without trusting parsed YAML", () => { + const empty = { modelCount: 0, modelsWithoutLimits: 0 }; + for (const document of [undefined, null, false, 42, "providers", [], {}, + { providers: null }, { providers: {} }, { providers: "bad" }, + { providers: [null, false, "bad", [], {}] }, + ...[undefined, null, false, 42, "bad", {}].map(models => ({ providers: [{ id: "opencodex", models }] })), + { providers: [{ id: "opencodex", models: [] }, { id: "opencodex", models: [] }] }, + ]) expect(summarizeRaycast(document)).toEqual(empty); + expect(summarizeRaycast({ providers: [null, { id: "foreign", models: "bad" }, { + id: "opencodex", models: [null, false, 1, "bad", [], {}, { id: "x" }, + { id: "", name: "empty id" }, { id: "x", name: 1 }, + { id: "known", name: "Known", context: 1000 }, + { id: "unknown", name: "Unknown" }, + { id: "invalid", name: "Invalid", context: "1000" }, + { id: "negative", name: "Negative", context: -1 }, + ], + }] })).toEqual({ modelCount: 4, modelsWithoutLimits: 3 }); + }); + test("uses product labels instead of raw slugs or provider suffixes", () => { expect(exportPresentationLabel({ namespaced: "anthropic/claude-fable-5-1", provider: "anthropic", id: "claude-fable-5-1", @@ -137,9 +158,9 @@ describe("Raycast client config", () => { /* * Abilities follow the catalog row, not the vendor name. Temperature and - * reasoning_effort are the same bit inverted: Raycast's own template notes - * that reasoning models commonly reject temperature. system_message and - * tools are always on, the same stance as Hermes. + * reasoning_effort use opposite flags as a conservative export convention. + * This is not a complete per-model capability oracle. system_message and + * tools retain the client export convention, not verified per-model support. */ test("maps vision and reasoning ladders onto abilities per model", () => { const document = buildClientConfig("raycast", context()) as RaycastGeneratedConfig; @@ -251,6 +272,28 @@ describe("Raycast client config", () => { .toEqual(fewer.map(model => model.namespaced).sort()); }); + test("implicit catalog refresh neither loads models nor connects an unowned Raycast", async () => { + const configPath = installRaycast(USER_SEED); + const outcomes = await refreshOwnedCatalogIntegrations({ + ...request(), + models: async () => { throw new Error("unowned client must not load models"); }, + }, ["raycast"]); + expect(outcomes).toEqual([]); + expect(readFileSync(configPath, "utf8")).toBe(USER_SEED); + expect(store.readRecords().raycast).toBeUndefined(); + expect(store.listOperations("raycast")).toEqual([]); + }); + + for (const hostname of ["0.0.0.0", "192.0.2.1"]) { + test(`refuses admission-authenticated bind ${hostname} without changing the file`, () => { + const configPath = installRaycast(USER_SEED); + const result = applyIntegration({ ...request(), config: { ...CONFIG, hostname } }); + expect(result).toMatchObject({ ok: false, reason: "non_loopback" }); + expect(readFileSync(configPath, "utf8")).toBe(USER_SEED); + expect(store.listOperations("raycast")).toEqual([]); + }); + } + test("refuses a file whose providers is a map rather than a sequence", () => { // `providers: {}` is a container we would have to REPLACE with `[]` to // write our element, and replacing a user's container is never a success. From 387d787b43b9a8b3e1b048d9913c927e98531565 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 07:45:00 +0900 Subject: [PATCH 032/412] fix(raycast): honor live export admission and defer ensure refresh (#3733) Use the existing live client-config API for Raycast CLI export, refusing admission-authenticated destinations before serialization. Resolve declared unauthenticated loopback ports consistently in CLI/API URL composition. Preserve other exporter policy and add OpenCode compatibility coverage. Remove parent-side ensure catalog refresh from saved config; actual server startup and explicit sync remain responsible. Add reachable CLI/API admission/listener tests and an executed-command-body ensure divergence regression. Tests, typecheck, lint and builds NOT RUN per worker scope; git diff --check passed. Main owns final CI and rendered preview. Co-authored-by: Chanhee Lee --- .../content/docs/fr/guides/integrations.md | 6 ++ .../src/content/docs/guides/integrations.md | 6 ++ .../content/docs/tr/guides/integrations.md | 6 ++ .../content/docs/zh-tw/guides/integrations.md | 5 ++ src/cli/export-command.ts | 36 +++++++---- src/cli/index.ts | 7 ++- src/server/management/model-routes.ts | 10 +++- tests/cli/cli-export-command.test.ts | 59 +++++++++++++++++++ .../clients/sync-client-integrations.test.ts | 45 +++++++++++++- .../management-client-config-route.test.ts | 45 ++++++++++++++ 10 files changed, 207 insertions(+), 18 deletions(-) diff --git a/docs-site/src/content/docs/fr/guides/integrations.md b/docs-site/src/content/docs/fr/guides/integrations.md index 6a0a6d0dd3..c718801ddc 100644 --- a/docs-site/src/content/docs/fr/guides/integrations.md +++ b/docs-site/src/content/docs/fr/guides/integrations.md @@ -62,6 +62,12 @@ la prise en charge des outils pour chaque modèle. Les valeurs des autres fourni préservées, sans garantie pour les commentaires ou la mise en forme YAML. Le format est documenté sur [manual.raycast.com/ai/custom-providers](https://manual.raycast.com/ai/custom-providers). +Les exports Raycast en CLI et les téléchargements utilisent la destination et la politique +d’admission du serveur actif, y compris son listener de bouclage sans authentification. +`ocx ensure` ne réactualise pas Raycast depuis sa copie de configuration enregistrée, qui peut +différer du serveur actif. Le démarrage du serveur et la synchronisation explicite restent disponibles. + + Les chemins respectent les variables de remplacement propres à chaque client, lorsqu'elles existent. Pour OMP, la présence de `OMP_PROFILE` l'emporte sur `PI_PROFILE`, même si sa valeur est explicitement vide. Un profil nommé emploie `PI_CONFIG_DIR` comme nom de répertoire relatif au dossier personnel de l'utilisateur diff --git a/docs-site/src/content/docs/guides/integrations.md b/docs-site/src/content/docs/guides/integrations.md index e6230e4956..ea3c93f2dd 100644 --- a/docs-site/src/content/docs/guides/integrations.md +++ b/docs-site/src/content/docs/guides/integrations.md @@ -92,6 +92,12 @@ Provider values are preserved; YAML formatting and comments are not guaranteed t The format is documented at [manual.raycast.com/ai/custom-providers](https://manual.raycast.com/ai/custom-providers). +Raycast CLI exports and dashboard downloads use the running server's destination and +admission policy, including a configured unauthenticated loopback listener. `ocx ensure` +does not refresh Raycast from its saved configuration snapshot: that can differ from the +running server. Server startup and explicit sync remain the catalog refresh paths. + + Cursor has a tab but is not one of these switches. Regular Cursor calls custom endpoints from its own backend, so a loopback proxy is unreachable without a public tunnel, and Cursor's separate Private Inference build is configured inside Cursor. The **Cursor** tab is read-only: diff --git a/docs-site/src/content/docs/tr/guides/integrations.md b/docs-site/src/content/docs/tr/guides/integrations.md index 145cd8c6bc..f068b0233f 100644 --- a/docs-site/src/content/docs/tr/guides/integrations.md +++ b/docs-site/src/content/docs/tr/guides/integrations.md @@ -66,6 +66,12 @@ değerleri korunur; YAML biçimlendirmesi ve yorumlarının korunması garanti e [manual.raycast.com/ai/custom-providers](https://manual.raycast.com/ai/custom-providers) adresinde belgelenmiştir. +Raycast CLI dışa aktarmaları ve panel indirmeleri, yapılandırılmış kimlik doğrulamasız +geri döngü dinleyicisi dahil çalışan sunucunun adresini ve kabul politikasını kullanır. +`ocx ensure`, çalışan sunucudan farklı olabilecek kayıtlı yapılandırma kopyasıyla Raycast'i +yenilemez. Sunucu başlangıcı ve açık senkronizasyon katalog yenilemeye devam eder. + + Yollar, varsa her istemcinin kendi ortam geçersiz kılmalarını dikkate alır. OMP için `OMP_PROFILE`, açıkça boş olduğunda bile varlığıyla `PI_PROFILE`'a üstün gelir. Adlandırılmış bir profil, `PI_CONFIG_DIR`'i kullanıcının ev dizinine göre diff --git a/docs-site/src/content/docs/zh-tw/guides/integrations.md b/docs-site/src/content/docs/zh-tw/guides/integrations.md index 6a42ea8571..46b03df9a1 100644 --- a/docs-site/src/content/docs/zh-tw/guides/integrations.md +++ b/docs-site/src/content/docs/zh-tw/guides/integrations.md @@ -53,6 +53,11 @@ macOS 私有偏好設定僅提供 Pro 狀態提示;Windows 完全不讀取該 但不保證 YAML 格式與註解不變。格式說明見 [manual.raycast.com/ai/custom-providers](https://manual.raycast.com/ai/custom-providers)。 +Raycast CLI 匯出與儀表板下載會使用執行中伺服器的目標位址和准入規則,包含已設定的 +無驗證 loopback listener。`ocx ensure` 不會以可能與執行中伺服器不同的已儲存設定快照 +重新整理 Raycast;伺服器啟動與明確執行的同步仍會更新目錄。 + + 路徑遵循客戶端自己的環境覆寫(environment override)。對 OMP 而言,`OMP_PROFILE` 以存在與否優先於 `PI_PROFILE`,即使明確為空也一樣。具名 profile 會把 `PI_CONFIG_DIR` 當作相對於使用者家目錄的目錄名稱,並忽略 `PI_CODING_AGENT_DIR`;沒有具名 profile 時,`PI_CODING_AGENT_DIR` 勝出。OMP 支援 provider 層級的 headers,但這個最初的整合刻意只支援 loopback;遠端 `x-opencodex-api-key` 的連線設定被延後。搬移過的 `HERMES_HOME`、`KIMI_CODE_HOME` 與 `XDG_CONFIG_HOME` 路徑同樣會被遵循,而非猜測。表格列出每個客戶端的預設值。 對原生 OpenAI 模型,產生的 OMP 區塊會選用其模型層級的 Responses API,保留圖片輸入與 reasoning-effort 控制。路由模型則維持 provider 的 Chat Completions 方言,讓它們既有的 adapters 保持相容。 diff --git a/src/cli/export-command.ts b/src/cli/export-command.ts index c576435432..906065b2e8 100644 --- a/src/cli/export-command.ts +++ b/src/cli/export-command.ts @@ -122,10 +122,10 @@ export function exportModelsFromProxyRows( * Resolved ONCE and handed back to `runtimeRequest` as `baseUrl`, so the catalog and the * exported endpoint can never come from two different probes. */ -function proxyV1BaseUrl(root: string): string { +function proxyV1BaseUrl(root: string, config: OcxConfig): string { const url = new URL(root); const port = url.port ? Number(url.port) : url.protocol === "https:" ? 443 : 80; - return opencodeProxyBaseUrl(port, url.hostname); + return opencodeProxyBaseUrl(port, url.hostname, config); } function parseClient(args: string[]): ExportClientId { @@ -172,17 +172,29 @@ export async function handleExportCommand(argv: string[], deps: ExportCommandDep const spec = EXPORT_CLIENTS[client]; const root = await runtimeBaseUrl(deps); - const rows = await runtimeRequest("/api/models", {}, { ...deps, baseUrl: root }); - if (!Array.isArray(rows)) { - throw new RuntimeApiError("Management API returned an unexpected /api/models payload.", 502, rows); + let built: { document: unknown; text: string }; + if (client === "raycast") { + // The dial address alone cannot distinguish a wildcard authenticated bind + // from loopback. Let the live server resolve its admission/listener policy; + // saved config can differ from the process serving this request. + const exported = await runtimeRequest<{ + client: string; format: string; config: unknown; text: string; + }>("/api/client-config?client=raycast", {}, { ...deps, baseUrl: root }); + if (!exported || exported.client !== "raycast" || exported.format !== "yaml" + || typeof exported.text !== "string" || exported.config === undefined) { + throw new RuntimeApiError("Management API returned an unexpected Raycast export payload.", 502, null); + } + built = { document: exported.config, text: exported.text }; + } else { + const rows = await runtimeRequest("/api/models", {}, { ...deps, baseUrl: root }); + if (!Array.isArray(rows)) { + throw new RuntimeApiError("Management API returned an unexpected /api/models payload.", 502, rows); + } + // Discovery can persist selection; preserve the existing exporters' flow. + const config = (deps.configImpl ?? loadConfig)(); + const models = exportModelsFromProxyRows(rows, config); + built = buildClientConfigText(client, { baseUrl: proxyV1BaseUrl(root, config), models, config }); } - // Discovery can persist pending -> ready selection. Read from the caller's - // config source after the response, rather than filtering with a stale snapshot. - const config = (deps.configImpl ?? loadConfig)(); - const models = exportModelsFromProxyRows(rows, config); - // The text is the client's OWN format — YAML, TOML and JSON5 clients would - // otherwise receive a JSON rendering their parser reads differently. - const built = buildClientConfigText(client, { baseUrl: proxyV1BaseUrl(root), models, config }); const clientConfig = built.document; const text = built.text; diff --git a/src/cli/index.ts b/src/cli/index.ts index 9d9f08951c..663514a120 100755 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -580,7 +580,9 @@ async function handleEnsure(options: { existingIsSuccess?: boolean } = {}): Prom return null; }); if (synced?.status === "skipped") console.log(" Codex integration OFF; startup left Codex native."); - await refreshOwnedRaycastCatalog(config, live.port); + // Do not refresh Raycast from saved config here: live bind/admission and + // secondary-listener settings may differ. Explicit sync or server startup + // owns catalog refresh; ensure must not overwrite a working destination. // Ensure env file exists for already-running proxy (may have been deleted or pre-dates this feature). const systemEnv = await injectSystemEnv(live.port, config).catch(() => ({ injected: false })); reportShellHookFailure(reconcileShellHook(systemEnv.injected)); @@ -625,7 +627,8 @@ async function handleEnsure(options: { existingIsSuccess?: boolean } = {}): Prom return null; }); if (synced?.status === "skipped") console.log(" Codex integration OFF; startup left Codex native."); - await refreshOwnedRaycastCatalog(config, port); + // The child performs Raycast refresh with its actual startup config. The + // parent's pre-spawn snapshot is not authoritative for a client-file write. // The child opens /healthz before its best-effort roster reconcile. Await the same idempotent // operation in the parent so `ocx ensure` cannot report success while stale ocx-*.md files are // still observable. Always use the live port, including fallback-port starts. diff --git a/src/server/management/model-routes.ts b/src/server/management/model-routes.ts index 28d1bef0ec..dd84d8af8c 100644 --- a/src/server/management/model-routes.ts +++ b/src/server/management/model-routes.ts @@ -1,5 +1,6 @@ import { randomUUID } from "node:crypto"; import { readFileSync } from "node:fs"; +import { shouldInjectApiAuthHeader } from "../../codex/loopback-target"; /** * Codex parses a catalog entry's `input_modalities` as a closed enum, and one out-of-enum @@ -480,6 +481,13 @@ export async function handleModelRoutes(ctx: ManagementContext): Promise { expect(parsed.provider.opencodex!.options.baseURL).not.toContain(":10100/"); }); + test("existing OpenCode export also resolves the declared unauthenticated listener", async () => { + const proxy = fakeProxy(); + const result = await run(["--client", "opencode", "--json"], { + baseUrl: proxy.baseUrl, + config: config({ hostname: "0.0.0.0", unauthenticatedLoopbackListener: { enabled: true, port: 10237 } }), + }); + expect(result.code).toBe(0); + const parsed = JSON.parse(result.stdout) as { provider: Record }; + expect(parsed.provider.opencodex!.options.baseURL).toBe("http://127.0.0.1:10237/v1"); + }); + test("disabled rows never reach the exported config", async () => { const proxy = fakeProxy(); const result = await run(["--client", "pi", "--json"], { baseUrl: proxy.baseUrl }); @@ -543,3 +554,51 @@ describe("export allowlist parity", () => { ], cfg).map(row => row.namespaced)).toEqual(["slash/org-model"]); }); }); + +describe("Raycast export uses the live management admission policy", () => { + for (const secondary of [false, true]) { + test(`live wildcard bind with secondary=${secondary} wins over saved loopback config`, async () => { + const oldHome = process.env.OPENCODEX_HOME; + const oldCodexHome = process.env.CODEX_HOME; + const root = tempDir(); + process.env.OPENCODEX_HOME = join(root, "ocx"); + process.env.CODEX_HOME = join(root, "codex"); + mkdirSync(process.env.CODEX_HOME, { recursive: true }); + try { + const liveConfig = config({ + hostname: "0.0.0.0", + providers: { mock: { + adapter: "openai-chat", baseUrl: "http://127.0.0.1/v1", + liveModels: false, models: ["fixture-model"], + } }, + ...(secondary ? { unauthenticatedLoopbackListener: { enabled: true, port: 10237 } } : {}), + }); + const proxy = managementProxy(liveConfig); + const out = join(root, "providers.yaml"); + writeFileSync(out, "keep existing export\n"); + const result = await run(["--client", "raycast", "--json", "--out", out, "--force"], { + baseUrl: proxy.baseUrl, + // Deliberately contradict both live bind and secondary port. + config: config({ unauthenticatedLoopbackListener: { enabled: true, port: 10999 } }), + }); + if (secondary) { + expect(result.code).toBe(0); + const document = JSON.parse(result.stdout) as { providers: Array<{ base_url: string }> }; + expect(document.providers[0]!.base_url).toBe("http://127.0.0.1:10237/v1"); + expect(readFileSync(out, "utf8")).toContain("10237/v1"); + expect(readFileSync(out, "utf8")).not.toContain("10999"); + } else { + expect(result.code).not.toBe(0); + expect(result.stdout).toBe(""); + expect(result.stderr).toContain("non_loopback"); + expect(readFileSync(out, "utf8")).toBe("keep existing export\n"); + } + } finally { + if (oldHome === undefined) delete process.env.OPENCODEX_HOME; + else process.env.OPENCODEX_HOME = oldHome; + if (oldCodexHome === undefined) delete process.env.CODEX_HOME; + else process.env.CODEX_HOME = oldCodexHome; + } + }); + } +}); diff --git a/tests/clients/sync-client-integrations.test.ts b/tests/clients/sync-client-integrations.test.ts index 9050eecd3b..65dc41a2b3 100644 --- a/tests/clients/sync-client-integrations.test.ts +++ b/tests/clients/sync-client-integrations.test.ts @@ -662,18 +662,57 @@ test("the direct ocx sync command refreshes MCode, Pi, Raycast and server-owned expect(command).toContain('synced.status !== "refused"'); }); -test("startup and ensure refresh owned Raycast through the catalog coordinator", async () => { +test("server startup owns Raycast refresh; ensure does not reuse a saved-config snapshot", async () => { const src = await Bun.file(new URL("../../src/cli/index.ts", import.meta.url)).text(); const start = src.slice(src.indexOf("async function handleStart"), src.indexOf("function detachedStartEnvironment")); const ensure = src.slice(src.indexOf("async function handleEnsure"), src.indexOf("async function handleTrayProxyStart")); expect(src).toContain("refreshOwnedCatalogIntegrations"); expect(src).toContain('}, ["raycast"]);'); expect(start).toContain("await refreshOwnedRaycastCatalog(config, port)"); - expect(ensure).toContain("await refreshOwnedRaycastCatalog(config, live.port)"); - expect(ensure).toContain("await refreshOwnedRaycastCatalog(config, port)"); + expect(ensure).not.toContain("await refreshOwnedRaycastCatalog("); expect(src).not.toContain("refreshAllOwnedIntegrations"); }); +test("already-running ensure leaves Raycast untouched when saved host and listener policy diverge", async () => { + // Exercise the actual command body with external effects injected. Importing + // index.ts directly starts CLI dispatch, so isolate only handleEnsure here. + const src = await Bun.file(new URL("../../src/cli/index.ts", import.meta.url)).text(); + const command = src.slice(src.indexOf("async function handleEnsure"), src.indexOf("async function handleTrayProxyStart")); + const executable = new Bun.Transpiler({ loader: "ts" }).transformSync(command); + const root = mkdtempSync(join(tmpdir(), "ocx-ensure-raycast-divergence-")); + const configPath = join(root, "providers.yaml"); + const original = "providers:\n - id: opencodex\n base_url: http://127.0.0.1:10237/v1\n"; + writeFileSync(configPath, original); + const savedConfig = { + port: 10100, hostname: "192.0.2.40", providers: {}, defaultProvider: "mock", + unauthenticatedLoopbackListener: { enabled: true, port: 10999 }, + } as OcxConfig; + let refreshCalls = 0; + const deps = { + findProxyOwnerBeforeJournalRecovery: async () => ({ live: { hostname: "127.0.0.1", port: 10237 } }), + loadConfig: () => savedConfig, + codexAutoStartEnabled: () => true, + syncModelsToCodex: async () => ({ status: "skipped" }), + refreshOwnedRaycastCatalog: async () => { + refreshCalls += 1; + writeFileSync(configPath, "wrong saved destination"); + }, + injectSystemEnv: async () => ({ injected: true }), + reportShellHookFailure: () => {}, + reconcileShellHook: () => ({ state: "installed" }), + reconcileEnsureDesiredIntegrations: async () => {}, + console: { log: () => {}, error: () => {} }, + }; + try { + const ensure = new Function(...Object.keys(deps), `${executable}; return handleEnsure;`)(...Object.values(deps)) as () => Promise; + expect(await ensure()).toBe(true); + expect(refreshCalls).toBe(0); + expect(readFileSync(configPath, "utf8")).toBe(original); + } finally { + removeTreeWithRetry(root); + } +}); + test("identical explicit mutation keys join but cannot swallow a different apply or disable", async () => { let release!: () => void; const gate = new Promise(resolve => { release = resolve; }); diff --git a/tests/server/management-client-config-route.test.ts b/tests/server/management-client-config-route.test.ts index d3d91aebdf..9fcb92e81d 100644 --- a/tests/server/management-client-config-route.test.ts +++ b/tests/server/management-client-config-route.test.ts @@ -23,6 +23,7 @@ import { type McodeGeneratedConfig, type OpencodeGeneratedConfig, type PiGeneratedConfig, + type RaycastGeneratedConfig, } from "../../src/clients/config-export"; import type { OcxConfig } from "../../src/types"; import { catalogConvergenceFactory } from "../helpers/catalog-convergence"; @@ -215,6 +216,50 @@ describe("native Anthropic effort ladder reaches the Aside document", () => { }); }); describe("GET /api/client-config", () => { + for (const hostname of ["0.0.0.0", "::", "192.0.2.40"]) { + test(`Raycast export refuses authenticated bind ${hostname} before generating a document`, async () => { + const response = await clientConfigApi(baseConfig({ hostname }), "?client=raycast"); + expect(response.status).toBe(400); + const body = await response.json() as Record; + expect(body.reason).toBe("non_loopback"); + expect(body.config).toBeUndefined(); + expect(body.text).toBeUndefined(); + }); + } + + test("Raycast export uses the declared unauthenticated listener instead of the management port", async () => { + const response = await clientConfigApi(baseConfig({ + hostname: "0.0.0.0", + unauthenticatedLoopbackListener: { enabled: true, port: 10237 }, + }), "?client=raycast"); + expect(response.status).toBe(200); + const body = await response.json() as ClientConfigEnvelope; + const document = body.config as RaycastGeneratedConfig; + expect(document.providers[0]!.base_url).toBe("http://127.0.0.1:10237/v1"); + expect(document.providers[0]!.models.length).toBeGreaterThan(0); + expect(body.text).not.toContain(REAL_LOOKING_KEY); + expect(body.text).not.toContain("api_keys"); + }); + + test("OpenCode export keeps its envelope and uses the declared unauthenticated listener", async () => { + const response = await clientConfigApi(baseConfig({ + hostname: "0.0.0.0", unauthenticatedLoopbackListener: { enabled: true, port: 10237 }, + }), "?client=opencode"); + expect(response.status).toBe(200); + const body = await response.json() as ClientConfigEnvelope; + expect(body.client).toBe("opencode"); + expect((body.config as OpencodeGeneratedConfig).provider.opencodex!.options.baseURL) + .toBe("http://127.0.0.1:10237/v1"); + }); + + test("Raycast export uses the main port for an ordinary loopback bind", async () => { + const response = await clientConfigApi(baseConfig(), "?client=raycast"); + expect(response.status).toBe(200); + const body = await response.json() as ClientConfigEnvelope; + expect((body.config as RaycastGeneratedConfig).providers[0]!.base_url) + .toBe("http://127.0.0.1:10100/v1"); + }); + test("opencode envelope carries the shared builder's exact bytes", async () => { const config = baseConfig(); const response = await clientConfigApi(config, "?client=opencode"); From 22f39ff105bea7675a82076b44b30aaf109826df Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 08:10:12 +0900 Subject: [PATCH 033/412] test(responses): exercise empty effort ladder through valid ingress CI 34065098625 and 34065112182 exposed a numeric-effort fixture rejected by parseRequest before it reaches the adapter. Use schema-valid high effort to exercise provider-wide omission and input immutability; preserve strict ingress validation. No production change and no local suites. Co-authored-by: jamespan --- tests/responses/openai-responses-passthrough.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/responses/openai-responses-passthrough.test.ts b/tests/responses/openai-responses-passthrough.test.ts index 7e97217dc2..24bc8e0e02 100644 --- a/tests/responses/openai-responses-passthrough.test.ts +++ b/tests/responses/openai-responses-passthrough.test.ts @@ -598,13 +598,13 @@ describe("DeepSeek Responses endpoint contract", () => { } }); - test("a provider-wide empty ladder removes even non-string raw effort", () => { + test("a provider-wide empty ladder removes schema-valid raw effort", () => { const keyed = { adapter: "openai-responses", baseUrl: "https://example.test/v1", authMode: "key" as const }; - const raw = { model: "model", input: "ping", reasoning: { effort: 123, summary: "auto" } }; + const raw = { model: "model", input: "ping", reasoning: { effort: "high", summary: "auto" } }; const wire = JSON.parse(createResponsesPassthroughAdapter({ ...keyed, reasoningEfforts: [] }) .buildRequest(parseRequest(raw)).body); expect(wire.reasoning).toEqual({ summary: "auto" }); - expect(raw.reasoning.effort).toBe(123); + expect(raw.reasoning.effort).toBe("high"); }); test("empty-ladder repair preserves unknown, non-rankable and native forward effort behavior", () => { From 95edd0aec05043d2e162c30edea98e174ad284e9 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 07:47:42 +0900 Subject: [PATCH 034/412] fix(export): preserve live CLI destination despite saved listener drift (#3733) Restore non-Raycast CLI URL composition from the live root only. Raycast remains delegated to the authoritative client-config API; API behavior is unchanged. Replace the OpenCode saved-listener substitution test with a live 10100 versus saved 10999 regression. Tests and suites NOT RUN; git diff --check passed. Co-authored-by: Chanhee Lee --- src/cli/export-command.ts | 6 +++--- tests/cli/cli-export-command.test.ts | 23 +++++++++++++++-------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/cli/export-command.ts b/src/cli/export-command.ts index 906065b2e8..739889a026 100644 --- a/src/cli/export-command.ts +++ b/src/cli/export-command.ts @@ -122,10 +122,10 @@ export function exportModelsFromProxyRows( * Resolved ONCE and handed back to `runtimeRequest` as `baseUrl`, so the catalog and the * exported endpoint can never come from two different probes. */ -function proxyV1BaseUrl(root: string, config: OcxConfig): string { +function proxyV1BaseUrl(root: string): string { const url = new URL(root); const port = url.port ? Number(url.port) : url.protocol === "https:" ? 443 : 80; - return opencodeProxyBaseUrl(port, url.hostname, config); + return opencodeProxyBaseUrl(port, url.hostname); } function parseClient(args: string[]): ExportClientId { @@ -193,7 +193,7 @@ export async function handleExportCommand(argv: string[], deps: ExportCommandDep // Discovery can persist selection; preserve the existing exporters' flow. const config = (deps.configImpl ?? loadConfig)(); const models = exportModelsFromProxyRows(rows, config); - built = buildClientConfigText(client, { baseUrl: proxyV1BaseUrl(root, config), models, config }); + built = buildClientConfigText(client, { baseUrl: proxyV1BaseUrl(root), models, config }); } const clientConfig = built.document; const text = built.text; diff --git a/tests/cli/cli-export-command.test.ts b/tests/cli/cli-export-command.test.ts index 03bfd199a7..6d8a513558 100644 --- a/tests/cli/cli-export-command.test.ts +++ b/tests/cli/cli-export-command.test.ts @@ -204,15 +204,22 @@ describe("ocx export --json (accept criterion 1)", () => { expect(parsed.provider.opencodex!.options.baseURL).not.toContain(":10100/"); }); - test("existing OpenCode export also resolves the declared unauthenticated listener", async () => { - const proxy = fakeProxy(); - const result = await run(["--client", "opencode", "--json"], { - baseUrl: proxy.baseUrl, - config: config({ hostname: "0.0.0.0", unauthenticatedLoopbackListener: { enabled: true, port: 10237 } }), + test("OpenCode export keeps the live port when saved listener settings point at a future port", async () => { + const code = await handleExportCommand(["--client", "opencode", "--json"], { + baseUrl: "http://127.0.0.1:10100", + configImpl: () => config({ + hostname: "0.0.0.0", + unauthenticatedLoopbackListener: { enabled: true, port: 10999 }, + }), + fetchImpl: (async input => { + expect(String(input)).toBe("http://127.0.0.1:10100/api/models"); + return Response.json(ROWS); + }) as typeof fetch, }); - expect(result.code).toBe(0); - const parsed = JSON.parse(result.stdout) as { provider: Record }; - expect(parsed.provider.opencodex!.options.baseURL).toBe("http://127.0.0.1:10237/v1"); + expect(code).toBe(0); + const parsed = JSON.parse(stdout()) as { provider: Record }; + expect(parsed.provider.opencodex!.options.baseURL).toBe("http://127.0.0.1:10100/v1"); + expect(parsed.provider.opencodex!.options.baseURL).not.toContain(":10999/"); }); test("disabled rows never reach the exported config", async () => { From d175335943da2a2e64c5dac92a99a99295199335 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 08:12:44 +0900 Subject: [PATCH 035/412] test(container): verify first-start migrations before persistence baseline [skip ci] Remote source startup proved the expected tier/subagent migrations and schema-default persistence, followed by byte-stable second startup. Verify exact seed bytes before startup, six explicit migration/default additions at readiness, and an immutable post-start hash through bootstrap refusal and recreation. Co-authored-by: Buseong Kim Co-authored-by: Ingwannu --- scripts/ci/docker-smoke.ts | 51 +++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/scripts/ci/docker-smoke.ts b/scripts/ci/docker-smoke.ts index eb488cf3b1..e26b11de34 100644 --- a/scripts/ci/docker-smoke.ts +++ b/scripts/ci/docker-smoke.ts @@ -127,6 +127,7 @@ const token = randomBytes(32).toString("hex"); const replacement = randomBytes(32).toString("hex"); const sha256 = (value: string) => createHash("sha256").update(value).digest("hex"); let seededConfigHash = ""; +let readyConfigHash = ""; // Check the loader, including its schema-repair/default-provider fallback, before server startup // and again in each running container. This isolates synthetic inference, not all process egress. @@ -184,6 +185,9 @@ async function inspect() { const stateProbe = ` import { readFileSync, statSync, writeFileSync } from 'node:fs'; import { createHash } from 'node:crypto'; + import { isDeepStrictEqual } from 'node:util'; + const phase = await Bun.stdin.text(); + if (!['seed', 'first-ready', 'steady'].includes(phase)) throw new Error('invalid state phase'); ${fixtureConfigCheck} const homes = ['/home/bun/.opencodex', '/home/bun/.codex']; const uid = process.getuid(); @@ -202,14 +206,51 @@ const stateProbe = ` if (s.uid !== uid || (s.mode & 0o777) !== 0o600 || s.size > 65536) throw new Error('file permissions/size'); return createHash('sha256').update(readFileSync(path)).digest('hex'); }); + // The immutable shipped config was byte-verified before fixture creation. Reconstruct only + // the deliberate fixture route edits, then compare every original key on disk (not loader defaults). + const seed = JSON.parse(readFileSync('docker/config.json', 'utf8')); + seed.providers = { smoke: { adapter: 'openai-responses', baseUrl: 'http://127.0.0.1:9/v1', authMode: 'local', allowPrivateNetwork: true } }; + seed.defaultProvider = 'smoke'; + const persisted = JSON.parse(readFileSync(paths[0], 'utf8')); + const loaded = JSON.parse(JSON.stringify(effective)); + for (const key of Object.keys(seed)) { + for (const config of [persisted, loaded]) { + if (!Object.hasOwn(config, key) || !isDeepStrictEqual(config[key], seed[key])) throw new Error('seed semantics changed'); + } + } + // Independent oracle measured by isolated startup; update only for an intentional contract change. + // Do not derive expected values from runtime migration/default helpers. + const additions = { + appOwnedMemoryBudgetMb: 256, fastRows: true, managementUsageMaxReadBytes: 67108864, + openaiProviderTierVersion: 2, + subagentModels: ['gpt-6-astra', 'gpt-5.6-sol', 'gpt-5.6-terra', 'gpt-5.6-luna', 'gpt-5.5'], + subagentModelsVersion: 1, + }; + for (const config of [persisted, loaded]) { + if (Object.keys(config).some(key => !Object.hasOwn(seed, key) && !Object.hasOwn(additions, key))) throw new Error('unexpected startup config addition'); + for (const [key, expected] of Object.entries(additions)) { + if (phase !== 'seed' || Object.hasOwn(config, key)) { + if (!Object.hasOwn(config, key) || !isDeepStrictEqual(config[key], expected)) throw new Error('startup oracle mismatch'); + } + } + } + if (phase === 'seed' && Object.keys(persisted).some(key => !Object.hasOwn(seed, key))) throw new Error('premature seed addition'); console.log(JSON.stringify(hashes)); `; -async function state() { - const hashes = JSON.parse(await compose(["exec", "-T", "hub", "bun", "-e", stateProbe])) as string[]; +async function state(phase: "seed" | "first-ready" | "steady" = "steady") { + const invocation = phase === "seed" ? ["run", "--rm", "-T", "--no-deps"] : ["exec", "-T"]; + const hashes = JSON.parse(await compose([...invocation, "hub", "bun", "-e", stateProbe], phase)) as string[]; check(hashes.length === 3 && hashes.every(hash => /^[a-f0-9]{64}$/.test(hash)), "invalid state evidence"); - check(hashes[0] === seededConfigHash, "seeded config changed"); check(hashes[1] === sha256(`${token}\n`) && hashes[2] === sha256(fixture), "token/catalog changed"); + if (phase === "first-ready") { + check(!readyConfigHash, "post-start config baseline already established"); + // stateProbe has checked persisted/effective semantics and the independent startup oracle. + readyConfigHash = hashes[0]!; + } else { + check(hashes[0] === (phase === "seed" ? seededConfigHash : readyConfigHash), + phase === "seed" ? "seeded config changed before startup" : "post-start config changed"); + } return JSON.stringify(hashes); } @@ -353,11 +394,13 @@ async function main() { check(/^[a-f0-9]{64}$/.test(seededConfigHash), "invalid seeded config evidence"); progress("bootstrap throwaway token"); await compose(["run", "--rm", "-T", "--no-deps", "hub", "bun", "run", "docker/bootstrap-token.ts"], `${token}\n`); + progress("verify exact seed state before startup"); + await state("seed"); progress("start and check admission"); await compose(["up", "--no-build", "--wait", "--wait-timeout", "120", "hub"], undefined, 150_000); const first = await inspect(); await acceptance(first.url); - const before = await state(); + const before = await state("first-ready"); progress("refuse token replacement"); const refused = await run(["docker", ...composeArgs, "run", "--rm", "-T", "--no-deps", "hub", "bun", "run", "docker/bootstrap-token.ts"], `${replacement}\n`); From 68d90aa37d63e9c51a4d538d009633d0fd33d93b Mon Sep 17 00:00:00 2001 From: JUN <243035832+lidge-jun@users.noreply.github.com> Date: Mon, 7 Sep 2026 08:43:01 +0900 Subject: [PATCH 036/412] docs(claude): describe redacted reasoning replay Carry the documentation-only tail of PR #3815 through 22135366225391494ca98301114486c85be466a4 across eight locales. Runtime and test trees remain identical to the verified protocol candidate. Co-authored-by: SB Yoon <44089734+yansigit@users.noreply.github.com> Co-authored-by: Yumi --- docs-site/src/content/docs/fr/guides/claude-code.md | 1 + docs-site/src/content/docs/guides/claude-code.md | 1 + docs-site/src/content/docs/ja/guides/claude-code.md | 1 + docs-site/src/content/docs/ko/guides/claude-code.md | 1 + docs-site/src/content/docs/ru/guides/claude-code.md | 1 + docs-site/src/content/docs/tr/guides/claude-code.md | 1 + docs-site/src/content/docs/zh-cn/guides/claude-code.md | 1 + docs-site/src/content/docs/zh-tw/guides/claude-code.md | 1 + 8 files changed, 8 insertions(+) diff --git a/docs-site/src/content/docs/fr/guides/claude-code.md b/docs-site/src/content/docs/fr/guides/claude-code.md index 7f1c0a54aa..2ae3940254 100644 --- a/docs-site/src/content/docs/fr/guides/claude-code.md +++ b/docs-site/src/content/docs/fr/guides/claude-code.md @@ -519,6 +519,7 @@ Sur l’adaptateur Anthropic prévu, les blocs signés non masqués (y compris t | Battement de coeur | `ping` | | Deltas de texte | `content_block_start` → `content_block_delta` (texte) → `content_block_stop` | | Résumé ou texte de raisonnement | Bloc `thinking` avec la signature relue, ou une enveloppe de secours `ocxr1` bornée | +| Raisonnement expurgé | Blocs `redacted_thinking` relus depuis l'enveloppe de raisonnement | | Trames d'appel de fonction | Bloc `tool_use` avec `input_json_delta` | | Événement terminal | `message_delta` → `message_stop` | | EOF avant la borne | style 502 `api_error` | diff --git a/docs-site/src/content/docs/guides/claude-code.md b/docs-site/src/content/docs/guides/claude-code.md index f1c1bfbfe1..14dbe92c81 100644 --- a/docs-site/src/content/docs/guides/claude-code.md +++ b/docs-site/src/content/docs/guides/claude-code.md @@ -533,6 +533,7 @@ name. | Heartbeat | `ping` | | Text deltas | `content_block_start` → `content_block_delta` (text) → `content_block_stop` | | Reasoning summary/text | `thinking` block with the replayed signature, or a bounded `ocxr1` fallback envelope | +| Redacted reasoning | `redacted_thinking` blocks replayed from the reasoning envelope | | Function-call frames | `tool_use` block with `input_json_delta` | | Terminal event | `message_delta` → `message_stop` | | EOF before terminal | 502-style `api_error` | diff --git a/docs-site/src/content/docs/ja/guides/claude-code.md b/docs-site/src/content/docs/ja/guides/claude-code.md index 2445e7fa3a..384c3f50df 100644 --- a/docs-site/src/content/docs/ja/guides/claude-code.md +++ b/docs-site/src/content/docs/ja/guides/claude-code.md @@ -387,6 +387,7 @@ role、`tool_use_id` のない `tool_result`、id/name のない `tool_use`、na | Heartbeat | `ping` | | テキスト delta | `content_block_start` → `content_block_delta`(text) → `content_block_stop` | | 推論要約/テキスト | 再生されたシグネチャ、または境界付き `ocxr1` フォールバックを持つ `thinking` ブロック | +| 秘匿化された推論 | 推論エンベロープから再生される `redacted_thinking` ブロック | | Function-call フレーム | `input_json_delta` を持つ `tool_use` ブロック | | 終了イベント | `message_delta` → `message_stop` | | 終了前に EOF | 502 形式 `api_error` | diff --git a/docs-site/src/content/docs/ko/guides/claude-code.md b/docs-site/src/content/docs/ko/guides/claude-code.md index 4e3535d821..676800d1e6 100644 --- a/docs-site/src/content/docs/ko/guides/claude-code.md +++ b/docs-site/src/content/docs/ko/guides/claude-code.md @@ -425,6 +425,7 @@ role, `tool_use_id` 없는 `tool_result`, id/name 없는 `tool_use`, name 없는 | Heartbeat | `ping` | | 텍스트 delta | `content_block_start` → `content_block_delta`(text) → `content_block_stop` | | 추론 요약/텍스트 | 재생된 서명 또는 제한된 `ocxr1` 폴백이 있는 `thinking` 블록 | +| 비공개 추론 | 추론 봉투에서 재생되는 `redacted_thinking` 블록 | | Function-call 프레임 | `input_json_delta`가 있는 `tool_use` 블록 | | 종료 이벤트 | `message_delta` → `message_stop` | | 종료 전에 EOF | 502 형식 `api_error` | diff --git a/docs-site/src/content/docs/ru/guides/claude-code.md b/docs-site/src/content/docs/ru/guides/claude-code.md index 847e79964a..60464bfb90 100644 --- a/docs-site/src/content/docs/ru/guides/claude-code.md +++ b/docs-site/src/content/docs/ru/guides/claude-code.md @@ -413,6 +413,7 @@ id/name; именованный `tool_choice` без имени. | Heartbeat | `ping` | | Текстовые дельты | `content_block_start` → `content_block_delta` (text) → `content_block_stop` | | Резюме/текст рассуждений | Блок `thinking` с повторно переданной подписью или ограниченным резервным конвертом `ocxr1` | +| Скрытое рассуждение | Блоки `redacted_thinking`, воспроизведённые из конверта рассуждений | | Кадры function-call | Блок `tool_use` с `input_json_delta` | | Завершающее событие | `message_delta` → `message_stop` | | EOF до завершающего события | `api_error` в стиле 502 | diff --git a/docs-site/src/content/docs/tr/guides/claude-code.md b/docs-site/src/content/docs/tr/guides/claude-code.md index f1c7fca438..4be81a4de8 100644 --- a/docs-site/src/content/docs/tr/guides/claude-code.md +++ b/docs-site/src/content/docs/tr/guides/claude-code.md @@ -602,6 +602,7 @@ kimlik/ad içermeyen `tool_use`; ad içermeyen adlandırılmış `tool_choice`. | Kalp atışı (Heartbeat) | `ping` | | Metin farkları | `content_block_start` → `content_block_delta` (metin) → `content_block_stop` | | Akıl yürütme özeti/metni | Tekrarlanan imzayı veya sınırlı bir `ocxr1` yedeğini taşıyan `thinking` bloğu | +| Gizli akıl yürütme | Akıl yürütme zarfından yeniden oynatılan `redacted_thinking` blokları | | Fonksiyon çağrısı çerçeveleri | `input_json_delta` ile `tool_use` bloğu | | Terminal olayı | `message_delta` → `message_stop` | | Terminalden önce EOF | 502 tarzı `api_error` | diff --git a/docs-site/src/content/docs/zh-cn/guides/claude-code.md b/docs-site/src/content/docs/zh-cn/guides/claude-code.md index 2b8c0bfa98..dd8bc740b8 100644 --- a/docs-site/src/content/docs/zh-cn/guides/claude-code.md +++ b/docs-site/src/content/docs/zh-cn/guides/claude-code.md @@ -364,6 +364,7 @@ role;`tool_result` 缺少 `tool_use_id`;`tool_use` 缺少 id/name;指定 | 心跳 | `ping` | | 文本增量 | `content_block_start` → `content_block_delta`(文本)→ `content_block_stop` | | 推理摘要/文本 | 带重放签名或有界 `ocxr1` 回退信封的 `thinking` 块 | +| 脱敏推理 | 从推理信封重放的 `redacted_thinking` 块 | | Function-call 帧 | 带 `input_json_delta` 的 `tool_use` 块 | | 终止事件 | `message_delta` → `message_stop` | | 在终止事件前 EOF | 502 风格的 `api_error` | diff --git a/docs-site/src/content/docs/zh-tw/guides/claude-code.md b/docs-site/src/content/docs/zh-tw/guides/claude-code.md index db1c779145..86a3ea0782 100644 --- a/docs-site/src/content/docs/zh-tw/guides/claude-code.md +++ b/docs-site/src/content/docs/zh-tw/guides/claude-code.md @@ -440,6 +440,7 @@ role;`tool_result` 缺少 `tool_use_id`;`tool_use` 缺少 id/name;指定 | 心跳 | `ping` | | 文字增量 | `content_block_start` → `content_block_delta`(文字)→ `content_block_stop` | | 推理摘要/文字 | 帶重播簽名或有界 `ocxr1` 備援信封的 `thinking` 塊 | +| 遮蔽推理 | 從推理信封重播的 `redacted_thinking` 塊 | | Function-call 幀 | 帶 `input_json_delta` 的 `tool_use` 塊 | | 終止事件 | `message_delta` → `message_stop` | | 在終止事件前 EOF | 502 風格的 `api_error` | From e87300809ce67a946ccf2059e80b19d435032738 Mon Sep 17 00:00:00 2001 From: JUN <243035832+lidge-jun@users.noreply.github.com> Date: Mon, 7 Sep 2026 08:49:52 +0900 Subject: [PATCH 037/412] docs(devlog): record verified protocol delivery and remainders --- .../260907_axis3_protocol/000_plan.md | 4 +++ .../260907_axis3_protocol/001_roadmap_lock.md | 0 .../010_prepare_and_verify.md | 0 .../260907_axis3_protocol/011_candidate.md | 0 .../260907_axis3_protocol/020_delivery.md | 15 +++++++++ .../021_delivery_record.md | 31 +++++++++++++++++++ .../260907_axis3_protocol/020_delivery.md | 7 ----- 7 files changed, 50 insertions(+), 7 deletions(-) rename devlog/{_plan => _fin}/260907_axis3_protocol/000_plan.md (90%) rename devlog/{_plan => _fin}/260907_axis3_protocol/001_roadmap_lock.md (100%) rename devlog/{_plan => _fin}/260907_axis3_protocol/010_prepare_and_verify.md (100%) rename devlog/{_plan => _fin}/260907_axis3_protocol/011_candidate.md (100%) create mode 100644 devlog/_fin/260907_axis3_protocol/020_delivery.md create mode 100644 devlog/_fin/260907_axis3_protocol/021_delivery_record.md delete mode 100644 devlog/_plan/260907_axis3_protocol/020_delivery.md diff --git a/devlog/_plan/260907_axis3_protocol/000_plan.md b/devlog/_fin/260907_axis3_protocol/000_plan.md similarity index 90% rename from devlog/_plan/260907_axis3_protocol/000_plan.md rename to devlog/_fin/260907_axis3_protocol/000_plan.md index 36cfe95772..d0511f46ec 100644 --- a/devlog/_plan/260907_axis3_protocol/000_plan.md +++ b/devlog/_fin/260907_axis3_protocol/000_plan.md @@ -11,3 +11,7 @@ Success: roadmap verified, accepted changes reviewed and remotely validated, com Acceptance: (1) thinking then text/tool then result retains order and genuine signatures; opaque blocks remain bounded and malformed/nested signatures fail closed. (2) Grok user agent receives ordinary Responses data without codex.rate_limits/codex.response.metadata, while proxy inspection and normal clients retain metadata. (3) valid external task seeds preserve text/order; absent metadata invalid tool outputs still reject. (4) no credential, admission, cache-retention default, provider/routing policy mutation. (5) final CI must really run relevant tests/typecheck, not skip/cancel or fabricate success. No local suite was run. Final failure permits lower-layer CI for localization; unrelated failures may defer delivery, never count as success. Sources: PRs https://github.com/lidge-jun/opencodex/pull/3815 and /pull/3816; issues /issues/3807 and /issues/3719. Current dev 137d6a727. Evidence snapshots under .tmp/axis3. Public notes contain no unreleased vulnerability detail; any new security investigation stays in scratch. + +## Terminal outcome + +Runtime scope delivered in3830–3832 with the evidence and explicit diagnostic remainders in021_delivery_record.md. Documentation-only completion retains the late source-author rows and archives this unit. Initial planning statements are historical; the delivery record is the outcome authority. diff --git a/devlog/_plan/260907_axis3_protocol/001_roadmap_lock.md b/devlog/_fin/260907_axis3_protocol/001_roadmap_lock.md similarity index 100% rename from devlog/_plan/260907_axis3_protocol/001_roadmap_lock.md rename to devlog/_fin/260907_axis3_protocol/001_roadmap_lock.md diff --git a/devlog/_plan/260907_axis3_protocol/010_prepare_and_verify.md b/devlog/_fin/260907_axis3_protocol/010_prepare_and_verify.md similarity index 100% rename from devlog/_plan/260907_axis3_protocol/010_prepare_and_verify.md rename to devlog/_fin/260907_axis3_protocol/010_prepare_and_verify.md diff --git a/devlog/_plan/260907_axis3_protocol/011_candidate.md b/devlog/_fin/260907_axis3_protocol/011_candidate.md similarity index 100% rename from devlog/_plan/260907_axis3_protocol/011_candidate.md rename to devlog/_fin/260907_axis3_protocol/011_candidate.md diff --git a/devlog/_fin/260907_axis3_protocol/020_delivery.md b/devlog/_fin/260907_axis3_protocol/020_delivery.md new file mode 100644 index 0000000000..714a9c0b8e --- /dev/null +++ b/devlog/_fin/260907_axis3_protocol/020_delivery.md @@ -0,0 +1,15 @@ +# Publish and deliver verified manual chain + +Prerequisite: wp1 accepted-source review and successful final-head remote validation, or source-grounded defer outcome. Publish ordinary PRs targeting dev then the parent branch, using every repository template section. Bodies name source PRs, own layer-only diff, exact final combined CI evidence and explicit lower-layer CI deferral per owner instruction. Do not attest local CI. Preserve original contributor trailers in commits; admin merge with merge commits preserves their identity. + +Read live native-stack membership and head/base identity before merge. Never register a native stack. Parent merges to dev first; retain its branch, retarget child to dev, verify current head and ancestry. If integration tree changes materially, refresh final combined CI before landing. Use --admin and --match-head-commit exact guard. Do not merge into the parent branch by mistake. Refresh origin/dev and prove each merge SHA ancestor. Close superseded source PRs only after equivalent fix is actually landed, with credit and replacement link. Keep #3807 and #3719 open if real reproduction/cache acceptance remains unmet. No release or deployment. + +Record final PR URLs, source-to-delivery mapping, commit authors/trailers, CI run and exact SHA, review verdicts, remaining limitations and preserved dirty-work evidence. No fabricated status checks. Completion: every candidate has an honest disposition, accepted work is landed, unresolved diagnostics explicitly deferred under user direction. + +## Delivery revalidation + +Previous D: all 24 real GitHub runtime producer jobs succeeded at final9b5b670db; same-head remote Bun1.4 full suite20897pass18skip0fail, focused405pass, docs build pass. Aggregate ci is still queued; do not claim the workflow complete or manufacture a status. Its only operation is combining those passed producer results. Maintainer explicitly authorized admin merge, and live dev rules expose no required_status_checks rule. Delivery may use the actual completed producer evidence with aggregation status explicitly disclosed; never waive an unrun or failed runtime producer. + +Carry late source docs #3815 through221353662: eight outbound redacted-reasoning table rows in the same eight locales. Prepared docs-only68d90aa37 has runtime/test trees identical to9b and remote docs build passed. After three runtime PRs land bottom-up, bring this docs-only tail and a final delivery record into a fourth ordinary PR. MOVE the completed owning unit from devlog/_plan/260907_axis3_protocol to devlog/_fin/260907_axis3_protocol and NEW021_delivery.md with actual merge/CI/source-credit evidence and deferred issues. No new runtime tests: exact code-tree equality plus docs build/hygiene are the applicable checks. + +Refresh dev and membership before each guarded admin merge; compare merged runtime tree with tested9b. Any unrelated concurrent dev change requires integration review and appropriate renewed evidence. Original #3815 and #3816 close only after their full carried changes (including docs tail) are landed. #3807 and #3719 remain open for the already recorded limits. diff --git a/devlog/_fin/260907_axis3_protocol/021_delivery_record.md b/devlog/_fin/260907_axis3_protocol/021_delivery_record.md new file mode 100644 index 0000000000..e27fd8b41b --- /dev/null +++ b/devlog/_fin/260907_axis3_protocol/021_delivery_record.md @@ -0,0 +1,31 @@ +# Axis 3 delivery record + +## Delivered runtime + +Ordinary PR chain, merged bottom-up with explicit owner admin authorization: + +| PR | Scope | Merge commit | +| --- | --- | --- | +| [3830](https://github.com/lidge-jun/opencodex/pull/3830) | Claude envelope foundation from #3815 | 2269e076d4222ada6ea3694fb8eed04f91a201d2 | +| [3831](https://github.com/lidge-jun/opencodex/pull/3831) | Grok strict-client projection from #3816 and SSE field correction | 07f8d70a75f088b19f4c9dd849e34034a88ab5f3 | +| [3832](https://github.com/lidge-jun/opencodex/pull/3832) | Replay boundaries, terminal overflow, established-history fixtures | 4349cf3cefdb5ed04575f49023ae34ffe6462e1c | + +Original contributors are retained in commits: SB Yoon and Yumi for #3815, Danh Thanh for #3816. Merge commits preserve the carried commits. The documentation-only tail of #3815 through221353662 is carried with both original contributor trailers in68d90aa37. + +## Verification + +- [Final candidate CI](https://github.com/lidge-jun/opencodex/actions/runs/34065721438) completed SUCCESS: all25 jobs at9b5b670db3e24ae5522c5d61e74c071c71257a26, including Linux, macOS shards/control and all six Windows shards. +- Same-head remote Linux Bun1.4.0 full suite:20897pass18skip0fail with `bun run test -- --parallel=1`; typecheck, privacy scan and documentation build passed. Focused protocol coverage:405pass1skip0fail. +- While CI ran, dev advanced to b65b9d8f2 with BigModel/Raycast changes. Conflict-free integration cc6afe2c97fb423363e99682b906bcb529478688 passed remote typecheck and633tests1skip0fail across15 relevant files, including shared passthrough/registry/layout guards. +- Actual runtime landing tree at4349cf3ce equals the integration tree ccaf0a0383cb3e8808e24576271c861625b506fb exactly. This is integration proof, not a claim that the earlier full CI ran on4349cf3ce. +- Independent Astra high source/security/integration reviews passed. The terminal-closure overflow finding was fixed before acceptance. New-test oracle mistakes found remotely were corrected without weakening exact assistant-array or pairing assertions. +- The earlier parallel remote run had21 catalog timeouts; isolated and final sequential runs passed, and final hosted CI passed. No separate root-cause fix is claimed. +- No local test suite or typecheck ran. All pushes used `--no-verify`. Native stacks and fabricated check statuses were not used. Automatic lower/intermediate CI was deferred or cancelled under the owner's combined-first direction. + +## Explicit remainders + +#3807 remains open: the demonstrated complete external-task envelope is already supported, and current-version raw reporter reproduction is unavailable. New ordinary, stored-ID continuation, v2-trigger and v1-compact fixtures preserve established history without relaxing missing-call-ID validation. + +#3719 remains open: live intended-Anthropic acceptance and controlled cache measurements are unverified. Locally hidden text through the Claude boundary and legacy combined-envelope streaming ordering remain outside the preservation claim. Existing compatibility enforcement, hidden display, authentication, routing and cache-retention defaults remain intact. + +The supplied dirty worktree and existing remote main checkout were preserved; execution used separate task worktrees. No release, deployment or account configuration change was made. diff --git a/devlog/_plan/260907_axis3_protocol/020_delivery.md b/devlog/_plan/260907_axis3_protocol/020_delivery.md deleted file mode 100644 index 050cc76d54..0000000000 --- a/devlog/_plan/260907_axis3_protocol/020_delivery.md +++ /dev/null @@ -1,7 +0,0 @@ -# Publish and deliver verified manual chain - -Prerequisite: wp1 accepted-source review and successful final-head remote validation, or source-grounded defer outcome. Publish ordinary PRs targeting dev then the parent branch, using every repository template section. Bodies name source PRs, own layer-only diff, exact final combined CI evidence and explicit lower-layer CI deferral per owner instruction. Do not attest local CI. Preserve original contributor trailers in commits; admin merge with merge commits preserves their identity. - -Read live native-stack membership and head/base identity before merge. Never register a native stack. Parent merges to dev first; retain its branch, retarget child to dev, verify current head and ancestry. If integration tree changes materially, refresh final combined CI before landing. Use --admin and --match-head-commit exact guard. Do not merge into the parent branch by mistake. Refresh origin/dev and prove each merge SHA ancestor. Close superseded source PRs only after equivalent fix is actually landed, with credit and replacement link. Keep #3807 and #3719 open if real reproduction/cache acceptance remains unmet. No release or deployment. - -Record final PR URLs, source-to-delivery mapping, commit authors/trailers, CI run and exact SHA, review verdicts, remaining limitations and preserved dirty-work evidence. No fabricated status checks. Completion: every candidate has an honest disposition, accepted work is landed, unresolved diagnostics explicitly deferred under user direction. From 91fba4b4cd3d31e79b7d404b3d201c7b9896f67d Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 07:41:25 +0900 Subject: [PATCH 038/412] ci: gate source-build Docker lifecycle verification [skip ci] Add Docker packaging paths to the existing CI scope, execute the isolated lifecycle smoke, and include it in the aggregate gate. Extend the workflow oracle and typecheck the new script. Final integration will be dispatched explicitly with lane=all; redundant lower-layer runs are intentionally skipped. Co-authored-by: Buseong Kim Co-authored-by: Ingwannu --- .github/workflows/ci.yml | 31 ++++++++++++++++- .../src/content/docs/guides/remote-hub.md | 6 ++++ tests/ci-workflows/ci-workflows.test.ts | 34 ++++++++++++++++++- 3 files changed, 69 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8c15cb696a..a6c0e7ab1a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,6 +26,10 @@ on: push: branches: [main, preview, dev] paths: + - "Dockerfile" + - "compose.yaml" + - ".dockerignore" + - "docker/**" - "src/**" - "bin/**" - "tests/**" @@ -180,6 +184,10 @@ jobs: # start the workflow so the aggregate check exists, while these # paths decide whether the expensive test jobs need to run. ci: + - 'Dockerfile' + - 'compose.yaml' + - '.dockerignore' + - 'docker/**' - 'src/**' - 'bin/**' - 'tests/**' @@ -423,6 +431,7 @@ jobs: run: | bun x tsc --noEmit bun x tsc --noEmit -p tests/tsconfig.doctor-service-memory-contract.json + bun x tsc --noEmit --strict --target ESNext --module ESNext --moduleResolution bundler --types bun-types --skipLibCheck scripts/ci/docker-smoke.ts - name: GUI tests run: cd gui && bun test --isolate tests @@ -908,6 +917,26 @@ jobs: bun run scripts/keyring-smoke.ts ' + # Exercise the source-build Compose contract, including real volume reuse. + # Host fixtures cannot prove image construction or container recreation. + docker-smoke: + name: docker smoke + needs: changes + if: github.event_name != 'pull_request' || needs.changes.outputs.ci == 'true' + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - name: Checkout + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 + with: + persist-credentials: false + + - name: Setup project Bun + uses: ./.github/actions/setup-project-bun + + - name: Build, start, and recreate the container + run: bun scripts/ci/docker-smoke.ts + npm-global-smoke: name: npm-global ${{ matrix.os }} needs: changes @@ -986,7 +1015,7 @@ jobs: # direct dependencies only, so a failing `select-windows-runner` would # otherwise reach this gate as nothing at all while its dependents report # `skipped` — which the gate is required to read as a deliberate skip. - needs: [changes, select-windows-runner, test, storage-policy, api-usage, gates, platform-macos, macos-control, platform-windows, keyring-smoke, npm-global-smoke] + needs: [changes, select-windows-runner, test, storage-policy, api-usage, gates, platform-macos, macos-control, platform-windows, keyring-smoke, docker-smoke, npm-global-smoke] runs-on: ubuntu-latest timeout-minutes: 5 steps: diff --git a/docs-site/src/content/docs/guides/remote-hub.md b/docs-site/src/content/docs/guides/remote-hub.md index 460fe4651d..6a2b2a33bd 100644 --- a/docs-site/src/content/docs/guides/remote-hub.md +++ b/docs-site/src/content/docs/guides/remote-hub.md @@ -291,6 +291,12 @@ unreadable, a non-loopback hub must not be accepted as ready. Never treat livene `docker compose down --volumes` as destructive: it deletes configuration, OAuth credentials, usage history, the data-plane token, and persisted Codex state together. +Cross-platform CI builds the source image and checks startup, data-plane token admission, and +container recreation using an isolated Compose project with throwaway credentials. It verifies that +both named volumes and a synthetic catalog survive replacement. This check does not validate a +real provider account, OAuth callback, custom mount migration, or every CPU architecture; perform +the authenticated routed-response check above for your deployment. + ## Rollback Inspect existing Serve mappings before changing them. `tailscale serve reset` removes every mapping diff --git a/tests/ci-workflows/ci-workflows.test.ts b/tests/ci-workflows/ci-workflows.test.ts index ec2c919c45..77192bbb48 100644 --- a/tests/ci-workflows/ci-workflows.test.ts +++ b/tests/ci-workflows/ci-workflows.test.ts @@ -506,17 +506,21 @@ describe("GitHub Actions hardening", () => { // allowlist. PRs always create the workflow and aggregate check; this list // decides whether the costly jobs run. Pin the entire list on both paths. const ciPaths = [ + ".dockerignore", ".gitattributes", ".github/workflows/ci.yml", ".github/workflows/enforce-pr-target.yml", ".github/workflows/release.yml", ".github/workflows/stale-needs-info.yml", ".npmignore", + "Dockerfile", "LICENSE", "README.md", "assets/**", "bin/**", "bun.lock", + "compose.yaml", + "docker/**", "gui/**", "package.json", "scripts/**", @@ -563,7 +567,7 @@ describe("GitHub Actions hardening", () => { expect(scopeIndex).toBeGreaterThan(filterIndex); const scopedCondition = "github.event_name != 'pull_request' || needs.changes.outputs.ci == 'true'"; - for (const jobName of ["test", "storage-policy", "gates", "platform-macos", "keyring-smoke"]) { + for (const jobName of ["test", "storage-policy", "gates", "platform-macos", "keyring-smoke", "docker-smoke"]) { const job = ci.jobs?.[jobName] as { needs?: string; if?: string } | undefined; expect(`${jobName}:${job?.needs}`).toBe(`${jobName}:changes`); expect(`${jobName}:${job?.if}`).toBe(`${jobName}:${scopedCondition}`); @@ -573,6 +577,34 @@ describe("GitHub Actions hardening", () => { expect(macosControlIf?.if).toBe("github.event_name == 'workflow_dispatch'"); }); + test("Docker smoke executes the source-build lifecycle and gates its result", async () => { + const ci = Bun.YAML.parse(await readText(".github/workflows/ci.yml")) as { + jobs?: Record; + steps?: Array<{ name?: string; run?: string; if?: string; "continue-on-error"?: boolean }>; + }>; + }; + const smoke = ci.jobs?.["docker-smoke"]; + expect(smoke?.["runs-on"]).toBe("ubuntu-latest"); + expect(smoke?.["timeout-minutes"]).toBe(20); + expect(smoke?.["continue-on-error"]).toBeUndefined(); + expect(smoke?.permissions).toBeUndefined(); // Inherits workflow contents:read. + const execution = smoke?.steps?.find(step => + hasExactShellCommand(step.run, "bun scripts/ci/docker-smoke.ts")); + expect(execution).toBeDefined(); + expect(execution?.if).toBeUndefined(); + expect(execution?.["continue-on-error"]).toBeUndefined(); + expect(ci.jobs?.ci?.needs).toContain("docker-smoke"); + const typecheck = ci.jobs?.gates?.steps?.find(step => step.name === "Typecheck"); + expect(hasExactShellCommand(typecheck?.run, + "bun x tsc --noEmit --strict --target ESNext --module ESNext --moduleResolution bundler --types bun-types --skipLibCheck scripts/ci/docker-smoke.ts", + )).toBe(true); + }); + test("cross-platform CI keeps the GUI lint and build gates", async () => { // Review finding (PR #97): the GUI build gate was silently dropped once; assert the // enhanced gate (PR #99) stays wired so broken GUI builds cannot merge unnoticed. From 15fa571554d8eda59b91ca05a931dcb98c2c8a2c Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 08:54:51 +0900 Subject: [PATCH 039/412] fix(container): retain routed catalog across managed recreation [skip ci] Real Docker CI exposed foreground shutdown stripping routed catalog rows despite persistent volumes. Declare the existing service lifecycle mode in the runtime image so Docker-managed stop/recreate preserves routed state. Keep the routed fixture and exact-byte checks. Two independent lifecycle/security reviews accepted this bounded packaging change; isolated CLI before/after reproduced the defect and preservation with service mode. Co-authored-by: Buseong Kim Co-authored-by: Ingwannu --- Dockerfile | 3 +++ .../025_container_lifecycle_mode.md | 10 ++++++++++ docs-site/src/content/docs/guides/remote-hub.md | 6 +++++- scripts/ci/docker-smoke.ts | 1 + tests/service/container-bootstrap.test.ts | 1 + 5 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 devlog/_plan/260907_platform_validation/025_container_lifecycle_mode.md diff --git a/Dockerfile b/Dockerfile index 1ed000743d..5987bfa991 100644 --- a/Dockerfile +++ b/Dockerfile @@ -25,7 +25,10 @@ RUN cd gui && bun run build FROM ${BUN_IMAGE} AS runtime WORKDIR /home/bun/app +# Docker supervises this foreground process; retain routed state on stop/recreate. +# This uses the existing service lifecycle mode and does not install a service manager. ENV NODE_ENV=production \ + OCX_SERVICE=1 \ OPENCODEX_HOME=/home/bun/.opencodex \ CODEX_HOME=/home/bun/.codex \ OCX_API_TOKEN_FILE=/home/bun/.opencodex/service-api-token diff --git a/devlog/_plan/260907_platform_validation/025_container_lifecycle_mode.md b/devlog/_plan/260907_platform_validation/025_container_lifecycle_mode.md new file mode 100644 index 0000000000..c86f4fc765 --- /dev/null +++ b/devlog/_plan/260907_platform_validation/025_container_lifecycle_mode.md @@ -0,0 +1,10 @@ +# Container lifecycle mode + +Amendment after real Docker recreation verification. Docker supervises the foreground hub and must retain persisted routed state across replacement. + +MODIFY Dockerfile runtime ENV: set existing OCX_SERVICE=1, with no service manager installation or privilege change. Preserve image digest, foreground CMD, listener authentication, separate writable homes and read-only root. +MODIFY scripts/ci/docker-smoke.ts: assert the actual container process receives service lifecycle mode. Retain the routed synthetic slug and exact token/catalog/config hashes across graceful recreation. +MODIFY tests/service/container-bootstrap.test.ts: include the runtime ENV declaration in the existing packaging contract. +MODIFY docs-site/src/content/docs/guides/remote-hub.md: document service-mode foreground lifecycle, Compose restart/recreation, and the limit on other dashboard restart paths. + +Independent Astra high lifecycle/security review accepted the bounded packaging change. Actual remote CLI comparison confirmed preservation with service mode. Final image CI must prove the same real container lifecycle; no local tests or Docker execution. This does not change shared CLI cleanup, restart policy, or authentication code. diff --git a/docs-site/src/content/docs/guides/remote-hub.md b/docs-site/src/content/docs/guides/remote-hub.md index 2334303be7..460fe4651d 100644 --- a/docs-site/src/content/docs/guides/remote-hub.md +++ b/docs-site/src/content/docs/guides/remote-hub.md @@ -167,7 +167,11 @@ opencodex does not publish an official container image. The repository does main [`compose.yaml`](https://github.com/lidge-jun/opencodex/blob/main/compose.yaml), and a narrow `.dockerignore`. The build pins the multi-platform Bun 1.4.0 image index by digest, runs the proxy as the non-root `bun` user, keeps the root filesystem read-only, drops Linux capabilities, and publishes -only the data listener on the host's `127.0.0.1:10100` by default. +only the data listener on the host's `127.0.0.1:10100` by default. The foreground process uses +`OCX_SERVICE=1`, so stopping or recreating the container preserves routed Codex state instead +of restoring a native desktop configuration. Docker supplies supervision; no OS service manager +is installed in the image. Use Compose to restart/recreate the container; this does not extend +support to every dashboard restart path. The image seeds a first-run `hub` configuration that binds the container listener to `0.0.0.0`. Before the first normal start, stream a freshly generated data-plane token into the bootstrap helper. diff --git a/scripts/ci/docker-smoke.ts b/scripts/ci/docker-smoke.ts index e26b11de34..c2a7ec0ee2 100644 --- a/scripts/ci/docker-smoke.ts +++ b/scripts/ci/docker-smoke.ts @@ -190,6 +190,7 @@ const stateProbe = ` if (!['seed', 'first-ready', 'steady'].includes(phase)) throw new Error('invalid state phase'); ${fixtureConfigCheck} const homes = ['/home/bun/.opencodex', '/home/bun/.codex']; + if (process.env.OCX_SERVICE !== '1') throw new Error('image service lifecycle mode missing'); const uid = process.getuid(); if (uid === 0) throw new Error('root user'); const status = readFileSync('/proc/self/status', 'utf8'); diff --git a/tests/service/container-bootstrap.test.ts b/tests/service/container-bootstrap.test.ts index ada807d1d0..9eec8edd6b 100644 --- a/tests/service/container-bootstrap.test.ts +++ b/tests/service/container-bootstrap.test.ts @@ -63,6 +63,7 @@ describe("container deployment contract", () => { const runtime = readFileSync(repoPath("Dockerfile"), "utf8").split(" AS runtime")[1]!; expect(runtime).toContain("OPENCODEX_HOME=/home/bun/.opencodex"); expect(runtime).toContain("CODEX_HOME=/home/bun/.codex"); + expect(runtime).toContain("OCX_SERVICE=1"); expect(runtime).toContain("install -d -m 0700 -o bun -g bun /home/bun/.opencodex /home/bun/.codex"); expect(runtime).toContain('VOLUME ["/home/bun/.opencodex", "/home/bun/.codex"]'); expect(runtime).toContain("USER bun"); From 6f2ad1ef32c113ff5827c58959c85cefa923b15c Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 07:52:43 +0900 Subject: [PATCH 040/412] ci: select explicit-file typecheck mode for TypeScript 7 [skip ci] Final run 34064754947 passed root typechecks but rejected the standalone smoke-script command with TS5112. Explicit --ignoreConfig retains all strict script flags and preserves the existing root/project checks. Co-authored-by: Buseong Kim Co-authored-by: Ingwannu --- .github/workflows/ci.yml | 2 +- tests/ci-workflows/ci-workflows.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a6c0e7ab1a..00abe5ec24 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -431,7 +431,7 @@ jobs: run: | bun x tsc --noEmit bun x tsc --noEmit -p tests/tsconfig.doctor-service-memory-contract.json - bun x tsc --noEmit --strict --target ESNext --module ESNext --moduleResolution bundler --types bun-types --skipLibCheck scripts/ci/docker-smoke.ts + bun x tsc --ignoreConfig --noEmit --strict --target ESNext --module ESNext --moduleResolution bundler --types bun-types --skipLibCheck scripts/ci/docker-smoke.ts - name: GUI tests run: cd gui && bun test --isolate tests diff --git a/tests/ci-workflows/ci-workflows.test.ts b/tests/ci-workflows/ci-workflows.test.ts index 77192bbb48..c967f9d4c0 100644 --- a/tests/ci-workflows/ci-workflows.test.ts +++ b/tests/ci-workflows/ci-workflows.test.ts @@ -601,7 +601,7 @@ describe("GitHub Actions hardening", () => { expect(ci.jobs?.ci?.needs).toContain("docker-smoke"); const typecheck = ci.jobs?.gates?.steps?.find(step => step.name === "Typecheck"); expect(hasExactShellCommand(typecheck?.run, - "bun x tsc --noEmit --strict --target ESNext --module ESNext --moduleResolution bundler --types bun-types --skipLibCheck scripts/ci/docker-smoke.ts", + "bun x tsc --ignoreConfig --noEmit --strict --target ESNext --module ESNext --moduleResolution bundler --types bun-types --skipLibCheck scripts/ci/docker-smoke.ts", )).toBe(true); }); From a3c2eb56216ac4f3331e7bc4b43b47e1d5d2ac6c Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 09:15:21 +0900 Subject: [PATCH 041/412] fix(anthropic): expire retained quota measurements at known resets [skip ci] Address #3825 review discussion_r3945728864. Retained standard and model-specific measurements become unknown after their known reset, including idle reads, hydration, persistence and joined failed probes. Reset-only headers cannot renew old usage. Keep unknown-reset behavior, probe clocks, unavailability and credential policy unchanged. Add real quota-evidence/manual-selection and persistence regressions; no local suites run per maintainer instruction. Original #3809 credit remains in ancestor f215f79b4. --- .../src/content/docs/guides/claude-code.md | 4 +- .../docs/reference/configuration/providers.md | 7 +- src/providers/quota.ts | 67 ++++- .../anthropic-ratelimit-headers.test.ts | 237 +++++++++++++++++- 4 files changed, 299 insertions(+), 16 deletions(-) diff --git a/docs-site/src/content/docs/guides/claude-code.md b/docs-site/src/content/docs/guides/claude-code.md index 2e841e205c..720a303b00 100644 --- a/docs-site/src/content/docs/guides/claude-code.md +++ b/docs-site/src/content/docs/guides/claude-code.md @@ -36,7 +36,9 @@ Operational contract when enabled: two the response carries is recorded for that account — each window independently, and a refusal counts as well as a success. Usage-aware selection works from ordinary traffic, without waiting for a dashboard poll. Headers preserve model-specific quota windows and do - not postpone usage probes or clear a failed usage probe's unavailable status. + not postpone usage probes or clear a failed usage probe's unavailable status. Measurements + whose known reset time has passed are discarded as unknown, including retained model-specific + windows. Values without a known reset are preserved; missing data is never reported as zero usage. - Affinity is **process-local** (lost on proxy restart). - **401/403** credential failures quarantine the account (`needsReauth`) so it is excluded from selection until re-authenticated. diff --git a/docs-site/src/content/docs/reference/configuration/providers.md b/docs-site/src/content/docs/reference/configuration/providers.md index c80176868e..710c069b24 100644 --- a/docs-site/src/content/docs/reference/configuration/providers.md +++ b/docs-site/src/content/docs/reference/configuration/providers.md @@ -446,7 +446,12 @@ of those two a given response carries is recorded against that account — each on refusals as well as successes. Usage-aware selection therefore works from the accounts you actually use, without waiting for the dashboard Providers page to poll them. These readings refresh the existing row rather than replacing it, so the model-scoped weekly bars that only the usage -endpoint reports are preserved. Header observations do not postpone usage probes or clear a failed +endpoint reports are preserved until their known reset time passes. Expired measurements become +unknown, including retained standard windows omitted by later headers. A reset-only header cannot +extend an older utilization measurement. Values with no known reset retain their existing behavior; +missing measurements are never replaced with zero usage. + +Header observations do not postpone usage probes or clear a failed probe's unavailable status. After restart, cached Anthropic observations remain available while the next quota read probes again, because the saved observations do not include the probe clock. diff --git a/src/providers/quota.ts b/src/providers/quota.ts index dbdb6699f7..5dcb69beb3 100644 --- a/src/providers/quota.ts +++ b/src/providers/quota.ts @@ -1552,6 +1552,37 @@ type AccountQuotaCacheEntry = { identity?: string; isCurrent?: () => boolean; }; +/** Expired measurements become unknown; missing reset evidence never implies a fresh allowance. */ +function normalizeAnthropicQuota(quota: ProviderQuota | null | undefined, now: number): ProviderQuota | null { + if (!quota) return null; + const expired = (resetAt: number | undefined): boolean => typeof resetAt === "number" + && Number.isFinite(resetAt) && resetAt > 0 && resetAt <= now; + let result = quota; + for (const [percent, reset] of [ + ["fiveHourPercent", "fiveHourResetAt"], + ["weeklyPercent", "weeklyResetAt"], + ["monthlyPercent", "monthlyResetAt"], + ] as const) { + if (!expired(quota[reset])) continue; + if (result === quota) result = { ...quota }; + delete result[percent]; + delete result[reset]; + } + // Persisted rows validate only the outer quota object, so custom data may be malformed. + if (quota.customWindows !== undefined) { + const windows = Array.isArray(quota.customWindows) ? quota.customWindows : []; + const retained = windows.filter(window => window !== null && typeof window === "object" + && typeof window.label === "string" && typeof window.percent === "number" + && Number.isFinite(window.percent) && !expired(window.resetAt)); + if (!Array.isArray(quota.customWindows) || retained.length !== windows.length) { + if (result === quota) result = { ...quota }; + if (retained.length) result.customWindows = retained; + else delete result.customWindows; + } + } + return hasQuotaRows(result) ? result : null; +} + const accountQuotaCache = new Map(); let explicitAccountEpoch = 0; @@ -1570,15 +1601,21 @@ function hydrateAccountQuotaCache(): void { for (const [key, quota] of readPersistedAccountQuotas()) { // Disk stores observation time, not the Anthropic usage probe's clock. if (!accountQuotaCache.has(key)) { - accountQuotaCache.set(key, { ts: key.startsWith("anthropic\u0000") ? 0 : quota.updatedAt, quota }); + const anthropic = key.startsWith("anthropic\u0000"); + accountQuotaCache.set(key, { + ts: anthropic ? 0 : quota.updatedAt, + quota: anthropic ? normalizeAnthropicQuota(quota, Date.now()) : quota, + }); } } } function persistAccountQuotaCache(): void { schedulePersistAccountQuotas(function* () { + const now = Date.now(); for (const [key, entry] of accountQuotaCache) { - if (entry.quota) yield [key, entry.quota] as [string, ProviderQuota]; + const quota = key.startsWith("anthropic\u0000") ? normalizeAnthropicQuota(entry.quota, now) : entry.quota; + if (quota) yield [key, quota] as [string, ProviderQuota]; } }); } @@ -1628,7 +1665,7 @@ function accountCacheKey(provider: string, accountId: string): string { export function getCachedProviderAccountQuota(provider: string, accountId: string): ProviderQuota | null { const entry = accountQuotaCache.get(accountCacheKey(provider, accountId)); if (entry?.isCurrent && !entry.isCurrent()) return null; - return entry?.quota ?? null; + return provider === "anthropic" ? normalizeAnthropicQuota(entry?.quota, Date.now()) : entry?.quota ?? null; } /** Test-only: seed or clear the per-account quota cache without probing upstream. */ @@ -1661,9 +1698,9 @@ export function parseAnthropicRateLimitHeaders(headers: Headers): ProviderQuota const weeklyResetAt = anthropicHeaderResetAt(headers.get("anthropic-ratelimit-unified-7d-reset")); return { ...(fiveHourPercent !== undefined ? { fiveHourPercent } : {}), - ...(fiveHourResetAt !== undefined ? { fiveHourResetAt } : {}), + ...(fiveHourPercent !== undefined && fiveHourResetAt !== undefined ? { fiveHourResetAt } : {}), ...(weeklyPercent !== undefined ? { weeklyPercent } : {}), - ...(weeklyResetAt !== undefined ? { weeklyResetAt } : {}), + ...(weeklyPercent !== undefined && weeklyResetAt !== undefined ? { weeklyResetAt } : {}), updatedAt: Date.now(), }; } @@ -1700,7 +1737,9 @@ export function recordAnthropicAccountQuotaFromHeaders( ...previous, // Headers do not prove that the last usage probe succeeded. ts: previous?.ts ?? 0, - quota: { ...(previous?.quota ?? {}), ...observed }, + quota: normalizeAnthropicQuota({ + ...normalizeAnthropicQuota(previous?.quota, observed.updatedAt), ...observed, + }, observed.updatedAt), }); persistAccountQuotaCache(); } @@ -1978,7 +2017,9 @@ async function fetchAccountQuota( const key = accountCacheKey(provider, accountId); const writerGeneration = captureConfigGeneration(); const cached = accountQuotaCache.get(key); - if (!forceRefresh && cached && Date.now() - cached.ts < ACCOUNT_QUOTA_TTL_MS) return cached; + if (!forceRefresh && cached && Date.now() - cached.ts < ACCOUNT_QUOTA_TTL_MS) { + return provider === "anthropic" ? { ...cached, quota: normalizeAnthropicQuota(cached.quota, Date.now()) } : cached; + } const joinable = accountQuotaInflight.get(key); if (joinable) return joinable; @@ -2016,7 +2057,8 @@ async function fetchAccountQuota( const entry: AccountQuotaCacheEntry = { ts: Date.now(), // Settle once for all joiners against observations committed during the probe. - quota: (provider === "anthropic" ? accountQuotaCache.get(key)?.quota : cached?.quota) ?? null, + quota: provider === "anthropic" + ? normalizeAnthropicQuota(accountQuotaCache.get(key)?.quota, Date.now()) : cached?.quota ?? null, unavailable: true, }; if (mayCommitAccountQuotaKey(key, writerGeneration)) { @@ -2026,7 +2068,9 @@ async function fetchAccountQuota( } return entry; } - const entry: AccountQuotaCacheEntry = { ts: Date.now(), quota }; + const entry: AccountQuotaCacheEntry = { + ts: Date.now(), quota: provider === "anthropic" ? normalizeAnthropicQuota(quota, Date.now()) : quota, + }; if (mayCommitAccountQuotaKey(key, writerGeneration)) { accountQuotaCache.set(key, entry); // Exhaustion state rides the SAME commit guard as the quota row: a probe from a @@ -2038,7 +2082,8 @@ async function fetchAccountQuota( } catch { const entry: AccountQuotaCacheEntry = { ts: Date.now(), - quota: (provider === "anthropic" ? accountQuotaCache.get(key)?.quota : cached?.quota) ?? null, + quota: provider === "anthropic" + ? normalizeAnthropicQuota(accountQuotaCache.get(key)?.quota, Date.now()) : cached?.quota ?? null, unavailable: true, }; if (mayCommitAccountQuotaKey(key, writerGeneration)) { @@ -2070,7 +2115,7 @@ export async function fetchProviderAccountQuotas( const entry = await fetchAccountQuota(provider, account.id, forceRefresh, providerConfig); const result: ProviderAccountQuota = { accountId: account.id, - quota: entry.quota, + quota: provider === "anthropic" ? normalizeAnthropicQuota(entry.quota, Date.now()) : entry.quota, ...(entry.unavailable ? { unavailable: true as const } : {}), }; if (!explicitAccountReader(provider)) return result; diff --git a/tests/adapters/anthropic/anthropic-ratelimit-headers.test.ts b/tests/adapters/anthropic/anthropic-ratelimit-headers.test.ts index 21ae2d8489..77989064ff 100644 --- a/tests/adapters/anthropic/anthropic-ratelimit-headers.test.ts +++ b/tests/adapters/anthropic/anthropic-ratelimit-headers.test.ts @@ -1,6 +1,6 @@ /** Anthropic response observations must preserve account usage and probe semantics. */ -import { afterEach, beforeEach, describe, expect, test } from "bun:test"; -import { mkdtempSync, writeFileSync } from "node:fs"; +import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test"; +import { mkdtempSync, readFileSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { @@ -9,8 +9,11 @@ import { forgetAnthropicFailoverQuorum, getAnthropicAccountHealthSnapshot, rotateAnthropicAccountOn429, + resetAnthropicRoutingForManualSelection, + resolveAnthropicAccountForSession, } from "../../../src/oauth/anthropic-routing"; import { projectStoredOAuthAccountHealth } from "../../../src/oauth/health"; +import { quotaEvidenceForCandidate } from "../../../src/routing/quota"; import { clearAccountQuotaCache, fetchProviderAccountQuotas, @@ -22,7 +25,7 @@ import { setCachedProviderAccountQuotaForTests, sweepExpiredProviderAccountQuotaRows, } from "../../../src/providers/quota"; -import { getAccountSet, saveCredential } from "../../../src/oauth/store"; +import { getAccountSet, saveCredential, setActiveAccount } from "../../../src/oauth/store"; import { clearPoolRotationState } from "../../../src/codex/pool-rotation"; import { removeTreeWithRetry } from "../../helpers/remove-tree"; import type { OcxConfig } from "../../../src/types"; @@ -526,3 +529,231 @@ describe("Anthropic malformed deadlines and partial windows", () => { }); }); }); + +describe("Anthropic known-reset expiry", () => { + const start = 1_800_000_000_000; + let now: number; + + beforeEach(() => { + now = start; + Date.now = () => now; + }); + + function observe(id: string, headers: Record = { + "anthropic-ratelimit-unified-5h-utilization": "0.41", + }): void { + recordAnthropicAccountQuotaFromHeaders(id, new Headers(headers), 0); + } + + test("headers expire only known elapsed custom windows without mutating their source", async () => { + const [id] = await seed(1); + const saved = { + fiveHourPercent: 10, + customWindows: [ + { label: "Opus", percent: 100, resetAt: start + 60_000 }, + { label: "Sonnet", percent: 90, resetAt: start + 600_000 }, + { label: "Fable", percent: 70 }, + { label: "Unknown reset", percent: 60, resetAt: 0 }, + ], + updatedAt: start, + }; + setCachedProviderAccountQuotaForTests("anthropic", id!, saved); + now += 120_000; + observe(id!); + const quota = getCachedProviderAccountQuota("anthropic", id!); + expect(quota?.customWindows).toEqual(saved.customWindows.slice(1)); + expect(quota?.fiveHourPercent).toBe(41); + expect(quota?.updatedAt).toBe(now); + expect(saved.customWindows).toHaveLength(4); + expect(saved.updatedAt).toBe(start); + now += 30_000; + observe(id!); + expect(getCachedProviderAccountQuota("anthropic", id!)?.customWindows).toEqual(saved.customWindows.slice(1)); + }); + + for (const [percent, reset, observedWindow] of [ + ["fiveHourPercent", "fiveHourResetAt", "7d"], + ["weeklyPercent", "weeklyResetAt", "5h"], + ["monthlyPercent", "monthlyResetAt", "5h"], + ] as const) { + test(`partial headers remove the expired ${percent} pair without inventing zero`, async () => { + const [id] = await seed(1); + setCachedProviderAccountQuotaForTests("anthropic", id!, { + [percent]: 100, [reset]: start + 60_000, updatedAt: start, + }); + now += 60_000; + observe(id!, { [`anthropic-ratelimit-unified-${observedWindow}-utilization`]: "0.2" }); + const quota = getCachedProviderAccountQuota("anthropic", id!); + expect(quota).not.toBeNull(); + expect(quota?.[percent]).toBeUndefined(); + expect(quota?.[reset]).toBeUndefined(); + }); + } + + test("standard windows without reset evidence remain known", async () => { + const [id] = await seed(1); + setCachedProviderAccountQuotaForTests("anthropic", id!, { weeklyPercent: 100, updatedAt: start }); + now += 120_000; + observe(id!); + expect(getCachedProviderAccountQuota("anthropic", id!)?.weeklyPercent).toBe(100); + }); + + test("a reset-only header cannot extend retained usage even before the original reset", async () => { + const [id] = await seed(1); + setCachedProviderAccountQuotaForTests("anthropic", id!, { + fiveHourPercent: 10, weeklyPercent: 100, weeklyResetAt: start + 60_000, updatedAt: start, + }); + now += 30_000; + observe(id!, { + "anthropic-ratelimit-unified-5h-utilization": "0.2", + "anthropic-ratelimit-unified-7d-utilization": "invalid", + "anthropic-ratelimit-unified-7d-reset": String((start + 600_000) / 1000), + }); + expect(getCachedProviderAccountQuota("anthropic", id!)?.weeklyResetAt).toBe(start + 60_000); + now += 30_000; + expect(getCachedProviderAccountQuota("anthropic", id!)?.weeklyPercent).toBeUndefined(); + expect(getCachedProviderAccountQuota("anthropic", id!)?.weeklyResetAt).toBeUndefined(); + observe(id!, { + "anthropic-ratelimit-unified-7d-utilization": "0.3", + "anthropic-ratelimit-unified-7d-reset": String((start + 600_000) / 1000), + }); + expect(getCachedProviderAccountQuota("anthropic", id!)).toMatchObject({ + weeklyPercent: 30, weeklyResetAt: start + 600_000, + }); + }); + + test("idle cache reads cross a reset without another observation or probe", async () => { + const [id] = await seed(1); + const quota = { customWindows: [{ label: "Opus", percent: 100, resetAt: start + 60_000 }], updatedAt: start }; + setCachedProviderAccountQuotaForTests("anthropic", id!, quota); + setCachedProviderAccountQuotaForTests("kiro", "untouched", quota); + const candidate = { provider: "anthropic", model: "claude-opus-4-6", accountRef: id! }; + now += 59_999; + expect(getCachedProviderAccountQuota("anthropic", id!)).toEqual(quota); + expect(quotaEvidenceForCandidate(candidate)).toMatchObject({ known: true, exhausted: true, headroom: 0 }); + now++; + expect(getCachedProviderAccountQuota("anthropic", id!)).toBeNull(); + expect(quotaEvidenceForCandidate(candidate)).toEqual({ known: false }); + const [row] = await fetchProviderAccountQuotas("anthropic"); + expect(row?.quota).toBeNull(); + expect(row?.unavailable).toBeUndefined(); + expect(getCachedProviderAccountQuota("kiro", "untouched")).toBe(quota); + }); + + test("expired Opus evidence stops suppressing an otherwise healthy manual selection", async () => { + const [a, b] = await seed(2); + setCachedProviderAccountQuotaForTests("anthropic", a!, { + fiveHourPercent: 30, customWindows: [{ label: "Opus", percent: 100, resetAt: start + 60_000 }], updatedAt: start, + }); + setCachedProviderAccountQuotaForTests("anthropic", b!, { fiveHourPercent: 11, updatedAt: start }); + await setActiveAccount("anthropic", a!); + resetAnthropicRoutingForManualSelection(a!); + const config = poolEnabled(); + config.anthropicAccountPool = { enabled: true, strategy: "quota", autoSwitchThreshold: 20 }; + const candidate = { provider: "anthropic", model: "claude-opus-4-6", accountRef: a! }; + expect(resolveAnthropicAccountForSession(null, config, now).accountId).toBe(b); + expect(quotaEvidenceForCandidate(candidate)).toMatchObject({ known: true, exhausted: true, headroom: 0 }); + now += 60_000; + expect(resolveAnthropicAccountForSession(null, config, now)).toMatchObject({ accountId: a, reason: "manual" }); + expect(quotaEvidenceForCandidate(candidate)).toMatchObject({ known: true, exhausted: false, headroom: 0.7 }); + }); + + for (const failure of ["http", "network"] as const) { + test(`joined ${failure} failures remove windows expiring during the shared probe`, async () => { + const [id] = await seed(1); + setCachedProviderAccountQuotaForTests("anthropic", id!, { + fiveHourPercent: 10, weeklyPercent: 100, weeklyResetAt: start + 60_000, + customWindows: [{ label: "Opus", percent: 100, resetAt: start + 60_000 }, { label: "Fable", percent: 63 }], + updatedAt: start, + }); + let started!: () => void; + const dispatched = new Promise(resolve => { started = resolve; }); + let finish!: (response: Response) => void; + let fail!: (error: Error) => void; + const response = new Promise((resolve, reject) => { finish = resolve; fail = reject; }); + let calls = 0; + globalThis.fetch = (async () => { calls++; started(); return response; }) as typeof fetch; + const first = fetchProviderAccountQuotas("anthropic", true); + await dispatched; + const second = fetchProviderAccountQuotas("anthropic", true); + now += 30_000; + observe(id!); + now += 30_000; + if (failure === "http") finish(new Response("busy", { status: 429 })); + else fail(new Error("offline")); + const [a, b] = await Promise.all([first, second]); + expect(calls).toBe(1); + expect(a).toEqual(b); + expect(a[0]?.unavailable).toBe(true); + expect(a[0]?.quota).toEqual({ fiveHourPercent: 41, customWindows: [{ label: "Fable", percent: 63 }], updatedAt: start + 30_000 }); + expect(getCachedProviderAccountQuota("anthropic", id!)).toEqual(a[0]?.quota); + expect((await fetchProviderAccountQuotas("anthropic"))[0]).toEqual(a[0]); + expect(calls).toBe(1); + }); + } + + test("restart cannot revive expired bars from a recently updated disk row", async () => { + const [id] = await seed(1); + now += 120_000; + writeFileSync(join(home, "provider-account-quota-cache.json"), JSON.stringify({ version: 1, rows: { + [`anthropic\u0000${id}`]: { + fiveHourPercent: 41, weeklyPercent: 100, weeklyResetAt: start + 60_000, + customWindows: [{ label: "Opus", percent: 100, resetAt: start + 60_000 }, { label: "Fable", percent: 63 }], + updatedAt: now, + }, + } })); + clearAccountQuotaCache(); + let calls = 0; + globalThis.fetch = (async () => { calls++; return new Response("busy", { status: 429 }); }) as typeof fetch; + const [row] = await fetchProviderAccountQuotas("anthropic"); + expect(calls).toBe(1); + expect(row?.unavailable).toBe(true); + expect(row?.quota).toEqual({ fiveHourPercent: 41, customWindows: [{ label: "Fable", percent: 63 }], updatedAt: now }); + }); + + for (const malformed of [null, {}, [null, "bad", { label: "invalid", percent: "100" }]]) { + test(`malformed persisted custom windows stay unknown without breaking other rows: ${JSON.stringify(malformed)}`, async () => { + const [id] = await seed(1); + writeFileSync(join(home, "provider-account-quota-cache.json"), JSON.stringify({ version: 1, rows: { + [`anthropic\u0000${id}`]: { customWindows: malformed, updatedAt: now }, + "kiro\u0000untouched": { monthlyPercent: 17, updatedAt: now }, + } })); + clearAccountQuotaCache(); + let calls = 0; + globalThis.fetch = (async () => { calls++; return new Response("busy", { status: 429 }); }) as typeof fetch; + const [row] = await fetchProviderAccountQuotas("anthropic"); + expect(calls).toBe(1); + expect(row?.quota).toBeNull(); + expect(row?.unavailable).toBe(true); + expect(getCachedProviderAccountQuota("kiro", "untouched")).toEqual({ monthlyPercent: 17, updatedAt: now }); + }); + } + + test("fresh utilization without a reset does not inherit an expired reset", async () => { + const [id] = await seed(1); + setCachedProviderAccountQuotaForTests("anthropic", id!, { + fiveHourPercent: 100, fiveHourResetAt: start + 60_000, updatedAt: start, + }); + now += 60_000; + observe(id!); + expect(getCachedProviderAccountQuota("anthropic", id!)).toEqual({ fiveHourPercent: 41, updatedAt: now }); + }); + + test("deferred persistence evaluates expiry at write time and leaves other providers intact", async () => { + const [id] = await seed(1); + const saved = { weeklyPercent: 100, weeklyResetAt: start + 60_000, updatedAt: start }; + setCachedProviderAccountQuotaForTests("anthropic", id!, saved); + setCachedProviderAccountQuotaForTests("kiro", "untouched", saved); + let flush!: () => void; + const timer = spyOn(globalThis, "setTimeout").mockImplementation(((callback: () => void) => { + flush = callback; + return 0 as unknown as ReturnType; + }) as typeof setTimeout); + try { observe(id!); } finally { timer.mockRestore(); } + now += 60_000; + flush(); + const disk = JSON.parse(readFileSync(join(home, "provider-account-quota-cache.json"), "utf8")); + expect(disk.rows[`anthropic\u0000${id}`]).toEqual({ fiveHourPercent: 41, updatedAt: start }); + expect(disk.rows["kiro\u0000untouched"]).toEqual(saved); + }); +}); From 54fcc688d7b23677892a01803fc07663fbdd2074 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 09:22:08 +0900 Subject: [PATCH 042/412] test(anthropic): keep probe fixtures inside live reset windows [skip ci] The attribution/cache tests used July 2026 quota reset dates, which correctly expire under the known-reset fix. Generate future reset dates from one clock snapshot; preserve all existing assertions. Explicit expiry tests retain fixed simulated boundaries. No local suites run. --- tests/providers/provider-account-quota.test.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/providers/provider-account-quota.test.ts b/tests/providers/provider-account-quota.test.ts index 989f55a410..1b940d71d0 100644 --- a/tests/providers/provider-account-quota.test.ts +++ b/tests/providers/provider-account-quota.test.ts @@ -33,9 +33,11 @@ async function seedTwoAccounts(): Promise { } function usageBody(fiveHour: number, sevenDay: number): string { + // These tests exercise current account measurements, not expired historical windows. + const now = Date.now(); return JSON.stringify({ - five_hour: { utilization: fiveHour, resets_at: "2026-07-05T12:00:00Z" }, - seven_day: { utilization: sevenDay, resets_at: "2026-07-08T12:00:00Z" }, + five_hour: { utilization: fiveHour, resets_at: new Date(now + 5 * 60 * 60_000).toISOString() }, + seven_day: { utilization: sevenDay, resets_at: new Date(now + 7 * 24 * 60 * 60_000).toISOString() }, }); } From d3c70f9d8c8cc6fced7a93577b93e8b141473ea3 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 09:44:37 +0900 Subject: [PATCH 043/412] fix(anthropic): normalize retained quota metadata and guard test transport [skip ci] Reject unusable custom labels/percentages, omit invalid reset metadata while retaining valid usage, and state the existing 60-second fallback. Guard unexpected test network calls with teardown-safe restoration. No new TTL or synthetic quota values. Addresses #3825 review findings; no local suite was run. --- .../src/content/docs/guides/claude-code.md | 2 +- .../docs/reference/configuration/providers.md | 2 +- src/providers/quota.ts | 38 ++++++++--- .../anthropic-quota-dispatch.test.ts | 64 +++++++++++++------ .../anthropic-ratelimit-headers.test.ts | 63 +++++++++++++++++- 5 files changed, 137 insertions(+), 32 deletions(-) diff --git a/docs-site/src/content/docs/guides/claude-code.md b/docs-site/src/content/docs/guides/claude-code.md index 720a303b00..4c5cc44b34 100644 --- a/docs-site/src/content/docs/guides/claude-code.md +++ b/docs-site/src/content/docs/guides/claude-code.md @@ -31,7 +31,7 @@ Operational contract when enabled: account within the same request (bounded). The cooldown uses a usable `Retry-After` when present, otherwise the latest valid reset time among windows Anthropic marks `rejected`, including weekly windows. Valid upstream deadlines are not shortened to a fixed cooldown ceiling. - A refusal with no usable deadline falls back to a default backoff. + A refusal with no usable deadline falls back to a 60-second default backoff. - Responses report the serving account's 5-hour and weekly utilization, and whichever of those two the response carries is recorded for that account — each window independently, and a refusal counts as well as a success. Usage-aware selection works from ordinary traffic, diff --git a/docs-site/src/content/docs/reference/configuration/providers.md b/docs-site/src/content/docs/reference/configuration/providers.md index 710c069b24..b4d7cb2094 100644 --- a/docs-site/src/content/docs/reference/configuration/providers.md +++ b/docs-site/src/content/docs/reference/configuration/providers.md @@ -437,7 +437,7 @@ When enabled, 429 records a cooldown and may rotate within the request. The cool from a usable `Retry-After`, otherwise from the latest valid reset time among rate-limit windows Anthropic reports as `rejected`, including weekly windows. Valid upstream deadlines are not shortened to a fixed cooldown ceiling; non-finite or unrepresentable deadlines are ignored. -A refusal with no usable deadline falls back to a short default backoff. Affinity is process-local +A refusal with no usable deadline falls back to a 60-second default backoff. Affinity is process-local and size-bounded. Credential 401/403 marks the account as needing reauthentication. If all eligible accounts are cooling, clients receive 429 with `Retry-After` when known, not an authentication error. diff --git a/src/providers/quota.ts b/src/providers/quota.ts index 5dcb69beb3..71644a9eae 100644 --- a/src/providers/quota.ts +++ b/src/providers/quota.ts @@ -1555,26 +1555,48 @@ type AccountQuotaCacheEntry = { /** Expired measurements become unknown; missing reset evidence never implies a fresh allowance. */ function normalizeAnthropicQuota(quota: ProviderQuota | null | undefined, now: number): ProviderQuota | null { if (!quota) return null; - const expired = (resetAt: number | undefined): boolean => typeof resetAt === "number" - && Number.isFinite(resetAt) && resetAt > 0 && resetAt <= now; + const validReset = (resetAt: unknown): resetAt is number => typeof resetAt === "number" + && Number.isFinite(resetAt) && resetAt > 0 && Number.isFinite(new Date(resetAt).getTime()); let result = quota; for (const [percent, reset] of [ ["fiveHourPercent", "fiveHourResetAt"], ["weeklyPercent", "weeklyResetAt"], ["monthlyPercent", "monthlyResetAt"], ] as const) { - if (!expired(quota[reset])) continue; + const resetAt = quota[reset]; + if (resetAt === undefined) continue; + const valid = validReset(resetAt); + if (valid && resetAt > now) continue; if (result === quota) result = { ...quota }; - delete result[percent]; + if (valid) delete result[percent]; delete result[reset]; } // Persisted rows validate only the outer quota object, so custom data may be malformed. if (quota.customWindows !== undefined) { const windows = Array.isArray(quota.customWindows) ? quota.customWindows : []; - const retained = windows.filter(window => window !== null && typeof window === "object" - && typeof window.label === "string" && typeof window.percent === "number" - && Number.isFinite(window.percent) && !expired(window.resetAt)); - if (!Array.isArray(quota.customWindows) || retained.length !== windows.length) { + const retained: ProviderQuotaWindow[] = []; + let changed = !Array.isArray(quota.customWindows); + for (const window of windows) { + if (!window || typeof window !== "object" || typeof window.label !== "string" || !window.label.trim() + || typeof window.percent !== "number" || !Number.isFinite(window.percent) + || window.percent < 0 || window.percent > 100) { + changed = true; + continue; + } + if (validReset(window.resetAt) && window.resetAt <= now) { + changed = true; + continue; + } + if (window.resetAt !== undefined && !validReset(window.resetAt)) { + const normalized = { ...window }; + delete normalized.resetAt; + retained.push(normalized); + changed = true; + } else { + retained.push(window); + } + } + if (changed) { if (result === quota) result = { ...quota }; if (retained.length) result.customWindows = retained; else delete result.customWindows; diff --git a/tests/adapters/anthropic/anthropic-quota-dispatch.test.ts b/tests/adapters/anthropic/anthropic-quota-dispatch.test.ts index 6442436fbb..09952ea5ab 100644 --- a/tests/adapters/anthropic/anthropic-quota-dispatch.test.ts +++ b/tests/adapters/anthropic/anthropic-quota-dispatch.test.ts @@ -13,10 +13,19 @@ import type { OcxConfig, OcxProviderConfig } from "../../../src/types"; import { removeTreeWithRetry } from "../../helpers/remove-tree"; const originalHome = process.env.OPENCODEX_HOME; +let originalFetch: typeof globalThis.fetch; +let unexpectedGlobalFetches = 0; let home: string; let sent: { authorization: string | null; apiKey: string | null; body: Record }[]; beforeEach(() => { + home = ""; + originalFetch = globalThis.fetch; + unexpectedGlobalFetches = 0; + globalThis.fetch = (async () => { + unexpectedGlobalFetches += 1; + throw new Error("Unexpected global fetch in Anthropic quota dispatch test"); + }) as typeof fetch; home = mkdtempSync(join(tmpdir(), "ocx-anthropic-quota-dispatch-")); process.env.OPENCODEX_HOME = home; sent = []; @@ -29,16 +38,25 @@ beforeEach(() => { }); afterEach(() => { - clearAnthropicAccountPoolState(); - forgetAnthropicFailoverQuorum(); - clearGenericFailoverHealth(); - // Cancel the debounced persistence before restoring the real home. - clearAccountQuotaCache(); - resetProviderQuotaReconcileStateForTests(); - clearResponseStateForTests(); - if (originalHome === undefined) delete process.env.OPENCODEX_HOME; - else process.env.OPENCODEX_HOME = originalHome; - removeTreeWithRetry(home); + try { + // Provider code may catch the guard's rejection; the attempted network call still fails the test. + expect(unexpectedGlobalFetches).toBe(0); + } finally { + try { + // Cancel the debounced persistence before restoring the real home. + clearAccountQuotaCache(); + clearAnthropicAccountPoolState(); + forgetAnthropicFailoverQuorum(); + clearGenericFailoverHealth(); + resetProviderQuotaReconcileStateForTests(); + clearResponseStateForTests(); + } finally { + globalThis.fetch = originalFetch; + if (originalHome === undefined) delete process.env.OPENCODEX_HOME; + else process.env.OPENCODEX_HOME = originalHome; + if (home) removeTreeWithRetry(home); + } + } }); function credential(index: number) { @@ -136,8 +154,9 @@ test("main A429 -> B200 records both physical responses against their sending ac return answer(body.stream === true); }); const response = await post(config); + const responseText = await response.text(); expect(response.status).toBe(200); - expect(await response.text()).toContain("The answer is complete."); + expect(responseText).toContain("The answer is complete."); expect(sent.map(row => row.authorization)).toEqual([`Bearer ${credential(0).access}`, `Bearer ${credential(1).access}`]); expectQuota(a!, 100, 61); expectQuota(b!, 23, 47); @@ -151,8 +170,8 @@ test("terminal 429 after both accounts are exhausted records both refused physic expectQuota(a!, 100, 61); return limited("0.89", "1"); })); - expect(response.status).toBe(429); await response.text(); + expect(response.status).toBe(429); expect(sent.map(row => row.authorization)).toEqual([`Bearer ${credential(0).access}`, `Bearer ${credential(1).access}`]); expectQuota(a!, 100, 61); expectQuota(b!, 89, 100); @@ -165,15 +184,16 @@ test("manual active switch while A is pending keeps A's measurement off B", asyn const config = configFor(() => { entered.resolve(); return returned.promise; }); const pending = post(config); await entered.promise; + let response!: Response; try { expect(sent[0]!.authorization).toBe(`Bearer ${credential(0).access}`); expect(await setActiveAccount("anthropic", b!)).toBe(true); } finally { returned.resolve(answer(false, "0.37", "0.53")); + response = await pending; + await response.text(); } - const response = await pending; expect(response.status).toBe(200); - await response.text(); expect(sent).toHaveLength(1); expect(getAccountSet("anthropic")!.activeAccountId).toBe(b!); expectQuota(a!, 37, 53); @@ -186,15 +206,16 @@ test("credential replacement while A is pending skips its old-generation respons const returned = deferred(); const pending = post(configFor(() => { entered.resolve(); return returned.promise; })); await entered.promise; + let response!: Response; try { expect(sent[0]!.authorization).toBe(`Bearer ${credential(0).access}`); await saveAccountCredential("anthropic", a!, { ...credential(0), access: "synthetic-replacement-access", refresh: "synthetic-replacement-refresh" }); } finally { returned.resolve(answer(false)); + response = await pending; + await response.text(); } - const response = await pending; expect(response.status).toBe(200); - await response.text(); expect(sent).toHaveLength(1); expect(getAccountSet("anthropic")!.accounts.find(row => row.id === a)!.credential.access).toBe("synthetic-replacement-access"); expect(getCachedProviderAccountQuota("anthropic", a!)).toBeNull(); @@ -208,8 +229,8 @@ const overriddenHeaders: { label: string; headers: Record; autho test.each(overriddenHeaders)("$label skips quota attribution even when a selected OAuth account exists", async ({ headers, authorization, apiKey }) => { const ids = await seed(); const response = await post(configFor(body => answer(body.stream === true), headers)); - expect(response.status).toBe(200); await response.text(); + expect(response.status).toBe(200); expect(sent).toHaveLength(1); expect(sent[0]).toMatchObject({ authorization, apiKey }); for (const id of ids) expect(getCachedProviderAccountQuota("anthropic", id)).toBeNull(); @@ -227,8 +248,9 @@ test("real web-search routed loop records A429 and B200 through fetchForRequest" }); config.webSearchSidecar = { backend: "anthropic", enabled: true }; const response = await post(config, { tools: [{ type: "web_search" }] }); + const responseText = await response.text(); expect(response.status).toBe(200); - expect(await response.text()).toContain("The answer is complete."); + expect(responseText).toContain("The answer is complete."); expect(sent.map(row => row.authorization)).toEqual([`Bearer ${credential(0).access}`, `Bearer ${credential(1).access}`]); expectQuota(a!, 100, 61); expectQuota(b!, 23, 47); @@ -252,8 +274,9 @@ test("real terminal continuation records A429 before retrying the continuation o input: "Please modify the file now", tools: [{ type: "function", name: "read_file", description: "read a file", parameters: { type: "object" } }], }); + const responseText = await response.text(); expect(response.status).toBe(200); - expect(await response.text()).toContain("The answer is complete."); + expect(responseText).toContain("The answer is complete."); expect(sent.map(row => row.authorization)).toEqual([`Bearer ${credential(0).access}`, `Bearer ${credential(0).access}`, `Bearer ${credential(1).access}`]); expectQuota(a!, 100, 61); expectQuota(b!, 23, 47); @@ -275,8 +298,9 @@ test("real image bridge routed loop records A429 and B200 through fetchForReques adapter: "openai-chat", baseUrl: "https://api.x.ai/v1", authMode: "key", apiKey: "synthetic-image-key", }; const response = await post(config, { stream: true, tools: [{ type: "image_generation" }] }); + const responseText = await response.text(); expect(response.status).toBe(200); - expect(await response.text()).toContain("The answer is complete."); + expect(responseText).toContain("The answer is complete."); expect(sent.map(row => row.authorization)).toEqual([`Bearer ${credential(0).access}`, `Bearer ${credential(1).access}`]); expectQuota(a!, 100, 61); expectQuota(b!, 23, 47); diff --git a/tests/adapters/anthropic/anthropic-ratelimit-headers.test.ts b/tests/adapters/anthropic/anthropic-ratelimit-headers.test.ts index 77989064ff..f1ad70542e 100644 --- a/tests/adapters/anthropic/anthropic-ratelimit-headers.test.ts +++ b/tests/adapters/anthropic/anthropic-ratelimit-headers.test.ts @@ -561,14 +561,56 @@ describe("Anthropic known-reset expiry", () => { now += 120_000; observe(id!); const quota = getCachedProviderAccountQuota("anthropic", id!); - expect(quota?.customWindows).toEqual(saved.customWindows.slice(1)); + const retained = [saved.customWindows[1], saved.customWindows[2], { label: "Unknown reset", percent: 60 }]; + expect(quota?.customWindows).toEqual(retained); expect(quota?.fiveHourPercent).toBe(41); expect(quota?.updatedAt).toBe(now); expect(saved.customWindows).toHaveLength(4); expect(saved.updatedAt).toBe(start); now += 30_000; observe(id!); - expect(getCachedProviderAccountQuota("anthropic", id!)?.customWindows).toEqual(saved.customWindows.slice(1)); + expect(getCachedProviderAccountQuota("anthropic", id!)?.customWindows).toEqual(retained); + }); + + test("custom windows reject empty labels and invalid percentages while preserving valid objects", async () => { + const [id] = await seed(1); + const valid = [{ label: "Opus", percent: 0 }, { label: "Sonnet", percent: 100, resetAt: start + 60_000 }]; + const saved = { customWindows: [ + ...valid, + { label: "", percent: 50 }, { label: " ", percent: 50 }, + { label: "negative", percent: -1 }, { label: "too high", percent: 101 }, + { label: "not finite", percent: Number.NaN }, { label: "infinite", percent: Infinity }, + ], updatedAt: start }; + setCachedProviderAccountQuotaForTests("anthropic", id!, saved); + const normalized = getCachedProviderAccountQuota("anthropic", id!); + expect(normalized?.customWindows).toEqual(valid); + expect(normalized?.customWindows?.[0]).toBe(valid[0]); + expect(saved.customWindows).toHaveLength(8); + setCachedProviderAccountQuotaForTests("anthropic", id!, normalized!); + expect(getCachedProviderAccountQuota("anthropic", id!)).toBe(normalized); + }); + + test("invalid reset metadata is removed without discarding valid usage", async () => { + const [id] = await seed(1); + const invalidResets = [0, -1, Number.NaN, Infinity, 8_640_000_000_000_001]; + const saved = { + fiveHourPercent: 40, fiveHourResetAt: 0, + weeklyPercent: 50, weeklyResetAt: Infinity, + monthlyPercent: 60, monthlyResetAt: 8_640_000_000_000_001, + customWindows: invalidResets.map((resetAt, index) => ({ label: `window-${index}`, percent: 70, resetAt })), + updatedAt: start, + }; + setCachedProviderAccountQuotaForTests("anthropic", id!, saved); + const normalized = getCachedProviderAccountQuota("anthropic", id!); + expect(normalized).toEqual({ + fiveHourPercent: 40, weeklyPercent: 50, monthlyPercent: 60, + customWindows: invalidResets.map((_, index) => ({ label: `window-${index}`, percent: 70 })), + updatedAt: start, + }); + expect(saved.customWindows[0]?.resetAt).toBe(0); + expect(saved.fiveHourResetAt).toBe(0); + setCachedProviderAccountQuotaForTests("anthropic", id!, normalized!); + expect(getCachedProviderAccountQuota("anthropic", id!)).toBe(normalized); }); for (const [percent, reset, observedWindow] of [ @@ -729,6 +771,23 @@ describe("Anthropic known-reset expiry", () => { }); } + test("persisted nonnumeric reset metadata does not erase otherwise valid windows", async () => { + const [id] = await seed(1); + writeFileSync(join(home, "provider-account-quota-cache.json"), JSON.stringify({ version: 1, rows: { + [`anthropic\u0000${id}`]: { + weeklyPercent: 80, weeklyResetAt: "unknown", + customWindows: [{ label: "Opus", percent: 70, resetAt: null }, { label: "Sonnet", percent: 60, resetAt: "later" }], + updatedAt: now, + }, + } })); + clearAccountQuotaCache(); + globalThis.fetch = (async () => new Response("busy", { status: 429 })) as typeof fetch; + const [row] = await fetchProviderAccountQuotas("anthropic"); + expect(row?.quota).toEqual({ weeklyPercent: 80, + customWindows: [{ label: "Opus", percent: 70 }, { label: "Sonnet", percent: 60 }], updatedAt: now }); + expect(row?.unavailable).toBe(true); + }); + test("fresh utilization without a reset does not inherit an expired reset", async () => { const [id] = await seed(1); setCachedProviderAccountQuotaForTests("anthropic", id!, { From 872f0e5aa714f6a2e757510195d1c038ac70e26d Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 07:41:57 +0900 Subject: [PATCH 044/412] fix(cli): explain which side of a version mismatch is older [skip ci] Address the diagnostic residual of #3464. Keep raw mismatch and placeholder behavior, compare valid SemVer precedence, and avoid false doctor match claims. No automatic service repair or request-policy change. Local suites omitted by owner instruction; final cumulative hosted CI pending. Reported-by: garysassano <10464497+garysassano@users.noreply.github.com> --- .../docs/ko/reference/cli/lifecycle.md | 13 +++ .../content/docs/reference/cli/lifecycle.md | 20 ++++- .../docs/ru/reference/cli/lifecycle.md | 13 +++ src/cli/doctor.ts | 4 +- src/cli/version-skew.ts | 39 ++++++++- tests/cli/cli-status-json.test.ts | 82 ++++++++++++++++++- tests/cli/cli-version-skew.test.ts | 70 +++++++++++++++- tests/codex-integration/doctor.test.ts | 63 +++++++++++++- 8 files changed, 291 insertions(+), 13 deletions(-) diff --git a/docs-site/src/content/docs/ko/reference/cli/lifecycle.md b/docs-site/src/content/docs/ko/reference/cli/lifecycle.md index 4847614674..068807025b 100644 --- a/docs-site/src/content/docs/ko/reference/cli/lifecycle.md +++ b/docs-site/src/content/docs/ko/reference/cli/lifecycle.md @@ -82,6 +82,19 @@ dedicated-provider history도 포함됩니다. 상태를 백업하고 이 전체 ### `ocx status [--json]` +status와 `ocx doctor`는 현재 CLI와 실행 중인 프록시의 버전을 비교합니다. CLI가 더 새로우면 +원하는 최신 설치로 프록시를 재시작하십시오. 백그라운드 서비스라면 `ocx service repair`를 +실행합니다(`ocx service restart`는 별칭). 프록시가 더 새로우면 CLI를 업그레이드하거나 +`PATH`가 원하는 설치를 가리키도록 수정하십시오. 이 진단은 서비스를 복구하거나 요청 허용 +여부를 바꾸지 않습니다. + +버전 문자열이 같거나 어느 쪽이 `unknown` / `0.0.0`이면 경고하지 않으며, 프록시 버전이 없어도 +경고하지 않습니다. doctor는 placeholder를 버전 일치로 확정하지 않습니다. 엄격한 SemVer로 +해석할 수 없는 서로 다른 문자열이나 build metadata만 다른 버전은 어느 쪽이 오래됐다고 +단정하지 않는 중립 경고를 표시합니다. 공백을 제거하거나 앞의 `v`를 정규화하지 않습니다. +JSON의 `versionSkew`에도 같은 안내가 들어가며 필드는 `cliVersion`, `proxyVersion`, `skewed`, +`warning` 그대로입니다. + 읽기 전용 진단 요약을 출력합니다. 프록시 PID, `/healthz` 도달 가능 여부, 대시보드 URL, 설정 경로, 기본 공급자, Codex 자동 시작 설정, 서비스 상태, shim 상태, 그리고 마스킹된 실제로 적용되는 Codex 홈이 포함됩니다. 명시적이고 높은 신뢰도의 Windows Orca 런타임 홈 시그니처만 diff --git a/docs-site/src/content/docs/reference/cli/lifecycle.md b/docs-site/src/content/docs/reference/cli/lifecycle.md index e75a2b6241..0dda487b3a 100644 --- a/docs-site/src/content/docs/reference/cli/lifecycle.md +++ b/docs-site/src/content/docs/reference/cli/lifecycle.md @@ -88,6 +88,19 @@ are left in place. ### `ocx status [--json]` +Status and `ocx doctor` compare this CLI's version with the running proxy. If the CLI is newer, +restart the proxy using the intended current installation; for a background service, run +`ocx service repair` (`ocx service restart` is an alias). If the proxy is newer, upgrade the CLI +or resolve `PATH` to the intended installation. These diagnostics do not repair the service or +change whether requests are allowed. + +Identical version strings and the `unknown` / `0.0.0` placeholders suppress the warning, as does +an absent proxy version. Doctor does not report placeholders as a confirmed match. Different +strings still produce a neutral warning when they cannot be strictly parsed as SemVer or differ +only in build metadata; neither side is called older. Versions are not trimmed and a leading `v` +is not normalized. JSON exposes the same advice in `versionSkew`, whose fields remain +`cliVersion`, `proxyVersion`, `skewed`, and `warning`. + Print a read-only diagnostic summary: proxy PID, `/healthz` reachability, dashboard URL, config path, default provider, Codex autostart setting, service state, shim state, and the redacted effective Codex home. Only the explicit, high-confidence Windows Orca runtime-home signature adds an actionable App-home @@ -261,9 +274,10 @@ bundled Bun paths are deliberately rediscovered after upgrades instead of being Definitions installed before this change still carry the old versioned paths and cannot migrate themselves — once the old executable is deleted, no opencodex code runs to fix it. Run `ocx service repair` once after upgrading; after that, each service start follows the launcher. -An already-running proxy is not replaced by an external upgrade: restart the service (or run -`ocx service repair`) so the new build serves, and treat a CLI/proxy version mismatch warning as -exactly that signal. +An already-running proxy is not replaced by an external upgrade: when the installed CLI is newer +than the running proxy, restart the service (or run `ocx service repair`) so the new build serves. +If the proxy is newer instead, check the CLI installation and `PATH` as described under +[`ocx status`](#ocx-status---json). | Subcommand | Action | | --- | --- | diff --git a/docs-site/src/content/docs/ru/reference/cli/lifecycle.md b/docs-site/src/content/docs/ru/reference/cli/lifecycle.md index 1ace7cc10f..7be5d5ad77 100644 --- a/docs-site/src/content/docs/ru/reference/cli/lifecycle.md +++ b/docs-site/src/content/docs/ru/reference/cli/lifecycle.md @@ -89,6 +89,19 @@ ocx eject back ### `ocx status [--json]` +Status и `ocx doctor` сравнивают версии текущего CLI и работающего прокси. Если CLI новее, +перезапустите прокси из нужной актуальной установки. Для фоновой службы используйте +`ocx service repair` (`ocx service restart` — её псевдоним). Если новее прокси, обновите CLI +или исправьте `PATH`, чтобы он указывал на нужную установку. Диагностика не ремонтирует службу +и не меняет разрешение запросов. + +При одинаковых строках версий, значениях `unknown` / `0.0.0` или отсутствии версии прокси +предупреждение подавляется. Doctor не считает placeholder подтверждённым совпадением. +Разные строки, которые нельзя строго разобрать как SemVer, и версии, отличающиеся только +build metadata, вызывают нейтральное предупреждение без указания устаревшей стороны. +Пробелы не удаляются, префикс `v` не нормализуется. JSON содержит ту же рекомендацию в +`versionSkew` с прежними полями `cliVersion`, `proxyVersion`, `skewed` и `warning`. + Печатает read-only диагностическую сводку: PID прокси, достижимость `/healthz`, URL дашборда, путь к конфигу, провайдера по умолчанию, настройку автозапуска Codex, состояние службы, состояние shim'а и redacted effective Codex home. Только явная и высокоуверенная сигнатура mismatch diff --git a/src/cli/doctor.ts b/src/cli/doctor.ts index 1ab4fe9f1b..d7148530a0 100644 --- a/src/cli/doctor.ts +++ b/src/cli/doctor.ts @@ -1157,11 +1157,11 @@ export async function runDoctor(args: string[] = []): Promise { // No extra probe -- findLiveProxy already carried the version back. { const { packageVersion } = await import("./help"); - const { computeVersionSkew } = await import("./version-skew"); + const { computeVersionSkew, isConfirmedVersionMatch } = await import("./version-skew"); const skew = computeVersionSkew(packageVersion(), live?.version); if (skew.skewed && skew.warning) { console.log(`!! ${skew.warning}`); - } else if (skew.proxyVersion !== null) { + } else if (isConfirmedVersionMatch(skew)) { console.log(`ok ocx ${skew.cliVersion} matches the running proxy`); } } diff --git a/src/cli/version-skew.ts b/src/cli/version-skew.ts index 588d29a307..48b71a51ee 100644 --- a/src/cli/version-skew.ts +++ b/src/cli/version-skew.ts @@ -1,5 +1,5 @@ /** - * CLI-versus-proxy version skew (#2701). + * CLI-versus-proxy version skew (#2701, #3464). * * The reported failure: `ocx` on PATH is an older install than the running proxy, so its * help describes commands the proxy does not have and its output describes a different @@ -9,6 +9,7 @@ * comparison instead of reimplementing it -- two diagnostics disagreeing about whether an * install is stale would be worse than neither reporting it. */ +import { parseStrictSemver, type StrictSemver } from "../lib/strict-semver"; /** Placeholder versions that mean "unknown", not "different". */ const PLACEHOLDERS = new Set(["unknown", "0.0.0"]); @@ -22,6 +23,30 @@ export interface VersionSkew { readonly warning: string | null; } +/** Suppressed comparisons are not confirmed matches, even when both placeholders agree. */ +export function isConfirmedVersionMatch(skew: VersionSkew): boolean { + return skew.proxyVersion === skew.cliVersion && !PLACEHOLDERS.has(skew.cliVersion); +} + +/** SemVer precedence ignores build metadata; raw equality is handled separately. */ +function compareVersions(cli: StrictSemver, proxy: StrictSemver): number { + for (let i = 0; i < cli.core.length; i++) { + if (cli.core[i]! !== proxy.core[i]!) return cli.core[i]! > proxy.core[i]! ? 1 : -1; + } + if (cli.prerelease.length === 0) return proxy.prerelease.length === 0 ? 0 : 1; + if (proxy.prerelease.length === 0) return -1; + for (let i = 0; i < Math.max(cli.prerelease.length, proxy.prerelease.length); i++) { + const left = cli.prerelease[i]; + const right = proxy.prerelease[i]; + if (left === right) continue; + if (left === undefined) return -1; + if (right === undefined) return 1; + if (typeof left !== typeof right) return typeof left === "bigint" ? -1 : 1; + return left > right ? 1 : -1; + } + return 0; +} + /** * Compare the running CLI against the live proxy. * @@ -36,11 +61,19 @@ export function computeVersionSkew(cliVersion: string, proxyVersion: string | un if (proxy === null || PLACEHOLDERS.has(proxy) || PLACEHOLDERS.has(cliVersion) || proxy === cliVersion) { return { cliVersion, proxyVersion: proxy, skewed: false, warning: null }; } + const cliSemver = parseStrictSemver(cliVersion); + const proxySemver = parseStrictSemver(proxy); + const order = cliSemver && proxySemver ? compareVersions(cliSemver, proxySemver) : 0; + const advice = order > 0 + ? "the running proxy is older than this CLI. Restart the proxy using the intended current installation. " + + "For a background service, run ocx service repair (ocx service restart is an alias)." + : order < 0 + ? "this ocx on PATH is older than the running proxy. Upgrade the CLI or resolve PATH to the intended installation." + : "the versions differ, but neither can be identified as older. Check which installations the CLI and proxy use."; return { cliVersion, proxyVersion: proxy, skewed: true, - warning: `CLI ${cliVersion} does not match the running proxy ${proxy} — this ocx on PATH is stale. ` - + "Its help and features describe a different build. Reinstall, or run the proxy's own binary.", + warning: `CLI ${cliVersion} does not match the running proxy ${proxy} — ${advice}`, }; } diff --git a/tests/cli/cli-status-json.test.ts b/tests/cli/cli-status-json.test.ts index 31371baa33..10ab4f110e 100644 --- a/tests/cli/cli-status-json.test.ts +++ b/tests/cli/cli-status-json.test.ts @@ -10,9 +10,11 @@ import { fileURLToPath } from "node:url"; import { isConnectionRefused, isUncleanExitEvidence, proxyHealthFailureReason, resolveStatusPid, selectListenTarget } from "../../src/cli/status"; import * as statusFacade from "../../src/cli/status"; import * as statusProbes from "../../src/cli/status-probes"; +import { packageVersion } from "../../src/cli/help"; +import { getDefaultConfig } from "../../src/config"; import { findDeadPid } from "../helpers/dead-pid"; import { removeTreeWithRetry } from "../helpers/remove-tree"; -import { STORE_BUDGET_MS } from "../helpers/test-budget"; +import { INTERNAL_DEADLINE_MS, SPAWN_BUDGET_MS, STORE_BUDGET_MS } from "../helpers/test-budget"; import { inspectClientRotationRecoveryGate, readClientConnectionState } from "../../src/client/state"; import * as lifecycleLock from "../../src/client/lifecycle-lock"; import { writeDesktopDisconnectReceipt } from "../../src/claude/desktop-remote-store"; @@ -28,6 +30,84 @@ function runStatusJson(opencodexHome: string) { }); } +describe("status version skew projection", () => { + test.each([ + ["0.0.1", "the running proxy is older"], + ["999999.0.0", "this ocx on PATH is older"], + [packageVersion(), null], + [`${packageVersion()}+skew-fixture`, "neither can be identified as older"], + ["not-a-version", "neither can be identified as older"], + ["unknown", null], + ["0.0.0", null], + [undefined, null], + ] as const)("projects proxy %s in JSON and human output", async (proxyVersion, expected) => { + const home = mkdtempSync(join(tmpdir(), "ocx-status-skew-")); + const codexHome = join(home, "codex"); + let server: ReturnType | undefined; + try { + // Explicit CODEX_HOME must exist before the CLI imports codex/paths.ts. + mkdirSync(codexHome, { recursive: true }); + server = Bun.serve({ + hostname: "127.0.0.1", port: 0, + fetch(request) { + return new URL(request.url).pathname === "/healthz" + ? Response.json({ service: "opencodex", status: "ok", version: proxyVersion, uptime: 1 }) + : new Response("not found", { status: 404 }); + }, + }); + writeFileSync(join(home, "config.json"), JSON.stringify({ + ...getDefaultConfig(), port: server.port, hostname: "127.0.0.1", codexAutoStart: false, + })); + for (const json of [true, false]) { + // Async child execution lets the fixture answer the real identity/health probes. + const child = Bun.spawn([process.execPath, cliPath, "status", ...(json ? ["--json"] : [])], { + cwd: repoRoot, + env: { ...process.env, OPENCODEX_HOME: home, CODEX_HOME: codexHome }, + stdout: "pipe", stderr: "pipe", + }); + let timedOut = false; + const timer = setTimeout(() => { + timedOut = true; + child.kill("SIGKILL"); + }, INTERNAL_DEADLINE_MS); + try { + const [stdout, stderr, exitCode] = await Promise.all([ + new Response(child.stdout).text(), new Response(child.stderr).text(), child.exited, + ]); + expect(timedOut).toBe(false); + // Preserve both gates while surfacing the child error when startup fails. + expect({ exitCode, stderr }).toEqual({ exitCode: 0, stderr: "" }); + if (json) { + const parsed = JSON.parse(stdout); + expect(parsed.schemaVersion).toBe(1); + expect(Object.keys(parsed.versionSkew).sort()).toEqual(["cliVersion", "proxyVersion", "skewed", "warning"]); + expect(parsed.versionSkew.cliVersion).toBe(packageVersion()); + expect(parsed.versionSkew.proxyVersion).toBe(proxyVersion ?? null); + expect(parsed.versionSkew.skewed).toBe(expected !== null); + if (expected === null) expect(parsed.versionSkew.warning).toBeNull(); + else expect(parsed.versionSkew.warning).toContain(expected); + } else if (expected === null) { + expect(stdout).not.toContain("does not match the running proxy"); + } else { + expect(stdout).toContain(expected); + } + } finally { + clearTimeout(timer); + if (child.exitCode === null) child.kill("SIGKILL"); + await child.exited; + } + } + expect(existsSync(join(home, "ocx.pid"))).toBe(false); + } finally { + try { + await server?.stop(true); + } finally { + removeTreeWithRetry(home); + } + } + }, SPAWN_BUDGET_MS); +}); + function withRecoveryStatusFixture(work: (fixture: { home: string; lockDeps: { lockPath: string }; diff --git a/tests/cli/cli-version-skew.test.ts b/tests/cli/cli-version-skew.test.ts index 6e45f83c28..36fb6845f9 100644 --- a/tests/cli/cli-version-skew.test.ts +++ b/tests/cli/cli-version-skew.test.ts @@ -1,5 +1,5 @@ import { describe, expect, test } from "bun:test"; -import { computeVersionSkew } from "../../src/cli/version-skew"; +import { computeVersionSkew, isConfirmedVersionMatch } from "../../src/cli/version-skew"; import { packageVersion } from "../../src/cli/help"; /** @@ -7,20 +7,83 @@ import { packageVersion } from "../../src/cli/help"; * build, and nothing surfaced it because the CLI never compared the two versions. */ describe("version skew detection", () => { - test("reports skew when the proxy reports a different version", () => { + test("directs an older CLI to upgrade or resolve PATH", () => { const skew = computeVersionSkew("2.35.0", "2.36.1"); expect(skew.skewed).toBe(true); expect(skew.cliVersion).toBe("2.35.0"); expect(skew.proxyVersion).toBe("2.36.1"); expect(skew.warning).toContain("2.35.0"); expect(skew.warning).toContain("2.36.1"); - expect(skew.warning).toContain("stale"); + expect(skew.warning).toContain("this ocx on PATH is older"); + expect(skew.warning).toContain("Upgrade the CLI or resolve PATH"); + expect(skew.warning).not.toContain("ocx service repair"); + }); + + test("#3464 directs a newer CLI to restart the older proxy", () => { + const skew = computeVersionSkew("2.42.0", "2.10.1-preview.20260805"); + expect(skew).toEqual({ + cliVersion: "2.42.0", + proxyVersion: "2.10.1-preview.20260805", + skewed: true, + warning: "CLI 2.42.0 does not match the running proxy 2.10.1-preview.20260805 — " + + "the running proxy is older than this CLI. Restart the proxy using the intended current installation. " + + "For a background service, run ocx service repair (ocx service restart is an alias).", + }); + expect(skew.warning).not.toContain("this ocx on PATH is older"); + }); + + test.each([ + ["2.43.0", "2.43.0-preview.1"], + ["2.43.0-preview.10", "2.43.0-preview.2"], + ["2.43.0-preview.beta", "2.43.0-preview.10"], + ["2.43.0-preview.1", "2.43.0-preview"], + ["2.43.0-beta", "2.43.0-alpha"], + ["2.44.0-preview.1", "2.43.0"], + ["10.0.0", "9.99.99"], + ["2.43.1", "2.43.0"], + ["2.43.0-preview.9007199254740993", "2.43.0-preview.9007199254740992"], + ])("orders %s above %s in both directions", (newer, older) => { + expect(computeVersionSkew(newer, older).warning).toContain("the running proxy is older"); + expect(computeVersionSkew(older, newer).warning).toContain("this ocx on PATH is older"); + }); + + test.each([ + ["2.43.0+build.1", "2.43.0+build.2"], + ["2.43.0", "2.43.0+build.1"], + ["2.43.0-preview.1+a", "2.43.0-preview.1+b"], + ["invalid", "2.43.0"], + ["2.43", "2.43.0"], + ["v2.43.0", "2.43.0"], + [" 2.43.0", "2.43.0"], + ["2.43.0 ", "2.43.0"], + ["2.43.0-preview.01", "2.43.0-preview.1"], + ["", "2.43.0"], + ])("keeps raw unequal %s / %s neutral in both directions", (left, right) => { + for (const [cli, proxy] of [[left, right], [right, left]]) { + const skew = computeVersionSkew(cli!, proxy!); + expect(skew.cliVersion).toBe(cli); + expect(skew.proxyVersion).toBe(proxy); + expect(skew.skewed).toBe(true); + expect(skew.warning).toContain("neither can be identified as older"); + expect(skew.warning).not.toContain("ocx service repair"); + expect(isConfirmedVersionMatch(skew)).toBe(false); + } + }); + + test.each(["unknown", "0.0.0"])("suppresses %s on either side without confirming a match", placeholder => { + for (const [cli, proxy] of [[placeholder, "2.43.0"], ["2.43.0", placeholder], [placeholder, placeholder]]) { + const skew = computeVersionSkew(cli!, proxy!); + expect(skew.skewed).toBe(false); + expect(skew.warning).toBeNull(); + expect(isConfirmedVersionMatch(skew)).toBe(false); + } }); test("stays quiet when the versions match", () => { const skew = computeVersionSkew("2.35.0", "2.35.0"); expect(skew.skewed).toBe(false); expect(skew.warning).toBeNull(); + expect(isConfirmedVersionMatch(skew)).toBe(true); }); test("stays quiet when nothing is live", () => { @@ -28,6 +91,7 @@ describe("version skew detection", () => { expect(skew.skewed).toBe(false); expect(skew.proxyVersion).toBeNull(); expect(skew.warning).toBeNull(); + expect(isConfirmedVersionMatch(skew)).toBe(false); }); test("suppresses the warning when the proxy reports the 0.0.0 placeholder", () => { diff --git a/tests/codex-integration/doctor.test.ts b/tests/codex-integration/doctor.test.ts index 9fdb7ee30d..acb0f1b87e 100644 --- a/tests/codex-integration/doctor.test.ts +++ b/tests/codex-integration/doctor.test.ts @@ -1,4 +1,7 @@ -import { afterEach, beforeEach, describe, expect, test } from "bun:test"; +import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test"; +import * as proxyLiveness from "../../src/server/proxy-liveness"; +import * as cliHelp from "../../src/cli/help"; +import { getDefaultConfig } from "../../src/config"; import { spawnSync } from "node:child_process"; import { existsSync, mkdirSync, mkdtempSync, utimesSync, writeFileSync } from "node:fs"; import { join } from "node:path"; @@ -32,6 +35,7 @@ import { } from "../../src/lib/local-management-capability"; import { findDeadPid } from "../helpers/dead-pid"; import { removeTreeWithRetry } from "../helpers/remove-tree"; +import { STORE_BUDGET_MS } from "../helpers/test-budget"; const TEST_DIR = join(import.meta.dir, ".tmp-doctor-test"); const TEST_CODEX_HOME = join(TEST_DIR, "codex"); @@ -780,6 +784,63 @@ describe("doctor abandoned response-state temps", () => { }); }); +describe("doctor version skew projection", () => { + test.each([ + ["2.42.0", "2.10.1-preview.20260805", "the running proxy is older"], + ["2.35.0", "2.36.1", "this ocx on PATH is older"], + ["2.43.0", "2.43.0", "ok ocx 2.43.0 matches the running proxy"], + ["2.43.0+a", "2.43.0+b", "neither can be identified as older"], + ["v2.43.0", "2.43.0", "neither can be identified as older"], + ["2.43.0", "unknown", null], + ["unknown", "2.43.0", null], + ["2.43.0", "0.0.0", null], + ["0.0.0", "0.0.0", null], + ["unknown", "unknown", null], + ["2.43.0", undefined, null], + ] as const)("projects CLI %s / proxy %s without false matches", async (cli, proxy, expected) => { + const home = mkdtempSync(join(tmpdir(), "ocx-doctor-skew-")); + const codexHome = join(home, "codex"); + const previousHome = process.env.OPENCODEX_HOME; + const previousCodexHome = process.env.CODEX_HOME; + const previousExitCode = process.exitCode; + const restore: Array<() => void> = []; + try { + // Runtime history diagnostics resolve and stat an explicit CODEX_HOME. + mkdirSync(codexHome, { recursive: true }); + process.env.OPENCODEX_HOME = home; + process.env.CODEX_HOME = codexHome; + writeFileSync(join(home, "config.json"), JSON.stringify({ ...getDefaultConfig(), port: 9, codexAutoStart: false })); + const logged: string[] = []; + const log = spyOn(console, "log").mockImplementation((...args: unknown[]) => { logged.push(args.map(String).join(" ")); }); + restore.push(() => log.mockRestore()); + const version = spyOn(cliHelp, "packageVersion").mockReturnValue(cli); + restore.push(() => version.mockRestore()); + // Other doctor sections probe upstream health; this diagnostic fixture must stay offline. + const fetch = spyOn(globalThis, "fetch").mockImplementation(async () => new Response(null, { status: 503 })); + restore.push(() => fetch.mockRestore()); + const proxyInfo: proxyLiveness.LiveProxy = { + pid: null, port: 9, hostname: "127.0.0.1", source: "config", ...(proxy === undefined ? {} : { version: proxy }), + }; + const live = spyOn(proxyLiveness, "findLiveProxy").mockResolvedValue(proxyInfo); + restore.push(() => live.mockRestore()); + await runDoctor([]); + const output = logged.join("\n"); + if (expected !== null) expect(output).toContain(expected); + else expect(output).not.toContain("does not match the running proxy"); + if (cli !== "2.43.0" || proxy !== "2.43.0") expect(output).not.toContain("matches the running proxy"); + if (expected === "the running proxy is older") expect(output).toContain("ocx service repair"); + } finally { + for (const cleanup of restore.reverse()) cleanup(); + process.exitCode = previousExitCode; + if (previousHome === undefined) delete process.env.OPENCODEX_HOME; + else process.env.OPENCODEX_HOME = previousHome; + if (previousCodexHome === undefined) delete process.env.CODEX_HOME; + else process.env.CODEX_HOME = previousCodexHome; + removeTreeWithRetry(home); + } + }, STORE_BUDGET_MS); +}); + describe("doctor reclaim wiring (end to end)", () => { // The formatter tests above cannot observe deletion. This covers the call site itself: // inverting the report/reclaim ternary in runDoctor must fail a test. From 2e8ef03428f8e619dc92b250fbbc5d5dd7ad53cb Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 07:42:20 +0900 Subject: [PATCH 045/412] fix(responses): classify encrypted task recovery failures Distinguish HTTP refusal, timeout, shared abort, transport failure and invalid output through the existing shared-flight cache. Preserve strict admission, success-only cache, wrapper APIs and caller-local cancellation. Addresses the diagnostic residual of #3661; multipart/retry policy stays deferred. Reported-by: Hu9956 <282876394+Hu9956@users.noreply.github.com> --- .../021_source_review.md | 7 ++ .../content/docs/reference/architecture.md | 14 ++- src/lib/bounded-body.ts | 29 +++-- .../responses/agent-task-recovery-cache.ts | 57 ++++++--- src/server/responses/agent-task-recovery.ts | 44 ++++--- structure/04_transports-and-sidecars.md | 14 ++- .../server/agent-task-recovery-cache.test.ts | 54 +++++++-- tests/server/agent-task-recovery.test.ts | 114 +++++++++++++++--- tests/server/bounded-body.test.ts | 62 +++++++++- 9 files changed, 327 insertions(+), 68 deletions(-) create mode 100644 devlog/_plan/260907_axis1_bugfixes/021_source_review.md diff --git a/devlog/_plan/260907_axis1_bugfixes/021_source_review.md b/devlog/_plan/260907_axis1_bugfixes/021_source_review.md new file mode 100644 index 0000000000..516a760813 --- /dev/null +++ b/devlog/_plan/260907_axis1_bugfixes/021_source_review.md @@ -0,0 +1,7 @@ +# wp1 source review + +Three bounded patches implemented with regression coverage. Hooke independently passed the physical-response quota observer wiring; Tesla independently passed quota/recovery security and source review with zero blockers. Version comparator and status/doctor projections inspected by main. All source workers report no local suite/typecheck/build execution. + +Quota source: #3809, Éverton Toffanetto; Co-authored-by included in f215f79b4. Version report: garysassano; Reported-by included in f91e3953a. Recovery report: Hu9956; Reported-by included in recovery commit. + +Source-only checks: git diff --check and documentation fence/whitespace inspection. These do not prove runtime correctness. wp2 final cumulative hosted CI is still mandatory. Final CI dispatch includes Windows because ordinary PR workflow omits it. No release/deploy workflow will be dispatched. diff --git a/docs-site/src/content/docs/reference/architecture.md b/docs-site/src/content/docs/reference/architecture.md index 8e1e361a81..e0fbc8bcba 100644 --- a/docs-site/src/content/docs/reference/architecture.md +++ b/docs-site/src/content/docs/reference/architecture.md @@ -233,7 +233,17 @@ response is not cacheable. Post-commit and 5xx errors keep the no-resend path. When encrypted agent-task recovery refuses a routed task, its existing 400 error can include a bounded `recovery_reason`: `unsupported_envelope`, -`admission_denied`, `recovery_unavailable`, `caller_cancelled`, or `input_changed`. -The field is omitted when no classified recovery result exists. +`admission_denied`, `recovery_unavailable`, `caller_cancelled`, `input_changed`, +`recovery_http_rejected`, `recovery_timeout`, `recovery_aborted`, +`recovery_transport_error`, or `recovery_invalid_output`. +HTTP rejection requires an observed non-success response. Invalid output includes +invalid UTF-8, oversized bodies, malformed or incomplete recovery streams, and +invalid or conflicting assignments. A caller's cancellation takes precedence over +an owned deadline, which takes precedence over decode/transport failures. +`recovery_aborted` describes a shared recovery cancelled independently of that caller. +Shared-flight waiters receive the same underlying failure unless individually cancelled; +only successful plaintext is cached. Diagnostics contain no upstream error or payload text. +The field is omitted when no classified recovery result exists, and existing combo +branches that return the original target failure keep that response. `recovery_unavailable` includes cache/singleflight capacity and does not prove an upstream request was attempted. No retry or broader envelope acceptance is enabled. diff --git a/src/lib/bounded-body.ts b/src/lib/bounded-body.ts index 4016a0a753..0975268560 100644 --- a/src/lib/bounded-body.ts +++ b/src/lib/bounded-body.ts @@ -212,13 +212,28 @@ export async function readBoundedResponseBytes( } } -function decodeUtf8(chunks: readonly Uint8Array[], fatal: boolean): string { +// Mark only exceptions thrown by our decoder, preserving their identity and TypeError contract. +// Timeout-path flushing may fail too; retain that origin so callers do not lose the deadline. +const decodeFailures = new WeakMap(); + +export function boundedBodyDecodeFailure(error: unknown): "invalid_utf8" | "timeout" | undefined { + return error !== null && typeof error === "object" ? decodeFailures.get(error) : undefined; +} + +function decodeUtf8(chunks: readonly Uint8Array[], fatal: boolean, timedOut = false): string { const decoder = new TextDecoder("utf-8", { fatal }); - let text = ""; - for (const chunk of chunks) text += decoder.decode(chunk, { stream: true }); - // Flush an incomplete trailing UTF-8 sequence deterministically. - text += decoder.decode(); - return text; + try { + let text = ""; + for (const chunk of chunks) text += decoder.decode(chunk, { stream: true }); + // Flush an incomplete trailing UTF-8 sequence deterministically. + text += decoder.decode(); + return text; + } catch (error) { + if (error !== null && typeof error === "object") { + decodeFailures.set(error, timedOut ? "timeout" : "invalid_utf8"); + } + throw error; + } } /** @@ -297,7 +312,7 @@ export async function readBoundedResponseBody( "TimeoutError", ); return { - text: decodeUtf8([retained.subarray(0, retainedBytes)], options.fatalUtf8 === true), + text: decodeUtf8([retained.subarray(0, retainedBytes)], options.fatalUtf8 === true, true), truncated: true, timedOut: true, totalTimedOut: outcome === TOTAL_TIMEOUT, diff --git a/src/server/responses/agent-task-recovery-cache.ts b/src/server/responses/agent-task-recovery-cache.ts index 93d0c1778b..398a0feba4 100644 --- a/src/server/responses/agent-task-recovery-cache.ts +++ b/src/server/responses/agent-task-recovery-cache.ts @@ -2,6 +2,20 @@ const MAX_CACHE_BYTES = 8 * 1024 * 1024; const MAX_CONCURRENT_RECOVERIES = 32; const CACHE_TTL_MS = 15 * 60 * 1000; +export type AgentTaskRecoveryResolutionFailureReason = + | "recovery_unavailable" + | "caller_cancelled" + | "recovery_http_rejected" + | "recovery_timeout" + | "recovery_aborted" + | "recovery_transport_error" + | "recovery_invalid_output"; + +/** Shared flights carry bounded failures; only successful plaintext enters the cache. */ +export type AgentTaskRecoveryResolution = + | { readonly recovered: true; readonly assignment: string } + | { readonly recovered: false; readonly reason: AgentTaskRecoveryResolutionFailureReason }; + interface RecoveryCacheEntry { assignment: string; bytes: number; @@ -11,7 +25,7 @@ interface RecoveryCacheEntry { interface RecoveryFlight { controller: AbortController; - promise: Promise; + promise: Promise; waiters: number; settled: boolean; } @@ -63,7 +77,7 @@ function insertRecoveryCacheEntry(key: string, assignment: string, maxEntries: n function startRecoveryFlight( key: string, maxEntries: number, - request: (signal: AbortSignal) => Promise, + request: (signal: AbortSignal) => Promise, ): RecoveryFlight | null { const active = RECOVERY_FLIGHTS.get(key); if (active) return active; @@ -72,15 +86,15 @@ function startRecoveryFlight( const controller = new AbortController(); const flight: RecoveryFlight = { controller, - promise: Promise.resolve(null), + promise: Promise.resolve({ recovered: false, reason: "recovery_unavailable" }), waiters: 0, settled: false, }; flight.promise = request(controller.signal) - .then((assignment) => { - if (!assignment || controller.signal.aborted) return null; - insertRecoveryCacheEntry(key, assignment, maxEntries); - return assignment; + .then((result): AgentTaskRecoveryResolution => { + if (controller.signal.aborted) return { recovered: false, reason: "recovery_aborted" }; + if (result.recovered) insertRecoveryCacheEntry(key, result.assignment, maxEntries); + return result; }) .finally(() => { flight.settled = true; @@ -93,14 +107,14 @@ function startRecoveryFlight( async function waitForRecoveryFlight( flight: RecoveryFlight, abortSignal?: AbortSignal, -): Promise { - if (abortSignal?.aborted) return null; +): Promise { + if (abortSignal?.aborted) return { recovered: false, reason: "caller_cancelled" }; flight.waiters += 1; let onAbort: (() => void) | undefined; try { if (!abortSignal) return await flight.promise; - const cancelled = new Promise((resolve) => { - onAbort = () => resolve(null); + const cancelled = new Promise((resolve) => { + onAbort = () => resolve({ recovered: false, reason: "caller_cancelled" }); abortSignal.addEventListener("abort", onAbort, { once: true }); if (abortSignal.aborted) onAbort(); }); @@ -120,12 +134,27 @@ export async function resolveCachedAgentTaskRecovery( request: (signal: AbortSignal) => Promise, abortSignal?: AbortSignal, ): Promise { - if (abortSignal?.aborted) return null; + const result = await resolveCachedAgentTaskRecoveryWithResult(key, maxEntries, async signal => { + const assignment = await request(signal); + return assignment + ? { recovered: true, assignment } + : { recovered: false, reason: "recovery_unavailable" }; + }, abortSignal); + return result.recovered ? result.assignment : null; +} + +export async function resolveCachedAgentTaskRecoveryWithResult( + key: string, + maxEntries: number, + request: (signal: AbortSignal) => Promise, + abortSignal?: AbortSignal, +): Promise { + if (abortSignal?.aborted) return { recovered: false, reason: "caller_cancelled" }; sweepRecoveryCache(Date.now(), maxEntries); const cached = RECOVERY_CACHE.get(key)?.assignment; - if (cached) return cached; + if (cached) return { recovered: true, assignment: cached }; const flight = startRecoveryFlight(key, maxEntries, request); - return flight ? waitForRecoveryFlight(flight, abortSignal) : null; + return flight ? waitForRecoveryFlight(flight, abortSignal) : { recovered: false, reason: "recovery_unavailable" }; } export function discardCachedAgentTaskRecovery(key: string): void { diff --git a/src/server/responses/agent-task-recovery.ts b/src/server/responses/agent-task-recovery.ts index 22b7a4e66b..a15a2563ca 100644 --- a/src/server/responses/agent-task-recovery.ts +++ b/src/server/responses/agent-task-recovery.ts @@ -1,14 +1,16 @@ import { createHash, createHmac, randomBytes } from "node:crypto"; import { decodeJwtPayload, extractAccountId } from "../../oauth/chatgpt"; import type { OcxConfig } from "../../types"; -import { readBoundedResponseBody } from "../../lib/bounded-body"; +import { boundedBodyDecodeFailure, readBoundedResponseBody } from "../../lib/bounded-body"; import { isApiAuthRequired, isProxyAdmissionSecret } from "../auth-cors"; import { structurallyValidFernetTokens } from "./encrypted-payload"; import { cachedAgentTaskRecovery, discardCachedAgentTaskRecovery, resetAgentTaskRecoveryCache, - resolveCachedAgentTaskRecovery, + resolveCachedAgentTaskRecoveryWithResult, + type AgentTaskRecoveryResolution, + type AgentTaskRecoveryResolutionFailureReason, } from "./agent-task-recovery-cache"; /** Experimental opt-in normalization through ChatGPT's fixed Codex endpoint. */ @@ -44,9 +46,8 @@ export interface AgentTaskRecoveryOptions { export type AgentTaskRecoveryFailureReason = | "unsupported_envelope" | "admission_denied" - // Includes cache capacity rejection; does not imply an upstream request was attempted. - | "recovery_unavailable" - | "caller_cancelled" + // recovery_unavailable includes capacity rejection, which does not imply an upstream attempt. + | AgentTaskRecoveryResolutionFailureReason | "input_changed"; export type AgentTaskRecoveryResult = @@ -436,7 +437,7 @@ async function requestRecovery( envelope: AgentEnvelope, options: AgentTaskRecoveryOptions, abortSignal?: AbortSignal, -): Promise { +): Promise { const controller = new AbortController(); const timeout = setTimeout( () => controller.abort(new DOMException("Agent task recovery timed out", "TimeoutError")), @@ -454,8 +455,11 @@ async function requestRecovery( redirect: "error", }); if (!response.ok) { - try { await response.body?.cancel(); } catch { /* already closed */ } - return null; + // A rejected or never-settling cancellation must not extend the recovery deadline. + try { void response.body?.cancel().catch(() => undefined); } catch { /* already closed */ } + if (abortSignal?.aborted) return { recovered: false, reason: "recovery_aborted" }; + if (controller.signal.aborted) return { recovered: false, reason: "recovery_timeout" }; + return { recovered: false, reason: "recovery_http_rejected" }; } const body = await readBoundedResponseBody(response, { signal, @@ -465,10 +469,18 @@ async function requestRecovery( inactivityTimeoutMs: options.timeoutMs ?? 45_000, firstByteTimeoutMs: options.timeoutMs ?? 45_000, }); - if (body.truncated || body.oversized || body.timedOut || !body.displaySafe) return null; - return assignmentFromRecoverySse(body.text, envelope); - } catch { - return null; + if (abortSignal?.aborted) return { recovered: false, reason: "recovery_aborted" }; + if (controller.signal.aborted || body.timedOut) return { recovered: false, reason: "recovery_timeout" }; + if (body.truncated || body.oversized || !body.displaySafe) return { recovered: false, reason: "recovery_invalid_output" }; + const assignment = assignmentFromRecoverySse(body.text, envelope); + return assignment === null + ? { recovered: false, reason: "recovery_invalid_output" } + : { recovered: true, assignment }; + } catch (error) { + if (abortSignal?.aborted) return { recovered: false, reason: "recovery_aborted" }; + const decodeFailure = boundedBodyDecodeFailure(error); + if (controller.signal.aborted || decodeFailure === "timeout") return { recovered: false, reason: "recovery_timeout" }; + return { recovered: false, reason: decodeFailure === "invalid_utf8" ? "recovery_invalid_output" : "recovery_transport_error" }; } finally { clearTimeout(timeout); } @@ -497,23 +509,23 @@ export async function recoverEncryptedAgentTaskWithResult( const admitted = admittedRecovery(req, input, config, context.parentThreadId); if (!admitted.admitted) return { recovered: false, reason: admitted.reason }; const { admission, cacheKey, envelope } = admitted.recovery; - const assignment = await resolveCachedAgentTaskRecovery( + const result = await resolveCachedAgentTaskRecoveryWithResult( cacheKey, options.cacheEntries ?? 200, signal => requestRecovery(admission, envelope, options, signal), context.abortSignal, ); - if (!assignment) { + if (!result.recovered) { return { recovered: false, - reason: context.abortSignal?.aborted ? "caller_cancelled" : "recovery_unavailable", + reason: context.abortSignal?.aborted ? "caller_cancelled" : result.reason, }; } if (context.abortSignal?.aborted) { discardCachedAgentTaskRecovery(cacheKey); return { recovered: false, reason: "caller_cancelled" }; } - if (!injectAssignment(input, envelope, assignment)) { + if (!injectAssignment(input, envelope, result.assignment)) { discardCachedAgentTaskRecovery(cacheKey); return { recovered: false, reason: "input_changed" }; } diff --git a/structure/04_transports-and-sidecars.md b/structure/04_transports-and-sidecars.md index 7e41dc2222..d27022c2ad 100644 --- a/structure/04_transports-and-sidecars.md +++ b/structure/04_transports-and-sidecars.md @@ -1719,7 +1719,17 @@ response is not cacheable. Post-commit and 5xx errors keep the no-resend path. When encrypted agent-task recovery refuses a routed task, its existing 400 error can include a bounded `recovery_reason`: `unsupported_envelope`, -`admission_denied`, `recovery_unavailable`, `caller_cancelled`, or `input_changed`. -The field is omitted when no classified recovery result exists. +`admission_denied`, `recovery_unavailable`, `caller_cancelled`, `input_changed`, +`recovery_http_rejected`, `recovery_timeout`, `recovery_aborted`, +`recovery_transport_error`, or `recovery_invalid_output`. +HTTP rejection requires an observed non-success response. Invalid output includes +invalid UTF-8, oversized bodies, malformed or incomplete recovery streams, and +invalid or conflicting assignments. A caller's cancellation takes precedence over +an owned deadline, which takes precedence over decode/transport failures. +`recovery_aborted` describes a shared recovery cancelled independently of that caller. +Shared-flight waiters receive the same underlying failure unless individually cancelled; +only successful plaintext is cached. Diagnostics contain no upstream error or payload text. +The field is omitted when no classified recovery result exists, and existing combo +branches that return the original target failure keep that response. `recovery_unavailable` includes cache/singleflight capacity and does not prove an upstream request was attempted. No retry or broader envelope acceptance is enabled. diff --git a/tests/server/agent-task-recovery-cache.test.ts b/tests/server/agent-task-recovery-cache.test.ts index 2ee994f8ce..35b5ba7050 100644 --- a/tests/server/agent-task-recovery-cache.test.ts +++ b/tests/server/agent-task-recovery-cache.test.ts @@ -29,16 +29,23 @@ describe("agent task recovery cache", () => { resetAgentTaskRecoveryCache(); }); - test("shared failure gives each waiter its own result without contaminating another key", async () => { + test.each([ + { kind: "http", reason: "recovery_http_rejected" }, + { kind: "reader", reason: "recovery_transport_error" }, + { kind: "decode", reason: "recovery_invalid_output" }, + ] as const)("shared $kind failure gives each waiter its own result without contaminating another key", async ({ kind, reason }) => { let release: (() => void) | undefined; const gate = new Promise(resolve => { release = resolve; }); let fetches = 0; globalThis.fetch = (async () => { const requestNumber = ++fetches; await gate; - return requestNumber === 1 - ? new Response("raw-failure-sentinel", { status: 503 }) - : new Response(recoverySse("Independent assignment.")); + if (requestNumber !== 1) return new Response(recoverySse("Independent assignment.")); + if (kind === "decode") return new Response(new Uint8Array([0xff])); + if (kind === "reader") return new Response(new ReadableStream({ + pull(controller) { controller.error(new TypeError("private-reader-failure")); }, + })); + return new Response("raw-failure-sentinel", { status: 503 }); }) as typeof fetch; const req = new Request("http://localhost/v1/responses", { headers: codexHeaders() }); const config = routedConfig(); @@ -53,8 +60,8 @@ describe("agent task recovery cache", () => { expect(fetches).toBe(2); release?.(); const [firstResult, secondResult, otherResult] = await Promise.all([first, second, other]); - expect(firstResult).toEqual({ recovered: false, reason: "recovery_unavailable" }); - expect(secondResult).toEqual({ recovered: false, reason: "recovery_unavailable" }); + expect(firstResult).toEqual({ recovered: false, reason }); + expect(secondResult).toEqual({ recovered: false, reason }); expect(firstResult).not.toBe(secondResult); expect(otherResult).toEqual({ recovered: true }); expect(firstInput).toEqual(encryptedInput()); @@ -68,6 +75,39 @@ describe("agent task recovery cache", () => { } }); + test("shared flight reset reports abort to surviving callers and never caches late plaintext", async () => { + let release!: () => void; + const gate = new Promise(resolve => { release = resolve; }); + let fetches = 0; + globalThis.fetch = (async () => { + fetches++; + await gate; + return new Response(recoverySse("private-late-assignment")); + }) as typeof fetch; + const req = new Request("http://localhost/v1/responses", { headers: codexHeaders() }); + const firstInput = encryptedInput(); + const secondInput = encryptedInput(); + const first = recoverEncryptedAgentTaskWithResult(req, firstInput, {}, routedConfig()); + const second = recoverEncryptedAgentTaskWithResult(req, secondInput, {}, routedConfig()); + try { + expect(fetches).toBe(1); + resetAgentTaskRecoveryCache(); + release(); + const results = await Promise.all([first, second]); + expect(results).toEqual([ + { recovered: false, reason: "recovery_aborted" }, + { recovered: false, reason: "recovery_aborted" }, + ]); + expect(results[0]).not.toBe(results[1]); + expect(firstInput).toEqual(encryptedInput()); + expect(secondInput).toEqual(encryptedInput()); + expect(agentTaskRecoveryCacheSnapshotForTests()).toEqual({ entries: 0, bytes: 0 }); + } finally { + release(); + await Promise.all([first, second]); + } + }); + for (const succeeds of [true, false]) { test(`caller cancellation stays local when the remaining waiter ${succeeds ? "succeeds" : "fails"}`, async () => { let release: (() => void) | undefined; @@ -95,7 +135,7 @@ describe("agent task recovery cache", () => { release?.(); expect(await second).toEqual(succeeds ? { recovered: true } - : { recovered: false, reason: "recovery_unavailable" }); + : { recovered: false, reason: "recovery_http_rejected" }); expect(fetches).toBe(1); expect(restoreCachedEncryptedAgentTasks(req, encryptedInput(), config)).toBe(succeeds ? 1 : 0); } finally { diff --git a/tests/server/agent-task-recovery.test.ts b/tests/server/agent-task-recovery.test.ts index ceb1c5b6b5..a168f2c364 100644 --- a/tests/server/agent-task-recovery.test.ts +++ b/tests/server/agent-task-recovery.test.ts @@ -1,4 +1,4 @@ -import { afterEach, beforeEach, describe, expect, test } from "bun:test"; +import { afterEach, beforeEach, describe, expect, spyOn, test } from "bun:test"; import { createTranslatorBudget } from "../../src/lib/translator-budget"; import { warnAgentTaskRecoveryStartup } from "../../src/server"; import { @@ -7,6 +7,7 @@ import { recoverEncryptedAgentTaskWithResult, resetAgentTaskRecoveryState, restoreCachedEncryptedAgentTasks, + type AgentTaskRecoveryFailureReason, } from "../../src/server/responses/agent-task-recovery"; import { agentTaskRecoveryWaiterCountForTests } from "../../src/server/responses/agent-task-recovery-cache"; import { @@ -78,24 +79,36 @@ describe("agent task recovery (opt-in, default off)", () => { }); } - const failedRecoveries: Array<[string, () => Response]> = [ - ["HTTP 503", () => new Response("raw-error-sentinel", { status: 503 })], - ["network exception", () => { throw new Error("raw-error-sentinel"); }], - ["malformed SSE", () => new Response("data: {not-json}\n\n")], - ["missing completion", () => new Response(recoverySse("payload-sentinel").split("data: {\"type\":\"response.completed\"")[0])], - ["conflicting assignment", () => new Response(recoverySse("payload-sentinel") + recoveryCompletedSse("other-payload-sentinel"))], - ["failed terminal", () => new Response(recoverySse("payload-sentinel") + 'data: {"type":"response.failed","response":{"error":{"message":"raw-error-sentinel"}}}\n\n')], - ["incomplete terminal", () => new Response(recoverySse("payload-sentinel") + 'data: {"type":"response.incomplete"}\n\n')], - ["bare error", () => new Response(recoverySse("payload-sentinel") + 'data: {"type":"error","error":{"message":"raw-error-sentinel"}}\n\n')], + const failedRecoveries: Array<[string, () => Response, AgentTaskRecoveryFailureReason]> = [ + ["HTTP 401", () => new Response("private-error", { status: 401 }), "recovery_http_rejected"], + ["HTTP 403", () => new Response("private-error", { status: 403 }), "recovery_http_rejected"], + ["HTTP 429", () => new Response("private-error", { status: 429 }), "recovery_http_rejected"], + ["fetch TypeError", () => { throw new TypeError("private-error"); }, "recovery_transport_error"], + ["unowned TimeoutError", () => { throw new DOMException("private-error", "TimeoutError"); }, "recovery_transport_error"], + ["reader TypeError", () => new Response(new ReadableStream({ + pull(controller) { controller.error(new TypeError("private-reader-error")); }, + })), "recovery_transport_error"], + ["invalid UTF-8", () => new Response(new Uint8Array([0xff])), "recovery_invalid_output"], + ["trailing UTF-8", () => new Response(new Uint8Array([0xe2, 0x82])), "recovery_invalid_output"], + ["oversized body", () => new Response(new Uint8Array(4 * 1024 * 1024 + 1)), "recovery_invalid_output"], + ["invalid arguments", () => new Response(recoverySse("task").replace('{\\"assignment\\":\\"task\\"}', '{broken')), "recovery_invalid_output"], + ["HTTP 503", () => new Response("raw-error-sentinel", { status: 503 }), "recovery_http_rejected"], + ["network exception", () => { throw new Error("raw-error-sentinel"); }, "recovery_transport_error"], + ["malformed SSE", () => new Response("data: {not-json}\n\n"), "recovery_invalid_output"], + ["missing completion", () => new Response(recoverySse("payload-sentinel").split("data: {\"type\":\"response.completed\"")[0]), "recovery_invalid_output"], + ["conflicting assignment", () => new Response(recoverySse("payload-sentinel") + recoveryCompletedSse("other-payload-sentinel")), "recovery_invalid_output"], + ["failed terminal", () => new Response(recoverySse("payload-sentinel") + 'data: {"type":"response.failed","response":{"error":{"message":"raw-error-sentinel"}}}\n\n'), "recovery_invalid_output"], + ["incomplete terminal", () => new Response(recoverySse("payload-sentinel") + 'data: {"type":"response.incomplete"}\n\n'), "recovery_invalid_output"], + ["bare error", () => new Response(recoverySse("payload-sentinel") + 'data: {"type":"error","error":{"message":"raw-error-sentinel"}}\n\n'), "recovery_invalid_output"], // Exact-case events are also used by the pinned official Codex source. Recovery's // additional completed-status requirement remains deliberately stricter. - ["mixed-case completion", () => new Response(recoverySse("payload-sentinel").replace("response.completed", "Response.Completed"))], - ["mixed-case status", () => new Response(recoverySse("payload-sentinel").replace('"status":"completed"', '"status":"Completed"'))], - ["missing status", () => new Response(recoverySse("payload-sentinel").replace('"status":"completed",', ""))], - ["ciphertext assignment", () => new Response(recoverySse(FERNET_TASK))], + ["mixed-case completion", () => new Response(recoverySse("payload-sentinel").replace("response.completed", "Response.Completed")), "recovery_invalid_output"], + ["mixed-case status", () => new Response(recoverySse("payload-sentinel").replace('"status":"completed"', '"status":"Completed"')), "recovery_invalid_output"], + ["missing status", () => new Response(recoverySse("payload-sentinel").replace('"status":"completed",', "")), "recovery_invalid_output"], + ["ciphertext assignment", () => new Response(recoverySse(FERNET_TASK)), "recovery_invalid_output"], ]; - for (const [name, response] of failedRecoveries) { - test(`typed recovery keeps ${name} coarse and preserves false without retrying`, async () => { + for (const [name, response, reason] of failedRecoveries) { + test(`typed recovery classifies ${name} and preserves false without retrying`, async () => { const req = new Request("http://localhost/v1/responses", { headers: codexHeaders() }); const config = routedConfig(); let fetches = 0; @@ -103,7 +116,7 @@ describe("agent task recovery (opt-in, default off)", () => { const input = encryptedInput(); const original = structuredClone(input); expect(await recoverEncryptedAgentTaskWithResult(req, input, {}, config)) - .toEqual({ recovered: false, reason: "recovery_unavailable" }); + .toEqual({ recovered: false, reason }); expect(input).toEqual(original); expect(fetches).toBe(1); expect(restoreCachedEncryptedAgentTasks(req, encryptedInput(), config)).toBe(0); @@ -113,6 +126,69 @@ describe("agent task recovery (opt-in, default off)", () => { }); } + test.each(["pending", "rejecting"] as const)("HTTP refusal does not await %s body cancellation", async mode => { + let cancels = 0; + let reads = 0; + let releaseCancel: (() => void) | undefined; + const cancellation = new Promise(resolve => { releaseCancel = resolve; }); + globalThis.fetch = (async () => new Response(new ReadableStream({ + pull() { reads++; }, + cancel() { + cancels++; + return mode === "pending" ? cancellation : Promise.reject(new Error("private-cancel-error")); + }, + }, { highWaterMark: 0 }), { status: 503 })) as typeof fetch; + try { + const result = await recoverEncryptedAgentTaskWithResult( + new Request("http://localhost/v1/responses", { headers: codexHeaders() }), encryptedInput(), {}, routedConfig(), + ); + expect(result).toEqual({ recovered: false, reason: "recovery_http_rejected" }); + expect(cancels).toBe(1); + expect(reads).toBe(0); + } finally { + releaseCancel?.(); + } + }); + + test.each(["headers", "body", "caller"] as const)("owned deadline classification at %s preserves cancellation precedence", async site => { + const callbacks: Array<() => void> = []; + const timers = spyOn(globalThis, "setTimeout").mockImplementation(((callback: () => void) => { + callbacks.push(callback); + return 0 as unknown as ReturnType; + }) as typeof setTimeout); + const caller = new AbortController(); + let started!: () => void; + const ready = new Promise(resolve => { started = resolve; }); + let fetches = 0; + globalThis.fetch = ((_, init) => { + fetches++; + if (site === "body") return Promise.resolve(new Response(new ReadableStream({ + pull(controller) { + controller.enqueue(new Uint8Array([0xe2, 0x82])); + started(); + return new Promise(() => {}); + }, + }, { highWaterMark: 0 }))); + return new Promise((_resolve, reject) => { + init?.signal?.addEventListener("abort", () => reject(init.signal?.reason), { once: true }); + started(); + }); + }) as typeof fetch; + try { + const pending = recoverEncryptedAgentTaskWithResult( + new Request("http://localhost/v1/responses", { headers: codexHeaders() }), encryptedInput(), {}, routedConfig(), + { abortSignal: caller.signal }, + ); + await ready; + callbacks[0]!(); // Fire the owned deadline without wall-clock sleeps. + if (site === "caller") caller.abort(new TypeError("private-caller-error")); + expect(await pending).toEqual({ recovered: false, reason: site === "caller" ? "caller_cancelled" : "recovery_timeout" }); + expect(fetches).toBe(1); + } finally { + timers.mockRestore(); + } + }); + test("keeps the disabled fail-fast response byte-identical to the absent feature", async () => { const snapshot = async (config: ReturnType) => { let fetchCalls = 0; @@ -226,7 +302,7 @@ describe("agent task recovery (opt-in, default off)", () => { expect(response.status).toBe(400); expect(json.error?.code).toBe("unreadable_encrypted_agent_task"); - expect(json.error?.recovery_reason).toBe("recovery_unavailable"); + expect(json.error?.recovery_reason).toBe("recovery_invalid_output"); expect(fetchedUrls.length).toBeGreaterThan(0); expect(fetchedUrls[0]).toContain("chatgpt.com/backend-api/codex"); }); @@ -778,7 +854,7 @@ describe("agent task recovery (opt-in, default off)", () => { expect(fetchedUrls).toHaveLength(1); expect(fetchedUrls[0]).toContain("chatgpt.com/backend-api/codex/responses"); expect(await response.json()).toMatchObject({ - error: { code: "unreadable_encrypted_agent_task", recovery_reason: "recovery_unavailable" }, + error: { code: "unreadable_encrypted_agent_task", recovery_reason: "recovery_transport_error" }, }); }); }); diff --git a/tests/server/bounded-body.test.ts b/tests/server/bounded-body.test.ts index f5223d34a4..0bf5e0ae1b 100644 --- a/tests/server/bounded-body.test.ts +++ b/tests/server/bounded-body.test.ts @@ -1,7 +1,8 @@ -import { describe, expect, test } from "bun:test"; +import { describe, expect, spyOn, test } from "bun:test"; import { BOUNDED_BODY_MAX_BYTES, boundedBodyBufferGrowthsForTests, + boundedBodyDecodeFailure, readBoundedResponseBytes, readBoundedResponseBody, } from "../../src/lib/bounded-body"; @@ -21,6 +22,65 @@ function responseFromChunks(...chunks: Uint8Array[]): Response { } describe("readBoundedResponseBody", () => { + test("only actual decoder exceptions carry the decode discriminator", async () => { + for (const bytes of [new Uint8Array([0xff]), new Uint8Array([0xe2, 0x82])]) { + let caught: unknown; + try { await readBoundedResponseBody(responseFromChunks(bytes), { fatalUtf8: true }); } + catch (error) { caught = error; } + expect(caught).toBeInstanceOf(TypeError); + expect(boundedBodyDecodeFailure(caught)).toBe("invalid_utf8"); + } + const readerError = new TypeError("private-reader-error"); + const response = new Response(new ReadableStream({ pull(controller) { controller.error(readerError); } })); + let caught: unknown; + try { await readBoundedResponseBody(response, { fatalUtf8: true }); } + catch (error) { caught = error; } + expect(caught).toBe(readerError); + expect(boundedBodyDecodeFailure(caught)).toBeUndefined(); + }); + + test("fatal UTF-8 abort retains the exact caller reason without a decode mark", async () => { + const caller = new AbortController(); + const reason = new TypeError("private-caller-error"); + const pending = readBoundedResponseBody(new Response(new ReadableStream({})), { signal: caller.signal, fatalUtf8: true }); + caller.abort(reason); + let caught: unknown; + try { await pending; } catch (error) { caught = error; } + expect(caught).toBe(reason); + expect(boundedBodyDecodeFailure(caught)).toBeUndefined(); + }); + + test.each([0, 1])("fatal timeout flush retains deadline origin %s and cancels without waiting", async deadline => { + const callbacks: Array<() => void> = []; + const timers = spyOn(globalThis, "setTimeout").mockImplementation(((callback: () => void) => { + callbacks.push(callback); + return 0 as unknown as ReturnType; + }) as typeof setTimeout); + let stalled!: () => void; + const ready = new Promise(resolve => { stalled = resolve; }); + let pulls = 0; + let cancelled = false; + const response = new Response(new ReadableStream({ + pull(controller) { + if (pulls++ === 0) controller.enqueue(new Uint8Array([0xe2, 0x82])); + else { stalled(); return new Promise(() => {}); } + }, + cancel() { cancelled = true; return new Promise(() => {}); }, + }, { highWaterMark: 0 })); + try { + const pending = readBoundedResponseBody(response, { fatalUtf8: true }); + await ready; + callbacks[deadline === 0 ? 0 : callbacks.length - 1]!(); + let caught: unknown; + try { await pending; } catch (error) { caught = error; } + expect(caught).toBeInstanceOf(TypeError); + expect(boundedBodyDecodeFailure(caught)).toBe("timeout"); + expect(cancelled).toBe(true); + } finally { + timers.mockRestore(); + } + }); + test("the bounded JSON caller allows a full total deadline for its first byte", () => { expect(UPSTREAM_JSON_BODY_READ_OPTIONS.firstByteTimeoutMs) .toBe(UPSTREAM_JSON_BODY_READ_OPTIONS.totalTimeoutMs); From 2c8ec0bc3684d9079d0c2a50cb0ed5284c56d226 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 10:05:03 +0900 Subject: [PATCH 046/412] docs(devlog): close axis five display and CLI delivery MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Record credited admin landings, successful feature CI, exact merged-tree focused checks, and the unresolved Mac timing/stall diagnosis. Co-authored-by: Éverton Toffanetto Co-authored-by: 투린 Co-authored-by: Zig Zag --- .../260907_axis5_display_cli/000_plan.md | 4 ++ .../001_roadmap_audit.md | 0 .../260907_axis5_display_cli/010_delivery.md | 0 .../260907_axis5_display_cli/020_delivery.md | 40 +++++++++++++++++++ 4 files changed, 44 insertions(+) rename devlog/{_plan => _fin}/260907_axis5_display_cli/000_plan.md (95%) rename devlog/{_plan => _fin}/260907_axis5_display_cli/001_roadmap_audit.md (100%) rename devlog/{_plan => _fin}/260907_axis5_display_cli/010_delivery.md (100%) create mode 100644 devlog/_fin/260907_axis5_display_cli/020_delivery.md diff --git a/devlog/_plan/260907_axis5_display_cli/000_plan.md b/devlog/_fin/260907_axis5_display_cli/000_plan.md similarity index 95% rename from devlog/_plan/260907_axis5_display_cli/000_plan.md rename to devlog/_fin/260907_axis5_display_cli/000_plan.md index 222ef89899..eb6ed46d27 100644 --- a/devlog/_plan/260907_axis5_display_cli/000_plan.md +++ b/devlog/_fin/260907_axis5_display_cli/000_plan.md @@ -31,3 +31,7 @@ Review-ready requirements remain visible; local suite prohibition is explicitly CI scope refinement: the discovered editor is the final layer so the final commit and PR diff include gui/**, activating GUI lint/build/artifact jobs. ci.yml gates always run GUI tests; docs deployment is NOT dispatched because it publishes. Public docs receive static source consistency inspection here, with docs build explicitly unverified unless an existing build-only remote path is available. CI scheduling refinement: lower-layer head commits may use GitHub documented [skip ci] to avoid push/pull_request suite launches; this yields missing/pending evidence, NOT green. Final head has no skip marker and receives lane=all workflow_dispatch. Source: https://docs.github.com/en/actions/how-tos/manage-workflow-runs/skip-workflow-runs (opened 2026-09-07). Admin merge records this explicit owner-requested lower-layer waiver. Do not propagate skip markers into integration merge messages. + +## Terminal status + +DONE: all three feature layers landed; see 020_delivery.md for exact commits, verification boundaries and deferred Mac test-runner investigation. diff --git a/devlog/_plan/260907_axis5_display_cli/001_roadmap_audit.md b/devlog/_fin/260907_axis5_display_cli/001_roadmap_audit.md similarity index 100% rename from devlog/_plan/260907_axis5_display_cli/001_roadmap_audit.md rename to devlog/_fin/260907_axis5_display_cli/001_roadmap_audit.md diff --git a/devlog/_plan/260907_axis5_display_cli/010_delivery.md b/devlog/_fin/260907_axis5_display_cli/010_delivery.md similarity index 100% rename from devlog/_plan/260907_axis5_display_cli/010_delivery.md rename to devlog/_fin/260907_axis5_display_cli/010_delivery.md diff --git a/devlog/_fin/260907_axis5_display_cli/020_delivery.md b/devlog/_fin/260907_axis5_display_cli/020_delivery.md new file mode 100644 index 0000000000..0b06325172 --- /dev/null +++ b/devlog/_fin/260907_axis5_display_cli/020_delivery.md @@ -0,0 +1,40 @@ +# Axis five delivery record + +Outcome: DONE on 2026-09-07. The three feature layers landed in dev through owner-authorized admin integration. Original contribution credit is present in both carried commits and merge commits. + +| Source | Delivery | Merge commit | +| --- | --- | --- | +| #3627 native OpenAI display names | #3820 | 1e16fe4c077ecf353d79c46873d8039d9176704d | +| #3780 provider list JSONL | #3821 | be24986e5ff8474ca6699895855f0ad9352e9d86 | +| #2716 discovered-model name editor | #3824 | 44c69fdd619b272066113388edd80f6c59b0682a | + +The source pull requests were closed after landing. The late #3627 head 81f150e4 added metadata wording already covered by the delivery; its runtime files were checked byte-for-byte against dev before closure. + +## Delivered behavior + +Native labels are reversible overlays on supported bare native rows. IDs, capabilities and routing remain intact; restoring a label still respects existing pinned Astra normalization. Both retained synchronization and convergence pass the same configuration map. + +JSONL emits one configured-provider object per line using the existing JSON fields. Both conflicting flag orders fail without stdout. Multi-provider parity and escaping are covered, and all translated CLI tables and generated capability documentation were updated. + +The editor preserves exact selectors, validates labels, supports reset, and recovers confirmed saves separately from failed refreshes and unknown transport outcomes. Stalled operations use the existing bounded-fetch mechanism. Draft reconciliation preserves the mounted dialog and focus behavior. Desktop/mobile Korean rendering and save/reset/validation/focus were driven against the compiled CI artifact with disposable fixtures. + +## Verification boundaries + +- Feature head f51ec2421c49df0fd4eac8a9a56a6283b426387d: [Cross-platform CI attempt 2](https://github.com/lidge-jun/opencodex/actions/runs/34068041704/attempts/2), 25 successful jobs. Dashboard tests: 1,737 passed, zero failed. Typecheck, lint, scans and build passed. +- Late platform base changes had zero overlap with the 39-file feature delta and passed [their 26-job CI](https://github.com/lidge-jun/opencodex/actions/runs/34068218011). Independent compatibility review checked the decompression diagnostics and container lifecycle interaction. +- Prospective merge tree 85c9b25818a93859a6d6fc824e2ed0678da46c8f passed 370 focused tests on isolated Linux with project Bun 1.4.0: 344 catalog/CLI tests and 26 editor tests, zero failures. The transmitted source archive SHA-256 was ae191e1f0a809e75c9c198bc92233964880541f6747e4603a47b2c180f773d49. +- The actual final runtime merge 44c69fdd619b272066113388edd80f6c59b0682a has exactly that tested tree. This is focused merged-tree evidence plus full feature-head CI, not a claim of full CI on the final merge commit. +- No local test suite, typecheck or build ran. Pushes used --no-verify. Lower-layer CI was deferred until a final-head failure, and no cancelled or missing check was presented as passing. +- Public documentation was source-reviewed. This axis did not run a documentation build. + +## Diagnostic disposition + +One Mac shard reached its 20-minute limit after an unchanged history-lock test. The full Mac control had two Cursor decoded-frame-silence assertion failures; the separately annotated server-auth stream reset was intentional and its test passed. Only the unsuccessful Mac jobs were replayed, with unchanged source and limits, and they passed. The [baseline control comparison](https://github.com/lidge-jun/opencodex/actions/runs/34069848260) also passed. These observations do not establish the stall or timing root cause. No threshold increase, assertion suppression, or unrelated harness fix was included; deeper investigation remains deferred. + +## Attribution + +- Éverton Toffanetto +- 투린 +- Zig Zag + +The preceding numbered files are the historical roadmap and audits; their original _plan locations refer to the planning phase before this closeout. From 0ccc6bdd5d4014f365451eb540bf89d44860f154 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 10:14:55 +0900 Subject: [PATCH 047/412] docs: keep delivery attribution without contact addresses [skip ci] --- devlog/_fin/260907_axis5_display_cli/020_delivery.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/devlog/_fin/260907_axis5_display_cli/020_delivery.md b/devlog/_fin/260907_axis5_display_cli/020_delivery.md index 0b06325172..7a2b76d0f8 100644 --- a/devlog/_fin/260907_axis5_display_cli/020_delivery.md +++ b/devlog/_fin/260907_axis5_display_cli/020_delivery.md @@ -33,8 +33,10 @@ One Mac shard reached its 20-minute limit after an unchanged history-lock test. ## Attribution -- Éverton Toffanetto -- 투린 -- Zig Zag +- Éverton Toffanetto +- 투린 +- Zig Zag + +Original author identities remain in the landed commits; this note lists names without contact addresses. The preceding numbered files are the historical roadmap and audits; their original _plan locations refer to the planning phase before this closeout. From b29bbb440aaf70b283445a9c37e194a4a4e6859a Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 10:51:00 +0900 Subject: [PATCH 048/412] fix(clients): preserve exact Aside file identities [skip ci] Use private BigInt stat identities so distinct legal 64-bit file IDs are not collapsed by Number conversion. Preserve all path/link/hardlink and directory replacement checks, manifest bounds, public IO types and serialization. Add semantic high-ID and native link controls with fixture-reachability checks. No local suite was run; the earlier Windows incident IDs remain unmeasured. --- scripts/test-layout/layout.json | 1 + src/clients/aside-profiles.ts | 15 ++- tests/clients/aside-profile-identity.test.ts | 132 +++++++++++++++++++ tests/fixtures/test-layout-expected.json | 1 + 4 files changed, 142 insertions(+), 7 deletions(-) create mode 100644 tests/clients/aside-profile-identity.test.ts diff --git a/scripts/test-layout/layout.json b/scripts/test-layout/layout.json index f560dffeb5..7547d467c7 100644 --- a/scripts/test-layout/layout.json +++ b/scripts/test-layout/layout.json @@ -239,6 +239,7 @@ "aside-profiles-routes.test.ts": "server", "aside-profiles.test.ts": "clients", "aside-profile-paths.test.ts": "clients", + "aside-profile-identity.test.ts": "clients", "aside-profile-sync-owner.test.ts": "clients", "assert-mergeable-review.test.ts": "ci-workflows", "auto-compact-budget.test.ts": "providers", diff --git a/src/clients/aside-profiles.ts b/src/clients/aside-profiles.ts index 31f13d9b76..770857611a 100644 --- a/src/clients/aside-profiles.ts +++ b/src/clients/aside-profiles.ts @@ -1,4 +1,4 @@ -import { lstatSync, readFileSync, readlinkSync, realpathSync, statSync, type Stats } from "node:fs"; +import { lstatSync, readFileSync, readlinkSync, realpathSync, statSync, type BigIntStats } from "node:fs"; import { homedir } from "node:os"; import { basename, dirname, isAbsolute, join, resolve } from "node:path"; import type { IntegrationIO } from "../integrations/config-io"; @@ -14,7 +14,7 @@ export interface AsideProfile { } const MAX_PROFILES = 128; -const MAX_MANIFEST_BYTES = 4 * 1024 * 1024; +const MAX_MANIFEST_BYTES = 4n * 1024n * 1024n; const MAX_LEAF_LINKS = 40; function refuse(message: string): never { @@ -30,9 +30,10 @@ function object(value: unknown): value is Record { return value !== null && typeof value === "object" && !Array.isArray(value); } -function inspect(path: string, follow = false): Stats | null { +function inspect(path: string, follow = false): BigIntStats | null { try { - return follow ? statSync(path) : lstatSync(path); + // File IDs can exceed Number's exact integer range; never round identities. + return follow ? statSync(path, { bigint: true }) : lstatSync(path, { bigint: true }); } catch (error) { if ((error as NodeJS.ErrnoException).code === "ENOENT") return null; return refuse("a filesystem boundary could not be inspected."); @@ -110,10 +111,10 @@ export function listAsideProfiles(env: NodeJS.ProcessEnv = process.env, home: st return readProfiles(root); } -type DirectoryIdentity = { path: string; dev: number; ino: number }; +type DirectoryIdentity = { path: string; dev: bigint; ino: bigint }; type Boundary = Array; -function sameIdentity(a: Pick, b: Pick): boolean { +function sameIdentity(a: Pick, b: Pick): boolean { return a.dev === b.dev && a.ino === b.ino; } @@ -162,7 +163,7 @@ function boundary(profile: AsideProfile, profiles: AsideProfile[], mutation: boo } if (absent) return identities; const leaf = inspect(profile.configPath); - if (leaf && (leaf.isSymbolicLink() || !leaf.isFile() || leaf.nlink > 1)) { + if (leaf && (leaf.isSymbolicLink() || !leaf.isFile() || leaf.nlink > 1n)) { refuse("the model catalog is a link, shared file or non-regular file."); } if (leaf && canonical(profile.configPath) !== join(parent!, "models.json")) { diff --git a/tests/clients/aside-profile-identity.test.ts b/tests/clients/aside-profile-identity.test.ts new file mode 100644 index 0000000000..771966a1c4 --- /dev/null +++ b/tests/clients/aside-profile-identity.test.ts @@ -0,0 +1,132 @@ +import { expect, spyOn, test } from "bun:test"; +import * as fs from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import type { IntegrationIO } from "../../src/integrations/config-io"; +import { removeTreeWithRetry } from "../helpers/remove-tree"; + +// Capture real delegates before spying. Only fixture inode values are controlled; +// existence, file type, link count, realpath and link resolution remain native. +const nativeLstat = fs.lstatSync; +const nativeStat = fs.statSync; +const FIRST_INODE = 2n ** 53n; +const SECOND_INODE = FIRST_INODE + 1n; + +test("Aside preserves high file identities without admitting shared targets or directory replacement", async () => { + const home = fs.mkdtempSync(join(tmpdir(), "ocx-aside-identity-")); + const root = join(home, ".aside"); + const paths = [0, 1].map(id => join(root, "u", String(id), "models.json")); + const identities = new Map(); + const reads = new Set(); + let observingBoundary = false; + const restoreSpies: Array<() => void> = []; + + function controlledStat(delegate: typeof fs.statSync, kind: "stat" | "lstat"): typeof fs.statSync { + // Preserve fs's overload contract: the native delegate determines the result + // type, including undefined for throwIfNoEntry:false and number vs bigint. + return ((path: fs.PathLike, options?: fs.StatOptions) => { + const stats = delegate(path, options); + const inode = typeof path === "string" ? identities.get(path) : undefined; + if (stats && inode !== undefined) { + if (observingBoundary) reads.add(`${kind}:${path}`); + // Mutate this fresh native result, retaining its prototype and method + // receiver. Spreading Stats would lose native isFile/isDirectory methods. + stats.ino = options?.bigint ? inode : Number(inode); + } + return stats; + }) as typeof fs.statSync; + } + + function observe(run: () => T): T { + reads.clear(); + observingBoundary = true; + try { return run(); } finally { observingBoundary = false; } + } + + try { + for (const id of [0, 1]) fs.mkdirSync(join(root, "u", String(id)), { recursive: true }); + fs.writeFileSync(join(root, "accounts.json"), JSON.stringify({ + currentAccountId: 0, accounts: [{ id: 0 }, { id: 1 }], + })); + for (const path of paths) fs.writeFileSync(path, "{}"); + // Controlled IDs must not hide a runtime lacking native BigInt stat support. + expect(typeof nativeStat(paths[0]!, { bigint: true }).ino).toBe("bigint"); + expect(typeof nativeLstat(paths[0]!, { bigint: true }).ino).toBe("bigint"); + const lstatSpy = spyOn(fs, "lstatSync"); + restoreSpies.push(() => lstatSpy.mockRestore()); + lstatSpy.mockImplementation(controlledStat(nativeLstat, "lstat")); + const statSpy = spyOn(fs, "statSync"); + restoreSpies.push(() => statSpy.mockRestore()); + statSpy.mockImplementation(controlledStat(nativeStat, "stat")); + + // Load after spies so the regression also covers the native named-import seam. + const { assertAsideProfileBoundary, guardAsideProfileIO, listAsideProfiles } = + await import("../../src/clients/aside-profiles"); + const [selected, peer] = listAsideProfiles({}, home); + if (!selected || !peer) throw new Error("fixture requires two profiles"); + const profiles = [selected, peer]; + expect(Number(FIRST_INODE)).toBe(Number(SECOND_INODE)); + expect(FIRST_INODE).not.toBe(SECOND_INODE); + expect(nativeStat(selected.configPath, { bigint: true }).dev) + .toBe(nativeStat(peer.configPath, { bigint: true }).dev); + // Distinct catalogs and directories are allowed even though their Number + // representations collide. + // Reads are recorded only DURING boundary calls, so a missed spy binding + // cannot silently turn this into a passing ordinary-filesystem test. + for (const target of ["configPath", "detectDir"] as const) { + identities.clear(); + identities.set(selected[target], FIRST_INODE); + identities.set(peer[target], SECOND_INODE); + for (const profile of profiles) { + const sibling = profile === selected ? peer : selected; + observe(() => expect(() => assertAsideProfileBoundary(profile, profiles, true)).not.toThrow()); + expect(reads.has(`lstat:${profile[target]}`)).toBe(true); + expect(reads.has(`stat:${sibling[target]}`)).toBe(true); + } + } + + identities.clear(); + identities.set(selected.detectDir, FIRST_INODE); + let delegatedReads = 0; + const io: IntegrationIO = { + readText: () => { delegatedReads++; return { kind: "text", text: "{}" }; }, + statKind: () => "file", + writeText: () => {}, removeFile: () => {}, mkdirp: () => {}, + now: () => 0, appendJournal: () => {}, putRecord: () => {}, dropRecord: () => {}, + }; + const guarded = observe(() => guardAsideProfileIO(selected, io, profiles)); + expect(reads.has(`lstat:${selected.detectDir}`)).toBe(true); + observe(() => expect(guarded.readText(selected.configPath)).toEqual({ kind: "text", text: "{}" })); + expect(reads.has(`lstat:${selected.detectDir}`)).toBe(true); + expect(delegatedReads).toBe(1); + identities.set(selected.detectDir, SECOND_INODE); + observe(() => expect(() => guarded.readText(selected.configPath)) + .toThrow("the account directory changed after the operation began.")); + expect(reads.has(`lstat:${selected.detectDir}`)).toBe(true); + expect(delegatedReads).toBe(1); + + // No synthetic IDs for these controls: real hardlinks and symlinks must + // continue to be refused by the same boundary, with native stat delegates. + identities.clear(); + fs.unlinkSync(peer.configPath); + fs.linkSync(selected.configPath, peer.configPath); + expect(nativeLstat(selected.configPath, { bigint: true }).nlink).toBe(2n); + for (const profile of profiles) { + expect(() => assertAsideProfileBoundary(profile, profiles, true)) + .toThrow("the model catalog is a link, shared file or non-regular file."); + } + fs.unlinkSync(peer.configPath); + fs.symlinkSync(selected.configPath, peer.configPath, "file"); + expect(nativeLstat(peer.configPath, { bigint: true }).isSymbolicLink()).toBe(true); + expect(() => assertAsideProfileBoundary(selected, profiles, true)) + .toThrow("account catalogs share a target."); + expect(() => assertAsideProfileBoundary(peer, profiles, true)) + .toThrow("the model catalog is a link, shared file or non-regular file."); + } finally { + observingBoundary = false; + identities.clear(); + reads.clear(); + for (const restore of restoreSpies.reverse()) restore(); + removeTreeWithRetry(home); + } +}); diff --git a/tests/fixtures/test-layout-expected.json b/tests/fixtures/test-layout-expected.json index 2a1cac7ec3..cac40976e1 100644 --- a/tests/fixtures/test-layout-expected.json +++ b/tests/fixtures/test-layout-expected.json @@ -74,6 +74,7 @@ "aside-profiles-routes.test.ts": "server", "aside-profiles.test.ts": "clients", "aside-profile-paths.test.ts": "clients", + "aside-profile-identity.test.ts": "clients", "aside-profile-sync-owner.test.ts": "clients", "assert-mergeable-review.test.ts": "ci-workflows", "auto-compact-budget.test.ts": "providers", From be112e4fae9596950f81fa1b039d5f1f5c365a5d Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 11:24:54 +0900 Subject: [PATCH 049/412] docs: close axis1 bug-fix delivery record [skip ci] --- .../260907_axis1_bugfixes/000_plan.md | 2 + .../260907_axis1_bugfixes/010_roadmap.md | 0 .../260907_axis1_bugfixes/011_audit.md | 0 .../260907_axis1_bugfixes/012_roadmap_lock.md | 0 .../020_bounded_fixes.md | 0 .../021_source_review.md | 0 .../260907_axis1_bugfixes/030_delivery.md | 0 .../031_delivery_record.md | 53 +++++++++++++++++++ 8 files changed, 55 insertions(+) rename devlog/{_plan => _fin}/260907_axis1_bugfixes/000_plan.md (96%) rename devlog/{_plan => _fin}/260907_axis1_bugfixes/010_roadmap.md (100%) rename devlog/{_plan => _fin}/260907_axis1_bugfixes/011_audit.md (100%) rename devlog/{_plan => _fin}/260907_axis1_bugfixes/012_roadmap_lock.md (100%) rename devlog/{_plan => _fin}/260907_axis1_bugfixes/020_bounded_fixes.md (100%) rename devlog/{_plan => _fin}/260907_axis1_bugfixes/021_source_review.md (100%) rename devlog/{_plan => _fin}/260907_axis1_bugfixes/030_delivery.md (100%) create mode 100644 devlog/_fin/260907_axis1_bugfixes/031_delivery_record.md diff --git a/devlog/_plan/260907_axis1_bugfixes/000_plan.md b/devlog/_fin/260907_axis1_bugfixes/000_plan.md similarity index 96% rename from devlog/_plan/260907_axis1_bugfixes/000_plan.md rename to devlog/_fin/260907_axis1_bugfixes/000_plan.md index 1fa7537164..ad0da69270 100644 --- a/devlog/_plan/260907_axis1_bugfixes/000_plan.md +++ b/devlog/_fin/260907_axis1_bugfixes/000_plan.md @@ -1,5 +1,7 @@ # Axis 1: measured bug fixes and failure diagnostics +Completed: see [031_delivery_record.md](031_delivery_record.md) for merged commits, final CI, attribution and deferrals. + Archetype: satisfy existing contracts. Trigger: owner assigned axis 1 (#3809, #3464, #3661). Goal: deliver reviewable fixes through a manual PR chain and merge the verified scope. Non-goals: new account/retry policy, auth defaults, multipart recovery, releases, native stacks, sibling edits. Stop: merged feasible scope plus explicit unresolved dispositions. Escalation: defer a policy-dependent or unreproducible slice; reclaim a worker slice after two failed packets. Evidence: this unit plus ignored `.tmp/axis1/` and `.codexclaw` receipts. Resources: task-owned worktree/branches and GitHub repository access; Astra high leaves within host capacity; no caller-specified token or wall-clock budget. Baseline: origin/dev 137d6a727; source PR #3809 at 4a1012359a522ddd6d7ff77203c9e5f3632d605c. Assigned 5cc8 checkout has pre-existing changes and remains untouched. Code lives in /tmp/ocx-axis1-20260907. diff --git a/devlog/_plan/260907_axis1_bugfixes/010_roadmap.md b/devlog/_fin/260907_axis1_bugfixes/010_roadmap.md similarity index 100% rename from devlog/_plan/260907_axis1_bugfixes/010_roadmap.md rename to devlog/_fin/260907_axis1_bugfixes/010_roadmap.md diff --git a/devlog/_plan/260907_axis1_bugfixes/011_audit.md b/devlog/_fin/260907_axis1_bugfixes/011_audit.md similarity index 100% rename from devlog/_plan/260907_axis1_bugfixes/011_audit.md rename to devlog/_fin/260907_axis1_bugfixes/011_audit.md diff --git a/devlog/_plan/260907_axis1_bugfixes/012_roadmap_lock.md b/devlog/_fin/260907_axis1_bugfixes/012_roadmap_lock.md similarity index 100% rename from devlog/_plan/260907_axis1_bugfixes/012_roadmap_lock.md rename to devlog/_fin/260907_axis1_bugfixes/012_roadmap_lock.md diff --git a/devlog/_plan/260907_axis1_bugfixes/020_bounded_fixes.md b/devlog/_fin/260907_axis1_bugfixes/020_bounded_fixes.md similarity index 100% rename from devlog/_plan/260907_axis1_bugfixes/020_bounded_fixes.md rename to devlog/_fin/260907_axis1_bugfixes/020_bounded_fixes.md diff --git a/devlog/_plan/260907_axis1_bugfixes/021_source_review.md b/devlog/_fin/260907_axis1_bugfixes/021_source_review.md similarity index 100% rename from devlog/_plan/260907_axis1_bugfixes/021_source_review.md rename to devlog/_fin/260907_axis1_bugfixes/021_source_review.md diff --git a/devlog/_plan/260907_axis1_bugfixes/030_delivery.md b/devlog/_fin/260907_axis1_bugfixes/030_delivery.md similarity index 100% rename from devlog/_plan/260907_axis1_bugfixes/030_delivery.md rename to devlog/_fin/260907_axis1_bugfixes/030_delivery.md diff --git a/devlog/_fin/260907_axis1_bugfixes/031_delivery_record.md b/devlog/_fin/260907_axis1_bugfixes/031_delivery_record.md new file mode 100644 index 0000000000..439c395f8b --- /dev/null +++ b/devlog/_fin/260907_axis1_bugfixes/031_delivery_record.md @@ -0,0 +1,53 @@ +# Axis 1 delivery record + +Terminal outcome: DONE for the authorized bounded bug/diagnostic scope, with the explicitly listed broader work deferred. Completed 2026-09-07. + +## Delivered + +- #3825 carries #3809 with serving-credential quota attribution, upstream deadline handling, probe-clock preservation and known-reset expiration. Invalid reset metadata does not erase otherwise valid usage; no new unknown-window TTL or synthetic zero was introduced. +- #3826 corrects CLI-versus-proxy version guidance in both directions and prevents false doctor match claims. +- #3827 exposes bounded recovery refusal/timeout/transport/invalid-output reasons through shared flights while preserving admission, success-only caching and caller-local cancellation. +- #3842 is supporting validation work: exact private BigInt file identities preserve existing Aside profile boundaries, including high-ID distinction and directory replacement detection. Public IO/serialization and link refusals remain unchanged. + +## Landing proof + +All four ordinary PRs were merged bottom-up with owner-authorized admin authority. No native stack was registered. Children were retargeted to dev before their parent branches could be automatically deleted. + +| PR | Reviewed layer head | Merge commit | +| --- | --- | --- | +| [#3825](https://github.com/lidge-jun/opencodex/pull/3825) | `d3c70f9d8c8cc6fced7a93577b93e8b141473ea3` | `85fbdb59621046da3db1839a5cce4c7260f99385` | +| [#3826](https://github.com/lidge-jun/opencodex/pull/3826) | `872f0e5aa714f6a2e757510195d1c038ac70e26d` | `860baaf9032fa7ea3030c78ab555608e3325a338` | +| [#3827](https://github.com/lidge-jun/opencodex/pull/3827) | `2e8ef03428f8e619dc92b250fbbc5d5dd7ad53cb` | `5a97db9b20f03a65e714ddc88d2523bea9aeacae` | +| [#3842](https://github.com/lidge-jun/opencodex/pull/3842) | `b29bbb440aaf70b283445a9c37e194a4a4e6859a` | `5fdf9bbdd9ff7657f0b6d7101697317d708af0e7` | + +The runtime integration commit is `5fdf9bbdd9ff7657f0b6d7101697317d708af0e7`. Its full tree `90a75118402d2f310393bef9ac3e4668cfcbdcfa` exactly matches the final combined validation candidate `9470fdb1bc9a02715a3760c36301d3d030a4e4fa`. A fresh fetch and ancestor check confirmed every merge on dev. The candidate included dev `bf85e675484a2391b94b2135bbebe739813a9621` plus all four layers. + +## Verification + +- [Cross-platform CI 34074350604](https://github.com/lidge-jun/opencodex/actions/runs/34074350604): all 26 jobs succeeded at the combined candidate, including Linux, macOS, Windows, Docker smoke, typecheck, privacy, build and operational checks. +- [Service lifecycle 34074351720](https://github.com/lidge-jun/opencodex/actions/runs/34074351720): Linux, macOS and Windows succeeded at the same candidate. +- Independent Astra high source/security audits covered the scoped implementations, merge interactions and exact-identity support. +- All current review threads on the four delivered PRs were resolved after runtime evidence was available. +- No local application test suite or local typecheck ran. Pushes used --no-verify; per-layer CI was deferred by explicit owner instruction. Cancelled and skipped checks were never represented as passing tests. +- Privacy scanning passed. Documentation static build produced 425 pages in 8.23 seconds at 2522264d5; its documentation subtree remained unchanged by the supporting identity fix. Dependencies were installed from the frozen lockfile with install scripts disabled. The build changed no tracked files. +- The assigned pre-existing working-tree changes were preserved; delivery used an isolated worktree. + +## Corrections and remaining limits + +Initial verification exposed incomplete test homes/default configuration and old calendar reset dates in current-measurement fixtures. Those fixtures were corrected without removing behavioral assertions. Known-expiry tests use explicit simulated time. Later review added expired-window handling, field normalization and a global test network guard. + +Imported axis-five closeout contact addresses blocked privacy scanning. [#3836](https://github.com/lidge-jun/opencodex/pull/3836) removed the addresses while retaining author names and all commit attribution; no scanner rule or allowlist was weakened. + +Earlier Windows Aside incidents reported an apparent shared catalog target. Their actual file IDs were not captured. The independently demonstrable Number-precision defect was corrected by #3842, and semantic/native regressions plus the previously failing route case passed in final CI. This does not retroactively prove every earlier incident's raw IDs or cause. + +An earlier Windows outbound-proxy test timed out at its existing 15-second bound. Its scoped test/transport files were unchanged and the stalled phase was not measured. No timeout increase or unrelated proxy repair was made; later passing execution is not a claim that the timing root cause was fixed. + +## Attribution and issue disposition + +Éverton Toffanetto's Co-authored-by trailer is retained in reachable commit `f215f79b4562735029ad5672a68bc6104e534b98`. The issue reporters garysassano and Hu9956 are acknowledged in the corresponding diagnostic commits. Merge commits preserve those commits and trailers. + +The original #3809 was confirmed closed with a landed-via-#3825 marker at final recheck. The initial carry source was 4a1012359; the original author subsequently updated the source PR, so this record does not claim a verbatim merge of its later head. + +#3464 remains open for its broader automatic-repair/request-policy requests. #3661 remains open for multipart reconstruction and recovery retry policy. Those choices were outside this delivery. No release, deployment, new account-selection strategy or authentication-default change was performed. + +The preceding numbered documents are historical plans and audits; their original _plan paths refer to the planning stage. From b96aa7d13031c0cb88eaddceeca47001e5dec474 Mon Sep 17 00:00:00 2001 From: DaedalGames Date: Mon, 7 Sep 2026 11:52:28 +0900 Subject: [PATCH 050/412] fix(codex): defer validation for quota-exhausted account registration --- .../pr-assets/codex-quota-registration.png | Bin 0 -> 118343 bytes .../docs/fr/guides/codex-integration.md | 12 +- .../content/docs/guides/codex-integration.md | 12 +- .../src/content/docs/guides/providers.md | 3 + .../docs/ja/guides/codex-integration.md | 6 +- .../docs/ko/guides/codex-integration.md | 6 +- .../docs/ru/guides/codex-integration.md | 13 +- .../docs/tr/guides/codex-integration.md | 14 +- .../docs/zh-cn/guides/codex-integration.md | 11 +- .../docs/zh-tw/guides/codex-integration.md | 11 +- .../components/codex-account-pool-cards.tsx | 5 +- gui/src/i18n/de.ts | 2 + gui/src/i18n/en.ts | 2 + gui/src/i18n/fr.ts | 2 + gui/src/i18n/ja.ts | 2 + gui/src/i18n/ko.ts | 2 + gui/src/i18n/ru.ts | 2 + gui/src/i18n/tr.ts | 2 + gui/src/i18n/zh-TW.ts | 2 + gui/src/i18n/zh.ts | 2 + gui/src/oauth-health-display.ts | 7 +- gui/tests/oauth-health-display.test.ts | 6 + src/codex/account-store.ts | 22 ++- src/codex/account-usability.ts | 5 +- src/codex/auth-api.ts | 55 +++++- src/oauth/health.ts | 16 +- src/oauth/token-guardian.ts | 1 + src/types/accounts.ts | 2 + .../codex-account-store.test.ts | 15 ++ .../codex-integration/codex-auth-api.test.ts | 175 +++++++++++++++++- .../codex-integration/token-guardian.test.ts | 15 ++ 31 files changed, 363 insertions(+), 67 deletions(-) create mode 100644 .github/pr-assets/codex-quota-registration.png diff --git a/.github/pr-assets/codex-quota-registration.png b/.github/pr-assets/codex-quota-registration.png new file mode 100644 index 0000000000000000000000000000000000000000..a98a0b56c69c483bb10e6a112112ddf305fbe6d5 GIT binary patch literal 118343 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 literal 0 HcmV?d00001 diff --git a/docs-site/src/content/docs/fr/guides/codex-integration.md b/docs-site/src/content/docs/fr/guides/codex-integration.md index 02ffa8a211..3132e16fc8 100644 --- a/docs-site/src/content/docs/fr/guides/codex-integration.md +++ b/docs-site/src/content/docs/fr/guides/codex-integration.md @@ -367,13 +367,11 @@ délégation v1/base/v2 et de ses mécanismes de repli. ## Préchauffage des comptes Codex -Lorsqu'un compte ChatGPT est ajouté au groupe de comptes Codex, opencodex le vérifie avant de l'enregistrer -avec une petite requête en streaming vers le service Codex Responses. La requête utilise un véritable tableau -d'éléments Responses (`input: [{ type: "message", ... }]`), attend `response.completed` et utilise par défaut -`gpt-5.4-mini`. Si ce modèle renvoie HTTP 400, opencodex réessaie avec `gpt-5.5` ; les détails structurés de -l'erreur en amont sont affichés sans exposer le corps brut de la réponse. La revalidation en arrière-plan est -distincte et désactivée par défaut. Elle ne s'exécute que si Token Guardian est actif, si la stratégie -d'actualisation `chatgpt` vaut `proactive` et si `tokenGuardian.codexWarmupEnabled` vaut true. +L’ajout ou la réauthentification vérifie normalement le compte avant son enregistrement par une petite requête attendant `response.completed`. Le modèle par défaut est `gpt-5.4-mini`, avec un essai sur `gpt-5.5` en cas de HTTP 400. Les erreurs publiques contiennent des catégories fixes, sans corps de réponse brut. + +Si la lecture authentifiée des quotas avec le nouveau jeton OAuth confirme un quota de 5 heures, hebdomadaire ou mensuel épuisé, le compte est enregistré sans appel au modèle et affiche **Validation en attente**. Il reste exclu du routage après un redémarrage ou un renouvellement du jeton. Après récupération du quota, actualisez les quotas : une lecture récente et complète avec de la capacité disponible permet une petite requête de validation. Seule sa réussite active le compte. Tout échec conserve la restriction. Les lectures passives ne déclenchent pas cette requête. Un quota inconnu à l’inscription conserve la vérification habituelle. + +La revalidation en arrière-plan est distincte et désactivée par défaut. Elle nécessite Token Guardian, la politique `proactive` du fournisseur `openai` et `tokenGuardian.codexWarmupEnabled`, et ignore les comptes dont la validation d’inscription est en attente. ## Restauration de Codex natif diff --git a/docs-site/src/content/docs/guides/codex-integration.md b/docs-site/src/content/docs/guides/codex-integration.md index 64466b61a4..c709cd2ce1 100644 --- a/docs-site/src/content/docs/guides/codex-integration.md +++ b/docs-site/src/content/docs/guides/codex-integration.md @@ -547,13 +547,11 @@ Catalog sync makes the selected sub-agent models available to Codex; see [Codex ## Codex account warmup -When a ChatGPT account is added to the Codex account pool, opencodex verifies it before persistence -with a small streaming request to the Codex Responses backend. The request uses a real Responses -item array (`input: [{ type: "message", ... }]`), waits for `response.completed`, and defaults to -`gpt-5.4-mini`. If that model returns HTTP 400, it retries with `gpt-5.5`; structured upstream error -details are surfaced without exposing raw response bodies. Background revalidation is separate and -off by default; it runs only when Token Guardian is enabled, the `chatgpt` refresh policy is -`proactive`, and `tokenGuardian.codexWarmupEnabled` is true. +When a ChatGPT account is added or reauthenticated, OpenCodex normally verifies it before saving with a small streaming request to the Codex Responses backend. It waits for `response.completed`, defaults to `gpt-5.4-mini`, and retries with `gpt-5.5` on HTTP 400. Public errors contain fixed failure categories rather than raw upstream response bodies. + +If the new OAuth credential's authenticated usage lookup confirms an exhausted 5-hour, weekly, or monthly quota, the account is saved without this model request and shows **Validation pending**. It cannot serve pool requests, even after a restart or token refresh. Once quota recovers, **Refresh quotas** finishes validation: a fresh, complete usage reading with headroom permits one small model request, and only a completed response enables the account. Failed or incomplete readings and failed validation preserve the restriction. Passive account polling does not trigger deferred validation. Unknown usage during initial registration retains the normal warmup gate. + +Background revalidation is separate and off by default. It requires Token Guardian, the `openai` provider's `proactive` refresh policy, and `tokenGuardian.codexWarmupEnabled`. It skips accounts awaiting deferred registration validation. ## Restoring native Codex diff --git a/docs-site/src/content/docs/guides/providers.md b/docs-site/src/content/docs/guides/providers.md index 5e46979816..7600ceed2a 100644 --- a/docs-site/src/content/docs/guides/providers.md +++ b/docs-site/src/content/docs/guides/providers.md @@ -30,6 +30,9 @@ Desktop mode and current credential-bound upstream permission; a catalog entry a authorize a request. See [Luna Reserve alongside routed models](/reference/cli/providers-accounts/#luna-reserve-alongside-routed-models) for setup, restart order, authorization requirements, and unsupported helpers. +For adding an account with exhausted quota and finishing its deferred validation, see +[Codex account warmup](/guides/codex-integration/#codex-account-warmup). + ### Providers overview pool capacity For Codex login in Pool mode, the Providers overview shows a configured-weight estimate of the diff --git a/docs-site/src/content/docs/ja/guides/codex-integration.md b/docs-site/src/content/docs/ja/guides/codex-integration.md index d1d977b35c..773ad97e99 100644 --- a/docs-site/src/content/docs/ja/guides/codex-integration.md +++ b/docs-site/src/content/docs/ja/guides/codex-integration.md @@ -233,7 +233,11 @@ ocx service install # persistent: auto-starts on login and respawns on crash ## Codex アカウントのウォームアップ -ChatGPT アカウントが Codex アカウント プールに追加されると、opencodex は、Codex Response バックエンドへの小さなストリーミング リクエストで永続化する前にそれを検証します。リクエストは実際の応答項目配列 (`input: [{ type: "message", ... }]`) を使用し、`response.completed` を待機し、デフォルトは `gpt-5.4-mini` になります。そのモデルが HTTP 400 を返した場合、`gpt-5.5` で再試行します。構造化されたアップストリーム エラーの詳細は、生の応答本体を公開することなく表示されます。バックグラウンドの再検証は個別に行われ、デフォルトではオフになっています。これは、トークン ガーディアンが有効で、`chatgpt` 更新ポリシーが `proactive` で、`tokenGuardian.codexWarmupEnabled` が true の場合にのみ実行されます。 +アカウントの追加・再認証では通常、保存前に小さなモデルリクエストで `response.completed` を確認します。既定モデルは `gpt-5.4-mini` で、HTTP 400 の場合は `gpt-5.5` で再試行します。公開エラーには固定の分類のみを表示し、生の応答本文は公開しません。 + +新しい OAuth トークンによる使用量取得で5時間・週次・月次の上限到達が確認された場合、モデルを呼ばずに保存し、**検証待ち**と表示します。再起動やトークン更新後も使用できません。上限回復後に使用量を更新すると、十分な空き容量を示す完全な最新情報を確認してから小さなモデルリクエストを送り、完了した場合のみ使用可能になります。取得や検証の失敗では待機状態を維持します。通常の状態ポーリングは検証リクエストを送りません。初回登録時の使用量が不明な場合は通常の検証が必要です。 + +バックグラウンド再検証は別機能で既定では無効です。Token Guardian、`openai` の `proactive` 更新ポリシー、`tokenGuardian.codexWarmupEnabled` が必要で、登録検証待ちのアカウントは除外します。 ## ネイティブ Codexの復元 diff --git a/docs-site/src/content/docs/ko/guides/codex-integration.md b/docs-site/src/content/docs/ko/guides/codex-integration.md index 44551de837..f8accd51b6 100644 --- a/docs-site/src/content/docs/ko/guides/codex-integration.md +++ b/docs-site/src/content/docs/ko/guides/codex-integration.md @@ -230,7 +230,11 @@ catalog sync는 선택된 서브에이전트 모델을 Codex가 쓸 수 있게 ## Codex 계정 워밍업 -ChatGPT 계정을 Codex account pool에 추가하면, opencodex는 이를 저장하기 전에 Codex Responses backend로 작은 streaming request를 보내 확인합니다. 요청은 실제 Responses item array(`input: [{ type: "message", ... }]`)를 사용하고, `response.completed`를 기다리며, 기본값은 `gpt-5.4-mini`입니다. 그 모델이 HTTP 400을 반환하면 `gpt-5.5`로 다시 시도합니다. 구조화된 upstream error detail은 보여 주되 raw response body는 노출하지 않습니다. background revalidation은 별도 기능이며 기본값은 꺼져 있습니다. Token Guardian이 활성화되고, `chatgpt` refresh policy가 `proactive`이며, `tokenGuardian.codexWarmupEnabled`가 true일 때만 실행됩니다. +ChatGPT 계정을 추가하거나 재인증할 때 OpenCodex는 일반적으로 저장 전에 작은 모델 요청으로 확인합니다. `gpt-5.4-mini`의 `response.completed`를 기다리며 HTTP 400이면 `gpt-5.5`로 재시도합니다. 오류에는 고정된 실패 분류만 표시하고 원본 응답 본문은 노출하지 않습니다. + +새 OAuth 토큰으로 인증된 사용량 조회에서 5시간·주간·월간 한도 소진이 확인되면 모델 요청 없이 계정을 저장하고 **검증 대기**로 표시합니다. 재시작이나 토큰 갱신 후에도 요청에 사용되지 않습니다. 한도 회복 후 **사용량 새로고침**을 실행하면, 여유가 있는 완전한 최신 사용량을 확인한 뒤 작은 모델 요청을 보내고 완료 응답을 받아야 계정을 사용할 수 있습니다. 조회나 검증 실패 시 대기 상태를 유지합니다. 일반적인 화면 상태 조회는 이 모델 요청을 보내지 않습니다. 최초 등록 때 사용량이 불명확하면 기존 워밍업 검증이 필요합니다. + +별도의 백그라운드 재검증은 기본적으로 꺼져 있습니다. Token Guardian, `openai`의 `proactive` 갱신 정책, `tokenGuardian.codexWarmupEnabled`가 필요하며 등록 검증 대기 계정은 제외합니다. ## 네이티브 Codex 복원 diff --git a/docs-site/src/content/docs/ru/guides/codex-integration.md b/docs-site/src/content/docs/ru/guides/codex-integration.md index 9707a3ea44..b3311ea02a 100644 --- a/docs-site/src/content/docs/ru/guides/codex-integration.md +++ b/docs-site/src/content/docs/ru/guides/codex-integration.md @@ -360,14 +360,11 @@ v1/base/v2 при делегировании и fallback — в ## Прогрев аккаунтов Codex -Когда аккаунт ChatGPT добавляется в пул аккаунтов Codex, opencodex проверяет его до сохранения -небольшим streaming-запросом в backend Codex Responses. Запрос использует настоящий массив -Responses item'ов (`input: [{ type: "message", ... }]`), ждёт `response.completed` и по умолчанию -использует `gpt-5.4-mini`. Если эта модель отвечает HTTP 400, выполняется повтор с `gpt-5.5`; -структурированные детали upstream-ошибки показываются без раскрытия сырых тел ответа. Фоновая -перепроверка отделена от этого процесса и по умолчанию выключена; она запускается только когда -включён Token Guardian, у `chatgpt` выставлена политика refresh `proactive`, а -`tokenGuardian.codexWarmupEnabled` равен true. +При добавлении или повторной аутентификации аккаунт обычно проверяется до сохранения небольшим запросом, ожидающим `response.completed`. По умолчанию используется `gpt-5.4-mini`, при HTTP 400 — повтор с `gpt-5.5`. Публичные ошибки содержат фиксированные категории без исходного тела ответа. + +Если запрос квоты с новым OAuth-токеном подтверждает исчерпание пятичасовой, недельной или месячной квоты, аккаунт сохраняется без вызова модели со статусом **Ожидает проверки**. Перезапуск и обновление токена не включают маршрутизацию. После восстановления квоты обновите её: полные свежие данные с доступной ёмкостью разрешают небольшой проверочный запрос. Только успешное завершение включает аккаунт. Ошибки сохраняют ограничение. Пассивный опрос не отправляет такой запрос. Неизвестная квота при регистрации требует обычной проверки. + +Фоновая проверка — отдельная функция, выключенная по умолчанию. Она требует Token Guardian, политики `proactive` провайдера `openai` и `tokenGuardian.codexWarmupEnabled` и пропускает аккаунты, ожидающие проверки регистрации. ## Восстановление нативного Codex diff --git a/docs-site/src/content/docs/tr/guides/codex-integration.md b/docs-site/src/content/docs/tr/guides/codex-integration.md index 02fae0f468..abf78a1de2 100644 --- a/docs-site/src/content/docs/tr/guides/codex-integration.md +++ b/docs-site/src/content/docs/tr/guides/codex-integration.md @@ -417,15 +417,11 @@ Arayüzü](/tr/guides/sub-agent-surface/) sayfasına bakın. ## Codex hesap ısınması -Codex hesap havuzuna bir ChatGPT hesabı eklendiğinde opencodex, Codex Responses -arka ucuna küçük bir akış isteği ile kalıcılıktan önce hesabı doğrular. İstek -gerçek bir Responses öğe dizisi kullanır (`input: [{ type: "message", ... }]`), -`response.completed` bekler ve varsayılan olarak `gpt-5.4-mini` kullanır. Bu -model HTTP 400 döndürürse `gpt-5.5` ile yeniden dener; ham yanıt gövdelerini -açığa çıkarmadan yapılandırılmış yukarı akış hata ayrıntıları ortaya çıkarılır. -Arka plan yeniden doğrulaması ayrıdır ve varsayılan olarak kapalıdır; yalnızca -Token Guardian etkinleştirildiğinde, `chatgpt` yenileme politikası `proactive` -olduğunda ve `tokenGuardian.codexWarmupEnabled` true olduğunda çalışır. +Hesap ekleme veya yeniden kimlik doğrulama, normalde kaydetmeden önce `response.completed` bekleyen küçük bir model isteğiyle doğrulanır. Varsayılan model `gpt-5.4-mini` olup HTTP 400 durumunda `gpt-5.5` denenir. Genel hatalar ham yanıt gövdesi yerine sabit hata kategorilerini içerir. + +Yeni OAuth belirteciyle yapılan kota sorgusu 5 saatlik, haftalık veya aylık kotanın tükendiğini doğrularsa hesap model çağrısı olmadan kaydedilir ve **Doğrulama bekleniyor** gösterilir. Yeniden başlatma veya belirteç yenileme yönlendirmeyi açmaz. Kota geri geldiğinde kotaları yenileyin: kullanılabilir kapasite gösteren eksiksiz güncel veri küçük bir doğrulama isteğine izin verir. Yalnızca tamamlanan yanıt hesabı etkinleştirir. Hatalarda kısıtlama korunur. Pasif sorgulama bu isteği göndermez. İlk kayıtta bilinmeyen kota normal doğrulamayı gerektirir. + +Arka plan doğrulaması ayrı ve varsayılan olarak kapalıdır. Token Guardian, `openai` için `proactive` yenileme ilkesi ve `tokenGuardian.codexWarmupEnabled` gerektirir; kayıt doğrulaması bekleyen hesapları atlar. ## Yerel Codex'i geri yükleme diff --git a/docs-site/src/content/docs/zh-cn/guides/codex-integration.md b/docs-site/src/content/docs/zh-cn/guides/codex-integration.md index 552c0c3f53..2b0868e513 100644 --- a/docs-site/src/content/docs/zh-cn/guides/codex-integration.md +++ b/docs-site/src/content/docs/zh-cn/guides/codex-integration.md @@ -306,12 +306,11 @@ fallback 行为,参见 [Sub-agent Surface](/guides/sub-agent-surface/)。 ## Codex 账号预热 -当把一个 ChatGPT 账号加入 Codex 账号池时,opencodex 会在持久化前向 Codex Responses backend -发送一个小型 streaming 请求来验证它。该请求使用真正的 Responses item 数组 -(`input: [{ type: "message", ... }]`),等待 `response.completed`,并默认使用 `gpt-5.4-mini`。 -如果该模型返回 HTTP 400,则会改用 `gpt-5.5` 重试;结构化的上游错误详情会被展示给用户,但不会暴露 -原始响应正文。后台重新验证是独立功能,默认关闭;只有在启用 Token Guardian、将 `chatgpt` 刷新策略设为 -`proactive`,并且 `tokenGuardian.codexWarmupEnabled` 为 true 时才会运行。 +添加或重新认证账号时,通常会在保存前发送一个小型模型请求并等待 `response.completed`。默认使用 `gpt-5.4-mini`,HTTP 400 时改用 `gpt-5.5` 重试。公开错误仅包含固定分类,不包含原始响应正文。 + +如果新 OAuth 凭据的已认证用量查询确认5小时、每周或每月额度耗尽,则不调用模型而直接保存账号,显示**等待验证**。重启或刷新令牌也不会使其可用。额度恢复后刷新额度:只有完整的最新用量显示有余额,才会发送一个小型验证请求;请求完成后账号才可用于路由。查询或验证失败将保留等待状态。普通状态轮询不会发送该请求。初次注册时用量未知仍需常规预热验证。 + +后台重新验证是独立功能,默认关闭。它要求 Token Guardian、`openai` 的 `proactive` 刷新策略及 `tokenGuardian.codexWarmupEnabled`,并跳过等待注册验证的账号。 ## 恢复原生 Codex diff --git a/docs-site/src/content/docs/zh-tw/guides/codex-integration.md b/docs-site/src/content/docs/zh-tw/guides/codex-integration.md index f371457be9..f3295565b4 100644 --- a/docs-site/src/content/docs/zh-tw/guides/codex-integration.md +++ b/docs-site/src/content/docs/zh-tw/guides/codex-integration.md @@ -313,12 +313,11 @@ ocx service install # 常駐:登入時自動啟動,崩潰後自動重新 ## Codex 帳號預熱 -向 Codex 帳號池新增 ChatGPT 帳號時,opencodex 會先用一個小型 streaming 請求向 Codex Responses -backend 驗證,成功後才持久化。請求使用真正的 Responses item 陣列 -(`input: [{ type: "message", ... }]`),等待 `response.completed`,預設模型為 `gpt-5.4-mini`。若該 -模型回傳 HTTP 400,則改用 `gpt-5.5` 重試;結構化上游錯誤細節會呈現給使用者,但不暴露原始 response -body。背景重新驗證是獨立功能,預設關閉;只有啟用 Token Guardian、將 `chatgpt` refresh policy 設為 -`proactive`,並把 `tokenGuardian.codexWarmupEnabled` 設為 true 時才會執行。 +新增或重新驗證帳號時,通常會在儲存前傳送小型模型請求並等待 `response.completed`。預設使用 `gpt-5.4-mini`,HTTP 400 時改用 `gpt-5.5` 重試。公開錯誤僅包含固定分類,不包含原始回應本文。 + +若新 OAuth 憑證的已驗證用量查詢確認5小時、每週或每月額度耗盡,則不呼叫模型而直接儲存帳號,顯示**等待驗證**。重新啟動或更新權杖也不會使其可用。額度恢復後重新整理額度:只有完整的最新用量顯示有餘額,才會傳送小型驗證請求;請求完成後帳號才可用於路由。查詢或驗證失敗將保留等待狀態。一般狀態輪詢不會傳送該請求。首次註冊時用量未知仍需一般預熱驗證。 + +背景重新驗證是獨立功能,預設關閉。它需要 Token Guardian、`openai` 的 `proactive` 更新政策及 `tokenGuardian.codexWarmupEnabled`,並略過等待註冊驗證的帳號。 ## 恢復原生 Codex diff --git a/gui/src/components/codex-account-pool-cards.tsx b/gui/src/components/codex-account-pool-cards.tsx index 7c112e7a72..619ec2ecf2 100644 --- a/gui/src/components/codex-account-pool-cards.tsx +++ b/gui/src/components/codex-account-pool-cards.tsx @@ -80,6 +80,7 @@ export function CodexAccountPoolCards({ const healthStatus = a.health?.status; const showReauth = Boolean(a.needsReauth) || oauthHealthShowsReauth(healthStatus); const inCooldown = oauthHealthIsCooldown(healthStatus); + const validationPending = a.health?.reason === "validation_pending"; const healthLabel = formatOAuthHealthLabel(t, a.health); const healthSummary = formatOAuthHealthSummary(t, "codex", a.id, a.health); return ( @@ -101,13 +102,13 @@ export function CodexAccountPoolCards({ {healthLabel} )} {showReauth && !healthLabel && {t("codexAuth.needsReauth")}} - {isNext(a) && !showReauth && !inCooldown && ( + {isNext(a) && !showReauth && !inCooldown && !validationPending && ( {t(accountModeState === "direct" ? "codexAuth.poolPrepared" : "codexAuth.nextSession")} )}
- {!a.paused && (!isNext(a) || pinnedId !== a.id) && !showReauth && !inCooldown && ( + {!a.paused && (!isNext(a) || pinnedId !== a.id) && !showReauth && !inCooldown && !validationPending && ( diff --git a/gui/src/i18n/de.ts b/gui/src/i18n/de.ts index 5faab4b356..05027dd497 100644 --- a/gui/src/i18n/de.ts +++ b/gui/src/i18n/de.ts @@ -2069,6 +2069,8 @@ export const de: Record = { "pws.healthLabel.reauthRequired": "Erneute Anmeldung erforderlich", "pws.healthLabel.refreshFailed": "Aktualisierung fehlgeschlagen", "pws.healthLabel.metadataMismatch": "Metadaten stimmen nicht überein", + "pws.healthLabel.validationPending": "Validierung ausstehend", + "pws.healthSummary.validationPending": "{provider} {account}: mit erschöpftem Kontingent registriert. Aktualisieren Sie nach der Erholung die Kontingente, um eine kleine Validierungsanfrage zu senden. Bis zum Erfolg bleibt das Routing deaktiviert.", "pws.healthLabel.credentialConflict": "Anmeldedaten-Konflikt", "pws.healthSummary.rateLimited": "{provider} {account}: ratelimited bis {until}. Routing für dieses Konto ist bis dahin pausiert.", "pws.healthSummary.quotaLimited": "{provider} {account}: Kontingent begrenzt bis {until}. Routing für dieses Konto ist bis dahin pausiert.", diff --git a/gui/src/i18n/en.ts b/gui/src/i18n/en.ts index c71208942f..94880b6d52 100644 --- a/gui/src/i18n/en.ts +++ b/gui/src/i18n/en.ts @@ -1312,6 +1312,8 @@ export const en = { "pws.healthLabel.reauthRequired": "Reauthentication required", "pws.healthLabel.refreshFailed": "Refresh failed", "pws.healthLabel.metadataMismatch": "Metadata mismatch", + "pws.healthLabel.validationPending": "Validation pending", + "pws.healthSummary.validationPending": "{provider} {account}: registered while quota-limited. After quota recovers, refresh quotas to run a small validation request. Routing stays disabled until it succeeds.", "pws.healthLabel.credentialConflict": "Credential conflict", "pws.healthSummary.rateLimited": "{provider} {account}: rate limited until {until}. Routing for this account is paused until then.", "pws.healthSummary.quotaLimited": "{provider} {account}: quota limited until {until}. Routing for this account is paused until then.", diff --git a/gui/src/i18n/fr.ts b/gui/src/i18n/fr.ts index e1b3519ef1..89d1bf5ab5 100644 --- a/gui/src/i18n/fr.ts +++ b/gui/src/i18n/fr.ts @@ -1302,6 +1302,8 @@ export const fr: Record = { "pws.healthLabel.reauthRequired": "Réauthentification requise", "pws.healthLabel.refreshFailed": "Actualisation échouée", "pws.healthLabel.metadataMismatch": "Métadonnées incompatibles", + "pws.healthLabel.validationPending": "Validation en attente", + "pws.healthSummary.validationPending": "{provider} {account} : enregistré avec un quota épuisé. Après sa récupération, actualisez les quotas pour envoyer une petite requête de validation. Le routage reste désactivé jusqu’à sa réussite.", "pws.healthLabel.credentialConflict": "Conflit d’identifiants", "pws.healthSummary.rateLimited": "{provider} {account} : débit limité jusqu’à {until}. Le routage de ce compte est suspendu jusque-là.", "pws.healthSummary.quotaLimited": "{provider} {account} : quota limité jusqu’à {until}. Le routage de ce compte est suspendu jusque-là.", diff --git a/gui/src/i18n/ja.ts b/gui/src/i18n/ja.ts index cf94831583..ade5b33931 100644 --- a/gui/src/i18n/ja.ts +++ b/gui/src/i18n/ja.ts @@ -1226,6 +1226,8 @@ export const ja: Record = { "pws.healthLabel.reauthRequired": "再認証が必要です", "pws.healthLabel.refreshFailed": "更新に失敗しました", "pws.healthLabel.metadataMismatch": "メタデータの不一致", + "pws.healthLabel.validationPending": "検証待ち", + "pws.healthSummary.validationPending": "{provider} {account}: 利用上限に達した状態で登録されました。上限の回復後、使用量を更新すると小さな検証リクエストを送信します。成功するまでリクエストには使用されません。", "pws.healthLabel.credentialConflict": "資格情報の競合", "pws.healthSummary.rateLimited": "{provider} {account}: {until} までレート制限中です。それまでこのアカウントのルーティングは停止します。", "pws.healthSummary.quotaLimited": "{provider} {account}: {until} までクォータ制限中です。それまでこのアカウントのルーティングは停止します。", diff --git a/gui/src/i18n/ko.ts b/gui/src/i18n/ko.ts index c1959482b7..867d7e6b0d 100644 --- a/gui/src/i18n/ko.ts +++ b/gui/src/i18n/ko.ts @@ -2096,6 +2096,8 @@ export const ko: Record = { "pws.healthLabel.reauthRequired": "재인증 필요", "pws.healthLabel.refreshFailed": "새로고침 실패", "pws.healthLabel.metadataMismatch": "메타데이터 불일치", + "pws.healthLabel.validationPending": "검증 대기", + "pws.healthSummary.validationPending": "{provider} {account}: 사용량 한도가 소진된 상태로 등록되었습니다. 한도 회복 후 사용량을 새로고침하면 소량의 검증 요청을 보냅니다. 성공할 때까지 요청에 사용되지 않습니다.", "pws.healthLabel.credentialConflict": "자격 증명 충돌", "pws.healthSummary.rateLimited": "{provider} {account}: {until}까지 요청 한도 초과. 그전까지 이 계정 라우팅이 일시 중지됩니다.", "pws.healthSummary.quotaLimited": "{provider} {account}: {until}까지 할당량 제한. 그전까지 이 계정 라우팅이 일시 중지됩니다.", diff --git a/gui/src/i18n/ru.ts b/gui/src/i18n/ru.ts index 0109f5ebdc..27613c710a 100644 --- a/gui/src/i18n/ru.ts +++ b/gui/src/i18n/ru.ts @@ -1296,6 +1296,8 @@ export const ru: Record = { "pws.healthLabel.reauthRequired": "Требуется повторная аутентификация", "pws.healthLabel.refreshFailed": "Ошибка обновления", "pws.healthLabel.metadataMismatch": "Несоответствие метаданных", + "pws.healthLabel.validationPending": "Ожидает проверки", + "pws.healthSummary.validationPending": "{provider} {account}: зарегистрирован с исчерпанной квотой. После её восстановления обновите квоты, чтобы отправить небольшой проверочный запрос. Маршрутизация отключена до успешной проверки.", "pws.healthLabel.credentialConflict": "Конфликт учётных данных", "pws.healthSummary.rateLimited": "{provider} {account}: ограничение частоты до {until}. Маршрутизация этой учётной записи приостановлена до этого времени.", "pws.healthSummary.quotaLimited": "{provider} {account}: квота ограничена до {until}. Маршрутизация этой учётной записи приостановлена до этого времени.", diff --git a/gui/src/i18n/tr.ts b/gui/src/i18n/tr.ts index fa8b8e9c25..afb392b0c8 100644 --- a/gui/src/i18n/tr.ts +++ b/gui/src/i18n/tr.ts @@ -1303,6 +1303,8 @@ export const tr: Record = { "pws.healthLabel.reauthRequired": "Yeniden doğrulama gerekli", "pws.healthLabel.refreshFailed": "Yenileme başarısız oldu", "pws.healthLabel.metadataMismatch": "Meta veri uyuşmazlığı", + "pws.healthLabel.validationPending": "Doğrulama bekleniyor", + "pws.healthSummary.validationPending": "{provider} {account}: kota tükenmişken kaydedildi. Kota yenilendikten sonra küçük bir doğrulama isteği göndermek için kotaları yenileyin. Başarılı olana kadar yönlendirme kapalı kalır.", "pws.healthLabel.credentialConflict": "Kimlik bilgisi çakışması", "pws.healthSummary.rateLimited": "{provider} {account}: {until} tarihine kadar oran kısıtlandı.", "pws.healthSummary.quotaLimited": "{provider} {account}: {until} tarihine kadar kota kısıtlandı.", diff --git a/gui/src/i18n/zh-TW.ts b/gui/src/i18n/zh-TW.ts index 3bc246543a..c4d2781de0 100644 --- a/gui/src/i18n/zh-TW.ts +++ b/gui/src/i18n/zh-TW.ts @@ -1089,6 +1089,8 @@ export const zhTW: Record = { "pws.healthLabel.reauthRequired": "需要重新認證", "pws.healthLabel.refreshFailed": "重新整理失敗", "pws.healthLabel.metadataMismatch": "後設資料不符合", + "pws.healthLabel.validationPending": "等待驗證", + "pws.healthSummary.validationPending": "{provider} {account}:已在額度耗盡時註冊。額度恢復後,重新整理額度將傳送一個小型驗證請求。驗證成功前不會用於路由。", "pws.healthLabel.credentialConflict": "憑證衝突", "pws.healthSummary.rateLimited": "{provider} {account}:限速至 {until}。在此之前將暫停該帳號的路由。", "pws.healthSummary.quotaLimited": "{provider} {account}:配額限制至 {until}。在此之前將暫停該帳號的路由。", diff --git a/gui/src/i18n/zh.ts b/gui/src/i18n/zh.ts index b10c48688d..41d3bd85bd 100644 --- a/gui/src/i18n/zh.ts +++ b/gui/src/i18n/zh.ts @@ -2089,6 +2089,8 @@ export const zh: Record = { "pws.healthLabel.reauthRequired": "需要重新认证", "pws.healthLabel.refreshFailed": "刷新失败", "pws.healthLabel.metadataMismatch": "元数据不匹配", + "pws.healthLabel.validationPending": "等待验证", + "pws.healthSummary.validationPending": "{provider} {account}:已在额度耗尽时注册。额度恢复后,刷新额度将发送一个小型验证请求。验证成功前不会用于路由。", "pws.healthLabel.credentialConflict": "凭证冲突", "pws.healthSummary.rateLimited": "{provider} {account}:限速至 {until}。在此之前将暂停该账户的路由。", "pws.healthSummary.quotaLimited": "{provider} {account}:配额限制至 {until}。在此之前将暂停该账户的路由。", diff --git a/gui/src/oauth-health-display.ts b/gui/src/oauth-health-display.ts index e635ef4973..56460f186d 100644 --- a/gui/src/oauth-health-display.ts +++ b/gui/src/oauth-health-display.ts @@ -17,6 +17,7 @@ export type OAuthHealthReason = | "refresh_failed" | "refresh_conflict" | "metadata_mismatch" + | "validation_pending" | "stale_credentials"; export type OAuthHealthView = { @@ -79,6 +80,8 @@ export function oauthHealthLabelKey(health: OAuthHealthView | undefined): TKey | : "pws.healthLabel.reauthRequired"; } switch (health.reason) { + case "validation_pending": + return "pws.healthLabel.validationPending"; case "refresh_conflict": return "pws.healthLabel.credentialConflict"; case "metadata_mismatch": @@ -113,6 +116,9 @@ export function formatOAuthHealthSummary( if (health.status === "reauth_required") { return t("pws.healthSummary.reauthRequired", { provider, account }); } + if (health.reason === "validation_pending") { + return t("pws.healthSummary.validationPending", { provider, account }); + } if (health.reason === "refresh_conflict") { return t("pws.healthSummary.credentialConflict", { provider, account }); } @@ -170,4 +176,3 @@ export function doctorCopyButtonLabel( if (!outcome) return t("pws.copyDoctor"); return outcome === "copied" ? t("pws.doctorCopied") : t("pws.doctorCopyUnavailable"); } - diff --git a/gui/tests/oauth-health-display.test.ts b/gui/tests/oauth-health-display.test.ts index 9d6c3162dc..1afc9fbb59 100644 --- a/gui/tests/oauth-health-display.test.ts +++ b/gui/tests/oauth-health-display.test.ts @@ -23,6 +23,12 @@ const t: TFn = ((key: string, vars?: Record) => { }) as TFn; describe("oauth health badge helpers", () => { + test("deferred Codex validation explains quota recovery without requesting reauthentication", () => { + const health = { status: "warning" as const, reason: "validation_pending" }; + expect(formatOAuthHealthLabel(t, health)).toBe("pws.healthLabel.validationPending"); + expect(formatOAuthHealthSummary(t, "codex", "acct_pending", health)).toBe("pws.healthSummary.validationPending"); + expect(accountNeedsReauth({ needsReauth: false, health })).toBe(false); + }); test("maps statuses to badge tones and classes", () => { expect(oauthHealthBadgeTone("healthy")).toBe("ok"); expect(oauthHealthBadgeTone("cooldown")).toBe("muted"); diff --git a/src/codex/account-store.ts b/src/codex/account-store.ts index 952ac048b8..7fa5cf2d1c 100644 --- a/src/codex/account-store.ts +++ b/src/codex/account-store.ts @@ -58,7 +58,8 @@ function isCredentialRecord(value: unknown): value is CodexAccountCredentialReco && (value.replacedAt === undefined || typeof value.replacedAt === "number") && (value.lastCodexValidatedAt === undefined || typeof value.lastCodexValidatedAt === "number") && (value.lastCodexValidationStatus === undefined || value.lastCodexValidationStatus === "ok" || value.lastCodexValidationStatus === "failed") - && (value.lastCodexValidationError === undefined || typeof value.lastCodexValidationError === "string"); + && (value.lastCodexValidationError === undefined || typeof value.lastCodexValidationError === "string") + && (value.codexValidationPending === undefined || typeof value.codexValidationPending === "boolean"); } export function refreshGrantFingerprintForToken(refreshToken: string): string { @@ -120,9 +121,10 @@ function persistCredentialMutation(store: CodexAccountStore): void { function preservedValidationMetadata(record: CodexAccountCredentialRecord | undefined): Pick< CodexAccountCredentialRecord, - "lastCodexValidatedAt" | "lastCodexValidationStatus" | "lastCodexValidationError" + "lastCodexValidatedAt" | "lastCodexValidationStatus" | "lastCodexValidationError" | "codexValidationPending" > { return { + ...(record?.codexValidationPending === true ? { codexValidationPending: true } : {}), ...(record?.lastCodexValidatedAt !== undefined ? { lastCodexValidatedAt: record.lastCodexValidatedAt } : {}), ...(record?.lastCodexValidationStatus !== undefined ? { lastCodexValidationStatus: record.lastCodexValidationStatus } : {}), ...(record?.lastCodexValidationError !== undefined ? { lastCodexValidationError: record.lastCodexValidationError } : {}), @@ -135,7 +137,11 @@ export function getCodexAccountCredential(id: string): CodexAccountCredentials | return record.credential ?? null; } -export function saveCodexAccountCredential(id: string, cred: CodexAccountCredentials): void { +export function saveCodexAccountCredential( + id: string, + cred: CodexAccountCredentials, + options: { validationPending?: boolean } = {}, +): void { withCredentialMutationLockSync(() => { const store = loadCodexAccountRecordStore(); const current = store[id]; @@ -148,21 +154,29 @@ export function saveCodexAccountCredential(id: string, cred: CodexAccountCredent refreshGrantFingerprint, replacedAt: current ? Date.now() : undefined, ...preservedValidationMetadata(current), + ...(options.validationPending ? { + codexValidationPending: true, + lastCodexValidatedAt: undefined, + lastCodexValidationStatus: undefined, + lastCodexValidationError: undefined, + } : {}), }; persistCredentialMutation(store); }); } -export function markCodexAccountValidated(id: string, atMs: number = Date.now()): void { +export function markCodexAccountValidated(id: string, atMs: number = Date.now(), generation?: number): void { withCredentialMutationLockSync(() => { const store = loadCodexAccountRecordStore(); const current = store[id]; if (!current || current.deletedAt != null || !current.credential) return; + if (generation !== undefined && current.generation !== generation) return; store[id] = { ...current, lastCodexValidatedAt: atMs, lastCodexValidationStatus: "ok", lastCodexValidationError: undefined, + codexValidationPending: undefined, }; persist(store); }); diff --git a/src/codex/account-usability.ts b/src/codex/account-usability.ts index 3ce27475ee..3001eb2b23 100644 --- a/src/codex/account-usability.ts +++ b/src/codex/account-usability.ts @@ -1,4 +1,4 @@ -import { getCodexAccountCredential } from "./account-store"; +import { readCodexAccountRecord } from "./account-store"; import { isAccountNeedsReauth } from "./account-runtime-state"; import { MAIN_CODEX_ACCOUNT_ID, @@ -48,5 +48,6 @@ export function isCodexAccountUsable( .some(account => isSelectableCodexPoolAccount(account) && account.id === accountId); if (!exists) return false; if (isAccountNeedsReauth(accountId)) return false; - return !!getCodexAccountCredential(accountId); + const record = readCodexAccountRecord(accountId); + return !!record?.credential && record.deletedAt == null && !record.codexValidationPending; } diff --git a/src/codex/auth-api.ts b/src/codex/auth-api.ts index 51e3fed303..34e94395de 100644 --- a/src/codex/auth-api.ts +++ b/src/codex/auth-api.ts @@ -621,7 +621,7 @@ function saveRuntimeConfig(sourceConfig: OcxConfig, nextConfig: OcxConfig): void interface StagedNewCodexAccountState { credential: CodexAccountCredentials; - validatedAt: number; + validatedAt?: number; } type PersistNewCodexAccountOutcome = @@ -674,8 +674,10 @@ function persistNewCodexAccount( } try { - saveCodexAccountCredential(addedAccount.id, staged.credential); - markCodexAccountValidated(addedAccount.id, staged.validatedAt); + saveCodexAccountCredential(addedAccount.id, staged.credential, { + validationPending: staged.validatedAt === undefined, + }); + if (staged.validatedAt !== undefined) markCodexAccountValidated(addedAccount.id, staged.validatedAt); clearAccountNeedsReauth(addedAccount.id); } catch { // Config is already durable. Return the failure outcome through the coordinator so its @@ -1047,6 +1049,7 @@ interface PoolQuotaRefreshFlight { state: { startCredentialGeneration?: number; resolvedCredentialGeneration?: number; + validatePending?: boolean; }; promise: Promise; } @@ -1417,6 +1420,7 @@ async function fetchPoolAccountQuota( forceRefresh = false, configuredPlan?: string, getValidToken: typeof getValidCodexToken = getValidCodexToken, + validatePending = false, ): Promise { const existing = getAccountQuota(accountId); if (!forceRefresh && existing && Date.now() - existing.updatedAt < POOL_CACHE_TTL) { @@ -1436,11 +1440,16 @@ async function fetchPoolAccountQuota( ?? flight.state.startCredentialGeneration; return generation !== undefined && isCodexAccountGenerationLive(accountId, generation); }); - if (current) return current.promise; + if (current) { + // A manual refresh joining a passive read must not lose its validation intent. + current.state.validatePending ||= validatePending; + return current.promise; + } if (poolQuotaFlightCount() >= MAX_POOL_QUOTA_FLIGHTS) throw new PoolQuotaProbeBusyError(); const state: PoolQuotaRefreshFlight["state"] = { startCredentialGeneration: record?.generation, + validatePending, }; const refresh = fetchFreshPoolAccountQuota( accountId, @@ -1448,7 +1457,28 @@ async function fetchPoolAccountQuota( configuredPlan, generation => { state.resolvedCredentialGeneration = generation; }, getValidToken, - ); + ).then(async result => { + // Only an explicit account-list refresh finishes deferred registration. Passive quota + // polls and startup priming remain read-only with respect to inference spending. + const generation = result.freshCredentialGeneration; + const record = state.validatePending ? readCodexAccountRecord(accountId) : null; + if (record?.codexValidationPending && record.credential && record.deletedAt == null + && generation !== undefined && record.generation === generation + && !isCodexAccountPaused(loadConfig(), accountId) + && isCompleteCodexQuotaRecoverySnapshot(result.freshQuota ?? null, result.freshPlan ?? configuredPlan)) { + try { + await warmCodexAccount({ + accessToken: record.credential.accessToken, + chatgptAccountId: record.credential.chatgptAccountId, + }); + markCodexAccountValidated(accountId, Date.now(), generation); + } catch { + // Keep the durable restriction on any failed/partial inference response, even + // when WHAM just reported headroom. No raw upstream text enters diagnostics. + } + } + return result; + }); const flight: PoolQuotaRefreshFlight = { state, promise: refresh }; const activeFlights = flights ?? new Set(); activeFlights.add(flight); @@ -1739,7 +1769,7 @@ export async function listCodexAuthAccountsSnapshot( quotaResult = { quota: null, needsReauth: true }; } else { try { - quotaResult = await fetchPoolAccountQuota(account.id, forceRefresh, account.plan); + quotaResult = await fetchPoolAccountQuota(account.id, forceRefresh, account.plan, getValidCodexToken, forceRefresh); } catch (error) { if (!(error instanceof PoolQuotaProbeBusyError)) throw error; quotaResult = { @@ -2574,7 +2604,12 @@ export async function handleCodexAuthAPI( break; } - const warmup = await verifyCodexAccountWarmup(accountId, cred.access, oauthAccountId); + // A successful authenticated WHAM read can prove quota is exhausted without + // spending an inference request. Store the account, but defer inference validation + // and keep it unavailable to routing. Unknown/failed usage reads retain the gate. + const warmup = isCodexQuotaExhausted(quota, plan) + ? { ok: true as const, validatedAt: undefined } + : await verifyCodexAccountWarmup(accountId, cred.access, oauthAccountId); if (!warmup.ok) { const body = await warmup.response.json().catch(() => ({})) as { error?: string; reason?: string }; setCodexLoginState(flowId, { @@ -2614,11 +2649,13 @@ export async function handleCodexAuthAPI( }; if (existingIdx >= 0) { - saveCodexAccountCredential(accountId, credential); + saveCodexAccountCredential(accountId, credential, { + validationPending: warmup.validatedAt === undefined, + }); // A successful reauthentication replaces the credential generation. Do not let a // failed optional WHAM probe make the replacement inherit quota from the old record. if (reauth) clearAccountQuota(accountId); - markCodexAccountValidated(accountId, warmup.validatedAt); + if (warmup.validatedAt !== undefined) markCodexAccountValidated(accountId, warmup.validatedAt); clearAccountNeedsReauth(accountId); if (quota) setAccountQuotaFromParsed(accountId, quota); // Keep the pool id stable; refresh display metadata after a successful login/reauth. diff --git a/src/oauth/health.ts b/src/oauth/health.ts index 011ebd8f41..af68353c50 100644 --- a/src/oauth/health.ts +++ b/src/oauth/health.ts @@ -1,7 +1,7 @@ import { getCodexAccountHealthSnapshot, type CodexCooldownSource } from "../codex/routing"; import { getAnthropicAccountHealthSnapshot } from "./anthropic-routing"; import { isAccountNeedsReauth } from "../codex/account-runtime-state"; -import { getCodexAccountCredential, listCodexAccountIds } from "../codex/account-store"; +import { getCodexAccountCredential, listCodexAccountIds, readCodexAccountRecord } from "../codex/account-store"; import { MAIN_CODEX_ACCOUNT_ID } from "../codex/main-account"; import { readRuntimePort } from "../config/process-state"; import { LOCAL_MANAGEMENT_READ_PATHS } from "../lib/local-management-capability"; @@ -15,7 +15,7 @@ export type OAuthAccountHealth = | { status: "healthy" } | { status: "cooldown"; until: string; reason: "rate_limit" | "quota" } | { status: "reauth_required"; reason: "unauthorized" | "forbidden" | "refresh_failed" } - | { status: "warning"; reason: "refresh_conflict" | "metadata_mismatch" | "stale_credentials" }; + | { status: "warning"; reason: "refresh_conflict" | "metadata_mismatch" | "stale_credentials" | "validation_pending" }; export type OAuthHealthLabel = | "Healthy" @@ -24,7 +24,8 @@ export type OAuthHealthLabel = | "Reauthentication required" | "Refresh failed" | "Metadata mismatch" - | "Credential conflict"; + | "Credential conflict" + | "Validation pending"; /** Shared masked-id fallback when `maskAccountId` returns nullish. */ export const MASKED_ACCOUNT_FALLBACK = "account-…????"; @@ -88,6 +89,9 @@ export function projectOAuthAccountHealth(input: { export const CODEX_REAUTH_ACTION = "reauthenticate via the dashboard Codex account pool"; function actionFor(provider: string, health: OAuthAccountHealth): string | undefined { + if (health.status === "warning" && health.reason === "validation_pending") { + return "wait for quota recovery, then refresh Codex account quotas to finish validation"; + } if (health.status === "reauth_required") { if (provider === "codex") return CODEX_REAUTH_ACTION; return `run \`ocx login ${provider}\``; @@ -112,6 +116,8 @@ export function oauthHealthLabel(health: OAuthAccountHealth): OAuthHealthLabel { return health.reason === "refresh_failed" ? "Refresh failed" : "Reauthentication required"; case "warning": switch (health.reason) { + case "validation_pending": + return "Validation pending"; case "refresh_conflict": return "Credential conflict"; case "metadata_mismatch": @@ -198,6 +204,10 @@ export function projectCodexAccountHealth(input: { needsReauth: boolean; now?: number; }): OAuthAccountHealth { + if (!input.needsReauth && input.accountId !== MAIN_CODEX_ACCOUNT_ID + && readCodexAccountRecord(input.accountId)?.codexValidationPending) { + return { status: "warning", reason: "validation_pending" }; + } const now = input.now ?? Date.now(); const snap = getCodexAccountHealthSnapshot(input.accountId, now); return projectOAuthAccountHealth({ diff --git a/src/oauth/token-guardian.ts b/src/oauth/token-guardian.ts index a84d68a7c2..81e0bfc393 100644 --- a/src/oauth/token-guardian.ts +++ b/src/oauth/token-guardian.ts @@ -211,6 +211,7 @@ export async function guardianSweep(nowMs: number = Date.now()): Promise opts.codexWarmupMaxAgeSeconds * 1000); if (!needsRefresh && !needsWarmup) continue; const key = `codex:${id}`; diff --git a/src/types/accounts.ts b/src/types/accounts.ts index 5ff48945c7..c5a9175c92 100644 --- a/src/types/accounts.ts +++ b/src/types/accounts.ts @@ -34,4 +34,6 @@ export interface CodexAccountCredentialRecord { lastCodexValidatedAt?: number; lastCodexValidationStatus?: "ok" | "failed"; lastCodexValidationError?: string; + /** OAuth succeeded while quota was exhausted; never route until deferred validation succeeds. */ + codexValidationPending?: boolean; } diff --git a/tests/codex-integration/codex-account-store.test.ts b/tests/codex-integration/codex-account-store.test.ts index 8b9ad8d9ab..bd02776a84 100644 --- a/tests/codex-integration/codex-account-store.test.ts +++ b/tests/codex-integration/codex-account-store.test.ts @@ -60,6 +60,21 @@ describe("codex-account-store CRUD", () => { beforeEach(() => { installScratchHome(); }); afterEach(async () => { await removeScratchHome(); }); + test("pending validation survives credential refresh and cannot be cleared by a stale probe", async () => { + const store = await import("../../src/codex/account-store"); + const cred = { accessToken: "access-pending", refreshToken: "refresh-pending", expiresAt: Date.now() + 3600_000, chatgptAccountId: "acct-pending" }; + store.saveCodexAccountCredential("pending", cred, { validationPending: true }); + const generation = store.readCodexAccountRecord("pending")!.generation; + expect(store.saveCodexAccountCredentialIfGeneration("pending", generation, { ...cred, accessToken: "refreshed-access" })).toBe(true); + expect(store.readCodexAccountRecord("pending")?.codexValidationPending).toBe(true); + store.markCodexAccountValidated("pending", Date.now(), generation); + expect(store.readCodexAccountRecord("pending")?.codexValidationPending).toBe(true); + expect(store.readCodexAccountRecord("pending")?.lastCodexValidatedAt).toBeUndefined(); + store.markCodexAccountValidated("pending", Date.now(), generation + 1); + expect(store.readCodexAccountRecord("pending")?.codexValidationPending).toBeUndefined(); + expect(store.readCodexAccountRecord("pending")?.lastCodexValidationStatus).toBe("ok"); + }); + test("save and load credential round-trip", async () => { const { saveCodexAccountCredential, getCodexAccountCredential } = await import("../../src/codex/account-store"); const cred = { accessToken: "tk_a", refreshToken: "rf_a", expiresAt: Date.now() + 3600_000, chatgptAccountId: "acc_a" }; diff --git a/tests/codex-integration/codex-auth-api.test.ts b/tests/codex-integration/codex-auth-api.test.ts index 04e19d49fa..efe13be799 100644 --- a/tests/codex-integration/codex-auth-api.test.ts +++ b/tests/codex-integration/codex-auth-api.test.ts @@ -27,6 +27,7 @@ import { saveCodexAccountCredential, } from "../../src/codex/account-store"; import * as accountStoreModule from "../../src/codex/account-store"; +import { isCodexAccountUsable } from "../../src/codex/account-usability"; import * as reserveAvailabilityModule from "../../src/codex/reserve-availability"; import { getMainAccountInfoCache, observeMainQuotaCredential } from "../../src/codex/main-account-cache"; import { @@ -123,6 +124,7 @@ async function completeMockCodexOAuth(options: { oauthAccountId: string; email: string; onWarmup: () => void; + warmupResponse?: () => Response; usageResponse?: () => Response; convergeCodexCatalog?: () => Promise; }): Promise<{ @@ -170,7 +172,7 @@ async function completeMockCodexOAuth(options: { } if (target === "https://chatgpt.com/backend-api/codex/responses") { options.onWarmup(); - return new Response('event: response.completed\ndata: {"type":"response.completed"}\n\n', { + return options.warmupResponse?.() ?? new Response('event: response.completed\ndata: {"type":"response.completed"}\n\n', { status: 200, headers: { "Content-Type": "text/event-stream" }, }); @@ -4948,6 +4950,177 @@ describe("codex-auth API", () => { } }); + test.each([ + { plan: "pro", primary: 0, secondary: 100 }, + { plan: "pro", primary: 100, secondary: 0 }, + { plan: "free", primary: 100, secondary: undefined }, + ])("OAuth stores an exhausted account without inference: %j", async ({ plan, primary, secondary }) => { + const accountId = "quota-pending"; + const config = makeConfig(); + setLiveStateStoreConfig(config); + let warmups = 0; + const added = await completeMockCodexOAuth({ + config, requestBody: { id: accountId }, oauthAccountId: "acct-quota-pending", email: "quota@example.test", + onWarmup: () => { warmups++; }, + warmupResponse: () => new Response("quota limited", { status: 429 }), + usageResponse: () => Response.json({ plan_type: plan, rate_limit: { + primary_window: { used_percent: primary, limit_window_seconds: plan === "free" ? 2592000 : 18000 }, + ...(secondary !== undefined ? { secondary_window: { used_percent: secondary, limit_window_seconds: 604800 } } : {}), + } }), + }); + expect(added.state.status).toBe("done"); + expect(warmups).toBe(0); + expect(config.codexAccounts?.map(account => account.id)).toContain(accountId); + expect(readCodexAccountRecord(accountId)?.codexValidationPending).toBe(true); + expect(readCodexAccountRecord(accountId)?.lastCodexValidatedAt).toBeUndefined(); + expect(isAccountNeedsReauth(accountId)).toBe(false); + expect(isCodexAccountUsable(config, accountId)).toBe(false); + // Neither a restart's lost runtime state nor an expired quota cache is evidence of recovery. + clearAccountQuota(); + clearCodexUpstreamHealth(); + expect(isCodexAccountUsable(loadConfig(), accountId)).toBe(false); + globalThis.fetch = (async () => new Response("unavailable", { status: 503 })) as typeof fetch; + const listed = await listCodexAuthAccounts(config, true); + expect(listed.find(account => account.id === accountId)).toMatchObject({ + needsReauth: false, health: { status: "warning", reason: "validation_pending" }, + }); + expect(isCodexAccountUsable(config, accountId)).toBe(false); + }); + + test("quota-pending registration validates only after a fresh recovered snapshot and completed inference", async () => { + const accountId = "quota-recovery"; + const config = makeConfig({ codexAccounts: [{ id: accountId, email: "quota@example.test", plan: "pro", isMain: false }] }); + saveConfig(config); + setLiveStateStoreConfig(config); + saveCodexAccountCredential(accountId, { + accessToken: "quota-access", refreshToken: "quota-refresh", expiresAt: Date.now() + 3600_000, chatgptAccountId: "acct-quota", + }, { validationPending: true }); + let used: number | undefined = 100; + let terminal = "response.incomplete"; + let warmups = 0; + let replaceDuringWarmup = false; + globalThis.fetch = (async (input: RequestInfo | URL) => { + if (String(input).endsWith("/wham/usage")) return Response.json({ plan_type: "pro", rate_limit: { + ...(used !== undefined ? { secondary_window: { used_percent: used, limit_window_seconds: 604800 } } : {}), + } }); + if (String(input).endsWith("/codex/responses")) { + warmups++; + if (replaceDuringWarmup) { + replaceDuringWarmup = false; + saveCodexAccountCredential(accountId, { + ...getCodexAccountCredential(accountId)!, accessToken: "replacement-access", + }, { validationPending: true }); + } + return new Response(`data: ${JSON.stringify({ type: terminal })}\n\n`); + } + throw new Error("unexpected request"); + }) as typeof fetch; + await listCodexAuthAccounts(config, true); + expect(warmups).toBe(0); + used = undefined; + await listCodexAuthAccounts(config, true); + expect(warmups).toBe(0); + used = 0; + config.pausedCodexAccountIds = [accountId]; + saveConfig(config); + await listCodexAuthAccounts(config, true); + expect(warmups).toBe(0); + config.pausedCodexAccountIds = []; + saveConfig(config); + clearAccountQuota(); + await listCodexAuthAccounts(config, false); + expect(warmups).toBe(0); // Passive reads never spend inference. + await listCodexAuthAccounts(config, true); + expect(warmups).toBe(1); + expect(isCodexAccountUsable(config, accountId)).toBe(false); + terminal = "response.completed"; + replaceDuringWarmup = true; + await listCodexAuthAccounts(config, true); + expect(warmups).toBe(2); + expect(isCodexAccountUsable(config, accountId)).toBe(false); + await listCodexAuthAccounts(config, true); + expect(warmups).toBe(3); + expect(isCodexAccountUsable(config, accountId)).toBe(true); + expect(readCodexAccountRecord(accountId)?.lastCodexValidationStatus).toBe("ok"); + await listCodexAuthAccounts(config, true); + expect(warmups).toBe(3); + }); + + test("explicit refresh joining a passive quota read retains deferred validation intent", async () => { + const accountId = "quota-coalesced"; + const config = makeConfig({ codexAccounts: [{ id: accountId, email: "quota@example.test", plan: "pro", isMain: false }] }); + saveConfig(config); + setLiveStateStoreConfig(config); + saveCodexAccountCredential(accountId, { + accessToken: "quota-access", refreshToken: "quota-refresh", expiresAt: Date.now() + 3600_000, chatgptAccountId: "acct-quota", + }, { validationPending: true }); + let release!: () => void; + const gate = new Promise(resolve => { release = resolve; }); + let usageCalls = 0; + let warmups = 0; + globalThis.fetch = (async (input: RequestInfo | URL) => { + if (String(input).endsWith("/wham/usage")) { + usageCalls++; + await gate; + return Response.json({ plan_type: "pro", rate_limit: { secondary_window: { used_percent: 0, limit_window_seconds: 604800 } } }); + } + if (String(input).endsWith("/codex/responses")) { + warmups++; + return new Response('data: {"type":"response.completed"}\n\n'); + } + throw new Error("unexpected request"); + }) as typeof fetch; + const passive = listCodexAuthAccounts(config, false); + for (let i = 0; i < 100 && usageCalls === 0; i++) await new Promise(resolve => setImmediate(resolve)); + expect(usageCalls).toBe(1); + const explicit = listCodexAuthAccounts(config, true); + // Let the second list pass its main-account read and join the held pool flight. + for (let i = 0; i < 20; i++) await new Promise(resolve => setImmediate(resolve)); + release(); + const [, listed] = await Promise.all([passive, explicit]); + expect(usageCalls).toBe(1); + expect(warmups).toBe(1); + expect(listed.find(account => account.id === accountId)?.health.status).toBe("healthy"); + expect(isCodexAccountUsable(config, accountId)).toBe(true); + }); + + test("quota-pending reauth replaces only the same identity and clears stale validation", async () => { + const accountId = "quota-reauth"; + const config = makeConfig({ codexAccounts: [{ id: accountId, email: "quota@example.test", plan: "pro", isMain: false }] }); + saveConfig(config); + setLiveStateStoreConfig(config); + saveCodexAccountCredential(accountId, { + accessToken: "old-access", refreshToken: "old-refresh", expiresAt: Date.now() + 3600_000, chatgptAccountId: "acct-quota", + }); + accountStoreModule.markCodexAccountValidated(accountId); + const options = { + config, requestBody: { id: accountId, reauth: true }, oauthAccountId: "other-account", email: "quota@example.test", + onWarmup: () => { throw new Error("exhausted accounts must not warm up"); }, + usageResponse: () => Response.json({ plan_type: "pro", rate_limit: { secondary_window: { used_percent: 100 } } }), + }; + const rejected = await completeMockCodexOAuth(options); + expect(rejected.state.status).toBe("error"); + expect(getCodexAccountCredential(accountId)?.accessToken).toBe("old-access"); + const added = await completeMockCodexOAuth({ ...options, oauthAccountId: "acct-quota" }); + expect(added.state.status).toBe("done"); + expect(readCodexAccountRecord(accountId)?.codexValidationPending).toBe(true); + expect(readCodexAccountRecord(accountId)?.lastCodexValidatedAt).toBeUndefined(); + expect(getCodexAccountCredential(accountId)?.accessToken).not.toBe("old-access"); + expect(isCodexAccountUsable(config, accountId)).toBe(false); + }); + + test.each([401, 403, 429, 503])("unknown quota retains the failed warmup gate (HTTP %s)", async status => { + const config = makeConfig(); + const result = await completeMockCodexOAuth({ + config, requestBody: { id: "quota-unknown" }, oauthAccountId: "acct-unknown", email: "unknown@example.test", + onWarmup: () => {}, warmupResponse: () => new Response("private error", { status }), + usageResponse: () => new Response("unknown", { status: 503 }), + }); + expect(result.state.status).toBe("error"); + expect(result.state.error).not.toContain("private error"); + expect(getCodexAccountCredential("quota-unknown")).toBeNull(); + }); + test("OAuth creation rejects a namespace claimed during warmup without persisting", async () => { const config = makeConfig(); const result = await completeMockCodexOAuth({ diff --git a/tests/codex-integration/token-guardian.test.ts b/tests/codex-integration/token-guardian.test.ts index 7c8e09ec85..8d6d7f51fe 100644 --- a/tests/codex-integration/token-guardian.test.ts +++ b/tests/codex-integration/token-guardian.test.ts @@ -159,6 +159,21 @@ describe("token guardian", () => { expect(mock.count()).toBeGreaterThan(0); }); + test("guardian preserves deferred registration without probing an exhausted account", async () => { + const mock = mockWarmupFetch(); + writeConfig({ + tokenGuardian: { enabled: true, codexWarmupEnabled: true, tickSeconds: 60, leadSeconds: 60 }, + providers: { openai: { adapter: "openai-responses", baseUrl: "https://chatgpt.com/backend-api/codex", authMode: "forward", codexAccountMode: "pool", refreshPolicy: "proactive" } }, + }); + saveCodexAccountCredential("acct-pending", { + accessToken: "pending", refreshToken: "rt-pending", expiresAt: Date.now() + 3600_000, chatgptAccountId: "cg-pending", + }, { validationPending: true }); + const res = await guardianSweep(Date.now()); + expect(res.warmed).toEqual([]); + expect(mock.calls()).toBe(0); + expect(readCodexAccountRecord("acct-pending")?.codexValidationPending).toBe(true); + }); + test("codex pool warmup is opt-in even when validation is stale", async () => { const mock = mockWarmupFetch(); writeConfig({ From be3b7804ac9c3990c59ed6d4e81c14818ad49d5f Mon Sep 17 00:00:00 2001 From: DaedalGames Date: Mon, 7 Sep 2026 11:57:45 +0900 Subject: [PATCH 051/412] fix(codex): fence deferred validation against stale guardian results --- src/codex/account-store.ts | 6 ++++-- src/codex/auth-api.ts | 8 ++++---- src/oauth/token-guardian.ts | 2 +- .../codex-account-store.test.ts | 2 ++ tests/codex-integration/token-guardian.test.ts | 18 ++++++++++++++++++ 5 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/codex/account-store.ts b/src/codex/account-store.ts index 7fa5cf2d1c..2d83bff28a 100644 --- a/src/codex/account-store.ts +++ b/src/codex/account-store.ts @@ -141,8 +141,8 @@ export function saveCodexAccountCredential( id: string, cred: CodexAccountCredentials, options: { validationPending?: boolean } = {}, -): void { - withCredentialMutationLockSync(() => { +): number { + return withCredentialMutationLockSync(() => { const store = loadCodexAccountRecordStore(); const current = store[id]; const refreshGrantFingerprint = current?.credential?.refreshToken === cred.refreshToken @@ -162,6 +162,7 @@ export function saveCodexAccountCredential( } : {}), }; persistCredentialMutation(store); + return store[id].generation; }); } @@ -170,6 +171,7 @@ export function markCodexAccountValidated(id: string, atMs: number = Date.now(), const store = loadCodexAccountRecordStore(); const current = store[id]; if (!current || current.deletedAt != null || !current.credential) return; + if (current.codexValidationPending && generation === undefined) return; if (generation !== undefined && current.generation !== generation) return; store[id] = { ...current, diff --git a/src/codex/auth-api.ts b/src/codex/auth-api.ts index 34e94395de..18ac70aca1 100644 --- a/src/codex/auth-api.ts +++ b/src/codex/auth-api.ts @@ -674,10 +674,10 @@ function persistNewCodexAccount( } try { - saveCodexAccountCredential(addedAccount.id, staged.credential, { + const generation = saveCodexAccountCredential(addedAccount.id, staged.credential, { validationPending: staged.validatedAt === undefined, }); - if (staged.validatedAt !== undefined) markCodexAccountValidated(addedAccount.id, staged.validatedAt); + if (staged.validatedAt !== undefined) markCodexAccountValidated(addedAccount.id, staged.validatedAt, generation); clearAccountNeedsReauth(addedAccount.id); } catch { // Config is already durable. Return the failure outcome through the coordinator so its @@ -2649,13 +2649,13 @@ export async function handleCodexAuthAPI( }; if (existingIdx >= 0) { - saveCodexAccountCredential(accountId, credential, { + const generation = saveCodexAccountCredential(accountId, credential, { validationPending: warmup.validatedAt === undefined, }); // A successful reauthentication replaces the credential generation. Do not let a // failed optional WHAM probe make the replacement inherit quota from the old record. if (reauth) clearAccountQuota(accountId); - if (warmup.validatedAt !== undefined) markCodexAccountValidated(accountId, warmup.validatedAt); + if (warmup.validatedAt !== undefined) markCodexAccountValidated(accountId, warmup.validatedAt, generation); clearAccountNeedsReauth(accountId); if (quota) setAccountQuotaFromParsed(accountId, quota); // Keep the pool id stable; refresh display metadata after a successful login/reauth. diff --git a/src/oauth/token-guardian.ts b/src/oauth/token-guardian.ts index 81e0bfc393..98862dec35 100644 --- a/src/oauth/token-guardian.ts +++ b/src/oauth/token-guardian.ts @@ -226,7 +226,7 @@ export async function guardianSweep(nowMs: number = Date.now()): Promise { const cred = { accessToken: "access-pending", refreshToken: "refresh-pending", expiresAt: Date.now() + 3600_000, chatgptAccountId: "acct-pending" }; store.saveCodexAccountCredential("pending", cred, { validationPending: true }); const generation = store.readCodexAccountRecord("pending")!.generation; + store.markCodexAccountValidated("pending"); + expect(store.readCodexAccountRecord("pending")?.codexValidationPending).toBe(true); expect(store.saveCodexAccountCredentialIfGeneration("pending", generation, { ...cred, accessToken: "refreshed-access" })).toBe(true); expect(store.readCodexAccountRecord("pending")?.codexValidationPending).toBe(true); store.markCodexAccountValidated("pending", Date.now(), generation); diff --git a/tests/codex-integration/token-guardian.test.ts b/tests/codex-integration/token-guardian.test.ts index 8d6d7f51fe..dfdc93423d 100644 --- a/tests/codex-integration/token-guardian.test.ts +++ b/tests/codex-integration/token-guardian.test.ts @@ -159,6 +159,24 @@ describe("token guardian", () => { expect(mock.count()).toBeGreaterThan(0); }); + test("a late guardian probe cannot validate a replacement pending credential", async () => { + writeConfig({ + tokenGuardian: { enabled: true, codexWarmupEnabled: true, tickSeconds: 60, leadSeconds: 60 }, + providers: { openai: { adapter: "openai-responses", baseUrl: "https://chatgpt.com/backend-api/codex", authMode: "forward", codexAccountMode: "pool", refreshPolicy: "proactive" } }, + }); + const credential = { + accessToken: "original", refreshToken: "rt-original", expiresAt: Date.now() + 3600_000, chatgptAccountId: "cg-pending", + }; + saveCodexAccountCredential("acct-late", credential); + globalThis.fetch = (async () => { + saveCodexAccountCredential("acct-late", { ...credential, accessToken: "replacement" }, { validationPending: true }); + return new Response('data: {"type":"response.completed"}\n\n'); + }) as typeof fetch; + await guardianSweep(Date.now()); + expect(readCodexAccountRecord("acct-late")?.codexValidationPending).toBe(true); + expect(readCodexAccountRecord("acct-late")?.lastCodexValidatedAt).toBeUndefined(); + }); + test("guardian preserves deferred registration without probing an exhausted account", async () => { const mock = mockWarmupFetch(); writeConfig({ From ec9cc943b46db1d4ed0eb670c6346362ebed5c11 Mon Sep 17 00:00:00 2001 From: DaedalGames Date: Mon, 7 Sep 2026 12:13:00 +0900 Subject: [PATCH 052/412] fix(codex): publish readiness changes and recheck pending selection --- src/codex/account-store.ts | 5 ++++- src/codex/auth-api.ts | 3 +++ src/oauth/token-guardian.ts | 4 +++- .../codex-account-store.test.ts | 3 +++ tests/codex-integration/codex-auth-api.test.ts | 12 ++++++++++++ tests/codex-integration/token-guardian.test.ts | 18 ++++++++++++++++++ tests/oauth/oauth-health.test.ts | 14 ++++++++++++++ 7 files changed, 57 insertions(+), 2 deletions(-) diff --git a/src/codex/account-store.ts b/src/codex/account-store.ts index 2d83bff28a..c11faa9e34 100644 --- a/src/codex/account-store.ts +++ b/src/codex/account-store.ts @@ -180,7 +180,10 @@ export function markCodexAccountValidated(id: string, atMs: number = Date.now(), lastCodexValidationError: undefined, codexValidationPending: undefined, }; - persist(store); + // Becoming routable invalidates credential-derived caches; a timestamp-only + // update on an already validated account preserves the existing epoch policy. + if (current.codexValidationPending) persistCredentialMutation(store); + else persist(store); }); } diff --git a/src/codex/auth-api.ts b/src/codex/auth-api.ts index 18ac70aca1..60174ebc63 100644 --- a/src/codex/auth-api.ts +++ b/src/codex/auth-api.ts @@ -2159,6 +2159,9 @@ export async function handleCodexAuthAPI( const exists = (runtimeConfig.codexAccounts ?? []) .some(account => isSelectableCodexPoolAccount(account) && account.id === body.accountId); if (!exists) return jsonResponse({ error: "Account not found" }, 400); + if (readCodexAccountRecord(body.accountId)?.codexValidationPending) { + return jsonResponse({ error: "Account validation is pending. Refresh quota after recovery to validate it." }, 409); + } } runtimeConfig.activeCodexAccountId = body.accountId ?? undefined; // "Use this account now" outranks selection order until the account is spent: diff --git a/src/oauth/token-guardian.ts b/src/oauth/token-guardian.ts index 98862dec35..bca76cd441 100644 --- a/src/oauth/token-guardian.ts +++ b/src/oauth/token-guardian.ts @@ -220,7 +220,9 @@ export async function guardianSweep(nowMs: number = Date.now()): Promise { test("pending validation survives credential refresh and cannot be cleared by a stale probe", async () => { const store = await import("../../src/codex/account-store"); + const { codexCredentialMutationEpoch } = await import("../../src/codex/credential-mutation-epoch"); const cred = { accessToken: "access-pending", refreshToken: "refresh-pending", expiresAt: Date.now() + 3600_000, chatgptAccountId: "acct-pending" }; store.saveCodexAccountCredential("pending", cred, { validationPending: true }); const generation = store.readCodexAccountRecord("pending")!.generation; @@ -72,7 +73,9 @@ describe("codex-account-store CRUD", () => { store.markCodexAccountValidated("pending", Date.now(), generation); expect(store.readCodexAccountRecord("pending")?.codexValidationPending).toBe(true); expect(store.readCodexAccountRecord("pending")?.lastCodexValidatedAt).toBeUndefined(); + const beforeValidation = codexCredentialMutationEpoch(); store.markCodexAccountValidated("pending", Date.now(), generation + 1); + expect(codexCredentialMutationEpoch()).toBe(beforeValidation + 1); expect(store.readCodexAccountRecord("pending")?.codexValidationPending).toBeUndefined(); expect(store.readCodexAccountRecord("pending")?.lastCodexValidationStatus).toBe("ok"); }); diff --git a/tests/codex-integration/codex-auth-api.test.ts b/tests/codex-integration/codex-auth-api.test.ts index efe13be799..c6d6b7165b 100644 --- a/tests/codex-integration/codex-auth-api.test.ts +++ b/tests/codex-integration/codex-auth-api.test.ts @@ -4999,6 +4999,16 @@ describe("codex-auth API", () => { let terminal = "response.incomplete"; let warmups = 0; let replaceDuringWarmup = false; + const selectAccount = () => { + const req = new Request("http://localhost/api/codex-auth/active", { + method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ accountId }), + }); + return handleCodexAuthAPI(req, new URL(req.url), config); + }; + const pendingSelection = await selectAccount(); + expect(pendingSelection?.status).toBe(409); + expect(loadConfig().activeCodexAccountId).toBeUndefined(); + expect(loadConfig().activeCodexAccountPinned).toBeUndefined(); globalThis.fetch = (async (input: RequestInfo | URL) => { if (String(input).endsWith("/wham/usage")) return Response.json({ plan_type: "pro", rate_limit: { ...(used !== undefined ? { secondary_window: { used_percent: used, limit_window_seconds: 604800 } } : {}), @@ -5042,6 +5052,8 @@ describe("codex-auth API", () => { expect(warmups).toBe(3); expect(isCodexAccountUsable(config, accountId)).toBe(true); expect(readCodexAccountRecord(accountId)?.lastCodexValidationStatus).toBe("ok"); + expect((await selectAccount())?.status).toBe(200); + expect(loadConfig().activeCodexAccountId).toBe(accountId); await listCodexAuthAccounts(config, true); expect(warmups).toBe(3); }); diff --git a/tests/codex-integration/token-guardian.test.ts b/tests/codex-integration/token-guardian.test.ts index dfdc93423d..aed115c8db 100644 --- a/tests/codex-integration/token-guardian.test.ts +++ b/tests/codex-integration/token-guardian.test.ts @@ -177,6 +177,24 @@ describe("token guardian", () => { expect(readCodexAccountRecord("acct-late")?.lastCodexValidatedAt).toBeUndefined(); }); + test("guardian rechecks pending replacement after asynchronous token resolution", async () => { + const mock = mockWarmupFetch(); + writeConfig({ + tokenGuardian: { enabled: true, codexWarmupEnabled: true, tickSeconds: 60, leadSeconds: 60 }, + providers: { openai: { adapter: "openai-responses", baseUrl: "https://chatgpt.com/backend-api/codex", authMode: "forward", codexAccountMode: "pool", refreshPolicy: "proactive" } }, + }); + const credential = { + accessToken: "original", refreshToken: "rt-original", expiresAt: Date.now() + 3600_000, chatgptAccountId: "cg-pending", + }; + saveCodexAccountCredential("acct-resolving", credential); + const sweep = guardianSweep(Date.now()); + saveCodexAccountCredential("acct-resolving", { ...credential, accessToken: "replacement" }, { validationPending: true }); + const result = await sweep; + expect(mock.calls()).toBe(0); + expect(result.warmed).toEqual([]); + expect(readCodexAccountRecord("acct-resolving")?.codexValidationPending).toBe(true); + }); + test("guardian preserves deferred registration without probing an exhausted account", async () => { const mock = mockWarmupFetch(); writeConfig({ diff --git a/tests/oauth/oauth-health.test.ts b/tests/oauth/oauth-health.test.ts index 1f04fbc996..594417bfc8 100644 --- a/tests/oauth/oauth-health.test.ts +++ b/tests/oauth/oauth-health.test.ts @@ -8,7 +8,9 @@ import { collectOAuthHealthEntries, collectOAuthHealthEntriesForCli, projectOAuthAccountHealth, + projectCodexAccountHealth, } from "../../src/oauth/health"; +import { saveCodexAccountCredential } from "../../src/codex/account-store"; import { getAccountSet, markAccountNeedsReauth, saveCredential } from "../../src/oauth/store"; import { clearAccountNeedsReauth, @@ -58,6 +60,18 @@ afterEach(() => { }); describe("projectOAuthAccountHealth", () => { + test("pending Codex pool validation warns while reauthentication and native main keep their own health", () => { + saveCodexAccountCredential("pending-health", { + accessToken: "pending-access", refreshToken: "pending-refresh", expiresAt: Date.now() + 3600_000, + chatgptAccountId: "pending-health", + }, { validationPending: true }); + expect(projectCodexAccountHealth({ accountId: "pending-health", needsReauth: false })) + .toEqual({ status: "warning", reason: "validation_pending" }); + expect(projectCodexAccountHealth({ accountId: "pending-health", needsReauth: true })) + .toEqual({ status: "reauth_required", reason: "refresh_failed" }); + expect(projectCodexAccountHealth({ accountId: MAIN_CODEX_ACCOUNT_ID, needsReauth: false })) + .toEqual({ status: "healthy" }); + }); test("reauth beats cooldown", () => { expect(projectOAuthAccountHealth({ needsReauth: true, From 1639ce4a96738e4055af4c2a7decab5dea66d905 Mon Sep 17 00:00:00 2001 From: DaedalGames Date: Mon, 7 Sep 2026 12:23:44 +0900 Subject: [PATCH 053/412] fix(codex): enforce pending readiness at request auth boundaries --- src/codex/auth-context.ts | 21 +++++++++++++++++++ src/codex/quota-auto-refresh.ts | 10 +++++++-- .../codex-auth-context.test.ts | 16 ++++++++++++++ .../codex-quota-auto-refresh.test.ts | 13 ++++++++++++ 4 files changed, 58 insertions(+), 2 deletions(-) diff --git a/src/codex/auth-context.ts b/src/codex/auth-context.ts index 2f319b3144..5ff54440e4 100644 --- a/src/codex/auth-context.ts +++ b/src/codex/auth-context.ts @@ -6,6 +6,7 @@ import { CodexCredentialRefreshStaleError, getValidCodexToken, isCodexAccountGenerationLive, + readCodexAccountRecord, } from "./account-store"; import { isAccountNeedsReauth, markAccountNeedsReauth } from "./account-runtime-state"; import { ConfigMutationLockError } from "../config"; @@ -199,6 +200,19 @@ export class CodexPoolAuthenticationError extends Error { } } +class CodexAccountValidationPendingError extends CodexPoolAuthenticationError { + constructor() { + super("Codex account validation is pending; refresh quota after recovery to validate it"); + this.name = "CodexAccountValidationPendingError"; + } +} + +function assertCodexAccountValidationReady(accountId: string): void { + if (accountId !== MAIN_CODEX_ACCOUNT_ID && readCodexAccountRecord(accountId)?.codexValidationPending) { + throw new CodexAccountValidationPendingError(); + } +} + export const CODEX_MAIN_PROFILE_MAINTENANCE_MESSAGE = "OpenCodex local native-main profile maintenance is active; retry this request"; @@ -536,6 +550,7 @@ export class CodexThreadAffinityExpiredError extends Error { export function shouldMarkAccountNeedsReauthForCodexAuthFailure(cause: unknown): boolean { return !(cause instanceof CodexMainAccountHardLockError) + && !(cause instanceof CodexAccountValidationPendingError) && !(cause instanceof CodexReserveUnavailableError) && !(cause instanceof CodexCredentialGenerationConflictError) && !(cause instanceof CodexCredentialRefreshLockTimeoutError) @@ -851,6 +866,9 @@ export async function resolveCodexAuthContext( } finally { selectionAdmission?.release(); } + // Legacy selectors may retain an unusable account for actionable errors. A + // deferred credential must never become request auth through that fallback. + assertCodexAccountValidationReady(accountId); // Lazy prime: if the selected account has no quota yet, the pool is likely // unprimed (dashboard never opened, or startup prime was blocked). Kick a // best-effort prime so the NEXT routing decision has real scores. This never @@ -938,6 +956,7 @@ export async function resolveCodexAuthContext( try { const token = await getValidCodexToken(accountId); + assertCodexAccountValidationReady(accountId); return { kind: "pool", accountId, @@ -977,6 +996,7 @@ export function applyCodexAuthContextToProvider( mode: CodexAccountMode | undefined, ): OcxRuntimeProviderConfig { if (mode !== "pool" || (ctx.kind !== "pool" && ctx.kind !== "main-pool") || provider.authMode !== "forward") return provider; + assertCodexAccountValidationReady(ctx.accountId); return { ...provider, _codexAccountOverride: { @@ -1019,6 +1039,7 @@ export function materializeCodexUpstreamAuth( if (value) selected.set(name, value); } if (ctx.kind === "pool" || ctx.kind === "main-pool") { + assertCodexAccountValidationReady(ctx.accountId); selected.set("authorization", `Bearer ${ctx.accessToken}`); selected.set("chatgpt-account-id", ctx.chatgptAccountId); if (ctx.kind === "main-pool") { diff --git a/src/codex/quota-auto-refresh.ts b/src/codex/quota-auto-refresh.ts index 88291e0cdd..66dd613712 100644 --- a/src/codex/quota-auto-refresh.ts +++ b/src/codex/quota-auto-refresh.ts @@ -8,7 +8,7 @@ import { isSelectableCodexPoolAccount } from "./account-id"; import { reconcileMainCodexAccountRuntimeState } from "./account-lifecycle"; import { isCodexAccountPaused } from "./account-pause"; import { isAccountNeedsReauth } from "./account-runtime-state"; -import { getValidCodexToken } from "./account-store"; +import { getValidCodexToken, readCodexAccountRecord } from "./account-store"; import { getMainAccountToken, getValidMainAccountToken, MAIN_CODEX_ACCOUNT_ID } from "./main-account"; import { isMainAccountHardLocked } from "./main-account-hard-lock"; import { tryAcquireNativeMainProfileClaim } from "./native-main-admission"; @@ -100,7 +100,12 @@ function mainWarmupRestricted(config: OcxConfig): boolean { async function warmAccount(config: OcxConfig, accountId: string): Promise { if (accountId !== MAIN_CODEX_ACCOUNT_ID) { - await warmCodexAccount(await getValidCodexToken(accountId)); + if (readCodexAccountRecord(accountId)?.codexValidationPending) return false; + const token = await getValidCodexToken(accountId); + const record = readCodexAccountRecord(accountId); + if (!record?.credential || record.deletedAt != null || record.codexValidationPending + || record.generation !== token.generation) return false; + await warmCodexAccount(token); return; } const lease = tryAcquireNativeMainProfileClaim(); @@ -183,6 +188,7 @@ export async function runCodexQuotaAutoRefresh( ]; const due = accountIds.flatMap(accountId => { if (isCodexAccountPaused(config, accountId) + || (accountId !== MAIN_CODEX_ACCOUNT_ID && readCodexAccountRecord(accountId)?.codexValidationPending) || isAccountNeedsReauth(accountId) || (accountId === MAIN_CODEX_ACCOUNT_ID && isMainAccountHardLocked(config)) || (retryAfterByAccount.get(accountId) ?? 0) > now) return []; diff --git a/tests/codex-integration/codex-auth-context.test.ts b/tests/codex-integration/codex-auth-context.test.ts index bb4f24a098..f2ee5ce556 100644 --- a/tests/codex-integration/codex-auth-context.test.ts +++ b/tests/codex-integration/codex-auth-context.test.ts @@ -218,6 +218,22 @@ function expiredJwt(): string { return `header.${payload}.signature`; } describe("Codex auth context", () => { + test("pending-only pool fallback cannot materialize request authentication", async () => { + const cfg = config(); + cfg.activeCodexAccountId = "pool-a"; + const credential = { accessToken: "pending-access", refreshToken: "pending-refresh", expiresAt: Date.now() + 3600_000, chatgptAccountId: "pool_acc" }; + saveCodexAccountCredential("pool-a", credential, { validationPending: true }); + await expect(resolveCodexAuthContext(new Headers(), cfg, "pool", { + primeCodexPoolQuotas: async () => {}, + })).rejects.toThrow(CodexPoolAuthenticationError); + expect(isAccountNeedsReauth("pool-a")).toBe(false); + + // Also reject a context acquired before reauthentication replaced the record. + const ctx = { kind: "pool" as const, accountId: "pool-a", generation: 0, writerGeneration: 0, + accessToken: "old-access", chatgptAccountId: "pool_acc" }; + expect(() => materializeCodexUpstreamAuth(new Headers(), ctx)).toThrow("validation is pending"); + expect(() => applyCodexAuthContextToProvider(cfg.providers.chatgpt!, ctx, "pool")).toThrow("validation is pending"); + }); test("main-profile drain routes a non-main pool account without native reads or quota priming", async () => { saveCodexAccountCredential("pool-a", { accessToken: "pool_token", diff --git a/tests/codex-integration/codex-quota-auto-refresh.test.ts b/tests/codex-integration/codex-quota-auto-refresh.test.ts index 7bbe2ae73e..879c3c266f 100644 --- a/tests/codex-integration/codex-quota-auto-refresh.test.ts +++ b/tests/codex-integration/codex-quota-auto-refresh.test.ts @@ -18,6 +18,7 @@ import { handleManagementAPI, type ManagementApiDeps } from "../../src/server/ma import { loadConfig, readConfigDiagnostics, validateConfigCandidate } from "../../src/config"; import type { OcxConfig } from "../../src/types"; import { startupHealthFixture } from "../helpers/startup-health"; +import { saveCodexAccountCredential } from "../../src/codex/account-store"; const NOW = 1_800_000_000_000; const RESET_SECONDS = NOW / 1000; @@ -101,6 +102,18 @@ afterEach(() => { }); describe("Codex quota window auto refresh", () => { + test("pending reauthentication suppresses scheduled inference and completion markers", async () => { + const cfg = config(); + saveCodexAccountCredential("pool-a", { + accessToken: "pending-access", refreshToken: "pending-refresh", expiresAt: NOW + 3600_000, chatgptAccountId: "pool-a", + }, { validationPending: true }); + let warmups = 0; + await runCodexQuotaAutoRefresh(cfg, NOW, { + getQuota: () => quota(), warmAccount: async () => { warmups++; }, persistCompleted: recordMarkers, + }); + expect(warmups).toBe(0); + expect(cfg.codexQuotaAutoRefresh?.["pool-a"]).toEqual({ fiveHour: true, weekly: true }); + }); test("detects only reported 5-hour and weekly capabilities", () => { const cfg = config(); expect(codexQuotaAutoRefreshStatus(cfg, "pool-a", quota())).toEqual({ From 2636e63f0209566da0fa0f42d24b2e52d0b68984 Mon Sep 17 00:00:00 2001 From: DaedalGames Date: Mon, 7 Sep 2026 12:28:48 +0900 Subject: [PATCH 054/412] fix(codex): fence failed warmup metadata by credential generation --- src/codex/account-store.ts | 4 +++- src/oauth/token-guardian.ts | 6 ++++-- tests/codex-integration/token-guardian.test.ts | 6 ++++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/codex/account-store.ts b/src/codex/account-store.ts index c11faa9e34..7e623da177 100644 --- a/src/codex/account-store.ts +++ b/src/codex/account-store.ts @@ -187,11 +187,13 @@ export function markCodexAccountValidated(id: string, atMs: number = Date.now(), }); } -export function markCodexAccountValidationFailed(id: string, reason: string): void { +export function markCodexAccountValidationFailed(id: string, reason: string, generation?: number): void { withCredentialMutationLockSync(() => { const store = loadCodexAccountRecordStore(); const current = store[id]; if (!current || current.deletedAt != null || !current.credential) return; + if (current.codexValidationPending && generation === undefined) return; + if (generation !== undefined && current.generation !== generation) return; store[id] = { ...current, lastCodexValidationStatus: "failed", diff --git a/src/oauth/token-guardian.ts b/src/oauth/token-guardian.ts index bca76cd441..0c888c62f5 100644 --- a/src/oauth/token-guardian.ts +++ b/src/oauth/token-guardian.ts @@ -217,12 +217,14 @@ export async function guardianSweep(nowMs: number = Date.now()): Promise { + let warmupGeneration: number | undefined; try { const token = await getValidCodexToken(id); if (needsRefresh) result.refreshed.push(key); const current = readCodexAccountRecord(id); if (needsWarmup && current?.credential && current.deletedAt == null && !current.codexValidationPending && current.generation === token.generation) { + warmupGeneration = token.generation; await warmCodexAccount({ accessToken: token.accessToken, chatgptAccountId: token.chatgptAccountId, @@ -239,8 +241,8 @@ export async function guardianSweep(nowMs: number = Date.now()): Promise { expect(mock.count()).toBeGreaterThan(0); }); - test("a late guardian probe cannot validate a replacement pending credential", async () => { + test.each(["response.completed", "response.failed"])("a late guardian probe cannot change a replacement pending credential (%s)", async terminal => { writeConfig({ tokenGuardian: { enabled: true, codexWarmupEnabled: true, tickSeconds: 60, leadSeconds: 60 }, providers: { openai: { adapter: "openai-responses", baseUrl: "https://chatgpt.com/backend-api/codex", authMode: "forward", codexAccountMode: "pool", refreshPolicy: "proactive" } }, @@ -170,11 +170,13 @@ describe("token guardian", () => { saveCodexAccountCredential("acct-late", credential); globalThis.fetch = (async () => { saveCodexAccountCredential("acct-late", { ...credential, accessToken: "replacement" }, { validationPending: true }); - return new Response('data: {"type":"response.completed"}\n\n'); + return new Response(`data: ${JSON.stringify({ type: terminal })}\n\n`); }) as typeof fetch; await guardianSweep(Date.now()); expect(readCodexAccountRecord("acct-late")?.codexValidationPending).toBe(true); expect(readCodexAccountRecord("acct-late")?.lastCodexValidatedAt).toBeUndefined(); + expect(readCodexAccountRecord("acct-late")?.lastCodexValidationStatus).toBeUndefined(); + expect(readCodexAccountRecord("acct-late")?.lastCodexValidationError).toBeUndefined(); }); test("guardian rechecks pending replacement after asynchronous token resolution", async () => { From d2d66261033f161d28239fdc068491caca046d8a Mon Sep 17 00:00:00 2001 From: DaedalGames Date: Mon, 7 Sep 2026 12:32:37 +0900 Subject: [PATCH 055/412] fix(codex): distinguish manual validation from background quota refresh --- src/codex/auth-api.ts | 15 +++++++++---- .../codex-integration/codex-auth-api.test.ts | 22 +++++++++++++------ 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/codex/auth-api.ts b/src/codex/auth-api.ts index 60174ebc63..0586c28b68 100644 --- a/src/codex/auth-api.ts +++ b/src/codex/auth-api.ts @@ -1758,6 +1758,7 @@ export interface CodexAuthAccountsSnapshot { export async function listCodexAuthAccountsSnapshot( config: OcxConfig, forceRefresh = false, + options: { validatePending?: boolean } = {}, ): Promise { const runtimeConfig = getRuntimeConfig(config); const poolAccounts = (runtimeConfig.codexAccounts ?? []).filter(isSelectableCodexPoolAccount); @@ -1769,7 +1770,7 @@ export async function listCodexAuthAccountsSnapshot( quotaResult = { quota: null, needsReauth: true }; } else { try { - quotaResult = await fetchPoolAccountQuota(account.id, forceRefresh, account.plan, getValidCodexToken, forceRefresh); + quotaResult = await fetchPoolAccountQuota(account.id, forceRefresh, account.plan, getValidCodexToken, options.validatePending === true); } catch (error) { if (!(error instanceof PoolQuotaProbeBusyError)) throw error; quotaResult = { @@ -1865,8 +1866,12 @@ export async function listCodexAuthAccountsSnapshot( }; } -export async function listCodexAuthAccounts(config: OcxConfig, forceRefresh = false): Promise { - return (await listCodexAuthAccountsSnapshot(config, forceRefresh)).accounts; +export async function listCodexAuthAccounts( + config: OcxConfig, + forceRefresh = false, + options: { validatePending?: boolean } = {}, +): Promise { + return (await listCodexAuthAccountsSnapshot(config, forceRefresh, options)).accounts; } interface PauseExhaustedResult { @@ -1979,7 +1984,9 @@ export async function handleCodexAuthAPI( if (url.pathname === "/api/codex-auth/accounts" && req.method === "GET") { const forceRefresh = url.searchParams.get("refresh") === "1" || url.searchParams.get("refresh") === "true"; - return jsonResponse({ accounts: await listCodexAuthAccounts(config, forceRefresh) }); + // Background report/reset pollers also bypass caches; only this explicit + // accounts refresh opts into inference-backed validation of pending accounts. + return jsonResponse({ accounts: await listCodexAuthAccounts(config, forceRefresh, { validatePending: forceRefresh }) }); } if (url.pathname === "/api/codex-auth/accounts" && req.method === "POST") { diff --git a/tests/codex-integration/codex-auth-api.test.ts b/tests/codex-integration/codex-auth-api.test.ts index c6d6b7165b..57c2c9b4d8 100644 --- a/tests/codex-integration/codex-auth-api.test.ts +++ b/tests/codex-integration/codex-auth-api.test.ts @@ -4999,6 +4999,11 @@ describe("codex-auth API", () => { let terminal = "response.incomplete"; let warmups = 0; let replaceDuringWarmup = false; + const refreshAccounts = async () => { + const req = new Request("http://localhost/api/codex-auth/accounts?refresh=1"); + const response = await handleCodexAuthAPI(req, new URL(req.url), config); + expect(response?.status).toBe(200); + }; const selectAccount = () => { const req = new Request("http://localhost/api/codex-auth/active", { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ accountId }), @@ -5025,15 +5030,15 @@ describe("codex-auth API", () => { } throw new Error("unexpected request"); }) as typeof fetch; - await listCodexAuthAccounts(config, true); + await refreshAccounts(); expect(warmups).toBe(0); used = undefined; - await listCodexAuthAccounts(config, true); + await refreshAccounts(); expect(warmups).toBe(0); used = 0; config.pausedCodexAccountIds = [accountId]; saveConfig(config); - await listCodexAuthAccounts(config, true); + await refreshAccounts(); expect(warmups).toBe(0); config.pausedCodexAccountIds = []; saveConfig(config); @@ -5041,20 +5046,23 @@ describe("codex-auth API", () => { await listCodexAuthAccounts(config, false); expect(warmups).toBe(0); // Passive reads never spend inference. await listCodexAuthAccounts(config, true); + expect(warmups).toBe(0); // Forced background reads are not manual validation. + expect(isCodexAccountUsable(config, accountId)).toBe(false); + await refreshAccounts(); expect(warmups).toBe(1); expect(isCodexAccountUsable(config, accountId)).toBe(false); terminal = "response.completed"; replaceDuringWarmup = true; - await listCodexAuthAccounts(config, true); + await refreshAccounts(); expect(warmups).toBe(2); expect(isCodexAccountUsable(config, accountId)).toBe(false); - await listCodexAuthAccounts(config, true); + await refreshAccounts(); expect(warmups).toBe(3); expect(isCodexAccountUsable(config, accountId)).toBe(true); expect(readCodexAccountRecord(accountId)?.lastCodexValidationStatus).toBe("ok"); expect((await selectAccount())?.status).toBe(200); expect(loadConfig().activeCodexAccountId).toBe(accountId); - await listCodexAuthAccounts(config, true); + await refreshAccounts(); expect(warmups).toBe(3); }); @@ -5085,7 +5093,7 @@ describe("codex-auth API", () => { const passive = listCodexAuthAccounts(config, false); for (let i = 0; i < 100 && usageCalls === 0; i++) await new Promise(resolve => setImmediate(resolve)); expect(usageCalls).toBe(1); - const explicit = listCodexAuthAccounts(config, true); + const explicit = listCodexAuthAccounts(config, true, { validatePending: true }); // Let the second list pass its main-account read and join the held pool flight. for (let i = 0; i < 20; i++) await new Promise(resolve => setImmediate(resolve)); release(); From 2dd7b43a1625dc2c24480ae17651564324909413 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 7 Sep 2026 03:34:54 +0000 Subject: [PATCH 056/412] chore(release): open dev at 2.47.0 before releasing 2.46.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bdf30eb215..0b2d5768c1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@bitkyc08/opencodex", - "version": "2.46.0", + "version": "2.47.0", "description": "Universal provider proxy for OpenAI Codex & Claude Code — use any LLM with Codex CLI/App/SDK and Claude Code", "type": "module", "main": "./bin/package-main.mjs", From ebf4728a5f03c9d1ad0763cdb51f96f0324ff575 Mon Sep 17 00:00:00 2001 From: DaedalGames Date: Mon, 7 Sep 2026 13:18:20 +0900 Subject: [PATCH 057/412] fix(codex): report pending validation in local health diagnostics --- src/oauth/health.ts | 6 ++---- tests/oauth/oauth-health.test.ts | 12 ++++++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/oauth/health.ts b/src/oauth/health.ts index af68353c50..acbc4a587c 100644 --- a/src/oauth/health.ts +++ b/src/oauth/health.ts @@ -282,11 +282,9 @@ function collectLocalCodexEntries(now: number): OAuthHealthEntry[] { const hasPoolCredential = accountId !== MAIN_CODEX_ACCOUNT_ID && getCodexAccountCredential(accountId) !== null; if (!hasPoolCredential && !needsReauth && !snap) continue; - const health = projectOAuthAccountHealth({ + const health = projectCodexAccountHealth({ + accountId, needsReauth, - reauthReason: needsReauth ? "refresh_failed" : undefined, - cooldownUntilMs: snap?.cooldownUntil, - cooldownReason: cooldownReasonFromSource(snap?.cooldownSource), now, }); pushEntry(entries, "codex", accountId, health); diff --git a/tests/oauth/oauth-health.test.ts b/tests/oauth/oauth-health.test.ts index 594417bfc8..51186074c0 100644 --- a/tests/oauth/oauth-health.test.ts +++ b/tests/oauth/oauth-health.test.ts @@ -122,6 +122,18 @@ describe("projectOAuthAccountHealth", () => { }); describe("collectOAuthHealthEntries", () => { + test("local Codex diagnostics expose pending validation with its recovery action", () => { + saveCodexAccountCredential("pending-local", { + accessToken: "pending-access", refreshToken: "pending-refresh", expiresAt: Date.now() + 3600_000, + chatgptAccountId: "pending-local", + }, { validationPending: true }); + expect(collectOAuthHealthEntries().find(entry => entry.provider === "codex" && entry.accountId === "pending-local")) + .toEqual({ + provider: "codex", accountId: "pending-local", + health: { status: "warning", reason: "validation_pending" }, + action: "wait for quota recovery, then refresh Codex account quotas to finish validation", + }); + }); test("projects needsReauth account with reauth action", async () => { await saveCredential("kimi", { access: "kimi-access", From 3dd3cfdfcfc75450761ed6fe9f600ce6fd960b23 Mon Sep 17 00:00:00 2001 From: DaedalGames Date: Mon, 7 Sep 2026 13:20:56 +0900 Subject: [PATCH 058/412] test(codex): distinguish passive quota observation from validation --- .../codex-quota-prime.test.ts | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/codex-integration/codex-quota-prime.test.ts b/tests/codex-integration/codex-quota-prime.test.ts index 94a605d5f2..aeb67e3370 100644 --- a/tests/codex-integration/codex-quota-prime.test.ts +++ b/tests/codex-integration/codex-quota-prime.test.ts @@ -125,6 +125,33 @@ describe("primeCodexPoolQuotas", () => { if (existsSync(TEST_DIR)) removeTreeWithRetry(TEST_DIR); }); + test("startup may observe pending account quota without inference or validation", async () => { + const config = makeConfig(); + seedPoolAccount(config, "pending", "pro"); + saveCodexAccountCredential("pending", readCodexAccountRecord("pending")!.credential!, { validationPending: true }); + const originalFetch = globalThis.fetch; + let usageReads = 0; + let modelRequests = 0; + try { + globalThis.fetch = async (input: RequestInfo | URL) => { + if (String(input).includes("/backend-api/wham/usage")) { + usageReads++; + return whamResponse(0); + } + modelRequests++; + throw new Error("startup must not send inference for pending validation"); + }; + await primeCodexPoolQuotas(config, "startup"); + expect(usageReads).toBe(1); + expect(getAccountQuota("pending")?.weeklyPercent).toBe(0); + expect(modelRequests).toBe(0); + expect(readCodexAccountRecord("pending")?.codexValidationPending).toBe(true); + expect(readCodexAccountRecord("pending")?.lastCodexValidatedAt).toBeUndefined(); + } finally { + globalThis.fetch = originalFetch; + } + }); + test("prime populates stale/unknown pool accounts", async () => { const config = makeConfig(); seedPoolAccount(config, "p1"); From 77ac748ce8e1141d0890fc23f1f3d811a1a2c168 Mon Sep 17 00:00:00 2001 From: DaedalGames Date: Mon, 7 Sep 2026 13:45:28 +0900 Subject: [PATCH 059/412] test: remove host timing dependencies from readiness checks --- .../pr-assets/codex-quota-registration.png | Bin 118343 -> 0 bytes gui/tests/apikeys-mutation-timeout.test.tsx | 11 ++- tests/routing/combo-management-api.test.ts | 72 ++++++++++-------- 3 files changed, 48 insertions(+), 35 deletions(-) delete mode 100644 .github/pr-assets/codex-quota-registration.png diff --git a/.github/pr-assets/codex-quota-registration.png b/.github/pr-assets/codex-quota-registration.png deleted file mode 100644 index a98a0b56c69c483bb10e6a112112ddf305fbe6d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 118343 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 diff --git a/gui/tests/apikeys-mutation-timeout.test.tsx b/gui/tests/apikeys-mutation-timeout.test.tsx index 55f3623f74..76bf9909a3 100644 --- a/gui/tests/apikeys-mutation-timeout.test.tsx +++ b/gui/tests/apikeys-mutation-timeout.test.tsx @@ -16,6 +16,7 @@ let restoreGlobals: (() => void) | undefined; let previousLanguageDescriptor: PropertyDescriptor | undefined; let previousAbortTimeout: PropertyDescriptor | undefined; let testWindow: Window; +let expireTimeouts: Array<() => void>; const AUTH_MATRIX = [ { endpoint: "/v1/responses", bearer: "rejected", dedicated: "required", xApiKey: "rejected" }, @@ -41,18 +42,20 @@ beforeEach(() => { testWindow = new Window({ url: "http://localhost/" }); previousLanguageDescriptor = Object.getOwnPropertyDescriptor(globalThis.navigator, "language"); Object.defineProperty(globalThis.navigator, "language", { configurable: true, value: "en-US" }); - // Shorten the fuse rather than the wiring. `createBoundedFetch` still runs, + // Control expiry rather than racing a 30ms wall-clock fuse under suite load. + // `createBoundedFetch` still runs, // still builds the combined signal, and the page still has to pass it to // `fetch` — waiting the real 15s would only prove the clock works, at the // price of half a minute on every suite run. The timer itself is covered in // tests/bounded-fetch.test.ts. previousAbortTimeout = Object.getOwnPropertyDescriptor(AbortSignal, "timeout"); + expireTimeouts = []; Object.defineProperty(AbortSignal, "timeout", { configurable: true, value: (ms: number) => { expect(ms).toBe(15_000); const controller = new AbortController(); - setTimeout(() => controller.abort(new DOMException("TimeoutError", "TimeoutError")), 30); + expireTimeouts.push(() => controller.abort(new DOMException("TimeoutError", "TimeoutError"))); return controller.signal; }, }); @@ -180,7 +183,7 @@ test("a delete that never answers gives navigation back instead of locking it", expect(backButton(container).disabled).toBe(true); // The bound fires and the page is usable again — no reload required. - await tick(120); + await act(async () => { for (const expire of expireTimeouts) expire(); }); await tick(); expect(seen.aborted).toBe(true); @@ -222,7 +225,7 @@ test("a rename that never answers releases the lock and keeps the draft", async expect(backButton(container).disabled).toBe(true); - await tick(120); + await act(async () => { for (const expire of expireTimeouts) expire(); }); await tick(); expect(seen.aborted).toBe(true); diff --git a/tests/routing/combo-management-api.test.ts b/tests/routing/combo-management-api.test.ts index 85f6be0ff6..e0c21f2957 100644 --- a/tests/routing/combo-management-api.test.ts +++ b/tests/routing/combo-management-api.test.ts @@ -42,6 +42,7 @@ import { syncCatalogModels } from "../../src/codex/catalog"; import { injectClaudeAgentDefs } from "../../src/claude/agents-inject"; import { catalogConvergenceFactory } from "../helpers/catalog-convergence"; import { removeTreeWithRetry } from "../helpers/remove-tree"; +import * as appServerProcesses from "../../src/codex/app-server-processes"; const VALID_COMBO = { targets: [{ provider: "a", model: "m1" }] }; @@ -831,38 +832,47 @@ describe("combo management API", () => { }); test("GET subagent models exposes a combo alias as an available round-trip value", async () => { - const config = baseConfig({ - subagentModels: ["deepseek-v4-flash"], - combos: { - free: { ...VALID_COMBO, alias: "deepseek-v4-flash" }, - }, - }); - config.providers.a!.modelContextWindows = { m1: 128_000 }; + // Process enumeration is unrelated to roster retention and can block on Windows CIM. + const processProbe = spyOn(appServerProcesses, "collectCodexAppServerCatalogState") + .mockReturnValue({ state: "not_running", processes: [], catalogMtimeMs: null }); + try { + const config = baseConfig({ + subagentModels: ["deepseek-v4-flash"], + combos: { + free: { ...VALID_COMBO, alias: "deepseek-v4-flash" }, + }, + }); + // This exercises configured alias visibility, not live provider discovery. + for (const provider of Object.values(config.providers)) provider.liveModels = false; + config.providers.a!.modelContextWindows = { m1: 128_000 }; - const response = await comboApi(config, "GET", "/api/subagent-models"); - expect(response?.status).toBe(200); - const body = await response!.json() as { chosen: string[]; available: string[] }; - expect(body.chosen).toEqual(["deepseek-v4-flash"]); - expect(body.available).toContain("deepseek-v4-flash"); - expect(body.available.filter(model => model === "deepseek-v4-flash")).toHaveLength(1); - expect(body.available).not.toContain("combo/free"); - - // Disabling an alias hides it from the pickable set, but NOT while it still holds a - // saved roster slot: the dashboard PUTs exactly the rows it can render, so dropping a - // chosen id here silently truncates the persisted roster on the next Save. Covered by - // tests/routing/subagent-roster-retention.test.ts. - config.disabledModels = ["deepseek-v4-flash"]; - const disabledResponse = await comboApi(config, "GET", "/api/subagent-models"); - const disabledBody = await disabledResponse!.json() as { chosen: string[]; available: string[] }; - expect(disabledBody.chosen).toEqual(["deepseek-v4-flash"]); - expect(disabledBody.available).toContain("deepseek-v4-flash"); - expect(disabledBody.available.filter(model => model === "deepseek-v4-flash")).toHaveLength(1); - - // Once it no longer occupies a roster slot, the disable takes full effect. - config.subagentModels = []; - const unfeaturedResponse = await comboApi(config, "GET", "/api/subagent-models"); - const unfeaturedBody = await unfeaturedResponse!.json() as { available: string[] }; - expect(unfeaturedBody.available).not.toContain("deepseek-v4-flash"); + const response = await comboApi(config, "GET", "/api/subagent-models"); + expect(response?.status).toBe(200); + const body = await response!.json() as { chosen: string[]; available: string[] }; + expect(body.chosen).toEqual(["deepseek-v4-flash"]); + expect(body.available).toContain("deepseek-v4-flash"); + expect(body.available.filter(model => model === "deepseek-v4-flash")).toHaveLength(1); + expect(body.available).not.toContain("combo/free"); + + // Disabling an alias hides it from the pickable set, but NOT while it still holds a + // saved roster slot: the dashboard PUTs exactly the rows it can render, so dropping a + // chosen id here silently truncates the persisted roster on the next Save. Covered by + // tests/routing/subagent-roster-retention.test.ts. + config.disabledModels = ["deepseek-v4-flash"]; + const disabledResponse = await comboApi(config, "GET", "/api/subagent-models"); + const disabledBody = await disabledResponse!.json() as { chosen: string[]; available: string[] }; + expect(disabledBody.chosen).toEqual(["deepseek-v4-flash"]); + expect(disabledBody.available).toContain("deepseek-v4-flash"); + expect(disabledBody.available.filter(model => model === "deepseek-v4-flash")).toHaveLength(1); + + // Once it no longer occupies a roster slot, the disable takes full effect. + config.subagentModels = []; + const unfeaturedResponse = await comboApi(config, "GET", "/api/subagent-models"); + const unfeaturedBody = await unfeaturedResponse!.json() as { available: string[] }; + expect(unfeaturedBody.available).not.toContain("deepseek-v4-flash"); + } finally { + processProbe.mockRestore(); + } }, 15_000); test("GET models round-trips a disabled combo alias for the Models GUI", async () => { From ceca43d804a4bf6befcc0f24860767e48f3d71fd Mon Sep 17 00:00:00 2001 From: DaedalGames Date: Mon, 7 Sep 2026 13:45:29 +0900 Subject: [PATCH 060/412] docs(pr): replace component preview with dashboard registration evidence --- .github/pr-assets/codex-quota-evidence.md | 35 ++++++++++++++++++++ .github/pr-assets/codex-quota-pending.png | Bin 0 -> 227826 bytes .github/pr-assets/codex-quota-recovered.png | Bin 0 -> 220466 bytes 3 files changed, 35 insertions(+) create mode 100644 .github/pr-assets/codex-quota-evidence.md create mode 100644 .github/pr-assets/codex-quota-pending.png create mode 100644 .github/pr-assets/codex-quota-recovered.png diff --git a/.github/pr-assets/codex-quota-evidence.md b/.github/pr-assets/codex-quota-evidence.md new file mode 100644 index 0000000000..429d3118ce --- /dev/null +++ b/.github/pr-assets/codex-quota-evidence.md @@ -0,0 +1,35 @@ +# Codex quota registration browser verification + +These captures show the production dashboard bundle served by `startServer`, +using the real management routes, device-login implementation, credential store, +account-pool controller, and refresh button. They are not component fixtures. + +The server used an isolated OpenCodex/Codex home. Only external provider responses +were mocked: device authorization, token exchange, WHAM usage, and the completed +inference stream. The account identity and credentials are synthetic. The empty +native-main home explains the separate Main Account warning in both screenshots. +No live OpenAI account was used or charged. + +The browser was Microsoft Edge through Playwright, at 1440 × 1100, English/light +theme, with external browser requests blocked. Verification ran on Windows. + +1. Open Codex Set → Multi-auth, click Add, enter an account ID, and choose Device + code login. Authorize through the mock device service. +2. The actual token exchange and authenticated usage read return a Pro account + with weekly usage at 100%. Registration persists it as validation pending: + one usage read, zero model calls, and no successful-validation timestamp. +3. Reload the page and click Refresh quotas while usage is still 100%. + The account remains pending. Cumulative counts: two usage reads, zero model + calls. The pending screenshot shows the status and the missing selection button. +4. Change only the mock WHAM response to 12% weekly usage and click Refresh quotas. + The server receives a completed validation response. Cumulative counts: + three usage reads, one model call. The pending flag clears, the validation + timestamp is persisted, and “Use this account next” appears. + +| Capture | Weekly usage | Pending | Model calls so far | +| --- | --- | --- | --- | +| `codex-quota-pending.png` | 100% | Yes | 0 | +| `codex-quota-recovered.png` | 12% | No | 1 | + +This verifies dashboard-to-server behavior against controlled upstream responses. +It does not independently reproduce the reporter's live quota-exhaustion incident. diff --git a/.github/pr-assets/codex-quota-pending.png b/.github/pr-assets/codex-quota-pending.png new file mode 100644 index 0000000000000000000000000000000000000000..45092ef8cea59621dd4ea9f9a808550db7239289 GIT binary patch literal 227826 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˙ICx6sUxBH$yMO@i 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 literal 0 HcmV?d00001 diff --git a/.github/pr-assets/codex-quota-recovered.png b/.github/pr-assets/codex-quota-recovered.png new file mode 100644 index 0000000000000000000000000000000000000000..d4ef7ff398da4ec210ecb8d9699454f4461aabd5 GIT binary patch literal 220466 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

??fALjqki*?OD`l}njx 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 XAp_YZiBpSfwC+RGZNP! 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

lXIH&{7`sErpfq2 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 z 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 Date: Mon, 7 Sep 2026 13:56:40 +0900 Subject: [PATCH 061/412] fix(codex): require a CSRF-protected POST for deferred validation --- gui/src/hooks/useCodexAccountPool.ts | 5 ++- .../provider-revalidation-policy.test.tsx | 11 +++--- src/codex/auth-api.ts | 10 ++++-- src/server/management/route-registry.ts | 1 + .../codex-integration/codex-auth-api.test.ts | 5 ++- tests/server/server-management-auth.test.ts | 36 +++++++++++++++++++ 6 files changed, 59 insertions(+), 9 deletions(-) diff --git a/gui/src/hooks/useCodexAccountPool.ts b/gui/src/hooks/useCodexAccountPool.ts index 0cd82d7293..f33b7080b6 100644 --- a/gui/src/hooks/useCodexAccountPool.ts +++ b/gui/src/hooks/useCodexAccountPool.ts @@ -237,7 +237,10 @@ export function useCodexAccountPool(apiBase: string, enabled = true): CodexAccou const accountsTask = (async (): Promise => { try { - const response = await fetch(`${apiBase}/api/codex-auth/accounts${refreshQuota ? "?refresh=1" : ""}`, { signal: bounded.signal }); + const response = await fetch(`${apiBase}/api/codex-auth/accounts${refreshQuota ? "/refresh" : ""}`, { + method: refreshQuota ? "POST" : "GET", + signal: bounded.signal, + }); if (!response.ok) throw new Error("account load failed"); const payload = await response.json(); if (loadGenerationRef.current === generation) { diff --git a/gui/tests/provider-revalidation-policy.test.tsx b/gui/tests/provider-revalidation-policy.test.tsx index e6be1936e1..1e19b634e7 100644 --- a/gui/tests/provider-revalidation-policy.test.tsx +++ b/gui/tests/provider-revalidation-policy.test.tsx @@ -162,6 +162,7 @@ for (const kind of ["oauth", "key", "codex"] as const) { test(`the real Providers page refresh selects ${kind} and awaits account plus report`, async () => { const name = kind === "codex" ? "openai" : `${kind}-fixture`; const seen: string[] = []; + const methods = new Map(); let finishReport!: (response: Response) => void; let finishAccounts!: (response: Response) => void; let reportStarted!: () => void; @@ -171,9 +172,10 @@ for (const kind of ["oauth", "key", "codex"] as const) { : kind === "oauth" ? { activeAccountId: "account", accounts: [{ id: "account", active: true, quotaMode: "probe" }] } : { keys: [{ id: "key", masked: "masked", active: true, quotaMode: "probe" }] }; - Object.defineProperty(globalThis, "fetch", { configurable: true, value: async (input: RequestInfo | URL) => { + Object.defineProperty(globalThis, "fetch", { configurable: true, value: async (input: RequestInfo | URL, init?: RequestInit) => { const url = new URL(String(input), "http://localhost"); seen.push(url.pathname + url.search); + methods.set(url.pathname + url.search, init?.method ?? "GET"); if (url.pathname === "/api/config") return Response.json({ port: 10100, defaultProvider: name, providers: { [name]: kind === "codex" ? { adapter: "openai-responses", authMode: "forward", codexAccountMode: "pool", baseUrl: "https://chatgpt.com/backend-api/codex" } @@ -188,8 +190,8 @@ for (const kind of ["oauth", "key", "codex"] as const) { return result; } if (url.pathname === "/api/oauth/accounts" || url.pathname === "/api/providers/keys" - || (kind === "codex" && url.pathname === "/api/codex-auth/accounts")) { - return url.searchParams.has("refresh") + || (kind === "codex" && (url.pathname === "/api/codex-auth/accounts" || url.pathname === "/api/codex-auth/accounts/refresh"))) { + return url.searchParams.has("refresh") || url.pathname.endsWith("/accounts/refresh") ? new Promise(resolve => { finishAccounts = resolve; }) : Response.json(accountBody); } if (url.pathname === "/api/codex-auth/accounts") return Response.json({ accounts: [] }); @@ -209,10 +211,11 @@ for (const kind of ["oauth", "key", "codex"] as const) { seen.length = 0; await act(async () => { refresh!.click(); }); await act(async () => { await reportReady; }); - const expected = kind === "codex" ? "/api/codex-auth/accounts?refresh=1" + const expected = kind === "codex" ? "/api/codex-auth/accounts/refresh" : kind === "oauth" ? `/api/oauth/accounts?provider=${name}"a=1&refresh=1` : `/api/providers/keys?name=${name}"a=1&refresh=1`; expect(seen).toContain(expected); + expect(methods.get(expected)).toBe(kind === "codex" ? "POST" : "GET"); if (kind !== "oauth") expect(seen.some(path => path.startsWith("/api/oauth/accounts"))).toBe(false); if (kind === "oauth") expect(seen.some(path => path.startsWith("/api/providers/keys"))).toBe(false); expect(container.textContent).toContain("Refreshing..."); diff --git a/src/codex/auth-api.ts b/src/codex/auth-api.ts index 0586c28b68..a446a1da6a 100644 --- a/src/codex/auth-api.ts +++ b/src/codex/auth-api.ts @@ -1984,9 +1984,13 @@ export async function handleCodexAuthAPI( if (url.pathname === "/api/codex-auth/accounts" && req.method === "GET") { const forceRefresh = url.searchParams.get("refresh") === "1" || url.searchParams.get("refresh") === "true"; - // Background report/reset pollers also bypass caches; only this explicit - // accounts refresh opts into inference-backed validation of pending accounts. - return jsonResponse({ accounts: await listCodexAuthAccounts(config, forceRefresh, { validatePending: forceRefresh }) }); + return jsonResponse({ accounts: await listCodexAuthAccounts(config, forceRefresh) }); + } + + if (url.pathname === "/api/codex-auth/accounts/refresh" && req.method === "POST") { + // Completing validation spends inference and changes durable readiness, so it + // must pass the management mutation/CSRF boundary rather than a read-only GET. + return jsonResponse({ accounts: await listCodexAuthAccounts(config, true, { validatePending: true }) }); } if (url.pathname === "/api/codex-auth/accounts" && req.method === "POST") { diff --git a/src/server/management/route-registry.ts b/src/server/management/route-registry.ts index 421ead31e0..f20ae46d20 100644 --- a/src/server/management/route-registry.ts +++ b/src/server/management/route-registry.ts @@ -95,6 +95,7 @@ export const MANAGEMENT_ROUTES: readonly ManagementRoute[] = [ { method: "PATCH", path: "/api/codex-auth/pool-strategy", module: "codex/auth-api", mutates: true }, { method: "POST", path: "/api/codex-auth/accounts", module: "codex/auth-api", mutates: true }, { method: "POST", path: "/api/codex-auth/accounts/clear-cooldown", module: "codex/auth-api", mutates: true }, + { method: "POST", path: "/api/codex-auth/accounts/refresh", module: "codex/auth-api", mutates: true }, { method: "POST", path: "/api/codex-auth/login", module: "codex/auth-api", mutates: true }, { method: "POST", path: "/api/codex-auth/login/cancel", module: "codex/auth-api", mutates: true }, { method: "POST", path: "/api/codex-auth/login/code", module: "codex/auth-api", mutates: true }, diff --git a/tests/codex-integration/codex-auth-api.test.ts b/tests/codex-integration/codex-auth-api.test.ts index 57c2c9b4d8..c34a6f2a27 100644 --- a/tests/codex-integration/codex-auth-api.test.ts +++ b/tests/codex-integration/codex-auth-api.test.ts @@ -5000,7 +5000,7 @@ describe("codex-auth API", () => { let warmups = 0; let replaceDuringWarmup = false; const refreshAccounts = async () => { - const req = new Request("http://localhost/api/codex-auth/accounts?refresh=1"); + const req = new Request("http://localhost/api/codex-auth/accounts/refresh", { method: "POST" }); const response = await handleCodexAuthAPI(req, new URL(req.url), config); expect(response?.status).toBe(200); }; @@ -5047,6 +5047,9 @@ describe("codex-auth API", () => { expect(warmups).toBe(0); // Passive reads never spend inference. await listCodexAuthAccounts(config, true); expect(warmups).toBe(0); // Forced background reads are not manual validation. + const readReq = new Request("http://localhost/api/codex-auth/accounts?refresh=1"); + expect((await handleCodexAuthAPI(readReq, new URL(readReq.url), config))?.status).toBe(200); + expect(warmups).toBe(0); // A read-only management capability cannot validate either. expect(isCodexAccountUsable(config, accountId)).toBe(false); await refreshAccounts(); expect(warmups).toBe(1); diff --git a/tests/server/server-management-auth.test.ts b/tests/server/server-management-auth.test.ts index 340ad70bd3..86cf843c6e 100644 --- a/tests/server/server-management-auth.test.ts +++ b/tests/server/server-management-auth.test.ts @@ -958,6 +958,42 @@ describe("management and data-plane credential separation", () => { } }); + test("deferred Codex validation requires a same-origin mutation session with CSRF", async () => { + const config = remoteConfig(); + config.hostname = "127.0.0.1"; + saveConfig(config); + const server = startServer(0); + try { + const bootstrap = await fetch(new URL("/opencodex-session", server.url)); + const html = await bootstrap.text(); + const token = html.match(/name="opencodex-session-token" content="([^"]+)"/)?.[1]; + const csrf = html.match(/name="opencodex-session-csrf" content="([^"]+)"/)?.[1]; + expect(token).toBeDefined(); + expect(csrf).toBeDefined(); + const headers = { + Origin: server.url.origin, + "x-opencodex-api-key": token!, + "x-opencodex-gui-origin": server.url.origin, + }; + const url = new URL("/api/codex-auth/accounts/refresh", server.url); + const missing = await fetch(url, { method: "POST", headers }); + expect(missing.status).toBe(401); + const crossOrigin = await fetch(url, { + method: "POST", + headers: { ...headers, Origin: "http://attacker.test", "x-opencodex-csrf-token": csrf! }, + }); + expect(crossOrigin.status).toBe(401); + const allowed = await fetch(url, { + method: "POST", + headers: { ...headers, "x-opencodex-csrf-token": csrf! }, + }); + expect(allowed.status).toBe(200); + expect(await allowed.json()).toHaveProperty("accounts"); + } finally { + await server.stop(true); + } + }); + test("session bootstrap escapes both browser and server origin attributes", async () => { const response = serveSessionBootstrap({ token: "ocx_session_safe", From 094d253b1c6dc8436688bb093d83d2f439130ef8 Mon Sep 17 00:00:00 2001 From: DaedalGames Date: Mon, 7 Sep 2026 14:12:33 +0900 Subject: [PATCH 062/412] fix(codex): support explicit CLI recovery and await validation in the GUI --- .../docs/fr/guides/codex-integration.md | 2 ++ .../content/docs/guides/codex-integration.md | 2 ++ .../docs/ja/guides/codex-integration.md | 2 ++ .../docs/ko/guides/codex-integration.md | 2 ++ .../docs/ru/guides/codex-integration.md | 2 ++ .../docs/tr/guides/codex-integration.md | 2 ++ .../docs/zh-cn/guides/codex-integration.md | 2 ++ .../docs/zh-tw/guides/codex-integration.md | 2 ++ gui/src/components/CodexAccountPool.tsx | 2 +- gui/src/hooks/useCodexAccountPool.ts | 30 ++++++++++++++----- gui/src/pages/Providers.tsx | 2 +- .../codex-account-pool-behaviour.test.tsx | 29 ++++++++++++++++++ .../codex-account-pool-controller.test.ts | 2 +- src/cli/account-api.ts | 6 ++-- src/cli/account-extended.ts | 2 +- src/cli/capabilities.ts | 12 ++++++++ tests/cli/cli-account.test.ts | 9 +++--- tests/cli/cli-capabilities.test.ts | 1 - 18 files changed, 92 insertions(+), 19 deletions(-) diff --git a/docs-site/src/content/docs/fr/guides/codex-integration.md b/docs-site/src/content/docs/fr/guides/codex-integration.md index 3132e16fc8..22c7c65796 100644 --- a/docs-site/src/content/docs/fr/guides/codex-integration.md +++ b/docs-site/src/content/docs/fr/guides/codex-integration.md @@ -371,6 +371,8 @@ L’ajout ou la réauthentification vérifie normalement le compte avant son enr Si la lecture authentifiée des quotas avec le nouveau jeton OAuth confirme un quota de 5 heures, hebdomadaire ou mensuel épuisé, le compte est enregistré sans appel au modèle et affiche **Validation en attente**. Il reste exclu du routage après un redémarrage ou un renouvellement du jeton. Après récupération du quota, actualisez les quotas : une lecture récente et complète avec de la capacité disponible permet une petite requête de validation. Seule sa réussite active le compte. Tout échec conserve la restriction. Les lectures passives ne déclenchent pas cette requête. Un quota inconnu à l’inscription conserve la vérification habituelle. +Sans tableau de bord, `ocx account refresh openai` effectue la même validation. `ocx account list openai --quota --refresh` consulte uniquement les quotas et ne valide pas les comptes en attente. + La revalidation en arrière-plan est distincte et désactivée par défaut. Elle nécessite Token Guardian, la politique `proactive` du fournisseur `openai` et `tokenGuardian.codexWarmupEnabled`, et ignore les comptes dont la validation d’inscription est en attente. ## Restauration de Codex natif diff --git a/docs-site/src/content/docs/guides/codex-integration.md b/docs-site/src/content/docs/guides/codex-integration.md index c709cd2ce1..1caaf34c9b 100644 --- a/docs-site/src/content/docs/guides/codex-integration.md +++ b/docs-site/src/content/docs/guides/codex-integration.md @@ -551,6 +551,8 @@ When a ChatGPT account is added or reauthenticated, OpenCodex normally verifies If the new OAuth credential's authenticated usage lookup confirms an exhausted 5-hour, weekly, or monthly quota, the account is saved without this model request and shows **Validation pending**. It cannot serve pool requests, even after a restart or token refresh. Once quota recovers, **Refresh quotas** finishes validation: a fresh, complete usage reading with headroom permits one small model request, and only a completed response enables the account. Failed or incomplete readings and failed validation preserve the restriction. Passive account polling does not trigger deferred validation. Unknown usage during initial registration retains the normal warmup gate. +On a headless installation, `ocx account refresh openai` performs the same validation. `ocx account list openai --quota --refresh` only reads usage and does not validate pending accounts. + Background revalidation is separate and off by default. It requires Token Guardian, the `openai` provider's `proactive` refresh policy, and `tokenGuardian.codexWarmupEnabled`. It skips accounts awaiting deferred registration validation. ## Restoring native Codex diff --git a/docs-site/src/content/docs/ja/guides/codex-integration.md b/docs-site/src/content/docs/ja/guides/codex-integration.md index 773ad97e99..132b3bc1ea 100644 --- a/docs-site/src/content/docs/ja/guides/codex-integration.md +++ b/docs-site/src/content/docs/ja/guides/codex-integration.md @@ -237,6 +237,8 @@ ocx service install # persistent: auto-starts on login and respawns on crash 新しい OAuth トークンによる使用量取得で5時間・週次・月次の上限到達が確認された場合、モデルを呼ばずに保存し、**検証待ち**と表示します。再起動やトークン更新後も使用できません。上限回復後に使用量を更新すると、十分な空き容量を示す完全な最新情報を確認してから小さなモデルリクエストを送り、完了した場合のみ使用可能になります。取得や検証の失敗では待機状態を維持します。通常の状態ポーリングは検証リクエストを送りません。初回登録時の使用量が不明な場合は通常の検証が必要です。 +ダッシュボードを使わずに `ocx account refresh openai` で同じ検証を実行できます。`ocx account list openai --quota --refresh` は使用量のみを取得し、待機中のアカウントを検証しません。 + バックグラウンド再検証は別機能で既定では無効です。Token Guardian、`openai` の `proactive` 更新ポリシー、`tokenGuardian.codexWarmupEnabled` が必要で、登録検証待ちのアカウントは除外します。 ## ネイティブ Codexの復元 diff --git a/docs-site/src/content/docs/ko/guides/codex-integration.md b/docs-site/src/content/docs/ko/guides/codex-integration.md index f8accd51b6..95cba39d1c 100644 --- a/docs-site/src/content/docs/ko/guides/codex-integration.md +++ b/docs-site/src/content/docs/ko/guides/codex-integration.md @@ -234,6 +234,8 @@ ChatGPT 계정을 추가하거나 재인증할 때 OpenCodex는 일반적으로 새 OAuth 토큰으로 인증된 사용량 조회에서 5시간·주간·월간 한도 소진이 확인되면 모델 요청 없이 계정을 저장하고 **검증 대기**로 표시합니다. 재시작이나 토큰 갱신 후에도 요청에 사용되지 않습니다. 한도 회복 후 **사용량 새로고침**을 실행하면, 여유가 있는 완전한 최신 사용량을 확인한 뒤 작은 모델 요청을 보내고 완료 응답을 받아야 계정을 사용할 수 있습니다. 조회나 검증 실패 시 대기 상태를 유지합니다. 일반적인 화면 상태 조회는 이 모델 요청을 보내지 않습니다. 최초 등록 때 사용량이 불명확하면 기존 워밍업 검증이 필요합니다. +대시보드 없이도 `ocx account refresh openai`로 같은 검증을 실행할 수 있습니다. `ocx account list openai --quota --refresh`는 사용량만 조회하며 대기 계정을 검증하지 않습니다. + 별도의 백그라운드 재검증은 기본적으로 꺼져 있습니다. Token Guardian, `openai`의 `proactive` 갱신 정책, `tokenGuardian.codexWarmupEnabled`가 필요하며 등록 검증 대기 계정은 제외합니다. ## 네이티브 Codex 복원 diff --git a/docs-site/src/content/docs/ru/guides/codex-integration.md b/docs-site/src/content/docs/ru/guides/codex-integration.md index b3311ea02a..7929c561bc 100644 --- a/docs-site/src/content/docs/ru/guides/codex-integration.md +++ b/docs-site/src/content/docs/ru/guides/codex-integration.md @@ -364,6 +364,8 @@ v1/base/v2 при делегировании и fallback — в Если запрос квоты с новым OAuth-токеном подтверждает исчерпание пятичасовой, недельной или месячной квоты, аккаунт сохраняется без вызова модели со статусом **Ожидает проверки**. Перезапуск и обновление токена не включают маршрутизацию. После восстановления квоты обновите её: полные свежие данные с доступной ёмкостью разрешают небольшой проверочный запрос. Только успешное завершение включает аккаунт. Ошибки сохраняют ограничение. Пассивный опрос не отправляет такой запрос. Неизвестная квота при регистрации требует обычной проверки. +Без панели управления ту же проверку выполняет `ocx account refresh openai`. Команда `ocx account list openai --quota --refresh` только читает квоты и не проверяет ожидающие аккаунты. + Фоновая проверка — отдельная функция, выключенная по умолчанию. Она требует Token Guardian, политики `proactive` провайдера `openai` и `tokenGuardian.codexWarmupEnabled` и пропускает аккаунты, ожидающие проверки регистрации. ## Восстановление нативного Codex diff --git a/docs-site/src/content/docs/tr/guides/codex-integration.md b/docs-site/src/content/docs/tr/guides/codex-integration.md index abf78a1de2..92447b8141 100644 --- a/docs-site/src/content/docs/tr/guides/codex-integration.md +++ b/docs-site/src/content/docs/tr/guides/codex-integration.md @@ -421,6 +421,8 @@ Hesap ekleme veya yeniden kimlik doğrulama, normalde kaydetmeden önce `respons Yeni OAuth belirteciyle yapılan kota sorgusu 5 saatlik, haftalık veya aylık kotanın tükendiğini doğrularsa hesap model çağrısı olmadan kaydedilir ve **Doğrulama bekleniyor** gösterilir. Yeniden başlatma veya belirteç yenileme yönlendirmeyi açmaz. Kota geri geldiğinde kotaları yenileyin: kullanılabilir kapasite gösteren eksiksiz güncel veri küçük bir doğrulama isteğine izin verir. Yalnızca tamamlanan yanıt hesabı etkinleştirir. Hatalarda kısıtlama korunur. Pasif sorgulama bu isteği göndermez. İlk kayıtta bilinmeyen kota normal doğrulamayı gerektirir. +Pano olmadan `ocx account refresh openai` aynı doğrulamayı gerçekleştirir. `ocx account list openai --quota --refresh` yalnızca kullanımı okur ve bekleyen hesapları doğrulamaz. + Arka plan doğrulaması ayrı ve varsayılan olarak kapalıdır. Token Guardian, `openai` için `proactive` yenileme ilkesi ve `tokenGuardian.codexWarmupEnabled` gerektirir; kayıt doğrulaması bekleyen hesapları atlar. ## Yerel Codex'i geri yükleme diff --git a/docs-site/src/content/docs/zh-cn/guides/codex-integration.md b/docs-site/src/content/docs/zh-cn/guides/codex-integration.md index 2b0868e513..08260a8410 100644 --- a/docs-site/src/content/docs/zh-cn/guides/codex-integration.md +++ b/docs-site/src/content/docs/zh-cn/guides/codex-integration.md @@ -310,6 +310,8 @@ fallback 行为,参见 [Sub-agent Surface](/guides/sub-agent-surface/)。 如果新 OAuth 凭据的已认证用量查询确认5小时、每周或每月额度耗尽,则不调用模型而直接保存账号,显示**等待验证**。重启或刷新令牌也不会使其可用。额度恢复后刷新额度:只有完整的最新用量显示有余额,才会发送一个小型验证请求;请求完成后账号才可用于路由。查询或验证失败将保留等待状态。普通状态轮询不会发送该请求。初次注册时用量未知仍需常规预热验证。 +无界面环境可运行 `ocx account refresh openai` 执行相同验证。`ocx account list openai --quota --refresh` 仅查询用量,不验证等待中的账号。 + 后台重新验证是独立功能,默认关闭。它要求 Token Guardian、`openai` 的 `proactive` 刷新策略及 `tokenGuardian.codexWarmupEnabled`,并跳过等待注册验证的账号。 ## 恢复原生 Codex diff --git a/docs-site/src/content/docs/zh-tw/guides/codex-integration.md b/docs-site/src/content/docs/zh-tw/guides/codex-integration.md index f3295565b4..3eeedbacf5 100644 --- a/docs-site/src/content/docs/zh-tw/guides/codex-integration.md +++ b/docs-site/src/content/docs/zh-tw/guides/codex-integration.md @@ -317,6 +317,8 @@ ocx service install # 常駐:登入時自動啟動,崩潰後自動重新 若新 OAuth 憑證的已驗證用量查詢確認5小時、每週或每月額度耗盡,則不呼叫模型而直接儲存帳號,顯示**等待驗證**。重新啟動或更新權杖也不會使其可用。額度恢復後重新整理額度:只有完整的最新用量顯示有餘額,才會傳送小型驗證請求;請求完成後帳號才可用於路由。查詢或驗證失敗將保留等待狀態。一般狀態輪詢不會傳送該請求。首次註冊時用量未知仍需一般預熱驗證。 +無介面環境可執行 `ocx account refresh openai` 進行相同驗證。`ocx account list openai --quota --refresh` 僅查詢用量,不驗證等待中的帳號。 + 背景重新驗證是獨立功能,預設關閉。它需要 Token Guardian、`openai` 的 `proactive` 更新政策及 `tokenGuardian.codexWarmupEnabled`,並略過等待註冊驗證的帳號。 ## 恢復原生 Codex diff --git a/gui/src/components/CodexAccountPool.tsx b/gui/src/components/CodexAccountPool.tsx index c01bd8b9d2..03a486f765 100644 --- a/gui/src/components/CodexAccountPool.tsx +++ b/gui/src/components/CodexAccountPool.tsx @@ -274,7 +274,7 @@ export default function CodexAccountPool({ apiBase, accountModeState = null, ban const refreshQuotas = async () => { setRefreshingQuota(true); try { - const ok = await load(true); + const ok = await load(true, { validatePending: true }); showActionFeedback(t(ok ? "codexAuth.quotaRefreshed" : "codexAuth.quotaRefreshFailed"), ok ? "ok" : "err"); } finally { setRefreshingQuota(false); diff --git a/gui/src/hooks/useCodexAccountPool.ts b/gui/src/hooks/useCodexAccountPool.ts index f33b7080b6..2d909b29bd 100644 --- a/gui/src/hooks/useCodexAccountPool.ts +++ b/gui/src/hooks/useCodexAccountPool.ts @@ -109,7 +109,7 @@ export interface CodexAccountPoolController { */ activePinnedId: string | null; - load(refreshQuota?: boolean): Promise; + load(refreshQuota?: boolean, options?: { validatePending?: boolean }): Promise; switchAccount(id: string | null): Promise>; setAccountPaused(id: string, paused: boolean): Promise; /** `null` resets the account to the default order. Accepts the `__main__` sentinel. */ @@ -217,10 +217,20 @@ export function useCodexAccountPool(apiBase: string, enabled = true): CodexAccou /** Full last /active payload, or undefined when none has succeeded yet. */ const readLastActive = useCallback(() => lastActiveRef.current?.value, []); - const load = useCallback(async (refreshQuota = false): Promise => { + const load = useCallback(async (refreshQuota = false, options: { validatePending?: boolean } = {}): Promise => { const generation = ++loadGenerationRef.current; - // Bounded per attempt: a hung accounts/active read must settle, not pin the poll. - const bounded = createBoundedFetch(20_000); + const validatePending = options.validatePending === true; + // Validation can include token recovery, WHAM and two 30s model attempts. + // Budget per known row (conservatively ignoring server parallelism), plus + // native-main lookup time. Ordinary reads retain their short polling deadline. + const knownAccounts = lastGoodByBase.get(apiBase)?.accounts.length ?? 0; + const bounded = createBoundedFetch(validatePending ? 30_000 + 120_000 * Math.max(1, knownAccounts) : 20_000); + // A periodic read must not supersede this longer-running explicit operation. + const validationLease = validatePending ? {} as PauseToken : null; + if (validationLease) { + pauseTokensRef.current!.add(validationLease); + setPauseCount(pauseTokensRef.current!.size); + } setInflightCount(count => count + 1); // The try opens immediately after the increment so even a synchronous throw in the // observer snapshot below cannot leave the counter stuck above zero. @@ -237,8 +247,8 @@ export function useCodexAccountPool(apiBase: string, enabled = true): CodexAccou const accountsTask = (async (): Promise => { try { - const response = await fetch(`${apiBase}/api/codex-auth/accounts${refreshQuota ? "/refresh" : ""}`, { - method: refreshQuota ? "POST" : "GET", + const response = await fetch(`${apiBase}/api/codex-auth/accounts${validatePending ? "/refresh" : refreshQuota ? "?refresh=1" : ""}`, { + method: validatePending ? "POST" : "GET", signal: bounded.signal, }); if (!response.ok) throw new Error("account load failed"); @@ -321,6 +331,10 @@ export function useCodexAccountPool(apiBase: string, enabled = true): CodexAccou return false; } finally { bounded.clear(); + if (validationLease) { + pauseTokensRef.current!.delete(validationLease); + setPauseCount(pauseTokensRef.current!.size); + } setInflightCount(count => Math.max(0, count - 1)); setFirstAttemptSettled(true); } @@ -357,7 +371,7 @@ export function useCodexAccountPool(apiBase: string, enabled = true): CodexAccou useEffect(() => { if (!enabled || !needsQuotaFill || pauseCount > 0) return; const timers = [350, 900, 2000].map((delayMs) => ( - window.setTimeout(() => { void load(false); }, delayMs) + window.setTimeout(() => { if (pauseTokensRef.current!.size === 0) void load(false); }, delayMs) )); return () => { for (const timer of timers) window.clearTimeout(timer); @@ -368,7 +382,7 @@ export function useCodexAccountPool(apiBase: string, enabled = true): CodexAccou // (no timer, no traffic) while the tab is hidden. useEffect(() => { if (!enabled || pauseCount > 0) return; - return startVisibilityPoll(() => { void load(); }, REFRESH_INTERVAL_MS); + return startVisibilityPoll(() => { if (pauseTokensRef.current!.size === 0) void load(); }, REFRESH_INTERVAL_MS); }, [enabled, load, pauseCount]); const pauseRefresh = useCallback((): PauseToken => { diff --git a/gui/src/pages/Providers.tsx b/gui/src/pages/Providers.tsx index 78b2096d95..41795a6098 100644 --- a/gui/src/pages/Providers.tsx +++ b/gui/src/pages/Providers.tsx @@ -418,7 +418,7 @@ export default function Providers({ apiBase }: { apiBase: string }) { const configured = config?.providers[provider]; const mode = configured?.authMode; const readAccounts = configured && isAccountProvider(provider, configured) - ? () => codexPool.load(true) + ? () => codexPool.load(true, { validatePending: true }) : mode === "oauth" ? () => fetchAccountSets([provider], true) : mode === "forward" || mode === "local" diff --git a/gui/tests/codex-account-pool-behaviour.test.tsx b/gui/tests/codex-account-pool-behaviour.test.tsx index 2d8e42037a..42cec3818c 100644 --- a/gui/tests/codex-account-pool-behaviour.test.tsx +++ b/gui/tests/codex-account-pool-behaviour.test.tsx @@ -218,6 +218,35 @@ test("the controller loads once on mount", async () => { expect(seen.current!.loadState).toBe("ready"); }); +test("forced quota reads remain GET unless deferred validation is explicitly requested", async () => { + const seen = await mountController(); + const originalTimeout = AbortSignal.timeout; + const deadlines: number[] = []; + AbortSignal.timeout = (ms: number) => { + deadlines.push(ms); + return new AbortController().signal; + }; + try { + calls = []; + await act(async () => { await seen.current!.load(true); }); + expect(calls).toContain("GET codex-auth/accounts?refresh=1"); + expect(calls.some(call => call.startsWith("POST codex-auth/accounts"))).toBe(false); + expect(deadlines.at(-1)).toBe(20_000); + calls = []; + let finishValidation!: () => void; + nextAccountsResponseGate = new Promise(resolve => { finishValidation = resolve; }); + let validation!: Promise; + await act(async () => { validation = seen.current!.load(true, { validatePending: true }); }); + expect(calls).toContain("POST codex-auth/accounts/refresh"); + expect(deadlines.at(-1)).toBeGreaterThan(8_000 + 2 * 30_000); + await act(async () => { await new Promise(resolve => setTimeout(resolve, 400)); }); + expect(calls.filter(call => call.includes("codex-auth/accounts"))).toEqual(["POST codex-auth/accounts/refresh"]); + await act(async () => { finishValidation(); expect(await validation).toBe(true); }); + } finally { + AbortSignal.timeout = originalTimeout; + } +}); + test("the controller joins 30-day usage to accounts by the displayed log label", async () => { accounts = [ { id: "main", email: "main", isMain: true, paused: false, priority: 0, hasCredential: true, quota: null }, diff --git a/gui/tests/codex-account-pool-controller.test.ts b/gui/tests/codex-account-pool-controller.test.ts index a701905c09..044b8156a0 100644 --- a/gui/tests/codex-account-pool-controller.test.ts +++ b/gui/tests/codex-account-pool-controller.test.ts @@ -32,7 +32,7 @@ test("the controller is the single data owner and exposes the agreed contract", // Observers arrive through one subscription path; load() takes no observer argument. expect(hook).toContain("subscribeLoadObserver"); - expect(hook).toContain("load(refreshQuota?: boolean): Promise"); + expect(hook).toContain("load(refreshQuota?: boolean, options?: { validatePending?: boolean }): Promise"); expect(hook).not.toContain("load(refreshQuota?: boolean, observer"); }); diff --git a/src/cli/account-api.ts b/src/cli/account-api.ts index 76c3456c9c..c1c625c882 100644 --- a/src/cli/account-api.ts +++ b/src/cli/account-api.ts @@ -263,10 +263,12 @@ export async function fetchCodexRows( baseUrl: string, forceRefresh = false, includeQuota = forceRefresh, + options: { validatePending?: boolean } = {}, ): Promise { - const accountsPath = `/api/codex-auth/accounts${forceRefresh ? "?refresh=1" : ""}`; + const validatePending = options.validatePending === true; + const accountsPath = `/api/codex-auth/accounts${validatePending ? "/refresh" : forceRefresh ? "?refresh=1" : ""}`; const [accountsRes, activeRes] = await Promise.all([ - apiJson(deps, baseUrl, "GET", accountsPath), + apiJson(deps, baseUrl, validatePending ? "POST" : "GET", accountsPath), apiJson(deps, baseUrl, "GET", "/api/codex-auth/active"), ]); if (accountsRes.status !== 0 && accountsRes.status !== 200) { diff --git a/src/cli/account-extended.ts b/src/cli/account-extended.ts index 38179aca42..f2a477a702 100644 --- a/src/cli/account-extended.ts +++ b/src/cli/account-extended.ts @@ -339,7 +339,7 @@ export async function cmdRefresh(args: string[], deps: AccountDeps): Promise { const url = new URL(req.url); - const body = req.method === "PUT" || req.method === "POST" ? await req.json() : undefined; + const body = req.method === "PUT" || req.method === "POST" ? await req.json().catch(() => undefined) : undefined; requests.push({ method: req.method, path: url.pathname, search: url.search, body }); - if (req.method === "GET" && url.pathname === "/api/codex-auth/accounts") { - if (url.searchParams.get("refresh") === "1" && codexRefreshFailure) { + if ((req.method === "GET" && url.pathname === "/api/codex-auth/accounts") + || (req.method === "POST" && url.pathname === "/api/codex-auth/accounts/refresh")) { + if ((url.searchParams.get("refresh") === "1" || req.method === "POST") && codexRefreshFailure) { return json({ error: codexRefreshFailure.error }, codexRefreshFailure.status); } if (lastDeletedType === "codex" && postDeleteReadFailure) { @@ -907,7 +908,7 @@ describe("ocx account CLI (issue #180 matrix)", () => { expect(human.code).toBe(0); expect(requests.some(request => - request.path === "/api/codex-auth/accounts" && request.search === "?refresh=1" + request.path === "/api/codex-auth/accounts/refresh" && request.method === "POST" )).toBe(true); expect(human.stdout).toContain("weekly 42%"); expect(human.stdout).toContain("monthly 17%"); diff --git a/tests/cli/cli-capabilities.test.ts b/tests/cli/cli-capabilities.test.ts index f8c7b26d04..9a3191804a 100644 --- a/tests/cli/cli-capabilities.test.ts +++ b/tests/cli/cli-capabilities.test.ts @@ -240,7 +240,6 @@ const UNDECLARED_ROUTES_2026_08_28: readonly string[] = [ "GET /api/oauth/status", "GET /api/provider-context-caps", "GET /api/provider-presets", - "GET /api/provider-quotas", "GET /api/providers", "GET /api/providers/keys", "GET /api/request-history", From a1ec6b3ff1c0554f918b99458d8bff6f964f06e0 Mon Sep 17 00:00:00 2001 From: DaedalGames Date: Mon, 7 Sep 2026 14:19:21 +0900 Subject: [PATCH 063/412] docs(codex): publish CLI recovery reference and final dashboard evidence --- .github/pr-assets/codex-quota-evidence.md | 8 +++++++ .github/pr-assets/codex-quota-pending.png | Bin 227826 -> 230070 bytes .github/pr-assets/codex-quota-recovered.png | Bin 220466 -> 218961 bytes .../ocx/references/01_management_surface.md | 21 ++++++++++++++++-- 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/.github/pr-assets/codex-quota-evidence.md b/.github/pr-assets/codex-quota-evidence.md index 429d3118ce..ef24fec548 100644 --- a/.github/pr-assets/codex-quota-evidence.md +++ b/.github/pr-assets/codex-quota-evidence.md @@ -12,6 +12,7 @@ No live OpenAI account was used or charged. The browser was Microsoft Edge through Playwright, at 1440 × 1100, English/light theme, with external browser requests blocked. Verification ran on Windows. +The final capture used runtime and GUI changes through `094d253b1`. 1. Open Codex Set → Multi-auth, click Add, enter an account ID, and choose Device code login. Authorize through the mock device service. @@ -25,6 +26,13 @@ theme, with external browser requests blocked. Verification ran on Windows. The server receives a completed validation response. Cumulative counts: three usage reads, one model call. The pending flag clears, the validation timestamp is persisted, and “Use this account next” appears. +5. Select the recovered account and confirm the dialog. The real active-account + endpoint and stored config both report `weekly-demo` as selected and pinned. + +Both explicit refreshes used `POST /api/codex-auth/accounts/refresh` with the GUI +session's CSRF header. The actual server accepted them. Separate live-server tests +reject POSTs without CSRF or with a different Origin; GET quota refreshes never +complete pending validation. | Capture | Weekly usage | Pending | Model calls so far | | --- | --- | --- | --- | diff --git a/.github/pr-assets/codex-quota-pending.png b/.github/pr-assets/codex-quota-pending.png index 45092ef8cea59621dd4ea9f9a808550db7239289..154a72697e4621f0952b3f0c8c3c9c0c63bc3e17 100644 GIT binary patch literal 230070 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 diff --git a/.github/pr-assets/codex-quota-recovered.png b/.github/pr-assets/codex-quota-recovered.png index d4ef7ff398da4ec210ecb8d9699454f4461aabd5..d3105f76f0d942552023b67519efd27c474cc87d 100644 GIT binary patch delta 162385 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ξJ(j!kd*dYQImI*N4AYTYe_>b?f^fmr@0{ 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

D05eXCMlyc6TiQ&zAXp#Wm9AMCU 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 delta 163965 zcmYg%byQSc+qZPX3>`zaq;z+8cT1Nb9eR-NmKZ`B6hs8+?(S|F5RmQ=#Bc8V`JVTE z_hRu6Yn|a-d++P|)l668)VAQ%ERO(4HSEG+a>^=t;CN($ScEYfjs5k2;cLm>^|R0q zSoy-mSw!?KWQ2qaSm=nUyzJJQ5#z0Y{x-OjmAABhX>IYd&oV#sGP7?vnh(-nH#a}4 zG}NadEWlfnGq^pCq7K0B>sxEytTwLu4R!f;G+TZKlaG`5`!pMHwU-~TXZ#f~Z8ZKf zt684=*7@z*%ilLgsZxcONaJ|GNrtrMo;quofybjGOFU(`tP1c()LVh#*ss(Lz|vtw$ku&opGF5F!`4 zw-xdBz&ciu@D$vj*a#gg7dDfVP}sLLKbqVc;IyvlVXnvF119P-RRy#UaL3n!p@67+U?(B4a6Jm zPF6mpScm22J^@cp#N(z?kNM)QtMx8Pw&i&O(bbzNZpXcsMi=fH&Jiimu6C4(Xztqd{L_DvGdp@P+10; zh8IZMZA(#wP(1VIXhFbj;W!Csn-pILp2cxl<&mSt^K)}^c_+lM`sCn+ga0_6o_v}9 zs2NYE|4aX-?y$V9495IyZ)ZmY;e5e1{rxqw%{eO$#U7RL+mh9o^-9KGel2}{6o3;c zVC7l{H0bBL`Mg&5m)D1pnK@_kSEl_qbp7p-+b7_8xo-05o9E8JqB$U2Y4COUdl(mB zvRC9)fwNw2gD-0lmeufUk2=RdfH8A@>cL@LucKH19V~v3QrG8X%8;6n$#dC-l{N%r z=518EBUIL7x9orbkGChPHW)3$K$6!dCyJ4gk&cJG9Eo?o3kqpwLI}yJH4}wM6RE^S z-u=Gr4nu3r`2oK$9HtGqUK7HOCfYM&V`{4~Il^OO_i@?vTw$+dO`N!}F=;+}YFHR7duJh0K0+7aak)m4S@UlUVhMfudS{RjT_{WJ|pQAZ(6d|si}viuu@~(bjF-J7@A;9 z&4W+-8Iv?dnt|h{7)oy8QeFhREpnLeNsg~CH^{i$RIe)Ba>3_-&Z%SS4b5j8ddqH=n z^9To!irK8o_!gNY^f=VNFe6%6NmCz(wamHzD?h3?%mjXpnxn&O;5tFOT0 z)^7nwN*y9yuLPN7utC#x8P)KoCfU?I5E(J}t*%WmhnN#?c{KBQw+drQMd;!2Vkgk~ zjHGm2kPUp16+p!mv)kNgmwc)z`0;}fxVk+#lC+Yl{m}95(QUKC?MAaw<9I`ygM))k zK`9IsXJv4^x&Orr&K*6q5j| zgtJ96FZF|8iQ+4bZ~ktD;WY^Qy2pwr#FK*Qed%9F=}4Y;Au)dnej8GUX%^y_CF;ld z`IXp}ag9|s{ES71{<~zPjLd>b?#y3LT>f4WTMWw!w~k}kx9gsQ*f>PJ$?-1Fxsbn3 zzUoq?nW`o*=Lwd6Edb1C}?E zsMul=_XtV&ae8mzRluVZ;d}l2$G1)>_NV=|!rm^IDczFTK>FCldI4wMS0ozi^S(xE8QoqLf$KRLyD3FZG4hu@6wL@4=u zjGF8gLfUO`b2vXbK5lnBO~Ppw4Sw7k&%vV*h_9tug%|X8^-blMFB-x>34QI?ri&Fx zI84InH{acv2LuSu>{tVzcpY#xaHu76PX!Wuw{qTe3{OtJS*%_sbIARG9Tywxs3!@9 zo^}3xE=kkq*+fFay*^sR+mt`c$`kdI!6G#(L12|iJ6Wzni=>r>?j6@n4p@qahp#Nu zIcPGlaB@=d*hafG<=dk#Q;7#+LxeyXZ#LS<0*!%+&rz#fV_uhLnT&7m znCkSWsQ>vEtUoTr{^|arqVaUSRr8ZYyBwkO@fh!9xX5k8@k%|LZ4i7nTK(SS=$J}0 z<+&0y`JR|Whah*8nCY6)Ow&stP}oo84sX~`wDvfCJO~9|vi!5=h?E9AK{Dl)ddz-t zJLo@O54afZ2sM@G>J*(AGTx(@f1z;qI`Tdfb1fu>=DxAQn@UcuWs5bk;|jW@PZIm` zivIMyBs=$)fZd^#Pk=?;n@x*VhqDdw`!LOoj(5zT*7n=3CYbRL-~jA%d45K!jU@}R zc#qd4CEzR~z{1h;&LPj|_H#K7`72l(94ut9POnQ|jnz#E`#FZ?Ldw}EaLK)YJB4XT zJ|26a!ne_Xh)l?3)MM!!{09v?1m|EkFJNKWyv4ipp)epFcPg)+|dJa@whG(yVno*&QfsKiJU zPaQtJiyUl#4)VSDGNkhWmExO1-I|_@K{a~sP zsV@a%1Z&>POADz&VWhb$J1QeL7h;A&xXD0S;f1S#eCUCxhp0g-j*0HqE+0p%IfW>J zbsIeb8-qBRso?bHW)fw0UeBmjB*S+PHq&MQ^zP5iqBUM>q5FletS210d);3(4NCmE z)?LCFq|%W1g8M-4z~I#!yhYOBz8;$fTBHD~%$jG)2w9hdJ=r_I8Unyza{hhHHAzoWgU z=DFl7GSniCF?fB1LoBORbqJucYThqTYb2LME;QW^)^zzJ$3v!GkBas))MgJ(QPl1| z;C-I@b4AzA`ey;Sn4fe*bEY=o5ttP_|r6hA^? zl(U!?uRyX(i0{otZvKf&2&p!0lgL(&H2%B0b-$V@3;vQp>EP{*h#cWB6Qy%oVek{P zi=yJa?z0G|CLbQV^n-wt`o%FBS}&H+zrZkKW{3nmsvxok+J*$UE8szd433b*PJYZD z=+rlPX*uu1Xby;_QsQ)YscqP$URO#nyub+MYcgVqexwh1+48F_$4HbG20tnsRr;L& zJu0{%F^f~iBR%4Y^m1l$?@ctCoeMo7;WdR2G5Hi0AW7*UY)|MXMvNn_7j~{tk?@kP z81mH@It21(c~@zOHj@w`EFLP9@LYjo9(+jJ-Qx}#Z_z;!6sH&|iPMlr%J}8WIT{`7 zif*5;@MKBCp<&1)Vd82b2r<0>VEOK5e(tkw%r>=7X1w~O`pLxJw21w2LdLwf`;vV__&tN`kf6Q=6MDH98DuUvA>!slE*TgSgVcZ@nhxRHa9Rs zPd3|A;cTc>@EVX#dmS23Ar4ZeBjU_V%10r%h69DLPSRI4eeeM>!W5~mS0AtAfU+_% zB8f=2){1yrW6*4-h4RmeXhA@G1Z@j_S;v(~>cU6UFbJ9SOySQ}z! zp>y6u6f&W8D7>AO}~CgN;EJQx)&?lM_5iw}Q7HdpTPp|ye zv0_)Ujsl1Fk8tGZ-n1Q=!C?w;8rSZwzUgFqmR3efBP)DnMh`XkYEtjM{u_?(Wkb_6 zCCE6dgY)5J4l3-$G_bV&TLa1$gDMmaXM~KHglZZZ?wcLrm)4n%^2%<*G+21I~qWK+v*pRVwAM=a}ZmegG#r6B;_ zCz#LJSt?D%6{v@<^F_3pp>u^P#RT7v1PYbNr(vtcunU5In(HMB){GJ#NG#)Ufc8PD zsp->MNvFE8Ao~ZCJw2FIri~!qkxu*jWt>mPQSS4OlKuQi>S;~Kkrty%I5y|#l%l?7 zZT_!Hi7L?8xDqcs?xS!h1i}lvB%J~%TD*TDI)^Bj0$o|C@X6`2fbA~O6cR=K{+FUlK*PkfTkZ# z%aschyRNFY7KCGy4r}%6|HDMwq5%7B9~p1^f#y%NI$VvKeiOxu9O;;Xx~&Kzt(c!n z0=BQK`#t?r=GvxINZ;oDNk+e*wHb*hVNflh6LLnEJk{Zs(*|GaNb8_YmBeW>qI)N8 zh6`ov6Xo7a?d;$mEjTe{==P1j$YW0BK8~bPdRZWs{wnzX9L{>rrWL8x)dBVX$sG5V zVdA1Q#QR~73f7e!xbykSEz*9fz)Un(NDoFgAoi}|0!p}I)Gr7fhJ)x?KhA>RM!Yva~r@t!oFmLk-Y zn8DZn)WZ4HP99-W>}t%=@*R=n_DpZc)uiO#lg3Sj!es2_L`u;GJwPs=s9u}X3*S~oEzIu*VXVep!sa^ zsdW;5X3+<>TaK!)9??C{FjMsH^NP1DgD+6NKsiZ@3jSGIepX3~==~gyEklbS9E=tX z>}lZ(a;Cw;R$L%`MU0YSke0WN#N<8+XMD@pk#~(x6HC+bV$P0)HuV){;V)4ztD(G! zvXiiOG$S9HH8Zu+wj$11fvb0Frc&s43bfmOey5e0r_aXJ%$fb{O-@CKrteRWBL{M< z(xQ(Q#zXzq7~!ZyU63Od>EMN^LjE5MzcoqH@kp$FwjLl9QTBAor5gFew2y!M^0r+} zw^o&TD{(dbQo_?ya8n$d#X;b_%y!TFqlyr#2}{O*Re^ale2WXH$cQpTgTsGs5HyZ3ZZ)z+qlMQB6Zj z?R@hP_USyBNGm<&s!8>;d?u0n5XKu8cYB-B!Qrg?7Gf=Hri@OGJQeY)@7X7JV2=$V zjhdIq8-E0J|I_d}wzyOaqxLGpH6vhTJ*L^=$jW^`7uH*Qk9$gwwbk2LBI7>MVJ=u@ z()c8~HAaWa@(9sgTLOvOW8qLG)YBIB0ObMirE4#&QaYic7vnw#N?ZOon{$zzdHgA9 z>UzFm3LbI>lAdMflkRd6D>R6{vR>^bgYoO=!7d82bopQiM)cFu6C5IX3?@=G!K_3$ zo3=vXw~Ar!K#(c{-q@{wU;iQ^BJ$XS%V^%qc9|%9?+6Kjf47YgpLiY&NjREz?@)b` zxlb?MABfvK-x7-ExTUS?k09~5Gwur|f1_n^j2(`Ssm@Z=9Q~Uug++8S3-?({@=y^B zK`02o2~!PB?E5>0uRf#r(L3Fl<$b)Cx(DCR!+^*>MTCRw)@UPP=~s-_?a3D~>cr1F z5+yb?oyAf@$``4|B6D|yQHmWfV(E@^&a_-)=rGhc*vLLAe zw&X**uobyqZsw)bAmf*pCq6Av__3z&#+lwk7bAGnBqo7ei=xkPEnKKDZGEcE9`x(k zzzTO&>PhwrNJ=HGrTFhBVgi^LvCgM-e60QVPB;^dYD%8bCQM(^13;Kw2--n>QAcJ( zfg=%n9>x~wY>c_>HcJ|L<`m=B;BAF^uN_@6`)}vH7HbaQgzN~rw^3D34%fcT7za!f zY=q1HsK9YIz&Ohq2{_1L7>r)2kSGX1eYn@1h;@-(`q5NF(R~dU6M%md1^8khR!a=i zyIZbgmN3$Y=$M)3@Q`3?ZsEZ?ivIsGE0M2`k3q(P&Oz=l#`|sUo z_0qOWIK}mJ5`_STjwi+)&GQ-PE&Ch%e<9<)u#qKfTS%>zhUa_?L`BCGS}1HQjN6ln zSPenDko5xLvV!vM=;(Xo56bQ~AqK ze>v00P_Mr}Y&yhec1+t=Hi~XY_4&}pQ#5hyehfr1#~cx2>_b8bVqUctK9Xqv*ND(k zvNA%XUJ}B^FQkyUn1)J?VA{{b3eokBc!JUhr}+0-Q@T%GyrOS`kLh1Dh&gMA104I} zAkz>={AQfsvfkH_kE7m@PUNUTnpP#1fs`xJkD+^NC15m%+Kl+&x}d%mhDzajfL4~X zDM!k78RwZjC)`TVnb4)=-E(x64IijY~JFMK!vN9Exd510tybXp zA!jAy6JLK^3tIvKXr4e}fY$HdYY&)bQBVBw1+rXE{e`?22yM1-RPEWJROUI>ln+f& zyJ8@^(Q7OEmj_A3BeJ5D!}#PS+40TYrEiSbF-e;Oo3B!V`#Cv-9L7E7GP)q~^Or7N z0I8KB>QkP9QE#**vV-8$q0VvSe`Mm&P?`16+5N;CBIrB5IqU`WSxBxFUNv#r(AKdk z-JTGgOP~#*4q8BLgSHVXbC7(7fp2NlUnO^s=lNfj% zI;vc!0T7|MXBqQ@+0#!e=b|6vnE>IOfrZ-deNmNeeO#fN;Q!-r3yn)sr;0FVrO zH~F3n1<$NLOGt&(f@q?C2C# z90Y^gCBh7Xnimn!=zHk!w-j;~{JEMqhQjWHZ50i=dYtYx26e1{xqEL1S?bNiI;y$| z>>maCAWP&nwdc|Ozry_T!MYS3%Q)ho)Z;#72T)0e`Ph?a zj_B>HF10ODm4SlcoiUeuw&l`2ge56{4fWo8C*rpqf%N1rSEww6>a2*2w!{6~k|q7; z=F{O-gw@O4IK3c$9P!&5b*}2uB&-U19UuH~iSxXy!KRT~ias=U!Dh|RRyQCTcIEH? z+jr}+p!J)h3SNL?(L9*aC9d|!GFnFXfG}C<1vLg_cbu^j#< z&ggY}E_pqMOLLWozgf7@02P|QLxM}M+&a-^obQRSFw$tazh$-gAHzfw!LAU87p$G= zT?Y{cH5Xon_jWS;>Puq&4y8FjiO;Lh_obmzEZs{u9Jjzp+<%W-sLYS;6N14L>sf51_51BRS{3DmTsPD5A)0dj5 z7Dy@ILn|CJwHY|L@;>g}!(xO|$@yv0ZK_!;;?)@#*kxFhP04Kc;{IkuJ0GlltBysy zPzEyWq)Slhq2?U@?*Ewt@ZWP59-?(E_j*dPBvsur5S~Ivc%d)@M)bJ~87)l4BKBU- zmUl7dXgJN07vB_X<4J*C33w9Z+qc( zyr}Q7T+wdLu#%jvws!zd_S(HX9R>>7;{3Paz$u-T2D$0xhGwzOLNz{;KWl@VcZn~F zBc5JMgetZHoG%2~{Cw$6=1@~!3#O)}vB8~+%>UU57KlrM3pCxVeURlyCMP*Nxd=Ql z!NA!~-a<^rYisb6W^at3(&w#fXuVpC8bfr%Ub0@F5epkE9DCNfRe^mr1xBYOJC^(E z-EwUyTxWNktI&o!Q&CBzU?O!GMI161*x8p4mi_j@-;IXfXfC<;yB$%{X0#+arT){9(b9UYyQFJBUN|4++KMweRDQ`O*! z!Db%cp6~>X*c=4^4b}7_?Eoe0ZP}0Knc(9W?Ni1$1?HVuV3h7U;nD%prrgdwy~Ep* z({>_4i|8z@9L(A%gk$Ks6qKSqa6kFJwp2Bf-563N9GP^UV+~TECzT}-)Q~n}z&Cf4 zxKT9Mj;{gWF2)|mGQAD4wm(zZTqL6>AqK5sK3x~VHXZ(v!@*Dry}tfOVPRpp|0Xk} zw~dP7gC<@NU~(t}D{30q%<%*p2$}~bI8r$YVfHnzRv;ui&a*OvGl{T6+l!i!+v14i z7ioR6jR|7*qA|Oz?crj>72G|``Sc0T`SsWVo3!)P4vi?>3&wyJ!?PC!!klgAblL`| z^7BuNQ;`Y(`1UP6C-!7)_Ls}eUi%;ZJZi!nSAc^f!9P?sNSQt{h1}=kN`VyyZXO`- zz1U0|T$I6>Ad&j-DjI^KznG13h*vEtWqGsGZA z3c)pw@R|QT_06&ikk7D3pf>Z&t-%DTTJj zQ&Bd9s+yq#ccxIUY~j~|0rJ9|HZlfJ_d6t(!4`UYa&lJnj?eD`%To|lopJBXj!;{> zdz#rjZ)nX)(AXW#d}RTWItnOp^g3uQBk+YUeemA{MDxLn^{F0fxA!UOxw-lI?{|m5 z|DnEMYd_#a+xawx$G#h7wY?_gOl^e z4FtlUqvT1VswyjOqSogxEoKs-A?s1rzS};rqZet6*-iueK z5QGIK<%{1PZ*V9Jx^1*MjUUdRtkjFTP0<9}Zmcy+a$4rEa^LNyY3!lPediXCfMxA& zp=mqxBUZ-Y9pgltYO4&U4Uf+;$vpKayG0ve;2q?n?T%ep(oMF?+b`>paSWAP{P`X5 zc>7^b39i2|{txED97O#2^CxMf=Hyog(dvtqmX`Z;bFsGj3P%i`3C@?>YaCdav6q4x z#z=f?q@?R_RrVc;qJ>G;x2ngte%UNy zT_7ywJmsS>7~lN1tLp0y4YQ)z!1MoV1wt?WhTXl=`x3+$Eu!XNdIwF0nG=aHn*sv>$T~No%{luD zZmDpkyb&pbn|QATbh^{x_Q_AeOx*tC_rR|$?Q=y{l~_8!Qfh%p(P1qkXRCA@YJ9i4 z23e?mAL)3ZeZ;zW!R5un*@`g2sP7@ji;uMxiYK_j?w9?>&wSjPF>FXOdZPC{BvQoOJ(bk-7)V~dtmvel9KrNc(_kD`vgBh*9$p2o^4;gykurB7kQUf z25uLD>+Ax^(g4lmEv3ks_v|>S1yct|aDPK8o&_7+1Zb;sI=n`!UL41nO|B?H=O}dQ z#-d#xdr)?(w6-KL4UWAx(Bt(DLkwo5Qt&8%3#fXY|4UdekaHz!C`?RL-Ud4RFn<)y z>#JWiZMTh-TU@qfli`cfmz%v8?I&O17h#ht?rai}Q&=(x=L6bR$Vg;!^JoS~zhR51%AiKx&=}b~fWyCqYtJKT_ac(6+`1Q@ zvZ{Am^}RX#BqegZUKf?W0?(0@C|lnCTD`j*{U!w0OkKWpTwV-Puluf^z#}htqIaus zQ{Up<4L@80_||y=wa`aNKzTp`sDW$i$^7=@j;gBTc|*(mzklwEIos#hm6e@_;n}`N zJW`K-qT&>IYGqEal{U=3U-*8+BDM=Zx-WBPTUHE7K6aDl1KgXzYY~fT!_*xikzu@K z+cq8H^0s(}yX(ELJK$0|JiN0b`oGLBT09XVtYc)9m6`{nv%wPS6xJYdL4~ z+D_Ul@FauoiS?&oD#o@V8y_qbt%WGchb&jI7xcmM|EItcXtaNJ+7#TPDoWlo{!}AxUvZ5D#1oAC3LGbIr)p4IX zoW=})M4jql_0$CMxFCMg;y?ESzwxI4AAT3GfTTs?`GL4XsQVa8r{rEgT<_%+B*XY6 z@LZ`8ryHWT%k&xdo~yeO&zJ2Gme!|z1Wb>6eZPL-qQ@j2uTg${#;=9G8>**mVu zmo2-)A3XyNs_HqzdfyXWOepDpwIrLw2X_-GFX5BLu#?D?;YZh#SW~nMEF^BlIv=l> z#<HlZItoH~ z2GVV+KpH;4m&4#8*NL&Qr@b8Eh=>T&23O;bV6yvYcpk(1aEg&(Lt#quO*2;nz&ytdo-J@?EJ;vuW>g0m77c$(Lidf|JV0I7L zqV5>{-8T+M&xYMoh+;(u-%|c5Z>UN%(3ej2`le4+J5=^x#yLoeAc%4GcP2e;s*fT` zwFNCTW7yU90HMt9lo%-12+p$h5iK1{woB~m2p{d@2{I%3RGatRj!QzHzA015djxh9 zt+_n0R7>*7M$@swu8O2bm*E(7HIciq)MKLFy>upAz$n6XWqJB79nYli*zMH0kMJ-p z7usUCue?qRA4OZa=6=47ZVUzm^>~rm;>LU40}+ft@91i9;~rppmxygw=&}&Uh6i|U z%O2-Sa#;IzHsN-_l?sg*42B_U$Y~3Vct9GS808^v#lRQfMSS@QQI%aADoZf! zB?K)KqK1rL%mVeC zP0Lywr;w-ud_Hy89Qz=s5Nsp)V#^h;%wC*!B;%XvRezTjqjXjx`N75d#AD!h=Tf_$ z3<@4Rs^6upt*zlC%<*xFdt`L9+hwlOaMH}P7dda+vh)2rrEEp5X)84~>0RPtbvE-R zB+V2nbb&dLq;qfQwIoG&pyTy)a3{|j-=F)YJ6>xm|(f$>pJU)D5 zTy`#Dfr$*s7N>UDs+G?~6+Bp6rCZ5l^5?Y4>D3WG)4wWZ#IN`kqq)qpPg)R=IZjsf zM!Zs#(5Xn*HPQgQ%_<`_O1y$ehyBi>=%-t3Zut^#;tth2mS;W83)UC_U;pp6ITv)v zHw1_sPcYP(Of1~XLIZzL&5hY?ekt%)+PxZcKfBi43|6Hd)H3vDea)fIJ?3Y!50AE7 z2B_l${xHV_mz+_reFH>pUoy{&AzF0_+b1@y1U-perby*4a zDogAN0*N@!*GBV+$9XM)K2#RgUMfX9KM*4i!^mvZ-~&gm6!;!bRx$~BXM?(4ybLvG z4{DXS-NF}Rje$#qN;Pj81;Pr@zGA}D4Lb<+AzL&O6g&$_DTL`~j4q)YZ4kG@2c=^f zkEY*ni&K`Kip_I~0KyR5t5n?wCI;uzG2FKhAqXW-9p#^`$^ngXee(gtYp#QggVJ(_ zeSssKvd5uN@w}VHY@Hob8UJ1AfnJD#ZkHojxmjO01kIE7^1ygMFoQVA?4HzpbVuGx z$nEuHY;8Se44WCt>jzra(&aZwWa7l{m7&p|t#HR*MmIV1T@(3ok__qT{6LREfOa!` z2m9^{!Ml5YJs|CX+xVpnp5|!UpQ$b8&xT-^OycnM8fBDL=h*d{&v8iqO0qOz2h}OR zs#(!P`P2frr8P08dk|o{p}}n%9@<7RVWFI8N@j!)0`xDq_5yy2FMjp-Y+-rii3|(4 zM?8&q``Lf}=+^s}w`VD`s!3K6v`bGM^~lphZ`qj+5EJhkn-p^-p3AX^_B=VZHn z?71nZ6FypC@b%LpVZCg6GW*k`2Oa%WV5)ay@EAQ>4DQgOQ*}DCD1q+SlF5;qK4j=> ztoD2?kC1NrM4q=G%t89c-(ODTQR@gg;N>e6OZU@i+>5}voqq+HoSN&C`l8z@#Z@7i zOWRNdV8d60>_BvA(OBhxdkK=Pz<80Zv&=TCIG)Ysy%f%{jFZS{K{wH;@Pfs+w~Q0_ zKMJN8;h;9XzFyvB(L9ZZ0tw}e-08PQ{^xj4uCK|+sqY)TuzG|mjwWux)Gj@Nk#yH#Tj}$qx0W|bxw&vU#xpuBI}bXD5XpUbO>dJ z>}@xx;a?+J54nprHpCL!JlP`$B!|mgZ?Q{oZ%xo4(puFdEuB!(0jsD}@ju=LiV_ zt{ICRluDQ99U;DD8r+v81#&Gzq`>-!nvtq)83Ub%5U%QTDn!vJeA4rP!2%M+k=Kqc zl37xx$2|!6Ztymk5SSs}VlP^aYd;1^&iWl~FDTKeOpB>RALG{ew{*49q2Yvk#o*-xnpnhN zv3Q}{6#w?g0;L13#E`H0*Fw0OIe!GZ$uTOFvkEKIWWyg&J~L*v_LtsuiBWMbogdkB7S_I7#(?5lB^Wk9$N19|@^1EhE_d#X(bQ0`$F$Y3&Qu>I9}ZOtaeq#^?hN|9FSjAb@Kk^siX9E!qX*M@{V~ zd9iH`QLMwjCAT1`Dnz%-)%quf!)aF|9&QEhoBFRpTDoIS`|S z`<|b%yt|Ps=>HLNDPRqk6~9dH!^$4sbodlKxHFhvJHot7l1V->1@gLZK0K5&h#BfN1oJlyL#*q+o5H?j9V@nD%XE+Jo@AlsnR(Mr-v59$W)qN4bHTY{kN1;D% zG}?#qN|*w%VRU$7GQHF48N=v){$nP07bF?lla_&i=^ysKo5fSj)Kk=`A~7 zm#3ll{uj`*e%+Yx%!v*n`aR7!eml?w!JY*Zw=WoB_`S8T%;`a%v2c@?qWJ^{45f2X1J zKB~*~upnJzT7UfP^+5xf?02o|k15pGIh?F^qtYg=**Ti42@oZkIa*&?JbM!wXIa&z zeHFMU1Wswg=;s&sUaf6QmjN`64&zF)wm625WTdEYKeFY;-ve$5%%k3x(0~ zz?j3Cm8BSu_s6m?@#k}W$v^JnvkVf@p03+*&K3sAyYaTrC8kwUfq~h=M>jFPWqAdn zC#k)Og#fqQqQ;;->P%od{(MX+_FtN91I26Iw0F|#)l;nSZbNSZXs<@~#;UfZc2a+gI4V+^niP8p-v-x*4Sql6Al zFv-XmvKg!AZ(W1MImE^mEkcrK8@zm*|6qYGFQzsy@eni ze%Qa8J*|%30bQWS2fZx0@WP8J6a^#|+m93`sJd|aXMXEE9a8D2KNf@sfvaG59 zXau3WUh_MhXqn^fJMpSCAx|7nT|#7u@ghj)H2Zx@IxxtC5B}L$}(Jvh{nC5fN zt2q?w8R!`pZ2cYiGNQ6ROY*iEvE?zkZU@~u@oG*)*Hd$zxMp7WM3IS^5&qTJa)uo) z-h_U{+m!%|h1!{!)FRkS>dfWk<(H9{Ft>=4CiS`lJ@vvXZ%`nX+&jID==7LUI>C~R z^xSkz+mccT`!c%{z;k9LH^?3_b96@&NyPD`dG*@FD5W+boh*M!z?@9ppOflQ9&x$D zA|rXeVGXWcqTh}ORi*<9+lku9irC=$-+kk6RLs!EJM9Jter6KVc7Q7kiUOm2|QIbLL-f9pd?w1)m009eOjcwI;THFwpJUoj` znov7a`{m1*A3uJ;W&QMB+hz`w;7w`)w2fbCi#k0$;XfWB9hzURN1RPQ7yW3`Q=QR) zzqsx_KUc43$RZ27P&{^BU9A^|fSS6xs)k0b7?TE8;;Y~*)(d(ox(5SG`WpFuMn;rJ zywLcOiO-+%fsfm2q)rG~V7;ChY8%RJ;*r)rKL#iwI--Pe6PnTlOu`Azr5PRBKW^#v zX{tKr(a>Z0;;X0^e9ZWmwu9v9;!Lodr0P91zy93Tw#Q+T3Z;>X;!xUk>&l^xF0#7w zYdemkXa%2>X>Q@O!i{}So*87r_Uf0M4 z4vy;sC^Pwp@0T?G-ruw980;LJAHwpoQ!sqP`bg*O`#sMm9PRAv`uqEbS%*K9Io0xv z-N~ZiW)NoX3XFZt%yUzW53vS z?oz}8fm?$$?K_o!Vp1S^}22(93fggZ#{uZ!CJ3SXx=z6aLL=xOMj#EO+bCLOuZstoAdd0OKSUoA9x*iE=R3 zS2gL;6p0EaA_ZOX%=Au3g%t9*Z{BXov#+RIrOH!e&3J{wnD?>z^n8rrMIuPGlSLuD&3 z6!YCH3hC&+R_?_TBGNtcv;4VtT6mZAMCbAS=@4_HGr@42`S&j2-+zg;Oei3w`b6Ad z?+KC6o1;nWP58Q{#l3O+(83Ak-CgUfNk=K|XB<`@&L+z)Df4JFyAv~U*hoI*Y?KQ3 zD&*ne)lE$sRUJW=A^s%rx2t<@?#J4i87y&S#Pi^khdgaAU?H0l9E9JZ$&BQapON8v z-&L5Ljf*9uF701QWZ5Pqgb0K;o%}zh-a4wPyW(%sSs$f8T8 zgmkCUA>E>McXtX%N_RK!m*@GN_nbZUAA5|w$41tg^Umw~+&!6xmf`OjbIpFMU(if` zc}2zWsvUdqS-)d9M9aeUUDaMZ|L#J^WPD$i5n+drEQrYJBDs$|r=Et!)8qJu!~vxY z26cO10J7LSXFA(wR~kR!|2~Ka1DQ?CTqIHN-u{RbLl90mEB#D7a37tQ(Q)ZHnZ}2; z{S&|788_5f^TR^^Osyri_1$}47(PWH`!_zh{Fed!#YS6(E*i$Q=#_|8^^|^tb=92V zAdgY!XUdeV<-O0A2@aMGmi_a~R^G%=fNlZ0zXcvJ92oEL?~hdkbxt4Weq1$O9ycvC zLH7&^p|r5$<)vOSw7gzIhrddLf~DUjJo)CN2q5yOJXXJq*9S+JmrwfTLf-LWwj5>B zg!}s4;}0Y~o;V#QB+>Vm$n(i^Ga88EAPkZc|Au3WIDgaj<2?35yHn!dM!gVvM>A9P z0P8Prn3bHB4(W4^bEO_1p4b!d=DFF}S8FPeb=bZD-}ir-7kqrDZz~63xW(z{@9kNF zp=eBYr|ty%1$k;I@lD4Y6|*-)A0|}Pwb!0I8w2u05~mG@!nfvzpnW4i=K}`rOd_pbb^DGH+lAjM)Ve9>EXX098)DaJQpWpEw)7lO}2M8m%Ltm z13dc+km2pssc!zX9W3*jhPO*NSvQed1p>($=W~(i-v%>z;ER6id10q*_SneNgM5s} zN`jU)!;QRCBO!jqLQIUzALi9q63AC>$Uj|S_Q62;hnXB|#=n9Ye5tN)i;IHoGX&C^=vauJHpVx)%Laj2^X_BpA5z8tkv8J;(DQaZvUtRYV_TzpjL`|fH|~&_ zT(gRHESDJreUZaf^78V=!zhgYi8o%~dE7MYPR>>f(XF|nhYIofDR_o<0N|?a8!0w1Jw8w2}@c=H^uVj(PP(0&H*DIHUX~s1Bc9M3F3o zyjPG^#*cz1|9*+jAsB(tewGvG(;uC@F(9F`%o5AwAA2hcPwER*=f7KeGq z$MFwhh3}EV5E<+Y#SY%8Y*CUZ{=YDf1qV{pbj5HBd)VNdObAWi|I7-$r`;L2y1OQR z5n^^}yD`9Vd0owM-y0k}zOnzk^^je*PiDb&B@7!lW%mz86}INDGowhjdTsiH%iA{L zH6%Sz5S=6-p3GL54>94xfS(7EY$RWW@i-8(s~nhu;tJJMJ@#s>aRkCe6%=HV$iEi6 zRw%zDBq1_22WrCRYWO{39lUR#O3^e{TBpjE;w|PVDl#gbE{bj!&w{5zn}67e$@*Z5 zWLWJ3ltWh>@FCoR<8koK{!KVzGPNNO#3ZK{zs2W%vQh7LTzkHO2gb=*WEnwfdw(11 zepFWjIK+Eqa`3rfb}4DAV)^)13K((AIIM}caaLm$y{8?4naxRFzydnbpDPA3DJd}p zw9!8Mtoj{?ae#)-l;BCvty-FW%EjX{{KiW^!XOS%Ho+qw*bZ)*E89W_8@bNMA+>&(VOWHAtOA@*BaFtvhQs z9bVK@f=PZ+QGa(gb-BputE|TuN0^VFklCMUnFIIygY)?Q?i`}5zP|$wuQJo1*Ijra z8Ycii0t{E0KEAH)@Pp2Hh$4X$Sy)TDoHI;ziX@6 z`}X2bv5to4<21on2NrxwGeS2@Piktyl4~&{2m#9_ z&25d0k1w^d92Ve4k1?#P@cH$6Qs#0d0hW*Gik7jjv_qigmwqTTR21bhLyne>rK>IX zh&GW9f551~uX;4E$12wcx5!h@0|Id?~){8TMa#fz#0v<*^XkSJ~ zC4#A|3t>)m$Y)vmXVDh0JO|lK`lN*_MnOSg$VN2`Kx@oXKc6kOh~`^bE_hw^kbaV8B-ezmu5*XKZ0Q14i>kcRpuFm(L zOs4BMxJNz}^11=?36A;$9~#lY<_;Eic7L_w^|k^mE25XIH2!KQ*HKxLa)t4%T8M0A zMj$BlC2%lKjJ@ql18>gmY}EpIu-DTdukNxkgZsN~AdbPfPh)qeCo##SWgK-SbzA)T_!c?d z*#Vitm&NH?r#>JybK4kh0fxwGu=oPcUfSD_XG?7;RG&`{-PThyfMAJQsL687jDYby zjB6`8^{q#-{_PlWg?)u!rPa&90ArB;VjI%BpD|C1i;oQ@h5u#F#qy)orHDN#u6njO zj2BT^Wrp?`ME~P&Pc;`cNEF`D(5$z{W_xO8q{g%pX7Phq2vm%=j3B zGDKD{@mHY&Ss|4*!JonN)c=*9OTDl-wCq6SD)X)_O*H73xD!RtrvCyjc~zqF-fv3k zFPbqLXApA09uGDb_=V_*{{54dmR|5W-UXISiST-~lKqFT0fK&iYyckG-`gVFx+Neo zb_5f}#l;Z_eXq8?tp!HFO6izqAl$Y>`4fd2LYJ#CfI9Uk?%+_8icPO_d|X*w{j4>F zqXaCQ``8-@{aR%?8e-$)^?`WR1prB!TYN#p2DA!~*~$q5s^--Cv#pQ7wYxJ{a}3u@NEv(o=C>2HJ(;&OWdN-JN8#>R)&BF+dLJvv-G-y1=Zq4$7Jq*9^l>yKS3yF^ z3+~5k(_gkfBG`MDzty(Y9oC=uvrvpgbzTMd`a?7^qDp6W2z z9l|bx?ekLWr-}5v*X>5iVIN1+7aq4oZ&Yf;$E!m3mrrii0V?L><&i0s*TJLyYCww` z8ygFP2dsF2D((2_3_OvqgqqyFS}xbq6chlg&b7u!ZS0wR3d0X|u8)6CTBmi=BLI_gU#xA7z(tJArOL zFOJ*XdG58}dT3YhD{AgH)>YUAPf;YXeS>(ni?*f%00Hj=Fm@UbS}~)Drw~oXcB|&O z9XDz~oUb|ReaXj%txJ5I7=nTMMCf8zbRdaqd!{0{oK>n@ zl`)c3pyQL*HF+c;9yxg|2QjLb=(>UOAft@eV`aMhB1C5dO1C-L(t&pbzpXnr`C$$d za6ABS!sbX;mvn>2_6`5a_!CByvCKqW6rMz1vvn+UGzVCsLn0;34G>Z%(dCHvwmX(R zdKy3RuEV|hB?bEk%qVLojvA$+lk-fv+{8kDutz{WBs5XC6TDdhX8mzBH4}I??eO#V zKXJpw!LiVKw5C+v_L3{Vz_mVzfd4V50830r+j17y3a<&Niuw-*!0hDk5r) zX8z=e?63enlirlZz1pwdE)7rJ3$2LTX`WE*?SYyEXqG*@Qe4jV=HD>zU4raI<$1Bx zOZ1$a$5K~aUtLSf67PjI{Y2D#zJ@NmLl)v_aGaWV!KUCp3GORJsQHrNT81vfsw)-x zF7$m0zc+`}Yl{#NR4DizH-PXaproL;*T)CZb^iPJ?<9JhM@{#)9N%#GxBYwu38WuJ zPB@obWm|1PMOOX+WttdkMdPJ|sHUop(-IrI{0YyIl~ z^#uZPJRwO!e5~W;sFpzzfk(I4rQ*r;5mj}>H z*berA6+c z`G;(wIc;C5l@&Vs0STS%exsn|pBjiXFOB)94T`#%QnN=yL3@t|MPbqRKQ>RCRCW zj)&TIp|$V#Mqh3}LD%GXS$cKO_cvWamHX3&e?UsToJ<1U!q+B#i{W$-MfeHU)w7ns zlOWP1$-MY`5KtRs*9S?fP)`m0gQpdBbx%CI3(O&bVylJ5TcP{I2iQWrw#|f&%bZu8 z8-^gtf5>qiK6q|Qq@jyF6^ zXPM}E5xMGx0~5MmRLg10cBOd8Ae)oS$+w?~x-#k!?;igUnClCAc^@2%fsfK{fS%&_ zJ#ln&)aM}v|H;nDvH4S9vv^>nP0HI0N-F_?c>uEXsgm38qLJZP#+#$rq&yABC3T5h zAMZ}53}!OL zc)5Xb4S_$u<71|zg{!mOu>!R|%ds5qppA*bDVO8M+48n(Vo3~HnP5GvJdIK>p!Ebu zICx&-#>nyUla{gBx=;H+)8CA7N;O=;r7rM4vjQOohTnPJY^dofUEywSZUFuPx>rcM z&UrpV6m=6megN8n$m74Cuj5rY;L3Wjsc+p^m)4^hr0U%VtUQHY!fJioMdz2J0cqgZ z$60nR1}Dshji=0P%(sVKM1}};PTT&4&P;N$H3Ifv#1F>e(R$9#K^S*G3F~uvb>I8o z=kxE!(oxNKkd4+*9qtuyu|$QSK||pOtxuiB+CLYUW^6~NZIregf;i8nU;pjxQ73t6 z(t_}9IGIDX2hOv3UYkGTpVs;}hciThT$-dmt;u%x51=c&iLW!d>;$>na3aO!Z=9m~ z1ao^L(SeX>Y&T$ja5#$=vlM_~xnc-z1U1ewDMviv=;s0DmyO8bE0GXpM&M4;V&KXF zCs!~WmXokkq;afjFN5Lg-H){&1ra3ZyKmmr3;b2+O0N))!=6ATU*m+?caoJh-0=(g zqCT;mFCcpBa+N*?P&QP?7byUSHdRW6hIo+{LTuE3q{YUJE_hJtbz1oA0X!0vp- zIRK9^Of2E&yUfAOq5FeB*kMn(YT-N68o(X^nujmgc1@+VTLl2s0h{Euox1>yYs*WDTQvg0VDNh&U`$TPQCTL6WFa} zo92vN;P`u@eIDrV75G-wq-4t;)x4RTh7<7_0R4{Fhfuplz@Qaauu5O6J2l)lUW>%2 zpLDA%S3@FAqhqfha9QhMDlx92@Q}KJJ>u>tp$Xr3Z4lr`!ddXi5VUuH%5wNZ&_h47 zVh-x5y@qp_biTjtA6r56R&4f0dJMWs%Y{aP1j%f`q^W+S?{-S$$?vjd(kZ{Ft&qeG z1oKq3lSO3gGvNOrS%6-82I!c(exR>(^$?MJ3DJG`r2)-JbfQ zrrmX3@Ei!={(8lJ1%c*0M=s@P&S5B%J(1hS{anwbLaq7tF5ram$v+jRM5!_JpBL{S zuAsIeqH|CPef-tNd@lal$UY9G0xd8N?G+~Db2?I1{x-QCo)3dr6ztERGmfLL+8~_qabqQhz7*_dEhbZ2*^a-uX`kqm$5l>beYu z4Zd9{0l|+0?J+D~Zo=tZLBl$PeQ2~mM>P=0Tvnk|Wh2iM zZ~AOPrSFwRs$#>(sS?nPj;^#D+Q2c?nryDQe@H$9T`I05Jd%x7taoQ;$0~dV!9qku zod!bF{bXMslvHIQ{h`n=qPEi(my0j^>3{NdAhF}UO(bz{mDr-hM6NFGk$3k`I&1uS zmSti+BeEB(lnI3JgrD{AVLiH&#{~1-@gsUI`O8`28;PyA&$xU-S;$2yZbupdx{_Mt zIETXooxxZZj0}d2xFa;ESXp{YG$QmM>&)>lYz!z@6L#Oml~@^9ry{`HRnd=^RB8ZYe%QXkqMT(Aq%LV_aGR<4JrMFuJRoIT6nR&($Lh2}x z3(E$*c{TF=MVC-%!`>f3#x%Lm?x(Ava@HZyix)~OymegmZf+?3{sU!?l%*$i@V;be zs%yvVaU>DbRr?p}RhmqjcuZTM|2ZqJYa89O%nZFwcvD>>oFN_9-yHJ5CY<(SPE z8JGL9Z-~U*qDHt1HPQrK541X=Ob$mR#)I@V7f-%e2+gt@IiQ%c8WXOwKVL_(irDSL ziNx!5aj;~bdPzn4hF`&Yaz_jJK`(bd?Pt#+2L=J`6G!@M#Wz6rUjypT!xx?hE!TkE zC_(PGo(l@3s=w~!sbTU-JPl-j#nFe5?jGj3bP~zu;N2;$!X-fva9LPM*@ZRMe5(* z2Xu>&n&FuAs>0Y6tt9vz=G3z%>`xt@!uVZZV46IFBk76zWF|eT8lU9F`OqLS7=l6D zLy}-pXd*zC?ky6`RuGt{mreu-#m$s{NZk~SQ0L*}@Rj_0=KTEA>N7J@oZjK9m?|}ZhTb*-CfjYRIHtK=8jjWDNxE?dqfAxu~H;Ekdtozz`UJ zF|IR5NY*Rm8M(1UewWeu;2sZWJE`Vc5>`LO@_F}K%125|to_ttzw7lW^-RYU!xYS^ z*l0GDnYC-_XG-u_tEGP5;TV+yVaa;wFhhrlpoBO54rB8uR(23e6mUwz*!UBZqeCM! z^R(INp1*G3Jzn%iveT3z%)lIQprb@=J!cbpbbbJmiDm38(^F^keKpz_;TSMpyRt;I zo_@PN&72N9!R$_Y z^dbQ9wPDQw2H_Pyrf+3NQn*~9x_1OEI=f!&384DjfT}(flbH+niwEU47fOY?r`UA3 zW44GKJ$!#?0*q*_(?=yO59fUeLC&XPC6RNW%>tC)_=JSg+sk#}g#6Nl0*z$4VUpH+ zoZBWkfP$3YX~$1P3c$X1VPWdG`R2%upI@6pI2Jfh?L{(i*luXxZb-=6D3-$dijLli znh8Nx=sBGUk!$8Xqlt9sC4Z)a>?G%(M*)wLjp*E3QaiSGx{I75^D@aJv4RDnS2(_| zX2HZK6rYA-q*g8esTVm1FyXtJ#;L`1Fi`gK_mWzSu?Z5XHph*GP|c9ol$lk;fhGvT z`s9PXfQzQq_m6v!?Ky`K{ohQ67uIV%x;ant@GZy0{xlEh!8?e+T>E#hh5jUbsCHg# za5m0LBqc#Dmdj$N;jzp&LOVT@G3^fi&!eKRL_T$uPnucqy^r}CiKG{<8Uqn*(*JS{ zl<;J|+>E6i9d@-F`=^;WPM{RNNG-t!#l*yvHm)Uxk#i?I|DlG}Y-C0~P&R=jj(6{z z*=n+ACXDB=DwrcbRE6J!ny!Q9XX3bYBU4jt-_L=nd=0cq&7XliCW^9s1{id_Lp3Ws zwN7PVI#uDdC(8V&SYp7YbHkxZEML)oH`*^W88BGwV6;_S1=j3fE-wsQ-9DXK7zW=b zJ{J1~Ar%R`rYo8b&5?*U0?ooO;*7)%re&svZa;1$DTYasw$6hiw}l`v?ImY0@{?sW zPG-?3^lBBnI5Urw>5QsbR(E5ASL}w=U9|DTSM0Q`)y~6Ly1RQ>nOVY}0YwSD&rU4I z6@7eBm9~wH3H}S(U`h`8)sLkVlx!ouvL=tSGY|8nmC*YGZygP*r=@Xr zHEr#p*@)h+X@!leJ0#S;-ah*zo~ZBm`0BWstRh1ti{-z$Br{On$g|aB?pPr2=ti)! z$I7#`!Y%%O#o%Fgzn~TWF+a(Y8AJgKwQ(R_MjVq6;((qF5^GGR0nDc%EX;Oes)|bR z#83z6#KTlA&hya*vHTBrx4&2BX%2&+m%@x7^hd*~F!YfT0>(T`OUs<{$&(o|9Ip))=NOkX=71reDuq;}j%`ESKQ0*=lXDxZv77-=bdvv) z`P2yUd2Nj|^UOO|*f=HQ`ux`X?em9P(1cAE9;HcR8|u6EDi}{T8@`Q9&sm3u_Mfsu z3I*y+s^`r1TUrU zt)?Z;2Zgp3En2m%c?WG0GO4j`BWAuFQR9j#e+|2i8k^)gDJCMCs8eU?wmvrb*^Hyu z_r(n`yl?%A3D!3x`o^6;bduq$+SLap#@@OL*3;EX^Dcik!GL_z_kGt8=z<<;4gZoJ z12Pq`B|8O}andrE^^z0-HZ~-OM`D5*r?A6|k85(U{h6$FkZ789W8-6&_d!koeS}Qm zVx8NuHZaH!KwMLaNd;f#NnLxH(>`Bq&eb>!k=j50lQZw(?6Ni8Gm4M9R;S;f*gaXS z1HjQ}e^A^(is5lRh`h?=iX6ygowTXEVat?-9cIgl=&lHCjd)82u;o3SFQtt>*zt$T z#msr|s~@C1T{MWua9l5QUhab-IC2(C_@l0jYjkLtI-}sg^oI*9;QA@mc>X_oSiMRn z?M6Ls_(^|gY%oUX0a1b~$D71N<%Tog!rz%!!F*jxF~H1+bqKyd_4K>G-e2@=Ty*o5 zd;auYk5)kxW9}8uwIkhgQCA1-bO~)MZDo69RkLP3I{9f8`YXW4FE0U|I-E%u z%(5kqDiz_GqSrXN$?jYAH4cX~os=bzai^{{o$%unuPa6Z#⋙Lek)hAwKiF^Mxek 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 z%0D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 NsVcrusF$;j_ Date: Mon, 7 Sep 2026 14:22:47 +0900 Subject: [PATCH 064/412] docs(devlog): plan code-mode host contract for routed models --- .../000_plan.md | 141 ++++++++++++ .../010_pre_call_contract.md | 139 ++++++++++++ .../020_post_hoc_annotation.md | 208 ++++++++++++++++++ .../030_docs_and_delivery.md | 74 +++++++ 4 files changed, 562 insertions(+) create mode 100644 devlog/_plan/260907_code_mode_host_contract/000_plan.md create mode 100644 devlog/_plan/260907_code_mode_host_contract/010_pre_call_contract.md create mode 100644 devlog/_plan/260907_code_mode_host_contract/020_post_hoc_annotation.md create mode 100644 devlog/_plan/260907_code_mode_host_contract/030_docs_and_delivery.md diff --git a/devlog/_plan/260907_code_mode_host_contract/000_plan.md b/devlog/_plan/260907_code_mode_host_contract/000_plan.md new file mode 100644 index 0000000000..6f85ef9c4d --- /dev/null +++ b/devlog/_plan/260907_code_mode_host_contract/000_plan.md @@ -0,0 +1,141 @@ +# 000 — Code-mode host contract for routed models: plan + +## Loop-spec + +- Loop archetype: satisfy-spec repair (verifier-defined). No optimization loop. +- Trigger: xai/grok-4.6 retrospective (2026-09-07) on a routed native-Responses Codex session. The + model hit four Codex host contracts that OpenCodex neither states before the first call nor + explains after the failure, then abandoned the right tools for shell heredocs and sleep loops. +- Goal: a routed non-OpenAI model in Codex code mode learns the host's exact argument shape and + waiting protocol up front, and when it still trips, the tool result names the rule it broke. +- Non-goals: rewriting model JavaScript; repairing payloads (`apply-patch-envelope.ts`, + `code-mode-helper-compat.ts`, `bridge.ts`, `parser.ts` untouched); changing OpenAI/ChatGPT + destinations or compaction requests; Lab; GUI; release/version bumps. No local test suite, + typecheck, build, or install in this worktree (user instruction). Merge/release out of scope. +- Verifier: hosted `.github/workflows/ci.yml` on the exact PR head (test shards 1-4 + gates: + typecheck, privacy scan). Local: NOT RUN by instruction. Each conditional path names its + activation test in the decade docs; those tests ride the hosted shards. +- Stop condition: PR open against `dev` with exact-head CI green and receipt bound; then DONE. +- Memory artifact: this unit (`devlog/_plan/260907_code_mode_host_contract/`), the bound + goalplan `.codexclaw/goalplans/code-mode-host-contract-for-routed-models-shared/`, PR body. +- Expected terminal outcomes: DONE (PR open, CI green); NOOP if the contract already exists + (ruled out below); BLOCKED if GitHub/CI infrastructure fails after retries; UNSAFE if a change + would rewrite JavaScript or widen a fail-open write; NEEDS_HUMAN for merge. +- Escalation: main reclaims a slice after two distinct agents fail its packet; pushing a slice to + a worker requires a P-phase amendment. Every dispatch uses `gpt-6-astra` reasoning `high`. +- HOTL bounds: write scope is this worktree on `codex/code-mode-host-contract`; tools are + git/gh/rg/read + `tools.apply_patch`; no token or wall-clock budget was set by the user. + +## Incident (what actually broke) + +All four strings below were read from the installed Codex 0.153.2 binaries +(`codex` and `codex-code-mode-host`, `strings -n 8`), so the wording here is the host's, not a guess. + +| # | Model action | Host response | Where OpenCodex says nothing today | +|---|---|---|---| +| 1 | `tools.apply_patch({ input: "..." })` | `\`apply_patch\` expects a string input` | Nudge says "host-executed" and describes markers, never the argument type | +| 2 | patch built in a template literal opening with a newline | `The first line of the patch must be '*** Begin Patch'` (also `The last line of the patch must be '*** End Patch'`) | Nudge says "begin exactly with" but not that leading whitespace/newline counts | +| 3 | `for i in 1..20; sleep 1` inside one `exec_command` | (no error; the turn just blocks) | No sentence about `session_id` + `write_stdin` with empty `chars` | +| 4 | `import x from "..."` inside the isolate | `Unsupported import in exec: ...` | Cursor normalize matches lowercase `unsupported import in exec` only; shared nudge silent | + +After 1 and 2 the model stopped using `apply_patch` entirely. That is the same pattern +`devlog/_fin/260813_260813-nudge-apply-patch-forbid/` recorded: once the tool feels forbidden or +broken, routed models fall back to `python3`/`cat < --exit-status` on the PR head SHA | + +Single PR (one reviewable diff, ~150 source lines + tests); no stack (DEV-STACK-OPT-IN-01). + +## Accept criteria (goalplan c1–c4) + +- c1: pre-call guidance present in all three code-mode injection sites, absent for flat/OpenAI catalogs. +- c2: exec results carrying any of the four host markers are annotated on routed Responses, Kiro, Cursor; non-matching output byte-identical; already-annotated text not doubled. +- c3: PR open against `dev` with the template body; exact-head hosted CI success; receipt bound. +- c4: each A gate has an independent `gpt-6-astra` audit; `structure/04` and docs-site guide updated. + +## Verifiers (PLAN-VERIFIER-REAL-01) + +Local execution is forbidden for this unit, so every row below is NOT RUN locally and observed on +hosted CI. "Reads the target" is proven by import paths in the named test files: + +- `bun test tests/adapters/tool-catalog-nudge.test.ts` — imports `../../src/adapters/tool-catalog-nudge` and `exec-tool-result-normalize` (file lines 2-7). Reads wp1 target. +- `bun test tests/providers/cursor/cursor-tool-definitions.test.ts` — imports `tool-guidance` (line 762-ish `buildCursorToolGuidanceSystemNote`). Reads wp1 Cursor target. +- `bun test tests/responses/openai-responses-passthrough.test.ts` — imports `responses-code-mode` (line 5). Reads wp1+wp2 native target. +- `bun test tests/providers/kiro/kiro-adapter.test.ts` — imports `exec-tool-result-normalize` (line 16) and exercises `createKiroAdapter`. Reads wp1+wp2 Kiro target. +- `bun test tests/providers/cursor/cursor-toolresult-normalize.test.ts` — imports `tool-result-normalize`. Reads wp2 Cursor target. +- `bun test tests/adapters/exec-tool-result-normalize.test.ts` (NEW in wp2) — imports the shared module directly. +- `bun test tests/test-layout-tooling.test.ts` — reads `scripts/test-layout/layout.json` and `tests/fixtures/test-layout-expected.json`; fails if the new file is unregistered. +- `bun run typecheck`, `bun run privacy:scan` — CI `gates` job. + +## Enforcement bypass (PLAN-BYPASS-NAMED-01) + +This unit adds guidance, not enforcement. Tier: none (prose the model may ignore). Executing +surface: request translation in the adapters. Known bypass: the model disregards the sentence; +the host still rejects the call exactly as today. Residual risk: none beyond status quo; the +post-hoc annotation cannot make a failed call succeed. Wording: this is an "early warning", not +enforcement. Final layer: Codex host validation (unchanged). + +## SoT sync targets (SOT-SYNC-01) + +- `structure/04_transports-and-sidecars.md` paragraph at ~line 325 ("Native routed Responses code-mode turns also receive…") — extend with the host contract. +- `docs-site/src/content/docs/guides/codex-integration.md` "Routed local tools" section (~line 315) — one paragraph; translated locales are not edited (they must not contradict, and adding text to English only is additive). + diff --git a/devlog/_plan/260907_code_mode_host_contract/010_pre_call_contract.md b/devlog/_plan/260907_code_mode_host_contract/010_pre_call_contract.md new file mode 100644 index 0000000000..9b41dd1653 --- /dev/null +++ b/devlog/_plan/260907_code_mode_host_contract/010_pre_call_contract.md @@ -0,0 +1,139 @@ +# 010 — wp1: pre-call host contract sentence and its three injection sites + +Depends on 000_plan.md. Class C2 (conventional slice across an existing shared module and its +three known consumers; no new abstraction, no new seam). Loop archetype satisfy-spec. + +## MODIFY `src/adapters/exec-tool-result-normalize.ts` + +Append after `CODE_MODE_RESULT_ECHO_SENTENCE` (line ~117): + +```ts +/** + * The host rules a routed model most often breaks on its first code-mode edit or wait, stated + * BEFORE the call. Wording tracks the Codex host (0.153.2): `apply_patch` rejects a non-string + * argument with "expects a string input" and a body whose first line is not the marker with + * "The first line of the patch must be '*** Begin Patch'"; the isolate rejects ES imports with + * "Unsupported import in exec"; a long command yields a session_id for write_stdin polling. + * Live 2026-09-07: xai/grok-4.6 hit the first two, abandoned apply_patch for heredoc writes, + * blocked a turn in a shell sleep loop, and died once on an import. None of that is a model + * defect the proxy can repair (see devlog/_plan/260905_apply_patch_envelope_gap/010 MODE B); + * it is a contract the proxy had not stated. + */ +export const CODE_MODE_HOST_CONTRACT_SENTENCE = + "Host contract for the nested helpers: `tools.apply_patch(patch)` takes exactly one string, never an object such as `{input: ...}`; the string's first line must be exactly `*** Begin Patch` and its last line `*** End Patch` with no leading newline, indentation, or extra asterisks, so start the literal at the marker. The isolate has no `import`, `require`, or module loader — use only the `tools`, `text`, `notify`, `store`/`load`, and `ALL_TOOLS` globals. For a command that may outlive `yield_time_ms`, let `tools.exec_command` return a `session_id` and poll it with `tools.write_stdin({session_id, chars: \"\"})` on later calls instead of blocking a shell in a sleep loop."; +``` + +## MODIFY `src/adapters/tool-catalog-nudge.ts` + +Line 7 import: `import { CODE_MODE_HOST_CONTRACT_SENTENCE, CODE_MODE_RESULT_ECHO_SENTENCE } from "./exec-tool-result-normalize";` + +Line 124 code-mode branch. BEFORE (tail of the string): + +``` +... + CODE_MODE_RESULT_ECHO_SENTENCE + " Nested `tools.apply_patch(input)` is host-executed: ... rejected by Codex before the file is touched." +``` + +AFTER: + +``` +... + CODE_MODE_RESULT_ECHO_SENTENCE + " Nested `tools.apply_patch(input)` is host-executed: ... rejected by Codex before the file is touched. " + CODE_MODE_HOST_CONTRACT_SENTENCE +``` + +The flat-catalog branch (`If a listed tool exposes nested helpers…`) is unchanged: a shell bridge +echoes stdout and has no isolate, so the sentence would be false there. + +## MODIFY `src/adapters/cursor/tool-guidance.ts` + +Line 2 import: add `CODE_MODE_HOST_CONTRACT_SENTENCE`. + +Line 190 (`codeMode ? CODE_MODE_RESULT_ECHO_SENTENCE + " There is no \`require\`, …"`). BEFORE: + +```ts +codeMode + ? CODE_MODE_RESULT_ECHO_SENTENCE + " There is no `require`, no `module`, and no filesystem or network globals; reach the host only through the nested helpers." + : undefined, +``` + +AFTER: + +```ts +codeMode + ? CODE_MODE_RESULT_ECHO_SENTENCE + " There is no `require`, no `module`, and no filesystem or network globals; reach the host only through the nested helpers. " + CODE_MODE_HOST_CONTRACT_SENTENCE + : undefined, +``` + +## MODIFY `src/adapters/responses-code-mode.ts` + +Line 3 import: add `CODE_MODE_HOST_CONTRACT_SENTENCE`. + +Instructions (line ~46). BEFORE: + +```ts +instructions: instructions.includes(CODE_MODE_RESULT_ECHO_SENTENCE) + ? instructions : [instructions, CODE_MODE_RESULT_ECHO_SENTENCE].filter(Boolean).join("\n\n"), +``` + +AFTER (idempotent per sentence, so a replayed body that already carries the echo sentence but +not the contract gains only the missing one): + +```ts +instructions: appendMissing(instructions, [CODE_MODE_RESULT_ECHO_SENTENCE, CODE_MODE_HOST_CONTRACT_SENTENCE]), +``` + +with a module-local helper: + +```ts +function appendMissing(instructions: string, sentences: readonly string[]): string { + return sentences.reduce( + (acc, sentence) => acc.includes(sentence) ? acc : [acc, sentence].filter(Boolean).join("\n\n"), + instructions, + ); +} +``` + +The exec `input` parameter description (line 27) keeps only the echo sentence: it is a schema +string, and Kiro-style description limiters bound injected instructions, not parameter text, but +the contract is long and belongs in `instructions` where the existing test already asserts. + +Activation scenario: any routed native Responses request whose visible catalog has a bare freeform +`exec` and no bare shell bridge, to a non-OpenAI destination, not a compaction request — the +exact gate at `responses-code-mode.ts:35-37`. Observable effect: `wire.instructions` ends with the +contract sentence. + +## TESTS (updated in place; no new file in wp1) + +`tests/adapters/tool-catalog-nudge.test.ts` +- In `"defines nested helper names as non-callable unless separately listed"` add: + `expect(note).toContain(CODE_MODE_HOST_CONTRACT_SENTENCE);` and + `expect(note).toContain("write_stdin({session_id, chars: \"\"})");`. +- In `"keeps the generic nested-helper parent-tool rule when exec is not listed"` add + `expect(note).not.toContain("Host contract for the nested helpers");`. +- Import the new constant on line 7. + +`tests/providers/cursor/cursor-tool-definitions.test.ts` +- In `"teaches the nested-helper contract instead of a top-level shell bridge"` (line ~754) add + `expect(note).toContain("takes exactly one string");` and + `expect(note).toContain("write_stdin");`. +- In `"keeps flat-catalog shell-bridge guidance when a bare bridge is advertised"` add + `expect(note).not.toContain("Host contract for the nested helpers");`. + +`tests/responses/openai-responses-passthrough.test.ts` +- `"first native request carries the echo rule…"` line 54 BEFORE: + `expect(wire.instructions).toBe(\`Keep this instruction.\n\n${CODE_MODE_RESULT_ECHO_SENTENCE}\`);` + AFTER: + `expect(wire.instructions).toBe(\`Keep this instruction.\n\n${CODE_MODE_RESULT_ECHO_SENTENCE}\n\n${CODE_MODE_HOST_CONTRACT_SENTENCE}\`);` +- `"does not duplicate instructions…"` already asserts idempotence; add a case where the body's + instructions already contain the echo sentence and assert exactly one contract sentence is appended. +- `"official OpenAI and non-code-mode catalogs remain untouched"`: add + `expect(JSON.stringify(wire)).not.toContain("Host contract for the nested helpers")` inside the native loop. + +`tests/providers/kiro/kiro-adapter.test.ts` +- In `"names ALL_TOOLS when a freeform exec is advertised…"` (line ~1817) add + `expect(content).toContain("Host contract for the nested helpers");` — proves the sentence + survives Kiro's `boundedInjectedInstruction` (16 384 chars) on the real wire prompt. + +## Verification (C, hosted only) + +NOT RUN locally by instruction. Hosted CI shards run the four files above; `gates` runs typecheck +and privacy scan. Evidence: `gh run list --branch codex/code-mode-host-contract` + `gh run view --exit-status`. + diff --git a/devlog/_plan/260907_code_mode_host_contract/020_post_hoc_annotation.md b/devlog/_plan/260907_code_mode_host_contract/020_post_hoc_annotation.md new file mode 100644 index 0000000000..105a592c2d --- /dev/null +++ b/devlog/_plan/260907_code_mode_host_contract/020_post_hoc_annotation.md @@ -0,0 +1,208 @@ +# 020 — wp2: post-hoc annotation of host failures on exec results + +Depends on 010 (the pre-call sentence names the same rules this half explains after the fact; the +two must share wording, which is why both live in one module). Class C2. + +## MODIFY `src/adapters/exec-tool-result-normalize.ts` + +Append after `CODE_MODE_HOST_CONTRACT_SENTENCE`: + +```ts +/** + * Post-hoc half of the host contract: the four host strings a routed model reads inside a + * non-error exec result, each paired with the rule it broke. Markers are compared + * case-insensitively because the host writes "Unsupported import in exec: " while + * earlier Cursor guidance matched the lowercase form; one table, one owner, so the + * recovery text can never drift from the pre-call sentence above. + */ +export const CODE_MODE_HOST_FAILURE_GUIDANCE: ReadonlyArray<{ marker: string; guidance: string }> = [ + { + marker: "expects a string input", + guidance: "tools.apply_patch takes exactly one string argument; pass the patch text itself, not an object such as {input: ...}.", + }, + { + marker: "the first line of the patch must be", + guidance: "The patch string must begin at `*** Begin Patch` with no leading newline, indentation, or extra asterisks; start the literal on the marker line.", + }, + { + marker: "the last line of the patch must be", + guidance: "The patch string must end with `*** End Patch` as its final line, with no trailing text or extra asterisks.", + }, + { + marker: "unsupported import in exec", + guidance: "Imports are not available in this exec context; use the injected globals (tools, text, notify, store, load, ALL_TOOLS) instead.", + }, +]; + +const HOST_FAILURE_RECOVERY_PREFIX = "[recovery: "; + +/** + * Append a one-line recovery hint when an exec-bridge result carries a known host failure string. + * Returns undefined when the result is not an exec-bridge tool, no marker matches, or a recovery + * line is already present, so callers keep their own fallback and never double-annotate. + */ +export function annotateCodeModeHostFailure( + text: string, + options: { toolName?: string; toolNamespace?: string } = {}, +): string | undefined { + if (!isCodexExecBridgeTool(options.toolName, options.toolNamespace)) return undefined; + if (text.includes(HOST_FAILURE_RECOVERY_PREFIX)) return undefined; + const lower = text.toLowerCase(); + const hit = CODE_MODE_HOST_FAILURE_GUIDANCE.find(({ marker }) => lower.includes(marker)); + return hit ? `${text}\n${HOST_FAILURE_RECOVERY_PREFIX}${hit.guidance}]` : undefined; +} +``` + +The Cursor guidance string for the import row is kept byte-identical to today's +(`"Imports are not available in this exec context; use the injected globals instead."` extended with +the global list) so `cursor-toolresult-normalize.test.ts:101` (`"injected globals"`) still matches. + +## MODIFY `src/adapters/responses-code-mode.ts` + +Line 55 BEFORE: + +```ts +const normalized = text === undefined ? undefined : normalizeEmptyExecToolResultText(text, { toolName: "exec" }); +``` + +AFTER: + +```ts +const normalized = text === undefined + ? undefined + : normalizeEmptyExecToolResultText(text, { toolName: "exec" }) + ?? annotateCodeModeHostFailure(text, { toolName: "exec" }); +``` + +Import `annotateCodeModeHostFailure` on line 3. Empty-wrapper first: an empty result can never +carry a marker, so the order is only for clarity. Activation: paired `custom_tool_call_output` +whose text contains e.g. `\`apply_patch\` expects a string input`; observable effect: output ends +with `[recovery: tools.apply_patch takes exactly one string argument…]`, and `input[0]` (the +program) is the same object reference as before. + +## MODIFY `src/adapters/kiro.ts` + +Line 47 import: add `annotateCodeModeHostFailure`. + +Lines 758-762 BEFORE: + +```ts +const normalizedExecText = normalizeEmptyExecToolResultText(text, { + toolName: tr.toolName, + toolNamespace: tr.toolNamespace, +}); +const resultText = normalizedExecText ?? (text.trim() ? text : KIRO_EMPTY_TOOL_RESULT_MESSAGE); +``` + +AFTER: + +```ts +const execOptions = { toolName: tr.toolName, toolNamespace: tr.toolNamespace }; +const normalizedExecText = normalizeEmptyExecToolResultText(text, execOptions) + ?? annotateCodeModeHostFailure(text, execOptions); +const resultText = normalizedExecText ?? (text.trim() ? text : KIRO_EMPTY_TOOL_RESULT_MESSAGE); +``` + +`rawGroupText` (line 774) already keeps `text` whenever `normalizedExecText !== EMPTY_EXEC_OUTPUT_MESSAGE`, +so the adjacent-result grouping path carries the RAW failure text; the annotated text is what the +single-result path emits. Line 774 is changed so a grouped result carries the annotated text too: + +BEFORE: `? text : undefined;` AFTER: `? (normalizedExecText ?? text) : undefined;` + +(For the empty-wrapper case `normalizedExecText === EMPTY_EXEC_OUTPUT_MESSAGE` short-circuits the +outer condition first, so that branch is unchanged.) + +## MODIFY `src/adapters/cursor/tool-result-normalize.ts` + +Import `CODE_MODE_HOST_FAILURE_GUIDANCE` from `../exec-tool-result-normalize`. + +`RUNTIME_FAILURE_GUIDANCE` (lines 50-67): DELETE the `unsupported import in exec` entry and spread +the shared table instead: + +```ts +const RUNTIME_FAILURE_GUIDANCE: ReadonlyArray<{ marker: string; guidance: string }> = [ + { marker: "SkyComputerUseError", guidance: "…" }, + { marker: "sky is not defined", guidance: "…" }, + { marker: "has already been declared", guidance: "…" }, + ...CODE_MODE_HOST_FAILURE_GUIDANCE, +]; +``` + +Loop at line 109 BEFORE: `if (text.includes(marker))` AFTER: compare against `text.toLowerCase()` +for the shared rows only — simplest correct form is to lowercase both sides for every row, since the +three Cursor markers contain no case-sensitive collisions (`SkyComputerUseError` lowercased still +matches only itself). Cursor policy (`isError: true` on a match) is unchanged; the shared helper is +not used here because Cursor owns its `isError` decision. + +## NEW `tests/adapters/exec-tool-result-normalize.test.ts` + +```ts +import { describe, expect, test } from "bun:test"; +import { + CODE_MODE_HOST_CONTRACT_SENTENCE, + CODE_MODE_HOST_FAILURE_GUIDANCE, + annotateCodeModeHostFailure, +} from "../../src/adapters/exec-tool-result-normalize"; + +describe("code-mode host failure annotation", () => { + test.each(CODE_MODE_HOST_FAILURE_GUIDANCE.map(row => [row.marker, row.guidance]))( + "annotates an exec result carrying %p", (marker, guidance) => { + const text = `Script failed\nOutput:\nError: ${marker.toUpperCase()}`; + const out = annotateCodeModeHostFailure(text, { toolName: "exec" }); + expect(out).toBe(`${text}\n[recovery: ${guidance}]`); + }); + + test("matches the host's real capitalisation for imports", () => { + const out = annotateCodeModeHostFailure("Unsupported import in exec: node:fs", { toolName: "exec" }); + expect(out).toContain("injected globals"); + }); + + test("leaves non-exec tools, non-matching text and already-annotated text alone", () => { + expect(annotateCodeModeHostFailure("expects a string input", { toolName: "read_file" })).toBeUndefined(); + expect(annotateCodeModeHostFailure("all good", { toolName: "exec" })).toBeUndefined(); + const once = annotateCodeModeHostFailure("expects a string input", { toolName: "exec" })!; + expect(annotateCodeModeHostFailure(once, { toolName: "exec" })).toBeUndefined(); + }); + + test("every failure row is a rule the pre-call sentence already states", () => { + // One owner, two halves: a model must never be told one thing before the call and another after. + expect(CODE_MODE_HOST_CONTRACT_SENTENCE).toContain("exactly one string"); + expect(CODE_MODE_HOST_CONTRACT_SENTENCE).toContain("*** Begin Patch"); + expect(CODE_MODE_HOST_CONTRACT_SENTENCE).toContain("*** End Patch"); + expect(CODE_MODE_HOST_CONTRACT_SENTENCE).toContain("no `import`"); + }); +}); +``` + +Register: `scripts/test-layout/layout.json` → `explicit`: `"exec-tool-result-normalize.test.ts": "adapters"` +(alphabetical, after `"exec-…"` neighbours or before `"identity-…"`); same key in +`tests/fixtures/test-layout-expected.json`. `tests/test-layout-tooling.test.ts` names a missing one. + +## Updated tests + +`tests/responses/openai-responses-passthrough.test.ts` — add to the code-mode describe: + +```ts +test("annotates a paired exec result that carries a host failure string", () => { + const failure = "Script failed\nWall time 0.1 seconds\nOutput:\nError: `apply_patch` expects a string input"; + const body = raw(failure); + const wire = JSON.parse(createResponsesPassthroughAdapter(routed).buildRequest(parseRequest(body)).body); + expect(wire.input[1].output).toBe(`${failure}\n[recovery: tools.apply_patch takes exactly one string argument; pass the patch text itself, not an object such as {input: ...}.]`); + expect(JSON.parse(wire.input[0].arguments).input).toBe(body.input[0].input); +}); +``` + +`tests/providers/kiro/kiro-adapter.test.ts` — beside the `EMPTY_EXEC_OUTPUT_MESSAGE` case at +line ~336, add one toolResult with `toolName: "exec"` and content +`"The first line of the patch must be '*** Begin Patch'"`; assert the emitted Kiro tool-result +text ends with `[recovery: The patch string must begin at …]`. + +`tests/providers/cursor/cursor-toolresult-normalize.test.ts` — line 101 row stays; add +`["Unsupported import in exec: node:fs", "injected globals"]` and +`["\`apply_patch\` expects a string input", "exactly one string"]` to the `test.each` table. + +## Verification (C, hosted only) + +NOT RUN locally. Hosted shards run the new and updated files; `tests/test-layout-tooling.test.ts` +proves registration. Activation for each conditional row is the marker-specific test above. + diff --git a/devlog/_plan/260907_code_mode_host_contract/030_docs_and_delivery.md b/devlog/_plan/260907_code_mode_host_contract/030_docs_and_delivery.md new file mode 100644 index 0000000000..8b7a848c69 --- /dev/null +++ b/devlog/_plan/260907_code_mode_host_contract/030_docs_and_delivery.md @@ -0,0 +1,74 @@ +# 030 — wp3: SoT sync, push, PR, exact-head CI receipt + +Depends on 020. Class C2 for the docs; the push/PR step is external state and is authorized by +the user for this branch only ("no verify로 푸시", "pr올려봐"). Merge is not authorized. + +## MODIFY `structure/04_transports-and-sidecars.md` + +After the paragraph ending "…or reconstruct output that the code-mode host never emitted." (~line 331) +add one paragraph: + +``` +Routed code-mode turns also carry the host contract for the nested helpers, stated in the same three +injection sites as the result-emission rule (shared catalog nudge, Cursor code-mode guidance, native +routed Responses instructions): `tools.apply_patch` takes one string whose first and last lines are +the bare patch markers, the isolate has no `import`/`require`, and a command that outlives +`yield_time_ms` is polled through `write_stdin` with empty `chars` rather than a shell sleep loop. +When a paired exec result still carries one of the host's failure strings ("expects a string +input", "The first line of the patch must be", "The last line of the patch must be", "Unsupported +import in exec"), the routed Responses, Kiro, and Cursor result paths append a one-line recovery +hint naming the broken rule. Both halves live in `src/adapters/exec-tool-result-normalize.ts` so +the pre-call and post-hoc wording cannot drift. Nothing rewrites the model's JavaScript or its +patch payload; the host still rejects the call exactly as before. +``` + +Add a Decision Log entry in the file's existing format (목적과 의도 / 기존 구현 및 제약 조건 / +검토한 주요 대안 / 선택한 방식 / 장점, 단점 및 영향) recording: purpose = stop routed models +abandoning apply_patch after two host rejections; alternatives = repair the argument shape in the +proxy (rejected: MODE B ambiguity, fail-open write), Cursor-only fix (rejected: incident was native +Responses); chosen = shared pair in one module; impact = longer system prompt on code-mode turns +(~600 chars), no behaviour change for OpenAI destinations or flat catalogs. + +## MODIFY `docs-site/src/content/docs/guides/codex-integration.md` + +In "Routed local tools" after the apply_patch conversion paragraph (~line 331) add: + +``` +Routed code-mode turns are also told the host's rules for the nested helpers before the first +call — `tools.apply_patch` takes one string starting at `*** Begin Patch`, the isolate has no +`import`, and long-running commands are polled with `write_stdin` — and when a result still +carries one of the host's failure messages, opencodex appends a one-line hint naming the rule. +The model's code and patch text are never rewritten. +``` + +Translated locales (7 files) are not edited; the English source gains a paragraph they do not +contradict. + +## Delivery steps (t3b) + +1. `git add -A devlog/_plan/260907_code_mode_host_contract src tests scripts structure docs-site` + — inspect `git diff --cached --stat` before every commit; only this unit's paths. +2. Commits already made per work-phase with `--no-verify` (wp0 docs, wp1, wp2, wp3 docs). +3. `git push --no-verify -u origin codex/code-mode-host-contract`. +4. `gh pr create --base dev --title "fix(code-mode): state the host contract for nested helpers and annotate host failures" --body-file .tmp/pr-body.md` + — body follows `.github/PULL_REQUEST_TEMPLATE.md` (Summary / Verification / Checklist), lists + local checks as NOT RUN, names hosted CI as the verifier. No `gui` mention (no screenshot rule). +5. Poll: `gh run list --branch codex/code-mode-host-contract --json databaseId,headSha,status,conclusion` + via `exec_command` short calls (each < 30 s); `gh run watch` is NOT used inside one call. +6. Receipt: at phase C, `cxc receipt test --session --cwd -- gh run view --exit-status` + where `` is the Cross-platform CI run whose `headSha` equals `git rev-parse HEAD`. + If the head moves (review fix), a fresh run and fresh receipt are required. + +## Verification (C) + +- `gh run view --exit-status` exit 0 on the exact head; `gh pr view --json headRefOid` equals HEAD. +- `gh pr checks ` lists test 1/4..4/4, gates, storage policy, api usage as pass. +- Local suite / typecheck / build: NOT RUN (instruction). + +## D record + +Append `040_delivery_record.md` with PR number, head SHA, CI run id, per-job results, what did not +improve (LOOP-PESSIMIST-01: prose cannot force compliance; effect on real Grok defect rate is +unmeasured until a live re-probe), and the residual: Anthropic/Google/OpenAI-chat/command-code +tool-result paths do not annotate host failures because they have no exec-result seam today. + From 3d901b5220a0d701edb5d3cf325676edb2044fd2 Mon Sep 17 00:00:00 2001 From: DaedalGames Date: Mon, 7 Sep 2026 14:26:57 +0900 Subject: [PATCH 065/412] fix(cli): retain pending Codex readiness in account output --- src/cli/account-api.ts | 4 ++++ src/cli/account-extended.ts | 1 + src/cli/account.ts | 1 + tests/cli/cli-account.test.ts | 18 ++++++++++++++++++ 4 files changed, 24 insertions(+) diff --git a/src/cli/account-api.ts b/src/cli/account-api.ts index c1c625c882..afd55265cc 100644 --- a/src/cli/account-api.ts +++ b/src/cli/account-api.ts @@ -22,6 +22,8 @@ export interface AccountRow { masked?: string; active: boolean; needsReauth?: boolean; + /** Registered credential that is still excluded from routing until validation completes. */ + validationPending?: boolean; /** Codex pool selection order, higher used earlier. Absent where ordering does not apply. */ priority?: number; quota?: CodexQuotaDto | null; @@ -237,6 +239,7 @@ interface CodexAccountDto { plan?: string; isMain?: boolean; needsReauth?: boolean; + health?: { reason?: string }; priority?: number; quota?: CodexQuotaDto | null; quotaRefresh?: unknown; @@ -302,6 +305,7 @@ export async function fetchCodexRows( plan: a.plan, active: a.id === activeId, needsReauth: a.needsReauth, + ...(a.health?.reason === "validation_pending" ? { validationPending: true } : {}), priority: typeof a.priority === "number" ? a.priority : 0, paused: a.paused === true, ...(includeQuota ? { diff --git a/src/cli/account-extended.ts b/src/cli/account-extended.ts index f2a477a702..628de6c8b7 100644 --- a/src/cli/account-extended.ts +++ b/src/cli/account-extended.ts @@ -264,6 +264,7 @@ function refreshLine(row: FamilyRows["rows"][number]): string { const quotaText = row.quota ? quotaParts(row.quota).join(" ") : ""; parts.push(quotaText.length > 0 ? quotaText : "quota: unknown"); if (row.needsReauth) parts.push("needs-reauth"); + if (row.validationPending) parts.push("validation-pending (routing disabled)"); return parts.filter(Boolean).join(" "); } diff --git a/src/cli/account.ts b/src/cli/account.ts index acda3639b8..041e99830b 100644 --- a/src/cli/account.ts +++ b/src/cli/account.ts @@ -99,6 +99,7 @@ function statusText(row: AccountRow): string { if (row.paused) parts.push("paused"); if (row.active) parts.push(row.type === "codex" ? "selected" : "active"); if (row.needsReauth) parts.push("needs-reauth"); + if (row.validationPending) parts.push("validation-pending"); return parts.join(" "); } diff --git a/tests/cli/cli-account.test.ts b/tests/cli/cli-account.test.ts index 8b464849e2..566e0d08c8 100644 --- a/tests/cli/cli-account.test.ts +++ b/tests/cli/cli-account.test.ts @@ -586,6 +586,24 @@ afterEach(() => { }); describe("ocx account CLI (issue #180 matrix)", () => { + test.each([100, 12])("pending validation stays visible at %s percent usage without exposing raw health details", async weeklyPercent => { + codexAccounts = [{ id: "pending", email: "p***@example.test", quota: { weeklyPercent }, + health: { status: "warning", reason: "validation_pending", message: RAW_SENTINEL } }]; + for (const command of [["list", "openai"], ["refresh", "openai"]]) { + const human = await run(command); + expect(human.code).toBe(0); + expect(human.stdout).toContain("validation-pending"); + expect(human.output).not.toContain(RAW_SENTINEL); + const machine = await run([...command, "--json"]); + expect(JSON.parse(machine.stdout).accounts[0].validationPending).toBe(true); + expect(machine.output).not.toContain(RAW_SENTINEL); + } + codexAccounts = [{ id: "pending", quota: { weeklyPercent: 12 }, health: { status: "healthy" } }]; + const recovered = await run(["refresh", "openai", "--json"]); + expect(JSON.parse(recovered.stdout).accounts[0]).not.toHaveProperty("validationPending"); + expect((await run(["refresh", "openai"])).stdout).not.toContain("validation-pending"); + }); + test("main quota diagnostics survive opt-in JSON without copying upstream data", async () => { codexAccounts = [{ id: "__main__", isMain: true, quota: null, quotaRefresh: { status: "http_error", httpStatus: 503, message: RAW_SENTINEL } }]; From 25798a590e747c64a2ad0ebb4e6a1d251da93846 Mon Sep 17 00:00:00 2001 From: DaedalGames Date: Mon, 7 Sep 2026 14:32:20 +0900 Subject: [PATCH 066/412] fix(codex): report deferred readiness when login completes --- gui/src/codex-account-mutation.ts | 3 +++ gui/src/components/CodexAccountPool.tsx | 8 +++++--- .../components/use-add-codex-account-oauth.ts | 1 + gui/src/pages/Providers.tsx | 6 +++--- .../providers-codex-completion-toast.test.tsx | 12 ++++++++++++ src/cli/account-auth.ts | 9 ++++++++- src/codex/auth-api.ts | 6 +++++- tests/cli/cli-account.test.ts | 18 ++++++++++++++++++ tests/codex-integration/codex-auth-api.test.ts | 6 ++++++ 9 files changed, 61 insertions(+), 8 deletions(-) diff --git a/gui/src/codex-account-mutation.ts b/gui/src/codex-account-mutation.ts index 1c90557cd4..4d0bea4faa 100644 --- a/gui/src/codex-account-mutation.ts +++ b/gui/src/codex-account-mutation.ts @@ -1,6 +1,7 @@ /** Privacy-safe completion state shared by account mutation UI flows. */ export interface CodexAccountMutationCompletion { catalogRefreshPending: boolean; + validationPending?: boolean; } /** Project only the public completion flag from an account mutation response. */ @@ -9,7 +10,9 @@ export function codexAccountMutationCompletion(value: unknown): CodexAccountMuta return { catalogRefreshPending: false }; } const descriptor = Object.getOwnPropertyDescriptor(value, "catalogRefreshPending"); + const validation = Object.getOwnPropertyDescriptor(value, "validationPending"); return { + ...(validation && "value" in validation && validation.value === true ? { validationPending: true } : {}), catalogRefreshPending: descriptor !== undefined && "value" in descriptor && descriptor.value === true, diff --git a/gui/src/components/CodexAccountPool.tsx b/gui/src/components/CodexAccountPool.tsx index 03a486f765..f211f1c689 100644 --- a/gui/src/components/CodexAccountPool.tsx +++ b/gui/src/components/CodexAccountPool.tsx @@ -199,13 +199,15 @@ export default function CodexAccountPool({ apiBase, accountModeState = null, ban const handleAccountAdded = useCallback((completion: CodexAccountMutationCompletion) => { void controller.syncAfterAccountAdded(); showActionFeedback( - t(completion.catalogRefreshPending + t(completion.validationPending + ? "pws.healthLabel.validationPending" + : completion.catalogRefreshPending ? "codexAuth.catalogRefreshPending" : "codexAuth.accountAdded"), - completion.catalogRefreshPending ? "warn" : "ok", + completion.validationPending || completion.catalogRefreshPending ? "warn" : "ok", ); closeAddModal(); - setModelsNotice({ catalogRefreshPending: completion.catalogRefreshPending }); + setModelsNotice(completion.validationPending ? null : { catalogRefreshPending: completion.catalogRefreshPending }); }, [closeAddModal, controller, showActionFeedback, t]); const setActive = async (id: string | null) => { diff --git a/gui/src/components/use-add-codex-account-oauth.ts b/gui/src/components/use-add-codex-account-oauth.ts index 5a5796000c..5c4a9bd241 100644 --- a/gui/src/components/use-add-codex-account-oauth.ts +++ b/gui/src/components/use-add-codex-account-oauth.ts @@ -227,6 +227,7 @@ export function useAddCodexAccountOAuth({ status: string; error?: string; catalogRefreshPending?: unknown; + validationPending?: unknown; }>(stRes); if (!aliveRef.current || pollSession.signal.aborted) return; if (!st) { diff --git a/gui/src/pages/Providers.tsx b/gui/src/pages/Providers.tsx index 41795a6098..53d303efd8 100644 --- a/gui/src/pages/Providers.tsx +++ b/gui/src/pages/Providers.tsx @@ -259,8 +259,8 @@ export default function Providers({ apiBase }: { apiBase: string }) { }, []); const notifyCodexCompletion = useCallback((completion: CodexAccountMutationCompletion) => { - if (completion.catalogRefreshPending) { - setStatus(t("codexAuth.catalogRefreshPending")); + if (completion.validationPending || completion.catalogRefreshPending) { + setStatus(t(completion.validationPending ? "pws.healthLabel.validationPending" : "codexAuth.catalogRefreshPending")); setStatusOk(false); setStatusTone("warn"); setStatusRevision(revision => revision + 1); @@ -708,7 +708,7 @@ export default function Providers({ apiBase }: { apiBase: string }) { onCodexAdded={(completion) => { setCodexLoginOpen(false); notifyCodexCompletion(completion); - modelsNotice.open("openai", !config.providers.openai, completion.catalogRefreshPending); + if (!completion.validationPending) modelsNotice.open("openai", !config.providers.openai, completion.catalogRefreshPending); void fetchConfig(); void fetchOauth(); void fetchProviderQuotas(true); diff --git a/gui/tests/providers-codex-completion-toast.test.tsx b/gui/tests/providers-codex-completion-toast.test.tsx index 1852f8884f..01f56e521f 100644 --- a/gui/tests/providers-codex-completion-toast.test.tsx +++ b/gui/tests/providers-codex-completion-toast.test.tsx @@ -31,6 +31,7 @@ let host: HTMLElement; let root: Root | null; let requests: Array<{ path: string; method: string }>; let catalogRefreshPending: boolean; +let validationPending: boolean; function pathCount(path: string): number { return requests.filter(request => request.path.startsWith(`${API_BASE}${path}`)).length; @@ -63,6 +64,7 @@ beforeEach(() => { requests = []; catalogRefreshPending = true; + validationPending = false; Object.defineProperty(globalThis, "fetch", { configurable: true, value: async (input: RequestInfo | URL, init?: RequestInit) => { @@ -110,6 +112,7 @@ beforeEach(() => { return Response.json({ status: "done", catalogRefreshPending, + validationPending, privateDetail: "private-account-detail", }); } @@ -224,6 +227,15 @@ test("pending Codex completion stays amber, private, dismissible, and refreshes expect(testWindow.document.querySelector(".toast-notice")).toBeNull(); }); +test("quota-pending registration stays amber and does not offer model selection", async () => { + validationPending = true; + await completeCodexLogin(); + const warning = testWindow.document.querySelector(".toast-notice.notice-warn"); + expect(warning?.textContent).toContain("Validation pending"); + expect(host.querySelector('[role="dialog"]')?.textContent ?? "").not.toContain("Choose models"); + expect(testWindow.document.body.textContent).not.toContain("private-account-detail"); +}); + test("completed Codex catalog convergence reports clean success without sync advice", async () => { catalogRefreshPending = false; await completeCodexLogin(); diff --git a/src/cli/account-auth.ts b/src/cli/account-auth.ts index f807659cb8..f8e95c6f12 100644 --- a/src/cli/account-auth.ts +++ b/src/cli/account-auth.ts @@ -154,7 +154,14 @@ async function login(argv: string[], deps: RuntimeApiDeps): Promise { {}, deps, ); if (state.status === "done") { - printData({ ...state, modelSelection: modelSelectionNextSteps("openai") }, wantsJson, [`Logged in${state.email ? ` as ${String(state.email)}` : ""}.`, ...modelSelectionGuidance("openai")]); + if (state.validationPending === true) { + printData({ ...state, recoveryCommand: "ocx account refresh openai" }, wantsJson, [ + "Account registered; validation pending (routing disabled).", + "After quota recovers, run 'ocx account refresh openai' to complete validation.", + ]); + } else { + printData({ ...state, modelSelection: modelSelectionNextSteps("openai") }, wantsJson, [`Logged in${state.email ? ` as ${String(state.email)}` : ""}.`, ...modelSelectionGuidance("openai")]); + } if (!wantsJson) warnIfCodexCatalogRefreshPending(state); return; } diff --git a/src/codex/auth-api.ts b/src/codex/auth-api.ts index a446a1da6a..44e6e2d8a0 100644 --- a/src/codex/auth-api.ts +++ b/src/codex/auth-api.ts @@ -186,6 +186,7 @@ interface CodexLoginStateRow { code?: string; needsReauth?: boolean; catalogRefreshPending?: boolean; + validationPending?: boolean; doneAt?: number; } const codexAuthLoginState = new Map(); @@ -2720,6 +2721,7 @@ export async function handleCodexAuthAPI( status: "done", accountId, email, + ...(warmup.validatedAt === undefined ? { validationPending: true } : {}), ...(catalogRefreshPending ? { catalogRefreshPending: true } : {}), doneAt: Date.now(), }); @@ -2832,7 +2834,9 @@ export async function handleCodexAuthAPI( && !isAccountNeedsReauth(accountId) && getCodexAccountCredential(accountId) ) { - return jsonResponse({ status: "done", accountId }); + return jsonResponse({ status: "done", accountId, + ...(readCodexAccountRecord(accountId)?.codexValidationPending ? { validationPending: true } : {}), + }); } return jsonResponse(st ? { ...st, email: maskEmail(st.email) ?? undefined } : { status: "expired" }); } diff --git a/tests/cli/cli-account.test.ts b/tests/cli/cli-account.test.ts index 566e0d08c8..00f492839b 100644 --- a/tests/cli/cli-account.test.ts +++ b/tests/cli/cli-account.test.ts @@ -2125,6 +2125,24 @@ describe("ocx account CLI (issue #180 matrix)", () => { expect(result.stdout).toContain("#3 unsupported (unsupported_format)"); }); + test("quota-pending login reports registration and recovery instead of ready model guidance", async () => { + codexLoginStatus = { status: "done", validationPending: true }; + const sleepSpy = spyOn(Bun, "sleep").mockImplementation(async () => {}); + try { + const human = await run(["login", "openai"]); + expect(human.code).toBe(0); + expect(human.stdout).toContain("validation pending (routing disabled)"); + expect(human.stdout).toContain("ocx account refresh openai"); + expect(human.stdout).not.toContain("Logged in"); + expect(human.stdout).not.toContain("ocx models"); + const machine = await run(["login", "openai", "--json"]); + expect(JSON.parse(machine.stdout)).toMatchObject({ validationPending: true, recoveryCommand: "ocx account refresh openai" }); + expect(JSON.parse(machine.stdout)).not.toHaveProperty("modelSelection"); + } finally { + sleepSpy.mockRestore(); + } + }); + test("pending Codex login keeps success and prints generic recovery guidance", async () => { codexLoginStatus = { status: "done", diff --git a/tests/codex-integration/codex-auth-api.test.ts b/tests/codex-integration/codex-auth-api.test.ts index c34a6f2a27..3a55cf0fd5 100644 --- a/tests/codex-integration/codex-auth-api.test.ts +++ b/tests/codex-integration/codex-auth-api.test.ts @@ -136,6 +136,7 @@ async function completeMockCodexOAuth(options: { accountId?: string; needsReauth?: boolean; catalogRefreshPending?: boolean; + validationPending?: boolean; }; }> { const oauth = await import("../../src/oauth"); @@ -4972,6 +4973,11 @@ describe("codex-auth API", () => { expect(warmups).toBe(0); expect(config.codexAccounts?.map(account => account.id)).toContain(accountId); expect(readCodexAccountRecord(accountId)?.codexValidationPending).toBe(true); + expect(added.state.validationPending).toBe(true); + const recoveredStatus = new Request(`http://localhost/api/codex-auth/login-status?flowId=forgotten&accountId=${accountId}`); + expect(await (await handleCodexAuthAPI(recoveredStatus, new URL(recoveredStatus.url), config))?.json()).toMatchObject({ + status: "done", validationPending: true, + }); expect(readCodexAccountRecord(accountId)?.lastCodexValidatedAt).toBeUndefined(); expect(isAccountNeedsReauth(accountId)).toBe(false); expect(isCodexAccountUsable(config, accountId)).toBe(false); From 041aec04af744c2243be3e67b4e30a64aafa598e Mon Sep 17 00:00:00 2001 From: JUN <243035832+lidge-jun@users.noreply.github.com> Date: Mon, 7 Sep 2026 14:36:06 +0900 Subject: [PATCH 067/412] docs(devlog): fold audit round 1 into the code-mode host contract roadmap --- .../000_plan.md | 218 +++++++------ .../010_pre_call_contract.md | 206 +++++++----- .../020_post_hoc_annotation.md | 300 ++++++++++++------ .../030_docs_and_delivery.md | 74 +++-- 4 files changed, 481 insertions(+), 317 deletions(-) diff --git a/devlog/_plan/260907_code_mode_host_contract/000_plan.md b/devlog/_plan/260907_code_mode_host_contract/000_plan.md index 6f85ef9c4d..406c2c186d 100644 --- a/devlog/_plan/260907_code_mode_host_contract/000_plan.md +++ b/devlog/_plan/260907_code_mode_host_contract/000_plan.md @@ -1,141 +1,159 @@ # 000 — Code-mode host contract for routed models: plan +Revision 2 after audit round 1 (gpt-6-astra explorer, VERDICT: FAIL, 8 blockers). Synthesis and +dispositions are in the "Audit round 1" section at the end; the body below is the amended plan. + ## Loop-spec - Loop archetype: satisfy-spec repair (verifier-defined). No optimization loop. - Trigger: xai/grok-4.6 retrospective (2026-09-07) on a routed native-Responses Codex session. The - model hit four Codex host contracts that OpenCodex neither states before the first call nor - explains after the failure, then abandoned the right tools for shell heredocs and sleep loops. -- Goal: a routed non-OpenAI model in Codex code mode learns the host's exact argument shape and - waiting protocol up front, and when it still trips, the tool result names the rule it broke. -- Non-goals: rewriting model JavaScript; repairing payloads (`apply-patch-envelope.ts`, - `code-mode-helper-compat.ts`, `bridge.ts`, `parser.ts` untouched); changing OpenAI/ChatGPT - destinations or compaction requests; Lab; GUI; release/version bumps. No local test suite, - typecheck, build, or install in this worktree (user instruction). Merge/release out of scope. -- Verifier: hosted `.github/workflows/ci.yml` on the exact PR head (test shards 1-4 + gates: - typecheck, privacy scan). Local: NOT RUN by instruction. Each conditional path names its - activation test in the decade docs; those tests ride the hosted shards. -- Stop condition: PR open against `dev` with exact-head CI green and receipt bound; then DONE. -- Memory artifact: this unit (`devlog/_plan/260907_code_mode_host_contract/`), the bound - goalplan `.codexclaw/goalplans/code-mode-host-contract-for-routed-models-shared/`, PR body. -- Expected terminal outcomes: DONE (PR open, CI green); NOOP if the contract already exists - (ruled out below); BLOCKED if GitHub/CI infrastructure fails after retries; UNSAFE if a change - would rewrite JavaScript or widen a fail-open write; NEEDS_HUMAN for merge. + model hit Codex host contracts that OpenCodex neither states before the first call nor explains + after the failure, then abandoned the right tools for shell heredocs and sleep loops. +- Goal: a routed non-OpenAI model in Codex code mode learns the host's argument shape and waiting + protocol up front, and when it still trips, the exec result names the rule it broke. +- Non-goals: rewriting model JavaScript; new payload repair (`apply-patch-envelope.ts`, + `code-mode-helper-compat.ts`, `bridge.ts`, `parser.ts` untouched); OpenAI/ChatGPT destinations + or compaction requests; Lab; GUI; version bumps; annotation on Anthropic/Google/OpenAI-chat/ + command-code result paths (they have no exec-result seam today). No local test suite, typecheck, + build, or install in this worktree (user instruction). Merge/release out of scope. +- Verifier: hosted `.github/workflows/ci.yml` on the exact head of each pushed work-phase (PR + `pull_request` trigger; test shards 1-4 + `gates` typecheck/privacy). Local: NOT RUN. +- Stop condition: PR ready-for-review against `dev` with exact-head CI green and receipt bound. +- Memory artifact: this unit, the bound goalplan + `.codexclaw/goalplans/code-mode-host-contract-for-routed-models-shared/`, and the PR body. +- Expected terminal outcomes: DONE (PR open, CI green); NOOP ruled out below; BLOCKED if + GitHub/CI fails after retries; UNSAFE if a change would rewrite JavaScript or widen a fail-open + write; NEEDS_HUMAN for merge. - Escalation: main reclaims a slice after two distinct agents fail its packet; pushing a slice to - a worker requires a P-phase amendment. Every dispatch uses `gpt-6-astra` reasoning `high`. -- HOTL bounds: write scope is this worktree on `codex/code-mode-host-contract`; tools are - git/gh/rg/read + `tools.apply_patch`; no token or wall-clock budget was set by the user. - -## Incident (what actually broke) - -All four strings below were read from the installed Codex 0.153.2 binaries -(`codex` and `codex-code-mode-host`, `strings -n 8`), so the wording here is the host's, not a guess. + a worker requires a P-phase amendment. Every dispatch uses `gpt-6-astra`, reasoning `high`. +- HOTL bounds: write scope is this worktree on `codex/code-mode-host-contract`; push of that branch + and PR creation are authorized by the user; no token or wall-clock budget was set. -| # | Model action | Host response | Where OpenCodex says nothing today | -|---|---|---|---| -| 1 | `tools.apply_patch({ input: "..." })` | `\`apply_patch\` expects a string input` | Nudge says "host-executed" and describes markers, never the argument type | -| 2 | patch built in a template literal opening with a newline | `The first line of the patch must be '*** Begin Patch'` (also `The last line of the patch must be '*** End Patch'`) | Nudge says "begin exactly with" but not that leading whitespace/newline counts | -| 3 | `for i in 1..20; sleep 1` inside one `exec_command` | (no error; the turn just blocks) | No sentence about `session_id` + `write_stdin` with empty `chars` | -| 4 | `import x from "..."` inside the isolate | `Unsupported import in exec: ...` | Cursor normalize matches lowercase `unsupported import in exec` only; shared nudge silent | +## Incident and live host evidence -After 1 and 2 the model stopped using `apply_patch` entirely. That is the same pattern -`devlog/_fin/260813_260813-nudge-apply-patch-forbid/` recorded: once the tool feels forbidden or -broken, routed models fall back to `python3`/`cat <` (host string; capital U) | -`src/adapters/exec-tool-result-normalize.ts` already owns one "pair": a pre-call sentence -(`CODE_MODE_RESULT_ECHO_SENTENCE`) and a post-hoc repair (`EMPTY_EXEC_OUTPUT_MESSAGE`), kept in one -file so the two never drift. The pre-call sentence is injected by three consumers: +So the Grok report's "blank line before the template literal" was not itself the rejection; the +"first line" error fires for a decorated marker, a code fence, prose, or any non-marker first +token. The pre-call sentence and recovery hints below describe exactly that and do not claim the +host rejects surrounding whitespace. -- `src/adapters/tool-catalog-nudge.ts:124` (shared: Anthropic, Google, Kiro, OpenAI-chat, command-code) -- `src/adapters/cursor/tool-guidance.ts:187-190` (Cursor code-mode branch) -- `src/adapters/responses-code-mode.ts:27,47` (native routed Responses instructions + exec input description) +The fourth contract has no error string: a shell `for i in 1..20; sleep 1` inside one +`exec_command` simply blocks the call, while the host's own protocol is to let the call return a +`session_id` and poll with `tools.write_stdin({session_id, chars: ""})`. -and the post-hoc repair runs at: +After the two apply_patch rejections the model stopped using apply_patch entirely — the pattern +`devlog/_fin/260813_260813-nudge-apply-patch-forbid/` recorded: once the tool feels broken, routed +models fall back to `python3`/`cat < --exit-status` on the PR head SHA | +Each implementation phase ends with an authorized `git push --no-verify` and gets exact-head hosted +CI as its C verifier (audit blocker 5). The PR is opened as a draft at wp1 so `pull_request` CI +exists for every later head, and is marked ready in wp3. + +| WP | Doc | Slice | Depends on | C verifier | +|----|-----|-------|------------|-----------| +| wp0 | this file + 010/020/030 | docs-only roadmap | — | audit of the docs | +| wp1 | 010_pre_call_contract.md | shared sentence + three injection sites + tests; push; draft PR | wp0 | exact-head CI on the wp1 head | +| wp2 | 020_post_hoc_annotation.md | shared annotate helper + three result seams + tests; push | wp1 | exact-head CI on the wp2 head | +| wp3 | 030_docs_and_delivery.md | structure + docs-site sync, PR body, ready-for-review, receipt | wp2 | exact-head CI on the final head | -Single PR (one reviewable diff, ~150 source lines + tests); no stack (DEV-STACK-OPT-IN-01). +Single PR; no stack (DEV-STACK-OPT-IN-01). ## Accept criteria (goalplan c1–c4) - c1: pre-call guidance present in all three code-mode injection sites, absent for flat/OpenAI catalogs. -- c2: exec results carrying any of the four host markers are annotated on routed Responses, Kiro, Cursor; non-matching output byte-identical; already-annotated text not doubled. -- c3: PR open against `dev` with the template body; exact-head hosted CI success; receipt bound. +- c2: exec results carrying any of the four host markers are annotated on routed Responses, Kiro (single and grouped), Cursor (text only, `isError` unchanged); non-matching output byte-identical; already-annotated text not doubled on replay. +- c3: PR ready against `dev` with the template body; exact-head hosted CI success; receipt bound. - c4: each A gate has an independent `gpt-6-astra` audit; `structure/04` and docs-site guide updated. ## Verifiers (PLAN-VERIFIER-REAL-01) -Local execution is forbidden for this unit, so every row below is NOT RUN locally and observed on -hosted CI. "Reads the target" is proven by import paths in the named test files: +Local execution is forbidden for this unit, so every row is NOT RUN locally and observed on hosted +CI. "Reads the target" is proven by import chains: -- `bun test tests/adapters/tool-catalog-nudge.test.ts` — imports `../../src/adapters/tool-catalog-nudge` and `exec-tool-result-normalize` (file lines 2-7). Reads wp1 target. -- `bun test tests/providers/cursor/cursor-tool-definitions.test.ts` — imports `tool-guidance` (line 762-ish `buildCursorToolGuidanceSystemNote`). Reads wp1 Cursor target. -- `bun test tests/responses/openai-responses-passthrough.test.ts` — imports `responses-code-mode` (line 5). Reads wp1+wp2 native target. -- `bun test tests/providers/kiro/kiro-adapter.test.ts` — imports `exec-tool-result-normalize` (line 16) and exercises `createKiroAdapter`. Reads wp1+wp2 Kiro target. -- `bun test tests/providers/cursor/cursor-toolresult-normalize.test.ts` — imports `tool-result-normalize`. Reads wp2 Cursor target. -- `bun test tests/adapters/exec-tool-result-normalize.test.ts` (NEW in wp2) — imports the shared module directly. -- `bun test tests/test-layout-tooling.test.ts` — reads `scripts/test-layout/layout.json` and `tests/fixtures/test-layout-expected.json`; fails if the new file is unregistered. +- `tests/adapters/tool-catalog-nudge.test.ts` imports `../../src/adapters/tool-catalog-nudge` (line 2) and `exec-tool-result-normalize` (line 7). wp1 target. +- `tests/providers/cursor/cursor-tool-definitions.test.ts` imports `buildCursorToolGuidanceSystemNote` through `../../../src/adapters/cursor/tool-definitions` (lines 6-22), which re-exports `tool-guidance`. wp1 Cursor target. +- `tests/responses/openai-responses-passthrough.test.ts` imports `responses-code-mode` (line 5). wp1+wp2 native target. +- `tests/providers/kiro/kiro-adapter.test.ts` imports `exec-tool-result-normalize` (line 16) and drives `createKiroAdapter`. wp1+wp2 Kiro target. +- `tests/providers/cursor/cursor-toolresult-normalize.test.ts` imports `tool-result-normalize` (line 5). wp2 Cursor target. +- `tests/adapters/exec-tool-result-normalize.test.ts` (NEW, wp2) imports the shared module. +- `tests/test-layout-tooling.test.ts` reads `scripts/test-layout/layout.json` and `tests/fixtures/test-layout-expected.json`. - `bun run typecheck`, `bun run privacy:scan` — CI `gates` job. ## Enforcement bypass (PLAN-BYPASS-NAMED-01) -This unit adds guidance, not enforcement. Tier: none (prose the model may ignore). Executing -surface: request translation in the adapters. Known bypass: the model disregards the sentence; -the host still rejects the call exactly as today. Residual risk: none beyond status quo; the -post-hoc annotation cannot make a failed call succeed. Wording: this is an "early warning", not -enforcement. Final layer: Codex host validation (unchanged). +Guidance, not enforcement. Tier: none. Executing surface: adapter request translation. Known +bypass: the model ignores the sentence; the host rejects exactly as today. Residual risk: status +quo. Wording: "early warning". Final layer: Codex host validation (unchanged). ## SoT sync targets (SOT-SYNC-01) -- `structure/04_transports-and-sidecars.md` paragraph at ~line 325 ("Native routed Responses code-mode turns also receive…") — extend with the host contract. -- `docs-site/src/content/docs/guides/codex-integration.md` "Routed local tools" section (~line 315) — one paragraph; translated locales are not edited (they must not contradict, and adding text to English only is additive). +- `structure/04_transports-and-sidecars.md` paragraph at ~line 325 ("Native routed Responses code-mode turns also receive…") plus a Decision Log entry (full text in 030). +- `docs-site/src/content/docs/guides/codex-integration.md` "Routed local tools" (~line 331); translated locales untouched. + +## Audit round 1 — synthesis (REVIEW-SYNTHESIS-01) + +| # | Sev | Disposition | +|---|---|---| +| 1 Kiro grouping clobbers raw text | High | Folded: only the host annotation substitutes; grouped activation test added (020). | +| 2 Cursor false positives / case collisions | High | Folded: Cursor table untouched; exec-gated branch via shared helper; benign-content and case controls added (020). | +| 3 Cursor idempotence | Med | Folded: shared `[recovery: ` guard reached from Cursor; replay test with `isError:false` (020). | +| 4 Global whitelist false | Med | Folded: non-exhaustive list deferring to the exec description (010). | +| 5 No CI before wp3 | Med | Folded: push + draft PR at wp1, push at wp2, ready at wp3 (this file, 030). | +| 6 Elided strings | Med | Folded: full hunks and full Decision Log text (010/020/030). | +| 7 Anchor drift | Low | Folded: anchors refreshed against ec799db26; test import chain corrected. | +| 8 Docs overstate | Med | Folded: "this change" scope wording; three result paths named (030). | + +Root cause across 1-3: the roadmap treated "reuse the seam" as "spread into the seam" without +re-reading each seam's own policy. Round 2 re-audits with the same reviewer. diff --git a/devlog/_plan/260907_code_mode_host_contract/010_pre_call_contract.md b/devlog/_plan/260907_code_mode_host_contract/010_pre_call_contract.md index 9b41dd1653..e728a0aa1f 100644 --- a/devlog/_plan/260907_code_mode_host_contract/010_pre_call_contract.md +++ b/devlog/_plan/260907_code_mode_host_contract/010_pre_call_contract.md @@ -1,88 +1,90 @@ # 010 — wp1: pre-call host contract sentence and its three injection sites -Depends on 000_plan.md. Class C2 (conventional slice across an existing shared module and its -three known consumers; no new abstraction, no new seam). Loop archetype satisfy-spec. +Depends on 000_plan.md (rev 2). Class C2. Anchors verified against ec799db26. Ends with an +authorized push and a draft PR so exact-head CI exists for this and later heads. ## MODIFY `src/adapters/exec-tool-result-normalize.ts` -Append after `CODE_MODE_RESULT_ECHO_SENTENCE` (line ~117): +Insert after the `CODE_MODE_RESULT_ECHO_SENTENCE` declaration (its closing `;` is at line 117): ```ts + /** - * The host rules a routed model most often breaks on its first code-mode edit or wait, stated - * BEFORE the call. Wording tracks the Codex host (0.153.2): `apply_patch` rejects a non-string - * argument with "expects a string input" and a body whose first line is not the marker with - * "The first line of the patch must be '*** Begin Patch'"; the isolate rejects ES imports with - * "Unsupported import in exec"; a long command yields a session_id for write_stdin polling. - * Live 2026-09-07: xai/grok-4.6 hit the first two, abandoned apply_patch for heredoc writes, - * blocked a turn in a shell sleep loop, and died once on an import. None of that is a model - * defect the proxy can repair (see devlog/_plan/260905_apply_patch_envelope_gap/010 MODE B); - * it is a contract the proxy had not stated. + * Host rules a routed model most often breaks on its first code-mode edit or wait, stated BEFORE + * the call. Wording tracks the Codex host (0.153.2), probed live on 2026-09-07: a non-string + * argument to `apply_patch` throws "expects a string input"; a body whose first line is not the + * bare marker (decorated `*** Begin Patch ***`, a code fence, prose) throws "The first line of the + * patch must be '*** Begin Patch'" — surrounding newlines are tolerated; ES imports throw + * "Unsupported import in exec"; a command that outlives `yield_time_ms` returns `session_id` for + * `write_stdin` polling. xai/grok-4.6 hit the first two, abandoned apply_patch for heredoc writes, + * blocked a turn in a shell sleep loop, and died once on an import. None of that is repairable in + * the proxy (devlog/_plan/260905_apply_patch_envelope_gap/010 MODE B); it is a contract the proxy + * had not stated. */ export const CODE_MODE_HOST_CONTRACT_SENTENCE = - "Host contract for the nested helpers: `tools.apply_patch(patch)` takes exactly one string, never an object such as `{input: ...}`; the string's first line must be exactly `*** Begin Patch` and its last line `*** End Patch` with no leading newline, indentation, or extra asterisks, so start the literal at the marker. The isolate has no `import`, `require`, or module loader — use only the `tools`, `text`, `notify`, `store`/`load`, and `ALL_TOOLS` globals. For a command that may outlive `yield_time_ms`, let `tools.exec_command` return a `session_id` and poll it with `tools.write_stdin({session_id, chars: \"\"})` on later calls instead of blocking a shell in a sleep loop."; + "Host contract for the nested helpers: `tools.apply_patch(patch)` takes exactly one string, never an object such as `{input: ...}`; that string's first line must be the bare marker `*** Begin Patch` and its last line `*** End Patch`, with no code fence, prose, or extra asterisks around either marker. The isolate has no `import`, `require`, or module loader; use the globals the exec tool description lists (for example `tools`, `text`, `notify`, `store`/`load`, `ALL_TOOLS`). For a command that may outlive `yield_time_ms`, let `tools.exec_command` return a `session_id` and poll it on later calls with `tools.write_stdin({session_id, chars: \"\"})` instead of blocking a shell in a sleep loop."; ``` ## MODIFY `src/adapters/tool-catalog-nudge.ts` -Line 7 import: `import { CODE_MODE_HOST_CONTRACT_SENTENCE, CODE_MODE_RESULT_ECHO_SENTENCE } from "./exec-tool-result-normalize";` - -Line 124 code-mode branch. BEFORE (tail of the string): - -``` -... + CODE_MODE_RESULT_ECHO_SENTENCE + " Nested `tools.apply_patch(input)` is host-executed: ... rejected by Codex before the file is touched." +Line 8 BEFORE: +```ts +import { CODE_MODE_RESULT_ECHO_SENTENCE } from "./exec-tool-result-normalize"; ``` - AFTER: +```ts +import { CODE_MODE_HOST_CONTRACT_SENTENCE, CODE_MODE_RESULT_ECHO_SENTENCE } from "./exec-tool-result-normalize"; +``` +Line 124 is one 1035-byte string ending in `rejected by Codex before the file is touched."`. +BEFORE (tail): +```ts +OpenCodex does not rewrite JavaScript inside exec, so extra asterisks on a marker line are rejected by Codex before the file is touched." ``` -... + CODE_MODE_RESULT_ECHO_SENTENCE + " Nested `tools.apply_patch(input)` is host-executed: ... rejected by Codex before the file is touched. " + CODE_MODE_HOST_CONTRACT_SENTENCE +AFTER (tail): +```ts +OpenCodex does not rewrite JavaScript inside exec, so extra asterisks on a marker line are rejected by Codex before the file is touched. " + CODE_MODE_HOST_CONTRACT_SENTENCE ``` - -The flat-catalog branch (`If a listed tool exposes nested helpers…`) is unchanged: a shell bridge -echoes stdout and has no isolate, so the sentence would be false there. +The flat-catalog branch (`"If a listed tool exposes nested helpers such as a tools.* API…"`) is unchanged. ## MODIFY `src/adapters/cursor/tool-guidance.ts` -Line 2 import: add `CODE_MODE_HOST_CONTRACT_SENTENCE`. - -Line 190 (`codeMode ? CODE_MODE_RESULT_ECHO_SENTENCE + " There is no \`require\`, …"`). BEFORE: - +Line 2 BEFORE: ```ts -codeMode - ? CODE_MODE_RESULT_ECHO_SENTENCE + " There is no `require`, no `module`, and no filesystem or network globals; reach the host only through the nested helpers." - : undefined, +import { CODE_MODE_RESULT_ECHO_SENTENCE } from "../exec-tool-result-normalize"; ``` - AFTER: +```ts +import { CODE_MODE_HOST_CONTRACT_SENTENCE, CODE_MODE_RESULT_ECHO_SENTENCE } from "../exec-tool-result-normalize"; +``` +Lines 189-191 BEFORE (4-space indent as in source): +```ts + codeMode + ? CODE_MODE_RESULT_ECHO_SENTENCE + " There is no `require`, no `module`, and no filesystem or network globals; reach the host only through the nested helpers." + : undefined, +``` +AFTER: ```ts -codeMode - ? CODE_MODE_RESULT_ECHO_SENTENCE + " There is no `require`, no `module`, and no filesystem or network globals; reach the host only through the nested helpers. " + CODE_MODE_HOST_CONTRACT_SENTENCE - : undefined, + codeMode + ? CODE_MODE_RESULT_ECHO_SENTENCE + " There is no `require`, no `module`, and no filesystem or network globals; reach the host only through the nested helpers. " + CODE_MODE_HOST_CONTRACT_SENTENCE + : undefined, ``` ## MODIFY `src/adapters/responses-code-mode.ts` -Line 3 import: add `CODE_MODE_HOST_CONTRACT_SENTENCE`. - -Instructions (line ~46). BEFORE: - +Line 3 BEFORE: ```ts -instructions: instructions.includes(CODE_MODE_RESULT_ECHO_SENTENCE) - ? instructions : [instructions, CODE_MODE_RESULT_ECHO_SENTENCE].filter(Boolean).join("\n\n"), +import { CODE_MODE_RESULT_ECHO_SENTENCE, normalizeEmptyExecToolResultText } from "./exec-tool-result-normalize"; ``` - -AFTER (idempotent per sentence, so a replayed body that already carries the echo sentence but -not the contract gains only the missing one): - +AFTER: ```ts -instructions: appendMissing(instructions, [CODE_MODE_RESULT_ECHO_SENTENCE, CODE_MODE_HOST_CONTRACT_SENTENCE]), +import { CODE_MODE_HOST_CONTRACT_SENTENCE, CODE_MODE_RESULT_ECHO_SENTENCE, normalizeEmptyExecToolResultText } from "./exec-tool-result-normalize"; ``` -with a module-local helper: - +Insert before `/** Native routed Responses needs the same first-call/output contract… */` (line 33): ```ts +/** Append each sentence a replayed instructions string does not already carry, in order. */ function appendMissing(instructions: string, sentences: readonly string[]): string { return sentences.reduce( (acc, sentence) => acc.includes(sentence) ? acc : [acc, sentence].filter(Boolean).join("\n\n"), @@ -91,49 +93,95 @@ function appendMissing(instructions: string, sentences: readonly string[]): stri } ``` -The exec `input` parameter description (line 27) keeps only the echo sentence: it is a schema -string, and Kiro-style description limiters bound injected instructions, not parameter text, but -the contract is long and belongs in `instructions` where the existing test already asserts. +Lines 46-47 BEFORE (4-space indent): +```ts + instructions: instructions.includes(CODE_MODE_RESULT_ECHO_SENTENCE) + ? instructions : [instructions, CODE_MODE_RESULT_ECHO_SENTENCE].filter(Boolean).join("\n\n"), +``` +AFTER: +```ts + instructions: appendMissing(instructions, [CODE_MODE_RESULT_ECHO_SENTENCE, CODE_MODE_HOST_CONTRACT_SENTENCE]), +``` + +The exec `input` parameter description (line 27) keeps only the echo sentence; the contract belongs in +`instructions`, which the existing test asserts byte-exactly. -Activation scenario: any routed native Responses request whose visible catalog has a bare freeform -`exec` and no bare shell bridge, to a non-OpenAI destination, not a compaction request — the -exact gate at `responses-code-mode.ts:35-37`. Observable effect: `wire.instructions` ends with the -contract sentence. +Activation: routed native Responses request whose visible catalog has a bare freeform `exec` and no +bare shell bridge, non-OpenAI destination, not a compaction request (gate at lines 35-37). +Observable: `wire.instructions` ends with the contract sentence. -## TESTS (updated in place; no new file in wp1) +## TESTS (in place; no new file in wp1) `tests/adapters/tool-catalog-nudge.test.ts` -- In `"defines nested helper names as non-callable unless separately listed"` add: - `expect(note).toContain(CODE_MODE_HOST_CONTRACT_SENTENCE);` and - `expect(note).toContain("write_stdin({session_id, chars: \"\"})");`. -- In `"keeps the generic nested-helper parent-tool rule when exec is not listed"` add - `expect(note).not.toContain("Host contract for the nested helpers");`. -- Import the new constant on line 7. +- Line 7 import becomes `import { CODE_MODE_HOST_CONTRACT_SENTENCE, CODE_MODE_RESULT_ECHO_SENTENCE, EMPTY_EXEC_OUTPUT_MESSAGE } from "../../src/adapters/exec-tool-result-normalize";` +- In `"defines nested helper names as non-callable unless separately listed"` append: +```ts + // The host contract rides the same code-mode branch as the echo rule (Grok 2026-09-07). + expect(note).toContain(CODE_MODE_HOST_CONTRACT_SENTENCE); + expect(note).toContain("takes exactly one string"); + expect(note).toContain("write_stdin({session_id, chars: \"\"})"); +``` +- In `"keeps the generic nested-helper parent-tool rule when exec is not listed"` append: +```ts + expect(note).not.toContain("Host contract for the nested helpers"); +``` `tests/providers/cursor/cursor-tool-definitions.test.ts` -- In `"teaches the nested-helper contract instead of a top-level shell bridge"` (line ~754) add - `expect(note).toContain("takes exactly one string");` and - `expect(note).toContain("write_stdin");`. -- In `"keeps flat-catalog shell-bridge guidance when a bare bridge is advertised"` add - `expect(note).not.toContain("Host contract for the nested helpers");`. +- In `"teaches the nested-helper contract instead of a top-level shell bridge"` (starts line 754) append + after the `"OpenCodex does not rewrite JavaScript inside exec"` assertion: +```ts + expect(note).toContain("Host contract for the nested helpers"); + expect(note).toContain("takes exactly one string"); + expect(note).toContain("write_stdin"); +``` +- In `"keeps flat-catalog shell-bridge guidance when a bare bridge is advertised"` append: +```ts + expect(note).not.toContain("Host contract for the nested helpers"); +``` `tests/responses/openai-responses-passthrough.test.ts` -- `"first native request carries the echo rule…"` line 54 BEFORE: - `expect(wire.instructions).toBe(\`Keep this instruction.\n\n${CODE_MODE_RESULT_ECHO_SENTENCE}\`);` +- Line 6 import adds `CODE_MODE_HOST_CONTRACT_SENTENCE`. +- Line 54 BEFORE: +```ts + expect(wire.instructions).toBe(`Keep this instruction.\n\n${CODE_MODE_RESULT_ECHO_SENTENCE}`); +``` AFTER: - `expect(wire.instructions).toBe(\`Keep this instruction.\n\n${CODE_MODE_RESULT_ECHO_SENTENCE}\n\n${CODE_MODE_HOST_CONTRACT_SENTENCE}\`);` -- `"does not duplicate instructions…"` already asserts idempotence; add a case where the body's - instructions already contain the echo sentence and assert exactly one contract sentence is appended. -- `"official OpenAI and non-code-mode catalogs remain untouched"`: add - `expect(JSON.stringify(wire)).not.toContain("Host contract for the nested helpers")` inside the native loop. +```ts + expect(wire.instructions).toBe(`Keep this instruction.\n\n${CODE_MODE_RESULT_ECHO_SENTENCE}\n\n${CODE_MODE_HOST_CONTRACT_SENTENCE}`); +``` +- New test after `"does not duplicate instructions or explain an unpaired or unrelated result"`: +```ts + test("a replayed body that already carries the echo rule gains only the missing contract sentence", () => { + const body = { ...raw(), instructions: `Keep this instruction.\n\n${CODE_MODE_RESULT_ECHO_SENTENCE}` }; + const parsed = parseRequest(body); + const first = normalizeResponsesCodeMode(body, parsed, routed) as typeof body; + expect(first.instructions).toBe(`${body.instructions}\n\n${CODE_MODE_HOST_CONTRACT_SENTENCE}`); + expect(first.instructions.split(CODE_MODE_RESULT_ECHO_SENTENCE).length).toBe(2); + const second = normalizeResponsesCodeMode(first, parsed, routed) as typeof body; + expect(second.instructions).toBe(first.instructions); + }); +``` +- In `"official OpenAI and non-code-mode catalogs remain untouched"`, inside the `for (const native…)` loop + append `expect(JSON.stringify(wire)).not.toContain("Host contract for the nested helpers");`. `tests/providers/kiro/kiro-adapter.test.ts` -- In `"names ALL_TOOLS when a freeform exec is advertised…"` (line ~1817) add - `expect(content).toContain("Host contract for the nested helpers");` — proves the sentence - survives Kiro's `boundedInjectedInstruction` (16 384 chars) on the real wire prompt. +- In `"names ALL_TOOLS when a freeform exec is advertised without a bare shell bridge"` (line 1817) append: +```ts + // Survives Kiro's 16 384-char injected-instruction bound on the real wire prompt. + expect(content).toContain("Host contract for the nested helpers"); +``` + +## Delivery for this phase + +`git add` only the files above; `git diff --cached --stat` first; commit `--no-verify`; then +`git push --no-verify -u origin codex/code-mode-host-contract` and +`gh pr create --draft --base dev --title "fix(code-mode): state the host contract for nested helpers and annotate host failures" --body-file .tmp/pr-body.md` +(body per template; Verification section says local checks NOT RUN, hosted CI is the verifier; +wp2/wp3 will extend it). ## Verification (C, hosted only) -NOT RUN locally by instruction. Hosted CI shards run the four files above; `gates` runs typecheck -and privacy scan. Evidence: `gh run list --branch codex/code-mode-host-contract` + `gh run view --exit-status`. +NOT RUN locally by instruction. Poll `gh run list --branch codex/code-mode-host-contract --json databaseId,headSha,status,conclusion,name` +in short `exec_command` calls; when the Cross-platform CI run for `git rev-parse HEAD` completes, +`cxc receipt test --session --cwd -- gh run view --exit-status`. diff --git a/devlog/_plan/260907_code_mode_host_contract/020_post_hoc_annotation.md b/devlog/_plan/260907_code_mode_host_contract/020_post_hoc_annotation.md index 105a592c2d..b428121f5d 100644 --- a/devlog/_plan/260907_code_mode_host_contract/020_post_hoc_annotation.md +++ b/devlog/_plan/260907_code_mode_host_contract/020_post_hoc_annotation.md @@ -1,19 +1,19 @@ # 020 — wp2: post-hoc annotation of host failures on exec results -Depends on 010 (the pre-call sentence names the same rules this half explains after the fact; the -two must share wording, which is why both live in one module). Class C2. +Depends on 010 (same module, same wording). Class C2. Anchors verified against ec799db26 plus +the wp1 delta. Ends with an authorized push; the draft PR from wp1 picks up the new head. ## MODIFY `src/adapters/exec-tool-result-normalize.ts` -Append after `CODE_MODE_HOST_CONTRACT_SENTENCE`: +Insert after `CODE_MODE_HOST_CONTRACT_SENTENCE` (added in wp1): ```ts + /** * Post-hoc half of the host contract: the four host strings a routed model reads inside a - * non-error exec result, each paired with the rule it broke. Markers are compared - * case-insensitively because the host writes "Unsupported import in exec: " while - * earlier Cursor guidance matched the lowercase form; one table, one owner, so the - * recovery text can never drift from the pre-call sentence above. + * non-error exec result, each paired with the rule it broke. Matched case-insensitively because + * the host writes "Unsupported import in exec: " while Cursor's earlier marker was + * lowercase; one table, one owner, so this text and the pre-call sentence cannot drift. */ export const CODE_MODE_HOST_FAILURE_GUIDANCE: ReadonlyArray<{ marker: string; guidance: string }> = [ { @@ -22,11 +22,11 @@ export const CODE_MODE_HOST_FAILURE_GUIDANCE: ReadonlyArray<{ marker: string; gu }, { marker: "the first line of the patch must be", - guidance: "The patch string must begin at `*** Begin Patch` with no leading newline, indentation, or extra asterisks; start the literal on the marker line.", + guidance: "The patch string's first line must be the bare marker `*** Begin Patch` with no code fence, prose, or extra asterisks around it.", }, { marker: "the last line of the patch must be", - guidance: "The patch string must end with `*** End Patch` as its final line, with no trailing text or extra asterisks.", + guidance: "The patch string's last line must be the bare marker `*** End Patch` with no trailing text or extra asterisks.", }, { marker: "unsupported import in exec", @@ -38,8 +38,9 @@ const HOST_FAILURE_RECOVERY_PREFIX = "[recovery: "; /** * Append a one-line recovery hint when an exec-bridge result carries a known host failure string. - * Returns undefined when the result is not an exec-bridge tool, no marker matches, or a recovery - * line is already present, so callers keep their own fallback and never double-annotate. + * Returns undefined when the tool is not an exec bridge, no marker matches, or a recovery line is + * already present (a replayed annotated result must not grow a second one). Never touches error + * status: the host already decided whether the call failed. */ export function annotateCodeModeHostFailure( text: string, @@ -53,86 +54,114 @@ export function annotateCodeModeHostFailure( } ``` -The Cursor guidance string for the import row is kept byte-identical to today's -(`"Imports are not available in this exec context; use the injected globals instead."` extended with -the global list) so `cursor-toolresult-normalize.test.ts:101` (`"injected globals"`) still matches. - ## MODIFY `src/adapters/responses-code-mode.ts` -Line 55 BEFORE: +Line 3 import gains `annotateCodeModeHostFailure`. +Line 55 BEFORE (6-space indent): ```ts -const normalized = text === undefined ? undefined : normalizeEmptyExecToolResultText(text, { toolName: "exec" }); + const normalized = text === undefined ? undefined : normalizeEmptyExecToolResultText(text, { toolName: "exec" }); ``` - AFTER: - ```ts -const normalized = text === undefined - ? undefined - : normalizeEmptyExecToolResultText(text, { toolName: "exec" }) - ?? annotateCodeModeHostFailure(text, { toolName: "exec" }); + const normalized = text === undefined + ? undefined + : normalizeEmptyExecToolResultText(text, { toolName: "exec" }) + ?? annotateCodeModeHostFailure(text, { toolName: "exec" }); ``` - -Import `annotateCodeModeHostFailure` on line 3. Empty-wrapper first: an empty result can never -carry a marker, so the order is only for clarity. Activation: paired `custom_tool_call_output` -whose text contains e.g. `\`apply_patch\` expects a string input`; observable effect: output ends -with `[recovery: tools.apply_patch takes exactly one string argument…]`, and `input[0]` (the -program) is the same object reference as before. +Activation: paired `custom_tool_call_output` whose text contains `\`apply_patch\` expects a string input`; +observable: output ends with the recovery line, `input[0]` is the same object reference. ## MODIFY `src/adapters/kiro.ts` -Line 47 import: add `annotateCodeModeHostFailure`. - -Lines 758-762 BEFORE: - +Line 47 BEFORE: ```ts -const normalizedExecText = normalizeEmptyExecToolResultText(text, { - toolName: tr.toolName, - toolNamespace: tr.toolNamespace, -}); -const resultText = normalizedExecText ?? (text.trim() ? text : KIRO_EMPTY_TOOL_RESULT_MESSAGE); +import { EMPTY_EXEC_OUTPUT_MESSAGE, normalizeEmptyExecToolResultText } from "./exec-tool-result-normalize"; ``` - AFTER: - ```ts -const execOptions = { toolName: tr.toolName, toolNamespace: tr.toolNamespace }; -const normalizedExecText = normalizeEmptyExecToolResultText(text, execOptions) - ?? annotateCodeModeHostFailure(text, execOptions); -const resultText = normalizedExecText ?? (text.trim() ? text : KIRO_EMPTY_TOOL_RESULT_MESSAGE); +import { EMPTY_EXEC_OUTPUT_MESSAGE, annotateCodeModeHostFailure, normalizeEmptyExecToolResultText } from "./exec-tool-result-normalize"; ``` -`rawGroupText` (line 774) already keeps `text` whenever `normalizedExecText !== EMPTY_EXEC_OUTPUT_MESSAGE`, -so the adjacent-result grouping path carries the RAW failure text; the annotated text is what the -single-result path emits. Line 774 is changed so a grouped result carries the annotated text too: - -BEFORE: `? text : undefined;` AFTER: `? (normalizedExecText ?? text) : undefined;` - -(For the empty-wrapper case `normalizedExecText === EMPTY_EXEC_OUTPUT_MESSAGE` short-circuits the -outer condition first, so that branch is unchanged.) +Lines 758-771 BEFORE (6-space indent): +```ts + const normalizedExecText = normalizeEmptyExecToolResultText(text, { + toolName: tr.toolName, + toolNamespace: tr.toolNamespace, + }); + const resultText = normalizedExecText ?? (text.trim() ? text : KIRO_EMPTY_TOOL_RESULT_MESSAGE); + const images = extractKiroImages(tr.content); + const toolUseId = normalizeToolId(tr.toolCallId); + const call = priorCalls.get(toolUseId); + if (!call || call.rawId !== tr.toolCallId) { + throw new Error(`Kiro history contains an orphaned tool result for call ${JSON.stringify(tr.toolCallId)}`); + } + // Keep real whitespace and failed wrappers, but no empty-success wrapper boilerplate. + const rawGroupText = text.length > 0 && (!text.trim() || normalizedExecText !== EMPTY_EXEC_OUTPUT_MESSAGE) + ? text : undefined; +``` +AFTER: +```ts + const execOptions = { toolName: tr.toolName, toolNamespace: tr.toolNamespace }; + const normalizedExecText = normalizeEmptyExecToolResultText(text, execOptions); + // A host failure string inside a non-empty exec result gets the rule it broke appended. This + // is the only substitution the grouping path below also carries: whitespace and empty/failed + // wrappers keep their existing raw policy. + const annotatedExecText = normalizedExecText === undefined ? annotateCodeModeHostFailure(text, execOptions) : undefined; + const resultText = normalizedExecText ?? annotatedExecText ?? (text.trim() ? text : KIRO_EMPTY_TOOL_RESULT_MESSAGE); + const images = extractKiroImages(tr.content); + const toolUseId = normalizeToolId(tr.toolCallId); + const call = priorCalls.get(toolUseId); + if (!call || call.rawId !== tr.toolCallId) { + throw new Error(`Kiro history contains an orphaned tool result for call ${JSON.stringify(tr.toolCallId)}`); + } + // Keep real whitespace and failed wrappers, but no empty-success wrapper boilerplate. + const rawGroupText = text.length > 0 && (!text.trim() || normalizedExecText !== EMPTY_EXEC_OUTPUT_MESSAGE) + ? (annotatedExecText ?? text) : undefined; +``` +`annotatedExecText` is defined only when `normalizedExecText` is undefined, i.e. the text is neither an +empty-success nor a failed-empty wrapper, so every existing grouping expectation +(`kiro-adapter.test.ts:1209` whitespace, `1252` raw failed wrapper) is unchanged by construction. ## MODIFY `src/adapters/cursor/tool-result-normalize.ts` -Import `CODE_MODE_HOST_FAILURE_GUIDANCE` from `../exec-tool-result-normalize`. - -`RUNTIME_FAILURE_GUIDANCE` (lines 50-67): DELETE the `unsupported import in exec` entry and spread -the shared table instead: +Imports (lines 12-18) gain `annotateCodeModeHostFailure`. `RUNTIME_FAILURE_GUIDANCE` (lines 50-67) and its +loop (lines 107-113) stay byte-identical: Cursor's marker semantics, case sensitivity and +`isError:true` policy are its own. +Lines 96-105 BEFORE (2-space indent): ```ts -const RUNTIME_FAILURE_GUIDANCE: ReadonlyArray<{ marker: string; guidance: string }> = [ - { marker: "SkyComputerUseError", guidance: "…" }, - { marker: "sky is not defined", guidance: "…" }, - { marker: "has already been declared", guidance: "…" }, - ...CODE_MODE_HOST_FAILURE_GUIDANCE, -]; + if (isCodexExecBridgeTool(options.toolName, options.toolNamespace) && isEmptyOrFailedExecWrapper(text.trim())) { + return { + // A `Script failed` wrapper is empty but NOT a success: reporting it as an empty success + // would erase the only failure signal. Text classification stays separate from Cursor's + // isError policy, which the Computer Use branch above owns. + text: isFailedEmptyExecWrapper(text.trim()) ? FAILED_EXEC_OUTPUT_MESSAGE : EMPTY_EXEC_OUTPUT_MESSAGE, + isError: false, + changed: true, + }; + } ``` - -Loop at line 109 BEFORE: `if (text.includes(marker))` AFTER: compare against `text.toLowerCase()` -for the shared rows only — simplest correct form is to lowercase both sides for every row, since the -three Cursor markers contain no case-sensitive collisions (`SkyComputerUseError` lowercased still -matches only itself). Cursor policy (`isError: true` on a match) is unchanged; the shared helper is -not used here because Cursor owns its `isError` decision. +AFTER (append one branch directly after that block): +```ts + if (isCodexExecBridgeTool(options.toolName, options.toolNamespace) && isEmptyOrFailedExecWrapper(text.trim())) { + return { + // A `Script failed` wrapper is empty but NOT a success: reporting it as an empty success + // would erase the only failure signal. Text classification stays separate from Cursor's + // isError policy, which the Computer Use branch above owns. + text: isFailedEmptyExecWrapper(text.trim()) ? FAILED_EXEC_OUTPUT_MESSAGE : EMPTY_EXEC_OUTPUT_MESSAGE, + isError: false, + changed: true, + }; + } + // A host failure string inside an exec-bridge result gets the rule it broke appended. The + // helper is exec-gated and refuses already-annotated text, so a replayed result does not grow + // a second line; Cursor's isError decision is left exactly as the caller passed it. + const hostFailure = annotateCodeModeHostFailure(text, options); + if (hostFailure !== undefined) return { text: hostFailure, isError, changed: true }; +``` +The existing `unsupported import in exec` row in `RUNTIME_FAILURE_GUIDANCE` still serves node_repl / +Computer Use tools; for exec-bridge tools the new branch runs first and carries the shared hint. ## NEW `tests/adapters/exec-tool-result-normalize.test.ts` @@ -144,65 +173,128 @@ import { annotateCodeModeHostFailure, } from "../../src/adapters/exec-tool-result-normalize"; +// Live host strings (Codex 0.153.2, probed 2026-09-07) and the rule each one names. The pre-call +// sentence and these rows are one contract in one module; a model must never be told one thing +// before the call and another after. describe("code-mode host failure annotation", () => { - test.each(CODE_MODE_HOST_FAILURE_GUIDANCE.map(row => [row.marker, row.guidance]))( - "annotates an exec result carrying %p", (marker, guidance) => { - const text = `Script failed\nOutput:\nError: ${marker.toUpperCase()}`; - const out = annotateCodeModeHostFailure(text, { toolName: "exec" }); - expect(out).toBe(`${text}\n[recovery: ${guidance}]`); - }); - - test("matches the host's real capitalisation for imports", () => { - const out = annotateCodeModeHostFailure("Unsupported import in exec: node:fs", { toolName: "exec" }); - expect(out).toContain("injected globals"); + test.each(CODE_MODE_HOST_FAILURE_GUIDANCE.map(row => [row.marker, row.guidance] as const))( + "annotates an exec result carrying %p regardless of case", + (marker, guidance) => { + const text = `Script failed\nWall time 0.1 seconds\nOutput:\nError: ${marker.toUpperCase()}`; + expect(annotateCodeModeHostFailure(text, { toolName: "exec" })).toBe(`${text}\n[recovery: ${guidance}]`); + }, + ); + + test("matches the host's real capitalisation and argument text", () => { + expect(annotateCodeModeHostFailure("Unsupported import in exec: node:fs", { toolName: "exec" })).toContain("injected globals"); + expect(annotateCodeModeHostFailure("Script error:\ntool `apply_patch` expects a string input", { toolName: "exec" })).toContain("exactly one string"); + expect(annotateCodeModeHostFailure( + "apply_patch verification failed: invalid patch: The first line of the patch must be '*** Begin Patch'", + { toolName: "exec_command" }, + )).toContain("bare marker `*** Begin Patch`"); }); - test("leaves non-exec tools, non-matching text and already-annotated text alone", () => { + test("leaves non-exec tools, non-matching text and already-annotated text byte-identical", () => { expect(annotateCodeModeHostFailure("expects a string input", { toolName: "read_file" })).toBeUndefined(); + expect(annotateCodeModeHostFailure("expects a string input", { toolName: "exec_command", toolNamespace: "mcp__docker" })).toBeUndefined(); expect(annotateCodeModeHostFailure("all good", { toolName: "exec" })).toBeUndefined(); - const once = annotateCodeModeHostFailure("expects a string input", { toolName: "exec" })!; + const once = annotateCodeModeHostFailure("expects a string input", { toolName: "exec" }); + if (!once) throw new Error("expected one annotation"); expect(annotateCodeModeHostFailure(once, { toolName: "exec" })).toBeUndefined(); }); test("every failure row is a rule the pre-call sentence already states", () => { - // One owner, two halves: a model must never be told one thing before the call and another after. - expect(CODE_MODE_HOST_CONTRACT_SENTENCE).toContain("exactly one string"); - expect(CODE_MODE_HOST_CONTRACT_SENTENCE).toContain("*** Begin Patch"); - expect(CODE_MODE_HOST_CONTRACT_SENTENCE).toContain("*** End Patch"); + expect(CODE_MODE_HOST_CONTRACT_SENTENCE).toContain("takes exactly one string"); + expect(CODE_MODE_HOST_CONTRACT_SENTENCE).toContain("`*** Begin Patch`"); + expect(CODE_MODE_HOST_CONTRACT_SENTENCE).toContain("`*** End Patch`"); expect(CODE_MODE_HOST_CONTRACT_SENTENCE).toContain("no `import`"); + expect(CODE_MODE_HOST_CONTRACT_SENTENCE).toContain("write_stdin"); + // Never shows the decorated marker as a copyable literal (same rule as the nudge tests). + expect(CODE_MODE_HOST_CONTRACT_SENTENCE).not.toContain("*** Begin Patch ***"); }); }); ``` -Register: `scripts/test-layout/layout.json` → `explicit`: `"exec-tool-result-normalize.test.ts": "adapters"` -(alphabetical, after `"exec-…"` neighbours or before `"identity-…"`); same key in -`tests/fixtures/test-layout-expected.json`. `tests/test-layout-tooling.test.ts` names a missing one. +Register in `scripts/test-layout/layout.json` `explicit` between +`"empty-tool-output-annotation.test.ts": "adapters",` (line 620) and its successor: +`"exec-tool-result-normalize.test.ts": "adapters",`; same key/value in +`tests/fixtures/test-layout-expected.json` in alphabetical position. The name matches no regex seed +(`"adapters"` seed is `^(?:bridge\.test\.ts|buffered|identity|run|tool|translator)-`), so the explicit +entry is required and `tests/test-layout-tooling.test.ts` names it if missing. ## Updated tests -`tests/responses/openai-responses-passthrough.test.ts` — add to the code-mode describe: +`tests/responses/openai-responses-passthrough.test.ts` — add inside the code-mode describe: +```ts + test("annotates a paired exec result that carries a host failure string without touching the program", () => { + const failure = "Script failed\nWall time 0.1 seconds\nOutput:\nScript error:\ntool `apply_patch` expects a string input"; + const body = raw(failure); + const wire = JSON.parse(createResponsesPassthroughAdapter(routed).buildRequest(parseRequest(body)).body); + expect(wire.input[1].output).toBe(`${failure}\n[recovery: tools.apply_patch takes exactly one string argument; pass the patch text itself, not an object such as {input: ...}.]`); + expect(JSON.parse(wire.input[0].arguments).input).toBe(body.input[0].input); + // Replayed history already carrying the hint is not annotated twice. + const replayed = raw(wire.input[1].output); + expect(normalizeResponsesCodeMode(replayed, parseRequest(replayed), routed)).toBe(replayed); + }); +``` +`tests/providers/kiro/kiro-adapter.test.ts` +- After `"an empty code-mode exec result carries the actionable reason…"` (line 323) add: ```ts -test("annotates a paired exec result that carries a host failure string", () => { - const failure = "Script failed\nWall time 0.1 seconds\nOutput:\nError: `apply_patch` expects a string input"; - const body = raw(failure); - const wire = JSON.parse(createResponsesPassthroughAdapter(routed).buildRequest(parseRequest(body)).body); - expect(wire.input[1].output).toBe(`${failure}\n[recovery: tools.apply_patch takes exactly one string argument; pass the patch text itself, not an object such as {input: ...}.]`); - expect(JSON.parse(wire.input[0].arguments).input).toBe(body.input[0].input); -}); + test("a code-mode exec result carrying a host failure string names the broken rule", async () => { + const execTool = { name: "exec", description: "Run JavaScript", parameters: { type: "object" } }; + const failure = "apply_patch verification failed: invalid patch: The first line of the patch must be '*** Begin Patch'"; + const messages = [ + { role: "user", content: "run it" }, + { role: "assistant", content: [{ type: "toolCall", id: "call-x", name: "exec", arguments: {} }] }, + { role: "toolResult", toolCallId: "call-x", toolName: "exec", content: failure, isError: false }, + ]; + const { body } = await createKiroAdapter(provider).buildRequest(parsedWith(messages, [execTool])); + const resultText = JSON.parse(body).conversationState.currentMessage.userInputMessage + .userInputMessageContext.toolResults[0].content[0].text; + expect(resultText).toBe(`${failure}\n[recovery: The patch string's first line must be the bare marker \`*** Begin Patch\` with no code fence, prose, or extra asterisks around it.]`); + }); +``` +- In the grouped-result table (the `execResult` cases around lines 1195-1262) add one case: +```ts + { + name: "host failure chunk in a multi group carries its recovery line beside raw siblings", + id: "call-host-failure-multi", + results: [execResult("call-host-failure-multi", " "), execResult("call-host-failure-multi", "tool `apply_patch` expects a string input"), execResult("call-host-failure-multi", failedExecWrapper)], + content: [{ text: " " }, { text: "tool `apply_patch` expects a string input\n[recovery: tools.apply_patch takes exactly one string argument; pass the patch text itself, not an object such as {input: ...}.]" }, { text: failedExecWrapper }], + status: "success", + forbidden: [EMPTY_EXEC_OUTPUT_MESSAGE, FAILED_EXEC_OUTPUT_MESSAGE, KIRO_EMPTY_TOOL_RESULT_MESSAGE], + }, +``` + This drives the grouping path with whitespace, an annotated chunk and a raw failed wrapper in one + group — the exact combination blocker 1 said the single-result test could not exercise. + +`tests/providers/cursor/cursor-toolresult-normalize.test.ts` — add after the `test.each` runtime-failure table: +```ts + test("an exec-bridge result carrying a host failure string gains the shared hint and keeps its isError", () => { + const out = normalizeCursorToolResultText("Unsupported import in exec: node:fs", { toolName: "exec" }); + expect(out.changed).toBe(true); + expect(out.isError).toBe(false); + expect(out.text).toContain("[recovery: Imports are not available in this exec context"); + // Replay of the annotated text with isError=false must not grow a second line. + expect(normalizeCursorToolResultText(out.text, { toolName: "exec" }).changed).toBe(false); + }); + + test("a non-exec tool whose successful output merely mentions a host phrase stays byte-identical", () => { + const doc = "The docs say apply_patch expects a string input."; + const out = normalizeCursorToolResultText(doc, { toolName: "read_file" }); + expect(out.changed).toBe(false); + expect(out.isError).toBe(false); + expect(out.text).toBe(doc); + }); ``` -`tests/providers/kiro/kiro-adapter.test.ts` — beside the `EMPTY_EXEC_OUTPUT_MESSAGE` case at -line ~336, add one toolResult with `toolName: "exec"` and content -`"The first line of the patch must be '*** Begin Patch'"`; assert the emitted Kiro tool-result -text ends with `[recovery: The patch string must begin at …]`. +## Delivery for this phase -`tests/providers/cursor/cursor-toolresult-normalize.test.ts` — line 101 row stays; add -`["Unsupported import in exec: node:fs", "injected globals"]` and -`["\`apply_patch\` expects a string input", "exactly one string"]` to the `test.each` table. +Stage only the files above (`git diff --cached --stat` first); commit `--no-verify`; push `--no-verify`. ## Verification (C, hosted only) -NOT RUN locally. Hosted shards run the new and updated files; `tests/test-layout-tooling.test.ts` -proves registration. Activation for each conditional row is the marker-specific test above. +NOT RUN locally. Exact-head Cross-platform CI on the wp2 head; receipt via +`cxc receipt test --session --cwd -- gh run view --exit-status`. diff --git a/devlog/_plan/260907_code_mode_host_contract/030_docs_and_delivery.md b/devlog/_plan/260907_code_mode_host_contract/030_docs_and_delivery.md index 8b7a848c69..e0c0df7990 100644 --- a/devlog/_plan/260907_code_mode_host_contract/030_docs_and_delivery.md +++ b/devlog/_plan/260907_code_mode_host_contract/030_docs_and_delivery.md @@ -1,12 +1,13 @@ -# 030 — wp3: SoT sync, push, PR, exact-head CI receipt +# 030 — wp3: SoT sync, ready-for-review, exact-head CI receipt -Depends on 020. Class C2 for the docs; the push/PR step is external state and is authorized by -the user for this branch only ("no verify로 푸시", "pr올려봐"). Merge is not authorized. +Depends on 020. Class C2 for the docs. Push and PR creation are authorized by the user for this +branch ("no verify로 푸시", "pr올려봐"); the draft PR already exists from wp1. Merge is not authorized. ## MODIFY `structure/04_transports-and-sidecars.md` -After the paragraph ending "…or reconstruct output that the code-mode host never emitted." (~line 331) -add one paragraph: +Insert after the paragraph that ends "…or reconstruct output that the code-mode host never +emitted." (line 331), before the `[Decision Log]` that begins "목적과 의도: Keep Codex hosted web +search usable on xAI's public Responses endpoint…": ``` Routed code-mode turns also carry the host contract for the nested helpers, stated in the same three @@ -14,31 +15,37 @@ injection sites as the result-emission rule (shared catalog nudge, Cursor code-m routed Responses instructions): `tools.apply_patch` takes one string whose first and last lines are the bare patch markers, the isolate has no `import`/`require`, and a command that outlives `yield_time_ms` is polled through `write_stdin` with empty `chars` rather than a shell sleep loop. -When a paired exec result still carries one of the host's failure strings ("expects a string +When an exec-bridge result still carries one of the host's failure strings ("expects a string input", "The first line of the patch must be", "The last line of the patch must be", "Unsupported -import in exec"), the routed Responses, Kiro, and Cursor result paths append a one-line recovery -hint naming the broken rule. Both halves live in `src/adapters/exec-tool-result-normalize.ts` so -the pre-call and post-hoc wording cannot drift. Nothing rewrites the model's JavaScript or its -patch payload; the host still rejects the call exactly as before. +import in exec"), the native routed Responses, Kiro, and Cursor result paths append a one-line +recovery hint naming the broken rule; Cursor's error classification and Kiro's whitespace and +failed-wrapper grouping are unchanged. Both halves live in `src/adapters/exec-tool-result-normalize.ts` +so the pre-call and post-hoc wording cannot drift. This guidance and annotation change rewrites +neither the model's JavaScript nor its patch payload; the existing name-alias delimiter +normalization in `src/responses/code-mode-helper-compat.ts` is unchanged, and the host still rejects a +malformed call exactly as before. Anthropic, Google, OpenAI-chat and command-code result paths +have no exec-result seam today and are not annotated. + +[Decision Log] +- 목적과 의도: Stop routed models from abandoning `apply_patch` after the Codex host rejects an object argument or a decorated marker, and from blocking a turn in a shell sleep loop when the host offers `session_id` polling. +- 기존 구현 및 제약 조건: The shared nudge, Cursor guidance and native Responses instructions already carry the result-emission rule from `exec-tool-result-normalize.ts`, but none stated the helper's argument type, the marker rule, the import ban, or the polling protocol; `260905_apply_patch_envelope_gap` refused to rewrite JavaScript bodies (MODE B), so payload repair is off the table. +- 검토한 주요 대안: Repair the argument shape inside the proxy (rejected: same body ambiguity as MODE B and it turns a rejected write into a performed one); Cursor-only guidance (rejected: the incident was native routed Responses on xAI); annotate every adapter's tool results (rejected: Anthropic/Google/OpenAI-chat/command-code have no exec-result seam and would need a new one). +- 선택한 방식: One pre-call sentence and one marker→recovery table in the module that already owns the echo pair; inject the sentence at the three existing code-mode sites; annotate at the three existing exec-result seams with an exec-gated, idempotent helper that never changes error status. +- 다른 대안 대신 이 방식을 선택한 이유: The safe repair for a host contract the model broke is to state it before the call and name it after the failure; keeping both halves in one file is what keeps them consistent. +- 장점, 단점 및 영향: Code-mode system prompts grow by roughly 600 characters on routed turns; OpenAI destinations, flat catalogs and compaction requests are untouched. An exec result that legitimately prints one of the four phrases gains a recovery line, which is additive text and never an error flip. The effect on the live Grok defect rate is unmeasured until a re-probe. ``` -Add a Decision Log entry in the file's existing format (목적과 의도 / 기존 구현 및 제약 조건 / -검토한 주요 대안 / 선택한 방식 / 장점, 단점 및 영향) recording: purpose = stop routed models -abandoning apply_patch after two host rejections; alternatives = repair the argument shape in the -proxy (rejected: MODE B ambiguity, fail-open write), Cursor-only fix (rejected: incident was native -Responses); chosen = shared pair in one module; impact = longer system prompt on code-mode turns -(~600 chars), no behaviour change for OpenAI destinations or flat catalogs. - ## MODIFY `docs-site/src/content/docs/guides/codex-integration.md` -In "Routed local tools" after the apply_patch conversion paragraph (~line 331) add: +Insert after the paragraph ending "…and unrelated native custom payloads stay unchanged." (line 331): ``` Routed code-mode turns are also told the host's rules for the nested helpers before the first -call — `tools.apply_patch` takes one string starting at `*** Begin Patch`, the isolate has no -`import`, and long-running commands are polled with `write_stdin` — and when a result still -carries one of the host's failure messages, opencodex appends a one-line hint naming the rule. -The model's code and patch text are never rewritten. +call: `tools.apply_patch` takes one string whose first and last lines are the bare patch markers, +the isolate has no `import`, and long-running commands are polled through `write_stdin`. When an +exec result on the native routed Responses, Kiro, or Cursor path still carries one of the host's +failure messages, opencodex appends a one-line hint naming the rule. This change does not rewrite +the model's code or its patch text. ``` Translated locales (7 files) are not edited; the English source gains a paragraph they do not @@ -46,18 +53,17 @@ contradict. ## Delivery steps (t3b) -1. `git add -A devlog/_plan/260907_code_mode_host_contract src tests scripts structure docs-site` - — inspect `git diff --cached --stat` before every commit; only this unit's paths. -2. Commits already made per work-phase with `--no-verify` (wp0 docs, wp1, wp2, wp3 docs). -3. `git push --no-verify -u origin codex/code-mode-host-contract`. -4. `gh pr create --base dev --title "fix(code-mode): state the host contract for nested helpers and annotate host failures" --body-file .tmp/pr-body.md` - — body follows `.github/PULL_REQUEST_TEMPLATE.md` (Summary / Verification / Checklist), lists - local checks as NOT RUN, names hosted CI as the verifier. No `gui` mention (no screenshot rule). -5. Poll: `gh run list --branch codex/code-mode-host-contract --json databaseId,headSha,status,conclusion` - via `exec_command` short calls (each < 30 s); `gh run watch` is NOT used inside one call. -6. Receipt: at phase C, `cxc receipt test --session --cwd -- gh run view --exit-status` - where `` is the Cross-platform CI run whose `headSha` equals `git rev-parse HEAD`. - If the head moves (review fix), a fresh run and fresh receipt are required. +1. Stage only `structure/04_transports-and-sidecars.md`, `docs-site/.../codex-integration.md` and this unit's + devlog; inspect `git diff --cached --stat`; commit `--no-verify`; `git push --no-verify`. +2. Rewrite the PR body (`gh pr edit --body-file .tmp/pr-body.md`) to the final template: Summary + (problem, before/after, the four host strings), Verification (hosted CI run ids per head; local + suite/typecheck/build NOT RUN by instruction), Checklist ticked truthfully. No `gui` mention. +3. Poll `gh run list --branch codex/code-mode-host-contract --json databaseId,headSha,status,conclusion,name` + in short `exec_command` calls (each < 30 s) until the Cross-platform CI run whose `headSha` equals + `git rev-parse HEAD` completes; `gh run watch` is not used inside one call. +4. Receipt at phase C: `cxc receipt test --session --cwd -- gh run view --exit-status`. +5. `gh pr ready ` only after that receipt exists. If the head moves later, a fresh run and fresh + receipt are required before any further ready claim. ## Verification (C) From d375916ee2508cbd390c4edb556aeab65ed6ec42 Mon Sep 17 00:00:00 2001 From: JUN <243035832+lidge-jun@users.noreply.github.com> Date: Mon, 7 Sep 2026 14:42:10 +0900 Subject: [PATCH 068/412] docs(devlog): fold audit round 2 into the code-mode host contract roadmap --- .../000_plan.md | 29 ++++- .../010_pre_call_contract.md | 9 +- .../020_post_hoc_annotation.md | 105 ++++++++++++------ .../030_docs_and_delivery.md | 19 ++-- 4 files changed, 111 insertions(+), 51 deletions(-) diff --git a/devlog/_plan/260907_code_mode_host_contract/000_plan.md b/devlog/_plan/260907_code_mode_host_contract/000_plan.md index 406c2c186d..91c130df0a 100644 --- a/devlog/_plan/260907_code_mode_host_contract/000_plan.md +++ b/devlog/_plan/260907_code_mode_host_contract/000_plan.md @@ -77,18 +77,26 @@ New exports in `exec-tool-result-normalize.ts` (full text in 010/020): non-exhaustive), `session_id` + `write_stdin` polling. 2. `CODE_MODE_HOST_FAILURE_GUIDANCE` — marker → recovery rows for the four host strings, matched case-insensitively. -3. `annotateCodeModeHostFailure(text, {toolName, toolNamespace})` — gated by - `isCodexExecBridgeTool`, refuses text already carrying `[recovery: `, appends one recovery - line; else `undefined`. Pure, idempotent, byte-identical on the negative path. +3. `annotateCodeModeHostFailure(text, {toolName, toolNamespace})` — gated by a new, narrower + `isCodexCodeModeExecResult` (bare `exec` or its `opencodex-responses` display alias; flat shell + bridges and foreign MCP namespaces excluded because the four strings originate only in the + isolate), refuses text already carrying the exported `CODE_MODE_HOST_RECOVERY_PREFIX`, appends + one recovery line; else `undefined`. Pure, idempotent, byte-identical on the negative path. + The empty-output repair keeps its wider `isCodexExecBridgeTool` gate. Cursor keeps its own `RUNTIME_FAILURE_GUIDANCE` table and its `isError` policy byte-identical; it gains one exec-gated branch that inserts the shared annotation WITHOUT changing `isError` (audit blockers 2 and 3). Kiro substitutes the annotation only where it would otherwise carry the raw text, leaving whitespace and failed-wrapper grouping untouched (blocker 1). -Accepted residual: an exec result that legitimately prints one of the four phrases (e.g. `cat` of -this devlog) gains a recovery line. The line is additive text on an exec result and never changes -error status, and the gate excludes every non-exec tool. +Accepted residual: a code-mode exec result that legitimately prints one of the four phrases (e.g. +`cat` of this devlog) gains a recovery line. The line is additive text and never changes error +status; the gate excludes every non-code-mode tool, shell bridge, and foreign namespace. + +Marker wording: the live probe shows the host tolerates blank lines and indentation around the +markers and rejects a decorated or missing marker. Every sentence, recovery hint and doc paragraph +says "opens/closes with the bare marker line … blank lines or indentation are tolerated" and never +"the first character must be". Why prose and not repair: `devlog/_plan/260905_apply_patch_envelope_gap/010_disposition.md` refused rewriting JavaScript bodies (MODE B). An object argument inside a program has the same @@ -157,3 +165,12 @@ quo. Wording: "early warning". Final layer: Codex host validation (unchanged). Root cause across 1-3: the roadmap treated "reuse the seam" as "spread into the seam" without re-reading each seam's own policy. Round 2 re-audits with the same reviewer. +## Audit round 2 — synthesis + +| # | Sev | Disposition | +|---|---|---| +| 1 Cursor lowercase replay falls through to legacy loop | High | Folded: the exec-gated branch returns early on an already-annotated result; lowercase and capitalised replay tests assert text/isError/changed (020). | +| 2 Namespace-negative test contradicts the predicate; flat shells annotated | Med | Folded: new `isCodexCodeModeExecResult` gate; shell-bridge, foreign-namespace and Cursor-alias tests; docs say flat catalogs untouched and mean it (020/030). | +| 3 Responses replay `toBe(replayed)` cannot hold | Med | Folded: assert output-item and program identity plus deep-equal idempotence of successive passes (020). | +| 4 Marker wording contradicts whitespace probe | Med | Folded: "bare marker line … blank lines or indentation tolerated" in sentence, hints, structure and docs-site text (010/020/030). | +| 5 Off-by-one anchors | Low | Folded: 116, 32, 45-46, 97-106 (010/020). | diff --git a/devlog/_plan/260907_code_mode_host_contract/010_pre_call_contract.md b/devlog/_plan/260907_code_mode_host_contract/010_pre_call_contract.md index e728a0aa1f..c6d7e6b9aa 100644 --- a/devlog/_plan/260907_code_mode_host_contract/010_pre_call_contract.md +++ b/devlog/_plan/260907_code_mode_host_contract/010_pre_call_contract.md @@ -5,7 +5,7 @@ authorized push and a draft PR so exact-head CI exists for this and later heads. ## MODIFY `src/adapters/exec-tool-result-normalize.ts` -Insert after the `CODE_MODE_RESULT_ECHO_SENTENCE` declaration (its closing `;` is at line 117): +Insert after the `CODE_MODE_RESULT_ECHO_SENTENCE` declaration (its closing `;` is at line 116): ```ts @@ -22,7 +22,7 @@ Insert after the `CODE_MODE_RESULT_ECHO_SENTENCE` declaration (its closing `;` i * had not stated. */ export const CODE_MODE_HOST_CONTRACT_SENTENCE = - "Host contract for the nested helpers: `tools.apply_patch(patch)` takes exactly one string, never an object such as `{input: ...}`; that string's first line must be the bare marker `*** Begin Patch` and its last line `*** End Patch`, with no code fence, prose, or extra asterisks around either marker. The isolate has no `import`, `require`, or module loader; use the globals the exec tool description lists (for example `tools`, `text`, `notify`, `store`/`load`, `ALL_TOOLS`). For a command that may outlive `yield_time_ms`, let `tools.exec_command` return a `session_id` and poll it on later calls with `tools.write_stdin({session_id, chars: \"\"})` instead of blocking a shell in a sleep loop."; + "Host contract for the nested helpers: `tools.apply_patch(patch)` takes exactly one string, never an object such as `{input: ...}`; the patch text opens with the bare marker line `*** Begin Patch` and closes with the bare marker line `*** End Patch`, written without a code fence, prose, or extra asterisks on those lines (blank lines or indentation around the markers are tolerated; a decorated or missing marker is rejected). The isolate has no `import`, `require`, or module loader; use the globals the exec tool description lists (for example `tools`, `text`, `notify`, `store`/`load`, `ALL_TOOLS`). For a command that may outlive `yield_time_ms`, let `tools.exec_command` return a `session_id` and poll it on later calls with `tools.write_stdin({session_id, chars: \"\"})` instead of blocking a shell in a sleep loop."; ``` ## MODIFY `src/adapters/tool-catalog-nudge.ts` @@ -82,7 +82,7 @@ AFTER: import { CODE_MODE_HOST_CONTRACT_SENTENCE, CODE_MODE_RESULT_ECHO_SENTENCE, normalizeEmptyExecToolResultText } from "./exec-tool-result-normalize"; ``` -Insert before `/** Native routed Responses needs the same first-call/output contract… */` (line 33): +Insert before `/** Native routed Responses needs the same first-call/output contract… */` (line 32): ```ts /** Append each sentence a replayed instructions string does not already carry, in order. */ function appendMissing(instructions: string, sentences: readonly string[]): string { @@ -93,7 +93,7 @@ function appendMissing(instructions: string, sentences: readonly string[]): stri } ``` -Lines 46-47 BEFORE (4-space indent): +Lines 45-46 BEFORE (4-space indent): ```ts instructions: instructions.includes(CODE_MODE_RESULT_ECHO_SENTENCE) ? instructions : [instructions, CODE_MODE_RESULT_ECHO_SENTENCE].filter(Boolean).join("\n\n"), @@ -184,4 +184,3 @@ wp2/wp3 will extend it). NOT RUN locally by instruction. Poll `gh run list --branch codex/code-mode-host-contract --json databaseId,headSha,status,conclusion,name` in short `exec_command` calls; when the Cross-platform CI run for `git rev-parse HEAD` completes, `cxc receipt test --session --cwd -- gh run view --exit-status`. - diff --git a/devlog/_plan/260907_code_mode_host_contract/020_post_hoc_annotation.md b/devlog/_plan/260907_code_mode_host_contract/020_post_hoc_annotation.md index b428121f5d..4bfa2df82d 100644 --- a/devlog/_plan/260907_code_mode_host_contract/020_post_hoc_annotation.md +++ b/devlog/_plan/260907_code_mode_host_contract/020_post_hoc_annotation.md @@ -22,11 +22,11 @@ export const CODE_MODE_HOST_FAILURE_GUIDANCE: ReadonlyArray<{ marker: string; gu }, { marker: "the first line of the patch must be", - guidance: "The patch string's first line must be the bare marker `*** Begin Patch` with no code fence, prose, or extra asterisks around it.", + guidance: "The patch text must open with the bare marker line `*** Begin Patch`: no code fence, prose, or extra asterisks on that line (blank lines or indentation before it are tolerated).", }, { marker: "the last line of the patch must be", - guidance: "The patch string's last line must be the bare marker `*** End Patch` with no trailing text or extra asterisks.", + guidance: "The patch text must close with the bare marker line `*** End Patch`: no trailing text or extra asterisks on that line (blank lines after it are tolerated).", }, { marker: "unsupported import in exec", @@ -34,11 +34,26 @@ export const CODE_MODE_HOST_FAILURE_GUIDANCE: ReadonlyArray<{ marker: string; gu }, ]; -const HOST_FAILURE_RECOVERY_PREFIX = "[recovery: "; +/** Prefix of every recovery line this module appends; callers use it to recognise replayed annotations. */ +export const CODE_MODE_HOST_RECOVERY_PREFIX = "[recovery: "; /** - * Append a one-line recovery hint when an exec-bridge result carries a known host failure string. - * Returns undefined when the tool is not an exec bridge, no marker matches, or a recovery line is + * The code-mode `exec` tool itself — bare, or under Cursor's `opencodex-responses` display namespace. + * The four host strings above originate only in that isolate, so flat shell bridges + * (`exec_command`, `shell`, …) and every foreign MCP namespace (`mcp__docker__exec`) are excluded: an + * unrelated server's output that happens to contain the phrase must not receive Codex guidance. + * Narrower than `isCodexExecBridgeTool` on purpose; the empty-output repair keeps the wider gate. + */ +export function isCodexCodeModeExecResult(toolName?: string, toolNamespace?: string): boolean { + if (!toolName) return false; + const lower = toolName.toLowerCase(); + if (toolNamespace) return toolNamespace.includes("opencodex-responses") && lower === "exec"; + return lower === "exec" || lower === "mcp__opencodex-responses__exec" || lower === "mcp_opencodex-responses_exec"; +} + +/** + * Append a one-line recovery hint when a code-mode exec result carries a known host failure string. + * Returns undefined when the tool is not the code-mode exec, no marker matches, or a recovery line is * already present (a replayed annotated result must not grow a second one). Never touches error * status: the host already decided whether the call failed. */ @@ -46,14 +61,17 @@ export function annotateCodeModeHostFailure( text: string, options: { toolName?: string; toolNamespace?: string } = {}, ): string | undefined { - if (!isCodexExecBridgeTool(options.toolName, options.toolNamespace)) return undefined; - if (text.includes(HOST_FAILURE_RECOVERY_PREFIX)) return undefined; + if (!isCodexCodeModeExecResult(options.toolName, options.toolNamespace)) return undefined; + if (text.includes(CODE_MODE_HOST_RECOVERY_PREFIX)) return undefined; const lower = text.toLowerCase(); const hit = CODE_MODE_HOST_FAILURE_GUIDANCE.find(({ marker }) => lower.includes(marker)); - return hit ? `${text}\n${HOST_FAILURE_RECOVERY_PREFIX}${hit.guidance}]` : undefined; + return hit ? `${text}\n${CODE_MODE_HOST_RECOVERY_PREFIX}${hit.guidance}]` : undefined; } ``` +Flat shell tools are deliberately not annotated: the strings come from the code-mode host, and the +"flat catalogs untouched" statement in the docs is therefore literally true. + ## MODIFY `src/adapters/responses-code-mode.ts` Line 3 import gains `annotateCodeModeHostFailure`. @@ -125,11 +143,12 @@ empty-success nor a failed-empty wrapper, so every existing grouping expectation ## MODIFY `src/adapters/cursor/tool-result-normalize.ts` -Imports (lines 12-18) gain `annotateCodeModeHostFailure`. `RUNTIME_FAILURE_GUIDANCE` (lines 50-67) and its +Imports (lines 12-18) gain `CODE_MODE_HOST_RECOVERY_PREFIX`, `annotateCodeModeHostFailure` and +`isCodexCodeModeExecResult`. `RUNTIME_FAILURE_GUIDANCE` (lines 50-67) and its loop (lines 107-113) stay byte-identical: Cursor's marker semantics, case sensitivity and `isError:true` policy are its own. -Lines 96-105 BEFORE (2-space indent): +Lines 97-106 BEFORE (2-space indent): ```ts if (isCodexExecBridgeTool(options.toolName, options.toolNamespace) && isEmptyOrFailedExecWrapper(text.trim())) { return { @@ -154,14 +173,19 @@ AFTER (append one branch directly after that block): changed: true, }; } - // A host failure string inside an exec-bridge result gets the rule it broke appended. The - // helper is exec-gated and refuses already-annotated text, so a replayed result does not grow - // a second line; Cursor's isError decision is left exactly as the caller passed it. - const hostFailure = annotateCodeModeHostFailure(text, options); - if (hostFailure !== undefined) return { text: hostFailure, isError, changed: true }; + // A host failure string inside a code-mode exec result gets the rule it broke appended, with + // Cursor's isError decision left exactly as the caller passed it. A replayed result that already + // carries a recovery line returns here unchanged: falling through would let the legacy loop + // below match the lowercase import marker a second time and flip isError. + if (isCodexCodeModeExecResult(options.toolName, options.toolNamespace)) { + if (text.includes(CODE_MODE_HOST_RECOVERY_PREFIX)) return { text, isError, changed: false }; + const hostFailure = annotateCodeModeHostFailure(text, options); + if (hostFailure !== undefined) return { text: hostFailure, isError, changed: true }; + } ``` The existing `unsupported import in exec` row in `RUNTIME_FAILURE_GUIDANCE` still serves node_repl / -Computer Use tools; for exec-bridge tools the new branch runs first and carries the shared hint. +Computer Use tools; for the code-mode exec the new branch runs first, carries the shared hint, and +terminates replay before the legacy loop can see it. ## NEW `tests/adapters/exec-tool-result-normalize.test.ts` @@ -190,13 +214,18 @@ describe("code-mode host failure annotation", () => { expect(annotateCodeModeHostFailure("Script error:\ntool `apply_patch` expects a string input", { toolName: "exec" })).toContain("exactly one string"); expect(annotateCodeModeHostFailure( "apply_patch verification failed: invalid patch: The first line of the patch must be '*** Begin Patch'", - { toolName: "exec_command" }, - )).toContain("bare marker `*** Begin Patch`"); + { toolName: "exec" }, + )).toContain("bare marker line `*** Begin Patch`"); }); - test("leaves non-exec tools, non-matching text and already-annotated text byte-identical", () => { + test("leaves non-exec tools, shell bridges, foreign namespaces, non-matching text and already-annotated text alone", () => { expect(annotateCodeModeHostFailure("expects a string input", { toolName: "read_file" })).toBeUndefined(); - expect(annotateCodeModeHostFailure("expects a string input", { toolName: "exec_command", toolNamespace: "mcp__docker" })).toBeUndefined(); + // Flat shell bridges never run the isolate, so the four strings cannot be theirs. + expect(annotateCodeModeHostFailure("expects a string input", { toolName: "exec_command" })).toBeUndefined(); + // A foreign MCP server's own exec is not Codex's, even when its output quotes the phrase. + expect(annotateCodeModeHostFailure("expects a string input", { toolName: "exec", toolNamespace: "mcp__docker" })).toBeUndefined(); + // Cursor's display namespace for the same code-mode tool still counts. + expect(annotateCodeModeHostFailure("expects a string input", { toolName: "exec", toolNamespace: "mcp__opencodex-responses" })).toContain("[recovery:"); expect(annotateCodeModeHostFailure("all good", { toolName: "exec" })).toBeUndefined(); const once = annotateCodeModeHostFailure("expects a string input", { toolName: "exec" }); if (!once) throw new Error("expected one annotation"); @@ -232,9 +261,13 @@ entry is required and `tests/test-layout-tooling.test.ts` names it if missing. const wire = JSON.parse(createResponsesPassthroughAdapter(routed).buildRequest(parseRequest(body)).body); expect(wire.input[1].output).toBe(`${failure}\n[recovery: tools.apply_patch takes exactly one string argument; pass the patch text itself, not an object such as {input: ...}.]`); expect(JSON.parse(wire.input[0].arguments).input).toBe(body.input[0].input); - // Replayed history already carrying the hint is not annotated twice. + // Replayed history already carrying the hint is not annotated twice: the output item and the + // program keep their identity, and a second pass over the normalized body is a deep no-op. const replayed = raw(wire.input[1].output); - expect(normalizeResponsesCodeMode(replayed, parseRequest(replayed), routed)).toBe(replayed); + const once = normalizeResponsesCodeMode(replayed, parseRequest(replayed), routed) as typeof replayed; + expect(once.input[1]).toBe(replayed.input[1]); + expect(once.input[0]).toBe(replayed.input[0]); + expect(normalizeResponsesCodeMode(once, parseRequest(once), routed)).toEqual(once); }); ``` @@ -252,7 +285,7 @@ entry is required and `tests/test-layout-tooling.test.ts` names it if missing. const { body } = await createKiroAdapter(provider).buildRequest(parsedWith(messages, [execTool])); const resultText = JSON.parse(body).conversationState.currentMessage.userInputMessage .userInputMessageContext.toolResults[0].content[0].text; - expect(resultText).toBe(`${failure}\n[recovery: The patch string's first line must be the bare marker \`*** Begin Patch\` with no code fence, prose, or extra asterisks around it.]`); + expect(resultText).toBe(`${failure}\n[recovery: The patch text must open with the bare marker line \`*** Begin Patch\`: no code fence, prose, or extra asterisks on that line (blank lines or indentation before it are tolerated).]`); }); ``` - In the grouped-result table (the `execResult` cases around lines 1195-1262) add one case: @@ -271,13 +304,24 @@ entry is required and `tests/test-layout-tooling.test.ts` names it if missing. `tests/providers/cursor/cursor-toolresult-normalize.test.ts` — add after the `test.each` runtime-failure table: ```ts - test("an exec-bridge result carrying a host failure string gains the shared hint and keeps its isError", () => { - const out = normalizeCursorToolResultText("Unsupported import in exec: node:fs", { toolName: "exec" }); - expect(out.changed).toBe(true); - expect(out.isError).toBe(false); - expect(out.text).toContain("[recovery: Imports are not available in this exec context"); - // Replay of the annotated text with isError=false must not grow a second line. - expect(normalizeCursorToolResultText(out.text, { toolName: "exec" }).changed).toBe(false); + test.each(["Unsupported import in exec: node:fs", "unsupported import in exec: node:fs"])( + "a code-mode exec result carrying %p gains the shared hint, keeps its isError, and is not re-annotated on replay", + (payload) => { + const out = normalizeCursorToolResultText(payload, { toolName: "exec" }); + expect(out.changed).toBe(true); + expect(out.isError).toBe(false); + expect(out.text).toBe(`${payload}\n[recovery: Imports are not available in this exec context; use the injected globals (tools, text, notify, store, load, ALL_TOOLS) instead.]`); + // Replay through Responses history arrives with isError=false; the legacy lowercase marker + // row must not get a second look at it. + const replay = normalizeCursorToolResultText(out.text, { toolName: "exec", isError: false }); + expect(replay).toEqual({ text: out.text, isError: false, changed: false }); + }, + ); + + test("the legacy node_repl import row keeps its own isError policy", () => { + const out = normalizeCursorToolResultText("unsupported import in exec", { toolName: "js", toolNamespace: "mcp__node_repl" }); + expect(out.isError).toBe(true); + expect(out.text).toContain("injected globals"); }); test("a non-exec tool whose successful output merely mentions a host phrase stays byte-identical", () => { @@ -297,4 +341,3 @@ Stage only the files above (`git diff --cached --stat` first); commit `--no-veri NOT RUN locally. Exact-head Cross-platform CI on the wp2 head; receipt via `cxc receipt test --session --cwd -- gh run view --exit-status`. - diff --git a/devlog/_plan/260907_code_mode_host_contract/030_docs_and_delivery.md b/devlog/_plan/260907_code_mode_host_contract/030_docs_and_delivery.md index e0c0df7990..f3fc8d2eef 100644 --- a/devlog/_plan/260907_code_mode_host_contract/030_docs_and_delivery.md +++ b/devlog/_plan/260907_code_mode_host_contract/030_docs_and_delivery.md @@ -12,14 +12,16 @@ search usable on xAI's public Responses endpoint…": ``` Routed code-mode turns also carry the host contract for the nested helpers, stated in the same three injection sites as the result-emission rule (shared catalog nudge, Cursor code-mode guidance, native -routed Responses instructions): `tools.apply_patch` takes one string whose first and last lines are -the bare patch markers, the isolate has no `import`/`require`, and a command that outlives +routed Responses instructions): `tools.apply_patch` takes one string that opens and closes with the +bare patch marker lines (blank lines or indentation around them are tolerated; a decorated or missing +marker is rejected), the isolate has no `import`/`require`, and a command that outlives `yield_time_ms` is polled through `write_stdin` with empty `chars` rather than a shell sleep loop. -When an exec-bridge result still carries one of the host's failure strings ("expects a string +When a code-mode exec result still carries one of the host's failure strings ("expects a string input", "The first line of the patch must be", "The last line of the patch must be", "Unsupported import in exec"), the native routed Responses, Kiro, and Cursor result paths append a one-line -recovery hint naming the broken rule; Cursor's error classification and Kiro's whitespace and -failed-wrapper grouping are unchanged. Both halves live in `src/adapters/exec-tool-result-normalize.ts` +recovery hint naming the broken rule; flat shell bridges and foreign MCP namespaces are never +annotated, and Cursor's error classification and Kiro's whitespace and failed-wrapper grouping are +unchanged. Both halves live in `src/adapters/exec-tool-result-normalize.ts` so the pre-call and post-hoc wording cannot drift. This guidance and annotation change rewrites neither the model's JavaScript nor its patch payload; the existing name-alias delimiter normalization in `src/responses/code-mode-helper-compat.ts` is unchanged, and the host still rejects a @@ -41,9 +43,9 @@ Insert after the paragraph ending "…and unrelated native custom payloads stay ``` Routed code-mode turns are also told the host's rules for the nested helpers before the first -call: `tools.apply_patch` takes one string whose first and last lines are the bare patch markers, -the isolate has no `import`, and long-running commands are polled through `write_stdin`. When an -exec result on the native routed Responses, Kiro, or Cursor path still carries one of the host's +call: `tools.apply_patch` takes one string that opens and closes with the bare patch marker lines, +the isolate has no `import`, and long-running commands are polled through `write_stdin`. When a +code-mode exec result on the native routed Responses, Kiro, or Cursor path still carries one of the host's failure messages, opencodex appends a one-line hint naming the rule. This change does not rewrite the model's code or its patch text. ``` @@ -77,4 +79,3 @@ Append `040_delivery_record.md` with PR number, head SHA, CI run id, per-job res improve (LOOP-PESSIMIST-01: prose cannot force compliance; effect on real Grok defect rate is unmeasured until a live re-probe), and the residual: Anthropic/Google/OpenAI-chat/command-code tool-result paths do not annotate host failures because they have no exec-result seam today. - From f4ae062082d6fe2b8f2d3af76c77533f21f006f2 Mon Sep 17 00:00:00 2001 From: DaedalGames Date: Mon, 7 Sep 2026 14:45:14 +0900 Subject: [PATCH 069/412] fix(codex): retain actionable validation failures without changing pause state --- .github/pr-assets/codex-quota-evidence.md | 4 +- .github/pr-assets/codex-quota-pending.png | Bin 230070 -> 229755 bytes .github/pr-assets/codex-quota-recovered.png | Bin 218961 -> 220523 bytes .../docs/fr/guides/codex-integration.md | 2 +- .../content/docs/guides/codex-integration.md | 2 +- .../docs/ja/guides/codex-integration.md | 2 +- .../docs/ko/guides/codex-integration.md | 2 +- .../docs/ru/guides/codex-integration.md | 2 +- .../docs/tr/guides/codex-integration.md | 2 +- .../docs/zh-cn/guides/codex-integration.md | 2 +- .../docs/zh-tw/guides/codex-integration.md | 2 +- src/codex/auth-api.ts | 11 ++- src/oauth/health.ts | 13 ++- .../codex-integration/codex-auth-api.test.ts | 79 ++++++++++++++++-- tests/gui/rate-limit-reset-credits.test.ts | 4 +- 15 files changed, 103 insertions(+), 24 deletions(-) diff --git a/.github/pr-assets/codex-quota-evidence.md b/.github/pr-assets/codex-quota-evidence.md index ef24fec548..2c2229336d 100644 --- a/.github/pr-assets/codex-quota-evidence.md +++ b/.github/pr-assets/codex-quota-evidence.md @@ -12,13 +12,15 @@ No live OpenAI account was used or charged. The browser was Microsoft Edge through Playwright, at 1440 × 1100, English/light theme, with external browser requests blocked. Verification ran on Windows. -The final capture used runtime and GUI changes through `094d253b1`. +The final capture used runtime and GUI changes through `25798a590`. 1. Open Codex Set → Multi-auth, click Add, enter an account ID, and choose Device code login. Authorize through the mock device service. 2. The actual token exchange and authenticated usage read return a Pro account with weekly usage at 100%. Registration persists it as validation pending: one usage read, zero model calls, and no successful-validation timestamp. + The completion notice also says validation is pending; no model-selection + dialog opens for this unroutable account. 3. Reload the page and click Refresh quotas while usage is still 100%. The account remains pending. Cumulative counts: two usage reads, zero model calls. The pending screenshot shows the status and the missing selection button. diff --git a/.github/pr-assets/codex-quota-pending.png b/.github/pr-assets/codex-quota-pending.png index 154a72697e4621f0952b3f0c8c3c9c0c63bc3e17..6a805026b8788face7910e809a0df8e81f507300 100644 GIT binary patch delta 220154 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 U5%vR000000Nks-uM6N<$g7MRemH+?% delta 220717 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⋙IQ{(}z)AbJQT#NE-;LfXO)b# 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 { await refreshAccounts(); expect(warmups).toBe(0); used = 0; - config.pausedCodexAccountIds = [accountId]; - saveConfig(config); - await refreshAccounts(); - expect(warmups).toBe(0); - config.pausedCodexAccountIds = []; - saveConfig(config); clearAccountQuota(); await listCodexAuthAccounts(config, false); expect(warmups).toBe(0); // Passive reads never spend inference. @@ -5075,6 +5069,79 @@ describe("codex-auth API", () => { expect(warmups).toBe(3); }); + test.each([ + { status: 401, replace: false }, { status: 403, replace: false }, + { status: 429, replace: false }, { status: 500, replace: false }, + { status: 401, replace: true }, { status: 403, replace: true }, + ])("deferred validation reports generation-current authentication failures: %j", async ({ status, replace }) => { + const accountId = "validation-auth-error"; + const config = makeConfig({ codexAccounts: [{ id: accountId, plan: "pro", isMain: false }] }); + saveConfig(config); + setLiveStateStoreConfig(config); + const credential = { accessToken: "auth-error-access", refreshToken: "auth-error-refresh", + expiresAt: Date.now() + 3600_000, chatgptAccountId: "auth-error-account" }; + saveCodexAccountCredential(accountId, credential, { validationPending: true }); + let fail = true; + globalThis.fetch = (async (input: RequestInfo | URL) => { + if (String(input).endsWith("/wham/usage")) return Response.json({ plan_type: "pro", + rate_limit: { secondary_window: { used_percent: 0, limit_window_seconds: 604800 } } }); + if (String(input).endsWith("/codex/responses")) { + if (fail && replace) saveCodexAccountCredential(accountId, { ...credential, accessToken: "replacement" }, { validationPending: true }); + return fail ? new Response("private-validation-body", { status }) + : new Response('data: {"type":"response.completed"}\n\n'); + } + throw new Error("unexpected request"); + }) as typeof fetch; + const refresh = async () => { + const req = new Request("http://localhost/api/codex-auth/accounts/refresh", { method: "POST" }); + const response = await handleCodexAuthAPI(req, new URL(req.url), config); + expect(response?.status).toBe(200); + return await response!.json(); + }; + const response = await refresh(); + expect(JSON.stringify(response)).not.toContain("private-validation-body"); + expect(readCodexAccountRecord(accountId)?.codexValidationPending).toBe(true); + expect(isCodexAccountUsable(config, accountId)).toBe(false); + // Clear volatile evidence: quota reads and restarts must not hide a permanent + // model-authorization failure; a replaced generation must not inherit it. + clearAccountNeedsReauth(accountId); + const rows = await listCodexAuthAccounts(config, false); + const authFailed = !replace && (status === 401 || status === 403); + expect(rows.find(row => row.id === accountId)).toMatchObject({ + needsReauth: authFailed, + health: { status: authFailed ? "reauth_required" : "warning", reason: authFailed ? "refresh_failed" : "validation_pending" }, + }); + fail = false; + await refresh(); + expect(readCodexAccountRecord(accountId)?.codexValidationPending).toBeUndefined(); + expect(isCodexAccountUsable(config, accountId)).toBe(true); + }); + + test("explicit validation preserves an account's pause and selection state", async () => { + const accountId = "paused-validation"; + const config = makeConfig({ codexAccounts: [{ id: accountId, plan: "pro", isMain: false }], pausedCodexAccountIds: [accountId] }); + saveConfig(config); + setLiveStateStoreConfig(config); + saveCodexAccountCredential(accountId, { accessToken: "paused-access", refreshToken: "paused-refresh", + expiresAt: Date.now() + 3600_000, chatgptAccountId: "paused-account" }, { validationPending: true }); + let warmups = 0; + globalThis.fetch = (async (input: RequestInfo | URL) => { + if (String(input).endsWith("/wham/usage")) return Response.json({ plan_type: "pro", + rate_limit: { secondary_window: { used_percent: 0, limit_window_seconds: 604800 } } }); + if (String(input).endsWith("/codex/responses")) { + warmups++; + return new Response('data: {"type":"response.completed"}\n\n'); + } + throw new Error("unexpected request"); + }) as typeof fetch; + const req = new Request("http://localhost/api/codex-auth/accounts/refresh", { method: "POST" }); + expect((await handleCodexAuthAPI(req, new URL(req.url), config))?.status).toBe(200); + expect(warmups).toBe(1); + expect(readCodexAccountRecord(accountId)?.codexValidationPending).toBeUndefined(); + expect(loadConfig().pausedCodexAccountIds).toEqual([accountId]); + expect(loadConfig().activeCodexAccountId).toBeUndefined(); + }); + test("explicit refresh joining a passive quota read retains deferred validation intent", async () => { const accountId = "quota-coalesced"; const config = makeConfig({ codexAccounts: [{ id: accountId, email: "quota@example.test", plan: "pro", isMain: false }] }); diff --git a/tests/gui/rate-limit-reset-credits.test.ts b/tests/gui/rate-limit-reset-credits.test.ts index 6078ea84a9..a65445e3cc 100644 --- a/tests/gui/rate-limit-reset-credits.test.ts +++ b/tests/gui/rate-limit-reset-credits.test.ts @@ -302,8 +302,8 @@ describe("rate-limit reset credits", () => { expect(source).toContain("className=\"card-badges\""); expect(source).toContain(" onOpenReset(a)} />"); // Next-session still renders BESIDE the ticket; health projection also suppresses - // it for projected reauth/cooldown (not only the legacy needsReauth flag). - expect(source).toContain("{isNext(a) && !showReauth && !inCooldown && ("); + // it for projected reauth/cooldown and pending validation. + expect(source).toContain("{isNext(a) && !showReauth && !inCooldown && !validationPending && ("); expect(source).toContain("{t(accountModeState === \"direct\" ? \"codexAuth.poolPrepared\" : \"codexAuth.nextSession\")}"); const styles = await Bun.file("gui/src/styles.css").text(); expect(styles).toContain(".card-badges { display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; min-width: 0; }"); From 3bcb9aa453a6567205d38409d955b3141ad977dd Mon Sep 17 00:00:00 2001 From: JUN <243035832+lidge-jun@users.noreply.github.com> Date: Mon, 7 Sep 2026 14:45:42 +0900 Subject: [PATCH 070/412] docs(devlog): fold audit round 3 into the code-mode host contract roadmap --- .../000_plan.md | 29 +++++++- .../020_post_hoc_annotation.md | 73 +++++++++++++++---- .../030_docs_and_delivery.md | 6 +- 3 files changed, 88 insertions(+), 20 deletions(-) diff --git a/devlog/_plan/260907_code_mode_host_contract/000_plan.md b/devlog/_plan/260907_code_mode_host_contract/000_plan.md index 91c130df0a..0f9a8057fb 100644 --- a/devlog/_plan/260907_code_mode_host_contract/000_plan.md +++ b/devlog/_plan/260907_code_mode_host_contract/000_plan.md @@ -72,9 +72,10 @@ Not a NOOP. New exports in `exec-tool-result-normalize.ts` (full text in 010/020): -1. `CODE_MODE_HOST_CONTRACT_SENTENCE` — pre-call: one string argument, bare markers as first/last - line with nothing before or after them, no `import`/`require` (globals per the exec description, - non-exhaustive), `session_id` + `write_stdin` polling. +1. `CODE_MODE_HOST_CONTRACT_SENTENCE` — pre-call: one string argument; the patch opens and closes + with the bare marker lines (blank lines or indentation around them tolerated; decorated or + missing marker rejected); no `import`/`require` (globals per the exec description, + non-exhaustive); `session_id` + `write_stdin` polling. 2. `CODE_MODE_HOST_FAILURE_GUIDANCE` — marker → recovery rows for the four host strings, matched case-insensitively. 3. `annotateCodeModeHostFailure(text, {toolName, toolNamespace})` — gated by a new, narrower @@ -89,9 +90,21 @@ it gains one exec-gated branch that inserts the shared annotation WITHOUT changi (audit blockers 2 and 3). Kiro substitutes the annotation only where it would otherwise carry the raw text, leaving whitespace and failed-wrapper grouping untouched (blocker 1). +Code-mode context per seam: the native routed Responses seam already runs only after the body-level +code-mode gate (`responses-code-mode.ts:35-37`), so its annotation is exact. Kiro has +`codeModeExecName` in scope at the same call site (`kiro.ts:650`) and additionally requires it, so a +structured `exec` or an `exec` beside a shell bridge is never annotated there. Cursor's +`normalizeCursorToolResultText` is reached from six call sites without catalog context +(`protobuf-request.ts:392,842,1062,1097,1158,1272`); threading code-mode context through them is a +larger refactor than this unit, so Cursor coverage is name-based (exact `exec` under the +`opencodex-responses` provider). That is an accepted residual, recorded here and in the +structure doc: on Cursor a structured tool literally named `exec` whose output quotes one of the +four phrases would gain an additive recovery line with no error flip. + Accepted residual: a code-mode exec result that legitimately prints one of the four phrases (e.g. `cat` of this devlog) gains a recovery line. The line is additive text and never changes error -status; the gate excludes every non-code-mode tool, shell bridge, and foreign namespace. +status; the gate excludes every non-`exec` tool, every shell bridge, and every namespace other than +the exact `opencodex-responses` display aliases. Marker wording: the live probe shows the host tolerates blank lines and indentation around the markers and rejects a decorated or missing marker. Every sentence, recovery hint and doc paragraph @@ -174,3 +187,11 @@ re-reading each seam's own policy. Round 2 re-audits with the same reviewer. | 3 Responses replay `toBe(replayed)` cannot hold | Med | Folded: assert output-item and program identity plus deep-equal idempotence of successive passes (020). | | 4 Marker wording contradicts whitespace probe | Med | Folded: "bare marker line … blank lines or indentation tolerated" in sentence, hints, structure and docs-site text (010/020/030). | | 5 Off-by-one anchors | Low | Folded: 116, 32, 45-46, 97-106 (010/020). | + +## Audit round 3 — synthesis (GO-WITH-FIXES, blockers=3) + +| # | Sev | Disposition | +|---|---|---| +| 1 Bare `exec` name does not prove code mode | Med | Folded for Responses (body gate) and Kiro (`codeModeExecName` gate + structured/shell-bridge negative tests); accepted and narrowed for Cursor (name-based, additive text only) — see "Code-mode context per seam". | +| 2 Namespace `includes` admits foreign tools | Med | Folded: exact equality against `opencodex-responses` / `mcp__opencodex-responses` and the two flattened aliases; `mcp__foreign-opencodex-responses` negative and both flattened positives added (020). | +| 3 Summary retained the rejected whitespace claim | Low | Folded (this file, Design §1). | diff --git a/devlog/_plan/260907_code_mode_host_contract/020_post_hoc_annotation.md b/devlog/_plan/260907_code_mode_host_contract/020_post_hoc_annotation.md index 4bfa2df82d..86430340c0 100644 --- a/devlog/_plan/260907_code_mode_host_contract/020_post_hoc_annotation.md +++ b/devlog/_plan/260907_code_mode_host_contract/020_post_hoc_annotation.md @@ -37,18 +37,26 @@ export const CODE_MODE_HOST_FAILURE_GUIDANCE: ReadonlyArray<{ marker: string; gu /** Prefix of every recovery line this module appends; callers use it to recognise replayed annotations. */ export const CODE_MODE_HOST_RECOVERY_PREFIX = "[recovery: "; +/** Namespaces under which Cursor displays Codex's own Responses tools (see cursor/tool-naming.ts). */ +const CODEX_RESPONSES_DISPLAY_NAMESPACES: ReadonlySet = new Set(["opencodex-responses", "mcp__opencodex-responses"]); +/** Flattened spellings of the same code-mode exec when a client folds the namespace into the name. */ +const CODEX_CODE_MODE_EXEC_ALIASES: ReadonlySet = new Set(["exec", "mcp__opencodex-responses__exec", "mcp_opencodex-responses_exec"]); + /** - * The code-mode `exec` tool itself — bare, or under Cursor's `opencodex-responses` display namespace. - * The four host strings above originate only in that isolate, so flat shell bridges - * (`exec_command`, `shell`, …) and every foreign MCP namespace (`mcp__docker__exec`) are excluded: an - * unrelated server's output that happens to contain the phrase must not receive Codex guidance. - * Narrower than `isCodexExecBridgeTool` on purpose; the empty-output repair keeps the wider gate. + * The code-mode `exec` tool by NAME — bare, or under Codex's own `opencodex-responses` display + * namespace, matched exactly. The four host strings above originate only in that isolate, so flat + * shell bridges (`exec_command`, `shell`, …) and every other namespace (`mcp__docker`, + * `mcp__foreign-opencodex-responses`) are excluded: an unrelated server's output that quotes the + * phrase must not receive Codex guidance. Narrower than `isCodexExecBridgeTool` on purpose; the + * empty-output repair keeps the wider gate. Callers that KNOW the catalog shape (Kiro's + * `codeModeExecName`, the Responses body gate) add that check on top; this predicate alone cannot + * tell a structured tool named `exec` from the freeform one. */ export function isCodexCodeModeExecResult(toolName?: string, toolNamespace?: string): boolean { if (!toolName) return false; const lower = toolName.toLowerCase(); - if (toolNamespace) return toolNamespace.includes("opencodex-responses") && lower === "exec"; - return lower === "exec" || lower === "mcp__opencodex-responses__exec" || lower === "mcp_opencodex-responses_exec"; + if (toolNamespace !== undefined) return CODEX_RESPONSES_DISPLAY_NAMESPACES.has(toolNamespace) && lower === "exec"; + return CODEX_CODE_MODE_EXEC_ALIASES.has(lower); } /** @@ -122,10 +130,14 @@ AFTER: ```ts const execOptions = { toolName: tr.toolName, toolNamespace: tr.toolNamespace }; const normalizedExecText = normalizeEmptyExecToolResultText(text, execOptions); - // A host failure string inside a non-empty exec result gets the rule it broke appended. This - // is the only substitution the grouping path below also carries: whitespace and empty/failed + // A host failure string inside a non-empty exec result gets the rule it broke appended, but + // only when this request's emitted catalog is genuinely code mode (`codeModeExecName` above): + // a structured tool named exec, or exec beside a shell bridge, never ran the isolate. This is + // the only substitution the grouping path below also carries: whitespace and empty/failed // wrappers keep their existing raw policy. - const annotatedExecText = normalizedExecText === undefined ? annotateCodeModeHostFailure(text, execOptions) : undefined; + const annotatedExecText = normalizedExecText === undefined && codeModeExecName !== undefined + ? annotateCodeModeHostFailure(text, execOptions) + : undefined; const resultText = normalizedExecText ?? annotatedExecText ?? (text.trim() ? text : KIRO_EMPTY_TOOL_RESULT_MESSAGE); const images = extractKiroImages(tr.content); const toolUseId = normalizeToolId(tr.toolCallId); @@ -222,10 +234,19 @@ describe("code-mode host failure annotation", () => { expect(annotateCodeModeHostFailure("expects a string input", { toolName: "read_file" })).toBeUndefined(); // Flat shell bridges never run the isolate, so the four strings cannot be theirs. expect(annotateCodeModeHostFailure("expects a string input", { toolName: "exec_command" })).toBeUndefined(); - // A foreign MCP server's own exec is not Codex's, even when its output quotes the phrase. + // A foreign MCP server's own exec is not Codex's, even when its output quotes the phrase, and a + // namespace that merely CONTAINS the provider name is still foreign. expect(annotateCodeModeHostFailure("expects a string input", { toolName: "exec", toolNamespace: "mcp__docker" })).toBeUndefined(); - // Cursor's display namespace for the same code-mode tool still counts. - expect(annotateCodeModeHostFailure("expects a string input", { toolName: "exec", toolNamespace: "mcp__opencodex-responses" })).toContain("[recovery:"); + expect(annotateCodeModeHostFailure("expects a string input", { toolName: "exec", toolNamespace: "mcp__foreign-opencodex-responses" })).toBeUndefined(); + // Codex's own display namespaces and flattened aliases for the same code-mode tool still count. + for (const options of [ + { toolName: "exec", toolNamespace: "opencodex-responses" }, + { toolName: "exec", toolNamespace: "mcp__opencodex-responses" }, + { toolName: "mcp__opencodex-responses__exec" }, + { toolName: "mcp_opencodex-responses_exec" }, + ]) { + expect(annotateCodeModeHostFailure("expects a string input", options)).toContain("[recovery:"); + } expect(annotateCodeModeHostFailure("all good", { toolName: "exec" })).toBeUndefined(); const once = annotateCodeModeHostFailure("expects a string input", { toolName: "exec" }); if (!once) throw new Error("expected one annotation"); @@ -275,7 +296,8 @@ entry is required and `tests/test-layout-tooling.test.ts` names it if missing. - After `"an empty code-mode exec result carries the actionable reason…"` (line 323) add: ```ts test("a code-mode exec result carrying a host failure string names the broken rule", async () => { - const execTool = { name: "exec", description: "Run JavaScript", parameters: { type: "object" } }; + // freeform: the Kiro seam annotates only when the emitted catalog is genuinely code mode. + const execTool = { name: "exec", description: "Run JavaScript", freeform: true, parameters: { type: "object" } }; const failure = "apply_patch verification failed: invalid patch: The first line of the patch must be '*** Begin Patch'"; const messages = [ { role: "user", content: "run it" }, @@ -287,6 +309,29 @@ entry is required and `tests/test-layout-tooling.test.ts` names it if missing. .userInputMessageContext.toolResults[0].content[0].text; expect(resultText).toBe(`${failure}\n[recovery: The patch text must open with the bare marker line \`*** Begin Patch\`: no code fence, prose, or extra asterisks on that line (blank lines or indentation before it are tolerated).]`); }); + + test("a host failure string on a non-code-mode catalog stays raw", async () => { + const failure = "tool `apply_patch` expects a string input"; + const messages = [ + { role: "user", content: "run it" }, + { role: "assistant", content: [{ type: "toolCall", id: "call-x", name: "exec", arguments: {} }] }, + { role: "toolResult", toolCallId: "call-x", toolName: "exec", content: failure, isError: false }, + ]; + for (const tools of [ + // A structured tool that merely shares the name exec. + [{ name: "exec", description: "Run a shell string", parameters: { type: "object" } }], + // Freeform exec beside a bare shell bridge is the flat-catalog shape, not code mode. + [ + { name: "exec", description: "Run JavaScript", freeform: true, parameters: { type: "object" } }, + { name: "exec_command", description: "Run", parameters: { type: "object" } }, + ], + ]) { + const { body } = await createKiroAdapter(provider).buildRequest(parsedWith(messages, tools)); + const resultText = JSON.parse(body).conversationState.currentMessage.userInputMessage + .userInputMessageContext.toolResults[0].content[0].text; + expect(resultText).toBe(failure); + } + }); ``` - In the grouped-result table (the `execResult` cases around lines 1195-1262) add one case: ```ts diff --git a/devlog/_plan/260907_code_mode_host_contract/030_docs_and_delivery.md b/devlog/_plan/260907_code_mode_host_contract/030_docs_and_delivery.md index f3fc8d2eef..8bd40668e0 100644 --- a/devlog/_plan/260907_code_mode_host_contract/030_docs_and_delivery.md +++ b/devlog/_plan/260907_code_mode_host_contract/030_docs_and_delivery.md @@ -20,8 +20,10 @@ When a code-mode exec result still carries one of the host's failure strings ("e input", "The first line of the patch must be", "The last line of the patch must be", "Unsupported import in exec"), the native routed Responses, Kiro, and Cursor result paths append a one-line recovery hint naming the broken rule; flat shell bridges and foreign MCP namespaces are never -annotated, and Cursor's error classification and Kiro's whitespace and failed-wrapper grouping are -unchanged. Both halves live in `src/adapters/exec-tool-result-normalize.ts` +annotated, Responses and Kiro additionally require the request's verified code-mode catalog, Cursor +matches the exact `exec` name under its `opencodex-responses` provider without catalog context, and +Cursor's error classification and Kiro's whitespace and failed-wrapper grouping are unchanged. Both +halves live in `src/adapters/exec-tool-result-normalize.ts` so the pre-call and post-hoc wording cannot drift. This guidance and annotation change rewrites neither the model's JavaScript nor its patch payload; the existing name-alias delimiter normalization in `src/responses/code-mode-helper-compat.ts` is unchanged, and the host still rejects a From 5b70dddb0bdeba8d26b7844df63c70f796b9228c Mon Sep 17 00:00:00 2001 From: JUN <243035832+lidge-jun@users.noreply.github.com> Date: Mon, 7 Sep 2026 14:46:34 +0900 Subject: [PATCH 071/412] docs(devlog): record live Codex host probe evidence for the code-mode contract --- .../001_host_probe_evidence.md | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 devlog/_plan/260907_code_mode_host_contract/001_host_probe_evidence.md diff --git a/devlog/_plan/260907_code_mode_host_contract/001_host_probe_evidence.md b/devlog/_plan/260907_code_mode_host_contract/001_host_probe_evidence.md new file mode 100644 index 0000000000..757ae63fe4 --- /dev/null +++ b/devlog/_plan/260907_code_mode_host_contract/001_host_probe_evidence.md @@ -0,0 +1,53 @@ +# 001 — Live host probe evidence (Codex 0.153.2, 2026-09-07) + +Research record backing the incident table in 000_plan.md. Every row was executed from this +session's own code-mode isolate (`custom_exec` → `tools.apply_patch`) against +`/Users/jun/.codex/worktrees/ec3e/opencodex/.tmp/`; scratch files were deleted afterwards. + +## Binary strings + +`strings -n 8` over the installed binaries under +`@openai/codex-darwin-arm64/vendor/aarch64-apple-darwin/bin/`: + +| Binary | String | +|---|---| +| `codex` | `\` expects a string input` (preceded by the tool name) | +| `codex` | `The first line of the patch must be '*** Begin Patch'` | +| `codex` | `The last line of the patch must be '*** End Patch'` | +| `codex` | `Script running with cell ID ` | +| `codex` | `Session identifier to pass to write_stdin when the process is still running.` | +| `codex` | `Bytes to write to stdin. Defaults to empty, which polls without writing.` | +| `codex-code-mode-host` | `Unsupported import in exec: ` and `unsupported import in exec` | + +## apply_patch argument probes + +| Argument passed to `tools.apply_patch` | Result | +|---|---| +| `{ input: "*** Begin Patch\n*** End Patch" }` | throws `tool \`apply_patch\` expects a string input` | +| `"*** Begin Patch ***\n*** Add File: …\n+z\n*** End Patch ***"` | throws `apply_patch verification failed: invalid patch: The first line of the patch must be '*** Begin Patch'` | +| `"\n*** Begin Patch\n*** Add File: …\n+x\n*** End Patch"` | accepted; file written | +| `"\n\n*** Begin Patch\n…"` | accepted; file written | +| `" *** Begin Patch\n…"` (two-space indent) | accepted; file written | +| `"…*** End Patch\n\n"` | accepted; file written | +| a patch with two operations on the same path | throws `invalid patch: multiple operations target ` | +| two `*** End Patch` lines (envelope pasted twice) | throws `The last line of the patch must be '*** End Patch'` | + +Conclusion carried into the wording: the host strips surrounding whitespace before checking the +marker lines, so "no leading newline" is not a rule. The rule is that the first non-blank line is +exactly `*** Begin Patch` and the last is exactly `*** End Patch`, undecorated. + +## Long-running command protocol + +The `exec_command` schema in this session: `yield_time_ms` "Wait before yielding output. Defaults to +10000 ms; effective range is 250-30000 ms"; `session_id` "Session identifier to pass to write_stdin +when the process is still running". `write_stdin`: `chars` "Defaults to empty, which polls without +writing"; empty polls wait 5000-300000 ms. A shell `for i in 1..20; sleep 1` inside one call +produces no error string; it simply spends the call's yield budget blocked. + +## Isolate globals + +The `exec` description in this session lists `exit`, `text`, `image`, `audio`, `generatedImage`, +`store`/`load`, `notify`, `setTimeout`/`clearTimeout`, `ALL_TOOLS`, `yield_control`, plus `tools.*`. +The list varies by client version, which is why the pre-call sentence names a few examples and +defers to the description rather than enumerating. + From adafd12f7721ba1e64d699caad48e8bdbb544239 Mon Sep 17 00:00:00 2001 From: JUN <243035832+lidge-jun@users.noreply.github.com> Date: Mon, 7 Sep 2026 14:49:39 +0900 Subject: [PATCH 072/412] fix(code-mode): state the host contract for nested helpers before the first call Routed models in Codex code mode learned apply_patch argument shape, the marker rule, the isolate import ban and session_id polling only by failing (xai/grok-4.6, 2026-09-07). State them once in exec-tool-result-normalize.ts beside the echo rule and inject at the three existing code-mode sites: shared nudge, Cursor guidance, native routed Responses instructions. --- src/adapters/cursor/tool-guidance.ts | 4 ++-- src/adapters/exec-tool-result-normalize.ts | 15 +++++++++++++++ src/adapters/responses-code-mode.ts | 13 ++++++++++--- src/adapters/tool-catalog-nudge.ts | 4 ++-- tests/adapters/tool-catalog-nudge.test.ts | 7 ++++++- .../cursor/cursor-tool-definitions.test.ts | 4 ++++ tests/providers/kiro/kiro-adapter.test.ts | 2 ++ .../openai-responses-passthrough.test.ts | 15 +++++++++++++-- 8 files changed, 54 insertions(+), 10 deletions(-) diff --git a/src/adapters/cursor/tool-guidance.ts b/src/adapters/cursor/tool-guidance.ts index 54ebcc86d1..87e63730ca 100644 --- a/src/adapters/cursor/tool-guidance.ts +++ b/src/adapters/cursor/tool-guidance.ts @@ -1,5 +1,5 @@ import type { OcxRequestOptions, OcxTool } from "../../types"; -import { CODE_MODE_RESULT_ECHO_SENTENCE } from "../exec-tool-result-normalize"; +import { CODE_MODE_HOST_CONTRACT_SENTENCE, CODE_MODE_RESULT_ECHO_SENTENCE } from "../exec-tool-result-normalize"; import { CODEX_SHELL_BRIDGE_TOOL_NAMES, CODEX_TOOL_SEARCH_TOOL, CODEX_UNIFIED_EXEC_TOOL, clientSemanticToolNameFromCursorWire, cursorRequestAdvertisesApplyPatch, cursorRequestHasExecutionPath, cursorRequestHasShellAlias, cursorRequestUsesCodeMode, cursorToolAllowedByChoice, cursorToolWireName, isCodexShellBridgeToolName, isCursorExecutionPathTool, isCursorStructuredEditToolName } from "./tool-naming"; export const CURSOR_SHELL_ALIAS_SYSTEM_NOTE = @@ -187,7 +187,7 @@ export function buildCursorToolGuidanceSystemNote( ? `\`${CODEX_UNIFIED_EXEC_TOOL}\` is Codex code mode: its body is JavaScript evaluated in a V8 isolate, not a shell command and not Node. Shell, file edits, and MCP are nested helpers called INSIDE that body as \`await tools.(...)\`, for example \`await tools.exec_command({cmd: \"ls\"})\`. Read the tool description and the isolate global \`ALL_TOOLS\` (not \`tools.ALL_TOOLS\`) for helpers this turn provides; absence from the top-level catalog or from \`exec\`'s description is not absence. Those nested helpers are not themselves top-level tools, so do not call \`exec_command\` or \`shell_command\` at the top level here${codeModeOtherTopLevelNames.length > 0 ? `; every other tool this turn lists, including ${quotedNames(codeModeOtherTopLevelNames)}, remains callable at the top level as usual` : ""}. Nested \`tools.apply_patch(input)\` is host-executed: the string must begin exactly with \`*** Begin Patch\` and end with \`*** End Patch\`, each marker line being three asterisks, one space, the two words, then end of line with no further asterisks. OpenCodex does not rewrite JavaScript inside exec, so extra asterisks on a marker line are rejected by Codex before the file is touched.` : undefined, codeMode - ? CODE_MODE_RESULT_ECHO_SENTENCE + " There is no `require`, no `module`, and no filesystem or network globals; reach the host only through the nested helpers." + ? CODE_MODE_RESULT_ECHO_SENTENCE + " There is no `require`, no `module`, and no filesystem or network globals; reach the host only through the nested helpers. " + CODE_MODE_HOST_CONTRACT_SENTENCE : undefined, codeMode ? "NEVER attempt Cursor-native Shell, Read, Grep, List, or any tool absent from the catalog — they are not executed in this environment and every probe wastes a turn. The exec code cell (with its nested helpers) is the ONLY execution surface; go to it directly on the FIRST attempt and do not narrate switching surfaces." diff --git a/src/adapters/exec-tool-result-normalize.ts b/src/adapters/exec-tool-result-normalize.ts index c103808420..ad1969c229 100644 --- a/src/adapters/exec-tool-result-normalize.ts +++ b/src/adapters/exec-tool-result-normalize.ts @@ -115,6 +115,21 @@ export const EMPTY_EXEC_OUTPUT_MESSAGE = export const CODE_MODE_RESULT_ECHO_SENTENCE = "Nothing in the isolate is echoed automatically: a bare trailing `await tools.(...)` or final expression value is DISCARDED, and the cell reports empty output. Pass anything you need to read to `text(...)` (or `notify(...)`) in the same cell — for example `text(JSON.stringify(await tools.exec_command({cmd: 'ls'})))` — and treat an empty result as your own missing `text(...)` call rather than a failed command or lost context."; +/** + * Host rules a routed model most often breaks on its first code-mode edit or wait, stated BEFORE + * the call. Wording tracks the Codex host (0.153.2), probed live on 2026-09-07: a non-string + * argument to `apply_patch` throws "expects a string input"; a body whose first line is not the + * bare marker (decorated `*** Begin Patch ***`, a code fence, prose) throws "The first line of the + * patch must be '*** Begin Patch'" — surrounding newlines are tolerated; ES imports throw + * "Unsupported import in exec"; a command that outlives `yield_time_ms` returns `session_id` for + * `write_stdin` polling. xai/grok-4.6 hit the first two, abandoned apply_patch for heredoc writes, + * blocked a turn in a shell sleep loop, and died once on an import. None of that is repairable in + * the proxy (devlog/_plan/260905_apply_patch_envelope_gap/010 MODE B); it is a contract the proxy + * had not stated. + */ +export const CODE_MODE_HOST_CONTRACT_SENTENCE = + "Host contract for the nested helpers: `tools.apply_patch(patch)` takes exactly one string, never an object such as `{input: ...}`; the patch text opens with the bare marker line `*** Begin Patch` and closes with the bare marker line `*** End Patch`, written without a code fence, prose, or extra asterisks on those lines (blank lines or indentation around the markers are tolerated; a decorated or missing marker is rejected). The isolate has no `import`, `require`, or module loader; use the globals the exec tool description lists (for example `tools`, `text`, `notify`, `store`/`load`, `ALL_TOOLS`). For a command that may outlive `yield_time_ms`, let `tools.exec_command` return a `session_id` and poll it on later calls with `tools.write_stdin({session_id, chars: \"\"})` instead of blocking a shell in a sleep loop."; + /** * Codex exec / shell-bridge tool names (flat and MCP-prefixed display aliases). An empty result * here is almost always a code-mode cell that never called text()/notify(). diff --git a/src/adapters/responses-code-mode.ts b/src/adapters/responses-code-mode.ts index 25e51f204e..ebbab97fd9 100644 --- a/src/adapters/responses-code-mode.ts +++ b/src/adapters/responses-code-mode.ts @@ -1,6 +1,6 @@ import { toolChoiceToolPredicate, type OcxParsedRequest, type OcxProviderConfig } from "../types"; import { isOpenAiOperatedResponsesDestination } from "../providers/openai-tiers"; -import { CODE_MODE_RESULT_ECHO_SENTENCE, normalizeEmptyExecToolResultText } from "./exec-tool-result-normalize"; +import { CODE_MODE_HOST_CONTRACT_SENTENCE, CODE_MODE_RESULT_ECHO_SENTENCE, normalizeEmptyExecToolResultText } from "./exec-tool-result-normalize"; import { isBareShellBridgeTool, isCodexCodeModeExecTool } from "./tool-catalog-nudge"; function record(value: unknown): value is Record { @@ -29,6 +29,14 @@ function withExecInputGuidance(tool: unknown): unknown { } } }; } +/** Append each sentence a replayed instructions string does not already carry, in order. */ +function appendMissing(instructions: string, sentences: readonly string[]): string { + return sentences.reduce( + (acc, sentence) => acc.includes(sentence) ? acc : [acc, sentence].filter(Boolean).join("\n\n"), + instructions, + ); +} + /** Native routed Responses needs the same first-call/output contract as translated adapters. */ export function normalizeResponsesCodeMode(body: unknown, parsed: OcxParsedRequest, provider: OcxProviderConfig): unknown { if (!record(body) || parsed._compactionRequest || isOpenAiOperatedResponsesDestination(provider)) return body; @@ -42,8 +50,7 @@ export function normalizeResponsesCodeMode(body: unknown, parsed: OcxParsedReque .map(item => item.call_id)); return { ...body, - instructions: instructions.includes(CODE_MODE_RESULT_ECHO_SENTENCE) - ? instructions : [instructions, CODE_MODE_RESULT_ECHO_SENTENCE].filter(Boolean).join("\n\n"), + instructions: appendMissing(instructions, [CODE_MODE_RESULT_ECHO_SENTENCE, CODE_MODE_HOST_CONTRACT_SENTENCE]), ...(Array.isArray(body.tools) ? { tools: body.tools.map(withExecInputGuidance) } : {}), ...(input ? { input: input.map(item => { if (!record(item)) return item; diff --git a/src/adapters/tool-catalog-nudge.ts b/src/adapters/tool-catalog-nudge.ts index 6e5659a78f..5b218f27e6 100644 --- a/src/adapters/tool-catalog-nudge.ts +++ b/src/adapters/tool-catalog-nudge.ts @@ -5,7 +5,7 @@ import { type OcxTool, type OcxProviderConfig, } from "../types"; -import { CODE_MODE_RESULT_ECHO_SENTENCE } from "./exec-tool-result-normalize"; +import { CODE_MODE_HOST_CONTRACT_SENTENCE, CODE_MODE_RESULT_ECHO_SENTENCE } from "./exec-tool-result-normalize"; // Tool names that exist only in OTHER agent harnesses (Claude Code and friends). Naming one // here tells a routed model not to call it unless this turn's catalog really lists it. @@ -121,7 +121,7 @@ export function buildNonOpenAIToolCatalogNudgeFromNames( "Call only listed names with their listed argument keys; do not invent, translate, or rename tools.", "Names mentioned only in instructions, tool descriptions, argument descriptions, or nested helper APIs are not additional top-level tools.", verifiedCodeModeExecName - ? "`" + verifiedCodeModeExecName + "` is Codex code mode: its body is JavaScript evaluated in a V8 isolate. Nested helpers are called INSIDE that body as `await tools.(...)`, for example `await tools.exec_command({cmd: \"ls\"})` or `await tools.codex_app__list_threads({})`. Absence from the top-level catalog or from `" + verifiedCodeModeExecName + "`'s description is not absence: deferred helpers stay callable on `tools.`. Discover them from the isolate global `ALL_TOOLS`, not `tools.ALL_TOOLS`. Do not skip an available nested helper because it is omitted from the listed top-level names. " + CODE_MODE_RESULT_ECHO_SENTENCE + " Nested `tools.apply_patch(input)` is host-executed: the string must begin exactly with `*** Begin Patch` and end with `*** End Patch`, each marker line being three asterisks, one space, the two words, then end of line with no further asterisks. OpenCodex does not rewrite JavaScript inside exec, so extra asterisks on a marker line are rejected by Codex before the file is touched." + ? "`" + verifiedCodeModeExecName + "` is Codex code mode: its body is JavaScript evaluated in a V8 isolate. Nested helpers are called INSIDE that body as `await tools.(...)`, for example `await tools.exec_command({cmd: \"ls\"})` or `await tools.codex_app__list_threads({})`. Absence from the top-level catalog or from `" + verifiedCodeModeExecName + "`'s description is not absence: deferred helpers stay callable on `tools.`. Discover them from the isolate global `ALL_TOOLS`, not `tools.ALL_TOOLS`. Do not skip an available nested helper because it is omitted from the listed top-level names. " + CODE_MODE_RESULT_ECHO_SENTENCE + " Nested `tools.apply_patch(input)` is host-executed: the string must begin exactly with `*** Begin Patch` and end with `*** End Patch`, each marker line being three asterisks, one space, the two words, then end of line with no further asterisks. OpenCodex does not rewrite JavaScript inside exec, so extra asterisks on a marker line are rejected by Codex before the file is touched. " + CODE_MODE_HOST_CONTRACT_SENTENCE : "If a listed tool exposes nested helpers such as a tools.* API, call the listed parent tool and use those helpers only inside that tool's input.", unavailableNeighborNames.length > 0 ? "Do not use neighboring-agent tool names " + quoteNames(unavailableNeighborNames) + " unless this turn's catalog lists those exact names." diff --git a/tests/adapters/tool-catalog-nudge.test.ts b/tests/adapters/tool-catalog-nudge.test.ts index 18fc5a301c..f875113a75 100644 --- a/tests/adapters/tool-catalog-nudge.test.ts +++ b/tests/adapters/tool-catalog-nudge.test.ts @@ -4,7 +4,7 @@ import { buildNonOpenAIToolCatalogNudgeFromNames, shouldInjectNonOpenAIToolCatalogNudge, } from "../../src/adapters/tool-catalog-nudge"; -import { CODE_MODE_RESULT_ECHO_SENTENCE, EMPTY_EXEC_OUTPUT_MESSAGE } from "../../src/adapters/exec-tool-result-normalize"; +import { CODE_MODE_HOST_CONTRACT_SENTENCE, CODE_MODE_RESULT_ECHO_SENTENCE, EMPTY_EXEC_OUTPUT_MESSAGE } from "../../src/adapters/exec-tool-result-normalize"; import type { OcxTool } from "../../src/types"; describe("non-OpenAI tool catalog nudge", () => { @@ -80,6 +80,10 @@ describe("non-OpenAI tool catalog nudge", () => { expect(note).toContain("OpenCodex does not rewrite JavaScript inside exec"); expect(note).toContain("Nested `tools.apply_patch(input)` is host-executed"); expect(note).not.toContain("call the listed parent tool and use those helpers only inside that tool's input"); + // The host contract rides the same code-mode branch as the echo rule (Grok 2026-09-07). + expect(note).toContain(CODE_MODE_HOST_CONTRACT_SENTENCE); + expect(note).toContain("takes exactly one string"); + expect(note).toContain("write_stdin({session_id, chars: \"\"})"); }); test("keeps the generic nested-helper parent-tool rule when exec is not listed", () => { @@ -88,6 +92,7 @@ describe("non-OpenAI tool catalog nudge", () => { expect(note).toContain("call the listed parent tool and use those helpers only inside that tool's input"); expect(note).not.toContain("is Codex code mode"); expect(note).not.toContain("tools.ALL_TOOLS"); + expect(note).not.toContain("Host contract for the nested helpers"); }); test("detects a wire-renamed exec as code mode", () => { diff --git a/tests/providers/cursor/cursor-tool-definitions.test.ts b/tests/providers/cursor/cursor-tool-definitions.test.ts index 852936a2e5..fb15f0e7d6 100644 --- a/tests/providers/cursor/cursor-tool-definitions.test.ts +++ b/tests/providers/cursor/cursor-tool-definitions.test.ts @@ -771,6 +771,9 @@ describe("Cursor code mode tool guidance", () => { expect(note).toContain("no further asterisks"); expect(note).not.toContain("*** Begin Patch ***"); expect(note).toContain("OpenCodex does not rewrite JavaScript inside exec"); + expect(note).toContain("Host contract for the nested helpers"); + expect(note).toContain("takes exactly one string"); + expect(note).toContain("write_stdin"); // The flat-catalog shell-bridge guidance must NOT appear: naming a top-level // `exec_command` in code mode sends the model after a tool that does not exist. @@ -819,6 +822,7 @@ describe("Cursor code mode tool guidance", () => { expect(note).toContain("is the Codex Responses shell bridge for this turn"); expect(note).not.toContain("is Codex code mode"); expect(note).not.toContain("V8 isolate"); + expect(note).not.toContain("Host contract for the nested helpers"); }); }); diff --git a/tests/providers/kiro/kiro-adapter.test.ts b/tests/providers/kiro/kiro-adapter.test.ts index f4a9aa83e6..fbdeec50b2 100644 --- a/tests/providers/kiro/kiro-adapter.test.ts +++ b/tests/providers/kiro/kiro-adapter.test.ts @@ -1823,6 +1823,8 @@ describe("kiro code-mode catalog nudge", () => { // Reaches the ACTUAL Kiro wire prompt, not just the builder: the live 2026-08-28 session that // misread a blank result was a routed Kiro turn. expect(content).toContain("Nothing in the isolate is echoed automatically"); + // Survives Kiro's 16 384-char injected-instruction bound on the real wire prompt. + expect(content).toContain("Host contract for the nested helpers"); // The generic fallback must be gone, not merely accompanied. expect(content).not.toContain("If a listed tool exposes nested helpers such as a tools.* API"); }); diff --git a/tests/responses/openai-responses-passthrough.test.ts b/tests/responses/openai-responses-passthrough.test.ts index 24bc8e0e02..25ee2af5ac 100644 --- a/tests/responses/openai-responses-passthrough.test.ts +++ b/tests/responses/openai-responses-passthrough.test.ts @@ -3,7 +3,7 @@ import { createOpenAIChatAdapter } from "../../src/adapters/openai-chat"; import { createResponsesPassthroughAdapter as createResponsesPassthroughAdapterProduction } from "../../src/adapters/openai-responses"; import { openaiResponsesUrl } from "../../src/adapters/openai-responses-url"; import { normalizeResponsesCodeMode } from "../../src/adapters/responses-code-mode"; -import { CODE_MODE_RESULT_ECHO_SENTENCE, EMPTY_EXEC_OUTPUT_MESSAGE, FAILED_EXEC_OUTPUT_MESSAGE } from "../../src/adapters/exec-tool-result-normalize"; +import { CODE_MODE_HOST_CONTRACT_SENTENCE, CODE_MODE_RESULT_ECHO_SENTENCE, EMPTY_EXEC_OUTPUT_MESSAGE, FAILED_EXEC_OUTPUT_MESSAGE } from "../../src/adapters/exec-tool-result-normalize"; import { chatCompletionsToResponsesBody } from "../../src/chat/inbound"; import { anthropicToResponsesBody } from "../../src/claude/inbound"; import { parseRequest } from "../../src/responses/parser"; @@ -51,7 +51,7 @@ describe("native routed code-mode result visibility", () => { const before = JSON.stringify(body); const request = createResponsesPassthroughAdapter(routed).buildRequest(parseRequest(body)); const wire = JSON.parse(request.body); - expect(wire.instructions).toBe(`Keep this instruction.\n\n${CODE_MODE_RESULT_ECHO_SENTENCE}`); + expect(wire.instructions).toBe(`Keep this instruction.\n\n${CODE_MODE_RESULT_ECHO_SENTENCE}\n\n${CODE_MODE_HOST_CONTRACT_SENTENCE}`); expect(wire.tools.find((tool: { name: string }) => tool.name === "exec").parameters.properties.input.description) .toContain(CODE_MODE_RESULT_ECHO_SENTENCE); expect(JSON.stringify(body)).toBe(before); @@ -103,6 +103,16 @@ describe("native routed code-mode result visibility", () => { expect(second.instructions).toBe(first.instructions); }); + test("a replayed body that already carries the echo rule gains only the missing contract sentence", () => { + const body = { ...raw(), instructions: `Keep this instruction.\n\n${CODE_MODE_RESULT_ECHO_SENTENCE}` }; + const parsed = parseRequest(body); + const first = normalizeResponsesCodeMode(body, parsed, routed) as typeof body; + expect(first.instructions).toBe(`${body.instructions}\n\n${CODE_MODE_HOST_CONTRACT_SENTENCE}`); + expect(first.instructions.split(CODE_MODE_RESULT_ECHO_SENTENCE).length).toBe(2); + const second = normalizeResponsesCodeMode(first, parsed, routed) as typeof body; + expect(second.instructions).toBe(first.instructions); + }); + test("official OpenAI and non-code-mode catalogs remain untouched", () => { const body = raw(); for (const native of [provider, { ...routed, baseUrl: "https://api.openai.com/v1" }]) { @@ -110,6 +120,7 @@ describe("native routed code-mode result visibility", () => { const wire = JSON.parse(createResponsesPassthroughAdapter(native).buildRequest(parseRequest(body)).body); expect(wire.instructions).toBe(body.instructions); expect(JSON.stringify(wire.tools)).not.toContain(CODE_MODE_RESULT_ECHO_SENTENCE); + expect(JSON.stringify(wire)).not.toContain("Host contract for the nested helpers"); } for (const tools of [ [{ type: "function", name: "exec", parameters: { type: "object" } }], From 163378050d75bda4bc6eb0821da9382e5a80c67a Mon Sep 17 00:00:00 2001 From: JUN <243035832+lidge-jun@users.noreply.github.com> Date: Mon, 7 Sep 2026 15:04:40 +0900 Subject: [PATCH 073/412] fix(code-mode): name the broken host rule on exec results that carry a host failure string Post-hoc half of the host contract. Exec-bridge results carrying "expects a string input", "The first/last line of the patch must be", or "Unsupported import in exec" gain one recovery line on the native routed Responses, Kiro and Cursor result paths. Responses and Kiro additionally require the verified code-mode catalog; Cursor matches the exact exec name under its opencodex-responses provider and keeps its isError policy. Flat shell bridges, foreign namespaces, whitespace/failed-wrapper grouping and replayed annotations are untouched. --- scripts/test-layout/layout.json | 1 + src/adapters/cursor/tool-result-normalize.ts | 12 ++++ src/adapters/exec-tool-result-normalize.ts | 67 +++++++++++++++++++ src/adapters/kiro.ts | 20 ++++-- src/adapters/responses-code-mode.ts | 7 +- .../exec-tool-result-normalize.test.ts | 62 +++++++++++++++++ tests/fixtures/test-layout-expected.json | 1 + .../cursor-toolresult-normalize.test.ts | 28 ++++++++ tests/providers/kiro/kiro-adapter.test.ts | 62 +++++++++++++++++ .../openai-responses-passthrough.test.ts | 15 +++++ 10 files changed, 266 insertions(+), 9 deletions(-) create mode 100644 tests/adapters/exec-tool-result-normalize.test.ts diff --git a/scripts/test-layout/layout.json b/scripts/test-layout/layout.json index 65ba23d900..60e0f22a0d 100644 --- a/scripts/test-layout/layout.json +++ b/scripts/test-layout/layout.json @@ -618,6 +618,7 @@ "empty-completion-guard.test.ts": "responses", "empty-completion-hardening.test.ts": "responses", "empty-tool-output-annotation.test.ts": "adapters", + "exec-tool-result-normalize.test.ts": "adapters", "ensure-desired-integrations-race.test.ts": "cli", "error-fidelity.test.ts": "server", "errors-adapter-failure.test.ts": "server", diff --git a/src/adapters/cursor/tool-result-normalize.ts b/src/adapters/cursor/tool-result-normalize.ts index fded734b93..edec3a14f4 100644 --- a/src/adapters/cursor/tool-result-normalize.ts +++ b/src/adapters/cursor/tool-result-normalize.ts @@ -10,9 +10,12 @@ */ import { + CODE_MODE_HOST_RECOVERY_PREFIX, EMPTY_EXEC_OUTPUT_MESSAGE, EMPTY_EXEC_OUTPUT_REGEX, FAILED_EXEC_OUTPUT_MESSAGE, + annotateCodeModeHostFailure, + isCodexCodeModeExecResult, isFailedEmptyExecWrapper, isCodexExecBridgeTool, } from "../exec-tool-result-normalize"; @@ -104,6 +107,15 @@ export function normalizeCursorToolResultText( changed: true, }; } + // A host failure string inside a code-mode exec result gets the rule it broke appended, with + // Cursor's isError decision left exactly as the caller passed it. A replayed result that already + // carries a recovery line returns here unchanged: falling through would let the legacy loop + // below match the lowercase import marker a second time and flip isError. + if (isCodexCodeModeExecResult(options.toolName, options.toolNamespace)) { + if (text.includes(CODE_MODE_HOST_RECOVERY_PREFIX)) return { text, isError, changed: false }; + const hostFailure = annotateCodeModeHostFailure(text, options); + if (hostFailure !== undefined) return { text: hostFailure, isError, changed: true }; + } if (!isError) { for (const { marker, guidance } of RUNTIME_FAILURE_GUIDANCE) { if (text.includes(marker)) { diff --git a/src/adapters/exec-tool-result-normalize.ts b/src/adapters/exec-tool-result-normalize.ts index ad1969c229..a6e4a3190a 100644 --- a/src/adapters/exec-tool-result-normalize.ts +++ b/src/adapters/exec-tool-result-normalize.ts @@ -130,6 +130,73 @@ export const CODE_MODE_RESULT_ECHO_SENTENCE = export const CODE_MODE_HOST_CONTRACT_SENTENCE = "Host contract for the nested helpers: `tools.apply_patch(patch)` takes exactly one string, never an object such as `{input: ...}`; the patch text opens with the bare marker line `*** Begin Patch` and closes with the bare marker line `*** End Patch`, written without a code fence, prose, or extra asterisks on those lines (blank lines or indentation around the markers are tolerated; a decorated or missing marker is rejected). The isolate has no `import`, `require`, or module loader; use the globals the exec tool description lists (for example `tools`, `text`, `notify`, `store`/`load`, `ALL_TOOLS`). For a command that may outlive `yield_time_ms`, let `tools.exec_command` return a `session_id` and poll it on later calls with `tools.write_stdin({session_id, chars: \"\"})` instead of blocking a shell in a sleep loop."; +/** + * Post-hoc half of the host contract: the four host strings a routed model reads inside a + * non-error exec result, each paired with the rule it broke. Matched case-insensitively because + * the host writes "Unsupported import in exec: " while Cursor's earlier marker was + * lowercase; one table, one owner, so this text and the pre-call sentence cannot drift. + */ +export const CODE_MODE_HOST_FAILURE_GUIDANCE: ReadonlyArray<{ marker: string; guidance: string }> = [ + { + marker: "expects a string input", + guidance: "tools.apply_patch takes exactly one string argument; pass the patch text itself, not an object such as {input: ...}.", + }, + { + marker: "the first line of the patch must be", + guidance: "The patch text must open with the bare marker line `*** Begin Patch`: no code fence, prose, or extra asterisks on that line (blank lines or indentation before it are tolerated).", + }, + { + marker: "the last line of the patch must be", + guidance: "The patch text must close with the bare marker line `*** End Patch`: no trailing text or extra asterisks on that line (blank lines after it are tolerated).", + }, + { + marker: "unsupported import in exec", + guidance: "Imports are not available in this exec context; use the injected globals (tools, text, notify, store, load, ALL_TOOLS) instead.", + }, +]; + +/** Prefix of every recovery line this module appends; callers use it to recognise replayed annotations. */ +export const CODE_MODE_HOST_RECOVERY_PREFIX = "[recovery: "; + +/** Namespaces under which Cursor displays Codex's own Responses tools (see cursor/tool-naming.ts). */ +const CODEX_RESPONSES_DISPLAY_NAMESPACES: ReadonlySet = new Set(["opencodex-responses", "mcp__opencodex-responses"]); +/** Flattened spellings of the same code-mode exec when a client folds the namespace into the name. */ +const CODEX_CODE_MODE_EXEC_ALIASES: ReadonlySet = new Set(["exec", "mcp__opencodex-responses__exec", "mcp_opencodex-responses_exec"]); + +/** + * The code-mode `exec` tool by NAME — bare, or under Codex's own `opencodex-responses` display + * namespace, matched exactly. The four host strings above originate only in that isolate, so flat + * shell bridges (`exec_command`, `shell`, …) and every other namespace (`mcp__docker`, + * `mcp__foreign-opencodex-responses`) are excluded: an unrelated server's output that quotes the + * phrase must not receive Codex guidance. Narrower than `isCodexExecBridgeTool` on purpose; the + * empty-output repair keeps the wider gate. Callers that KNOW the catalog shape (Kiro's + * `codeModeExecName`, the Responses body gate) add that check on top; this predicate alone cannot + * tell a structured tool named `exec` from the freeform one. + */ +export function isCodexCodeModeExecResult(toolName?: string, toolNamespace?: string): boolean { + if (!toolName) return false; + const lower = toolName.toLowerCase(); + if (toolNamespace !== undefined) return CODEX_RESPONSES_DISPLAY_NAMESPACES.has(toolNamespace) && lower === "exec"; + return CODEX_CODE_MODE_EXEC_ALIASES.has(lower); +} + +/** + * Append a one-line recovery hint when a code-mode exec result carries a known host failure string. + * Returns undefined when the tool is not the code-mode exec, no marker matches, or a recovery line is + * already present (a replayed annotated result must not grow a second one). Never touches error + * status: the host already decided whether the call failed. + */ +export function annotateCodeModeHostFailure( + text: string, + options: { toolName?: string; toolNamespace?: string } = {}, +): string | undefined { + if (!isCodexCodeModeExecResult(options.toolName, options.toolNamespace)) return undefined; + if (text.includes(CODE_MODE_HOST_RECOVERY_PREFIX)) return undefined; + const lower = text.toLowerCase(); + const hit = CODE_MODE_HOST_FAILURE_GUIDANCE.find(({ marker }) => lower.includes(marker)); + return hit ? `${text}\n${CODE_MODE_HOST_RECOVERY_PREFIX}${hit.guidance}]` : undefined; +} + /** * Codex exec / shell-bridge tool names (flat and MCP-prefixed display aliases). An empty result * here is almost always a code-mode cell that never called text()/notify(). diff --git a/src/adapters/kiro.ts b/src/adapters/kiro.ts index 200b1edb77..56ee632343 100644 --- a/src/adapters/kiro.ts +++ b/src/adapters/kiro.ts @@ -44,7 +44,7 @@ import { extractKiroImages, normalizeKiroImages, type KiroImage } from "./kiro-i import { sniffImageDimensions } from "./anthropic-image-guard"; import { fetchKiroWithRetry, noteKiroTransientThrottle } from "./kiro-retry"; import { convertKiroToolContext } from "./kiro-tools"; -import { EMPTY_EXEC_OUTPUT_MESSAGE, normalizeEmptyExecToolResultText } from "./exec-tool-result-normalize"; +import { EMPTY_EXEC_OUTPUT_MESSAGE, annotateCodeModeHostFailure, normalizeEmptyExecToolResultText } from "./exec-tool-result-normalize"; import { identifyRoutedModel } from "./identity"; import { buildNonOpenAIToolCatalogNudgeFromNames, isBareShellBridgeTool, isCodexCodeModeExecTool } from "./tool-catalog-nudge"; import { @@ -755,11 +755,17 @@ export function buildKiroPayload( // the task instead of calling text()/notify(). Checked before `text.trim()` because the // wrapper form ("Script completed\nWall time ...\nOutput:\n") is non-blank and would // otherwise pass through as if it were real output. - const normalizedExecText = normalizeEmptyExecToolResultText(text, { - toolName: tr.toolName, - toolNamespace: tr.toolNamespace, - }); - const resultText = normalizedExecText ?? (text.trim() ? text : KIRO_EMPTY_TOOL_RESULT_MESSAGE); + const execOptions = { toolName: tr.toolName, toolNamespace: tr.toolNamespace }; + const normalizedExecText = normalizeEmptyExecToolResultText(text, execOptions); + // A host failure string inside a non-empty exec result gets the rule it broke appended, but + // only when this request's emitted catalog is genuinely code mode (`codeModeExecName` above): + // a structured tool named exec, or exec beside a shell bridge, never ran the isolate. This is + // the only substitution the grouping path below also carries: whitespace and empty/failed + // wrappers keep their existing raw policy. + const annotatedExecText = normalizedExecText === undefined && codeModeExecName !== undefined + ? annotateCodeModeHostFailure(text, execOptions) + : undefined; + const resultText = normalizedExecText ?? annotatedExecText ?? (text.trim() ? text : KIRO_EMPTY_TOOL_RESULT_MESSAGE); const images = extractKiroImages(tr.content); const toolUseId = normalizeToolId(tr.toolCallId); const call = priorCalls.get(toolUseId); @@ -768,7 +774,7 @@ export function buildKiroPayload( } // Keep real whitespace and failed wrappers, but no empty-success wrapper boilerplate. const rawGroupText = text.length > 0 && (!text.trim() || normalizedExecText !== EMPTY_EXEC_OUTPUT_MESSAGE) - ? text : undefined; + ? (annotatedExecText ?? text) : undefined; const last = turns.at(-1); if ( adjacentResult?.rawId === tr.toolCallId diff --git a/src/adapters/responses-code-mode.ts b/src/adapters/responses-code-mode.ts index ebbab97fd9..8e53481fa8 100644 --- a/src/adapters/responses-code-mode.ts +++ b/src/adapters/responses-code-mode.ts @@ -1,6 +1,6 @@ import { toolChoiceToolPredicate, type OcxParsedRequest, type OcxProviderConfig } from "../types"; import { isOpenAiOperatedResponsesDestination } from "../providers/openai-tiers"; -import { CODE_MODE_HOST_CONTRACT_SENTENCE, CODE_MODE_RESULT_ECHO_SENTENCE, normalizeEmptyExecToolResultText } from "./exec-tool-result-normalize"; +import { CODE_MODE_HOST_CONTRACT_SENTENCE, CODE_MODE_RESULT_ECHO_SENTENCE, annotateCodeModeHostFailure, normalizeEmptyExecToolResultText } from "./exec-tool-result-normalize"; import { isBareShellBridgeTool, isCodexCodeModeExecTool } from "./tool-catalog-nudge"; function record(value: unknown): value is Record { @@ -59,7 +59,10 @@ export function normalizeResponsesCodeMode(body: unknown, parsed: OcxParsedReque } if ((item.type !== "function_call_output" && item.type !== "custom_tool_call_output") || !execCalls.has(item.call_id)) return item; const text = textOnlyOutput(item.output); - const normalized = text === undefined ? undefined : normalizeEmptyExecToolResultText(text, { toolName: "exec" }); + const normalized = text === undefined + ? undefined + : normalizeEmptyExecToolResultText(text, { toolName: "exec" }) + ?? annotateCodeModeHostFailure(text, { toolName: "exec" }); return normalized === undefined ? item : { ...item, output: normalized }; }) } : {}), }; diff --git a/tests/adapters/exec-tool-result-normalize.test.ts b/tests/adapters/exec-tool-result-normalize.test.ts new file mode 100644 index 0000000000..a685ba6463 --- /dev/null +++ b/tests/adapters/exec-tool-result-normalize.test.ts @@ -0,0 +1,62 @@ +import { describe, expect, test } from "bun:test"; +import { + CODE_MODE_HOST_CONTRACT_SENTENCE, + CODE_MODE_HOST_FAILURE_GUIDANCE, + annotateCodeModeHostFailure, +} from "../../src/adapters/exec-tool-result-normalize"; + +// Live host strings (Codex 0.153.2, probed 2026-09-07) and the rule each one names. The pre-call +// sentence and these rows are one contract in one module; a model must never be told one thing +// before the call and another after. +describe("code-mode host failure annotation", () => { + test.each(CODE_MODE_HOST_FAILURE_GUIDANCE.map(row => [row.marker, row.guidance] as const))( + "annotates an exec result carrying %p regardless of case", + (marker, guidance) => { + const text = `Script failed\nWall time 0.1 seconds\nOutput:\nError: ${marker.toUpperCase()}`; + expect(annotateCodeModeHostFailure(text, { toolName: "exec" })).toBe(`${text}\n[recovery: ${guidance}]`); + }, + ); + + test("matches the host's real capitalisation and argument text", () => { + expect(annotateCodeModeHostFailure("Unsupported import in exec: node:fs", { toolName: "exec" })).toContain("injected globals"); + expect(annotateCodeModeHostFailure("Script error:\ntool `apply_patch` expects a string input", { toolName: "exec" })).toContain("exactly one string"); + expect(annotateCodeModeHostFailure( + "apply_patch verification failed: invalid patch: The first line of the patch must be '*** Begin Patch'", + { toolName: "exec" }, + )).toContain("bare marker line `*** Begin Patch`"); + }); + + test("leaves non-exec tools, shell bridges, foreign namespaces, non-matching text and already-annotated text alone", () => { + expect(annotateCodeModeHostFailure("expects a string input", { toolName: "read_file" })).toBeUndefined(); + // Flat shell bridges never run the isolate, so the four strings cannot be theirs. + expect(annotateCodeModeHostFailure("expects a string input", { toolName: "exec_command" })).toBeUndefined(); + // A foreign MCP server's own exec is not Codex's, even when its output quotes the phrase, and a + // namespace that merely CONTAINS the provider name is still foreign. + expect(annotateCodeModeHostFailure("expects a string input", { toolName: "exec", toolNamespace: "mcp__docker" })).toBeUndefined(); + expect(annotateCodeModeHostFailure("expects a string input", { toolName: "exec", toolNamespace: "mcp__foreign-opencodex-responses" })).toBeUndefined(); + // Codex's own display namespaces and flattened aliases for the same code-mode tool still count. + for (const options of [ + { toolName: "exec", toolNamespace: "opencodex-responses" }, + { toolName: "exec", toolNamespace: "mcp__opencodex-responses" }, + { toolName: "mcp__opencodex-responses__exec" }, + { toolName: "mcp_opencodex-responses_exec" }, + ]) { + expect(annotateCodeModeHostFailure("expects a string input", options)).toContain("[recovery:"); + } + expect(annotateCodeModeHostFailure("all good", { toolName: "exec" })).toBeUndefined(); + const once = annotateCodeModeHostFailure("expects a string input", { toolName: "exec" }); + if (!once) throw new Error("expected one annotation"); + expect(annotateCodeModeHostFailure(once, { toolName: "exec" })).toBeUndefined(); + }); + + test("every failure row is a rule the pre-call sentence already states", () => { + expect(CODE_MODE_HOST_CONTRACT_SENTENCE).toContain("takes exactly one string"); + expect(CODE_MODE_HOST_CONTRACT_SENTENCE).toContain("`*** Begin Patch`"); + expect(CODE_MODE_HOST_CONTRACT_SENTENCE).toContain("`*** End Patch`"); + expect(CODE_MODE_HOST_CONTRACT_SENTENCE).toContain("no `import`"); + expect(CODE_MODE_HOST_CONTRACT_SENTENCE).toContain("write_stdin"); + // Never shows the decorated marker as a copyable literal (same rule as the nudge tests). + expect(CODE_MODE_HOST_CONTRACT_SENTENCE).not.toContain("*** Begin Patch ***"); + }); +}); + diff --git a/tests/fixtures/test-layout-expected.json b/tests/fixtures/test-layout-expected.json index cb554012ea..fe613ac71f 100644 --- a/tests/fixtures/test-layout-expected.json +++ b/tests/fixtures/test-layout-expected.json @@ -458,6 +458,7 @@ "errors-adapter-failure.test.ts": "server", "eventstream-decoder.test.ts": "responses", "exa-web-search.test.ts": "providers", + "exec-tool-result-normalize.test.ts": "adapters", "expand-user-path.test.ts": "config", "fast-row-ingress.test.ts": "providers", "fast-row-listing.test.ts": "codex-integration", diff --git a/tests/providers/cursor/cursor-toolresult-normalize.test.ts b/tests/providers/cursor/cursor-toolresult-normalize.test.ts index c62ad8e27b..610e5e578e 100644 --- a/tests/providers/cursor/cursor-toolresult-normalize.test.ts +++ b/tests/providers/cursor/cursor-toolresult-normalize.test.ts @@ -106,6 +106,34 @@ describe("normalizeCursorToolResultText (#1920/#1866 unit rows)", () => { expect(out.text).toContain(hint); }); + test.each(["Unsupported import in exec: node:fs", "unsupported import in exec: node:fs"])( + "a code-mode exec result carrying %p gains the shared hint, keeps its isError, and is not re-annotated on replay", + (payload) => { + const out = normalizeCursorToolResultText(payload, { toolName: "exec" }); + expect(out.changed).toBe(true); + expect(out.isError).toBe(false); + expect(out.text).toBe(`${payload}\n[recovery: Imports are not available in this exec context; use the injected globals (tools, text, notify, store, load, ALL_TOOLS) instead.]`); + // Replay through Responses history arrives with isError=false; the legacy lowercase marker + // row must not get a second look at it. + const replay = normalizeCursorToolResultText(out.text, { toolName: "exec", isError: false }); + expect(replay).toEqual({ text: out.text, isError: false, changed: false }); + }, + ); + + test("the legacy node_repl import row keeps its own isError policy", () => { + const out = normalizeCursorToolResultText("unsupported import in exec", { toolName: "js", toolNamespace: "mcp__node_repl" }); + expect(out.isError).toBe(true); + expect(out.text).toContain("injected globals"); + }); + + test("a non-exec tool whose successful output merely mentions a host phrase stays byte-identical", () => { + const doc = "The docs say apply_patch expects a string input."; + const out = normalizeCursorToolResultText(doc, { toolName: "read_file" }); + expect(out.changed).toBe(false); + expect(out.isError).toBe(false); + expect(out.text).toBe(doc); + }); + test("a non-computer-use tool with empty output stays byte-identical", () => { const out = normalizeCursorToolResultText("", { toolName: "read_file" }); expect(out.changed).toBe(false); diff --git a/tests/providers/kiro/kiro-adapter.test.ts b/tests/providers/kiro/kiro-adapter.test.ts index fbdeec50b2..947d6ad740 100644 --- a/tests/providers/kiro/kiro-adapter.test.ts +++ b/tests/providers/kiro/kiro-adapter.test.ts @@ -339,6 +339,68 @@ describe("kiro adapter — buildRequest", () => { } }); + test("a code-mode exec result carrying a host failure string names the broken rule", async () => { + // freeform: the Kiro seam annotates only when the emitted catalog is genuinely code mode. + const execTool = { name: "exec", description: "Run JavaScript", freeform: true, parameters: { type: "object" } }; + const failure = "apply_patch verification failed: invalid patch: The first line of the patch must be '*** Begin Patch'"; + const messages = [ + { role: "user", content: "run it" }, + { role: "assistant", content: [{ type: "toolCall", id: "call-x", name: "exec", arguments: {} }] }, + { role: "toolResult", toolCallId: "call-x", toolName: "exec", content: failure, isError: false }, + ]; + const { body } = await createKiroAdapter(provider).buildRequest(parsedWith(messages, [execTool])); + const resultText = JSON.parse(body).conversationState.currentMessage.userInputMessage + .userInputMessageContext.toolResults[0].content[0].text; + expect(resultText).toBe(`${failure}\n[recovery: The patch text must open with the bare marker line \`*** Begin Patch\`: no code fence, prose, or extra asterisks on that line (blank lines or indentation before it are tolerated).]`); + }); + + test("a host failure string on a non-code-mode catalog stays raw", async () => { + const failure = "tool `apply_patch` expects a string input"; + const messages = [ + { role: "user", content: "run it" }, + { role: "assistant", content: [{ type: "toolCall", id: "call-x", name: "exec", arguments: {} }] }, + { role: "toolResult", toolCallId: "call-x", toolName: "exec", content: failure, isError: false }, + ]; + for (const tools of [ + // A structured tool that merely shares the name exec. + [{ name: "exec", description: "Run a shell string", parameters: { type: "object" } }], + // Freeform exec beside a bare shell bridge is the flat-catalog shape, not code mode. + [ + { name: "exec", description: "Run JavaScript", freeform: true, parameters: { type: "object" } }, + { name: "exec_command", description: "Run", parameters: { type: "object" } }, + ], + ]) { + const { body } = await createKiroAdapter(provider).buildRequest(parsedWith(messages, tools)); + const resultText = JSON.parse(body).conversationState.currentMessage.userInputMessage + .userInputMessageContext.toolResults[0].content[0].text; + expect(resultText).toBe(failure); + } + }); + + test("a host failure chunk in a coalesced group carries its recovery line beside raw siblings", async () => { + // Whitespace and a failed-empty wrapper keep their raw grouping policy; only the chunk that + // carries a host failure string is substituted (the exact combination review round 1 named). + const execTool = { name: "exec", description: "Run JavaScript", freeform: true, parameters: { type: "object" } }; + const failedExecWrapper = "Script failed\nWall time 0.1 seconds\nOutput:\n"; + const hostFailure = "tool `apply_patch` expects a string input"; + const result = (content: string) => ({ role: "toolResult", toolCallId: "call-g", toolName: "exec", content, isError: false }); + const messages = [ + { role: "user", content: "run it" }, + { role: "assistant", content: [{ type: "toolCall", id: "call-g", name: "exec", arguments: {} }] }, + result(" "), result(hostFailure), result(failedExecWrapper), + ]; + const { body } = await createKiroAdapter(provider).buildRequest(parsedWith(messages, [execTool])); + const toolResults = JSON.parse(body).conversationState.currentMessage.userInputMessage + .userInputMessageContext.toolResults as Array<{ content: Array<{ text: string }>; status: string }>; + expect(toolResults).toHaveLength(1); + expect(toolResults[0].status).toBe("success"); + expect(toolResults[0].content).toEqual([ + { text: " " }, + { text: `${hostFailure}\n[recovery: tools.apply_patch takes exactly one string argument; pass the patch text itself, not an object such as {input: ...}.]` }, + { text: failedExecWrapper }, + ]); + }); + test("real exec output and empty non-exec results are left alone", async () => { // Review finding (Codex P2): a failed cell with no output is empty but NOT a success. The // success guidance would erase the only failure signal — reachable via Responses history, diff --git a/tests/responses/openai-responses-passthrough.test.ts b/tests/responses/openai-responses-passthrough.test.ts index 25ee2af5ac..df2d064cab 100644 --- a/tests/responses/openai-responses-passthrough.test.ts +++ b/tests/responses/openai-responses-passthrough.test.ts @@ -103,6 +103,21 @@ describe("native routed code-mode result visibility", () => { expect(second.instructions).toBe(first.instructions); }); + test("annotates a paired exec result that carries a host failure string without touching the program", () => { + const failure = "Script failed\nWall time 0.1 seconds\nOutput:\nScript error:\ntool `apply_patch` expects a string input"; + const body = raw(failure); + const wire = JSON.parse(createResponsesPassthroughAdapter(routed).buildRequest(parseRequest(body)).body); + expect(wire.input[1].output).toBe(`${failure}\n[recovery: tools.apply_patch takes exactly one string argument; pass the patch text itself, not an object such as {input: ...}.]`); + expect(JSON.parse(wire.input[0].arguments).input).toBe(body.input[0].input); + // Replayed history already carrying the hint is not annotated twice: the output item and the + // program keep their identity, and a second pass over the normalized body is a deep no-op. + const replayed = raw(wire.input[1].output); + const once = normalizeResponsesCodeMode(replayed, parseRequest(replayed), routed) as typeof replayed; + expect(once.input[1]).toBe(replayed.input[1]); + expect(once.input[0]).toBe(replayed.input[0]); + expect(normalizeResponsesCodeMode(once, parseRequest(once), routed)).toEqual(once); + }); + test("a replayed body that already carries the echo rule gains only the missing contract sentence", () => { const body = { ...raw(), instructions: `Keep this instruction.\n\n${CODE_MODE_RESULT_ECHO_SENTENCE}` }; const parsed = parseRequest(body); From 6bdcba5bff4196debf3cd159c7af3d34e35a24e0 Mon Sep 17 00:00:00 2001 From: JUN <243035832+lidge-jun@users.noreply.github.com> Date: Mon, 7 Sep 2026 15:27:23 +0900 Subject: [PATCH 074/412] docs: record the routed code-mode host contract Document the pre-call nested-helper contract and post-hoc host-failure annotation in the transports SoT and the Codex integration guide. This change does not rewrite model JavaScript or patch payloads. --- .../content/docs/guides/codex-integration.md | 7 +++++ structure/04_transports-and-sidecars.md | 28 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/docs-site/src/content/docs/guides/codex-integration.md b/docs-site/src/content/docs/guides/codex-integration.md index 64466b61a4..7d66e72c3f 100644 --- a/docs-site/src/content/docs/guides/codex-integration.md +++ b/docs-site/src/content/docs/guides/codex-integration.md @@ -330,6 +330,13 @@ Codex. Native custom calls and converted function calls use the same completion patch previews are held while their executable form is unresolved. JavaScript that merely contains patch text and unrelated native custom payloads stay unchanged. +Routed code-mode turns are also told the host's rules for the nested helpers before the first +call: `tools.apply_patch` takes one string that opens and closes with the bare patch marker lines, +the isolate has no `import`, and long-running commands are polled through `write_stdin`. When a +code-mode exec result on the native routed Responses, Kiro, or Cursor path still carries one of the host's +failure messages, opencodex appends a one-line hint naming the rule. This change does not rewrite +the model's code or its patch text. + Ordinary routed Responses function calls also use the original declared parameter schema at completion: integral floats in integer fields and integral numbers in string-only fields are normalized, while fractions and numeric unions stay unchanged. An explicitly empty completed diff --git a/structure/04_transports-and-sidecars.md b/structure/04_transports-and-sidecars.md index d27022c2ad..c568bb0151 100644 --- a/structure/04_transports-and-sidecars.md +++ b/structure/04_transports-and-sidecars.md @@ -330,6 +330,34 @@ whole result is examined; populated text, image/file parts, unpaired results, sh compaction and OpenAI-operated destinations are untouched. This does not rewrite valid JavaScript or reconstruct output that the code-mode host never emitted. +Routed code-mode turns also carry the host contract for the nested helpers, stated in the same three +injection sites as the result-emission rule (shared catalog nudge, Cursor code-mode guidance, native +routed Responses instructions): `tools.apply_patch` takes one string that opens and closes with the +bare patch marker lines (blank lines or indentation around them are tolerated; a decorated or missing +marker is rejected), the isolate has no `import`/`require`, and a command that outlives +`yield_time_ms` is polled through `write_stdin` with empty `chars` rather than a shell sleep loop. +When a code-mode exec result still carries one of the host's failure strings ("expects a string +input", "The first line of the patch must be", "The last line of the patch must be", "Unsupported +import in exec"), the native routed Responses, Kiro, and Cursor result paths append a one-line +recovery hint naming the broken rule; flat shell bridges and foreign MCP namespaces are never +annotated, Responses and Kiro additionally require the request's verified code-mode catalog, Cursor +matches the exact `exec` name under its `opencodex-responses` provider without catalog context, and +Cursor's error classification and Kiro's whitespace and failed-wrapper grouping are unchanged. Both +halves live in `src/adapters/exec-tool-result-normalize.ts` +so the pre-call and post-hoc wording cannot drift. This guidance and annotation change rewrites +neither the model's JavaScript nor its patch payload; the existing name-alias delimiter +normalization in `src/responses/code-mode-helper-compat.ts` is unchanged, and the host still rejects a +malformed call exactly as before. Anthropic, Google, OpenAI-chat and command-code result paths +have no exec-result seam today and are not annotated. + +[Decision Log] +- 목적과 의도: Stop routed models from abandoning `apply_patch` after the Codex host rejects an object argument or a decorated marker, and from blocking a turn in a shell sleep loop when the host offers `session_id` polling. +- 기존 구현 및 제약 조건: The shared nudge, Cursor guidance and native Responses instructions already carry the result-emission rule from `exec-tool-result-normalize.ts`, but none stated the helper's argument type, the marker rule, the import ban, or the polling protocol; `260905_apply_patch_envelope_gap` refused to rewrite JavaScript bodies (MODE B), so payload repair is off the table. +- 검토한 주요 대안: Repair the argument shape inside the proxy (rejected: same body ambiguity as MODE B and it turns a rejected write into a performed one); Cursor-only guidance (rejected: the incident was native routed Responses on xAI); annotate every adapter's tool results (rejected: Anthropic/Google/OpenAI-chat/command-code have no exec-result seam and would need a new one). +- 선택한 방식: One pre-call sentence and one marker→recovery table in the module that already owns the echo pair; inject the sentence at the three existing code-mode sites; annotate at the three existing exec-result seams with an exec-gated, idempotent helper that never changes error status. +- 다른 대안 대신 이 방식을 선택한 이유: The safe repair for a host contract the model broke is to state it before the call and name it after the failure; keeping both halves in one file is what keeps them consistent. +- 장점, 단점 및 영향: Code-mode system prompts grow by roughly 600 characters on routed turns; OpenAI destinations, flat catalogs and compaction requests are untouched. An exec result that legitimately prints one of the four phrases gains a recovery line, which is additive text and never an error flip. On Cursor, a structured tool literally named `exec` whose output quotes one of those phrases would also gain that line. The effect on the live Grok defect rate is unmeasured until a re-probe. + [Decision Log] - 목적과 의도: Keep Codex hosted web search usable on xAI's public Responses endpoint without forwarding private OpenAI-only fields that xAI rejects. - 기존 구현 및 제약 조건: Codex emits `external_web_access`, `search_context_size`, `search_content_types`, and `user_location`; xAI documents a live-only `web_search` tool with domain filters and image flags, while Codex cached mode explicitly forbids external access. From f1604c6b26bdb4326ae512f69fb46eb398c977b3 Mon Sep 17 00:00:00 2001 From: Ingwannu Date: Fri, 4 Sep 2026 21:20:40 +0000 Subject: [PATCH 075/412] docs(devlog): make CI completion check fail closed [skip ci] (cherry picked from commit e5bbd79ef70faeb258a8c13a4fc30c3d8bd1d588) Co-authored-by: Ingwannu <186453546+Ingwannu@users.noreply.github.com> --- .../090_outcome.md | 2 +- .../091_post_merge_audit.md | 31 ++++++++++++++++--- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/devlog/_fin/260905_always_on_429_failover/090_outcome.md b/devlog/_fin/260905_always_on_429_failover/090_outcome.md index 3de38c8936..07e4399881 100644 --- a/devlog/_fin/260905_always_on_429_failover/090_outcome.md +++ b/devlog/_fin/260905_always_on_429_failover/090_outcome.md @@ -18,7 +18,7 @@ the tree rather than against the plan — the plan's own criteria were satisfied Two were defects the fix itself created (#3499, #3503), three were surfaces still describing the old contract (#3517, #3520, #3523), one closed the structural gap that let this unit ship two subset-rotator loops (#3512), and one cleaned up after a collision with concurrent maintainer -work (#3526). All are recorded in `091`. +work (#3526). The runtime post-merge findings and CI lessons are recorded in `091`. ## What changed diff --git a/devlog/_fin/260905_always_on_429_failover/091_post_merge_audit.md b/devlog/_fin/260905_always_on_429_failover/091_post_merge_audit.md index 490040325d..297213b2a3 100644 --- a/devlog/_fin/260905_always_on_429_failover/091_post_merge_audit.md +++ b/devlog/_fin/260905_always_on_429_failover/091_post_merge_audit.md @@ -67,14 +67,37 @@ The post-merge run on `dev` then showed `ci failure`, which was a genuinely alar out. It turned out to be cancellation by the maintainer's next merge two minutes later, not a real failure — every job read `cancelled`, not `failure`. -**Rule:** verify with the check-runs API and require zero `null` conclusions, not a pass count: +**Rule:** use the exact head SHA, require every expected aggregate or policy gate by name, and +also require zero non-terminal check runs. A missing check is not success. Paginate before treating +the returned set as complete: ```bash -gh api repos///commits//check-runs \ - --jq '[.check_runs[] | .conclusion] | group_by(.) | map({(.[0]//"null"): length}) | add' +set -o pipefail +gh api --paginate repos///commits//check-runs \ + | jq -se ' + [.[].check_runs[]] as $runs + | ["ci", "enforce-target", "hygiene", "react-doctor"] as $expected + | ($expected - [ + $runs[] + | select(.status == "completed" and .conclusion == "success") + | .name + ]) as $missing + | [ + $runs[] + | select(.status != "completed" or .conclusion == null) + | .name + ] as $pending + | if ($missing | length) == 0 and ($pending | length) == 0 + then {ready: true, expected: $expected} + else error("missing=\($missing) pending=\($pending)") + end' ``` -A clean result looks like `{"skipped":3,"success":24}` — no `null` key at all. +A clean result is `{"ready":true,...}` with exit status 0. This does not replace review-policy +checks such as confirming the approval belongs to the same head. Every `$expected` value is an +exact Checks API `.check_runs[].name`, not a workflow title or workflow-run name. If those required +check-run names change, update this list with the policy; silently accepting an absent name +recreates the original bug. The near-miss paid for itself: sweeping `dev` afterwards found a real defect. #3511 and #3513 landed concurrently, one moving `anthropic-quorum-cache.test.ts` into `tests/routing/` and the From 3e4a01c66bba66cf355c4e8562a349cc16a2fffc Mon Sep 17 00:00:00 2001 From: luvs01 <27862058+luvs01@users.noreply.github.com> Date: Mon, 7 Sep 2026 10:23:03 +0900 Subject: [PATCH 076/412] fix(kiro): gate request diagnostics behind the debug check [skip ci] `debugProviderDiagnostic` already returns early when provider debug is off, but its argument object is built by the caller first. The Kiro request path therefore ran `new TextEncoder().encode(body).length` over the entire serialized request body on every request, including when diagnostics were disabled, and then discarded the result inside the callee. Wrap the diagnostic call in `isDebugEnabled()` so the details are only constructed when they can actually be emitted. `src/adapters/openai-chat.ts` already guards its diagnostics the same way. The regression asserts that building a request performs no `TextEncoder` encode over the serialized payload while diagnostics are off; it fails without the guard and passes with it. (cherry picked from commit d5d711a7b9897bb8eee8364a5d8765b55206bf6f) Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com> --- src/adapters/kiro.ts | 27 ++++++++++++++---------- tests/providers/kiro/kiro-stream.test.ts | 15 +++++++++++++ 2 files changed, 31 insertions(+), 11 deletions(-) diff --git a/src/adapters/kiro.ts b/src/adapters/kiro.ts index 56ee632343..4039142a8b 100644 --- a/src/adapters/kiro.ts +++ b/src/adapters/kiro.ts @@ -1,6 +1,7 @@ import { decodeEventStream } from "../lib/eventstream-decoder"; import { estimateTokens } from "../lib/token-estimate"; import { debugProviderDiagnostic } from "../lib/debug"; +import { isDebugEnabled } from "../lib/debug-settings"; import { resolveKiroApiRegion, resolveKiroRequestProfile } from "../oauth/kiro"; import { KIRO_MODEL_CONTEXT_WINDOWS, normalizeKiroModelId } from "../providers/kiro-models"; import { modelRecordValue } from "../reasoning-effort"; @@ -2120,17 +2121,21 @@ export function createKiroAdapter(provider: OcxProviderConfig): ProviderAdapter const rawContextInputEstimate = estimateKiroPayloadInputTokens(built.payload, parsed.modelId); const contextInputEstimate = calibrateKiroEstimate(built.conversationId, rawContextInputEstimate); const body = JSON.stringify(built.payload); - debugProviderDiagnostic("kiro", "request", { - region, - requestedModel: parsed.modelId, - completionMode: built.completionMode, - bodyBytes: new TextEncoder().encode(body).length, - messageCount: kiroPayloadMessages(parsed).length, - toolCount: parsed.context.tools?.length ?? 0, - hasProfileArn: Boolean(profileArn), - wireClient, - hasPreviousResponseId: Boolean(parsed.previousResponseId), - }); + // Every field below is evaluated before the call, so an unguarded call re-encodes the + // whole request body on each request even when provider debug is off. Gate the details. + if (isDebugEnabled()) { + debugProviderDiagnostic("kiro", "request", { + region, + requestedModel: parsed.modelId, + completionMode: built.completionMode, + bodyBytes: new TextEncoder().encode(body).length, + messageCount: kiroPayloadMessages(parsed).length, + toolCount: parsed.context.tools?.length ?? 0, + hasProfileArn: Boolean(profileArn), + wireClient, + hasPreviousResponseId: Boolean(parsed.previousResponseId), + }); + } return { request: { url: kiroRuntimeEndpoint(provider, region), diff --git a/tests/providers/kiro/kiro-stream.test.ts b/tests/providers/kiro/kiro-stream.test.ts index b85c698ae1..1a9b7a6e02 100644 --- a/tests/providers/kiro/kiro-stream.test.ts +++ b/tests/providers/kiro/kiro-stream.test.ts @@ -196,6 +196,21 @@ describe("kiro adapter — parseStream", () => { expect(providerState).toEqual({ kiro: { conversationId: "returned-conversation-1" } }); }); + test("request diagnostics do not re-encode the body when provider debug is off", async () => { + const encodeSpy = spyOn(TextEncoder.prototype, "encode"); + try { + const adapter = createKiroAdapter(provider); + const before = encodeSpy.mock.calls.length; + await adapter.buildRequest(parsedWith([{ role: "user", content: "hi" }])); + const during = encodeSpy.mock.calls.slice(before); + // The diagnostic argument list is evaluated eagerly, so an unguarded call encodes the + // full serialized request body on every request even with diagnostics disabled. + expect(during.some(([value]) => typeof value === "string" && value.includes("conversationState"))).toBe(false); + } finally { + encodeSpy.mockRestore(); + } + }); + test("invalid returned message metadata cannot poison continuation state", async () => { const adapter = createKiroAdapter(provider); const request = await adapter.buildRequest(parsedWith([{ role: "user", content: "hi" }])); From 98564bdbfe6feace448eaf21cfbf424650c0bbf6 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 18:17:49 +0900 Subject: [PATCH 077/412] fix(copilot): route Responses-only GPT, Grok and MAI models correctly [skip ci] Carries PR #3840 (head 9a214529d, 5 commits squashed onto current dev): gpt-6-astra, Grok and MAI models on GitHub Copilot default to the Responses wire instead of Chat Completions, which returned unsupported_api_for_model. Docs scope the per-wire model lists and the discovery fallback test covers legacy overrides. (carried from https://github.com/lidge-jun/opencodex/pull/3840) Co-authored-by: chilung-cgu <215337896+chilung-cgu@users.noreply.github.com> --- .../src/content/docs/fr/guides/providers.md | 4 +- .../fr/reference/configuration/providers.md | 2 +- .../src/content/docs/guides/providers.md | 4 +- .../src/content/docs/ja/guides/providers.md | 4 +- .../ja/reference/configuration/providers.md | 2 +- .../src/content/docs/ko/guides/providers.md | 4 +- .../ko/reference/configuration/providers.md | 2 +- .../docs/reference/configuration/providers.md | 2 +- .../src/content/docs/ru/guides/providers.md | 6 +- .../ru/reference/configuration/providers.md | 2 +- .../src/content/docs/tr/guides/providers.md | 4 +- .../tr/reference/configuration/providers.md | 2 +- .../content/docs/zh-cn/guides/providers.md | 4 +- .../reference/configuration/providers.md | 2 +- .../content/docs/zh-tw/guides/providers.md | 4 +- src/providers/registry.ts | 5 ++ .../github-copilot-wire-defaults.test.ts | 76 +++++++++++++++---- 17 files changed, 90 insertions(+), 39 deletions(-) diff --git a/docs-site/src/content/docs/fr/guides/providers.md b/docs-site/src/content/docs/fr/guides/providers.md index 89b3a7c626..6ed7553957 100644 --- a/docs-site/src/content/docs/fr/guides/providers.md +++ b/docs-site/src/content/docs/fr/guides/providers.md @@ -543,8 +543,8 @@ flux d'appareil contre un jeton d'API Copilot de courte durée, et non contre un reste une passerelle à clé ou jeton d'abonnement sur son point de terminaison compatible OpenAI. **Cloudflare AI Gateway** exige que les identifiants de votre compte et de votre passerelle figurent dans l'URL. -Copilot présente un catalogue qui utilise plusieurs protocoles : sa famille GPT-5 (`gpt-5.3-codex`, `gpt-5.4`, -`gpt-5.4-mini`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`) rejette +Copilot présente un catalogue qui utilise plusieurs protocoles : ces modèles (`gpt-5.3-codex`, `gpt-5.4`, +`gpt-5.4-mini`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-6-astra`, `grok-4.5`, `grok-4.6`, `mai-code-1.1-flash`, `mai-code-1-flash-picker`) rejettent `/chat/completions` pour le trafic d'agent. opencodex route donc ces modèles sur l'API Responses par défaut, tandis que tous les autres modèles Copilot restent sur Chat Completions. L'ordre de priorité est le suivant : verrouillage explicite du protocole → entrée [`modelAdapters`](/fr/reference/configuration/providers/) définie diff --git a/docs-site/src/content/docs/fr/reference/configuration/providers.md b/docs-site/src/content/docs/fr/reference/configuration/providers.md index 32b6a28023..96d00e5668 100644 --- a/docs-site/src/content/docs/fr/reference/configuration/providers.md +++ b/docs-site/src/content/docs/fr/reference/configuration/providers.md @@ -116,7 +116,7 @@ sauvegarde dont le contenu diffère, puis réécrit en identifiants sans préfix | `modelReasoningEfforts?` | `Record` | Libellés propres à chaque modèle. Une liste vide masque le contrôle de l'effort. Comme pour `reasoningEfforts`, chaque échelle configurée avec l'adaptateur `google` déclare la capacité `thinkingLevel` ; les requêtes directes et Vertex sans image utilisent le chemin Gemini à plat, tandis que Cloud Code Assist l'envoie dans son enveloppe de requête. | | `modelSupportsReasoningSummaries?` | `Record` | Définissez un modèle sur `false` pour arrêter la publicité des résumés et supprimer les champs de livraison du résumé. | | `modelReasoningSummaryDelivery?` | `Record` | Énumération de livraison des réponses par modèle ; réécrit un champ de livraison existant. | -| `modelAdapters?` | `Record` | Remplacement du protocole `openai-chat` ou `openai-responses` par modèle pour les passerelles multiprotocoles. Les entrées explicites priment sur les valeurs par défaut du registre. Le préréglage OpenCode Go sélectionne Responses pour `gpt-5.6-luna` tout en laissant les modèles apparentés sur leurs protocoles documentés ; DeepSeek peut sélectionner Responses natif pour `deepseek-v4-flash` ; GitHub Copilot déclare des valeurs par défaut limitées à Responses pour sa famille GPT-5 (`gpt-5.3-codex`, `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`), car ces modèles rejettent `/chat/completions` pour le trafic des agents. Les modèles sans valeur intégrée par défaut, comme `gpt-5.4-nano`, peuvent être activés ici. Les services en amont à protocole unique et le transfert canonique ChatGPT rejettent ces remplacements. | +| `modelAdapters?` | `Record` | Remplacement du protocole `openai-chat` ou `openai-responses` par modèle pour les passerelles multiprotocoles. Les entrées explicites priment sur les valeurs par défaut du registre. Le préréglage OpenCode Go sélectionne Responses pour `gpt-5.6-luna` tout en laissant les modèles apparentés sur leurs protocoles documentés ; DeepSeek peut sélectionner Responses natif pour `deepseek-v4-flash` ; GitHub Copilot déclare des valeurs par défaut limitées à Responses pour ces modèles (`gpt-5.3-codex`, `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-6-astra`, `grok-4.5`, `grok-4.6`, `mai-code-1.1-flash`, `mai-code-1-flash-picker`), car ces modèles rejettent `/chat/completions` pour le trafic des agents. Les modèles sans valeur intégrée par défaut, comme `gpt-5.4-nano`, peuvent être activés ici. Les services en amont à protocole unique et le transfert canonique ChatGPT rejettent ces remplacements. | | Activation Responses xAI (tableau de bord) | interrupteur | Pour `xai` uniquement, définit ou efface atomiquement les entrées `modelAdapters` de `grok-4.5` et `grok-4.6`. Une seule entrée apparaît comme un état mixte jusqu’à la prochaine écriture. Les autres remplacements et le comportement des tiers restent inchangés. | | `xaiResponsesXSearch?` | `boolean` | Désactivé par défaut. Sur une destination xAI Responses, ajoute la déclaration `x_search` hébergée par le fournisseur uniquement lorsqu’un outil `web_search` actif subsiste après la normalisation finale de la requête. Les déclarations existantes ne sont pas dupliquées, les sélecteurs `tool_choice`/`allowed_tools` de l’appelant ne sont jamais élargis, et cette option est distincte des options `search.xSearch` du service auxiliaire de recherche web. | | `modelPreferHostedTools?` | `Record` | Activation explicite par modèle exact pour les passerelles Responses hors transfert qui réservent un espace de noms aux outils hébergés. Seul `["image_generation"]` est actuellement accepté ; le modèle correspondant doit utiliser le protocole `openai-responses` et prendre en charge cet outil hébergé. Le proxy supprime les déclarations clientes `image_gen` en conflit et réécrit leurs sélecteurs afin de préserver le choix d'outil de l'appelant. Pour les modèles virtuels `-pro` de l'API OpenAI, l'identifiant public sélectionné est comparé en premier et l'identifiant résolu du modèle de base sur le protocole sert de repli. `modelAdapters` résout d'abord l'identifiant public, puis celui de base ; la seconde résolution détermine le protocole final. Les autres modèles conservent le comportement normal des alias. | diff --git a/docs-site/src/content/docs/guides/providers.md b/docs-site/src/content/docs/guides/providers.md index 5e46979816..8a9477a759 100644 --- a/docs-site/src/content/docs/guides/providers.md +++ b/docs-site/src/content/docs/guides/providers.md @@ -669,8 +669,8 @@ device-flow login for a short-lived Copilot API token — not a pasted API key. a key/subscription-token gateway on its OpenAI-compatible endpoint. **Cloudflare AI Gateway** needs your account + gateway ids filled into the URL. -Copilot fronts a mixed-wire catalog: its GPT-5 family (`gpt-5.3-codex`, `gpt-5.4`, -`gpt-5.4-mini`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`) rejects +Copilot fronts a mixed-wire catalog: the following models (`gpt-5.3-codex`, `gpt-5.4`, +`gpt-5.4-mini`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-6-astra`, `grok-4.5`, `grok-4.6`, `mai-code-1.1-flash`, `mai-code-1-flash-picker`) reject `/chat/completions` for agent traffic, so opencodex routes those models over the Responses API by built-in default while every other Copilot model stays on chat completions. The precedence is: hard wire pin → your explicit diff --git a/docs-site/src/content/docs/ja/guides/providers.md b/docs-site/src/content/docs/ja/guides/providers.md index ae692e1e2c..db0bdb87b2 100644 --- a/docs-site/src/content/docs/ja/guides/providers.md +++ b/docs-site/src/content/docs/ja/guides/providers.md @@ -384,8 +384,8 @@ Amazon Bedrock ネイティブ API のような、これらの実装のいずれ **サブスクリプショントークン**(通常の API キーではない)で認証します。**Cloudflare AI Gateway** は URL にアカウント + ゲートウェイ ID を埋める必要があります。 -Copilot は混在 wire カタログを提供します。GPT-5 系モデル(`gpt-5.3-codex`、`gpt-5.4`、 -`gpt-5.4-mini`、`gpt-5.5`、`gpt-5.6-luna`、`gpt-5.6-sol`、`gpt-5.6-terra`)はエージェント +Copilot は混在 wire カタログを提供します。モデル(`gpt-5.3-codex`、`gpt-5.4`、 +`gpt-5.4-mini`、`gpt-5.5`、`gpt-5.6-luna`、`gpt-5.6-sol`、`gpt-5.6-terra`、`gpt-6-astra`, `grok-4.5`, `grok-4.6`, `mai-code-1.1-flash`, `mai-code-1-flash-picker`)はエージェント 通信の `/chat/completions` を拒否するため、opencodex はこれらのモデルを組み込みデフォルトで Responses API 経由にルーティングし、他の Copilot モデルはすべて chat completions のままです。 優先順位は次のとおりです: ハード wire ピン → 明示的な diff --git a/docs-site/src/content/docs/ja/reference/configuration/providers.md b/docs-site/src/content/docs/ja/reference/configuration/providers.md index ddbb22d666..8938073e6c 100644 --- a/docs-site/src/content/docs/ja/reference/configuration/providers.md +++ b/docs-site/src/content/docs/ja/reference/configuration/providers.md @@ -105,7 +105,7 @@ account を削除しても mapping は保持され、同じ id を再追加す | `modelReasoningEfforts?` | `Record` |モデルごとのラベル。空のリストは努力制御を非表示にします。 | | `modelSupportsReasoningSummaries?` | `Record` |モデルを `false` に設定して、概要の広告を停止し、概要配信フィールドを削除します。 | | `modelReasoningSummaryDelivery?` | `Record` |モデルごとの応答配信列挙型。既存の配信フィールドを書き換えます。 | -| `modelAdapters?` | `Record` | 混合配線ゲートウェイのモデルごとの `openai-chat` または `openai-responses` 配線オーバーライド。明示的なエントリはレジストリのデフォルトを破ります。DeepSeek のプリセットは `deepseek-v4-flash` のネイティブ Responses を選択でき、GitHub Copilot は GPT-5 ファミリー (`gpt-5.3-codex`, `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`) を Responses 専用デフォルトとして宣言します。これらのモデルはエージェント トラフィックで `/chat/completions` を拒否するためです。`gpt-5.4-nano` のようなビルトイン デフォルトのないモデルはここでオプトインできます。単線アップストリーム ピンと正規の ChatGPT 転送はオーバーライドを拒否します。 | +| `modelAdapters?` | `Record` | 混合配線ゲートウェイのモデルごとの `openai-chat` または `openai-responses` 配線オーバーライド。明示的なエントリはレジストリのデフォルトを破ります。DeepSeek のプリセットは `deepseek-v4-flash` のネイティブ Responses を選択でき、GitHub Copilot は モデル (`gpt-5.3-codex`, `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-6-astra`, `grok-4.5`, `grok-4.6`, `mai-code-1.1-flash`, `mai-code-1-flash-picker`) を Responses 専用デフォルトとして宣言します。これらのモデルはエージェント トラフィックで `/chat/completions` を拒否するためです。`gpt-5.4-nano` のようなビルトイン デフォルトのないモデルはここでオプトインできます。単線アップストリーム ピンと正規の ChatGPT 転送はオーバーライドを拒否します。 | | xAI Responses オプトイン(ダッシュボード) | スイッチ | `xai` のみで、`grok-4.5` と `grok-4.6` の `modelAdapters` エントリを原子的に設定または削除します。片方だけの場合は、次のスイッチ操作で両方が正規化されるまで混合状態を表示します。他のオーバーライドと tier 動作は変わりません。 | | `xaiResponsesXSearch?` | `boolean` | デフォルトでは無効です。xAI Responses の宛先では、最終的なリクエスト正規化後もライブの `web_search` ツールが残っている場合にのみ、プロバイダーがホストする `x_search` 宣言を追加します。既存の宣言は重複させず、呼び出し元の `tool_choice` / `allowed_tools` セレクターの範囲を拡張することもありません。また、これは `search.xSearch` オプションを持つウェブ検索サイドカーとは別です。 | | `modelPreferHostedTools?` | `Record` | hosted tool namespace を予約する非 forward Responses gateway 向けの完全一致モデル opt-in。現在は `["image_generation"]` のみを受け付けます。一致したモデルは `openai-responses` wire を使い、その hosted tool をサポートする必要があります。競合するクライアント `image_gen` 宣言を除去し、呼び出し元の tool choice を維持するため selector も書き換えます。OpenAI API の仮想 `-pro` モデルでは、まず選択した公開 ID に一致させ、解決後のベース wire-model ID をフォールバックとして使用します。`modelAdapters` は公開 ID、次にベース ID の順に解決し、後者の結果が最終 wire を決めます。未設定のモデルは通常の alias 動作を維持します。 | diff --git a/docs-site/src/content/docs/ko/guides/providers.md b/docs-site/src/content/docs/ko/guides/providers.md index c49ede4ec6..268e6e0cf1 100644 --- a/docs-site/src/content/docs/ko/guides/providers.md +++ b/docs-site/src/content/docs/ko/guides/providers.md @@ -375,8 +375,8 @@ Amazon Bedrock 네이티브 API처럼 이 구현 중 어느 것과도 맞지 않 **구독 토큰**(일반 API 키가 아님)으로 인증합니다. **Cloudflare AI Gateway**는 URL에 계정 + 게이트웨이 id를 채워야 합니다. -Copilot은 혼합 wire 카탈로그를 제공합니다. GPT-5 계열 모델(`gpt-5.3-codex`, `gpt-5.4`, -`gpt-5.4-mini`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`)은 에이전트 +Copilot은 혼합 wire 카탈로그를 제공합니다. 모델(`gpt-5.3-codex`, `gpt-5.4`, +`gpt-5.4-mini`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-6-astra`, `grok-4.5`, `grok-4.6`, `mai-code-1.1-flash`, `mai-code-1-flash-picker`)은 에이전트 트래픽에 대해 `/chat/completions`를 거부하므로 opencodex는 이 모델들을 내장 기본값으로 Responses API를 통해 라우팅하고, 다른 Copilot 모델은 모두 chat completions를 유지합니다. 우선순위는 하드 wire 핀 → 명시적 [`modelAdapters`](/ko/reference/configuration/providers/) diff --git a/docs-site/src/content/docs/ko/reference/configuration/providers.md b/docs-site/src/content/docs/ko/reference/configuration/providers.md index 160d313be3..2dda27e7bf 100644 --- a/docs-site/src/content/docs/ko/reference/configuration/providers.md +++ b/docs-site/src/content/docs/ko/reference/configuration/providers.md @@ -105,7 +105,7 @@ managed map을 활성화하면 privacy-safe selector를 만들고, 이후 계정 | `modelReasoningEfforts?` | `Record` | 모델별 레이블입니다. 빈 목록이면 effort 제어를 숨깁니다. | | `modelSupportsReasoningSummaries?` | `Record` | 모델을 `false`로 두면 summary 광고를 멈추고 summary 전달 필드를 제거합니다. | | `modelReasoningSummaryDelivery?` | `Record` | 모델별 Responses 전달 enum입니다. 기존 delivery 필드를 다시 씁니다. | -| `modelAdapters?` | `Record` | 혼합 와이어 게이트웨이를 위한 모델별 `openai-chat` 또는 `openai-responses` 와이어 재정의입니다. 명시적 항목이 레지스트리 기본값보다 우선합니다. DeepSeek 프리셋은 `deepseek-v4-flash`에 네이티브 Responses를 선택할 수 있고, GitHub Copilot은 GPT-5 계열(`gpt-5.3-codex`, `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`)을 Responses 전용 기본값으로 선언합니다. 이 모델들은 에이전트 트래픽에서 `/chat/completions`를 거부하기 때문입니다. `gpt-5.4-nano`처럼 기본값이 없는 모델은 여기서 직접 옵트인할 수 있습니다. 단일 와이어 상위 항목과 정식 ChatGPT forward는 재정의를 거부합니다. | +| `modelAdapters?` | `Record` | 혼합 와이어 게이트웨이를 위한 모델별 `openai-chat` 또는 `openai-responses` 와이어 재정의입니다. 명시적 항목이 레지스트리 기본값보다 우선합니다. DeepSeek 프리셋은 `deepseek-v4-flash`에 네이티브 Responses를 선택할 수 있고, GitHub Copilot은 모델(`gpt-5.3-codex`, `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-6-astra`, `grok-4.5`, `grok-4.6`, `mai-code-1.1-flash`, `mai-code-1-flash-picker`)을 Responses 전용 기본값으로 선언합니다. 이 모델들은 에이전트 트래픽에서 `/chat/completions`를 거부하기 때문입니다. `gpt-5.4-nano`처럼 기본값이 없는 모델은 여기서 직접 옵트인할 수 있습니다. 단일 와이어 상위 항목과 정식 ChatGPT forward는 재정의를 거부합니다. | | xAI Responses 옵트인(대시보드) | 스위치 | `xai`에서만 `grok-4.5`와 `grok-4.6`의 `modelAdapters` 항목을 원자적으로 설정하거나 지웁니다. 한 항목만 있으면 다음 스위치 쓰기가 둘을 정규화할 때까지 혼합 상태로 표시됩니다. 다른 재정의와 티어 동작은 바뀌지 않습니다. | | `xaiResponsesXSearch?` | `boolean` | 기본적으로 비활성화됩니다. xAI Responses 대상에서는 최종 요청 정규화 후에도 실제 `web_search` 도구가 남아 있을 때만 공급자가 호스팅하는 `x_search` 선언을 추가합니다. 기존 선언은 중복하지 않고, 호출자의 `tool_choice`/`allowed_tools` 선택기 범위를 확장하지 않으며, 웹 검색 사이드카의 `search.xSearch` 옵션과는 별개입니다. | | `modelPreferHostedTools?` | `Record` | hosted tool namespace를 예약하는 non-forward Responses gateway용 정확한 모델 ID opt-in입니다. 현재 `["image_generation"]`만 허용하며, 일치하는 모델은 `openai-responses` wire를 사용하고 해당 hosted tool을 지원해야 합니다. 충돌하는 클라이언트 `image_gen` 선언을 제거하고 호출자의 tool choice를 유지하도록 selector도 다시 씁니다. OpenAI API 가상 `-pro` 모델은 선택한 공개 ID를 먼저 일치시키고, 해석된 기본 wire-model ID를 대체값으로 사용합니다. `modelAdapters`는 공개 ID를 먼저, 그 다음 기본 ID를 해석하며, 두 번째 결과가 최종 wire를 결정합니다. 설정하지 않은 모델은 일반 alias 동작을 유지합니다. | diff --git a/docs-site/src/content/docs/reference/configuration/providers.md b/docs-site/src/content/docs/reference/configuration/providers.md index 6aa8c78d00..b0792b7367 100644 --- a/docs-site/src/content/docs/reference/configuration/providers.md +++ b/docs-site/src/content/docs/reference/configuration/providers.md @@ -162,7 +162,7 @@ predictions. Explicit provider/model price overrides still take precedence. | `modelReasoningEfforts?` | `Record` | Per-model labels. An empty list hides effort control. As with `reasoningEfforts`, each configured `google`-adapter ladder asserts `thinkingLevel` capability; direct and Vertex non-image requests use the flat Gemini path, while Cloud Code Assist sends it under its request envelope. | | `modelSupportsReasoningSummaries?` | `Record` | Set a model to `false` to stop advertising summaries and strip summary-delivery fields. | | `modelReasoningSummaryDelivery?` | `Record` | Per-model Responses delivery enum; rewrites an existing delivery field. | -| `modelAdapters?` | `Record` | Per-model `openai-chat` or `openai-responses` wire override for mixed-wire gateways. Explicit entries beat registry defaults. The OpenCode Go preset selects Responses for `gpt-5.6-luna` while leaving sibling models on their documented wires; DeepSeek can select native Responses for `deepseek-v4-flash`; and GitHub Copilot declares Responses-only defaults for its GPT-5 family (`gpt-5.3-codex`, `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`) because those models reject `/chat/completions` for agent traffic. Models without a built-in default (for example `gpt-5.4-nano`) can be opted in here. Single-wire upstream pins and canonical ChatGPT forward reject overrides. | +| `modelAdapters?` | `Record` | Per-model `openai-chat` or `openai-responses` wire override for mixed-wire gateways. Explicit entries beat registry defaults. The OpenCode Go preset selects Responses for `gpt-5.6-luna` while leaving sibling models on their documented wires; DeepSeek can select native Responses for `deepseek-v4-flash`; and GitHub Copilot declares Responses-only defaults for the following models (`gpt-5.3-codex`, `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-6-astra`, `grok-4.5`, `grok-4.6`, `mai-code-1.1-flash`, `mai-code-1-flash-picker`) because those models reject `/chat/completions` for agent traffic. Models without a built-in default (for example `gpt-5.4-nano`) can be opted in here. Single-wire upstream pins and canonical ChatGPT forward reject overrides. | | xAI Chat Completions (dashboard / CLI) | switch | Grok 4.5/4.6 OAuth Responses requests default to Responses. Existing Chat overrides are migrated once on upgrade; later Chat choices are preserved. Turn on to select Chat for both models, off to select Responses. CLI: `ocx provider edit xai --xai-chat on` or `--xai-chat off` (running proxy required). Mixed means only one model currently uses Chat. Other overrides and tier policy stay unchanged. API-key and translated Chat/Anthropic defaults are unchanged. | | `xaiResponsesXSearch?` | `boolean` | Disabled by default. On an xAI Responses destination, append the provider-hosted `x_search` declaration only when a live `web_search` tool survives final request normalization. Existing declarations are not duplicated, caller `tool_choice`/`allowed_tools` selectors are never widened, and this is separate from the web-search sidecar's `search.xSearch` options. | | `modelPreferHostedTools?` | `Record` | Exact-model opt-in for non-forward Responses gateways that reserve a hosted-tool namespace. Currently accepts only `["image_generation"]`; a matching model must use the `openai-responses` wire and support that hosted tool. It removes colliding client `image_gen` declarations and rewrites their selectors to preserve caller tool choice. For OpenAI API virtual `-pro` models, the selected public ID is matched first and the resolved base wire-model ID is a fallback. `modelAdapters` resolves the public ID first, then the base ID; the second resolution determines the final wire. Other models retain normal alias behavior. | diff --git a/docs-site/src/content/docs/ru/guides/providers.md b/docs-site/src/content/docs/ru/guides/providers.md index e680f1bd91..80f00c0d63 100644 --- a/docs-site/src/content/docs/ru/guides/providers.md +++ b/docs-site/src/content/docs/ru/guides/providers.md @@ -416,9 +416,9 @@ Assist), `azure` / `azure-openai`, `kiro` и `cursor`. Проприетарны **GitLab Duo** остаётся шлюзом с ключом/токеном подписки на своей OpenAI-совместимой конечной точке. **Cloudflare AI Gateway** требует подставить в URL id аккаунта и шлюза. -Copilot предоставляет каталог со смешанными проводами: его семейство GPT-5 (`gpt-5.3-codex`, -`gpt-5.4`, `gpt-5.4-mini`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`) -отклоняет `/chat/completions` для агентного трафика, поэтому opencodex по умолчанию +Copilot предоставляет каталог со смешанными проводами: модели (`gpt-5.3-codex`, +`gpt-5.4`, `gpt-5.4-mini`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-6-astra`, `grok-4.5`, `grok-4.6`, `mai-code-1.1-flash`, `mai-code-1-flash-picker`) +отклоняют `/chat/completions` для агентного трафика, поэтому opencodex по умолчанию маршрутизирует эти модели через Responses API, а все остальные модели Copilot остаются на chat completions. Приоритет: жёсткий wire-пин → явная запись [`modelAdapters`](/ru/reference/configuration/providers/) → дефолт реестра → adapter всего diff --git a/docs-site/src/content/docs/ru/reference/configuration/providers.md b/docs-site/src/content/docs/ru/reference/configuration/providers.md index 7279179991..14a8b0a3ce 100644 --- a/docs-site/src/content/docs/ru/reference/configuration/providers.md +++ b/docs-site/src/content/docs/ru/reference/configuration/providers.md @@ -118,7 +118,7 @@ cross-route credential fallback не существует. Строки API GPT- | `modelReasoningEfforts?` | `Record` | Label'ы по отдельным моделям. Пустой список скрывает управление effort. | | `modelSupportsReasoningSummaries?` | `Record` | Установите `false` для модели, чтобы перестать рекламировать summary и вырезать поля доставки summary. | | `modelReasoningSummaryDelivery?` | `Record` | Responses delivery enum по моделям; переписывает уже существующее поле delivery. | -| `modelAdapters?` | `Record` | Wire-override по модели для `openai-chat` или `openai-responses` в gateway с несколькими wire-форматами. Явные записи имеют приоритет над default'ами registry; preset DeepSeek может выбирать native Responses для `deepseek-v4-flash`, а GitHub Copilot объявляет Responses-only default'ы для семейства GPT-5 (`gpt-5.3-codex`, `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`), потому что эти модели отклоняют `/chat/completions` для агентного трафика. Модели без встроенного default'а (например, `gpt-5.4-nano`) можно включить здесь. Single-wire upstream pin'ы и canonical ChatGPT forward override не принимают. | +| `modelAdapters?` | `Record` | Wire-override по модели для `openai-chat` или `openai-responses` в gateway с несколькими wire-форматами. Явные записи имеют приоритет над default'ами registry; preset DeepSeek может выбирать native Responses для `deepseek-v4-flash`, а GitHub Copilot объявляет Responses-only default'ы для моделей (`gpt-5.3-codex`, `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-6-astra`, `grok-4.5`, `grok-4.6`, `mai-code-1.1-flash`, `mai-code-1-flash-picker`), потому что эти модели отклоняют `/chat/completions` для агентного трафика. Модели без встроенного default'а (например, `gpt-5.4-nano`) можно включить здесь. Single-wire upstream pin'ы и canonical ChatGPT forward override не принимают. | | Opt-in xAI Responses (панель) | переключатель | Только для `xai`: атомарно задаёт или удаляет записи `modelAdapters` для `grok-4.5` и `grok-4.6`. Одна запись отображается как смешанное состояние до следующего переключения. Остальные override и поведение tier не меняются. | | `xaiResponsesXSearch?` | `boolean` | По умолчанию отключено. Для назначения xAI Responses декларация `x_search`, размещённая у провайдера, добавляется только тогда, когда действующий инструмент `web_search` сохраняется после окончательной нормализации запроса. Существующие декларации не дублируются, селекторы вызывающей стороны `tool_choice`/`allowed_tools` никогда не расширяются, и эта настройка не связана с параметрами `search.xSearch` сайдкара веб-поиска. | | `modelPreferHostedTools?` | `Record` | Opt-in для точного model ID в non-forward Responses gateway, который резервирует namespace hosted tool. Сейчас допускается только `["image_generation"]`; совпавшая модель должна использовать wire `openai-responses` и поддерживать этот hosted tool. Прокси удаляет конфликтующие клиентские объявления `image_gen` и переписывает их selectors, сохраняя caller tool choice. Для виртуальных моделей OpenAI API `-pro` сначала сопоставляется выбранный публичный ID, а затем в качестве fallback используется ID базовой wire-модели. `modelAdapters` сначала разрешается по публичному ID, затем по базовому ID; второй результат определяет итоговый wire. Остальные модели сохраняют обычное alias-поведение. | diff --git a/docs-site/src/content/docs/tr/guides/providers.md b/docs-site/src/content/docs/tr/guides/providers.md index 6ff4f1c038..5943758e5a 100644 --- a/docs-site/src/content/docs/tr/guides/providers.md +++ b/docs-site/src/content/docs/tr/guides/providers.md @@ -589,8 +589,8 @@ login github-copilot`). **GitLab Duo**, OpenAI uyumlu uç noktasında bir anahtar/abonelik belirteci ağ geçidi olarak kalır. **Cloudflare AI Gateway**, URL'ye doldurulan hesap + ağ geçidi kimliklerinize ihtiyaç duyar. -Copilot karma hatlı bir katalog sunar: GPT-5 ailesi (`gpt-5.3-codex`, `gpt-5.4`, -`gpt-5.4-mini`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`) ajan +Copilot karma hatlı bir katalog sunar: modeller (`gpt-5.3-codex`, `gpt-5.4`, +`gpt-5.4-mini`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-6-astra`, `grok-4.5`, `grok-4.6`, `mai-code-1.1-flash`, `mai-code-1-flash-picker`) ajan trafiği için `/chat/completions`'ı reddeder, bu nedenle opencodex yerleşik varsayılan olarak bu modelleri Responses API üzerinden yönlendirirken diğer tüm Copilot modelleri sohbet tamamlamalarında kalır. Öncelik sırası: sabit hat diff --git a/docs-site/src/content/docs/tr/reference/configuration/providers.md b/docs-site/src/content/docs/tr/reference/configuration/providers.md index 91cb923fc3..3e01051010 100644 --- a/docs-site/src/content/docs/tr/reference/configuration/providers.md +++ b/docs-site/src/content/docs/tr/reference/configuration/providers.md @@ -123,7 +123,7 @@ alanlı seçilmiş kimlikleri yalın kimliklere yeniden yazar. | `modelReasoningEfforts?` | `Record` | Model başına etiketler. Boş bir liste çaba denetimini gizler. `reasoningEfforts`'ta olduğu gibi, yapılandırılmış her `google` adaptör merdiveni `thinkingLevel` yeteneğini iddia eder; doğrudan ve Vertex görsel olmayan istekleri düz Gemini yolunu kullanırken, Cloud Code Assist bunu istek zarfı altında gönderir. | | `modelSupportsReasoningSummaries?` | `Record` | Özetlerin bildirilmesini durdurmak ve özet teslim alanlarını kaldırmak için bir modeli `false` olarak ayarlayın. | | `modelReasoningSummaryDelivery?` | `Record` | Model başına Responses teslim enum'ı; mevcut bir teslim alanını yeniden yazar. | -| `modelAdapters?` | `Record` | Karışık hatlı ağ geçitleri için model başına `openai-chat` veya `openai-responses` hat geçersiz kılma. Açık girdiler kayıt defteri varsayılanlarını yener. OpenCode Go önayarı, kardeş modelleri belgelenmiş hatlarında bırakırken `gpt-5.6-luna` için Responses'ı seçer; DeepSeek, `deepseek-v4-flash` için yerel Responses seçebilir; ve GitHub Copilot, GPT-5 ailesi (`gpt-5.3-codex`, `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`) için yalnızca Responses varsayılanlarını bildirir çünkü bu modeller ajan trafiği için `/chat/completions`'ı reddeder. Yerleşik varsayılanı olmayan modeller (örneğin `gpt-5.4-nano`) burada dahil edilebilir. Tek hatlı yukarı akış pinleri ve kurallı ChatGPT iletme geçersiz kılmaları reddeder. | +| `modelAdapters?` | `Record` | Karışık hatlı ağ geçitleri için model başına `openai-chat` veya `openai-responses` hat geçersiz kılma. Açık girdiler kayıt defteri varsayılanlarını yener. OpenCode Go önayarı, kardeş modelleri belgelenmiş hatlarında bırakırken `gpt-5.6-luna` için Responses'ı seçer; DeepSeek, `deepseek-v4-flash` için yerel Responses seçebilir; ve GitHub Copilot, modeller (`gpt-5.3-codex`, `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.5`, `gpt-5.6-luna`, `gpt-5.6-sol`, `gpt-5.6-terra`, `gpt-6-astra`, `grok-4.5`, `grok-4.6`, `mai-code-1.1-flash`, `mai-code-1-flash-picker`) için yalnızca Responses varsayılanlarını bildirir çünkü bu modeller ajan trafiği için `/chat/completions`'ı reddeder. Yerleşik varsayılanı olmayan modeller (örneğin `gpt-5.4-nano`) burada dahil edilebilir. Tek hatlı yukarı akış pinleri ve kurallı ChatGPT iletme geçersiz kılmaları reddeder. | | xAI Responses katılımı (panel) | anahtar | Yalnızca `xai` için `grok-4.5` ve `grok-4.6` `modelAdapters` girdilerini atomik olarak ayarlar veya temizler. Tek girdi, sonraki anahtar yazımı ikisini eşitleyene kadar karma durum olarak görünür. Diğer geçersiz kılmalar ve katman davranışı değişmez. | | `xaiResponsesXSearch?` | `boolean` | Varsayılan olarak devre dışıdır. Bir xAI Responses hedefinde, yalnızca canlı bir `web_search` aracı son istek normalleştirmesinden sağ çıktığında sağlayıcı tarafından barındırılan `x_search` bildirimini ekler. Mevcut bildirimler yinelenmez, çağıranın `tool_choice`/`allowed_tools` seçicileri hiçbir zaman genişletilmez ve bu, web araması yardımcı hizmetinin `search.xSearch` seçeneklerinden ayrıdır. | | `modelPreferHostedTools?` | `Record` | Barındırılan bir araç ad alanı ayıran iletme harici Responses ağ geçitleri için tam model dahil etme. Şu anda yalnızca `["image_generation"]` kabul eder; eşleşen bir model `openai-responses` hattını kullanmalı ve bu barındırılan aracı desteklemelidir. Çakışan istemci `image_gen` bildirimlerini kaldırır ve arayan araç seçimini korumak için seçicilerini yeniden yazar. OpenAI API sanal `-pro` modelleri için önce seçilen genel kimlik eşleştirilir ve çözümlenen temel hat model kimliği bir geri dönüştür. `modelAdapters` önce genel kimliği, ardından temel kimliği çözer; ikinci çözümleme son hattı belirler. Diğer modeller normal takma ad davranışını korur. | diff --git a/docs-site/src/content/docs/zh-cn/guides/providers.md b/docs-site/src/content/docs/zh-cn/guides/providers.md index b4010cdae5..314894c3d1 100644 --- a/docs-site/src/content/docs/zh-cn/guides/providers.md +++ b/docs-site/src/content/docs/zh-cn/guides/providers.md @@ -359,8 +359,8 @@ GPT-5.6 Sol/Terra/Luna 会预置在提供商的回退列表中,因此即使实 使用 Bearer **订阅令牌**(而非普通 API 密钥)进行认证。 **Cloudflare AI Gateway** 需要将 account 和 gateway id 填入 URL。 -Copilot 提供混合 wire 目录:其 GPT-5 系列模型(`gpt-5.3-codex`、`gpt-5.4`、 -`gpt-5.4-mini`、`gpt-5.5`、`gpt-5.6-luna`、`gpt-5.6-sol`、`gpt-5.6-terra`)会拒绝面向 +Copilot 提供混合 wire 目录:其模型(`gpt-5.3-codex`、`gpt-5.4`、 +`gpt-5.4-mini`、`gpt-5.5`、`gpt-5.6-luna`、`gpt-5.6-sol`、`gpt-5.6-terra`、`gpt-6-astra`, `grok-4.5`, `grok-4.6`, `mai-code-1.1-flash`, `mai-code-1-flash-picker`)会拒绝面向 agent 流量的 `/chat/completions`,因此 opencodex 默认将这些模型路由到 Responses API,而其他 Copilot 模型仍走 chat completions。优先级为:硬 wire 固定 → 显式 [`modelAdapters`](/zh-cn/reference/configuration/providers/) 条目 → 注册表默认值 → 提供商级 diff --git a/docs-site/src/content/docs/zh-cn/reference/configuration/providers.md b/docs-site/src/content/docs/zh-cn/reference/configuration/providers.md index f121d67bc0..32f2b52a69 100644 --- a/docs-site/src/content/docs/zh-cn/reference/configuration/providers.md +++ b/docs-site/src/content/docs/zh-cn/reference/configuration/providers.md @@ -105,7 +105,7 @@ selector,而不是分配一个新名称。 | `modelReasoningEfforts?` | `Record` | 按模型设置的标签。空列表会隐藏 effort 控件。 | | `modelSupportsReasoningSummaries?` | `Record` | 将某个模型设为 `false`,即可停止暴露摘要并移除摘要交付字段。 | | `modelReasoningSummaryDelivery?` | `Record` | 按模型设置的 Responses 交付枚举;会重写现有的 delivery 字段。 | -| `modelAdapters?` | `Record` | 按模型设置的 `openai-chat` 或 `openai-responses` 线协议覆盖项,用于混合线协议网关。显式条目优先于注册表默认值;DeepSeek 预设可以为 `deepseek-v4-flash` 选择原生 Responses,GitHub Copilot 则为 GPT-5 系列(`gpt-5.3-codex`、`gpt-5.4`、`gpt-5.4-mini`、`gpt-5.5`、`gpt-5.6-luna`、`gpt-5.6-sol`、`gpt-5.6-terra`)声明了 Responses 专用默认值,因为这些模型在代理流量下会拒绝 `/chat/completions`。没有内置默认值的模型(例如 `gpt-5.4-nano`)可以在此手动启用。单一线协议上游固定项和规范 ChatGPT forward 会拒绝覆盖。 | +| `modelAdapters?` | `Record` | 按模型设置的 `openai-chat` 或 `openai-responses` 线协议覆盖项,用于混合线协议网关。显式条目优先于注册表默认值;DeepSeek 预设可以为 `deepseek-v4-flash` 选择原生 Responses,GitHub Copilot 则为 模型(`gpt-5.3-codex`、`gpt-5.4`、`gpt-5.4-mini`、`gpt-5.5`、`gpt-5.6-luna`、`gpt-5.6-sol`、`gpt-5.6-terra`、`gpt-6-astra`, `grok-4.5`, `grok-4.6`, `mai-code-1.1-flash`, `mai-code-1-flash-picker`)声明了 Responses 专用默认值,因为这些模型在代理流量下会拒绝 `/chat/completions`。没有内置默认值的模型(例如 `gpt-5.4-nano`)可以在此手动启用。单一线协议上游固定项和规范 ChatGPT forward 会拒绝覆盖。 | | xAI Responses 启用项(仪表板) | 开关 | 仅用于 `xai`,以原子方式设置或清除 `grok-4.5` 和 `grok-4.6` 的 `modelAdapters` 条目。若只存在一个条目,则显示混合状态,直到下次开关写入将两者统一。其他覆盖项和层级行为不变。 | | `xaiResponsesXSearch?` | `boolean` | 默认禁用。在 xAI Responses 目标上,仅当有效的 `web_search` 工具在最终请求规范化后仍保留时,才附加由提供方托管的 `x_search` 声明。不会重复已有声明,绝不会扩大调用方的 `tool_choice`/`allowed_tools` 选择范围,并且此项独立于网络搜索辅助服务的 `search.xSearch` 选项。 | | `modelPreferHostedTools?` | `Record` | 非 forward Responses gateway 的精确模型 ID opt-in,用于上游预留 hosted tool namespace 的情况。目前只支持 `["image_generation"]`;匹配模型必须使用 `openai-responses` wire 且支持该 hosted 工具。它会移除冲突的客户端 `image_gen` 声明,并改写其 selector 以保持调用方的 tool choice。对于 OpenAI API 的虚拟 `-pro` 模型,先匹配所选公开 ID,未命中时才使用解析出的基础 wire-model ID 作为回退。`modelAdapters` 会先按公开 ID、再按基础 ID 解析;后一次结果决定最终 wire。未配置模型保持普通 alias 行为。 | diff --git a/docs-site/src/content/docs/zh-tw/guides/providers.md b/docs-site/src/content/docs/zh-tw/guides/providers.md index d26d093b7e..a1b4483cf3 100644 --- a/docs-site/src/content/docs/zh-tw/guides/providers.md +++ b/docs-site/src/content/docs/zh-tw/guides/providers.md @@ -460,8 +460,8 @@ Antigravity/Cloud Code Assist 模式)、`azure` / `azure-openai`、`kiro`、 短效 Copilot API token,不是貼上 API key。**GitLab Duo** 仍是使用 OpenAI-compatible endpoint 的 key/subscription-token gateway。**Cloudflare AI Gateway** 需要在 URL 填入 account 與 gateway id。 -Copilot 的 catalog 混合多種 wire:GPT-5 family(`gpt-5.3-codex`、`gpt-5.4`、`gpt-5.4-mini`、 -`gpt-5.5`、`gpt-5.6-luna`、`gpt-5.6-sol`、`gpt-5.6-terra`)會拒絕 agent traffic 的 +Copilot 的 catalog 混合多種 wire:模型(`gpt-5.3-codex`、`gpt-5.4`、`gpt-5.4-mini`、 +`gpt-5.5`、`gpt-5.6-luna`、`gpt-5.6-sol`、`gpt-5.6-terra`、`gpt-6-astra`, `grok-4.5`, `grok-4.6`, `mai-code-1.1-flash`, `mai-code-1-flash-picker`)會拒絕 agent traffic 的 `/chat/completions`,因此 opencodex 會依內建預設把這些模型路由到 Responses API;其他 Copilot 模型 仍使用 chat completions。優先順序為:hard wire pin → 你明確設定的 [`modelAdapters`](/zh-tw/reference/configuration/providers/) → registry default → provider-wide adapter。 diff --git a/src/providers/registry.ts b/src/providers/registry.ts index ef7cb59e00..b1f689a8bd 100644 --- a/src/providers/registry.ts +++ b/src/providers/registry.ts @@ -3081,6 +3081,11 @@ export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [ "gpt-5.6-luna": "openai-responses", "gpt-5.6-sol": "openai-responses", "gpt-5.6-terra": "openai-responses", + "gpt-6-astra": "openai-responses", + "grok-4.5": "openai-responses", + "grok-4.6": "openai-responses", + "mai-code-1.1-flash": "openai-responses", + "mai-code-1-flash-picker": "openai-responses", }, note: "Experimental unofficial Copilot bridge. Logs in via GitHub device flow using the public VS Code OAuth client id, then exchanges for a short-lived Copilot API token (copilot_internal). Requires an active Copilot subscription. GitHub may tighten or revoke this path; do not send confidential material you would not paste into Copilot Chat.", }, diff --git a/tests/providers/github-copilot/github-copilot-wire-defaults.test.ts b/tests/providers/github-copilot/github-copilot-wire-defaults.test.ts index 29af09048d..50019d02cf 100644 --- a/tests/providers/github-copilot/github-copilot-wire-defaults.test.ts +++ b/tests/providers/github-copilot/github-copilot-wire-defaults.test.ts @@ -8,7 +8,10 @@ * flipped the wire back, so the end-to-end cases assert the captured upstream URL — * the externally observable wire. Pattern mirrors tests/providers/deepseek-inbound-wire.test.ts. */ -import { afterEach, describe, expect, test } from "bun:test"; +import { afterEach, describe, expect, spyOn, test } from "bun:test"; +import * as oauth from "../../../src/oauth"; +import { fetchProviderModels } from "../../../src/codex/catalog/provider-fetch"; +import { clearModelCache } from "../../../src/codex/model-cache"; import { providerConfigSeed } from "../../../src/providers/derive"; import { getProviderRegistryEntry } from "../../../src/providers/registry"; import { resolveWireProtocolOverride } from "../../../src/server/adapter-resolve"; @@ -23,11 +26,42 @@ const RESPONSES_ONLY = [ "gpt-5.6-luna", "gpt-5.6-sol", "gpt-5.6-terra", + "gpt-6-astra", + "grok-4.5", + "grok-4.6", + "mai-code-1.1-flash", + "mai-code-1-flash-picker", ] as const; const CHAT_SERVED = ["gpt-4o", "gpt-4.1", "gpt-4.1-mini", "claude-sonnet-4", "gemini-2.5-pro", "gpt-5-mini"] as const; const INBOUNDS = ["responses", "chat", "anthropic"] as const; +const DISCOVERY_ONLY = ["gpt-6-astra", "grok-4.5", "grok-4.6", "mai-code-1.1-flash", "mai-code-1-flash-picker"]; + +describe("Copilot discovery-only models do not widen the cold-start seed", () => { + for (const authMode of ["key", "oauth"] as const) { + test(`${authMode} discovery exposes new models but failure retains the configured seed`, async () => { + const auth = spyOn(oauth, "resolveModelsAuthToken").mockResolvedValue("test-token"); + const original = globalThis.fetch; + const provider = { ...providerConfigSeed(getProviderRegistryEntry("github-copilot")!), authMode, apiKey: "test-token" }; + try { + clearModelCache("github-copilot"); + globalThis.fetch = (async () => Response.json({ data: DISCOVERY_ONLY.map(id => ({ id })) })) as typeof fetch; + const live = await fetchProviderModels("github-copilot", { ...provider, fetch: globalThis.fetch } as OcxProviderConfig, 0); + expect(live.map(model => model.id).sort()).toEqual([...DISCOVERY_ONLY].sort()); + clearModelCache("github-copilot"); + globalThis.fetch = (async () => new Response("unavailable", { status: 503 })) as typeof fetch; + const fallback = await fetchProviderModels("github-copilot", { ...provider, fetch: globalThis.fetch } as OcxProviderConfig, 0); + expect(fallback.map(model => model.id).sort()).toEqual([...provider.models!].sort()); + for (const model of DISCOVERY_ONLY) expect(fallback.some(row => row.id === model)).toBe(false); + } finally { + globalThis.fetch = original; + auth.mockRestore(); + clearModelCache("github-copilot"); + } + }); + } +}); function copilotProvider(): OcxProviderConfig { // The entry's allowKeyAuthOverride lets tests use key auth instead of live OAuth. @@ -57,13 +91,15 @@ describe("Copilot chat-served models stay on the provider chat wire", () => { }); describe("explicit modelAdapters beat the registry default in both directions", () => { - test("opt-out: a listed Responses-default model pinned back to chat", () => { - const provider = { ...copilotProvider(), modelAdapters: { "gpt-5.4": "openai-chat" } }; - for (const inbound of INBOUNDS) { - expect(resolveWireProtocolOverride("github-copilot", "gpt-5.4", provider, inbound).adapter) - .toBe("openai-chat"); - } - }); + for (const model of RESPONSES_ONLY) { + test(`opt-out: ${model} pinned back to chat`, () => { + const provider = { ...copilotProvider(), modelAdapters: { [model]: "openai-chat" } }; + for (const inbound of INBOUNDS) { + expect(resolveWireProtocolOverride("github-copilot", model, provider, inbound).adapter) + .toBe("openai-chat"); + } + }); + } test("opt-in: an unlisted model mapped to Responses (the gpt-5.4-nano escape hatch)", () => { const provider = { ...copilotProvider(), modelAdapters: { "gpt-5.4-nano": "openai-responses" } }; @@ -81,13 +117,15 @@ describe("explicit modelAdapters beat the registry default in both directions", }); describe("the registry default is isolated to the copilot provider", () => { - test("a same-named model on another provider is untouched", () => { - const other: OcxProviderConfig = { adapter: "openai-chat", baseUrl: "https://example.com/v1", apiKey: "sk-test" }; - for (const inbound of INBOUNDS) { - expect(resolveWireProtocolOverride("some-custom", "gpt-5.4", other, inbound).adapter) - .toBe("openai-chat"); - } - }); + for (const model of RESPONSES_ONLY) { + test(`${model} on another provider is untouched`, () => { + const other: OcxProviderConfig = { adapter: "openai-chat", baseUrl: "https://example.com/v1", apiKey: "sk-test" }; + for (const inbound of INBOUNDS) { + expect(resolveWireProtocolOverride("some-custom", model, other, inbound).adapter) + .toBe("openai-chat"); + } + }); + } test("resolution preserves credentials and base URL through the copy", () => { const resolved = resolveWireProtocolOverride("github-copilot", "gpt-5.4", copilotProvider(), "responses"); @@ -143,6 +181,14 @@ describe("the wire default survives the handleResponses replay", () => { expect(url).not.toContain("/chat/completions"); }); + for (const model of ["gpt-6-astra", "grok-4.5", "grok-4.6", "mai-code-1.1-flash", "mai-code-1-flash-picker"]) { + for (const inbound of INBOUNDS) { + test(`${model} reaches /responses on ${inbound} inbound replay`, async () => { + expect(await drive(model, inbound)).toBe("https://api.githubcopilot.com/v1/responses"); + }); + } + } + test("gpt-4o still reaches /chat/completions", async () => { expect(await drive("gpt-4o", "responses")).toBe("https://api.githubcopilot.com/chat/completions"); }); From 6061dcce02bb8955dd8c4cfc353af3ed64082301 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 18:20:21 +0900 Subject: [PATCH 078/412] test(kiro): isolate and restore every debug setting the diagnostics gate reads [skip ci] Resolves the maintainer objection on #3837 (discussion_r3945935220): the shared setup cleared only OCX_DEBUG_FRAMES, so an inherited OCX_DEBUG=1 or a runtime debug override made the encoder-spy test fail legitimately. Snapshot OCX_DEBUG, OCX_DEBUG_FRAMES and the runtime override in beforeEach, clear them, and restore the exact previous values in afterEach. Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com> --- tests/providers/kiro/kiro-stream.test.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/tests/providers/kiro/kiro-stream.test.ts b/tests/providers/kiro/kiro-stream.test.ts index 1a9b7a6e02..47dfaf1833 100644 --- a/tests/providers/kiro/kiro-stream.test.ts +++ b/tests/providers/kiro/kiro-stream.test.ts @@ -16,6 +16,11 @@ import { parseKiroEvent } from "../../../src/adapters/kiro-events"; import { resetKiroThrottleStateForTests } from "../../../src/adapters/kiro-retry"; import { resetKiroCalibration } from "../../../src/adapters/kiro-calibration"; import { buildResponseJSON } from "../../../src/bridge"; +import { + clearDebugSetting, + getDebugSettings, + setDebugSettings, +} from "../../../src/lib/debug-settings"; import { encodeMessage } from "../../../src/lib/eventstream-decoder"; import { estimateTokens } from "../../../src/lib/token-estimate"; import { createTranslatorBudget } from "../../../src/lib/translator-budget"; @@ -34,11 +39,16 @@ const origApiRegion = process.env.KIRO_API_REGION; const origArn = process.env.KIRO_PROFILE_ARN; const origCredsFile = process.env.KIRO_CREDS_FILE; const origCredentialsFile = process.env.KIRO_CREDENTIALS_FILE; -const origDebugFrames = process.env.OCX_DEBUG_FRAMES; +let origDebug: string | undefined; +let origDebugFrames: string | undefined; +let origDebugOverride: boolean | undefined; const realFetch = globalThis.fetch; let tmp: string; beforeEach(() => { + origDebug = process.env.OCX_DEBUG; + origDebugFrames = process.env.OCX_DEBUG_FRAMES; + origDebugOverride = getDebugSettings().runtimeOverride.debug; tmp = mkdtempSync(join(tmpdir(), "kiro-stream-")); process.env.HOME = tmp; process.env.KIRO_REGION = "us-east-1"; @@ -46,7 +56,9 @@ beforeEach(() => { delete process.env.KIRO_PROFILE_ARN; delete process.env.KIRO_CREDS_FILE; delete process.env.KIRO_CREDENTIALS_FILE; + delete process.env.OCX_DEBUG; delete process.env.OCX_DEBUG_FRAMES; + clearDebugSetting("debug"); }); afterEach(() => { globalThis.fetch = realFetch; @@ -57,7 +69,10 @@ afterEach(() => { if (origArn === undefined) delete process.env.KIRO_PROFILE_ARN; else process.env.KIRO_PROFILE_ARN = origArn; if (origCredsFile === undefined) delete process.env.KIRO_CREDS_FILE; else process.env.KIRO_CREDS_FILE = origCredsFile; if (origCredentialsFile === undefined) delete process.env.KIRO_CREDENTIALS_FILE; else process.env.KIRO_CREDENTIALS_FILE = origCredentialsFile; + if (origDebug === undefined) delete process.env.OCX_DEBUG; else process.env.OCX_DEBUG = origDebug; if (origDebugFrames === undefined) delete process.env.OCX_DEBUG_FRAMES; else process.env.OCX_DEBUG_FRAMES = origDebugFrames; + if (origDebugOverride === undefined) clearDebugSetting("debug"); + else setDebugSettings({ debug: origDebugOverride }); removeTreeWithRetry(tmp); }); From 25689e1ec3631ba2ca8735bb41d4fd4d366d44a4 Mon Sep 17 00:00:00 2001 From: luvs01 <27862058+luvs01@users.noreply.github.com> Date: Mon, 7 Sep 2026 10:54:56 +0900 Subject: [PATCH 079/412] fix(responses): bound the streaming citation marker span [skip ci] (cherry picked from commit 8ef77f773523ba3ec55202a79f5abad247166026) Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com> --- src/responses/citation-markers.ts | 17 +++++++++++++++++ tests/responses/citation-markers.test.ts | 22 ++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/responses/citation-markers.ts b/src/responses/citation-markers.ts index 5fe58142cf..b65477b66e 100644 --- a/src/responses/citation-markers.ts +++ b/src/responses/citation-markers.ts @@ -68,6 +68,15 @@ export interface CitationMarkerFilter { flush(): string; } +/** + * Upper bound on the text withheld for one unterminated START. + * + * A real span is `cite` plus a few turn-scoped ids, so it is far under this. Without a + * bound, a backend that emits a START and never terminates it makes `held` grow for the + * whole response, and every later delta re-scans that accumulated prefix. + */ +const MAX_STREAMING_MARKER_SPAN_LENGTH = 4_096; + /** * Streaming filter. * @@ -75,6 +84,9 @@ export interface CitationMarkerFilter { * next — so a stateless per-delta strip would emit the tail of a span it never recognized. * This holds back the text from an unterminated START and releases it once the END arrives * (removed) or the stream ends (verbatim, so nothing the model actually said is lost). + * + * A span that grows past `MAX_STREAMING_MARKER_SPAN_LENGTH` is malformed ordinary text, so + * it is released verbatim instead of withheld; a later START can still open a valid span. */ export function createCitationMarkerFilter(): CitationMarkerFilter { // Text from an open START that has not been terminated yet. @@ -87,6 +99,11 @@ export function createCitationMarkerFilter(): CitationMarkerFilter { if (start === -1) return stripCitationMarkers(combined); const endAfterStart = combined.indexOf(CITATION_MARKER_END, start + 1); if (endAfterStart !== -1) return stripCitationMarkers(combined); + // Over the bound: this is not a citation span we will ever close. Emit it verbatim + // so neither the retained text nor the per-delta rescan grows without limit. + if (combined.length - start > MAX_STREAMING_MARKER_SPAN_LENGTH) { + return stripCitationMarkers(combined.slice(0, start)) + combined.slice(start); + } // The trailing span is still open: emit everything before it, hold the rest. held = combined.slice(start); return stripCitationMarkers(combined.slice(0, start)); diff --git a/tests/responses/citation-markers.test.ts b/tests/responses/citation-markers.test.ts index 0c1921750c..6145dbe688 100644 --- a/tests/responses/citation-markers.test.ts +++ b/tests/responses/citation-markers.test.ts @@ -87,4 +87,26 @@ describe("streaming citation marker filter (#3150)", () => { const filter = createCitationMarkerFilter(); expect(filter.push(`visible now ${S}cite`)).toBe("visible now "); }); + + test("an unterminated span past the bound is released instead of retained", () => { + // A backend that opens a span and never closes it must not make the filter accumulate + // the rest of the response, which every later delta would then re-scan. + const filter = createCitationMarkerFilter(); + let out = filter.push(`kept ${S}cite`); + expect(out).toBe("kept "); + for (let i = 0; i < 5_000; i += 1) out += filter.push("x"); + + // Everything after the malformed START is emitted verbatim, so nothing is lost, and + // flush() has nothing left to release. + expect(out).toBe(`kept ${S}cite${"x".repeat(5_000)}`); + expect(filter.flush()).toBe(""); + }); + + test("a later START still opens a valid span after a released malformed one", () => { + const filter = createCitationMarkerFilter(); + let out = filter.push(`a${S}${"y".repeat(5_000)}`); + out += filter.push(`${S}cite${P}turn1view0${E} tail`); + expect(out).toBe(`a${S}${"y".repeat(5_000)} tail`); + expect(filter.flush()).toBe(""); + }); }); From 00b74c7200ea5d33dbe495cc39788a91cbe4fd2b Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 18:22:45 +0900 Subject: [PATCH 080/412] fix(responses): keep an oversized citation span verbatim before a later marker in the same delta [skip ci] Resolves the unresolved major finding on #3843 (discussion_r3946034145): lastIndexOf selected the later START, its END made the whole-string strip pair the first START with that END, and the malformed text vanished. Walk START-delimited segments independently so a superseded or over-bound span is emitted verbatim and only a bounded trailing span is held for the next delta. Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com> --- src/responses/citation-markers.ts | 34 +++++++++++++++--------- tests/responses/citation-markers.test.ts | 8 ++++++ 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/responses/citation-markers.ts b/src/responses/citation-markers.ts index b65477b66e..3e3943cad5 100644 --- a/src/responses/citation-markers.ts +++ b/src/responses/citation-markers.ts @@ -95,18 +95,29 @@ export function createCitationMarkerFilter(): CitationMarkerFilter { push(delta: string): string { const combined = held + delta; held = ""; - const start = combined.lastIndexOf(CITATION_MARKER_START); - if (start === -1) return stripCitationMarkers(combined); - const endAfterStart = combined.indexOf(CITATION_MARKER_END, start + 1); - if (endAfterStart !== -1) return stripCitationMarkers(combined); - // Over the bound: this is not a citation span we will ever close. Emit it verbatim - // so neither the retained text nor the per-delta rescan grows without limit. - if (combined.length - start > MAX_STREAMING_MARKER_SPAN_LENGTH) { - return stripCitationMarkers(combined.slice(0, start)) + combined.slice(start); + let start = combined.indexOf(CITATION_MARKER_START); + if (start === -1) return combined; + let out = combined.slice(0, start); + // Walk START-delimited segments independently so an earlier malformed START is never + // paired with a later span's END (the whole-string strip would do exactly that). + while (start !== -1) { + const nextStart = combined.indexOf(CITATION_MARKER_START, start + 1); + const segment = combined.slice(start, nextStart === -1 ? combined.length : nextStart); + const end = segment.indexOf(CITATION_MARKER_END, 1); + if (end !== -1) { + // A complete span: drop it, keep whatever trails it inside this segment. + out += segment.slice(end + 1); + } else if (nextStart === -1 && segment.length <= MAX_STREAMING_MARKER_SPAN_LENGTH) { + // Only a bounded trailing span can still be completed by a later delta. + held = segment; + } else { + // Superseded by a later START, or over the bound: ordinary text, emitted verbatim + // so neither the retained text nor the per-delta rescan grows without limit. + out += segment; + } + start = nextStart; } - // The trailing span is still open: emit everything before it, hold the rest. - held = combined.slice(start); - return stripCitationMarkers(combined.slice(0, start)); + return out; }, flush(): string { const rest = held; @@ -115,4 +126,3 @@ export function createCitationMarkerFilter(): CitationMarkerFilter { }, }; } - diff --git a/tests/responses/citation-markers.test.ts b/tests/responses/citation-markers.test.ts index 6145dbe688..dcc7f9abc6 100644 --- a/tests/responses/citation-markers.test.ts +++ b/tests/responses/citation-markers.test.ts @@ -109,4 +109,12 @@ describe("streaming citation marker filter (#3150)", () => { expect(out).toBe(`a${S}${"y".repeat(5_000)} tail`); expect(filter.flush()).toBe(""); }); + + test("an oversized malformed span survives a later valid marker in the same delta", () => { + const filter = createCitationMarkerFilter(); + const malformed = `${S}${"y".repeat(5_000)}`; + expect(filter.push(`a${span}${malformed}${S}cite${P}turn1view0${E} tail`)) + .toBe(`a${malformed} tail`); + expect(filter.flush()).toBe(""); + }); }); From 924b65799d32f22e1ec0bdb8cc216897bc8527ef Mon Sep 17 00:00:00 2001 From: luvs01 <27862058+luvs01@users.noreply.github.com> Date: Mon, 7 Sep 2026 11:02:32 +0900 Subject: [PATCH 081/412] fix(providers): refuse keychain restore across provider ownership [skip ci] (cherry picked from commit 73abec9a995d157e3acb55edfd7d8f082cc11aae) Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com> --- src/providers/key-store.ts | 22 +++++++++++++++ tests/providers/provider-key-store.test.ts | 32 +++++++++++++++++++++- 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/providers/key-store.ts b/src/providers/key-store.ts index 12e4ce6cb7..614fd3372f 100644 --- a/src/providers/key-store.ts +++ b/src/providers/key-store.ts @@ -64,6 +64,16 @@ function keychainAccount(reference: string): string { return reference.slice(KEYCHAIN_REFERENCE_PREFIX.length); } +/** + * A reference belongs to `name` only when its account is that provider's own active account + * or one of its pool accounts. `storeProviderKeyInKeychain` writes exactly those two shapes, + * so anything else in a provider's config names another provider's secret. + */ +function keychainReferenceBelongsToProvider(reference: string, name: string): boolean { + const account = keychainAccount(reference); + return account === name || account.startsWith(`${name}/`); +} + function readKeychain(account: string): string | undefined { const cached = resolvedCache.get(account); if (cached !== undefined) return cached; @@ -185,6 +195,18 @@ export function restoreProviderKeyFromKeychain(config: OcxConfig, name: string): const pool = provider.apiKeyPool ?? []; const resolved = new Map(); const refs = [provider.apiKey, ...pool.map(e => e.key)].filter(isKeychainReference); + // Restore reads a secret out of the keychain, writes it back to config as plaintext, and then + // DELETES the keychain item. Following a reference to another provider's account would both + // disclose that secret through this provider's config and destroy the real owner's credential, + // so refuse before anything is read or removed. + const foreign = refs.filter(ref => !keychainReferenceBelongsToProvider(ref, name)); + if (foreign.length > 0) { + return { + ok: false, + error: `provider "${name}" references a keychain account it does not own (${foreign.length} reference(s)); config left unchanged`, + status: 400, + }; + } for (const ref of refs) { const account = keychainAccount(ref); if (resolved.has(account)) continue; diff --git a/tests/providers/provider-key-store.test.ts b/tests/providers/provider-key-store.test.ts index 645920e32c..1197a1fea9 100644 --- a/tests/providers/provider-key-store.test.ts +++ b/tests/providers/provider-key-store.test.ts @@ -156,6 +156,37 @@ describe("store / restore", () => { expect(probeProviderKeychain().available).toBe(false); }); + test("restore refuses a reference to another provider's keychain account", () => { + const { store, factory } = fakeKeychain(); + setProviderKeychainEntryFactoryForTests(factory); + const config = loadConfig(); + config.providers.other = { adapter: "openai-chat", baseUrl: "https://other.example/v1", apiKey: POOL_SECRET }; + expect(storeProviderKeyInKeychain(config, "other")).toEqual({ ok: true, moved: 1 }); + expect(config.providers.other!.apiKey).toBe("keychain:other"); + + // Point "relay" at the account "other" owns. Restore would otherwise read that secret, + // write it into relay's config as plaintext, and delete the owner's keychain item. + config.providers.relay!.apiKey = "keychain:other"; + const result = restoreProviderKeyFromKeychain(config, "relay"); + expect(result.ok).toBe(false); + if (!result.ok) expect(result.status).toBe(400); + + expect(config.providers.relay!.apiKey).toBe("keychain:other"); + expect(readFileSync(join(testDir, "config.json"), "utf8")).not.toContain(POOL_SECRET); + // The real owner's secret is still in the keychain and still resolves for that provider. + expect(store.size).toBe(1); + expect(resolveProviderApiKey(config.providers.other!.apiKey)).toBe(POOL_SECRET); + }); + + test("restore still accepts a provider's own active and pool accounts", () => { + const { factory } = fakeKeychain(); + setProviderKeychainEntryFactoryForTests(factory); + const config = loadConfig(); + config.providers.relay!.apiKeyPool = [{ id: "a1", key: SECRET }, { id: "b2", key: POOL_SECRET }]; + expect(storeProviderKeyInKeychain(config, "relay")).toEqual({ ok: true, moved: 2 }); + expect(restoreProviderKeyFromKeychain(config, "relay")).toEqual({ ok: true, restored: 2 }); + }); + test("management route: GET reports store kind, POST store/restore round-trips", async () => { const { factory } = fakeKeychain(); setProviderKeychainEntryFactoryForTests(factory); @@ -192,4 +223,3 @@ describe("store / restore", () => { } }); }); - From 55de3ee97d7e7e98cb9c38c2a42c5cf7290885f0 Mon Sep 17 00:00:00 2001 From: DaedalGames Date: Mon, 7 Sep 2026 18:25:55 +0900 Subject: [PATCH 082/412] fix(codex): clear matching reauth state after deferred validation --- src/codex/account-runtime-state.ts | 7 ++++- src/codex/auth-api.ts | 1 + .../codex-integration/codex-auth-api.test.ts | 30 ++++++++++++++++--- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/codex/account-runtime-state.ts b/src/codex/account-runtime-state.ts index ff036429d7..35f3c9cca5 100644 --- a/src/codex/account-runtime-state.ts +++ b/src/codex/account-runtime-state.ts @@ -60,6 +60,11 @@ export function isAccountNeedsReauth(id: string): boolean { return true; } -export function clearAccountNeedsReauth(id: string): void { +export function clearAccountNeedsReauth(id: string, credentialGeneration?: number): void { + // A model response proves only the credential it used. Keep account-wide + // quarantine and evidence from another generation intact. + if (credentialGeneration !== undefined + && (reauthAccounts.get(id) !== credentialGeneration + || !isCodexAccountGenerationLive(id, credentialGeneration))) return; reauthAccounts.delete(id); } diff --git a/src/codex/auth-api.ts b/src/codex/auth-api.ts index d6e7107c8e..ace16961eb 100644 --- a/src/codex/auth-api.ts +++ b/src/codex/auth-api.ts @@ -1473,6 +1473,7 @@ async function fetchPoolAccountQuota( chatgptAccountId: record.credential.chatgptAccountId, }); markCodexAccountValidated(accountId, Date.now(), generation); + clearAccountNeedsReauth(accountId, generation); } catch (error) { // Keep the durable restriction on any failed/partial inference response, even // when WHAM just reported headroom. No raw upstream text enters diagnostics. diff --git a/tests/codex-integration/codex-auth-api.test.ts b/tests/codex-integration/codex-auth-api.test.ts index 3157ac36c6..a525469b3c 100644 --- a/tests/codex-integration/codex-auth-api.test.ts +++ b/tests/codex-integration/codex-auth-api.test.ts @@ -5073,7 +5073,7 @@ describe("codex-auth API", () => { { status: 401, replace: false }, { status: 403, replace: false }, { status: 429, replace: false }, { status: 500, replace: false }, { status: 401, replace: true }, { status: 403, replace: true }, - ])("deferred validation reports generation-current authentication failures: %j", async ({ status, replace }) => { + ].flatMap(scenario => [false, true].map(restart => ({ ...scenario, restart }))))("deferred validation reports generation-current authentication failures: %j", async ({ status, replace, restart }) => { const accountId = "validation-auth-error"; const config = makeConfig({ codexAccounts: [{ id: accountId, plan: "pro", isMain: false }] }); saveConfig(config); @@ -5102,9 +5102,9 @@ describe("codex-auth API", () => { expect(JSON.stringify(response)).not.toContain("private-validation-body"); expect(readCodexAccountRecord(accountId)?.codexValidationPending).toBe(true); expect(isCodexAccountUsable(config, accountId)).toBe(false); - // Clear volatile evidence: quota reads and restarts must not hide a permanent - // model-authorization failure; a replaced generation must not inherit it. - clearAccountNeedsReauth(accountId); + // Exercise both in-process recovery and lost volatile state after restart. + // Durable failure guidance must survive; replacement credentials must not inherit it. + if (restart) clearAccountNeedsReauth(accountId); const rows = await listCodexAuthAccounts(config, false); const authFailed = !replace && (status === 401 || status === 403); expect(rows.find(row => row.id === accountId)).toMatchObject({ @@ -5114,6 +5114,7 @@ describe("codex-auth API", () => { fail = false; await refresh(); expect(readCodexAccountRecord(accountId)?.codexValidationPending).toBeUndefined(); + expect(isAccountNeedsReauth(accountId)).toBe(false); expect(isCodexAccountUsable(config, accountId)).toBe(true); }); @@ -5672,4 +5673,25 @@ describe("codex-auth helpers", () => { clearAccountNeedsReauth(id); expect(isAccountNeedsReauth(id)).toBe(false); }); + + test("generation-scoped reauth recovery preserves replacement and account-wide evidence", () => { + const id = "reauth-generation-recovery"; + const credential = { accessToken: "old-access", refreshToken: "refresh", + expiresAt: Date.now() + 3600_000, chatgptAccountId: "account" }; + const oldGeneration = saveCodexAccountCredential(id, credential); + markAccountNeedsReauth(id, undefined, oldGeneration); + clearAccountNeedsReauth(id, oldGeneration); + expect(isAccountNeedsReauth(id)).toBe(false); + + const replacementGeneration = saveCodexAccountCredential(id, { ...credential, accessToken: "replacement" }); + markAccountNeedsReauth(id, undefined, replacementGeneration); + clearAccountNeedsReauth(id, oldGeneration); + expect(isAccountNeedsReauth(id)).toBe(true); + + markAccountNeedsReauth(id); + clearAccountNeedsReauth(id, replacementGeneration); + expect(isAccountNeedsReauth(id)).toBe(true); + clearAccountNeedsReauth(id); + expect(isAccountNeedsReauth(id)).toBe(false); + }); }); From 6eadb165873a33d8589e46bf5256a61524d82ec7 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 18:18:33 +0900 Subject: [PATCH 083/412] fix(management): expose the effective web-search sidecar enabled state GET and PUT /api/sidecar-settings return webSearch.model/backend/stream flags but omitted webSearch.enabled, so the dashboard could not tell whether the sidecar master switch was off. Serialize the effective value (unset reads as enabled) on both responses. Reimplements https://github.com/lidge-jun/opencodex/pull/2033 on current dev (the original branch is 1364 commits behind and its test moved to tests/vision/ under the test-layout split). Co-authored-by: louis-tepe <161487332+louis-tepe@users.noreply.github.com> --- src/server/management/config-routes.ts | 2 ++ .../vision/sidecar-settings-vision-controls.test.ts | 12 ++++++++++++ tests/vision/vision-anthropic.test.ts | 4 ++-- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/server/management/config-routes.ts b/src/server/management/config-routes.ts index 4d551a886d..08f4b85d27 100644 --- a/src/server/management/config-routes.ts +++ b/src/server/management/config-routes.ts @@ -701,6 +701,7 @@ export async function handleConfigRoutes(ctx: ManagementContext): Promise { expect(config.visionSidecar).toEqual({ ...FULL_VISION, enabled: false }); }); + test("GET and PUT expose the effective web-search enabled state", async () => { + const unset = await getSidecarSettings(emptyConfig()); + expect((await unset.json() as { webSearch: { enabled: boolean } }).webSearch.enabled).toBe(true); + + const config = emptyConfig({ webSearchSidecar: { enabled: false } }); + const disabled = await getSidecarSettings(config); + expect((await disabled.json() as { webSearch: { enabled: boolean } }).webSearch.enabled).toBe(false); + + const response = await putSidecarSettings(config, { webSearch: { streamRoutedModelOutput: true } }); + expect((await response.json() as { webSearch: { enabled: boolean } }).webSearch.enabled).toBe(false); + }); + test("timeoutMs validation reuses the runtime bounds rather than a second contract", async () => { expect(resolveVisionTimeoutMs(undefined)).toBe(DEFAULT_VISION_TIMEOUT_MS); expect(resolveVisionTimeoutMs(MIN_VISION_TIMEOUT_MS)).toBe(MIN_VISION_TIMEOUT_MS); diff --git a/tests/vision/vision-anthropic.test.ts b/tests/vision/vision-anthropic.test.ts index ee4b01b421..086e5df7bb 100644 --- a/tests/vision/vision-anthropic.test.ts +++ b/tests/vision/vision-anthropic.test.ts @@ -339,7 +339,7 @@ describe("Anthropic vision planning and management config", () => { config, ); const getBody = await get!.json() as Record; - expect(getBody.webSearch).toEqual({ model: "claude-haiku-4-5", backend: "anthropic", streamRoutedModelOutput: false }); + expect(getBody.webSearch).toEqual({ enabled: true, model: "claude-haiku-4-5", backend: "anthropic", streamRoutedModelOutput: false }); expect(getBody.vision).toEqual({ enabled: true, model: "claude-sonnet-5", @@ -363,7 +363,7 @@ describe("Anthropic vision planning and management config", () => { ); expect(clear.status).toBe(200); const clearBody = await clear.json() as Record; - expect(clearBody.webSearch).toEqual({ model: "gpt-5.6-luna", streamRoutedModelOutput: false }); + expect(clearBody.webSearch).toEqual({ enabled: true, model: "gpt-5.6-luna", streamRoutedModelOutput: false }); expect(clearBody.vision).toEqual({ enabled: true, model: "gpt-5.4-mini", From 8f94fd1f406f327a445c87463abec3b66d8e56f3 Mon Sep 17 00:00:00 2001 From: DaedalGames Date: Mon, 7 Sep 2026 19:02:19 +0900 Subject: [PATCH 084/412] fix(codex): require dashboard consent for deferred validation --- .github/pr-assets/codex-quota-evidence.md | 21 ++++++------ .github/pr-assets/codex-quota-pending.png | Bin 229755 -> 78743 bytes .github/pr-assets/codex-quota-recovered.png | Bin 220523 -> 69314 bytes AGENTS.md | 4 +-- AGENTS_INSTALL.md | 10 +++++- .../docs/fr/guides/codex-integration.md | 2 +- .../content/docs/guides/codex-integration.md | 2 +- .../docs/ja/guides/codex-integration.md | 2 +- .../docs/ko/guides/codex-integration.md | 2 +- .../docs/ru/guides/codex-integration.md | 2 +- .../docs/tr/guides/codex-integration.md | 2 +- .../docs/zh-cn/guides/codex-integration.md | 2 +- .../docs/zh-tw/guides/codex-integration.md | 2 +- .../ocx/references/01_management_surface.md | 4 +-- src/cli/account-api.ts | 8 ++--- src/cli/account-auth.ts | 4 +-- src/cli/account-extended.ts | 4 +-- src/cli/capabilities.ts | 4 +-- src/codex/auth-api.ts | 9 ++++-- src/oauth/health.ts | 2 +- src/server/management-api.ts | 2 +- tests/cli/cli-account.test.ts | 4 +-- .../codex-integration/codex-auth-api.test.ts | 30 ++++++++++++++++-- tests/oauth/oauth-health.test.ts | 2 +- tests/server/server-management-auth.test.ts | 26 +++++++++++++++ 25 files changed, 107 insertions(+), 43 deletions(-) diff --git a/.github/pr-assets/codex-quota-evidence.md b/.github/pr-assets/codex-quota-evidence.md index 2c2229336d..8244c2441b 100644 --- a/.github/pr-assets/codex-quota-evidence.md +++ b/.github/pr-assets/codex-quota-evidence.md @@ -10,9 +10,10 @@ inference stream. The account identity and credentials are synthetic. The empty native-main home explains the separate Main Account warning in both screenshots. No live OpenAI account was used or charged. -The browser was Microsoft Edge through Playwright, at 1440 × 1100, English/light -theme, with external browser requests blocked. Verification ran on Windows. -The final capture used runtime and GUI changes through `25798a590`. +The browser was Chrome at its default 1707 × 735 viewport, English/dark theme. +Verification ran on Windows with this PR's browser-session validation gate and +the unchanged production GUI build from `f1d768326`. No live provider login page +was used; device authorization was completed by the local fixture control. 1. Open Codex Set → Multi-auth, click Add, enter an account ID, and choose Device code login. Authorize through the mock device service. @@ -28,13 +29,15 @@ The final capture used runtime and GUI changes through `25798a590`. The server receives a completed validation response. Cumulative counts: three usage reads, one model call. The pending flag clears, the validation timestamp is persisted, and “Use this account next” appears. -5. Select the recovered account and confirm the dialog. The real active-account - endpoint and stored config both report `weekly-demo` as selected and pinned. +5. Select the recovered account and confirm the dialog. The stored config reports + `weekly-demo` as the active account. -Both explicit refreshes used `POST /api/codex-auth/accounts/refresh` with the GUI -session's CSRF header. The actual server accepted them. Separate live-server tests -reject POSTs without CSRF or with a different Origin; GET quota refreshes never -complete pending validation. +Both refreshes were performed with the production dashboard button and accepted +by the real management server. Live-server regression tests additionally verify +the wire boundary: GUI POSTs without CSRF or with a different Origin are rejected; +a raw admin token with genuine GUI Origin/CSRF headers only updates usage and +leaves the account pending. Only the authenticated GUI session completes model +validation. GET quota refreshes remain observational. | Capture | Weekly usage | Pending | Model calls so far | | --- | --- | --- | --- | diff --git a/.github/pr-assets/codex-quota-pending.png b/.github/pr-assets/codex-quota-pending.png index 6a805026b8788face7910e809a0df8e81f507300..f142433e252ff7549397bf15cc4d7673c3844810 100644 GIT binary patch literal 78743 zcmeFZcUV))*C@PciWHR+>4FdhLX)agQRzJ-A(Q||ibyEZL5dp{6#g%}{nr2!E#-$} z`BW7A03{Oz6%)n&TYwuZBqbHaL3#gj6qI0bsgBcvP@~fT1r-$qH8m{*4He}vN(vf) zf|81whKczY%Q-35EAVK36U24TnBv~!5H@L9q{qEyvFUvRGPeC2XRbDQO+!uX@Pv|U zp|o;>-k%#mh8$o{2kx)DK>v^-2)e)oRv6_m3Mxt(YN{gy3Q8s_YE}p$+JyO>6bqc@ zx<`61zx0)jd&Lc(_s0MR5Dmm&0xknTz5%i!00y9(0{9MjXR>PZ(Vw8E1b`O+Uo15s zs0}8c(!G`WZYig%T}q_>8C!O0KlG*872pMJ3+2_Pv>;pr&<3fW0;eg|z!+T|3;@8u zxq}Gn1 zVxtR$8~{SDs)3#kaDoqPAT=m(8cZXADTj_FgzqI-L&jiPDX9;NLdn2<0HA(Bdk6<~ z`6$&6LR3RhDbLEa^zd)W2#)L*<^q}pMw6F3vyr0~`@l1ypBnqXeKhK8LY>@p`19A4 zA%YBJ^xj*~8dwCP&-gh#VnCU*U3wFU=KJG*UDXec4<7}F_JY1hS>_{8x)49;eaY)Z;Aq}$1{yrp8^!2?$ng}730q4t_}@fpOuGwnk-MZ zvl>qsiJDKPJ9hRMScyvvM)(n1&xQO}VDp&G6~Cwt1Kw=@YwLV(4`c7Ad#q+FDjC!q zz8<71FJuL|4mNbIG#j4<0F}Smu_=33-#Rf+Kjt+JSRr8ZWgfH~STR=su!2FKH59B# z;57Bq7hnts16voMiJ1bx9zq#%h(XPaJb?Tc9QBLSx|C|b-y8F4$O|wh=BtNoalq)P zJz}AMLJwkxPVMvwu+;(W-_a9SwXdojgqi*AWy)5;wYB|Nu0-TuIgC+pSJ zoo>}}ar*ofXbEa8ZeB~qJM&=z_WHzy%C3N_bYlKDmC>IsMisfb-XJmN#F=*Q-U->w z0D?fjQA+E3AKqh10ZB$1(Kc3=5b^5p)Sg|euA^Rf@xuk;MUz=ry$iSCr)g>0Ro^|$ zrcp~fLJrZ@`{B}%pN7) zUhcX6_Utdco*+&agy^>Qq(@$zc;ip?(HZUJ&Iz~Pyf$K9vLsaBhdXK{=$zShTqxv!r}fsUZzh9ff#-a_rSUH9BC{vGix$6e`Z#LcAAc;& zF>v|#Ha!n+EofY^`n#~x`l$-UwX2a@Z3|U!3~`-D?@dQmuKYFIrE*)>g4*tYZ#W{^ z$@S~!n;)F?2~{hPy__qB9L*zKzZs<`#%;Qc1*f^Twc1$hew%W=TB3WKyQ)!zNjhaR zxbpn?#xwhG^`v&cQF-L*%%FF*;-%$@VT4ktwe%dSZOh9#C}g5y>P~2yTfS4i8-mo? zH~vf3{Q1L}0=?vmaWW15voW_j2Zy?y$0S1y638yk^7+#X>)i+zlcG>;?oZunf0z*D z((c`GShH&#YN2|VdZ;bYFl5imCOnfzJE|EnQ|r+z+VZ6)NVu=0(}lcBz9-JQ-G1LW zFL^mfAFRxbXoM)jq?JYSv*bPzp{CRxREZ`Ir%04~fo`S++@|Xpho~QdSCNJTtVm-nGWS(zO)RYaraD=kQO zf`ZU{USWCfn-TgQKJ)0>Ar4u*2=mQ5-kTbRFO-g(FU^);b9dXlIq%{crCQNOLV8^i zf@&5?C>w9S>VcZ{YS7U24{5(M=ZmoZs?j#h0?SXf6M3dN9xC_P8Jjv(JT^9fzD`;* ze5c}2(=Hp`D&FYW%G=?Ux@G$F(SU~c87>Vu*E(pRIdr*nK3`hSA~FJ1EB$D*?g1Wa zIaxY+UNp#E4_b(0yLFaiC9V$eQL1XT zf$f-pgj3 ziv%0DD8fO30t?f{Em!83a1_D^ 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�nD$)h_ElRQG{$rUv*%`iA{@wL?3@Ix4OVP$Z4>TS(hWMTt(=NoBlYI@AM`S6BGWdR%v0bPdmD?|sU)X(y9G=j@<9Otg4+ zbMxM|O-Pw;VR%KU6Bk`?`5dW4@G6Py1;;#0yTSA1RYwrj^w~hN=7cqG8Kak*%DI+p z$@7Gufm>gfnv~z7*Xn!G*PL*KxwXkG_<%u_@T@jUD$GD!|BK=6pZelCV@lZrn3(CH zJXeDoe?IYlTB1x=aA1G9x8Z=m%_p!@2cZ_Gw zYd*eZE5LNReIKw|lYBRn$Xcx;QfMM?A*-FCb#;M2xIX3syNnDs{+auxJCXe3$IM>

ZH0JdI)BOzC)5QB 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 TyWh`5P&aAWpT+k5J^udzS4}$+ literal 229755 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 }F;- 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ℑOa)s=h={^Ob z4WNXX7Fr^k#F5~%rz?NM;B3oZeO1BvbeU-?k?}V$m&eDBCNHy(yBgtFGUO0 zN;+5iMmb#)ccmGx|ioTeJT)YM8OBMv$G(72(>4^3S5h^xN~wq)g2dy`P8$G zfQd?298x=cB4$U0ZgWic5-%|6@D=b&1bGw0?x3lOs#AfJ>C`V7v~GA$YFX7i%ZZkc zoQh}uF3l5kXc$DGKqH7BO~5AH>TY)x^6bI?IT?2x0wX5wc7YX&*$$1T7aB~$2~QB( zpNvI|{-IFrmZQ92@gsW`Ajacw-!1c|8-Fja%X@%l0g>y5rwDxe2HP{~rHB zq@14nEZ!4?Deyi5=}H<-)9VT9TR<%=lgo|ITe_Te{-QSgiS=0$5)kNBB0aw8LeNJf z#)Y+B23OZ)F)~JxFR{tYt4TltM7==iU~PKSN$p|_?(8xkAFIXRU3`jeTiV7t`@SiF^$?Z2+k%Z zUN#|U@ncO_?Me-i`uM zAmnCt_RJ#=TdX^y5*K&I@neC;Ss0>+4?aDKq8Q@Y9**MT99?fNSFB z^(dw(?TP>`H^c1fw7#C6;bBR!VdeW?p5 zx`jJkxS+Ra$LGUIr%|)G-Ezsx6Sv}A3!r{D zzBalD6O0&IRv9WvZ6lPLogQ8zxl@eu5%!nnQG$ni%aP+(;t0>M=)P})gJK_9;vo8w@W_SX) z1WAGvsH@!tj=gdBs+xZ0*fiKHoTut3p^MT+j3@6g1Fd0$gZ!G9Q=iZjzQ8s!8%FV= z#S!N$lo4q{_!qePcZv&C!`yy9dYDZe1lN~%V$I0u;}f}pZpSD}Bu2;(AN@m^x_kOI zQ-I*rPZ*hNcuz{Cc>IM8p3n_k9-660&s0!MPa7f0rqEOE59G*Z<2Q5Jk@}XqJDsZ@ zdktLQSIk22I5bov)6Q3PYm)N%ME_o6WPB5I{%#wpjDKhYSA)G%qu|veO`Q32kcMz| zv${K98?7#oOnTQp+ z0G7Ftk`rSf(h^VoPa&CH4jmoHT;zqk4DqqV>6Vrjcp3-5SKP)a`@|JtX+quwo^;>Y znjIs{UuoT~FDF}JqQsEUFPaBAbQ7Zpv$-RwDLP|t)r!8?zwi#5#JRyFcJd>%i}r=b z{dS@TTsk=Qq)+0|B5I!4#GDiNe8R|r_}?V=9CS#`;MIFxHZ5(on`6=VlgZ`iE!);UnF06cwWK$un=NSiYi|d}2vFnKpG* zQ$5H+AlIJ(?V`gO!*P;vlS0O{msNqws-m1HkMoJcNx9L-Jk(4Elyb7$Pm&4LYt_=s zkq&T9W0@-j-OCHyt%ES%Uh(_-u4Llbp3g_fx=GNx2g~C`+N*p_u>8B#gj~8v%2NX3 zloo4(%5cRUNr4h5q5wCk7@5gH61~HMkO+5gU}} zzrsB??#|V-Xb1aZ`CTrL!4I(5$FA>23uUVCJPGy&)Rh*)--VDCECs&Z`0JmbYa`f5 z7l>-mU>^~h)}2l~w{h1==@yK)H}V3=aJz%CK^o9e;I9k#gZ}W=mp@+UF4eA`xf*cUWVDC zif20oRU@iqeB%b$FI;Pqw{dR76zAf*qZ%_3DOlir{RyD&vJsD8$1jHJGF3ln#_YGi zy~8Tknp$(Xlx1$0frl>B7qK_Y#IB0Ke91dl8A#)ZRikdW)@(T$+chXTreywL!EtJx z*U5$j`E{Lf#QfsQP_ZrN?xcoPnJleg68|ehyEZ>=bsnV44OYvt%5gf;qmm~ARceCK z31!`VcIASk>a|L8&0{n3EkX8ma{$ODCvR(qi95@h;Yvk;{uJxOh+x3EO@FdMYe@Jo zh>!xy)w`>xL(Zn~9IEOK#fd9jKxy6hq$=fqfs6nrM?CP$FpMuLKZ}3BCgNyw6i99Y zV&3{2nn>dkg*!VGogl!9$K~jKam^W*7Ri(;b$yDQfVhfUj9dLP$w!$U+};(?AZRKf z(hIcCEH`@jd?w1Y5Zjl8IW=S8>l7GEqja#P=RfWd%j4RDWE(*fugb0`UW|Gt|8=J0 zH+;j;;6p+}LTF>~d1c1c;y%b7Z8r8>AIga71bUngjV5W28Ft^ps_s5zv8>> zP{)*ynss_>K%SlLZ9(iomfmb~dZI9Bfwh#z5*t48Fvzp1L@UX$nJ{7FdGx_t^g)tB zdV*ZtQ}0;`0_6V7rX-i5811`O$-d_=y|eZZCQo7crfp~v`b&RhiSAWhg5(PkKP1EF zyk2Dg{zb+8{G{Z^83i=L^t*iO{50*#>dnEYZOQ;(g=Nbh|h+@!mNq+=RSzR4ltEJJj$uz8V&fS^@2 z_@tq#(0E$&(;L#hax8%#w#vmp9ww0)p+TrR3Zy$?hI7dME~I|p5Ho%z_yT3lYkWUF zoMfD}`4m2WnXH-eztg$oc^SRH*Lq4MF`E+i~UsDDQNo`(A1U| z7X5dP!tO*6v!Iud_m%O)le`{r9wvjh** zUYV}A+;(_Jd#+2B;*O1F6$86L)OTrSAJRT`h*ly z&@>H5W?<$-?V86Io03$=b^340CNB)@0wQ45c>g+Z+Mrpw@trpTjVBV(CZ3L8+iCu) z!>U@4*+Dr0f0a`4ZNrB$n?9z5!~Lj>!c}+v>r_(b4yx+T=|mkJp@Y4K&N~Jz5ni3R zEgl;yk6y{Tr}k*0NQI6FOguH8mcC1Rl#LYjr?yK8jT5`1dW}9wWATJjk1u2*lF&5_ zb_?J?Q|XQMaE7Bh!dyUuh}fQUsQ;!~_|U~7p^7$+`Lo%FQ;)|L7$!ESYA&U;?616mxt-{>2Y$wpZcMBBIYgP&`fd>JvP(_%1ts_6=Z2&`p?Bgc(83o&uB zWBiu{yg$EBB{dRXckc0B@(+Nzvbpy&Pj?X^zJ#PQ7kLr&}hh>Ic%dY6{Y?+owl9N#-KIE$o=` zeZ1#Hh}P26VvwP|H0id+E`4<>XO=jFx~T*^uc7)LTl(%AP>fus&dE@*F5-;N`6XK7 zVzmy~ec#*I-p(quj16{3&tR3uc28kN2KxF~B|i{Qm;Qi89dMGM(UMrI$YI$ZPBVt~eZkh@Jy$Q1dJ9fS~)=G+gKo-=7uziv=8mT0~vLA5J|K1sFVI z<5NJiWpshjLNJ@`U+A^8wcEf4cvAhLGe5;DIa@jZ0g1bapQOlooOOJCZ%?or~MdZRf%+vcwbZb^`VD3@o-eqPg1s zF}*nMJ#13mJLCa(Qai+noR&)-qhKj(vA3B-e9EN}az+;6x9*1WCWx#&n z@q*$s;K}pnd0So(fcmUm7qi}I`=S;=ca#nlktT^*GqA(p<(5#FR<-;;ST%WK-e!zt z7a$wfQU#yuN1o2c(ZRjB(DwU&%|sXlWAT^R4OS=93j+M|lciPic65mxcS#0<#Xh!N z=q=@O-jk9?JUCiNC9to`an_RH4ocD20Q~hpfZm_%Idp9!6MgdaX zFh^Ko)GCmCq&%piS5^Rzl!E7im4<_@OWJdfi4_o9|ABR9k@k`TBHR2tHgC$x!UAPW zC31lK0i2pK4b>M|^ZqyDK%1~}RLXeAOfTuY#t6&&4)FUpGq^0nrXoQ(t9hX2f3&UY zsd;WUayVgTvHX-MK7A7tfE&=7!3Tq@8jGuFuJ7dZGwjmwKNPdkjn-Q?6O=yfvO($Xr z$-q5?fr?eos^QCH(pWYq=^#lZ0*V+A6NLYKD;pO(`{Fv|;sMr+12&sm{5Jxu<=}sY z2OrsrH?xb`op2}nPV($d2+6u@`Bl9zC+lCo{%rB#Z*$`Ie7xhTz}jY4z2J7;)e|4zTC3YEeoW-^-o_{Q9n`}M)R$2F#@+qj7Z%koD$)9flEr%0yk@5_CJayP|EB*gbMUM@+#i;R22n z0GJTzUTQys1U#WITHDG%|F{r(o_~jjp}I8`>&wdIU)>6|U$7jt4wEqs^?-9AIyk{G zKyJF!V}kWOKRd3&on3afrKe1hgvnr?s`4j?O;%knbzjOWH+T~z2M+^4&!-p|utJs) zHu~~8;nixqFJHgLRbWZ^R~?C#oMCtGG_PjDfN);R@qA!?0-Wq6ewwZR%e?@ZoIru^ zs4CL2{~p99R8qucFZyVamn~@Zi~b#ajVFZGr{2_hE?<}NhbSr3o#NwX-JGG$VIw)y z85-}0{e=PsJ0sc}u9o-Z!?(65SUfr9x_LMJM8BznI_l8{yhe9d*OqtM zbHFVHh)B%|lO2_j|6Lc)LF1g{vI$O$-+z~e3aOp^JfU4YHu&luH{Rv zf$b~bxBqSk81p|&n7*X(!lTl*cWbD$)!OyauBd52<_9mDAePdG$%FU`+ni=`{USsr ze!|Jg3D&*lLBjU-Hb5|9c**|1zj|;i)?A{thG%#>PDU|sO z@Lv7u-1Jaby+r*-Qc@+6IIqaNlL{kh3A48(NMz&#r1~#SYp*=4L+U?kto|a#OLC&= zkMjA7?1r~aH3@}1@D86x2b|~SoTMh@c#fDiu+}=ZMUuqEnUtt~N~8Jj4?_Bcxi3*t zt01XgzYZK1fAapp>C`KZKMl+7964kP-O}f4_p+QM*$nTY#!1!{ym@vdX)0+blvf~- z2I)3F(e&SQf*_Xg?w>)9*e_=CxUL%=gYpDdt26{$2!a@@bof+9_D^cb$BYZ;lap(6 z$s|77<>=Ok<~=8tIg<0f+}W*m1-+rD=WX3n~Cn^Xzg z8LH1Kw%cSTd!lC1!@Bo4`8Bm{(pBY{sG~nqczvZ*`~P!0p@0?pTmmTU1=iA%!1ZtCBn?=K>)toe+`<6rLy9GeAMQmUZy}+S(Z_2!VhJ z93@tLFOc&}NbF)elmy@dU=a`?ZouVe+Gy93TZuK%{M30<@ho!>W^jacc-h|E_is^J zzH7(>jA{+K84#(cD2{jI9{>{`>g4PM0#e#6DV1Nv|9RNwvc;w;s;=KAYfs>v>~Y!G zHL)g^Dn#-IQdRM%r94t4smgfHPooATBx0WAXQ&D~kj6N&gHBY|u{#C=5|>H6O=n&! zOMV6DoM*BR8v%9W+QIo-Ss*l5SWGfPzKF#gZsJTI-=dRe&*Zs{&S)aKN;Ez>YtpA=tieTjoZf0>S%FAU?P9(8~Ff}v+q5*ptz6%@q z8<>n>ZGB*p3wSJ%#t9(jTtx9-QehBx2o6E+?(P}}aQ%eEACZ_do1#w(RBoMqd40Pl z0*l@Njf_g|2ug4$0`LMF96HXK?_*7kz{o28$Ua2KZHb!Z0})datlr!?uxW@*2Qmdr z`D6g;f-8#^{-7cGZj!1AmL}0K%zJ1*o`7;{ehSqsu>UxsKz9P)4O8Oo1VcaQc(mfN zV~5L^8Sr*yp5WV9w*>OMPsD*|rlZiafT3AUAmXRngz;5&J5(nvsbo%6BtHO-e#K{* zCqt@PgyVr;1Xmf?fmC{v_%i6>@q;;bozV|}m}pj;Xr`s|@%)`qX4stF*wGyJ0MKC1&>Lm=#y;1ObyBfx!f-ooN8+h}QV72IN@ zr=vr?)g1)}e@r?m%G0x^&U#yiF^3Cxd=VnwlsNul*$IYQJ?|gV61Bbjh>4^AvtfWx zHykh-)^t|)(n{1HceLC~7kj>!N1zo^Bi^57K`m?wQ$Av1M{#UU99Si>DTVn1F6Fe> zBNPQ&n2d}}T$mF7Xx9A!P)9^#0r>NR7$ca9NTi$jj^Qt9qOkmD$Q22Ifu*?NI8>I= zpw|$qb-FMH8IqqmWE?x<;;f&0P(LI0oVhKg^ShpqjG>#APz_)5Pvu>Q*o0A`GenF{ z8Up6}_Dpq9Y3Ojm^k8cQQJoF9Lh!~ot{u_U%GfSlrKd6Js??mCUICTx7>9)#;!eBi zH)2cDJ)Cg*Qr)I%X}{$Cxw9lHOcx% ztPq#tMm9D$k9!@UGE;gsXMAaR7M6UhZN(j0U+NjH^tT5j-e1tM^etM86NBAz?qbBg zsSaDhmZL-V^#=;Eh^wJ-+wG9L{ZJU28o9OT{G=|rI|i38d=BCp;W&folVuhx!V!rR0V!8yOrf5nR#BI@^w1$N;l(7Ycg@7RB%e{ zl72(`p8oTuf+xf&IID%9evjHdh{cHYLcJc}|I<=Hm%EdaUAg$m-u#Fbry7qcLE*q1 zEEVQ?x6nQI^}~m1aTczGb*Jyo#umf7Z7!|(oy~iaPi}TtZR%PU={`dzqxh<4re11I zA9l6YIbX4|pSCAUP3B8Q4dBJb#7N<)dA?WFZJdm3+v&R~S!n2+d(Y*^=sf!CpB`~p z`HL4Wd_64ARs7+x*e+j|IDus8gcb-v%y0wFr3Cke9(aN_mHPBAMEhg$(DWH`@XfqZ z$u`@;H>ASAgETunUC1YoUR^sl+2X#Mz7#zDq@*M`C*BT|rH5~v<8$9B)1VvYeW>xm zb5eUTn5Tx1>IU`ZBBKXIQJ$^~`nne~_q)CCNX7XFYm*Pv@GF8Khj)+Lf}|$O2A5_O zv)pG&SN*=oxkp$-K6rbE+7)>hlIH7e^Eu` z9K-(y(7kK>=e=SjKB?m=GAD8peY`7V!>M#ztwN8yEfn@T(^%4-Ew*yI^_b;QrdAVG zIy8PMR->R(_79^7#1YWn>0V z5^$A22H1T}mOx2KS=1_N58QyW7tUNBUS0^UIj;A+v1yMQmf((o65TXx(Y@(wP+(xZ z=S0n}2&dC>XZ5wi26-yE(Km0~qa-eVXt2LBLo7?jgW69eoYh2YEK$M2Aowrr-$6Q6 zaaSwQiM$#Kc~u^4y;ni4lb0c)jB_Ib&?aiEjzN)h#J0v<6(g)`1I3gb{MZ*^)=^onwBS7lIYWZS#TK&5rPhbb?3H~!KOT$S&|-Z2FrUMP zV?(>5JR(nyGtHk8sjfTl5KHusxy$Z#M`Hsx8w!yJkLUT8hjX}KV$h9>0;Rs==MkTC zOT6;(Het_W;NBcr;7icKRns8x#7>}K^vxvZ*bOFL6+AV#wZxBYQ4!f5;m|OzQJKpZ0ZQ5>)qGW7-ycvZ(9+W0DA{C~9!O)%S!-^VJF(!+D&SWA zEmtSf9BN`{^gvlyNmSVHlKv$lqs+ZRYaWM7)XUu)onenOU#%nFY~)k^(1nW$!mKl{ z(d|G{NH;XKlN0*HqQR~OZVF%+Xcowody~aR#BQ%PqW;-n4;Q1=e;Rj~SHF^7xaAO; zcD!F2^;9e6wa>$By1qzSBZESLej({O)=i(I&7O)4RuiSrfzxo}F=p2I>{K;a*F-qm z0I$GaW|*zH7r+r%Bz@utCW?Wo(cruVg_|Z9w8L3o5hMru;deg?6Vx`aa2E^U@F{$w%!n1kl;p%y}`q4o9(@ zb#%$$bow?Nd<7%l)PHK5+lAp*R#nxih+NObS*Y-e!6#s%rYx1G&5O@2SydK1lkH-BFNvtAwPY_&a}kt!*N;Gid&DI2LECrMX* zn_q?+je8YZ{xf9PO3o{r`qGp@D@bbS}qiM_vR;x`-$UT?j2g#?+k5a zS~E4*Y&{&{<7t&1VpyEumw&%q!75t5=AIpEMlmPj?lD@_;O_M$-9nP2on2R{QVwkM{_$F;SRzkkCP2ZIotl2x&vVcS2q9P-ZMMRfr!Tp=QWK z`e-IZ3w;@ulUr6?I7gl8XB5*QOg>$wM@ky z)qpr-ALl>643F%UR^%Lyp-dNsCn(H5fH@j@xx+QdU^?y1C#&7YYHKyxm%Kbg5=rA; zG@WHX87>wJ1&U|9KEq40kZld#T)F89j8E`oI|T-p$iHiqt=hXKDA1d#>nI`I>ncLV zB*>M&eH_*YP?UEW2IkCdHP<6WB)OFB*DC=ZbGN#iWqIgrlg7TJTjiriGTGaf+pG(E>|ki z;Exn0FT5=6Vp*K9HguyUin4NY&5)M~ROJUs;el>$ZqCjtfbw;K$mf5rMjp*wnJWL9 zFC?MMDs4T@AD^k)3B<3(yl{xu*~~uEeBu~WQ*001(gK2ZBRxH|WPG`1ywn5vAR=UJY^?u1m~;PWe$Wl3g9m ztG$}M&zGVx)Gp47{ zLz*K{#;!R#Gl)7AKX{Opo8TP)=miL|Sp^2M@{H{nTsDGK5&~*D?4%Fx^(t6t4;VLR zWn^dx!Svyuf)so7G&o9KHQhbA@v=zW@9XHwZOJ^ogjtyf1G0QCFdX#uU1fYaiPZE% zswq!saX#0Ux4Zee4xein;jR|Oq+5o@7a;ZZ?4giUnhV1}Z z^lFG2)Y3%ahUa2$o`8n}WX_|S=6<~Z1P&T~u+r1aBX5^6GdJg0P`DS9pOb^`!ieZo zxNC9i7fU~=sH|KT*@vG1OzRE7)0F}D1+p(;bYMwH7axs%y|dpBMgB;}I z(7xRM@pcpH7jTQFJrMj$dm3R$GT*{F)O3 zn+8Uiul*4mYXeZpNgwlnFnlh*IJORzDJtW*(WbqkVFFDWd*Sw zxn!&!BUldO6~B&;`8khqmYHq=>mu6JOHPo}>B9AH#;6?z0|y;WrlcPaH>JzS>U0HQ6H-%Cn}~cdrbA2QCoJ3T zD+b_5YtBBxXH!cLg}zZjN-7wjFw0sCGy-oD5jY4`o;%AuFf}7l*A2(NcQDA}7k~2) zV6Cf6ocy-@*pkCEgY6-^Gq|z?^to z+TVYv8<)>n=4JcSF{t$)-seh%<7>%>bA+n;WK8L2dPF2Y_K?ma7}8Iw*AiS5)bx&^ zu4FVte~P8?&*LICFx|fO?(*u}GxI1=MNDJqTuU*d*p2b?qRv~;>*Rcn&B)9gbQHpi ze~(_QU%@#hWQFt4;ndLB*x1PE;Cy-97jeHurD0}xArctLgL<@ke-97q?uV9o00LSL zn+}|l)pksL4{+~7WzP_w9mDY+ANlaQYEe8VztVSJ^63l~*_ETB>kSi8y(Ct!*@&+- zgJB?({TX02V&nGpw$j$qVKWn|J*=>#doYy8Tc8z=DITlzho<^tot1_bSotfSBaren zQ33vBLLy5~S?LDsX(UV^iGS1AlP3NRAhKFEZOG9xFwj^6G*wg1e+mXp&~<=Yt)4HF z1?aApnGf!gT%RaQSheKvSc5V(b&6ad2wb>J$2doUD5u7y&2a)jPfeJgdwVY8ST{`I zP{0Y8@TWvEw3m(@>NZ;e_{h7MQIwb{XI^@-RMIw>OdG%KfLo%O4RN)##Kg;kJoP}_^9EGosGSjhf9>Xi*I%N`! zNh6Ipj(J!MLWhd)uuZSL^hPU-xRdpE9MjOmU8$KDWuAtyls_$uFCkCqxV-bKE)hXM zf7+kqUbqn0cWry#TB<{zbQR1sveTeR(no8oBk$-8^40O>)?e`n-VvgC31<{+u+?`C zp$j+6db{r-pR7*l$_}&Taxf;cHW~ek1w^luBzIHup01o?4`VqIOPeIP;ab}HBT`!J z{vT1_9f)QB{a?x+A$w+TvNzd6vbRKp>=DY!%9cH{Hz6x4BQtxK>=lyiY~pwBdOqLZ z^Y>HT*LA(eIj?mRIo#Zr4DiXz9}jL*O*9F$Ny*~4Z0g&#z7D!@w-1c z=%6nUDOF=8vkG}!`6Qa+DJvPZ-gL#1X&)_a;1#^lj;26G49jSDxg|2vC2Oz8k#s~P zTNNK-GN2p2bB`X~FH_u;2tAMiouGzJZ6X>au8u zcwTlF%|uab4B@w`$%u+rT+!Aw4vM%(6YGqxnzIYqTeha;EK6?y%AqY6cqcI56DZXK z=*cy{C;%QTJX)K>Lqnx#z8BE#c<|EF_OP9Vw}KIq_>sBd7WDcq8(&!d-hr{-^~si5 zFR0!zPzNnI5xPZF7d#Kupw3jI{Ya4X^-Y>kUrYd3kI02v>5K!f(2CUtTr*#J*9=@zbeQ5NL7ko`b0$%x(fc6tY%DZ#O&)|?=q!*b*q&UA8L8hT^jSiR@ zVK()}7@ob(he=YNsB79Meb7lFkzuBn0k|O05_h9aI}yeoz?oi=^AW>^EF&8JRCef2 zvLW>W;*+2YabPb!q|}^Ci096O;$_+q-j~?8 zxR?hJ6WWQ!1&=HvZdCIup-Kt4{1(9-jO(<-RoAv|yo|Q5+4EV*mAHwF97)2BL`o|D zl5bu|@rIU9UM-k(nHj#w%$m#^X*qNe^WAB}P^WgRb|maWBR0T?8}G7{<9NEF*|5O! zIASb)e2FCKPm@OzI;wO;M??OE*y)4CR~oOV2w!KfWTgo^{%jTuMsXdzJ0SwWP{JC) z8ELa>H;gsVaM#Il9&(Acp<#QgxwhoyFz8>v|Nqj`<(uWrt&=@^F`Q_ky zo@z7{*&_P+*9c26(mn{$Xzm?oCU~IJ_{jsC_PR77m~5Y6Kvk?k=ykIoNRyNO_gRNz z6g(i>Do>f@qcgFo*xW}Bc7M74-#`k=kPuS+l%3A8qK1LrH${mi3hKB>-rr3~uzN*c zF>m1#{6*Rz$bpMl_3k{7}Tc*_);T#Y(5Ze9|-TAN&O18b*Q+}#`b@#xF2UX6EPl|;`>j(#$ zP;2G!8i5p*Ywj!NSJL;?teQvHI%0KAx+3)|9$)9fo3)_GRZLLEC4f3Kio9&T79G9S zTX$Y!#A0#r;`Dd)HAf9R1^SQ2nBBMyjH+p9z4xjkUO5`iH4A2|jJ)CDg3z<7qSXiWo+VBWl(zQFI2fLy~5 zaS*D{9&rW1u=hOn(SCbE7aoE)$nwR~`~?hz!(~xBv9irp@Gv}Kym!_X8KC#dEckQa zNPI6#{ai>9JXi>_QlQE!B&{2Vd>EkwHY>|`r2e~#a_zjBYhzhq%FP2hKYXs6qdKGk zh%ZH|-txge3mhqkEVIt=%pTFS-WRmb)MT0#tQfzd9O~RBiH+2YrVku}3KM=9)|3b1h=hw-Wo9ASo9WG(IR!v32*E zk@LLuxVtXJl>?7~-}-#>IcR?oWU(vfsFcD(N^kx5@-%rl*8&=#@PWdnO-ORH6|iGI z+etOmsn+!~m{KqUOc__pNe=X9Laifzz&yKJ)cExA0y#-D+HX)Z2YKpcXj}`j#+LE! z48bGOHThr_W8~(SwUUOXx9H3rqTZvZ2k4Y?zT&K z_}=4xRcQ=vP%814Rt2NkdVss|c4VPkVj_5s|`mNfTEKz38m`3JX zyE%{Uo8sN9G4I8XPgvt!Vs>078{u+9cb9!fh!HIZNAVHt>Nn(qIPSPgsM|x&zZnNR zzdk|oyGDz=&2^I?-Vj>TECt0jB+gX|in()S!CeVJ#i23=SenGIe+IkxM$6gp4j02d zxTPQ&j|mM!{m0r`&TFk=4P^T$3Ss{m%;9&_@LqMwo@RxEhtO9-z7GLF@0m-S8u@yMR*sfK58$zI}{_nP1?RVi5byrMBs8JPba(TU^c$ zA~|4^DA%#bs22^U#n)_^U?2|e$-W{V5phtP5QPv$~rNTd2VWi zgzZ5EPlp-(c(DXiXa96KJ*=+|ZhPDc_sX=xK`Bs`xq*$0;b)zLYa*cVtP~4;WL&^$$3#Mv=h4 z>@NHDCCEPWPM)-%l$P+VG%ce?2X`)Rnk!9~NPMaco4CusAm@W^pm#%_Wk4Nk?Uz7b zg#iS_zXV@!->nvdiyk(wHa%^&cWae;4_T!rY{_qOtbrjP(fdEP!T^d{kSG;7k5rg<{nocrQ&-Pdx8fOO?makg%|F1QmS_Sag_YZG$nW}W zp;t#Vh@M`9XGHYRd7$NLrC;Y`hwH(Xx}(cJ9LqfS1G1?}rHZ!|S#NL!a5WKhEW7K9 zbv>6G1~NDv)A{yIVHc&78{wasR&L~OiAAFQUK~%6v+n4r?9v+;#lE@Lyl;n>+--H7 z5UKmepHZWS4-NyK0Ov6&BO?kQ+GmXn4tSXi<%aAZTO$0cp1VYjl;z0N^kZkoXVTEn zY>aha%eD1cq9*N9^in#aBYr17U%xT-nx@rJ(5~svUvG@{N2%i<#uHprtrQXjMM}H! zZrVDile31_ELyxm@CFvx(`T&O?;b}?|Cn#Rj@>CwQ|X0QEe~5EB*@Bpz+sh2!eOsT)(0AoIABXsG- zFoWJV9~tb-sUUuvS<;s;U+P(%l2o3T>yv#BSJ1K%3cFf}ST?b)H2cx0wbYpYizKN^ zo$R-0nwNT)adK=<+Nq@uT2fJT7-~|H5elNQht}lnEjvW51rN)KV9kCfa^!AP7`yg; z+s79tpYM$&V4(Pg`B-8L_G!}mru)(-vtYUUuqW%?N%mQRi%!21ue?0=Y`Hd0QNnpSTDLgQbfb53?qXhr zYP4DeiYR34boTgiK5^|R1OkBt^{s&2N8c--Q(^SKzfQU@CL$sN7A?%klqINZ#pFEK z5TSoGQOED_k_N3`DcB$x7l-A&YteXajF?eA?F$cvLOuPI_<;BGQhour8aQ9dO+Ep4 z511k0zuy`UGm%QICvslQojng9ZgjNSvJ5ySZCP_KA_}bMIN?(h`EupzqP}cRY~Nh} z<(r)K@D6hZg?E03Xb|#yv7b4JUx{$;S3n(mn@JVzzn>WjSNGObW1-!7?MvdXW(qM* z4tzh`>~bCxyl)suV!~=7Ek^%5(QH^=iupglTrnjsK0a{Us*XyWOyC)oRBQX&Xk`Ku$i!&s7${E}GhOMwYzj3KeYtK| zX?pN5{#ud+g~zDJm%o~U*;lQIY%@52Puhbp|KZosJS%`=A++7x`R;oE!vZ{>|9C&w z*vreQJ4%#9w2Iob$%!km46i^xD1jt^s^me@(kWPb$QZuSc; z2#j__^d>ALcn$f(kPXq~-F@UnDZ;$*8jn*UQ>|vJEt}f&ETnUa54*1VV5&Ri9qkSt zGLFVxR;$yg)4}@a0)UBt0m8v*2X6qHIFLNIx3~ZIcV6D%<>iIzT|(kABv=GSnD0!s znC8k8H8)ZioNzX_7#%VC6a2PT4sl}fRT8Ex^l-&VMF%R1m5M-!Q}>Pw1yCQL`2&Kx zx2I=O!5p!Lq(eTTp(d~)hGe>>Ph*n_sO4cBCVnj0^%dZ_@ZZUv{H=zRFVkizVm$9d zA!p7lVrf;FM#7Ycgj(#O21gREG^cW(ZBEUN&BN(3hQ8<43NoqsZg;a-#N=b?9!4?8 zrChwbzbTNoU7{i^+JfQ8J=>;4DcJBw@H^UH=i0OAzaF;u$Vzj#o$Q(u zAO0?CSez+W);#7yM(laShP;XKMTq@n?q?cx8;bU~153t+r2}gt@o6^#cQ~d|(c4Kr+x{tj%=oM3o2l)XT@|J7|JDZ@&Go?a(|I{9tH_S~ z6+?VD*~u+O7ut6sW%Me>o<9pm&i&F@zcsxPjq$L4aGWu|_nb4B zC-^L)IJ5nRu6pme(ThcM0R{Ao#$|F9y^#L?B;G2y-cjjZM6yuiJv*$Ei_tb?#~5sL%5#j52sK2F!$dJD8L)8>w<_YRdaisKkwa6$<=m=S(~> zBN#0lVK<6Dz0u`dXz(FN!a;paEx7pk;#P^{XqYzLc-a%2^NiVSgAdC!YVE^3!6pTo zgqgG1aVoj-sjQSJ8S$ag0`C$H#hE(a%`Y8!tGoMz?a#NBm1G zE^0XGmKGfuRS@P>SU)0}nO)lxN{L@G_Ya~Q{cPvSi}q7_U71KeyCGZ$m1HJIx;ts) z_{motuJ=x8hX(kO%#S^u9Gc@WxT>p>&Hv;aV^^YeA^7|RH)>`?syBQ{)XpbQv6}g4 zrSF-VhxxK{s+Y_|d6Ag=rv$){2aeoQ=0)8RP#8Yd!b20k4b!3$dr$Plj~0<-mMI@n@K#uy`?*%9glgw+nZSR2qogZ>IyTRKDuA&urFi~Ofm zsqMuK(oKGxKU{gtNm$;5SGc7Dcqro-MsM%(`KVan1bBGOY@9v+%==sV3H5n>B{1dN ziJ8*;L=MLVB)t?81%dV6Vomd1ly`W7)k%*%;x zOL8VL>%IFvCiN}+?)=FFyWJT#C<-aF%^nR<~=Owo<>Ta(>V;q0R#%Za2uPAh4CW=2yeP1h9R@iI7%jKLH zXvoD|K&B9rnDtBDBw{3v+Dos(-ZWaII)p&^%S+j?PPHL|d8t9kUph4g)fL+h_p}|u zv91X9&sfzzs|1eCr?+Q$$=JDYx|zQ&6)CNw}`# z;$%6&>Ot-n3djUhFpxYv8)m9`0D%NidyMt~kX-_r1d=h8c${j8HwU6YEGjJQBdF96 zqqUV1SpU_l8cs!%WC}meag)M7tK$Zt8VWYIZW0_-Sd_4B1Pry1NGLBn@i#~_%R0*O z?PaH`>l)LM%S#Y0l_kLC2`1+3FR|8ogn{i`7kM8QdE-^TY66=^Bl`d;OH}huT!s+E zczjlGSzR5?-NM#Ns6Sz`17VK-=A+*ykhf`G_VGf5;tfgmVop zOhbw$j)@5g$e+fP6%`f1a{?PbABX6L`WT%SuacuR#Gpeiw=TtZdi-n0Mk{|yVGVrN zb!kG=!QJuSjJ7UaHWbpTZ!7e1IThUM4&~UM9k$t-c;njF%~TB*d#LwQ5S6Lb#f60R zvJlZ>OfpSLwPO&3D+jy9^IL5DJ)doNjEr_-X9(}faMb*07R;=e$}=bzDJe)AbVx-- zh0}2vjk<)#4~m^Et3|y_WXBsxwG!`;Q|R<+38Ixtp0E@}*IKvWp?@{tF!1s=Y~($;qzoWm%K9Vgz!A>C>L9 zALhLkw01MgLgHBs!c4SS&`d%{%aOW)Wqmv*L!dUq94^Y&?I;WgyJ;LqGrXZv2PEzc z%$_(@VradKK>vL{MI^N?Bk=|0<>i6Evd-q)Hf)*Up`i@17yB@(2f!s5ff5D@e-dDD z8sUm=0toRIg%IvMjsLwl1pH+1!Roqc4up;EhQ}c$NPr7~=APJo51nHhCOjfytp~QRbF7y;z)(YKGWp=k15G^76FUASek;Mv6gJUo?jv+6fmA?=SQq z9io}mdy_Cpx!@_OHH9ke#}D`O?M!$cI|G2?=(KQT`VmNWwIXF1P#l=NLL9HF71;BEFJ$+qnn-^e&WrhQJMzyQwhtcd3UOU%M(dcOC%q(Bv@v|@VIMc= zVNS-;N6|%i-F->qT8XGd(Jd&k?Aktto8eE;Rx!I+(Q1Uv6mY5uJ!!8Z)|Mr@JLDfk zrWY;1q!j#B&qxWmuB9WKQ-XFZ(5T8zlVZS*rIL;V-o_p5d+lKFAB5|6g;bFoS7>FM zyq;dn#HY)z3|pv_?uQj*OVonhYvVVrQI_Z()3&xYpf`U2rMtRy3^#HB-*1rizYY#Y zcnAR+oGqNmf%?*tySRR#p5K!JW2N~#5yjyG#Ew3ce7;6!wK z3OYp47$|y%ii)l6COGdvEiwnt zwsOi;HVqRK69>lwpEG)HZgoz{>(OGkm#|yoVq^IlpMG#y@PQKqOz&_ne1_7d&UR|7 z%0gN88Q&pX2$aRe#muN^w2W*fe@oyHjv^<$107DX;0kljXNMRy-OGNB-Y0l3B+#uvTO>6C&lr@SQ-%#EaQhGm0R`f`)E)$ytR+A~Ai(kxR>vdHts1Bv06O=9BsvJn zCl9<;k9V01lh(jol_}^z3#B6Po8AfBR)GhklrPvm{n zv|`iheq-^%VG4PZGblJ=-FZi5bUE#RWV3DZ z3iDTgtm?iu5*A@4lPBUs#=G0f+~FaBpOTn{Pe7q1%!8y9T*o^oPyW`xlEQ0`r?%9! zKI~#rTf}yjeFsBL2@kzFguT;({JBRLV^nW>+F26Ft+CvrD4MYecq>y z*GMZj#KihA@PsMpL`2A#)B|7xPJ=KAlF*hlq@|Ja5+S4t5u*F{UbJEZW$~JD{BO~m zoE%rCS5`SkDXJH81pe`_e*YN$R;;P;w^AnP_Sab4-)l^Btfvlk{P3fQPO}SUKc4+~ z5Ktvf2S1wqbdrKWUlugDkcXJG&8sS_-!-Cajv3mKmcZTBQiH15jE%8x%D2;8j6*HN4P zi&(LUQ>d(tVC5tdt1@NR4-V+MlnczAXB;eUb(c9XrVg#$osyN#L`q$7dmTt1Ys_jdJe-7{b+cpE)5L#hw7C!nsgbLGNZAwN%L&I6x%+-ip zzVr~Y$x%{$wXUKTCtr_5`i%8*W+rIp**p9i6*v6C(tKxvnCfOZN|v$~h&bkg^{7OnXZaTJKS^G$HMXYt`j8)ed>#?=yKMBg(uZ}v3bagzHjoOWycalS+ zxFaYi$j?uRD$n*n5!oLgVmO&g7i+8V^2+)xq*Im5}q4XCq6S}`-@z9CF@Y7Ye?!H<|%)1Q?!N)#}B@R2YML< zb{p2Bl=g-`7_`o!6|Q3ailsYu)@?-90^~@8Bo5qm_%IZA*ecq;K_<^jGjS>gyXpI+ z6C0`1DKAS@!<{g*=UPU?2Gqr9I|!NW$3yrYRaIBHR8_H!^br_m4W)^?7NqX zRxTa!f0w&m{D(ss17oUPo*b;2@o_(`t&_SL1A62P4BpBws*T*fGhmMMvt3)rr8j$Q ziIX5lsh%)+I7IfovmU~oJ#rLKEXf${8z#CMjpuCQBm8z!c>?X}bkhqB#o%0D!SWnv~=1tOczix-p` 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 R#`yh4{pO(Ut!2 z^4b8>^B3KXJW4Z6EGPt@E14yDd=eZ3xgurIVFC+FHFC71I8?NuV3(v?#a|gXl#m{4 z>Gw+lK{RIH=F2EY#y}T2doYrENKaa&kjVBB9Hjg-BO7m)-Uy!Wql9p&hb~Y>OPjt4 zXr)1Yzb-seBqDSre#-c(h)tu?L_ScEC!6f4a5)M+X72*7W7a1+)Iw0BK9vcxF|B80 zh={65L}5|24)yC4#y7w8K(Sqdi& zIZDmnYhC;d{W}|;MEdfqa~C6V@a+SI^R-k^!QGZ{KlJ1DX4S6O%vb`S!Sh^?wLBlR zk{VkGk)-zM{jinPRf>gsr&d%K>J{FOj%(2;%}#ekHH7sLPC14!8N>G^O6W_TBvj04 zjTd@C1>7H5PpNTNn~`?JR@b13eIH97!7{@AzLrl4;N-CnDZ$thy%lYIIeSE$Y`=PM z<^}{6d0!kmeZSBi<`^ef62wSgD)oXZ#rmO$!>f$hB9rgx^1q`dKJE9 zTD3eo1jL=^1E#H*|F$$g;KktZcP|tnD|IWPe&OC6rN#SprG8jW4VVC&?v(j81vr*d{AEOm%cyW$Rmc~81l!8W|!7k?Kv zZ$kia)m;?`P_AB#)IRIxUj)pX+5RifHZq?+`ja&i{PXXNpJ#)0PkI;sM;U+1K1O%!O0^yh^)YU&3&5O2nMPNB(4 z^h@TQ=1rbV*vVFGFeWC;{ zu>$E_PVc~ULT?JY3PDd+zeDKae)}pyF+*sY#4X zt1tV;vhv0y@LhzPLZ@UxI(P+>bH5VyEKi;jiIobbfKQhqh<)RwH|LY{?0ZC#iTXB% zrP*BBH@p-lt$L+2pW^h?aV(v!aVrD@C5*d5*!gDu-g-7hH)pYw+^rW=wHF;ggUtSK!03GS8;}I= zF<-Saw_F_!(mr@}RmXfO@_Wqk#r3YuU!^4Zi!D6)gRpNc|2Cr-`;O>3Jq=fpXa_gG zsuXT+8nhB#Z0i5`kpwMWCpUQzfRIMhCi$0#e0K}%( z72>U@M)KAzQJ7BMtV-7k%jL&TkHj>Lor!D+E-Fn(pqdNZ9ra}76Ou%B?EAVEZuROz z80M#aEeSXyB6tQbFKFCzy0uE*uGiqv!-o;r*qX9o-U7H%`nfVw?q5X264ig6^*~w= zA|G5$yu2^~#AnlYzPZ%bFV9GCZE5|E*820$GxMeW_r3#iw`1;?N8Fx)gO)e53YSmw zyjuY09KFgDxu(81E-T+oc#(jG1W z3)M88Y)2_C(}fagM?CptQ-DXKZ4cAtb3 z>9jxXHW4bWPN6YD-lyW5_J!UFOv$-^@yLaNbV_}p9~}uO66}lzNc*j7lR65YL}8L? zJvA{k^;|6q)-J{l@l;e_rwnbEKujIofPy}Yx7)8*Ka^;nS4jWTM~Wp@D%8~DY2b;< zUyLQm1HCdgmC;N$yF(x;4<;d)VkXJ z#E}2W4M?t;RsSd_KE<9gnV+N|sV|!idSWvMTEBk+eH<+*s$$Qc>OIaP3cfxFwnmSg z$Pc5G-B&tjM;*D;(6-886&uFUA&Ia0Dr+43&K{Mq)$mmY2ZDFikC)kAr}GKsT)$t` z<7Gr-Yn-(|O~-w(l2}^tzg)ny`HMnXHhoNnSMBIlE9w*BEUKqa!i?e}DaoIm4iAV| z@5PjHC1!-z%IPXaB`xI7p&S`ahu`2a-gl7$e02)vsS4+{H&bmFM{nDRvxk))E<6J) z)t*4F%P%H=F~nLQa^}k~#Nrt9^%(Pu-+x1X1Lm)g{E+`r9zTqR*;`*|K=|NKJ_s#r zr460_W|Bq!5RLXQ49O6P+!!29P~-Gt3w-Q5)h7a+SWV5$3tIQixpJH)a93=;e^JAi z3PyTljH=^khkH*)-B1Z8kY~!*6DglO)tB0^)YO0Ln9%9fhb;k!bBvsTR{L#U7?K#?t_D z*JE_&n+CccA_9YeE}}afkzcQN!g*|$e)1qw4O(+LB`WWV^?Zckk1ie zH6xr!mGm=*Fh_4UZkIiUw0oL`9^tCX@=594lM~pfu!qTOM5bT4*VtaFhv{TPm_q%pb+1L1`Y%3;mc*(kYykVa49Yfp;eV z_Rq_k`Azx1DhkIc3I|vU_x^=QQx$um9+flBCk+m0+X?+~(2hioEzj1tK?;vrpB?YE zy4+F(^>$Rt&paw@H8oi$OzVQj%!KeyP{R!IxG)bYPPa$=T}eG&gpJ7bd;Pr@f5v*A zWwB=4r;n3YP32rua1cpkW!A}PAS@)F6X{rg|HM0gl^c%@Z7ff<4E0MM@MIkzzmej^ z5GcWVV&g!myXnBA6}=1d_Y2NskN58QIZJG^d|zqL9%Szd4(u6w$w}px^(x8wHTsbH zdhTh0Bjbw}iq)^irv7qgOX0%z5^+x2Zf0&ThMvm*d7^OoWZ{01&D9F+?OD?8*}IUP zcR<65(htyU0UBFT-%0UT+b<|S zJ{wx>qQ@matiyf~M}FaC8?m4cvG+cK$qgH-f(uH)aX~SEV&Nu)dm zF$KQVuIa|PNZqhR<^U2#T2=$2fd9wTTQEcwt>MBTDcvG)jlkC7{5!J?EbL-G4B9_Fii}>#0|Eul9P)3q2Fmb&B+?T;$IKl>N*iC*}>;`=4_3(Ah<8N8d_mB5EZ2eivK$|Lxr!!wT*E)!scyqG%S z=*h63tS`2Spruk=TBM3MA{i2&m+xUs8i#TsoY{f;CD?eHoNOrsSlTr>bnWM}B5wLi zr(8FNhG$h80U*c7c#qRS`d{duhvrK%3L&Y3X^q3^_T0+O(#D$j44@naR)j7Jlou0W zMlCEdSxnxQEKB|7gN(U$n(d5Dm^#}UNjs(myg`bg=lQI1L(Qv4)GY%(R7)G*%KX4w zQ7S=^AHVLHuIJ86_B`L1J$q~Nn?C+DC=~Jj2^ftepLQgl@_*dt&p=(OCIMY@^>e$c z?$!smiKfyiUa7FT-61N&4xz>y^5pjzs8xPi52_?+Q7hEWbjgGGvKBw(kJ60P*Uej@ zIVieF%ijYP5VIjIs6N^RRkm?^)b8-eyj922LEdRB!zb9Jd7~H$nE;pHBX%g>rXQJUj89S=1FH0jAZGt71h*`M~ zLpyuMy8XLiEH|UZU>-r-_TG;aJLOS59NvoY0}mlKX64Wb@s~m(`NCd9rHM#@#xL$q zlvB_6kBw~+=hPtiFsXoIk$rzY!$8z|m6YhT&S6v~42=N8EO=5T>`4I{lp>7{?$MeW zU=lVc6tucyW|2p?!BU#oIX*Ig|Edk61-~O_cIQX?t8^sw1bX<#FZh;$o==P~iFN{^nERZ7gBS+sobOA`B3 z-H`|#RAF45u)I{_K*`|k3@d`;LoSlVEC$Y6_PZk&k}~VjO)|NMxUscA>;3;nTD z<9Y1G*erUxWR-FdHT%-ve1A0+Y}3YPqD@|MQKi#>Xve7pjG|Q;1Q;)Qa9tK!YX_aG z&AW-KEIjopT{be=swZC@yb9gLZ5FfDDQT@&Jub$l#yXC@;{mcnF;wxQ9LE6>9G+vrS2G&=-$gJ z$}YVp&-`G@L~x5;YTDk$Ly%97NF4m(~1$}s-3Cg5N8nsaL z_&=%e_L>o~D#0WgYPMATik51=8leeTBR;WW72$>9aZz2k1++;7}!Mg*TDxgyyxl+hM*)c#{#CB`YLf;r!)%xs{RaKS-)& zqHDR%(TNbkcBpVNM0uOZdx)xi?XH)gb>Kt`PuX{U4@DaN5jI7c>H$y@)c5R%(LrW& zhs;PDc=Zi7N2nj@c4gky>wNT{9ZG-YGEW39-0MJ{kO4i26YV>Ra9rOaSN(O-WP4E- z)h>Trc>U;ik@ee6=4qMZuy@3cf(wvxv$@Pm!9Yl)d;_{ zG)#pBb=VGl+vD~0iIB&5HU(O+26Q^Jp{zvkNgOk=ru(eu;7B3Duw_=zFvg3c3AnR<-+qLY~W~l6< z2o#AN&f`xkn+CO=!QM2x??B&}>HID;CGp`3)dDqzd@sE740ZVkwaQE@9LjYkEr+t|wtYh8ac%$OmHMI7_UQ<<9T~3SUP9BE4b6b+L&nO8DT8Ob^Lt_BEOFA=T zK8C-V4s8x1O%BP?)ZV^GuuLrO4+iJ|AAj@zifq>7)BzX*QPlO09RbdVnYdny@Z#W`ehbsSQs z8GAUsrtVmOWeDj$#n6sC87tSEk&Gi-oGe#uTyp(~it!hN=B?CI;f$1@_PC)2g*I46 zp#tgVI7jO2#mXb}GoG1X_0V20$Dq^)VxhhlLk4VbD_TyCRu8#%F zK^&`DB{NT${iyiYp=0xRclcyHL60fJ*<5v7h>RS}}2y4l`|t@n-7>7X?IL zes0W3er;VUW(l(>Hp&bYSPXsPL17KNH&V7cG+6^~UBy-CcUS<$C)=E@P6-!@K zoFUi3&a7$If7s}_tjc2a&?CO64wb0i%tvoC5UPE}w-kElzF^-vRHGSW0=JwKWDB4? zv7Aep#L>+$a@kLV=@`(R1LxDks1Gr`Lg z(3(%g&`+=pV`)oujZ{9DR=Z7J{iZVoVxT8wgyN;fiZObG!#?lEDkDO7nlj$h`G&mS z7)AIv#`tWUkg!vKGLZ#>Z3^@Ycmh8fv3FFrNo`0&L@mcV+LH6aNOo)Q!wg!O2SS9f zXASo-eoE|qsIY|Wo*!6zUkdAt78(}b%GqC%A+hcKA1P`7E8yi{ zrC{=?4ON@lNJK%l1g(vgf%DRA*LIiL#7S#Y(1tr#;osh61{v~{ zt<#q;G@)8QSx4d`cDb)$;X<$Bv+4@m`G_C1<3Tuf25W-wu%kHR{KVxk`$L3Uh53Zs zR_V!P;aut#e#Za}{qkR2&hyIpx>5bYE}{V^ejscoYdX1iX`_p-`uwAy!@%DuCifdW z=ATqW#_~T{Eo%L}vpozq4RaSwq*lecvRK7}1y#K#eN_Mul5+|>w!%whA&+6em4s4c z_c_|nSo9GfVqBa~(1-$LMCBkPr*)XP)9n!^@{o!nP}bm1fYm&U_}g!Y$J-WOi;n4> zY&y_1zt8Yy;& z6jXn)wCZd+xfV1a7Em^7xWy6MXh+}3n?X9^iDbY0V(F05sMdVX0X$_wyPCyTZ<Ddys~Z?FEe1Z zFI}>R^}5KpD_Pv_SaDO?n(-wfG7_MA+T7Tbb*fsHUsuVv{g$~eWlnrcX((cc2<0O`vbj1ZutCFGh zw6sLqfbkAQ3|qEiw^I}PB@<&Rx*C8qlehcUOtCER_PfAWeNmWC{eTuFRvEgH(yjde za4Y!o8z$vyR?)(|-nyPnHVrV(D!#4gcI)drR}Qlzlfp2LOf>*su&G(mA#IS!yi`1v z>QeoHJLhBsr_IYokC!c~0EHXDt(4A3J?1SO0f!j5FH5u^MSpgL*f1@pqMORMBJ8bY zsIu(=GXc)Lkl%s~mx*&N2&V~_!DMWSjH$Hags=EVZ_umy)1_K-r#)tdelV`wpQD&6 zu8Q2JZ?4?s-KKtX6Rl+(pu{<U=hgb*f#un|7mWduNr?u-Zowlkc$hLd3?F zNpW5;ce{!Vn7XtYcI{58u7-gEu61wW6jmW|ij;J$t@WZ7YDyD`9>uo)jyG}x3c{0X zCA+7il-8otYO`%&2tT`H%AIn4nP72m=;Lni3i*Qse;RacsVNlySwi*As@&G zR*xWnu$)D)0oWbX=wb%O4a%=MA`@-PL9)mb^yvJuN!lX?eAHb@ucaX+=^0S^L7tU6 zvX^JtKawjzdXp@Ns9UBcEvb7hgqGzXmTrC?iNk(3{_a>zo!Uq-q4Bcdsw4zMZcNBK z#x4Lm>#f9cs0tEa2}p^gAcMZ-ioDe|v0C6CixFXs$r*-0o98}BLe}xqu&NWYc_t>t>-a;h{KGi zfyt?W# zm*=`cD&`ul0yXx*cJIhMq^(HJ83aW<(1Ob0(4DUjA_C zJXO1iS!oWN18{~tgDd2UD>J>N0!4Vnn-a7n<#t;_6~>0&^+Nyqi`>nu};`g z?E9?u(!`N4sKD`u@Ttbxj}-7Yf7H{C$rVh^e6^a+w#U~x zSI$C7LkK&BG@XVMB|nLK$xW=1b)&s(=Ri)ghb`9#QV-!t&U?i28{#0+Os*pQbbe)G zc!@XS_+sK_FAr~`f?jz0>h)6aDt`j>#jrak=BySX?6Cw|kw_xot%s>8lF1}(ZQE~? z88}^QuURt6B(tqG0*dh|-)lg2LVJ$K%CF86zNB$Re^ zKRPBw-6y08=?2G9LRS4g4);~CwB+lb+aIUOJjc*-kZqX^fsBj;{a;*6W*l)Ln5>M;UlWT$YcGa5{WhnKS4!_;cu z7*?#TWk85^=IQxV@k`B0)l=IP05$KD@mi0#ZbTpzfAzB~a)2>MAaeeUxvsSS$Z;|I z@>~=_77BM6Qu7S=z@V;%B|9|wo{5hq#+D5YNOFYc3-c<(I==TwhpG}xNK;jJFxFUu zw;B-l-DUEuljh!H2mxP7HoHN6=N_lq{bF19&5!3lAR^aQs;qq!}C$$lzO0!L@%Bc`cXj37VA)q#5JuZ{}8oi zp~PcTQqb}A^WSMeH6>Ah0En44I;EgSB&clG59wQ?*DJ9Lte2We9ha_=au71+5sqqv zJvVPC5--U-h#<-`Vu*}j%Ji3bhDYytk_lQs)9e%t`n2u}eaXJ?Oqyfwm8PLb@+*%%1kz{_eZ&OFt>%O2GZVae+F(-Zocu zCLN6iJ_|YvAcS9}Bn1vU1GeaYVCHi%kQ+ohjQ*CmW~^UU5cdP%4X_mRuk!*QP6tvL zTBl{sR4Cf!<1!f4l&aVCTRy%VV|jLIK@dCx7zw@&_Y3nkst^RW3bIBoiezzp_f1-5 z@5cbnW7p4Rs0%O)A%&f>?NL&6;pFMv2OWzdax;a-B9W}f1@sg-e8<>SW;z#ajKbGt8 zW(Gr8QSFe1J|P|lyIBJ#3Rko>Uo`C*l@xrXglIRyhe17y8@(4D4v$5eJ%q z+k|%01wj_2f6l%>14fI#bw3{JFiE-YihzvneFV@taIrJ|e2)8k{_6SiRme7Ta9_;R zt=sc$Zv@(OzUTpc;3g9Fd5Br}*D0;K|8W6<_e&vO$isqYnov_!S5>a69%21a_atM7*AI46}~LZR13v46L! zZ>=MbH#z!m6r*X&@X3lK(eE*6KL>eUgd z!@%QE{pKOv2sA>OD0^XO7R^dgSwugJFFT+_$VN7&opz!^Iheg+t%O^bKf0LEHiS~# zajL~VOO`Rtq4SeUwp{`l;fA@6*=EPmkH2r``X+ZZs)UGY2_TjI`*L<9*k`49GuF8B zAb(H9(AD{KL?gno&IDLwHF=Mr2UC3ujl8Q8q1kIiS^_DxUtzVmB8n7mZ<3^@cM!5x zX|gMSqt?5zP!g~HaQWTiWLX&UbPtqKonpKB%Kp9qsvy4pIsNiH37A`+GJ)l7_0R3~ zeDd|NP4f9lGGu$;WfGs*@ttVM!I_EAhIhzAWyr$>-?VT4Kikvw#bXT6<}#c6{7(S? z8*}z_dKN9t<(hcWCfK09wTp-*9D&3WGz!jqYMz$BOn0T0QyBTT=^7hk7_2YClfDEz zDBQE+2mlQtkT)Kus8i_qmc)ms8G06{sA)u~9HAdRie%l3g?k?kE#%^a{Oo+C0_hRH z{Z_1DIMgdH**uq6e>M(z1Mtt#!zX?$H)yUeY!-2?_uH;}J@}b^>Fc&;dO_*)f;9qz+2Fj3NT?N6@|Wx8 zW?%Om=K=;o-t6-^T@69Px#dX z@Kr5!-?mEr?U(#(_B0-H|Mx)h%wiZ=3}zSc24G>&fh$;B*NMx&l9uPaZwgo|oNg~8rnI5`Wo<44QNcfT3ok=uV*w(h<$d|dcOr-qf@ho~;v$cO_{D<0D9 zV@*>+cnCC2p}R5mZA!r=)8(IpHew%HRFHvfI_+%d7OXmtT_Zb;V&f6Jdjpl_p$=P4 zwRYbOt?=_pTDzeqyoe>VkHCz##Q#yQ{Hn$7aapmPij3UB&d$bFg?-gj4=aci-}P*< z@wZ;5rLwv~)N0w7wtX3tcrtfp<+`!-3-w{G2q8oy9Ed{ETV6La8xgS%krfZ&%h|Y3 zU}1toNv-vn4PHQU`#a=8y%O3yvMD0TJe`UpG^gqvZ~u@GztZFnK1U0g2|4$rTR*w% z2}9bLi_0|iKLYMgK-rqr?=R1R8{SKRlk0m(@WwCGgOK0&Pm4bu-aP#RHW6{ci_V=% zx8SSH?(6ci$M0v1q-MvQ-d=Q<$|NzSe^&pYhz7su0C>YrjCMnrDS0mQVENfrl%o6w z;Kov^JbS1=oBI!RFJZg$*R6EnNud;#8J|rQJKA1PD7S1xw!3$%Rw^t?VU$3ZQfO!@l!+Y^fCmiCoHIJW|xqBUI7cmbRFX#Uf8aQ z%A5BYURs4Gb*=g*pUY>dXem+Csyi0g=qTZLFb_Sj`kN!9wyAO@WH!p)nH(GGI0c;K zr3kH;UMg}mCQ>KD{0LNe-6(BI8(-uGb>ng&+u!%L@P}5K?ZgKUy9y6cr0XLslQS%JN8k9584(Jl2O49gFp zbq6)`>DA-hs~~HjK_!TPMZaY&Bpn&N4x{>~(>PVzk}&Ei344+ZHDJQBNK!t_U9|JA za(m9Ec;%bSBGcr_*5m4Q+>N}js;{q{o~zMs}Ui!F-+JS-@G`7oN- zNt+69uA0c?mYeE_hira{Vpkr2Tc3Wyq2N37Z|!6jZ2~;%m?Jhzi3;{#w-$tds;QH4 zbqfm2O{}R{_KhV<@&4)ePkOVaZHybQl4V3k+v;heZvC*>gm$~Rc^wVu{FmdWvM>Qm zt#jq7A=io_(CvY^vpd+Ckl!URk7KlOy=|6IQ*74dOb)v z2YDcDSA03UP1t#lE0)ZSqbdG3Y5l2GqI#FI-sB-;(y#oQ7*=|Y#Z|_IJ>yE77&QDOHY0`86OguV)&KNJQ4>8#SF)gY)If1N<)h}e z`eP)|!*Bt_^R!?1xKijhv^6_~ge$fg^8EPY`4K?r&AE!_|6nLkMD;WiBLV$a6b4wY zpD!ezhJSaR1vS2c0zFkgy#ti*H9^-?WytFDiO0|uup4Ih{0Q=Gw%?1IT+@danH1mw zooZ^?Pf1UQN&e2)s$Z{F{~c5SY_Lrd{=4+=tomw4Z}Sh6s*9X(!SPkZ-@#CgOlBTD zKS8jbGKq)i4pFnER3Pm|1M!ov#!H?u(2;NM1+g1PP6^KK4Ug=Evo|U_I&Gp7T9l;d z<`n<1!Ayl5^eg3Pdi0|}N<70Hc6}!UpeCXKc=hy}uGwJEArLVcTedw+TFa!=$9|up zD}S}`S|Z&^{)5GH-|FSuabnxYsBh_H%yNd>l8b50U${)%YHB_p8eacMhpeU&>u(?J z?IN^q4yM&^qF?Qkto6J|dt+fHb^OeHmYPNFg+(<`(uM^X(+nJPTEZ6z%?vZ-^PE zDLw7ZCY?{)84XnTFF+FaQ7r*$+oBmQ27HnYToVtAW1dDO@0o+uaQ?_tYUE$0$Gmyi z0#2W+y6K?P87H%~E}B~=$KTk?Gci{O)6|l|CTUN=m%g=?5<}4~QMgf+3kVnl!alM} zUyc8NmN8EEZKi8L7mx03LWc^|@<%nS@8P33M~(IE5;n|7sFFfpMdu|c`oGa{9p8GIFDC|>TevjT z)n%mhyKm4TYZX5?TcI%M`g zGkUPUv}R#$b+IJQnI9MrMgUX1ZFk>l3;EOL20yC!`uzJ@;+V7xFm(fTB&f}(Zc+7B z*RJ#sz*T+D3vT_Vxv|+lBf!X^vJNNCI5D#{`xjB9UQ&BSQ)~tl#`B@FWa~^Rm{24Z z+&?ha$V?1*NNB&9oE#mCvS!|5Z=_8e9yM)=w>LC`SeH{rn0?Un(lBe0hmjlCUvH3}BNeZmqrU(FbXH*@C-az$9T zW8{xVFhBa(HW6ehod>Pz75jJXkp2XcVAwOSdR~tZ@>EpcE?Zn4AfCeQC>S|fkf{h+5?|p_K!~e((Oxjn6(PINdU!q<0?yEoe zi4|3XSf-GrzDpCS%0tQ&W4V54Sl$6VdJE{nrqF}}aQBy=h(|Tc7J;N}xxD0Nupw1R zVFNE`S3lGTljDDqfp@V?e`#)dQy43Lt&fF9?;Iv z_pN9m$vSg-%bRW7RyK9XfviB*y>5KNwtqp9LSI&J9N?v9G);inKVMWNcMNn1^0n~s zH{d0c_^{o6R60DiNQc~O50Ir@5N@VAS)&dIe=Aqb1nB3W>%&>NPr6BW;5|@|+P3bA z`MV~kb-qD2w|90yPis(%+8i>u*?187b!){_n9ns_KW3{1?%4`45=+19(btLUy;R+ zLI;I*h$_W9N9_rnzk7QgFZ1By!@$CpHh2XR|MC#uO^R^;qtPs+JJ7{5(o zfBIw_j^*@e4VjuSG3s!{&JWaN?DD+=S$hKKB(tqg$oTmE1m`F|G9lJ9g!BRPz#TE4 z4;u7MgvI3fanrO9yrciYA4AQ=0#oPsY=ex{2L0!wvu7?{LhSo8J{_A(JZiek6Je2j zbJ^QZCQ0nhRp^hwCCR&H39|Bsc0XHE4hoilp6AL<= z@ZtV<)vS=#r)&U7ZmnA+tZEnazsCgFTzK;`KQZMYcNcc{VDZ8D$7m?M3P-jAAZA_k zq>gBi(Kb#}8|;;uP0;JjVm}?L9iomW=(O>Frui8bFBqiA>^jz6%-%FE$f=w+knVqwDO&J|TFX#Jw*{uA1^U<5B7G*XK(oml3Q zlE^kZ3=3$ba;R`D0g6MUu=2;+9w8d>YMr4J`PjQCCRmTqDnUk237~2Dp>9d~qS8)h zwFll`-d`O&qRp?zx6VVVIkg=e*{bSe+R{|@7NtQ|UZ(trtmDoh9=?}IwMP#G(cyt9 z(WdzLQ!wf_1xRS!eOYN~R=cSdjNpG<0OCfGxJp(L^ZS{^-53$LwEwu1Kn?qYeZ`>l zRBCk%B8HU{vmOe5a!%%snvpaUSChRBR@^Kq-T|34#b25sheqWEgqAt5cDzzK5= z71A+!AVa5DeCfV?h?W9kyAfD-F4vsHJD>60N{7Y@0~& zql1VAsyS;*ujp!|kOTu&^7$Ro+yo7&kpd`af*tliK8lREd(hf(ofvqrPFVgmw^sCL zK|?ucDXN^aJ1sV>Izc{(Sm3pHy#`IunBylFEs|YI?Kask4k6(e$=S6-V4w;JKf6|r zZU-SJLn_Qe%@$=y8a~BNpP-wEq;Czzc0ZQAxAK4b>-XHojI(oH01^}d@E<_Znini; ze69NLqpF7XpDxU7!M-kV<9BBYU>#NCAwS%d6tiyGMIrShQX4Jy%qHTYao<__!F#32 z?qA}Hn@&DRt}K={9ZdEVh)}+Zb)_Md6CL~ftW??vjfmGO0VzHHG*@mxoMYSuQ*Q%y z&!i}^Xav(yt0DF<<=5{ok4X0!N71W@_lortD!qL>Y}q2Ke~EFaB{YwE4cQv5(}j&F{p9V?pVaNPRQQ z2AR-z^N=M~-_p_T8N+$P(TjE2zsX{6Y>IY^Z6Kt$Mh3i>qh(#CnX@5O|HL$h&1^_P z>5}TTK9G3y7<)}y5g40ReqTCOa6(3ppcpyFI%H<&j;+gAM8)54Qa8VUV|l-zlA1Zb zA`oW5ItT5=Xo~miFDYfC5KgS5?eb=EMT;eL_txqp)O@}31M3U4YcRQzCP0YaM0+*& z`A{Bjqsvs6bxRJ*?-$d1s@?N-fr;}Kc$a|R;Sz< z0+UoXU?7x8zmi1%l2WH2u)|mKfBE`%asj!n+y&9I>4Snnson4a4Zg>qpK|!49?;S= zVbR5mI9IIhPkPBn)IrGf8|EQH&P}qZ5O>UZY&;r7S%{Xe%<_shG(sBGgKHf%dAmGH zuWw(rC;ZcxfHqYZoM%YQ#ArfcL?vFn-0jmevI1$nthN zf|BjcKDg}t^f`_blRi4r6d|AOhdTecUS7=a@q)_k8lOZp+Y9aO>G^%4<8>`@P9yOh zs*orw%zahS*@Alz2bvB&QJIE#+Oaj5b3CL{#iK2u(q8}9_p`QS*|q$s6fj~ns{b&o z!#$O2YaxU4;2b-Eh)^Ri=ddH=J3z$H{*<%Q!38TveOXA+S=VmQsEX031YuEJ&x3uh2v3>)N{68Qd&oVVK`PS@in=jpGDE1 z!>%Pi-zA2bXxXRFCF-1T3dEq8lW}sy3nJVxs^yi33XaUs%ZF;^k?ghRoU_8{0v0_{6$7P6^Fqo7#sc$b zixJd6VkhPXmOE*&43I65cY=ySOZ4-GL=&faFt%^p`_xrB6GBCj`g!THXk$C?f#<|b zpr0t{5sJTy__t~O=OIu0>jqd!K4AoiJ!DqauDsV&Y_>&FxZH6cO%ULn$0l8J(%V|~ zl2wGH_R*d2s~bN^k9>EAhs9$|@4M1~h$seKBeeO=a5?s7=dmeQ5uOI-=YaAagwyL| zR?S4RLt8n}qoKtlll8*8_96b=@Qf(FVudPlRqcr~`l8e^Wvq*rNmVxjnb1Q{8AV60 zQhmu9+}93~(%_xY;$nK9;nV~qsXj2>&InITj}Vh&vV`R_9-_HdtgMF>f9iwAl|m6A zV50iZ=5r537DMXH)BLEkVLeFFQy8+h(I zBDX%)$?1rU6;&*$A4Pu7^2i9X2w+TqYyWA;(6`tq1)1Xyr|BQ*0+;X8lxKuO@iMtM zpuIX`V|&svFM|GN90;NRa%Gs@qG12HCg`i51XxbhL=bip&FoRwU$ijk{=`}Aa?%`> zk`*_s59itNKo)b>#{ZkeKpmQZ>_tWvQ$bDeE}mdQ+Y+2yj0*EuczD^z!cWJIQ#1vS z56&*|K)xfWkNAhDDk_31#-_45&fY*gy#(@|yGA>kvIs<+XSMIn)mQ2g97Q#ZnzM(bdQ9`(?_SS-_Vv<8K9Ut@ z)ju8stk<*ub#=n`TU)z-h)`zg^__H?m+Nrbo6xwtrSryZy+#jf!V`BH#gBfr%p;Q& zu@P~peG~iwQ*Ao)XToH^lpM=bd|^p zdhg7r*XS{F$}P0e-^0?Mf)#qqd0nZi1n7C0F%_M4w+8F{=T}(kdv^!qM7ZxtKlg4W zec%7t>`H$`#uHO5v_XfGM$Bt4?z}gt>#Ha;#N_sJ7{bq5sGt1hL&X^8`@JCjt1n@o z>43pWxswcp+G2P@?f*Xzi_|44%7mDPi|?maPVWD*uWH3T2~Q z1TPzozr}oHaHiqqMM-%l&6s|uKvrPaMdfmRS~ersI~0pr&r{~Wtu4Rzv+kM>OYd=D z92F(?j6~;6fYm1#IM2>4sUbXE_bDgSxk6jw1NK9IJz3rUN=^>1{5SQrHzIX$GWSMn zA>SwPH>Zv|g$F}_hn}W`)a0fLNWH9a%UjuYaOsKnmTK^rbw)KwqNVA3>hzUsRvi{= zW`1eI#pr9emOqakJ}vAe)|+$?dNOB_92;24eT_hcmR# zkpC1*#Bx6j+m`I+l)7J6DOJ|Lakd~P3Fci&`Hsm%tqboJ52lvMrr|X(DT_Kn zjYXG5pe`jWi(uhYhb+^{HysukzqG-nKaWvThFG^CULB(Pq$isTNRJnRrfmM~|Mbk6 zaGBwkU0LAv%4fk|*Kw~tv^!-rM$Gt0q=m+@mqSZ4i1lvtC!$4Ym$>>ZnylAb@I9ax`)7 z@6Lvp>VZYmf5FL&|ADj;5f;R#2^I@Fr>+O_qk4Dl{ByW9+u=dhwY(0^zK?{Q?@Ocr z#pFH*X__6SZ2xXjW=YP-0K@mi?AN=A7n7&zAEIU@6+RMk+AdsNTTc@Fcrd{qFI_?b z9~mOby~M@M{?;|ri!oQ}VpO&+APphYtcSVc%?1!^v_ktCI&`~PHl(z|arc~UU(W@^ z?#SQto=Gt=j1tq$rXhGS5RMhxvXt%@(gXDrpEtFee!IqjV zh(0PuHRjX%G_Lu`O>Xa$R)iN$wK9fP2dvw~V_FHUEJ;8)60(;GiuRt1cO;ENel&uV z=g=&+M#dE5?^ zGX$yON{e9#`<|OCNm<|DQFfkd(HA0ldUMSv{NwU@rd^;wS+z(45HDz9tXqszYc)HJ zMrt$9pFBh~(j|@w&yfElQlp$j^{eO_Ie7kuj3B?(0G&Nty1l*_)YlUX)kB~jL5pg_ z5M3Z``!+(?^Z6*6*k#uWn@6VI!o^-*!x_IG%OD=_A%0GdR>Q(jj^m^DW`suy>5#2_ zngo}g@(N8_$P_ficgahRs$mnzO(@wmUVnWhojnaR4#Dsc5}+1eqc_bKZ? zIJiEVFYxeX2Z~o$U5r0QWIABlBRNuYMU%h-U+cXQywiQHB;VE1k&(>sIY<%NrU)hmRml>536jp2tDgUENrHQbF2CCcmUkvu;! zDu$X%X0k-vOyd);(lC}{Bb<=%PBsrGY6PY9JSD zX^(d=hNSOjxp8Wu$%c5Sruj#6{J_Wnp%-8=Y^5p(c!;JymV$uvA~)xYYyJT%nCoEt zgpk;V5HQmRNHMGD`uGxU?*zy$t38AQC*}s=m%hHm*q9kJ0oP*GxHCYb9d!uBze%Tj z(z?+7A?am;WuTUdgm2;Q8gGGzhtB{nc4v^H5Z}Nf?tb+e#w~}0vN6)-$h-f;>v8&OsM@5^7YJPzJB-T4yJbmY> zAvG(X32F{U!6A`vzGh?nUJkaJu1iO7tSyjJTF1k#ox{K8mgdWl-St79i$jkZ-$6(3 zPY_P_H*<>fa2`vy#0j<;ZSSV{EU|>*e&+ih7XUVpv=(5nPQq&8hS91b?hVIc^Us<<;<3;?MH`#zi^8Z>9E0O;7*qQ(hy$A@ei5)26#Rd7a7{yH4 zIsTjC!Yhs_ia>J%Wz6x_(DZWbGIA{XSEnNd4#o`@k@#>aP+0}&VNl5tj!*ouJ$;uD z9xEtS1R7CLB6QCpXNFp7x9|)o(ze7(>bz_gbexG6`d+$jXKG()Y|b!P)e#Xnp!$Xh za`xKhFksqiH~vgB>=>>u!l7evN=H&}Lf{qonxomhmfkui5S^)kxYE;k%pzx!XJP^9 zpPH6VU3f7;>o(Dwcr%`WN@5o_E@ah{pYnU7#(>x?i1y=_o*J%jC8>oWQqm) zsU93+$70?;7h)v;ZvC@VQJ(n@zxCMwIs!EBsgtNBPoIN4- zT_Ax~d3wSuf$y3s-^N@10MzEpO+z4i)JuZig?0(2U%woUVE>VgS=)? z-3164!|xl=bBM{AS`c^c<9MTEhsg9I^}wsb+Z+X}BfTh`2W0Jwh zQUhQE$O92%Ux^G2Oa9&9qY#`|J~1iUV<7lC0jY!{XILl|9c$!JWmhf1%A)52m@{+# z_0fKDCjpH*kQ?hVYX>HJdX6uKe3Yy>ujcLMkio2I5_pvRbcO`^J|KUNRkG&AuUQ#j z5pVkgTl)Jt^J$vnnZASLDo@?o4MvOGQFMoi_dPo&qItr^cP)xvuj1t7a_wssQ4lG6 z)gaLl;FaHCv3g~QjPR3hofL#W>C?wU1+az<4ELwZv3;p#s~)EmZ>ja6eg$Y-SZVN8 zDR!+4s48J)*bZ!OuR%~-iZDv6Z9Krs-`MPGtLlMGyLY3k`0Qp#R5wkRh9%F9ZqQ!) zk`UjE;j8BBi4x)&a~M~lPGUk73zxA4-cY1)>R$(2FMDz{DWKMNSct|xwz1_k^FgK$(Kn0^hXQ)%N>W-6t+?gxhy=|KRVxKW77@#pftG`HIcp zZ}MnZ*6tiMg4%C2MTr$;3(`*)dch|V=l_iz#rn*iT_{p*>9Ddrlv|r+D<|^({fJK)=$D)PA zMTl)}>xKo8&DQ8BH>85@w9jpU9aW^4T>5eQ%vSYbU*BL_O7MI$LpWwzJv#Yv3 zQwyt=Gm^m9hUfHe?qya%|Mu-9TnwLkk=YG@0Y{m@f`^^)h{T5z8MHyCk0Pr~iDl>6vBxMJVRJi2y)I z7u{d)nqHi|g=_QA5_2vOH0j(Pfr!0LFSTyC3)=80M|V{9DnK_3!kay}o&G+7W@+4^ zvkC7|6SVV7jp4Ck^t1i}xo(94Tc;{7#0R0Y>`XLYR)rmS z?tGa|lj~n)iBIPar3td82r#0i{$H(C(F`Eg6abFc=j+0!`G&{UhM?Q#!jtd6J^r5_ zvw~qsK;Hl7Q+n5Ma(Er}DsT&^J8Rk8F3&W57+{vz!nVL2yF$-)_09KxzL&A8h1|**;CIamM6MLyKorrdUm3XU$EJI9K+Aa zw{`0cZ9-zjHro57LJt+)zza?r!QWFN6XUqH77A<_dwqnO3yd|VO(0n&&CPM>>=X7F z0oPo_8`o?>dlzGNbBKVPlC%~9j$0^$`XRxMU*Bo=i96yJUe8lX4ce$=1U-a`l;inj z7x^<5bG+)67RRDU$o5~3eC(QsFK#=;vX36eTk|ZP1fyxWeE9WfD`jn#+Y=-eClna? zOa~hl#JT@pO=lSu<@F%LBrArVH1PrwXRBi^B$W1Q z@BE~#9jI-Q)8;^R2l^|y7L=Scsyu)JcuHDjUKY7-3f5TFhsb& zUru;*owg=8bouPuI9Q5Z6+CU9N7b1--T$=d+I^CGx8Z}9ypjQgzB@!{^Q!G`4CH?C zh&=H9uZ{UI61ZCb^RbdLYj&c>EBF?5c4lH0%IaTcSJ$H|$v17J;B>4+R$)yJBY`5T zd4pvfq5^gH{SpN8lS?m`F`*2a7>l%%0>lMa!-GFvLl|z^dCW%6`D8G4>Kwx}G>awa za2bqiSAUC|O~pKl%!470tSKMbFtRJZ%z`W(uY+ziMR+1PO!%>hNtFeJ7@BGY_Ic(x zdkKGm9pQsJe0EX(zC^(Ctl{!8Lvs>5N3c!{}QzVvktpo)K zxAQH3)h!@cKQ)-x%sB|-=uP_%g~{vMr<=(9$1mic-@~f(g@Cj-Af~v*I|{-2#Bz!4`(x>R)SxmHZwhv04aEPUa}PA{3WyczrBF5-Dxryc&~ z9DIBm;^E(C-a8$Ls@!bNH1k}F4_l^I0CCzTPx0-KDv56!^R?IIom}dGVl}U=Run4F zwY`U47mn^>$8dKokSrxnHk!j2=y$3Lre!XO;iSG?x(JPuOzhJ6#qpTNbkLJhy=78d4x zf0Ne@>@O6B!kYMDuEyTOv>86;4zm-eqii`@kZQG`iu8PF4m?)4C{7+TO*$z;ej4w4 zU8GmJGi*Rq=zGlXptiL4R5{}>(v7RXimsruiVx9>MqU@P!7$Y7nFkRehSyW-NHC!F znVU-*0+5yf=4*4~nHF_UjQ0y4U;6DM+S3{h6pAd|cjC?)a{Rl)^5Lgt(88A$A0XB< zWQ&1DH01IASuXIH*%-Lpbxrmpr{ekPAbPdZjlmNDcyCgd8>`&q2) z0V?2CfEZ--3ya=-w~XcW(*gK9yd`mrV(qlkYySWgZ@zN66X~9UF^WecF?RiHNJ=>P zs#x;;E%1M113a!+bHIdGZ*=UUxwJh8wx7j$c!Rt%GM!l;^3h4X9W~DN=#&09{LL3V zCc|l*b<@l`uYT!IX3kQ+sy+^VuARDJ!q6hHMc!#lwSu@3*i$U?LlEQ7=rWtF9#l>; zMH1KQI(6`)ou}cteJkZW=|55`rA%h&ANZ{$owc>qR?C^x8g43WT{?WYeG}tXsC{ex z68(X448y?UF&u&*nIAD;B-lpA{M2#A)J!@4-T@?&v3&OL7cYuFgDtu8HJ25rpm)Yj zFFq=}8mQkV&(TW~y(+?_N0&g?>HqfZ@n4sv*46--<)z3bpt&O1_zl4JXl|!tg8zID z{zLOn7V?8j_lzwdWnFn`lQVG_khAv35z&syCoOb6UP-Z?oB`;rf7C&jGvIIgnhYk3 z37tnz9b$DG?3?W>hyLsPgRAX-VyxOE)=o2bDCP_;tF-SLi`=1Tr9eUVa5gWSi+?Qk zZZ+z3OgH*~vXa^s1D4La^}n`VSBU1F(%mvR$X1+bFJY9V3l$>NLj4XX{S0@V+88Q| zUvhPK{%9DiYA=zKXno!L7($4uev2W#&8nb6I$kHdq_b-%@@5ouGG5s8eyp-{bk)K! z!u!()QL3zbn}JB!@M@bFhN7lLcn)LawM|O0v!8A)pIq>y-Z=TcJcqA7z~PrECwJdZE@EvP4@KDp z3yUBivA?zV|BMUX7RrFP{$V5o1wrcPQRyrn?6^+_9GH@vVm@*q3lxT|A5!^ThQg@}kXY+qW%Xnd?wFz*Qq@XD>lXfImW7hd@AtgW$$1l)##tL>`8`g}@>lYP21`SkSJhwp^YWEyABfwS z&*y+TNaI9aCrG;wKGUO8q!CG(%`JAr;f`3SzQiRqayg3CV67PN%QO-#mM!(PlgWL2 zyZI{A#)YY<&hTFp$^!!tO7BVD9nv7iKQg$rz%vJN`({Af{rOdt{I2`iXkac0=gao8>Jwjb9G@tjJZ<(4a`*OiR7;YZ1cT>>#auW%2LgTnY)whV zKc1LTU6}#UJx+Wd#ITEa{vi0cb*}fWJ4NZhmu;x*(s$Wx=y6v&HuQBf^~{NU`YgWm zRxG{Jp*NkUNNiru|-afR3hw*NQ?##NO8m ztMS~>nx6)lDlD-bWj&}j60W{Pe!BM0-!}}+!>G5w)~sND0qORQC6gfvL}&M+j&c zg1xw=QZAF!!Glrh%2#;H0m8&D}>lqaF zE0W12nSo-7pH>Y>XK0nuaw`-p2>2Bx4-o?kz3h*i$JGs-55?A!QD_4l=QPJU)x^aR z@!0g(W|S7u0x^$@KU6J)0TP>GqQp0^dwZlum-)16TEOVzMs8xliSYtTM-NUn0l|g* z_WK2?ys>=NwJ^+=^tRKEBa$M(gcU43A7smbhxOe29{+>6IIiF>?*o>KK;Ue;I_<+- z1*}dU0n5wx-FJXu=>|(b&=I^)ma}%XV0ogv03?kTXdeL-)Te~5>x7g0$&eb`%a$HG^|k|>CA+P8@B?$+D1Vo6D@~oUs;yI2@SC)l4t`7C zKuUA1S|}+e)6nE3?Qc@0X`3{eyi#(yBpk^=g1m69*dnZt9k&H%%=DOjW)$B)wuq(_ z4eD7$$r(xw&JCvBg-pxpXLwQ%_2wt8 z0CH8o-;fvwiXw<3^`UnsP=`I**P~;o-|hJUC8Cq>9*E_<0N}~9c>6;lU^sN{k0nrj z?^-P{$~S?CK773kXdlb9<L8h^juFn*jxqiR2^WDG`2P7C)V z;y$lndiEdz0lT_hWjMdqlJA8Ci`)}2goT7YR49S#jh6N?I7-sG+D#`D00*8S!ifdyB9sO*(%@RgJV2hhjn(3;&y0`Vu{>RF-Q=8yKD&A7r#u4B4KH;-sbdfyQbYr8I2Mgu2k@k9Hl=B|mqdTb~138O&z{(n{ME!lyV$EWg@?noz0<{}_mJ{{(y0WbxPO zcYV5QOdGY)90HxKnGG6Dswb99VZd{TlglV$EMkLDbe6d#ev(XMl>DB0xt*8HlmsW_ z!wZojAo1ICC~3=OPVXF{mj*7{qQ!0b{ZRWY48Kq+XelDu_9|YLjQiCot^Fjl=+*P( zxn?c-uRqp50+R1JWx?_L=*W!oD45KXaXnt_>}R12LGg7+AkMlq#25wk%TRey#@7Zj zIvrafq*$JZQ!g3Q?0JOM7t!q61LK&pH9B9hQe^m+M9?&s>^m?9PhD7-P-;=Job|jI z$Wr=5r$D^|rWn}N3$2(zCC?A0aC@VulI{G>`S_K2#LMz|Ix53tL^X_zO^mX$-~Ef? z2x>{@uEPZAqQP4l1HMtQxM}Ynum=%si4;GN$PYRLs-8DtEHfnzphf>uD-hdS=-!rU zL@WRrw&CiY`9x*W;WZ!t1E?H7gi0R8PFaAQuiq#XQ_K>Zdn-K1zW(pL{vMiYgU|Qr zyni4l>(3dg`uT;{epI}8<0p90gl#pDE3?=?(${4z_X1-~`_&CWVU(dKCxT#TpFQ%j zu3cP7FOh+YsW%ADN}q3c5D)|K6sdmSK>OG>WP~#76euHbC$wc&atPE-=+}r~Q2FmW8*Ajr? zaY!x^xkN%h(H4Y1wW%Y3J6s3n`i7=Fm$lu~4|ryHUbXA=hyaJ-glH#XzF!SU+;?0) zorI_Y<0$V|PC zGyp-JJuahM;^RE2-cT^YW%?%y4;6IeH%oDM+#t5e+E)S;5qa*O?=MR;`wMO?OuZgD z3QBNV>6lkzJJ^>LerJ$;%0zN7j=e0(*vU=)WYD8;@&L>%$BWIXXus zppn&NLt2IhwSPfAeOlZ%6#2ySc1Bxl6C%CU=n-7P-A(^~u16dvvA;uw_%mpO<1gQv ze**~l6i>2UMgzN5%kv5?l4|<;>9Tjp?grAH0+glmjOI0%_V1?)x2rr#T8TJkk{H)t z2sTE1FG;x{i6hwgQUYSb5sHA^*qR(-t{}nRu%gEJ5YC+|I(JG$@ddAA3IQ2xEbcNY z;2bBa5@gXDp4VDb0=y8Tbl!I=N;(N>>E0d-pLi*qm?P@HeskQyK-KQ!dH8plV4IWU zZLJy;E4qhFZ4Dzia3I|wA3>p^ixX+ZHYk|P9~Nm26YCS9Z8-E#?2EgL!>wjyikG@^+xjkkD^`dsgZI>P^J{Re<qu)CnuoLv{B(b|4E9uYm)>K3=Wf4dxRg4$#f0t0{y*pET5zW58>E=|t0;tny|DJ60; zLFl;h*L+k|%f4v|Hp!*wR~|l&$S&OWAO~mc)t}MtFW}_|B;4YvVhxWby`W}MwmhgO zEYih|7t;EGVyZSCrm>;}!&ia>#`3r|5g!?A5Cs839E6dZqQ6@JwqKAz@$9j_@&~e2 z#ET0dTknB;HOSjnNBK&vM?Fo&KfW2i5LP$7=fk}j$mB4-4?9^wSN|@cSe6YA$I;to zPE6#XIjD?;dPGV#6Vz9>0ly$2_MjoGIPE%>Rl~H2gbm|2@kTu?>2Y(31d+PT!+lk3 z&Vl87Vfs>+IJ4_jZb;H{_ReLzUx}$1m(hNk4CFhO5D^KK~9z!(lhg-1ea zC@wQN+?v@}hZl4FaXS9D5HC__NgAQsWmj?^*A9CU>4(@Gec?tD$Fc_Y+U6?J67fps z20BNdS%SBDQsUJ$=5|IF>vx7EtkErnMMiXUk6Q%nTd~Q*u9WKt?GGYi;=)e8&hq42 zX|zKH9tsJ>XvnETkI*#doA9aUbN{sETq#)&Q z!p~p;6nD~pTTPi;LjHL-5`_hD1jHAHU{v`}OG}lN%yPiX@ohb8*FE%G$jB^?763@4 zj4*WMnHwbH%s~rf+E=RZXi}(FDY?H>V_L$6lgs-SxC1z|j1sa58eQ}wYtI@!PeLJc zukxCt`8Syp^ky-oLV86`KDA#bwmrrpD@abCa^teuxdLZ-U%NQ}q18&kt$_w=w#M%> z1aZgt7!*wC=GD+?u3?(RHf_y(6M=P4ZtiK6S%s*m3VJhb2rl}AW)xt(uPOECqs0y% zSkF-r2K+%VaH&hRGxZQ}9FRa5#5!jWA`$yY@VsBwC*28bhKLqkSo*)@A~Kle56e5qMwc?qxL11I@Sax;Otu?7~~O zqs0`|uf!LgW?aO&eRd7(qjXm7n^zcxWfinkl#7Vj4lj<|TMHKPW*&&Vl_fSq+Y2?q z$pw~(!X=VjhpQOm7Y}>h8rgQK`$q@{oChUImREd5gsj|j|1Z$#Z}H`~^xWWD&`%#s zmp#;+?N^3JHA;z#mpCm9&PeD~c*FIEwbu6??bmdj-$U8;=sqHRDQ}4jxfuSd_6dlt z0V@eXV}%yw*$IYFAT{qRZ_|3ZV}%jkvSO6Z?sJhJzkDOMY~Q9YCdzvvEr!G}w`b57EhZYmEUMA(>p*OG+E~!{h5T0^48zqn zoc%3gR2PgJp^ULXZ(1t|4aLlI+`D^WvyLzfq!ry4sfp8rNYFmsH?-$1-xDM0`RjR? z>}Njl_aq#p!Px6w&W1S`>3PT5Io0b2SoNe6W&$^&Ir103XbW4c?LZ$5q zS#hpMPFCA!vV#n{^Q}Q)v#IC!6Mp5=6tlZ2n^X6E;q1z(%68ieBA6?;6c!)l;(Arl zw^|_H_I~6p;W$(m4`U}fmbt5RS(w<&gAAG^XZfxL6dUQO)W%acf2`$Azuodh zwNMz5p{iM(yYIK8*Fh3fR#>mOLqNbSP*spMDDleBK18a^EQBC9QYfd%@$M%kf8LY* zaYxZS4|HkI50T07(8clZ16j4{Rh?x6?1-|D@R*?j!oWyU+=waF6-`6xZ&g z%~Cc#jfnCBk%#y;D@Qlp{qc97tUm5}yAN#>oTL`B96DVS;pD4Z1u#lp>l6J?LKU`6h!Jx7#xCdsqo-L?3s zsJDh*isl0Peza$tuP71+$p^=5W@X_9U8@Rhs;udFur_;nB#OiVXo4My8a{+TwCmW6G* zhJUH?Klwo%|4Nm zaER+iSR7>9PIoSaQ?#x2MG7J!BRx_nK)`#Bie4f!dr$eXua;-VtXnRxO!w8e2OBQ< z9$Dw`yHy>y$9@L#LM?gRlmU@@xJw@Z-+DPj$d~IQ8#?pC%q{|}Xc6LQ**o?HG{Hum z3PAjT2EdW^4DRosG=xU@DOMr4(v#0e#Jdl}0~k5n#6m>Q0^>&rhjhG%IJbE|$Ibp| z<iyvu>vazv^L}VxnGQA^9SE96Rw#~(rxY^doU;mt7xBm!}PA4vCo&Fpy z>P)lA*$uT)`n`_Phw`+nXv-N^$H<4m>SIQ8lvu$RSeUff7Eg&122=19DqYvG9m`%+ zn(ivnB(7Afv=FeET**G_dn7pR9$xeix=JTvc^R)79TJ76G8jPvTDH6{_xe-X6X^ni z-R3L4Tx^<9SN?Ni;t4`Z)^g14M8q7_hTcdvZzCgo|N75p;^Bx@bLlW0wY(CV#lL4? ztXK$*N%>A;R96-2y2F7<{$p7E{J49Y-mGD_{1rR=$U}`Lzb6tI&agJ#Z*3hCBbNYe zf*w)pdO ztAfK8M))3$bEh>w(mQnxM?ZAhStCBx$yjK)b7H?gYnDbm1G4D~?jd=**)h~=)~XjY zbG>LME73(h1rTUpSES{alx{k*(!QH~>-Jz_77LgjO0;X;7D;*`-uuT1DuW zm9?tjKhcwk|H+e=T9$HOujVbij$=PwH2m!EG(Biy06mX{Esal(XvI-azs~%{<-mse zPaGDqEjw(6xE)(geRyU}hfPl;qoxYp5lf4fRO<}GhSP%Lr0bQyd+CU!FPmqQ);q*W zmKLfxNZTWYLm5MJf~}QIUEkFYN;ojdEyka=xJ*aKIquDw=J=t=Z=BjjxdQ9&^4QN8xq{ZP%?E8TH-phv; z`Tg%Ox{X&4HUB%rB&$FCy=^N!`fJm}`B?LKs)4vqn;&^x^P{nP&%4B=k}EDZ5#hJY zI9mwH8?>KJfm;zKJQ7NA`tpORg7#}vO|re|PdBhMI)1A13Q7g;*i>mBrtN*w4Ng_? z#@Lt)SeP#rcYqBR_?KfERcKD(zW9Y&?2P)Ks6IP+IQTOKyg)z9BoIaq5x(dY@3la&}WN=b0t)jfZe ztv&XxGqo{&7V!9%(|e=ZZ{W#-)f|zX-pV~FxsJ&8)Bg^oWe@S{W15oJb;2lZVwi3E zOp7!(>a+TVyxf#nnGN>j9NoTo-H}WaiV_KhA+Yiey#o|izX1bP|Dq8;Y=nSNHcmAa z@+N!oHnH#QL?ac3HCyHVn{ZIJ+gY$z!hVPK?*EAB-^vs{{(X@PC{fVD_9l_lFSzz^ zKSeclvPOF;e#`1Bk`+bITECY0MR-yBfQ}SgJ-Lrc*?+6ZkG?5^k8E6k+S(nk0c!FV zM2~E$F7qtWK;x1J^WKn!_t)sYBTP8uio(@Z=#;g9Fm;CYBVX<5Cko5__hE@0kxSaU z*vNDu(N#eFWl?J@Ma7b=10ydLa;D8iA}brFyP4zd_4qr=VnumnQ1NYG_o(~>BXa~0 znO4Fm_}DTs>Bgk@e6&EVL>?OcUG1Da^LyLplwAfE*Rz zT1eY*hVr3d8aHEjN&0oOG}mduQmqW662Xb!q0A4($IMlxnL@fU;w&%{`vM?jMlyi1 z(H05#t@e3TQ0Zv;tD*y^IhAKqDq-%f)JUTS;rDLpfC*xVNthq*c^`K0Ye*+mOCBr? z0m8X_1eKO0ynRenT%(;19%y7CLLIWsScy-uvs(_9D#ldCia&(CH=>1GYWW0};on@( zqYiO&dYMdOb?69>%YHC#t=>Wl+9TR+25*oU@DGH8Nz-0!$zZ16CPz5Re`@$z*~MvNZBFQgL+hyoLaWpi&}{2%9fAyz{ks=xK}DrjzW(pR?P{MDn^6Td{sTtyk$t8x-nMFw->ww2B^QXGMV5S@)a4Y%1l^=Ju+G_2WJ4rECfBY@)b8qka3@yVr9;F$AbNTMyVr2u0`)Q|*yJ{*a%E^1dize7JhRpkGgJN!zKf6l<-uT$ir;(;eyqR%%Xz%uWa8{5i@9FcR3x`p2?^ z-k+TX7rzjI)2`Ho1FURz4f!BPo4RIIOfWH2-UzcRJWqEn$;kj6U<(@$)jlwnIFdI) zDLxVVT&S@))Ke+kk&nLEoRZ`i*IF&@EL1!qs|xbat)l@^$*Soxky(JYK1Z0!aSvnj z%XakESvUri{XlZ&?NUH`6}v~mcuIXuOedT#h50Z1@_c7st!49%OUdJIYu_jB38Y?>l+UrD zg)n!8o!+c(aU9GzIy6#0O|vDQ<_`yBH!hRfzv}UAxT5@QCZOoQIam$g#_Ex=A<41z zT4&LhYBwD&I-<0(z0FMsNuCA`xU*o?%0B5w+G}Qni zA^;!)f55LP;5tA~N=8mbN={BjPC-FVNqvTznu>~==`cyw!Pz(RX#8%@gP2dSMnMQE5f^F{yH)YQ!&K1P063V zW9Rb*1p+5>*&lf-{L&^n_<#BtmX-(7#X>=|;;Ccg~Gq`L0+ z@N`CnKg8Y((!W`5hQdQ;M?IPA*m*wRxkB#$gEV07$va-=`by>H?&7a0sX-Ty(scHB zTO8t0PrY!k1Iv<{Zx=7K0X$Ts#P6Tw0)S~M5fJZw=(ieo zx5maZoySc9;OzOx-G*M>sgb)pY%R5&Rzsd`UaUS-<5#h?&DTDq22q^9tJ@UnLgM+X zF@Ls|bGS6RzDD-t!7>Q|&?L-yvo^nwv>*LzSouS#!NDR9CDJ(QVSqFY9DNW-g-8j# z%R_Y@3;`mr$CvpOPNfr!@=WeCa4G=jc?bvqpdtjMnZTn^ zLIMEDXIZ}|U+KNEuh38`n>u$RdEMrISN!+(U%>Sq++K3im!t5>T2^3?U*<*7w#Xz^ zc|=+{@3O~PR)N5Y$tv}Fe(fC-S=RBIgYWb*8KX~~$vk2fMDeZ5K1KpP*^uw7wgo1~ z6PmmS!V9VmHKPYFl7e}Mh6Z#ahTaN0sJ7>$IdPE~=HhogE4xK6_Dgf_ZJWb~RC&GQZlsV;-@Dfuk4EW?yxS6`)H|804l zE3bdjDW!^@!f)`kK)3VSu*)9sIEF24d56TYSJL|mxK|VnS8~}eTz|R>Q-k!5M_pRW zX_NRIn9VzM(IUQTU4dqMYOLqRq&jh&ccgEXXj_AYlZ=5d$d&yCjuj0#6JPdnq zA6<+_9JK3;DsDu-8g8O^s7vi|FKT`~T2HDjTv26WK_jit(xWT68&?=4wy5pR8S~u# z+Uxzqu#x~NM-B1gx&icXMYGD|672xza~s9A7hRql8ujG{o<|*K%uO7_^GCc&SB}nl z-?$LpF=`-#4d(v9c8)B{F2%{@20yJ5&v&^Lb|x1k6IeHD$;55hDqYL`p^B7Ps+z!H zuVb)l8v=pXelpY^Z-o&pz=&tTe4nT3Q?ud|Nupj9($f zV&Ysxl3xEk=?k>m@nQbWrDW~h4FgI70aF46}VRuA5dh)9Fsts1JwMasGS*X~HV$X3Vr6vbacBucA0y z&K`7W9GeRNxb|HfDX+U;p0X)MRo0!Nr~F;Ew9@Fby}E_VmQ~G^@3d|EOTocP^43dD zEUy_U3tGj=$Bbo1^pX)qU)3Rbqw7mQi>H7!pBF9Cw5nlt-Uh~Y+wUI2Dw+dFtII~q zS$i}_$8;lVZaD5~b8X+rKD2%ccfN74=pLCOlV|I^8GF1^-q&5un(4%;%2<*&gENW) zGv~tsX0k`l*jC554ELSm+m9B(mLMg%BT7`@lc^W`J!~^rlOx~TURJe^?PyR`q8tdFcvdnGXP%E&{%SIHpI=T@XnkN1p8)gEn%RzjqN($U@Qf=gTv%L4tkJMWNh zRwiAa-tU)l{9_*Y8+H(jyN?U z?Om!l81Q~ptUJL^5rt10)$4UkgKul|6{A>P&y`pftH$-*wFoSbk?pUjkd~K(N;GsQ z>2#I*UA*LL?_p=U9#vl3J<@02{LPIdcc4f@D7R#3xQDL{mKd%QCsXo8Ex?lTXKwwH z9eiNW_DjP1BSTfm=TlqbQFeyUQ*+WC9o(Xm{X`;Gc$4;E7m8dU>(eEHzW|fdWm5Jk zZZR$%s_<)>VLAK~zkprauS3gj)Bh0WpwttjzYWUQPzF$Rf}r~58R;}AaVby4E+|i# z$X*jE1Inr3^5_tg62OD@pU1p^d${PzY(D3*M{oK7GrU)m9^Y`5fdZFfkHo>c(>fay zQlMrVxP`o&$9uzCi}rUqlDsi@Av|nX(fL%)E)E5S(F6L7m{_~P?lH)Op>bq6%EotG zXY&bTZbqV0IiIV5Z8ZX4@AmSwb0|OpW9C=&wS-sQ?o!k#QB&u1zAI~ze5P21VF<2G zrs5HEE3GJqGZ9(O(v3>HCXNw-17w&OwPj@EMGiM=Ea9R4i$ElJRgg54u!evd17UF> z1=SER`)3IuU@|GeFoEw89~k|H->L(V5!huXKqw3a^%#KR5yJywCN$HDa&c0`$3uvS z4bUem4!l1AHQo@Kh)zsihDZ z;~g&|klIoR&~5J|usW}7X$j=LCIyHL2#T31UA;doDy6dJC)#GDUu|dscE?aS>DY>w znXPHFpjEfq&8Rss++5D3JEG7buA*5$(Xb@w{wd7m0*MF5!kU*Xp>C{KeVlhHf|XL) zw5T81VG4N%uPki2WdDTSm7QNbh_tCw^<#}_ebSs!o?=~PsPVOHc`c<+1yPYV6jE9l zu;XVpUI_^kSU@;)DQp-s`j+hSTYc6$y&+T1B{`_0rIB0Gu>r2CHU4`#HTKckym7J^ zu}0?$TLIq`3~UflN{n5+a?n)tF7h7)wo?leuPB|@Fe2k_xE0=H5yNp?UpO( z)iS47E+D)SI-`8Y7 zBh@9f^9`lPX3cbE%x$1f_~qhaWOi{I{p5t#Zk~R7@YD~h8TD?f{6LLOp*ok3zTY2| ziwKd|do98%s*Te{E4sCu^U?Vn=gvJ}=1DN@D3@kRHpI4TJ8WpXm8nnJV_OsPExgWU zj>>Cj+4IR4f~skIQOjn2a_hAXTiTqZk2Zx#iU&9?xLUVMu0|Mr930Su=&iB%OyX7` zo2rN@d)?I7G~+doXT~;F;~`2H&A7OvB1OcdRaK%pYgIi@3FR0@+xjvY8|mLL<`)?% z)`^o-MK&X5zv$ideUPb4bbZzLa*?UMsT2k_)Ii4~&h?}kSCqKr6<}hCO~;oV%_jy% z;$VSC+ycds9Fn5D)iMxYqA^M8R+eCBQe3^2D6xsoK4xMOZkHZcSbs4otn?IPxDA_! z;O4nPXIUwPq&`j6PUn)ky`#N1q8pdG*=Ta7n?J-{pR~&us!d{8uE<$yE3l}#T%Kro z<4j6EG*bA2S+=UiT)Ib_)xmramJ7*o_2H-h`HIc0cW1TvK(l9 z)J)x2^jhv7gEvH0d8BV>jR~i+m$V_~>_8R$zXJa&;tA0B>kdRRJVZB7RN}uCVn9rj z=wvTL?4eAotPB#O0R~OdP%r^%^0kkD0RsAatUu_)@coWo$Cd-1|NFkC1`A+;K!cn9 z#j4!G59x5|lswHf(=NKut!UWcRUPxdf?`})uIjr+^) z^uK@xnbj)|4Rc4SD)&D{A9E`JA#~sH#lL{$D)pbMbD9547rafhf8|q2?N7%6?r%Bw z9{v+u*4}G|xqoN+?&!sDrt&;=+4p^YU+pPH`~qe;_PJ*ep5NbPU-_!`gDyR^6f8sh zU3Pi%K1C8)`%3F#VGiC$))U6pC8F18IICU16?D;DXc@SOze^V}()gq;llZvy_F=R| zU9i^w|B>jYcj+RZCJ-NSwJu1=KWW1fPy9(y)~Me;d>S*q0|ow05tqhIEAjGzT@xz$ zcPh#r|{@y)`!jh_mLV2YK)-vk>mg%*@iQ49K>=i%EZbbMvL&C zfbSF^AVQr;NRfE{n|kr((!VJnt?mZOP$T_po9N&we{12+I}YYhD|6|~adz=g`R=CA z?l0-mxk3aKAJw*Fyx&^%V4czAE3)-7&y_gG6wYkVpRxuhnGt)2T}A`8fcusZMsUWpwWem^v- zt=;v-Jyjas`$cuSu-DC&jh0#0gPET}U;FfV&2AXI%K8)7Dh@T8_o=XA&G-8|4ziAy z7V1`-{9KAwijJkGU6{2)W`szwm)IAXiM$c*8&bQ2LrPRa0qn*w&JGE&C{{=92Q z&n$+Dd{^z~o1v0oTv8I2?ra(s{PQ#cy>R*&;;qG8D|UJPf&%$}O?O+MfCsUff>{_%uL1sJIrjAeyU+ z_vM6kB6U7#TlG|n%oNtTY)#vFBz5k`LANL65*x}#I%7@p%~+;6lXO!Pa?Py_zQlJ( z`BabL%sao-$D2St*C4d>+s0o~OW#hXLD$k3W+rC)uV08>lzMhWfp1K(}pt7}|rwv;y2gUUSm2705Tk>Fh^8Qw$ba!AvQDImK+Y4w* zJmg3NJJNv5-kE5;)0Tc(DECuIW>H?$>D)Yb`@Re(l~RQF;5WZ|Lq?a)>luXEN&psu zK3?edmmx|vEVZAoiE%u`cZQnp3?(19SIK1ptxOvAzsX67ctVLkoTRh(PSkHOO{$7e zQE9*eA?eMhtJGD>Ye^Mtgf#prgggYfHNj7B^fr_3Z2SW<*+UclzMlC%G)7 zCAFdAHr{rY>nr@bW-_=S#)-1ix6U2NXHBYx4%QT~wQL9p&Dd+&$9Ab&b>e%Qv`mNx zMDBCvC+3j95f!Rgr4C(_5oGnu@{m_TRy`ge zQI$@Bk|SODE$L80TP0eliUNj~m3WQS3qDL+eGtXi&K?($?j`F@_(p8Q(R~*{7199|$`_uza3G;Uev|A>NPudAUJm#dLZtIE04Q>@l3 z#B8)vD;a;6giMSAVbJZ&zG}uapyX~hd%aAOf$oEOdW zI9^qtViQy1TN33yH57et&R302>axpdMWFLXmufyY2}d8Tt%(|o)MPl_rP~lUW+Xq>!jLnBzx4%Gxr+{`@S@(NBqPzXIESgH9!Ny7jZGEEZi|M4QLObo$g3yc_r%H(9} zylV5B3u9Rn-%n$h^;bN7om;c@+1tU}=l&^el0kQ!fFlr5{8O5K<>7k*PL?L*0?|LE z$pSv?6L17(ZU4-OkiOO*|Kz-r=4%4YDLFmP$LYW8imYAsV)03X2Yi@GMD@M&Kv+{d zpE@h_+nQiU`};(v7orS4uQKtqXP{znlh7dqnM+MD^YbV(T#EvL>OU_Wi6>=-oFx*K zZQsXaT%lgTqz);>5?g$F^;6@fX@+R*{N-6@O+`NrLzT`6et8xZ)m~gu%|;G-TKoRt z=TP{~hJc8c7=z{{CJ)Ydqqp*gT$q0CdL^pKC-0<8-rU2iHW3@l`(sw84$o&ucgB6I z)h?(wSXW3XmKbC&=5th(7B;A>yh6H)MGdcJ3$%G6ikQFBk$>_3B%Bj?pC!Ga_|VnX zceI#gp!r?@(^nE^c>9^M_Wa6)as3C;G`gpJEycB-n$2B{QO9GFCX1)4yI-ZpCODfs znh_p+Dk~`NrnR3c`Ig2#nh(C_pxfLxqv~Vw2AQzh%=BHJqOIB|%GZ@IvchHLF5Vk5 zHPMKrd$soHHr(G}+kVIIqKh8oh4$X5 zr#4@uTF$oazkn|Fs8OM~{FKDVinfY&>O zm-4?3RM)7K`F5h@W5*v=~(oFPcFGvI+4Unl_!kUj&A1jHJErw!~=t7|fNeguWc z#zue37=z@*g1!WV#8f zcD`7sE-;0ee_pt!a8$Wez2|E_lYgtKnC<8+m(=!<5@nW3c!5atNOq2ik~MX$HfI@0 zwntnw5AMP6pf!+!zy=`0r6w!y!RzO#G9xjIEz?Y{|w@Z(O zmeKSReYxNf#Oj7i;h@XtSfA0jT`EM}1d?xGfy*1hd!>jDM%nCMs~XI$Xcdugcp>6p zf=`mG6dQA2v9?R$5zcaq*JcqF4N(wgD#_78nte0HcGN0vtSd$hxE2L;@z-HF`Zof>Dyt|;y~jAOBBqq1cWxVR6(((O_(!xCN;#?t9=HTOm9Z@iFb z6vZIAYsXW278^H{fujPIgTrxg(mhWbnk*bgo z5MK1+HCT389vfED6RsRL(&WDIF(`e@B7sVRFn1Up0V0%qgcKDikRV8!dFD|VGhq!O zC~Ci#O$M^p0AYH0%>Ub&YexR>Q(5%i2JvA@L;iKMd#~aiy;EJ$`TkQ?9p}R)9o1*0 z{QR-II}7U*Sp+Y(C@{a;I8Z!V)w{SKn<%@t8i>%=w2E0{Vn&O?r0JDAY!1A54LRc2 zhCRMI_2RdDhv}#*RdN>@kssMQ`or#+6$efjay7a?i7&cjL-vnSNAMJ=*EZKoBQxUmrXm3JFDkg%ccdAqZCZx zqR~T&2t$!5AJv8C7P}SYdost%fD7Aom((@Hf z6pQ-Swa?${s{U9!rupy4R#~xrjbGKxCXD{IOsd~miS~i}0ZNa63nC|_ z|Caqje9HV}{;-@(66#RVTPJhoHxdd|pRm088;KpuVYRqvl7OgE6z_Y=n4 zZ+c6EpuXv)(z${;p&|ob;#m?_1^T4D54*)O{eg&j;e6#{6+}50KxPvN)oeyKD7) z>NFoK6A@lBVuMh!2gDyVAd8`3j)>>M?Z|Q#R#t$Dg_sKRnu^rY^5o*DR3;50J9%wq z-~0mNFC0bf{&Bs@$Y(xr&iUtMU?5=V%9Xg#Dt*&M*P&#s*jwv!QS)pE9NMR!?cyx8 z68XZQ$F~Mm5~Vj??Lj*XTsLCTVscEi{H=ul>{QNx9L7zrMkzH&qohCf%xfQ)FQ!r> z{uvTexy+2OpS9}Y68ocjmxAI`4pgjaEI1#gm3Y;6-$;M?12W;XR zJ^ODTkN@D6SF5?A(f?ll`AhzfeI2+vR17hWaN|7Q)x`%aFW@g8NAy$GR%_mW^wM{{ z%|EQ>NmuToUcQ#ka2M@}mu#B!p6R@A`LUW`wA;P7^h`gu?FXnKO)~*j-SBxdyhd7f zAKt}YU1X7CQELnRyb!Rr<`CRqo}w0K_%>oilbM6sWqQL5VP30Udc|WeZS?Kh*-03I z-Ggb9L(R8PmdAn&<*w> zqTr^(8{Pk|V{Pwp6QMOZ7Tmc`x6YM3TX@&8V}@VK%gsYu2U5Pfl^Q{d>Qz4%0NG{&p;V-%bDC)C=5}nr{m{MqseGJ z=p|k7BNjU2vt10Tx~r%W_{2NkaR>aiZyx-49yzxX!}5rUY+r#&#sz707_(*az=WY8 zy&p7_^O>9#?|XN?fd)$9J4NFARYO;hZ;PJZ$GA=ymLOEe8#jGs85B5LvjfG$7vLk_ z!*JQH@CKP|^Rry+iu59>H6=eYm2RDW^~NvC_*Pk~tLn2MLtTcrT^poVYK-fZQi z6vu{P^QYT(MEJJ{WW)j(OlOPw8YRt_ke_u|L%lNBaWA=@b;ameE*L)2=Hg41uvT;O z^HuTO-gBD7rFCe1CO@{gE=q&AtPq`8qYJ06F`fP@FXk$2*j+r1YIMITd&bu^>EVoE z>m6!p=(Nzzut^s#ziObq;z~|BXR+!!;yR*%D^@O}#_zo~6k3&;J~{q9a-?(EX<@3` zP%KHWOm^E3WFUI6RZyU)q{SYU!pdv!*8oG#xJB9fZruwq?U|=&8NHB|;O}c?Jm}(r zeO?-9?}2mT#n@KJB1YAI3Y#e}5RKpbN$XR4wsmczZ2J7rAY9xYr5miP4iT-NPW2P( zTdsj+n(K!d4vyIRt8BL-AlF$F#_FvbQ;J=1*`;JEB+n^~V^_%&ZnD|hveht(FeRy& zF{oXElx%j6L2Cm&Rpg$YYO&^JiT!w(kzlhosID8{jEggJw6a%e;7vi{Qe`n`=#oeZ zJwlzYmoax3Q(`XdN8L!bZu2WGKp$<5*(DMiG9x>ajG;!og@;Ol?gna+=gRLhywH5F zNY}bE&6tRM8`USgLp}hjqIE?}d3zQGLdDuvEFSF6YRg<-c!=(Mf0(tOGDqQ`3;*&( zYHy&6R(_pDa7HvgL(sa|C)!EQZNU!v9#wP>EuzkeRC=6Ji)c}oN9L1vW?ZXh7D<|D zqf7TPYv5+$O!Rote!53*+a;Jp3t!eP#E;IPN#=rP*L#bXOxdga%yCuq5vCusR0`~d zqS$Q0b&czFaP0^+{OA$-~7;A011@_|z4o<@MLwYN<3t4mV`^mlGYl3IQ#tO{bp=EwN2jmK#uKd;c` zVD4(C?^i85XGk3+acdOXIr~$eW1!dss&2?JW3OG(=7rl-Fd#TI{YRjwYCchzg;2jm zq(d1XB65bHWotkdz{PrDk?gl~?_X7k2s$;I$ug9{j>!N1^A|5VvwlZ3p@34(qlFat zymNGy`Zxz^9LD)Q808nkv-Urw$l3+saAu8|i|<-rq^`1a7vDWD6Gh=g(2jK-Qf@giJ5sa1PO|k}I%9P- zLM&pQsrp@q(50{a$GGL!%e*k`hP`V|ai#nE#yIbg8wc%RI;Z}*dC8kqBb5k^NgAjr zOeVTdUH+bf<&@!>LuHb!y3>iPMRk&^cb@9m)FqjL(ELgrO_qssA3h73~&pTuo5 z7%qiecq8?WwmmC1Gp6)#U$UL4#AmlW_~|bI)m`jrbfBUn1{_m74!%z@$R(9ol#LBR za(0{h=X`Q$Y2DU3W^Fg25mwivC4K6JM=%?iArxva zS`~X#?j4eBrKsno2wUY}zL(Y-)44WpepigH>qb!{GkxE?LqmG8!ai>Su3WhbIkWV6 zgAqP4I$E51W=0weXccrEntu;h@*VFu!EkWEO$UTzi$VvQ&Snh+3q-NTv&F=o-NC3@ z@B}ePyX#y327^{uoczuVWH&J8xvCl+Y$q_{(Ts@Xm?@U=r5xa;nbz2#ZQ}ekKFB)BNDj0Lxi@!n|ZeefTG<6*R;Wg3fdyOa- zJ->9Wb7)&8b43Aqb>7TytpuD;xnf_OiGXFT>UV{Mg*(w+)rRJ{s9`6qE<>5@pUNS` zPxN-E6^QEWoNvt@en?D&zO9~I{fO~c&R(uvE-bT4xqBmOUUEQNQx$MK zv&5#dr^eA7 z%jPrJon}@f6JZ)um5RYwLF6T%ZL0@n#>w5yLlH~p!l%5ipdLi`> zK2vMqNh51&#jfY=wcZv*;WM0I2!GgTZ;M}m*7=Twi`uZr=C8)5a7*y&0mTSc9Ikl8 zBlABBpZ_(?sVm1Jk2UY_eHeglAU`uRlTL(u|aUIpgRh{Z*yuEC1{D+uc^o;dz5M z5hKiO@is}uoD*>+Ru-kcBL%RdcWLR=&I)lkiK#Si*7A_`g(C2SAP-cO!z(i543et% z8kljhD^lVHayT)4e29xAug6#3npd_~v^da>uMLl1XK-xiVrDXiA2t=@ed^=RJyo4> zFKl$^mrG*ENTn^wiW11K6sTFN?X<{CO1+iYh7)vlb^g$WFN%gFNmzMhXK&6|1MArX zmJ(*Gs}{zl)9Pm)xHx-6n}QbI>e3Yi++##H(i>@YHrL(=>AJiVXw!up+ib2j5hyvR z{n!vh3$+qyb6&M8uyao5Gn8Y)SuuzVh~KR)S)Og~N%43qY!xa)VImnHQxph1wULUm#UOmE8H|iXsD}%XvY#~RgCARAV^mcdK8-ih zD%>T?%6?tAaf{2$IGwEo>r(!{8X;C>5uoekG4*nHrDL5xzck-o>V1pp;T+%Xw-|b} zMyR)^1j3nC=g=~NwjiefWtp;am0Emo@w;sCR2d!HpBZ=(lbhd=eFFNiJ#W=sx%6#q zPtua-ul4g^$RG>z43u?s;Ncl~rgrkR3;LXIj=op~9%Y)A)b=TQz;V~N2B899vwnT&=9W(sV{Q@!T22L}<$V5ed9_RYp`P{) z5i^gdazo@d54>;v6Uq(_P3=c-CTrd@7{hZn8_X;l+HGZJ50f;@UX4E$9XQssbr^-2K5aSVJpa|UF6TU@_Lhq`JXVK zXxszC5g&>AE#H9&(}uTJe#IC+EGJcMq=BaLx?lHlz2oEf+KUphVi8SF^|7|@r7d~( z)k0FeZT6;d$n|l|%V`cDMds4TZHLU#@QnKL5J}!-`_AH?;LW}t!i|py<*7v5ZZJv~p+>CmQw}iW zGg?+gCOw?6oj%JWwiR9s>M&klrnX^I`SPV8((k~I8pc*E zV8*+0@7M-Z5#iD{QAz42{sS!vv@+%Ob6uivF2kF!{1 zHrdLde#~IuJ>2-cTtyA6IL0NvT?8MZ`%%}tlsu>QwnDl&p3u8w6FQXSKn>QFPh+`KQp zb_XT!k?EpaoG3N2Rm9W$<#8ha0bhVI1mbqX)^pay#`rp9s64)$ixy@bV7jOpiPY!s z-0H;pRN(S|d{h2-YmKFlRis?J^FW;Kt66_<&3M|uilihB=5WF0*0SqpPWpOda_d{EzZKTcT+_u6(!TF-(5yK4$C)JS2nxDBn z_IfPKFhSRk?xMVzZCM3b4x9shIu#Dy%g83N;*|zGf;Eh&HPygS6Gn!xupEv_H;qx9 zt;ZOOj{AOL%cG0Pj!7?XPIf-a^sJ$fBT)t3TgY6~u!>LlR)6%=|A&`mxE-zE1u_*z zT}JE&`=l;*=%(5)KsU}%beMwabSp(+LBYURwe@8@e_lFYxaMXgB&Pz#t1?%PPri4{ zt=Ly?;n4SbIrV)8N#jI}Rft7gqQ%?c4P5CJQ_f5B?13pY5>1tM@K5dhb}(kn>;qdx zZy5IvnFi6)dJ%`VbwP2Kk?Uj*A|4K^3Kd#kx+f6jc>5qf_uZNui|NyRy~oZud8oWi zc({pdk?)X8&Dc@av?OPEMhPsx#LexVtVo5hmD_tiN z7Jw;2;;QW?`cpRx>-{!K!YL4ku=BLTl`1=jyC~|c0X18t&2H0L3ZnIubbgXc}uw|IwY78!y z`Ry#g<8JCYKs%OU@fEj_rSKSpi5XI%*}B~w!x|{C!9mlpW)-zQ2ak!Y^D!KPYUAC! zT_#eyE0+A;%D_TD5Pf#$O|>!>MOGxogkR3_X2>x=LQd^LAhJeNCd>Xj|FWL^zs^vB zDix*3FJSF}NEzGGNIkIw)7 zO$)fe%{cyB;j+mGm%0BG{=>HPpD9mv*UbDHe~xedDr0?e6nXR=^*ajf{JRE;M=U)q z$8JJbqCCa|kDxdD?)LJBA(9dL#KV#QTC_=-+qv-;p4D@k8lN9vHla0+f%H!OwTf z%7`_}D1Y}FXiR73;rZLl@TUR$w@VkV%-#6gKK|v>zviU|0YFhllBB5gNrG9zzDA8N z;(CSJitVFZG!pnWuY0)s_plKG72%x9nB^?E1*O0bnrMJ zUrKR%Xn3COhoZ3=I>%5i#_Jx1qIER<7l0Sq82NBXH}u10b_bMw8v}bXJ)?x;z>3!m z+`;$IqdVXR@lB=698TTAWXTfrqrBj$o#T&$Vg1-AaRRkxw1kYDjZ}jW%-#ZR6`NM6 zcQYO_vH1z-6t&*&EXWDdaegK{q=l9ZeylTv?(uNX44!4n%|O1T@kFb;sg;Z2H?QH# z{a)y`TzUzK)hY|PG-2Kyj%c`WwL4X=KAFp@I8LH?usc=n9?b>X!hw36a}K(a!B*>N zvO6LAJw)uS%Sf|@y8}XXh2-C-Gg0DS78P-$-$v(5aFk9?LO}P5zt1uMjNI?|B15*u z^b})SCW(zvH}+*4vsV{)3+IBA%qWK<)$~*#H1PkP)1~U^F+n~p+r27_;?6K zgmaJt(o>H#z+(~+0xz5Fa(^!U7YpS-=h>Y>Cl3@Bi>-mL@DK&$p#xrsyz@afA^L+7 z*O#n)jY5e)wu}ic{W5aOuy@Zd<1J&^(*|3V-)i{;TEr@l0 zqoMScf-*&|bb{>=atP7jpK7f4!;a5E!Oe1dy~f4y`zMoc+9)qsXA3EJ6x`dgI83@x zIB|X0i+_MQAWr{ZcW&TA|A)8u0l|}iniTx|145ttZwAs((opaa3P`NB3KG~_s*uS* zLVn&?#t|QJtR;_s&g`7i>30n)UJ63%oyj=7BMZd(A=uXlnPKU)5ex5&W`oBI1R(ZE$etL86 z_-#b;PvNUGslNczbC(of&`W+tK5UfvS-v1}ANBsO<1b*8;wha|o6awQIrCHBFQCXj z^2I_G*TkzY4?dDi>@Z$wza?LJf8(E+w`FwSbo&Q+^gokx{6&81LCuu7Ihi%f@B2z` z2ttL}V=>rr=#nPeqBp|dO7=L(84C_2no61A;imlCC5dzz{3MRl)SZurLv0ZJ!j}i6 zVBrH@n7|GC-<)B1^h^VY^i|PaKc%whR^;_b9rB3ZZ@T!q(9VV+h+p7Lw!}6LxM@qv zGW$Ocs%96CxE^Vjpl8Zr31Nl9p^9!r>f*H?eT~+$6rmv!uUJ|a2VYQnS5%ONSJDRi zeC|)gOpdekE!4Os?HVuN^tmh@?tB{dq^6eo&2nLWP+CV5YEG!DiTrOwV-r zjKv3fI54Gl=+0d-GWR;mz68J|0@#(hH`K1uiJ67)aC_mDNiKTOQ;f5V*pT zdcSmGVJvi?ktvlK-|E60X;TfuVynufp|!H_G$wmo(;?8$i0YzL<-^NL^U*^#qPc_6 z!=)A$>S^fX1d*jPIWKsTQs_R_-jN2;F{dkLTg}1LIb5y6cLKJLHMwZ7JKtVH$8CmN zMt2@`5BK122tzec$u$p--gD~@2EJq|c%v8F$eOL?qVYwvjdSg0ym|6i&%K;Z)#{Rn zqzVst9SepxNg8Dxi0e-zP_ip%^9B@3rb3I~HoK!k)uG}@RxG*n=)n%BJaJLmB{yTn z0*xav_PC;>bcfv;OpRVhK|;uAsfOU~K&wkHNQ&R^J|0e>dfd@xJYuIV)^1lCz_4D@ zV8!Z5GMb%4_C$NfO$${^9m0uWii9cX<=RPzXjEvdbVe;&A()FM@vrInALrQR#ueEi z-g#w1F31&rbz_MqPNi>g3Ui}>evdoWMASGB`#9p6?A)92rN$I&s;H0nP19(YQsh

0ih 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 ?`{ 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 YoQFr6+yUvbNlG8<96tcs@!Q~k0i!@kA^-pY literal 220523 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

??fALjqki*?OD`l}njx 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 XAp_YZiBpSfwC+RGZNP! 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 {lhyOoE(9x|pn1B-doETaIOg5&0+&peh7jK% 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 e21!IgR09D0r)Nn! { - const validatePending = options.validatePending === true; - const accountsPath = `/api/codex-auth/accounts${validatePending ? "/refresh" : forceRefresh ? "?refresh=1" : ""}`; + const refreshAction = options.refreshAction === true; + const accountsPath = `/api/codex-auth/accounts${refreshAction ? "/refresh" : forceRefresh ? "?refresh=1" : ""}`; const [accountsRes, activeRes] = await Promise.all([ - apiJson(deps, baseUrl, validatePending ? "POST" : "GET", accountsPath), + apiJson(deps, baseUrl, refreshAction ? "POST" : "GET", accountsPath), apiJson(deps, baseUrl, "GET", "/api/codex-auth/active"), ]); if (accountsRes.status !== 0 && accountsRes.status !== 200) { diff --git a/src/cli/account-auth.ts b/src/cli/account-auth.ts index f8e95c6f12..9ecc637a7a 100644 --- a/src/cli/account-auth.ts +++ b/src/cli/account-auth.ts @@ -155,9 +155,9 @@ async function login(argv: string[], deps: RuntimeApiDeps): Promise { ); if (state.status === "done") { if (state.validationPending === true) { - printData({ ...state, recoveryCommand: "ocx account refresh openai" }, wantsJson, [ + printData({ ...state, recoveryCommand: "ocx gui", recoveryAction: "After quota recovers, click Refresh quotas in the dashboard Codex account pool." }, wantsJson, [ "Account registered; validation pending (routing disabled).", - "After quota recovers, run 'ocx account refresh openai' to complete validation.", + "After quota recovers, open 'ocx gui' and click Refresh quotas to complete validation.", ]); } else { printData({ ...state, modelSelection: modelSelectionNextSteps("openai") }, wantsJson, [`Logged in${state.email ? ` as ${String(state.email)}` : ""}.`, ...modelSelectionGuidance("openai")]); diff --git a/src/cli/account-extended.ts b/src/cli/account-extended.ts index 628de6c8b7..a6fa3b707c 100644 --- a/src/cli/account-extended.ts +++ b/src/cli/account-extended.ts @@ -264,7 +264,7 @@ function refreshLine(row: FamilyRows["rows"][number]): string { const quotaText = row.quota ? quotaParts(row.quota).join(" ") : ""; parts.push(quotaText.length > 0 ? quotaText : "quota: unknown"); if (row.needsReauth) parts.push("needs-reauth"); - if (row.validationPending) parts.push("validation-pending (routing disabled)"); + if (row.validationPending) parts.push("validation-pending (routing disabled; open 'ocx gui' and click Refresh quotas after recovery)"); return parts.filter(Boolean).join(" "); } @@ -340,7 +340,7 @@ export async function cmdRefresh(args: string[], deps: AccountDeps): Promise { if (url.pathname === "/api/codex-auth/accounts" && req.method === "GET") { @@ -1995,9 +1996,11 @@ export async function handleCodexAuthAPI( } if (url.pathname === "/api/codex-auth/accounts/refresh" && req.method === "POST") { - // Completing validation spends inference and changes durable readiness, so it - // must pass the management mutation/CSRF boundary rather than a read-only GET. - return jsonResponse({ accounts: await listCodexAuthAccounts(config, true, { validatePending: true }) }); + // Inference spends quota: only a dashboard session carries the consent + // required by AGENTS_INSTALL.md. Raw-admin/CLI refreshes remain observational. + return jsonResponse({ accounts: await listCodexAuthAccounts(config, true, { + validatePending: principal === "gui-session", + }) }); } if (url.pathname === "/api/codex-auth/accounts" && req.method === "POST") { diff --git a/src/oauth/health.ts b/src/oauth/health.ts index f52e8093a9..98fd64126d 100644 --- a/src/oauth/health.ts +++ b/src/oauth/health.ts @@ -90,7 +90,7 @@ export const CODEX_REAUTH_ACTION = "reauthenticate via the dashboard Codex accou function actionFor(provider: string, health: OAuthAccountHealth): string | undefined { if (health.status === "warning" && health.reason === "validation_pending") { - return "wait for quota recovery, then refresh Codex account quotas to finish validation"; + return "wait for quota recovery, then click Refresh quotas in the dashboard Codex account pool to finish validation"; } if (health.status === "reauth_required") { if (provider === "codex") return CODEX_REAUTH_ACTION; diff --git a/src/server/management-api.ts b/src/server/management-api.ts index c703a33e07..2db088503a 100644 --- a/src/server/management-api.ts +++ b/src/server/management-api.ts @@ -371,7 +371,7 @@ export async function handleManagementAPI( const { ConfigMutationLockError } = await import("../config"); const { CodexCredentialRefreshLockTimeoutError } = await import("../codex/account-store"); try { - return await handleCodexAuthAPI(req, url, config, convergeCodexCatalog); + return await handleCodexAuthAPI(req, url, config, convergeCodexCatalog, principal); } catch (error) { // Credential writers remap ConfigMutationLockError to CodexCredentialRefreshLockTimeoutError; // treat both as the same retryable busy response. diff --git a/tests/cli/cli-account.test.ts b/tests/cli/cli-account.test.ts index 00f492839b..214270e4be 100644 --- a/tests/cli/cli-account.test.ts +++ b/tests/cli/cli-account.test.ts @@ -2132,11 +2132,11 @@ describe("ocx account CLI (issue #180 matrix)", () => { const human = await run(["login", "openai"]); expect(human.code).toBe(0); expect(human.stdout).toContain("validation pending (routing disabled)"); - expect(human.stdout).toContain("ocx account refresh openai"); + expect(human.stdout).toContain("ocx gui"); expect(human.stdout).not.toContain("Logged in"); expect(human.stdout).not.toContain("ocx models"); const machine = await run(["login", "openai", "--json"]); - expect(JSON.parse(machine.stdout)).toMatchObject({ validationPending: true, recoveryCommand: "ocx account refresh openai" }); + expect(JSON.parse(machine.stdout)).toMatchObject({ validationPending: true, recoveryCommand: "ocx gui" }); expect(JSON.parse(machine.stdout)).not.toHaveProperty("modelSelection"); } finally { sleepSpy.mockRestore(); diff --git a/tests/codex-integration/codex-auth-api.test.ts b/tests/codex-integration/codex-auth-api.test.ts index a525469b3c..43ccc82b9e 100644 --- a/tests/codex-integration/codex-auth-api.test.ts +++ b/tests/codex-integration/codex-auth-api.test.ts @@ -5007,7 +5007,7 @@ describe("codex-auth API", () => { let replaceDuringWarmup = false; const refreshAccounts = async () => { const req = new Request("http://localhost/api/codex-auth/accounts/refresh", { method: "POST" }); - const response = await handleCodexAuthAPI(req, new URL(req.url), config); + const response = await handleCodexAuthAPI(req, new URL(req.url), config, undefined, "gui-session"); expect(response?.status).toBe(200); }; const selectAccount = () => { @@ -5094,7 +5094,7 @@ describe("codex-auth API", () => { }) as typeof fetch; const refresh = async () => { const req = new Request("http://localhost/api/codex-auth/accounts/refresh", { method: "POST" }); - const response = await handleCodexAuthAPI(req, new URL(req.url), config); + const response = await handleCodexAuthAPI(req, new URL(req.url), config, undefined, "gui-session"); expect(response?.status).toBe(200); return await response!.json(); }; @@ -5118,6 +5118,30 @@ describe("codex-auth API", () => { expect(isCodexAccountUsable(config, accountId)).toBe(true); }); + test.each([undefined, "admin-token", "local-read-capability"] as const)("non-browser refresh stays observational for principal %s", async principal => { + const accountId = "validation-consent"; + const config = makeConfig({ codexAccounts: [{ id: accountId, plan: "pro", isMain: false }] }); + saveConfig(config); + setLiveStateStoreConfig(config); + saveCodexAccountCredential(accountId, { accessToken: "consent-access", refreshToken: "consent-refresh", + expiresAt: Date.now() + 3600_000, chatgptAccountId: "consent-account" }, { validationPending: true }); + let warmups = 0; + globalThis.fetch = (async (input: RequestInfo | URL) => { + if (String(input).endsWith("/wham/usage")) return Response.json({ plan_type: "pro", + rate_limit: { secondary_window: { used_percent: 12, limit_window_seconds: 604800 } } }); + warmups++; + return new Response('data: {"type":"response.completed"}\n\n'); + }) as typeof fetch; + const req = new Request("http://localhost/api/codex-auth/accounts/refresh", { method: "POST", + headers: { "x-opencodex-gui-origin": "http://localhost", "x-opencodex-csrf-token": "forged" } }); + const response = await handleCodexAuthAPI(req, new URL(req.url), config, undefined, principal); + expect(response?.status).toBe(200); + expect((await response!.json()).accounts.find((row: { id: string }) => row.id === accountId).quota.weeklyPercent).toBe(12); + expect(warmups).toBe(0); + expect(readCodexAccountRecord(accountId)?.codexValidationPending).toBe(true); + expect(isCodexAccountUsable(config, accountId)).toBe(false); + }); + test("explicit validation preserves an account's pause and selection state", async () => { const accountId = "paused-validation"; const config = makeConfig({ codexAccounts: [{ id: accountId, plan: "pro", isMain: false }], pausedCodexAccountIds: [accountId] }); @@ -5136,7 +5160,7 @@ describe("codex-auth API", () => { throw new Error("unexpected request"); }) as typeof fetch; const req = new Request("http://localhost/api/codex-auth/accounts/refresh", { method: "POST" }); - expect((await handleCodexAuthAPI(req, new URL(req.url), config))?.status).toBe(200); + expect((await handleCodexAuthAPI(req, new URL(req.url), config, undefined, "gui-session"))?.status).toBe(200); expect(warmups).toBe(1); expect(readCodexAccountRecord(accountId)?.codexValidationPending).toBeUndefined(); expect(loadConfig().pausedCodexAccountIds).toEqual([accountId]); diff --git a/tests/oauth/oauth-health.test.ts b/tests/oauth/oauth-health.test.ts index 51186074c0..c92629b5ce 100644 --- a/tests/oauth/oauth-health.test.ts +++ b/tests/oauth/oauth-health.test.ts @@ -131,7 +131,7 @@ describe("collectOAuthHealthEntries", () => { .toEqual({ provider: "codex", accountId: "pending-local", health: { status: "warning", reason: "validation_pending" }, - action: "wait for quota recovery, then refresh Codex account quotas to finish validation", + action: "wait for quota recovery, then click Refresh quotas in the dashboard Codex account pool to finish validation", }); }); test("projects needsReauth account with reauth action", async () => { diff --git a/tests/server/server-management-auth.test.ts b/tests/server/server-management-auth.test.ts index 86cf843c6e..4b9995ab90 100644 --- a/tests/server/server-management-auth.test.ts +++ b/tests/server/server-management-auth.test.ts @@ -5,6 +5,7 @@ import { tmpdir } from "node:os"; import { join } from "node:path"; import { getConfigPath, saveConfig } from "../../src/config"; import { startServer } from "../../src/server"; +import { readCodexAccountRecord, saveCodexAccountCredential } from "../../src/codex/account-store"; import type { OcxConfig } from "../../src/types"; import { serveGuiFile, serveSessionBootstrap } from "../../src/server/gui-static"; import { isProxyAdmissionSecret } from "../../src/server/auth-cors"; @@ -961,7 +962,23 @@ describe("management and data-plane credential separation", () => { test("deferred Codex validation requires a same-origin mutation session with CSRF", async () => { const config = remoteConfig(); config.hostname = "127.0.0.1"; + const accountId = "consent-wire"; + config.codexAccounts = [{ id: accountId, isMain: false, plan: "pro" }]; saveConfig(config); + saveCodexAccountCredential(accountId, { accessToken: "consent-access", refreshToken: "consent-refresh", + expiresAt: Date.now() + 3600_000, chatgptAccountId: "consent-account" }, { validationPending: true }); + const originalFetch = globalThis.fetch; + let warmups = 0; + globalThis.fetch = (async (input: RequestInfo | URL, init?: RequestInit) => { + const target = input instanceof Request ? input.url : String(input); + if (target.endsWith("/wham/usage")) return Response.json({ plan_type: "pro", + rate_limit: { secondary_window: { used_percent: 12, limit_window_seconds: 604800 } } }); + if (target.endsWith("/codex/responses")) { + warmups++; + return new Response('data: {"type":"response.completed"}\n\n'); + } + return originalFetch(input, init); + }) as typeof fetch; const server = startServer(0); try { const bootstrap = await fetch(new URL("/opencodex-session", server.url)); @@ -976,6 +993,12 @@ describe("management and data-plane credential separation", () => { "x-opencodex-gui-origin": server.url.origin, }; const url = new URL("/api/codex-auth/accounts/refresh", server.url); + const admin = await fetch(url, { method: "POST", headers: { + ...headers, "x-opencodex-api-key": "admin-secret", "x-opencodex-csrf-token": csrf!, + } }); + expect(admin.status).toBe(200); + expect(warmups).toBe(0); + expect(readCodexAccountRecord(accountId)?.codexValidationPending).toBe(true); const missing = await fetch(url, { method: "POST", headers }); expect(missing.status).toBe(401); const crossOrigin = await fetch(url, { @@ -989,8 +1012,11 @@ describe("management and data-plane credential separation", () => { }); expect(allowed.status).toBe(200); expect(await allowed.json()).toHaveProperty("accounts"); + expect(warmups).toBe(1); + expect(readCodexAccountRecord(accountId)?.codexValidationPending).toBeUndefined(); } finally { await server.stop(true); + globalThis.fetch = originalFetch; } }); From 61a775ca2dcbe1fd7d7678901abea0351f8ef461 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 18:23:16 +0900 Subject: [PATCH 085/412] docs: record lane B manual delivery roadmap [skip ci] --- devlog/_plan/260907_release_train_b/000_plan.md | 11 +++++++++++ devlog/_plan/260907_release_train_b/010_carry.md | 3 +++ devlog/_plan/260907_release_train_b/020_carry.md | 3 +++ 3 files changed, 17 insertions(+) create mode 100644 devlog/_plan/260907_release_train_b/000_plan.md create mode 100644 devlog/_plan/260907_release_train_b/010_carry.md create mode 100644 devlog/_plan/260907_release_train_b/020_carry.md diff --git a/devlog/_plan/260907_release_train_b/000_plan.md b/devlog/_plan/260907_release_train_b/000_plan.md new file mode 100644 index 0000000000..be31f8e242 --- /dev/null +++ b/devlog/_plan/260907_release_train_b/000_plan.md @@ -0,0 +1,11 @@ +# Lane B delivery roadmap + +Satisfy-spec HOTL, triggered by delegated release-train packet. Goal: prepare a manual #3856 -> #3849 carry chain for main-session integration. No merges, releases, installs, local tests/typechecks/builds, native stacks, or edits to other lane files. Resources: existing git/gh and astra reviewers; user set no token/cost/time limit. Stop after exact top-head remote CI success, independent security verdicts, and handoff evidence. BLOCKED means a concrete unresolved owner/security/CI condition; #3848 is DEFER until #3856 lands. Main reclaims after two distinct failed leaf packets; new worker scope requires plan amendment. + +Memory/evidence: this neutral roadmap, `.tmp/lane-b/` for all security work notes, `.codexclaw/` for FSM/goalplan. Escalate cross-lane conflicts to main. How-it-works English/ja/ko/ru/zh-cn ownership was explicitly assigned to B by main. No automatic peer writes beyond collision coordination. + +1. Docs-only roadmap audit and lock. +2. Carry quota activation original commits with cherry-pick -x and contributor trailers; inspect default-off, identity and pending-state contracts. Lower layer code verification is deferred to top CI by explicit user instruction; its D certifies carry preparation, not runtime success. +3. Carry Mihomo transport commit plus IPv6-only and canonical NO_PROXY/unsafe companion regressions. Publish manual chain, independently review final implementation, dispatch ci.yml lane=all only on top. Repair lower layers sequentially and cascade with rebase --update-refs. + +Verifier: gh workflow run ci.yml --ref codex/260907-b-mihomo-ipv6 -f lane=all; read exact head SHA and every job including Windows shards. Local product commands NOT RUN by user instruction. Inspect workflow definitions instead of executing local verifiers. No claims of live TUN validation; deterministic resolver/pinned transport tests are remote CI proof. diff --git a/devlog/_plan/260907_release_train_b/010_carry.md b/devlog/_plan/260907_release_train_b/010_carry.md new file mode 100644 index 0000000000..cde8f79785 --- /dev/null +++ b/devlog/_plan/260907_release_train_b/010_carry.md @@ -0,0 +1,3 @@ +# Quota activation carry + +Detailed working plan: `.tmp/lane-b/010_carry.md` (gitignored security work space). Public source and contributor provenance are recorded in the roadmap. Only published outcomes will be added here. diff --git a/devlog/_plan/260907_release_train_b/020_carry.md b/devlog/_plan/260907_release_train_b/020_carry.md new file mode 100644 index 0000000000..10d853e99e --- /dev/null +++ b/devlog/_plan/260907_release_train_b/020_carry.md @@ -0,0 +1,3 @@ +# Mihomo IPv6 carry + +Detailed working plan: `.tmp/lane-b/020_carry.md` (gitignored security work space). Public source and contributor provenance are recorded in the roadmap. Only published outcomes will be added here. From 1386e3d4a04b7a12eacea0ced74ed55307d6dfa3 Mon Sep 17 00:00:00 2001 From: Terry Tan Date: Sun, 6 Sep 2026 23:17:29 -0700 Subject: [PATCH 086/412] fix(codex): sustain quota window activation [skip ci] (cherry picked from commit 0da9f2ce0812c0dbf39d48077bfb038b2c526783) Co-authored-by: terrytan95 <10609214+terrytan95@users.noreply.github.com> --- .../docs/getting-started/how-it-works.mdx | 8 +- src/codex/auth-api.ts | 15 ++ src/codex/quota-auto-refresh-state.ts | 6 + src/codex/quota-auto-refresh.ts | 162 +++++++++++++++--- src/codex/warmup.ts | 4 + src/config.ts | 2 + src/types/config.ts | 3 + structure/08_openai-provider-tiers.md | 7 +- 8 files changed, 178 insertions(+), 29 deletions(-) diff --git a/docs-site/src/content/docs/getting-started/how-it-works.mdx b/docs-site/src/content/docs/getting-started/how-it-works.mdx index 0344037b75..b5995732b6 100644 --- a/docs-site/src/content/docs/getting-started/how-it-works.mdx +++ b/docs-site/src/content/docs/getting-started/how-it-works.mdx @@ -50,7 +50,13 @@ account before the request is forwarded upstream. The rule is intentionally spli its minimal non-stored account warmup request through the exact account whose window is due, coalesces simultaneous windows into one request, and durably persists both reset timestamps to prevent duplicate work after restarts. Paused accounts and accounts - requiring reauthentication are skipped; the next normal quota poll reports the activated window. + requiring reauthentication are skipped. Activation captures successful response quota headers; + opted-in idle accounts also refresh stale quota metadata at most once every five minutes, + without needing an open dashboard. Observed reset boundaries are retained across restarts + until completed, so a moving idle-window timestamp cannot erase a pending activation. + Metadata refresh uses the existing bounded authentication recovery; an inference 401 marks + the rejected credential for reauthentication instead of repeatedly spending retries on it. + Failures log only an opaque account label and a status-only reason. This is separate from reset-window routing: routing chooses an account for incoming work, while activation sends one request to a specific opted-in account only after its own reset is due. diff --git a/src/codex/auth-api.ts b/src/codex/auth-api.ts index 51e3fed303..8ab7f7418f 100644 --- a/src/codex/auth-api.ts +++ b/src/codex/auth-api.ts @@ -1835,6 +1835,21 @@ export async function listCodexAuthAccountsSnapshot( }; } +/** One opted-in account's metadata; reuse the bounded WHAM 401 recovery and generation fence. */ +export async function refreshCodexQuotaForActivation(config: OcxConfig, accountId: string): Promise { + if (accountId === MAIN_CODEX_ACCOUNT_ID) { + await fetchMainAccountInfoAttempt(true, 1, undefined, false, false); + return; + } + const account = configuredPoolAccount(config, accountId); + if (!account) return; + const writerGeneration = captureConfigGeneration(); + const result = await fetchPoolAccountQuota(accountId, true, account.plan); + if (result.needsReauth && result.credentialGeneration !== undefined) { + markAccountNeedsReauth(accountId, writerGeneration, result.credentialGeneration); + } +} + export async function listCodexAuthAccounts(config: OcxConfig, forceRefresh = false): Promise { return (await listCodexAuthAccountsSnapshot(config, forceRefresh)).accounts; } diff --git a/src/codex/quota-auto-refresh-state.ts b/src/codex/quota-auto-refresh-state.ts index 43bb606d63..72b7d5828c 100644 --- a/src/codex/quota-auto-refresh-state.ts +++ b/src/codex/quota-auto-refresh-state.ts @@ -4,13 +4,19 @@ export type CodexQuotaAutoRefreshWindows = { fiveHour?: number; weekly?: number export const completedByAccount = new Map(); export const retryAfterByAccount = new Map(); +export const scheduledByAccount = new Map(); +export const quotaRefreshAfterByAccount = new Map(); export function forgetCodexQuotaAutoRefreshAccount(accountId: string): void { completedByAccount.delete(accountId); retryAfterByAccount.delete(accountId); + scheduledByAccount.delete(accountId); + quotaRefreshAfterByAccount.delete(accountId); } export function resetCodexQuotaAutoRefreshStateForTests(): void { completedByAccount.clear(); retryAfterByAccount.clear(); + scheduledByAccount.clear(); + quotaRefreshAfterByAccount.clear(); } diff --git a/src/codex/quota-auto-refresh.ts b/src/codex/quota-auto-refresh.ts index 88291e0cdd..b61cc1467e 100644 --- a/src/codex/quota-auto-refresh.ts +++ b/src/codex/quota-auto-refresh.ts @@ -1,5 +1,5 @@ import { mutatePersistedConfig } from "../config"; -import { registerStateSweepAfterTick } from "../lib/state-store-sweeper"; +import { captureConfigGeneration, registerStateSweepAfterTick } from "../lib/state-store-sweeper"; import { isCanonicalOpenAiForwardProvider, OPENAI_CODEX_PROVIDER_ID } from "../providers/openai-tiers"; import { normalizeResetAt } from "../providers/quota-wire"; import { providerCodexAccountMode } from "../providers/registry"; @@ -7,17 +7,20 @@ import type { OcxConfig } from "../types"; import { isSelectableCodexPoolAccount } from "./account-id"; import { reconcileMainCodexAccountRuntimeState } from "./account-lifecycle"; import { isCodexAccountPaused } from "./account-pause"; -import { isAccountNeedsReauth } from "./account-runtime-state"; -import { getValidCodexToken } from "./account-store"; +import { isAccountNeedsReauth, markAccountNeedsReauth } from "./account-runtime-state"; +import { getValidCodexToken, isCodexAccountGenerationLive } from "./account-store"; +import { codexAccountLogLabel } from "./account-label"; import { getMainAccountToken, getValidMainAccountToken, MAIN_CODEX_ACCOUNT_ID } from "./main-account"; import { isMainAccountHardLocked } from "./main-account-hard-lock"; import { tryAcquireNativeMainProfileClaim } from "./native-main-admission"; import { withNativeMainSharedClaim } from "./native-main-claim"; import { resolveNativeProfileContext } from "./native-profile-store"; -import { getAccountQuota, type StoredAccountQuota } from "./quota"; -import { warmCodexAccount } from "./warmup"; +import { captureMainQuotaWriter } from "./main-account-cache"; +import { applyAccountQuotaFromUpstreamHeaders, getAccountQuota, type StoredAccountQuota } from "./quota"; +import { CodexWarmupError, codexWarmupFailureReason, warmCodexAccount } from "./warmup"; import { - completedByAccount, retryAfterByAccount, resetCodexQuotaAutoRefreshStateForTests, + completedByAccount, retryAfterByAccount, scheduledByAccount, quotaRefreshAfterByAccount, + resetCodexQuotaAutoRefreshStateForTests, type CodexQuotaAutoRefreshWindows, } from "./quota-auto-refresh-state"; export type { CodexQuotaAutoRefreshWindows } from "./quota-auto-refresh-state"; @@ -36,6 +39,7 @@ export interface CodexQuotaAutoRefreshStatus { export interface CodexQuotaAutoRefreshRunDeps { getQuota?: (accountId: string) => StoredAccountQuota | null; + refreshQuota?: (config: OcxConfig, accountId: string) => Promise; /** Only false means skipped; existing void callbacks still report a successful warmup. */ warmAccount?: (config: OcxConfig, accountId: string) => Promise; persistCompleted?: ( @@ -69,29 +73,83 @@ export function dueCodexQuotaAutoRefreshWindows( now: number, completed = completedByAccount.get(accountId), ): CodexQuotaAutoRefreshWindows | null { - if (!quota) return null; const saved = config.codexQuotaAutoRefresh?.[accountId]; + const scheduled = scheduledByAccount.get(accountId) ?? ( + saved?.nextFiveHourResetAt !== undefined || saved?.nextWeeklyResetAt !== undefined + ? { fiveHour: saved.nextFiveHourResetAt, weekly: saved.nextWeeklyResetAt } : undefined + ); const due: CodexQuotaAutoRefreshWindows = {}; - const shortResetAt = normalizeResetAt(quota.shortResetAt); - const weeklyResetAt = normalizeResetAt(quota.weeklyResetAt); + const shortResetAt = normalizeResetAt(scheduled ? scheduled.fiveHour : quota?.shortResetAt); + const weeklyResetAt = normalizeResetAt(scheduled ? scheduled.weekly : quota?.weeklyResetAt); if (saved?.fiveHour === true - && quota.shortWindowSeconds === FIVE_HOUR_WINDOW_SECONDS + && (scheduled?.fiveHour !== undefined || saved.nextFiveHourResetAt !== undefined + || quota?.shortWindowSeconds === FIVE_HOUR_WINDOW_SECONDS) && shortResetAt !== undefined && shortResetAt <= now - && normalizeResetAt(saved.lastFiveHourResetAt) !== shortResetAt - && normalizeResetAt(completed?.fiveHour) !== shortResetAt) { + && shortResetAt > (normalizeResetAt(saved.lastFiveHourResetAt) ?? -1) + && shortResetAt > (normalizeResetAt(completed?.fiveHour) ?? -1)) { due.fiveHour = shortResetAt; } if (saved?.weekly === true && weeklyResetAt !== undefined && weeklyResetAt <= now - && normalizeResetAt(saved.lastWeeklyResetAt) !== weeklyResetAt - && normalizeResetAt(completed?.weekly) !== weeklyResetAt) { + && weeklyResetAt > (normalizeResetAt(saved.lastWeeklyResetAt) ?? -1) + && weeklyResetAt > (normalizeResetAt(completed?.weekly) ?? -1)) { due.weekly = weeklyResetAt; } return due.fiveHour === undefined && due.weekly === undefined ? null : due; } +/** Retain the earliest uncompleted observation, including across process restarts. */ +function rememberWindows(config: OcxConfig, accountId: string, quota: StoredAccountQuota | null): void { + const saved = config.codexQuotaAutoRefresh?.[accountId]; + if (!saved) return; + const completed = completedByAccount.get(accountId); + const previous = scheduledByAccount.get(accountId) ?? { + fiveHour: normalizeResetAt(saved.nextFiveHourResetAt), + weekly: normalizeResetAt(saved.nextWeeklyResetAt), + }; + const next: CodexQuotaAutoRefreshWindows = {}; + for (const window of ["fiveHour", "weekly"] as const) { + if (!saved[window]) continue; + const done = normalizeResetAt(completed?.[window] + ?? (window === "fiveHour" ? saved.lastFiveHourResetAt : saved.lastWeeklyResetAt)); + const observed = normalizeResetAt(window === "fiveHour" + ? quota?.shortWindowSeconds === FIVE_HOUR_WINDOW_SECONDS ? quota.shortResetAt : undefined + : quota?.weeklyResetAt); + const candidates = [normalizeResetAt(previous[window]), observed] + .filter((value): value is number => value !== undefined && (done === undefined || value > done)); + if (candidates.length) next[window] = Math.min(...candidates); + } + scheduledByAccount.set(accountId, next); + if (normalizeResetAt(saved.nextFiveHourResetAt) === next.fiveHour + && normalizeResetAt(saved.nextWeeklyResetAt) === next.weekly) return; + try { + const outcome = mutatePersistedConfig(persisted => { + const current = persisted.codexQuotaAutoRefresh?.[accountId]; + if (!current) return { changed: false, value: null }; + const setting = { ...current }; + // A settings change that raced this sweep remains authoritative. + delete setting.nextFiveHourResetAt; + delete setting.nextWeeklyResetAt; + if (current.fiveHour && next.fiveHour !== undefined) setting.nextFiveHourResetAt = next.fiveHour; + if (current.weekly && next.weekly !== undefined) setting.nextWeeklyResetAt = next.weekly; + persisted.codexQuotaAutoRefresh = { ...persisted.codexQuotaAutoRefresh, [accountId]: setting }; + return { changed: true, value: setting }; + }); + if (outcome.status !== "unavailable" && outcome.value) { + config.codexQuotaAutoRefresh = { ...config.codexQuotaAutoRefresh, [accountId]: outcome.value }; + } + } catch { + // Keep the in-memory deadline and retry its narrow persistence on the next tick. + } +} + +async function refreshQuota(config: OcxConfig, accountId: string): Promise { + const { refreshCodexQuotaForActivation } = await import("./auth-api"); + await refreshCodexQuotaForActivation(config, accountId); +} + function mainWarmupRestricted(config: OcxConfig): boolean { return isMainAccountHardLocked(config) || isCodexAccountPaused(config, MAIN_CODEX_ACCOUNT_ID) @@ -99,8 +157,23 @@ function mainWarmupRestricted(config: OcxConfig): boolean { } async function warmAccount(config: OcxConfig, accountId: string): Promise { + const writerGeneration = captureConfigGeneration(); if (accountId !== MAIN_CODEX_ACCOUNT_ID) { - await warmCodexAccount(await getValidCodexToken(accountId)); + const token = await getValidCodexToken(accountId); + if (isCodexAccountPaused(config, accountId) || isAccountNeedsReauth(accountId)) return false; + try { + await warmCodexAccount({ ...token, onCompleted: headers => { + if (isCodexAccountGenerationLive(accountId, token.generation)) { + applyAccountQuotaFromUpstreamHeaders(accountId, headers, writerGeneration); + } + } }); + } catch (error) { + if (error instanceof CodexWarmupError && error.status === 401) { + markAccountNeedsReauth(accountId, writerGeneration, token.generation); + } + throw error; + } + if (!isCodexAccountGenerationLive(accountId, token.generation)) return false; return; } const lease = tryAcquireNativeMainProfileClaim(); @@ -116,7 +189,18 @@ async function warmAccount(config: OcxConfig, accountId: string): Promise { + if (writer) applyAccountQuotaFromUpstreamHeaders(accountId, headers, writerGeneration, writer); + } }); + } catch (error) { + if (error instanceof CodexWarmupError && error.status === 401 + && getMainAccountToken()?.accessToken === token.accessToken) { + markAccountNeedsReauth(accountId, writerGeneration); + } + throw error; + } }); } finally { lease.release(); @@ -175,30 +259,54 @@ export async function runCodexQuotaAutoRefresh( const quotaFor = deps.getQuota ?? getAccountQuota; const warm = deps.warmAccount ?? warmAccount; const persist = deps.persistCompleted ?? persistCompleted; + const refresh = deps.refreshQuota ?? refreshQuota; inFlight = (async () => { retryPendingMarkers(config, persist); const accountIds = [ MAIN_CODEX_ACCOUNT_ID, ...(config.codexAccounts ?? []).filter(isSelectableCodexPoolAccount).map(account => account.id), ]; - const due = accountIds.flatMap(accountId => { - if (isCodexAccountPaused(config, accountId) - || isAccountNeedsReauth(accountId) - || (accountId === MAIN_CODEX_ACCOUNT_ID && isMainAccountHardLocked(config)) - || (retryAfterByAccount.get(accountId) ?? 0) > now) return []; - const windows = dueCodexQuotaAutoRefreshWindows(config, accountId, quotaFor(accountId), now); - return windows ? [{ accountId, windows }] : []; - }); - for (let index = 0; index < due.length; index += CONCURRENCY) { - await Promise.all(due.slice(index, index + CONCURRENCY).map(async ({ accountId, windows }) => { + const eligible = (accountId: string) => { + const setting = config.codexQuotaAutoRefresh?.[accountId]; + const provider = config.providers[OPENAI_CODEX_PROVIDER_ID]; + return provider?.disabled !== true && isCanonicalOpenAiForwardProvider(provider) + && providerCodexAccountMode(OPENAI_CODEX_PROVIDER_ID, provider) === "pool" + && (accountId === MAIN_CODEX_ACCOUNT_ID || config.codexAccounts?.some( + account => account.id === accountId && isSelectableCodexPoolAccount(account))) + && (setting?.fiveHour === true || setting?.weekly === true) + && !isCodexAccountPaused(config, accountId) && !isAccountNeedsReauth(accountId) + && !(accountId === MAIN_CODEX_ACCOUNT_ID && isMainAccountHardLocked(config)); + }; + for (let index = 0; index < accountIds.length; index += CONCURRENCY) { + await Promise.all(accountIds.slice(index, index + CONCURRENCY).map(async accountId => { + if (!eligible(accountId)) return; + // Capture before WHAM can move an idle window's reset into the future. + rememberWindows(config, accountId, quotaFor(accountId)); + const quota = quotaFor(accountId); + if ((!quota || now - quota.updatedAt >= RETRY_MS) + && (quotaRefreshAfterByAccount.get(accountId) ?? 0) <= now) { + quotaRefreshAfterByAccount.set(accountId, now + RETRY_MS); + try { await refresh(config, accountId); } catch { /* Retry metadata at the bounded cadence. */ } + } + if (!eligible(accountId)) return; + rememberWindows(config, accountId, quotaFor(accountId)); + if ((retryAfterByAccount.get(accountId) ?? 0) > now) return; + const windows = dueCodexQuotaAutoRefreshWindows(config, accountId, quotaFor(accountId), now); + if (!windows) return; try { if (await warm(config, accountId) === false) return; retryAfterByAccount.delete(accountId); const completed = { ...completedByAccount.get(accountId), ...windows }; completedByAccount.set(accountId, completed); persist(config, accountId, completed); - } catch { + rememberWindows(config, accountId, quotaFor(accountId)); + } catch (error) { retryAfterByAccount.set(accountId, now + RETRY_MS); + const account = config.codexAccounts?.find(candidate => candidate.id === accountId); + const label = account ? codexAccountLogLabel(account) : "main"; + console.warn(`[codex-quota-auto-refresh] ${label}: ${codexWarmupFailureReason(error)}; ${ + isAccountNeedsReauth(accountId) ? "reauthentication required" : "retry in five minutes" + }`); } })); } diff --git a/src/codex/warmup.ts b/src/codex/warmup.ts index 51b52ac2ba..cc2f10ac55 100644 --- a/src/codex/warmup.ts +++ b/src/codex/warmup.ts @@ -22,6 +22,8 @@ export interface CodexWarmupOptions { chatgptAccountId: string; model?: string; timeoutMs?: number; + /** Publish quota headers only after a completed inference, never on a failed stream. */ + onCompleted?: (headers: Headers) => void; } const CODEX_RESPONSES_URL = "https://chatgpt.com/backend-api/codex/responses"; @@ -263,6 +265,8 @@ async function tryWarmup(options: CodexWarmupOptions, model: string): Promise {}); diff --git a/src/config.ts b/src/config.ts index d5ef05c33f..d25aa07ad2 100644 --- a/src/config.ts +++ b/src/config.ts @@ -856,6 +856,8 @@ const codexQuotaAutoRefreshEntrySchema = z.object({ weekly: z.boolean().optional(), lastFiveHourResetAt: z.number().finite().nonnegative().optional(), lastWeeklyResetAt: z.number().finite().nonnegative().optional(), + nextFiveHourResetAt: z.number().finite().nonnegative().optional(), + nextWeeklyResetAt: z.number().finite().nonnegative().optional(), }).strict(); const CODEX_QUOTA_AUTO_REFRESH_KEY_ERROR = "quota auto-refresh keys must be a Codex pool-account id or the main Codex account and cannot be reserved JavaScript object keys"; diff --git a/src/types/config.ts b/src/types/config.ts index ee97cdf9ac..31b5a52ceb 100644 --- a/src/types/config.ts +++ b/src/types/config.ts @@ -723,6 +723,9 @@ export interface OcxConfig { /** Upstream reset timestamps already activated, retained across restarts. */ lastFiveHourResetAt?: number; lastWeeklyResetAt?: number; + /** Observed boundaries retained until activation, even if an idle upstream clock moves. */ + nextFiveHourResetAt?: number; + nextWeeklyResetAt?: number; }>; /** * Selection order per account id, higher used earlier; absent = 0. Keyed by id diff --git a/structure/08_openai-provider-tiers.md b/structure/08_openai-provider-tiers.md index 1f838baeb5..834cbd46ee 100644 --- a/structure/08_openai-provider-tiers.md +++ b/structure/08_openai-provider-tiers.md @@ -75,7 +75,12 @@ plan-relevant window is freshly confirmed at exactly 100%; unknown and failed re `codexQuotaAutoRefresh` is a separate default-off spending intent. For each explicitly enabled account/window, the one-minute state sweep compares the cached upstream reset timestamp, sends the existing minimal non-stored warmup through that exact account once the timestamp is due, then -field-patches the completed timestamp; the next normal quota poll reports the activated window. +field-patches the completed timestamp. The next observed reset boundary is also retained in +`nextFiveHourResetAt` / `nextWeeklyResetAt` until completed; later idle-window metadata cannot +postpone it. Successful warmups publish quota headers under the captured credential/identity fence. +For opted-in accounts only, stale metadata is refreshed at most once per five minutes through +the existing WHAM recovery path, independently of dashboard traffic or reset notifications. +Inference 401s quarantine the rejected credential; failures log an opaque label and safe reason. Paused or reauthentication-required accounts are skipped, simultaneous 5-hour/weekly resets share one warmup, transient failures retry after five minutes, and account deletion removes its setting and completion markers. From c38677004f80605dd8628fb109e804169cbc2b7f Mon Sep 17 00:00:00 2001 From: Terry Tan Date: Mon, 7 Sep 2026 00:51:39 -0700 Subject: [PATCH 087/412] test(codex): cover quota activation regressions [skip ci] (cherry picked from commit 5d01860f23cabaedd68dd53a9c8e751a71ca2ba2) Co-authored-by: terrytan95 <10609214+terrytan95@users.noreply.github.com> --- .../docs/getting-started/how-it-works.mdx | 4 + .../docs/ja/getting-started/how-it-works.mdx | 16 +++ .../docs/ko/getting-started/how-it-works.mdx | 16 +++ .../docs/ru/getting-started/how-it-works.mdx | 19 +++ .../zh-cn/getting-started/how-it-works.mdx | 25 ++++ src/codex/quota-auto-refresh-state.ts | 2 + src/codex/quota-auto-refresh.ts | 11 ++ src/codex/warmup.ts | 1 + .../codex-quota-auto-refresh.test.ts | 116 ++++++++++++++++++ tests/codex-integration/codex-warmup.test.ts | 23 ++++ 10 files changed, 233 insertions(+) diff --git a/docs-site/src/content/docs/getting-started/how-it-works.mdx b/docs-site/src/content/docs/getting-started/how-it-works.mdx index b5995732b6..c75ffed90e 100644 --- a/docs-site/src/content/docs/getting-started/how-it-works.mdx +++ b/docs-site/src/content/docs/getting-started/how-it-works.mdx @@ -60,6 +60,10 @@ account before the request is forwarded upstream. The rule is intentionally spli This is separate from reset-window routing: routing chooses an account for incoming work, while activation sends one request to a specific opted-in account only after its own reset is due. +**Downgrade note:** Before running an older version, remove only `nextFiveHourResetAt` and +`nextWeeklyResetAt` from automatic activation settings. Older strict readers reject these new +fields and can disable the entire activation settings block. + ## Sub-agent model selection On a fresh install, `subagentModels` features `gpt-6-astra`, the GPT-5.6 Sol/Terra/Luna trio, and diff --git a/docs-site/src/content/docs/ja/getting-started/how-it-works.mdx b/docs-site/src/content/docs/ja/getting-started/how-it-works.mdx index 0970b0e7c0..2e0e87f1ee 100644 --- a/docs-site/src/content/docs/ja/getting-started/how-it-works.mdx +++ b/docs-site/src/content/docs/ja/getting-started/how-it-works.mdx @@ -39,6 +39,22 @@ Codex は OpenAI **Responses API** を使います。opencodex は HTTP と Serv `GET /api/codex-auth/accounts?refresh=1` でクォータを強制再照会できます。成功した上流 応答はクォータヘッダーを保存し、429 はアカウントをクールダウンに置き、401/403 は再認証必要状態としてマークします。 +- **アイドル状態の利用枠も自動開始できます。** 詳細設定の自動開始はデフォルトでオフです。 + 現在のメインアカウントと追加アカウントが報告する 5 時間枠・週間枠をまとめて切り替えます。 + 新しく追加したアカウントには自動で適用されません。Pool モードでは、期限が来たアカウントへ + 利用枠を消費する最小限の非保存リクエストを送ります。同時に期限が来た枠は 1 回にまとめ、 + 一時停止中・再認証が必要なアカウントやメインアカウントのハードロックは回避しません。 + 完了した応答のクォータヘッダーを保存し、有効なアイドルアカウントの古いメタデータも + 最大 5 分に 1 回更新するため、ダッシュボードを開いておく必要はありません。 + 観測済みの期限は完了まで再起動をまたいで保持し、後の照会で動く時刻に上書きされません。 + メタデータ照会は既存の回数制限付き認証回復を使い、推論の 401 は拒否された認証情報を + 再認証必要として扱います。失敗ログには不透明なアカウントラベルと安全な状態理由だけを記録します。 + これは入力リクエストのアカウント選択とは別の機能です。 + +**旧バージョンへ戻す場合:** 自動開始設定の `nextFiveHourResetAt` と `nextWeeklyResetAt` だけを +削除してから旧バージョンを起動してください。旧版の厳密な設定検証はこれらの新しいフィールドを +受け付けず、自動開始設定全体を無効にする場合があります。 + ## サブエージェントモデルの選択 新規インストールすると `subagentModels` のデフォルトで `gpt-6-astra`、GPT-5.6 Sol/Terra/Luna の 3 モデル、 diff --git a/docs-site/src/content/docs/ko/getting-started/how-it-works.mdx b/docs-site/src/content/docs/ko/getting-started/how-it-works.mdx index e2a75024d1..1538c701b3 100644 --- a/docs-site/src/content/docs/ko/getting-started/how-it-works.mdx +++ b/docs-site/src/content/docs/ko/getting-started/how-it-works.mdx @@ -39,6 +39,22 @@ pool 계정을 고를 수 있습니다. 규칙은 의도적으로 둘로 나뉩 `GET /api/codex-auth/accounts?refresh=1`로 할당량을 강제 재조회할 수 있습니다. 성공한 업스트림 응답은 할당량 헤더를 저장하고, 429는 계정을 cooldown에 넣으며, 401/403은 재인증 필요 상태로 표시합니다. +- **유휴 상태의 할당량 창도 자동으로 활성화할 수 있습니다.** 고급 설정의 자동 활성화는 기본적으로 + 꺼져 있으며 현재 메인 계정과 추가 계정이 보고하는 5시간·주간 창을 함께 제어합니다. + 새로 추가한 계정에는 자동 적용되지 않습니다. Pool 모드에서는 만료된 창의 정확한 계정으로 + 할당량을 소비하는 최소한의 비저장 요청을 보내며, 동시에 만료된 창은 요청 하나로 묶습니다. + 일시 중지 또는 재인증이 필요한 계정은 건너뛰고 메인 계정의 하드록도 준수합니다. + 완료 응답의 할당량 헤더를 반영하고, 활성화 대상인 유휴 계정의 오래된 메타데이터는 최대 5분에 + 한 번 갱신하므로 대시보드를 열어 둘 필요가 없습니다. 관측한 만료 시점은 활성화가 끝날 때까지 + 재시작 후에도 유지되어, 나중의 조회에서 시점이 밀려도 대기 작업을 잃지 않습니다. + 메타데이터 조회에는 기존의 횟수 제한 인증 복구를 사용합니다. 추론 401은 거부된 자격 증명을 + 재인증 필요로 표시하며, 실패 로그에는 불투명한 계정 라벨과 안전한 상태 사유만 기록합니다. + 이 기능은 들어오는 요청의 계정을 선택하는 라우팅과 별개입니다. + +**다운그레이드 안내:** 이전 버전을 실행하기 전에 자동 활성화 설정에서 `nextFiveHourResetAt`과 +`nextWeeklyResetAt`만 제거하세요. 이전 버전의 엄격한 설정 검증은 이 새 필드를 허용하지 않아 +자동 활성화 설정 전체를 비활성화할 수 있습니다. + ## Sub-agent 모델 선택 새로 설치하면 `subagentModels` 기본값으로 `gpt-6-astra`, GPT-5.6 Sol/Terra/Luna 세 모델, diff --git a/docs-site/src/content/docs/ru/getting-started/how-it-works.mdx b/docs-site/src/content/docs/ru/getting-started/how-it-works.mdx index d18b081b12..ceeff22531 100644 --- a/docs-site/src/content/docs/ru/getting-started/how-it-works.mdx +++ b/docs-site/src/content/docs/ru/getting-started/how-it-works.mdx @@ -43,6 +43,25 @@ Codex даже не догадывается, что общается не с Op провайдера сохраняют заголовки квоты, 429 отправляет аккаунт в кулдаун, а 401/403 помечает его как требующий повторной аутентификации. +- **Неиспользуемые окна квоты можно активировать автоматически.** В расширенных настройках эта + функция по умолчанию выключена и управляет доступными 5-часовыми и недельными окнами всех + текущих основных и добавленных аккаунтов. Новые аккаунты не включаются автоматически. + В режиме Pool после наступления срока отправляется минимальный несохраняемый запрос именно + через нужный аккаунт; он расходует квоту. Одновременные сбросы объединяются в один запрос. + Приостановленные аккаунты и аккаунты, требующие повторной аутентификации, пропускаются; + жёсткая блокировка основного аккаунта также соблюдается. Заголовки квоты успешного ответа + обновляют кеш, а устаревшие метаданные включённых подходящих аккаунтов обновляются не чаще + одного раза в пять минут даже без открытой панели. Наблюдаемые сроки сохраняются до завершения + активации, включая перезапуски, поэтому сдвиг времени при следующем опросе не удаляет ожидающую + работу. Опрос использует существующее ограниченное восстановление аутентификации; ответ 401 + на запрос модели помечает отклонённые учётные данные для повторной аутентификации. + В журнал ошибок попадают только непрозрачная метка аккаунта и безопасная причина состояния. + Активация отличается от выбора аккаунта для входящего запроса. + +**Возврат к старой версии:** перед её запуском удалите только `nextFiveHourResetAt` и +`nextWeeklyResetAt` из настроек автоматической активации. Строгий валидатор старой версии +не принимает эти новые поля и может отключить весь блок настроек активации. + ## Выбор модели для подагентов После чистой установки `subagentModels` включает `gpt-6-astra`, тройку GPT-5.6 Sol/Terra/Luna и diff --git a/docs-site/src/content/docs/zh-cn/getting-started/how-it-works.mdx b/docs-site/src/content/docs/zh-cn/getting-started/how-it-works.mdx index e90bcb38b8..d234dd1ff5 100644 --- a/docs-site/src/content/docs/zh-cn/getting-started/how-it-works.mdx +++ b/docs-site/src/content/docs/zh-cn/getting-started/how-it-works.mdx @@ -21,6 +21,31 @@ Codex 使用 OpenAI **Responses API**。opencodex 接收通过 HTTP 与 Server-S └─────────────────────────────────────────────────────────────────────┘ ``` +![Codex 多账号路由:已有线程保持账号绑定,新会话可以查询额度并选择使用量更低的健康账号。](../../../../assets/multi-auth-routing.svg) + +## Codex 认证账号选择 + +当选择的 provider 使用 ChatGPT/Codex 直通时,opencodex 可以在转发请求前从已保存的账号池中选择账号。 + +- **已有线程保持绑定。** 线程绑定到开始时所选的账号代次,长时间运行的 SSH、tmux 或移动端 + Codex 会话不会在正常对话过程中重新分配账号。 +- **新会话可以重新分配。** 新线程按 `accountPoolStrategy` 选择可用账号,默认为 `quota`,也支持 + `round-robin` 和 `fill-first`。`quota` 比较已知的 5 小时、每周和 30 天额度使用量,并在当前账号 + 超过 `autoSwitchThreshold` 时选择使用量更低的账号。冷却中或需要重新认证的账号会被跳过。 +- **额度和失败信号参与路由。** 仪表盘通过 `GET /api/codex-auth/accounts?refresh=1` 强制刷新额度。 + 成功的上游响应会更新额度头信息;429 使账号进入冷却,401/403 会将账号标记为需要重新认证。 +- **空闲额度窗口可以自动激活。** 高级设置中的自动激活默认关闭,统一控制当前主账号和附加账号 + 已报告的 5 小时及每周窗口;新添加账号不会自动启用。在 Pool 模式下,窗口到期后会通过对应账号 + 发送最小化、不保存的请求,并消耗少量额度;同时到期的窗口合并为一次请求。暂停、需要重新认证 + 的账号会被跳过,主账号硬锁限制也会得到遵守。成功响应的额度头会更新缓存;已启用且符合条件的 + 空闲账号还会每隔至少 5 分钟刷新过期的额度元数据,无需保持仪表盘打开。已观察到的到期时间会保留 + 至激活完成,重启或后续查询的时间变化不会丢失待处理窗口。元数据查询复用现有的有次数限制的认证 + 恢复逻辑;推理请求返回 401 时,被拒绝的凭据会标记为需要重新认证。失败日志仅记录不透明账号标签 + 和安全的状态原因。该功能独立于为传入请求选择账号的路由逻辑。 + +**降级说明:** 运行旧版本前,请仅移除自动激活设置中的 `nextFiveHourResetAt` 和 +`nextWeeklyResetAt`。旧版严格校验不接受这两个新字段,可能因此禁用整个自动激活设置块。 + ## Sub-agent 模型选择 全新安装会通过 `subagentModels` 在 Codex 的 sub-agent 选择器中优先显示 `gpt-6-astra`、GPT-5.6 diff --git a/src/codex/quota-auto-refresh-state.ts b/src/codex/quota-auto-refresh-state.ts index 72b7d5828c..75ebe0db64 100644 --- a/src/codex/quota-auto-refresh-state.ts +++ b/src/codex/quota-auto-refresh-state.ts @@ -7,6 +7,7 @@ export const retryAfterByAccount = new Map(); export const scheduledByAccount = new Map(); export const quotaRefreshAfterByAccount = new Map(); +/** Drop every activation record when its account is removed. */ export function forgetCodexQuotaAutoRefreshAccount(accountId: string): void { completedByAccount.delete(accountId); retryAfterByAccount.delete(accountId); @@ -14,6 +15,7 @@ export function forgetCodexQuotaAutoRefreshAccount(accountId: string): void { quotaRefreshAfterByAccount.delete(accountId); } +/** Clear the dependency-free activation bookkeeping for isolated tests. */ export function resetCodexQuotaAutoRefreshStateForTests(): void { completedByAccount.clear(); retryAfterByAccount.clear(); diff --git a/src/codex/quota-auto-refresh.ts b/src/codex/quota-auto-refresh.ts index b61cc1467e..bb3d001e2e 100644 --- a/src/codex/quota-auto-refresh.ts +++ b/src/codex/quota-auto-refresh.ts @@ -51,6 +51,7 @@ export interface CodexQuotaAutoRefreshRunDeps { let inFlight: Promise | null = null; +/** Report upstream window availability separately from persisted spending intent. */ export function codexQuotaAutoRefreshStatus( config: OcxConfig, accountId: string, @@ -66,6 +67,7 @@ export function codexQuotaAutoRefreshStatus( }; } +/** Select retained, enabled boundaries newer than both durable and in-memory completions. */ export function dueCodexQuotaAutoRefreshWindows( config: OcxConfig, accountId: string, @@ -145,17 +147,20 @@ function rememberWindows(config: OcxConfig, accountId: string, quota: StoredAcco } } +/** Load metadata recovery only when an opted-in account actually needs a probe. */ async function refreshQuota(config: OcxConfig, accountId: string): Promise { const { refreshCodexQuotaForActivation } = await import("./auth-api"); await refreshCodexQuotaForActivation(config, accountId); } +/** Keep billable main-account work behind the current pause, reauth and hard-lock policy. */ function mainWarmupRestricted(config: OcxConfig): boolean { return isMainAccountHardLocked(config) || isCodexAccountPaused(config, MAIN_CODEX_ACCOUNT_ID) || isAccountNeedsReauth(MAIN_CODEX_ACCOUNT_ID); } +/** Warm the exact account and fence quota/reauth publication to the dispatched credential. */ async function warmAccount(config: OcxConfig, accountId: string): Promise { const writerGeneration = captureConfigGeneration(); if (accountId !== MAIN_CODEX_ACCOUNT_ID) { @@ -207,6 +212,7 @@ async function warmAccount(config: OcxConfig, accountId: string): Promise, @@ -247,6 +254,7 @@ function retryPendingMarkers( } } +/** Coalesce sweeps, refresh stale metadata and activate due accounts with bounded concurrency. */ export async function runCodexQuotaAutoRefresh( config: OcxConfig, now = Date.now(), @@ -266,6 +274,7 @@ export async function runCodexQuotaAutoRefresh( MAIN_CODEX_ACCOUNT_ID, ...(config.codexAccounts ?? []).filter(isSelectableCodexPoolAccount).map(account => account.id), ]; + /** Recheck spending authorization after asynchronous metadata work. */ const eligible = (accountId: string) => { const setting = config.codexQuotaAutoRefresh?.[accountId]; const provider = config.providers[OPENAI_CODEX_PROVIDER_ID]; @@ -314,6 +323,7 @@ export async function runCodexQuotaAutoRefresh( return inFlight; } +/** Attach activation to the shared minute sweep and return its owner-scoped cleanup. */ export function registerCodexQuotaAutoRefreshWorker(config: OcxConfig): () => void { return registerStateSweepAfterTick({ name: "codex-quota-auto-refresh", @@ -321,6 +331,7 @@ export function registerCodexQuotaAutoRefreshWorker(config: OcxConfig): () => vo }); } +/** Clear scheduling and single-flight state between isolated test cases. */ export function resetCodexQuotaAutoRefreshForTests(): void { inFlight = null; resetCodexQuotaAutoRefreshStateForTests(); diff --git a/src/codex/warmup.ts b/src/codex/warmup.ts index cc2f10ac55..5af42490b4 100644 --- a/src/codex/warmup.ts +++ b/src/codex/warmup.ts @@ -215,6 +215,7 @@ async function drainWarmupSse(body: ReadableStream, signal: AbortSig } } +/** Bound one inference attempt and publish metadata only after a successful terminal event. */ async function tryWarmup(options: CodexWarmupOptions, model: string): Promise { const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS; if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 0 || timeoutMs > MAX_TIMEOUT_MS) { diff --git a/tests/codex-integration/codex-quota-auto-refresh.test.ts b/tests/codex-integration/codex-quota-auto-refresh.test.ts index 7bbe2ae73e..e0d765dea3 100644 --- a/tests/codex-integration/codex-quota-auto-refresh.test.ts +++ b/tests/codex-integration/codex-quota-auto-refresh.test.ts @@ -11,6 +11,7 @@ import { } from "../../src/codex/quota-auto-refresh"; import { clearAccountQuota, + getAccountQuota, setAccountQuotaFromParsed, type StoredAccountQuota, } from "../../src/codex/quota"; @@ -18,11 +19,30 @@ import { handleManagementAPI, type ManagementApiDeps } from "../../src/server/ma import { loadConfig, readConfigDiagnostics, validateConfigCandidate } from "../../src/config"; import type { OcxConfig } from "../../src/types"; import { startupHealthFixture } from "../helpers/startup-health"; +import { saveCodexAccountCredential } from "../../src/codex/account-store"; +import { clearAccountNeedsReauth, isAccountNeedsReauth } from "../../src/codex/account-runtime-state"; const NOW = 1_800_000_000_000; const RESET_SECONDS = NOW / 1000; let testHome = ""; let previousHome: string | undefined; +let previousFetch: typeof fetch; + +function writePoolCredential(accessToken = "activation-fixture") { + saveCodexAccountCredential("pool-a", { + accessToken, refreshToken: "activation-refresh-fixture", + expiresAt: NOW + 86_400_000, chatgptAccountId: "activation-workspace-fixture", + }); +} + +function completedWithQuota(resetAt: number) { + return new Response('data: {"type":"response.completed"}\n\n', { headers: { + "content-type": "text/event-stream", + "x-codex-primary-used-percent": "0", + "x-codex-primary-window-minutes": "300", + "x-codex-primary-reset-at": String(resetAt), + } }); +} function config(): OcxConfig { return { @@ -85,6 +105,7 @@ function putSettings(cfg: OcxConfig, value: unknown): Promise { } beforeEach(() => { + previousFetch = globalThis.fetch; previousHome = process.env.OPENCODEX_HOME; testHome = mkdtempSync(join(tmpdir(), "ocx-quota-auto-refresh-")); process.env.OPENCODEX_HOME = testHome; @@ -93,6 +114,8 @@ beforeEach(() => { }); afterEach(() => { + globalThis.fetch = previousFetch; + clearAccountNeedsReauth("pool-a"); clearAccountQuota(); resetCodexQuotaAutoRefreshForTests(); if (previousHome === undefined) delete process.env.OPENCODEX_HOME; @@ -101,6 +124,99 @@ afterEach(() => { }); describe("Codex quota window auto refresh", () => { + test("regression: successive idle windows use completed response quota headers", async () => { + const cfg = config(); + cfg.codexQuotaAutoRefresh = { "pool-a": { fiveHour: true } }; + writeFileSync(join(testHome, "config.json"), JSON.stringify(cfg)); + writePoolCredential(); + setAccountQuotaFromParsed("pool-a", quota({ shortPercent: 100 })); + let calls = 0; + globalThis.fetch = Object.assign(async () => completedWithQuota(RESET_SECONDS + ++calls * 18_000), + { preconnect: previousFetch.preconnect }); + const deps = { refreshQuota: async () => {} }; + await runCodexQuotaAutoRefresh(cfg, NOW, deps); + expect(getAccountQuota("pool-a")).toMatchObject({ shortPercent: 0, shortResetAt: RESET_SECONDS + 18_000 }); + resetCodexQuotaAutoRefreshForTests(); + await runCodexQuotaAutoRefresh(loadConfig(), NOW + 18_000_000, deps); + expect(calls).toBe(2); + expect(loadConfig().codexQuotaAutoRefresh?.["pool-a"]?.lastFiveHourResetAt).toBe(NOW + 18_000_000); + }); + + test("regression: failed windows survive shifted metadata and restart", async () => { + let cfg = config(); + writeFileSync(join(testHome, "config.json"), JSON.stringify(cfg)); + let observed = quota(); + let calls = 0; + const deps = { + getQuota: (id: string) => id === "pool-a" ? observed : null, + refreshQuota: async () => {}, + warmAccount: async () => { if (++calls === 1) throw new Error("fixture failure"); }, + }; + await runCodexQuotaAutoRefresh(cfg, NOW, deps); + expect(loadConfig().codexQuotaAutoRefresh?.["pool-a"]).toMatchObject({ + nextFiveHourResetAt: NOW, nextWeeklyResetAt: NOW, + }); + observed = quota({ shortResetAt: RESET_SECONDS + 18_000, weeklyResetAt: RESET_SECONDS + 604_800 }); + resetCodexQuotaAutoRefreshForTests(); + cfg = loadConfig(); + await runCodexQuotaAutoRefresh(cfg, NOW + 300_000, deps); + expect(calls).toBe(2); + expect(loadConfig().codexQuotaAutoRefresh?.["pool-a"]).toMatchObject({ + lastFiveHourResetAt: NOW, lastWeeklyResetAt: NOW, + }); + await runCodexQuotaAutoRefresh(cfg, NOW + 300_001, deps); + expect(calls).toBe(2); + }); + + test("regression: stale idle metadata refresh is bounded and disabled accounts do not probe", async () => { + const cfg = config(); + let probes = 0; + let warmups = 0; + const deps = { + getQuota: () => null, + refreshQuota: async () => { probes += 1; }, + warmAccount: async () => { warmups += 1; }, + }; + await runCodexQuotaAutoRefresh(cfg, NOW, deps); + await runCodexQuotaAutoRefresh(cfg, NOW + 299_999, deps); + expect(probes).toBe(1); + await runCodexQuotaAutoRefresh(cfg, NOW + 300_000, deps); + expect(probes).toBe(2); + cfg.codexQuotaAutoRefresh = {}; + await runCodexQuotaAutoRefresh(cfg, NOW + 600_000, deps); + expect(probes).toBe(2); + expect(warmups).toBe(0); + }); + + test("regression: inference 401 quarantines a time-valid bearer and stops retries", async () => { + const cfg = config(); + writePoolCredential(); + setAccountQuotaFromParsed("pool-a", quota()); + const request = spyOn(globalThis, "fetch").mockResolvedValue(new Response("{}", { status: 401 })); + try { + const deps = { refreshQuota: async () => {}, persistCompleted: recordMarkers }; + await runCodexQuotaAutoRefresh(cfg, NOW, deps); + expect(isAccountNeedsReauth("pool-a")).toBe(true); + await runCodexQuotaAutoRefresh(cfg, NOW + 300_000, deps); + expect(request).toHaveBeenCalledTimes(1); + expect(cfg.codexQuotaAutoRefresh?.["pool-a"]?.lastWeeklyResetAt).toBeUndefined(); + } finally { request.mockRestore(); } + }); + + test.each([200, 401])("regression: late HTTP %i cannot publish quota or quarantine replacement credentials", async status => { + const cfg = config(); + writePoolCredential(); + setAccountQuotaFromParsed("pool-a", quota({ shortPercent: 90 })); + globalThis.fetch = Object.assign(async () => { + writePoolCredential("replacement-fixture"); + return status === 200 ? completedWithQuota(RESET_SECONDS + 18_000) : new Response("{}", { status }); + }, { preconnect: previousFetch.preconnect }); + await runCodexQuotaAutoRefresh(cfg, NOW, { refreshQuota: async () => {}, persistCompleted: recordMarkers }); + expect(isAccountNeedsReauth("pool-a")).toBe(false); + expect(getAccountQuota("pool-a")).toMatchObject({ shortPercent: 90, shortResetAt: RESET_SECONDS }); + expect(cfg.codexQuotaAutoRefresh?.["pool-a"]?.lastFiveHourResetAt).toBeUndefined(); + }); + test("detects only reported 5-hour and weekly capabilities", () => { const cfg = config(); expect(codexQuotaAutoRefreshStatus(cfg, "pool-a", quota())).toEqual({ diff --git a/tests/codex-integration/codex-warmup.test.ts b/tests/codex-integration/codex-warmup.test.ts index 14dd1455ff..d186fb7221 100644 --- a/tests/codex-integration/codex-warmup.test.ts +++ b/tests/codex-integration/codex-warmup.test.ts @@ -12,6 +12,29 @@ afterEach(() => { }); describe("codex warmup", () => { + test("regression: failed streams never publish completion metadata", async () => { + let publications = 0; + globalThis.fetch = (async () => sseResponse('data: {"type":"response.failed"}\n\n')) as typeof fetch; + await expect(warmCodexAccount({ accessToken: "fixture", chatgptAccountId: "fixture", + onCompleted: () => { publications += 1; }, + })).rejects.toMatchObject({ code: "stream_failed" }); + expect(publications).toBe(0); + }); + + test("regression: metadata publication failure never retries completed inference", async () => { + let requests = 0; + let publications = 0; + globalThis.fetch = (async () => { + requests += 1; + return sseResponse('data: {"type":"response.completed"}\n\n'); + }) as typeof fetch; + await expect(warmCodexAccount({ accessToken: "fixture", chatgptAccountId: "fixture", + onCompleted: () => { publications += 1; throw new Error("fixture metadata failure"); }, + })).resolves.toBeUndefined(); + expect(publications).toBe(1); + expect(requests).toBe(1); + }); + test("posts a minimal gpt-5.4-mini Responses stream request and accepts response.completed", async () => { let body: Record | undefined; let auth: string | null = null; From 6bcf86492502e1db00a6f2888c4669298ee40403 Mon Sep 17 00:00:00 2001 From: yhualin Date: Mon, 7 Sep 2026 11:07:32 +0800 Subject: [PATCH 088/412] fix(transport): admit Mihomo IPv6 fake-IP under TUN transparency exception for canonical URLs (cherry picked from commit 38308625da4d2f88d4f4790c0b8ce0eccda13648) Co-authored-by: hualiny <82697947+hualiny@users.noreply.github.com> --- src/lib/provider-outbound.ts | 15 +++++++-------- tests/providers/provider-account-quota.test.ts | 4 ++-- tests/providers/provider-outbound.test.ts | 17 +++++++++++++++++ tests/providers/provider-quota.test.ts | 2 +- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/src/lib/provider-outbound.ts b/src/lib/provider-outbound.ts index 02bdbc2077..95341573d1 100644 --- a/src/lib/provider-outbound.ts +++ b/src/lib/provider-outbound.ts @@ -143,11 +143,12 @@ async function providerOutboundRequest( // below reason about the same value. `null` here means "no proxy fetch would actually use", // even if some other proxy variable is set. const effectiveProxy = effectiveProxyFor(parsed); - const allowMihomoIpv6FakeIp = effectiveProxy !== null && !noProxyMatches(parsed); + const isCanonicalUrl = dependencies.isCanonicalUrl ?? (() => false); + const allowMihomoIpv6FakeIp = (effectiveProxy !== null && !noProxyMatches(parsed)) + || transparentFakeIpException(url, parsed, isCanonicalUrl, name); const resolveAddresses = dependencies.resolveAddresses ?? resolvePublicAddresses; const pinnedGet = dependencies.pinnedGet ?? pinnedHttpGet; const pinnedPost = dependencies.pinnedPost ?? pinnedHttpPost; - const isCanonicalUrl = dependencies.isCanonicalUrl ?? (() => false); const allowPrivate = providerAllowsPrivateNetwork(name, provider); let resolved: Awaited>; try { @@ -169,11 +170,9 @@ async function providerOutboundRequest( // pinned to the registry destination independently. allowBenchmarkAddresses: (proxyConfigured && !noProxyMatches(parsed)) || transparentFakeIpException(url, parsed, isCanonicalUrl, name), - // Mihomo IPv6 fake-IP (fdfe:dcba:9876::/48) answers are admitted on a stricter gate - // than the benchmark range: the proxy must be the one fetch will use for this URL's - // scheme, and the request below is then bound to it explicitly (#3462). A ULA answer - // is otherwise indistinguishable from a real private host, so proxy presence alone - // is not enough. + // Mihomo IPv6 fake-IP (fdfe:dcba:9876::/48) answers are admitted either when bound + // to a scheme-matched proxy (#3462) or under the TUN transparency exception for a + // canonical registry/accounting destination. allowMihomoIpv6FakeIp, }); } catch (error) { @@ -191,7 +190,7 @@ async function providerOutboundRequest( warnProxyBoundaryOnce(); // When the Mihomo exception could have admitted an answer, pin the transport to the // proxy the admission assumed instead of letting fetch re-infer it from the environment. - const proxy = allowMihomoIpv6FakeIp ? effectiveProxy : undefined; + const proxy = (allowMihomoIpv6FakeIp && effectiveProxy) ? effectiveProxy : undefined; return globalThis.fetch(url, { ...init, method, redirect: "manual", ...(proxy ? { proxy } : {}) }); } if (proxyConfigured && resolved.privateNetwork && !noProxyMatches(parsed)) { diff --git a/tests/providers/provider-account-quota.test.ts b/tests/providers/provider-account-quota.test.ts index 1b940d71d0..e8e05de9d6 100644 --- a/tests/providers/provider-account-quota.test.ts +++ b/tests/providers/provider-account-quota.test.ts @@ -796,8 +796,8 @@ describe("google-antigravity per-account quota (#1082)", () => { expect(posted).toHaveLength(urls.length * 2); for (const url of urls) { expect(resolved.filter(row => row.url === url)).toEqual([ - { url, benchmark: true, private: false, mihomo: false }, - { url, benchmark: true, private: false, mihomo: false }, + { url, benchmark: true, private: false, mihomo: true }, + { url, benchmark: true, private: false, mihomo: true }, ]); } for (const [auth, project] of [["Bearer agy-first", "proj-first"], ["Bearer agy-second", "proj-second"]]) { diff --git a/tests/providers/provider-outbound.test.ts b/tests/providers/provider-outbound.test.ts index 2853e0e335..1e80634395 100644 --- a/tests/providers/provider-outbound.test.ts +++ b/tests/providers/provider-outbound.test.ts @@ -501,6 +501,23 @@ describe("#3462 Mihomo IPv6 fake-IP admission is gated on the scheme-matched pro expect(resolveOptions).toEqual([{ allowMihomoIpv6FakeIp: false }]); expect(fetchInits).toHaveLength(0); }); + + test("canonical destination without proxy env: admitted under TUN transparentFakeIpException", async () => { + for (const key of proxyKeys) delete process.env[key]; + const { providerOutboundGet } = await import("../../src/lib/provider-outbound"); + const resolveOptions: Captured[] = []; + const { dependencies, captured } = directDependencies(new Response(null, { status: 200 })); + dependencies.isCanonicalUrl = (name, url) => name === "opencode-go" && url === target; + dependencies.resolveAddresses = mock(async (_url: string, options?: Captured) => { + resolveOptions.push({ allowMihomoIpv6FakeIp: options?.allowMihomoIpv6FakeIp }); + return { hostname: "opencode.ai", addresses: [{ address: ULA, family: 6 }, { address: "198.18.0.1", family: 4 }], privateNetwork: false }; + }) as ProviderOutboundDependencies["resolveAddresses"]; + + const response = await providerOutboundGet("opencode-go", { baseUrl: "https://opencode.ai/zen/v1" }, target, {}, dependencies); + expect(response.status).toBe(200); + expect(resolveOptions).toEqual([{ allowMihomoIpv6FakeIp: true }]); + expect(captured.address).toBe("198.18.0.1"); + }); }); describe("effectiveProxyFor picks the variable Bun fetch actually honours", () => { diff --git a/tests/providers/provider-quota.test.ts b/tests/providers/provider-quota.test.ts index 9c12869b04..a8d4bef728 100644 --- a/tests/providers/provider-quota.test.ts +++ b/tests/providers/provider-quota.test.ts @@ -3159,7 +3159,7 @@ describe("fetchProviderQuotaReports", () => { }); const result = await fetchProviderQuotaReports(config(), true); const urls = fallback ? [summaryUrl, modelsUrl] : [summaryUrl]; - expect(resolved).toEqual(urls.map(url => ({ url, benchmark: true, private: false, mihomo: false }))); + expect(resolved).toEqual(urls.map(url => ({ url, benchmark: true, private: false, mihomo: true }))); expect(posted).toEqual(urls.map(url => ({ url, address: "198.18.56.214", tls: true, auth: "Bearer agy-canonical-access", body: JSON.stringify({ project: "agy-canonical-project" }), signal: true }))); expect(result.reports[0]?.source).toBe(fallback ? "google-antigravity:fetchAvailableModels" : "google-antigravity:retrieveUserQuotaSummary"); expect(result.reports[0]?.quota.customWindows).toEqual([{ label: "Gem", percent: fallback ? 25 : 40 }]); From bdd4e460e6ccede4623996fed74db1d32c786ab3 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 18:27:46 +0900 Subject: [PATCH 089/412] fix(transport): retain IPv6 pinning across proxy mismatches [skip ci] Co-authored-by: hualiny <82697947+hualiny@users.noreply.github.com> --- src/lib/provider-outbound.ts | 6 +- tests/fixtures/provider-outbound-mihomo.ts | 106 +++++++++++++++++++++ tests/providers/provider-outbound.test.ts | 12 +++ 3 files changed, 122 insertions(+), 2 deletions(-) create mode 100644 tests/fixtures/provider-outbound-mihomo.ts diff --git a/src/lib/provider-outbound.ts b/src/lib/provider-outbound.ts index 95341573d1..334f46dad5 100644 --- a/src/lib/provider-outbound.ts +++ b/src/lib/provider-outbound.ts @@ -42,7 +42,7 @@ function pickPinnedAddress(addresses: Array<{ address: string; family: number }> * * Under TUN mode the packet path intercepts the fake-IP destination itself, so a * canonical registry destination whose local DNS answers include Clash fake-IP - * space (198.18.0.0/15) is reachable by pin-connecting through the TUN — no + * space (198.18.0.0/15 or fdfe:dcba:9876::/48) is reachable by pin-connecting through the TUN — no * outbound HTTP(S) proxy env is required. The exception is deliberately narrow: * * - hostname-only: a literal 198.18.x.x URL never reaches it (the literal gate @@ -186,7 +186,9 @@ async function providerOutboundRequest( warnProxyDnsDegradationOnce(); return globalThis.fetch(url, { ...init, method, redirect: "manual" }); } - if (proxyConfigured && !resolved.privateNetwork) { + // A canonical TUN exception with no scheme-matched proxy must retain the + // validated address, even when an unrelated HTTP_PROXY/ALL_PROXY is present. + if (proxyConfigured && !resolved.privateNetwork && (effectiveProxy !== null || !allowMihomoIpv6FakeIp)) { warnProxyBoundaryOnce(); // When the Mihomo exception could have admitted an answer, pin the transport to the // proxy the admission assumed instead of letting fetch re-infer it from the environment. diff --git a/tests/fixtures/provider-outbound-mihomo.ts b/tests/fixtures/provider-outbound-mihomo.ts new file mode 100644 index 0000000000..25eb6eb68f --- /dev/null +++ b/tests/fixtures/provider-outbound-mihomo.ts @@ -0,0 +1,106 @@ +import assert from "node:assert/strict"; +import { mock } from "bun:test"; +import type { ProviderOutboundDependencies } from "../../src/lib/provider-outbound"; +import { PROXY_ENV_KEYS } from "../../src/lib/proxy-env"; + +// Isolate the DNS module mock from other tests while exercising the real classifier. +let answers: { address: string; family: number }[] = []; +mock.module("node:dns/promises", () => ({ lookup: async () => answers })); +const { providerOutboundGet, providerOutboundPost, ProviderOutboundPolicyError } = await import("../../src/lib/provider-outbound"); +const target = "https://opencode.ai/zen/v1/models"; +const fake = { address: "fdfe:dcba:9876::1", family: 6 }; +const body = '{"project":"mihomo-fixture"}'; +let ipv6Pinned = 0; +let proxyBound = 0; +let denied = 0; + +for (const method of ["GET", "POST"] as const) { + async function attempt( + env: Record, + dns: typeof answers, + expected: "pinned" | "proxy" | "denied", + url = target, + proof: "canonical" | "missing" | "noncanonical" = "canonical", + ) { + for (const key of PROXY_ENV_KEYS.flatMap(key => [key, key.toLowerCase()])) delete process.env[key]; + Object.assign(process.env, env); + answers = dns; + let pinnedCalls = 0; + let fetchCalls = 0; + const originalFetch = globalThis.fetch; + const capture: NonNullable = async (requestUrl, address, _signal, options) => { + pinnedCalls++; + assert.equal(expected, "pinned"); + assert.equal(requestUrl, target); + assert.deepEqual(address, fake); + assert.equal(options?.rejectUnauthorized, true); + assert.equal(new Headers(options?.headers).get("authorization"), "Bearer mihomo-fixture"); + return new Response("pinned"); + }; + const dependencies: ProviderOutboundDependencies = { + ...(proof !== "missing" ? { isCanonicalUrl: (name: string, value: string) => proof === "canonical" && name === "opencode-go" && value === url } : {}), + pinnedGet: capture, + pinnedPost: async (requestUrl, address, requestBody, signal, options) => { + assert.equal(method, "POST"); + assert.equal(requestBody, body); + return capture(requestUrl, address, signal, options); + }, + }; + globalThis.fetch = Object.assign(async (input: Parameters[0], init?: RequestInit & { proxy?: string }) => { + fetchCalls++; + assert.equal(expected, "proxy"); + assert.equal(String(input), target); + assert.equal(init?.proxy, "http://127.0.0.1:7897"); + assert.equal(init?.redirect, "manual"); + assert.equal(init?.method, method); + if (method === "POST") assert.equal(init?.body, body); + return new Response("proxy"); + }, { preconnect: originalFetch.preconnect }); + try { + const provider = { baseUrl: "https://opencode.ai/zen/v1" }; + const init = { headers: { authorization: "Bearer mihomo-fixture" } }; + const request = method === "GET" + ? providerOutboundGet("opencode-go", provider, url, init, dependencies) + : providerOutboundPost("opencode-go", provider, url, { ...init, body }, dependencies); + if (expected === "denied") { + await assert.rejects(request, ProviderOutboundPolicyError); + assert.equal(pinnedCalls, 0); + assert.equal(fetchCalls, 0); + denied++; + } else { + assert.equal(await (await request).text(), expected); + assert.equal(pinnedCalls, expected === "pinned" ? 1 : 0); + assert.equal(fetchCalls, expected === "proxy" ? 1 : 0); + if (expected === "pinned") ipv6Pinned++; + else proxyBound++; + } + } finally { + globalThis.fetch = originalFetch; + } + } + + // TUN handles the validated IPv6 address even if unrelated proxy variables exist. + const directEnvs: Record[] = [{}, { HTTP_PROXY: "http://127.0.0.1:7897" }, { ALL_PROXY: "socks5://127.0.0.1:7891" }]; + for (const env of directEnvs) { + await attempt(env, [fake], "pinned"); + } + await attempt({ HTTPS_PROXY: "http://127.0.0.1:7897" }, [fake], "proxy"); + + for (const noProxy of ["opencode.ai", ".opencode.ai", "*"]) { + const noProxyEnvs: Record[] = [{ NO_PROXY: noProxy }, { NO_PROXY: noProxy, HTTPS_PROXY: "http://127.0.0.1:7897" }]; + for (const env of noProxyEnvs) { + await attempt(env, [fake], "denied"); + } + } + for (const address of ["127.0.0.1", "10.0.0.5", "169.254.169.254", "169.254.1.2", "::1", "fd00::1", "fe80::1", "::", "fdfe:dcba:9877::1"]) { + const unsafe = { address, family: address.includes(":") ? 6 : 4 }; + await attempt({}, [fake, unsafe], "denied"); + await attempt({}, [unsafe, fake], "denied"); + } + await attempt({}, [fake], "denied", target, "missing"); + await attempt({}, [fake], "denied", "https://custom.example/v1/models", "noncanonical"); + // Even an erroneous canonical proof cannot admit a literal fake IP. + await attempt({}, [fake], "denied", "https://[fdfe:dcba:9876::1]/v1/models"); +} + +console.log(JSON.stringify({ ipv6Pinned, proxyBound, denied })); diff --git a/tests/providers/provider-outbound.test.ts b/tests/providers/provider-outbound.test.ts index 1e80634395..dca53eefe4 100644 --- a/tests/providers/provider-outbound.test.ts +++ b/tests/providers/provider-outbound.test.ts @@ -5,6 +5,7 @@ import { join } from "node:path"; import type { ProviderOutboundDependencies } from "../../src/lib/provider-outbound"; import { PROXY_ENV_KEYS } from "../../src/lib/proxy-env"; import { removeTreeWithRetry } from "../helpers/remove-tree"; +import { fixturePath, repoRoot } from "../helpers/repo-root"; const proxyKeys = PROXY_ENV_KEYS.flatMap(key => [key, key.toLowerCase()]); const originalProxyEnv = Object.fromEntries(proxyKeys.map(key => [key, process.env[key]])); @@ -427,6 +428,17 @@ describe("#3462 Mihomo IPv6 fake-IP admission is gated on the scheme-matched pro const ULA = "fdfe:dcba:9876::7e"; const target = "https://opencode.ai/zen/v1/models"; + test("canonical IPv6-only TUN transport preserves pinning and rejects unsafe DNS answers", async () => { + const child = Bun.spawn([process.execPath, fixturePath("provider-outbound-mihomo.ts")], { + cwd: repoRoot(), stdout: "pipe", stderr: "pipe", + }); + const [stdout, stderr, exitCode] = await Promise.all([ + new Response(child.stdout).text(), new Response(child.stderr).text(), child.exited, + ]); + if (exitCode !== 0) throw new Error(`Mihomo fixture exited ${exitCode}: ${stderr}`); + expect(JSON.parse(stdout.trim())).toEqual({ ipv6Pinned: 6, proxyBound: 2, denied: 54 }); + }); + async function run(env: Record, opts: { admit: boolean }) { for (const key of proxyKeys) delete process.env[key]; for (const [k, v] of Object.entries(env)) process.env[k] = v; From a814dd3aadace7d3bd0b8dd02b7e2b2705f5b196 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 18:40:45 +0900 Subject: [PATCH 090/412] test(transport): run DNS fixture in the Bun test loader [skip ci] Co-authored-by: hualiny <82697947+hualiny@users.noreply.github.com> --- tests/fixtures/provider-outbound-mihomo.ts | 7 ++++-- tests/providers/provider-outbound.test.ts | 29 +++++++++++++++------- 2 files changed, 25 insertions(+), 11 deletions(-) diff --git a/tests/fixtures/provider-outbound-mihomo.ts b/tests/fixtures/provider-outbound-mihomo.ts index 25eb6eb68f..e376d8246b 100644 --- a/tests/fixtures/provider-outbound-mihomo.ts +++ b/tests/fixtures/provider-outbound-mihomo.ts @@ -5,7 +5,8 @@ import { PROXY_ENV_KEYS } from "../../src/lib/proxy-env"; // Isolate the DNS module mock from other tests while exercising the real classifier. let answers: { address: string; family: number }[] = []; -mock.module("node:dns/promises", () => ({ lookup: async () => answers })); +let dnsCalls = 0; +mock.module("node:dns/promises", () => ({ lookup: async () => { dnsCalls++; return answers; } })); const { providerOutboundGet, providerOutboundPost, ProviderOutboundPolicyError } = await import("../../src/lib/provider-outbound"); const target = "https://opencode.ai/zen/v1/models"; const fake = { address: "fdfe:dcba:9876::1", family: 6 }; @@ -25,6 +26,7 @@ for (const method of ["GET", "POST"] as const) { for (const key of PROXY_ENV_KEYS.flatMap(key => [key, key.toLowerCase()])) delete process.env[key]; Object.assign(process.env, env); answers = dns; + dnsCalls = 0; let pinnedCalls = 0; let fetchCalls = 0; const originalFetch = globalThis.fetch; @@ -74,6 +76,7 @@ for (const method of ["GET", "POST"] as const) { if (expected === "pinned") ipv6Pinned++; else proxyBound++; } + assert.equal(dnsCalls, url.startsWith("https://[") ? 0 : 1, "hostname requests must use the isolated DNS mock"); } finally { globalThis.fetch = originalFetch; } @@ -103,4 +106,4 @@ for (const method of ["GET", "POST"] as const) { await attempt({}, [fake], "denied", "https://[fdfe:dcba:9876::1]/v1/models"); } -console.log(JSON.stringify({ ipv6Pinned, proxyBound, denied })); +console.log("MIHOMO_RESULT=" + JSON.stringify({ ipv6Pinned, proxyBound, denied })); diff --git a/tests/providers/provider-outbound.test.ts b/tests/providers/provider-outbound.test.ts index dca53eefe4..9907c23664 100644 --- a/tests/providers/provider-outbound.test.ts +++ b/tests/providers/provider-outbound.test.ts @@ -1,7 +1,8 @@ import { afterEach, describe, expect, mock, test } from "bun:test"; -import { mkdtempSync} from "node:fs"; +import { mkdtempSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; +import { pathToFileURL } from "node:url"; import type { ProviderOutboundDependencies } from "../../src/lib/provider-outbound"; import { PROXY_ENV_KEYS } from "../../src/lib/proxy-env"; import { removeTreeWithRetry } from "../helpers/remove-tree"; @@ -429,14 +430,24 @@ describe("#3462 Mihomo IPv6 fake-IP admission is gated on the scheme-matched pro const target = "https://opencode.ai/zen/v1/models"; test("canonical IPv6-only TUN transport preserves pinning and rejects unsafe DNS answers", async () => { - const child = Bun.spawn([process.execPath, fixturePath("provider-outbound-mihomo.ts")], { - cwd: repoRoot(), stdout: "pipe", stderr: "pipe", - }); - const [stdout, stderr, exitCode] = await Promise.all([ - new Response(child.stdout).text(), new Response(child.stderr).text(), child.exited, - ]); - if (exitCode !== 0) throw new Error(`Mihomo fixture exited ${exitCode}: ${stderr}`); - expect(JSON.parse(stdout.trim())).toEqual({ ipv6Pinned: 6, proxyBound: 2, denied: 54 }); + const childDir = mkdtempSync(join(tmpdir(), "ocx-mihomo-test-")); + const childTest = join(childDir, "mihomo.test.ts"); + // Builtin module mocks are activated by Bun's test loader, not plain bun execution. + writeFileSync(childTest, `import { test } from "bun:test";\ntest("Mihomo matrix", async () => { await import(${JSON.stringify(pathToFileURL(fixturePath("provider-outbound-mihomo.ts")).href)}); });\n`); + try { + const child = Bun.spawn([process.execPath, "test", childTest], { + cwd: repoRoot(), stdout: "pipe", stderr: "pipe", + }); + const [stdout, stderr, exitCode] = await Promise.all([ + new Response(child.stdout).text(), new Response(child.stderr).text(), child.exited, + ]); + if (exitCode !== 0) throw new Error(`Mihomo fixture exited ${exitCode}: ${stderr}`); + const result = stdout.split(/\r?\n/).find(line => line.startsWith("MIHOMO_RESULT=")); + expect(result).toBeDefined(); + expect(JSON.parse(result!.slice("MIHOMO_RESULT=".length))).toEqual({ ipv6Pinned: 6, proxyBound: 2, denied: 54 }); + } finally { + removeTreeWithRetry(childDir); + } }); async function run(env: Record, opts: { admit: boolean }) { From 3955e10402dd12298a2fd6bf7cf9040daa02eb44 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 18:25:42 +0900 Subject: [PATCH 091/412] fix(codex): fence main quota activation recovery [skip ci] Co-authored-by: terrytan95 <10609214+terrytan95@users.noreply.github.com> --- src/codex/auth-api.ts | 23 ++++- src/codex/quota-auto-refresh.ts | 19 +++- ...-quota-auto-refresh-main-admission.test.ts | 91 ++++++++++++++++++- 3 files changed, 126 insertions(+), 7 deletions(-) diff --git a/src/codex/auth-api.ts b/src/codex/auth-api.ts index 8ab7f7418f..6768c4fa09 100644 --- a/src/codex/auth-api.ts +++ b/src/codex/auth-api.ts @@ -1838,7 +1838,28 @@ export async function listCodexAuthAccountsSnapshot( /** One opted-in account's metadata; reuse the bounded WHAM 401 recovery and generation fence. */ export async function refreshCodexQuotaForActivation(config: OcxConfig, accountId: string): Promise { if (accountId === MAIN_CODEX_ACCOUNT_ID) { - await fetchMainAccountInfoAttempt(true, 1, undefined, false, false); + const lease = tryAcquireNativeMainProfileClaim(); + if (!lease) return; + try { + reconcileMainCodexAccountRuntimeState(); + if (isAccountNeedsReauth(accountId)) return; + const identityGeneration = captureMainAccountIdentityGeneration(); + const writerGeneration = captureConfigGeneration(); + try { + // Refresh may need an exclusive claim; prepare before WHAM takes its shared claim. + if (!await getValidMainAccountToken({ preserveReauth: true })) return; + } catch (error) { + if (error instanceof MainAccountTokenRefreshError && error.reason === "reauth" + && isMainAccountIdentityGenerationLive(identityGeneration)) { + markAccountNeedsReauth(accountId, writerGeneration); + } + return; + } + if (isAccountNeedsReauth(accountId)) return; + await fetchMainAccountInfoAttempt(true, 1, lease, false, false); + } finally { + lease.release(); + } return; } const account = configuredPoolAccount(config, accountId); diff --git a/src/codex/quota-auto-refresh.ts b/src/codex/quota-auto-refresh.ts index bb3d001e2e..26b88a886c 100644 --- a/src/codex/quota-auto-refresh.ts +++ b/src/codex/quota-auto-refresh.ts @@ -15,7 +15,7 @@ import { isMainAccountHardLocked } from "./main-account-hard-lock"; import { tryAcquireNativeMainProfileClaim } from "./native-main-admission"; import { withNativeMainSharedClaim } from "./native-main-claim"; import { resolveNativeProfileContext } from "./native-profile-store"; -import { captureMainQuotaWriter } from "./main-account-cache"; +import { getMainQuotaCredentialGeneration, observeMainQuotaCredential } from "./main-account-cache"; import { applyAccountQuotaFromUpstreamHeaders, getAccountQuota, type StoredAccountQuota } from "./quota"; import { CodexWarmupError, codexWarmupFailureReason, warmCodexAccount } from "./warmup"; import { @@ -194,18 +194,29 @@ async function warmAccount(config: OcxConfig, accountId: string): Promise { + reconcileMainCodexAccountRuntimeState(); + const current = getMainAccountToken(); + return current?.accessToken === token.accessToken + && current.chatgptAccountId === token.chatgptAccountId + && getMainQuotaCredentialGeneration() === credentialGeneration; + }; try { await warmCodexAccount({ ...token, onCompleted: headers => { - if (writer) applyAccountQuotaFromUpstreamHeaders(accountId, headers, writerGeneration, writer); + if (writer && credentialStillLive()) { + applyAccountQuotaFromUpstreamHeaders(accountId, headers, writerGeneration, writer); + } } }); } catch (error) { if (error instanceof CodexWarmupError && error.status === 401 - && getMainAccountToken()?.accessToken === token.accessToken) { + && credentialStillLive()) { markAccountNeedsReauth(accountId, writerGeneration); } throw error; } + if (!credentialStillLive()) return false; }); } finally { lease.release(); diff --git a/tests/codex-integration/codex-quota-auto-refresh-main-admission.test.ts b/tests/codex-integration/codex-quota-auto-refresh-main-admission.test.ts index d676690c09..88080d5a4d 100644 --- a/tests/codex-integration/codex-quota-auto-refresh-main-admission.test.ts +++ b/tests/codex-integration/codex-quota-auto-refresh-main-admission.test.ts @@ -10,7 +10,7 @@ import { getMainAccountHardLockStatus } from "../../src/codex/main-account-hard- import { setMainAccountPlan } from "../../src/codex/main-account"; import * as mainAccount from "../../src/codex/main-account"; import * as nativeClaim from "../../src/codex/native-main-claim"; -import { clearAccountQuota, flushQuotaObservationsForTests, setAccountQuotaFromParsed } from "../../src/codex/quota"; +import { clearAccountQuota, flushQuotaObservationsForTests, getAccountQuota, getMainPolicyQuota, setAccountQuotaFromParsed } from "../../src/codex/quota"; import { resetCodexQuotaAutoRefreshForTests, runCodexQuotaAutoRefresh, type CodexQuotaAutoRefreshWindows } from "../../src/codex/quota-auto-refresh"; import { getNativeMainProfileRequestCount, resetLifecycleDrainStateForTests } from "../../src/server/lifecycle"; import { flushConfigDirHardeningForTests } from "../../src/config/paths"; @@ -23,6 +23,7 @@ const RESET_SECONDS = 1_700_000_000; const RESET_MILLISECONDS = 1_700_000_000_000; const responsesUrl = "https://chatgpt.com/backend-api/codex/responses"; const tokenUrl = "https://auth.openai.com/oauth/token"; +const whamUrl = "https://chatgpt.com/backend-api/wham/usage"; let home: string; let previousHome: string | undefined; let previousCodexHome: string | undefined; @@ -71,7 +72,7 @@ function installFetch(handler: (url: string, init?: RequestInit) => Promise[0], init?: RequestInit) => { calls.push(String(input)); - expect([tokenUrl, responsesUrl]).toContain(String(input)); + expect([tokenUrl, responsesUrl, whamUrl]).toContain(String(input)); expect(getNativeMainProfileRequestCount()).toBe(1); return handler(String(input), init); }, { preconnect: previousFetch.preconnect }); @@ -137,6 +138,92 @@ afterEach(async () => { }); describe("quota auto-refresh native-main admission", () => { + test("stale metadata prepares an expired main token before WHAM and activation", async () => { + const cfg = config(); + writeMain(bearer(true)); + const cached = getAccountQuota(MAIN); + if (!cached) throw new Error("Expected cached main quota"); + cached.updatedAt = now - 300_000; + const fresh = bearer(); + const calls = installFetch(async (url, init) => { + if (url === tokenUrl) { + return Response.json({ access_token: fresh, refresh_token: "fixture-rotated", expires_in: 86_400 }); + } + expect(new Headers(init?.headers).get("authorization")).toBe(`Bearer ${fresh}`); + if (url === whamUrl) return Response.json({ plan_type: "plus", rate_limit: { + primary_window: { used_percent: 0, limit_window_seconds: 18_000, reset_at: RESET_SECONDS }, + secondary_window: { used_percent: 0, limit_window_seconds: 604_800, reset_at: RESET_SECONDS }, + } }); + return completedResponse(); + }); + await runCodexQuotaAutoRefresh(cfg, now, { persistCompleted: recordMarkers }); + expect(calls).toEqual([tokenUrl, whamUrl, responsesUrl]); + expect(isAccountNeedsReauth(MAIN)).toBe(false); + expect(cfg.codexQuotaAutoRefresh?.[MAIN]?.lastFiveHourResetAt).toBe(RESET_MILLISECONDS); + expect(getNativeMainProfileRequestCount()).toBe(0); + }); + + test.each(["bearer", "workspace", "missing"] as const)( + "%s replacement during main SSE cannot publish old quota or completion markers", async change => { + const cfg = config(); + const entered = deferred(); + let controller!: ReadableStreamDefaultController; + const calls = installFetch(async () => new Response(new ReadableStream({ + start(value) { controller = value; }, + pull() { entered.resolve(); }, + }), { headers: { + "content-type": "text/event-stream", + "x-codex-primary-used-percent": "0", + "x-codex-primary-window-minutes": "300", + "x-codex-primary-reset-at": String(RESET_SECONDS + 18_000), + } })); + const run = runCodexQuotaAutoRefresh(cfg, now, { persistCompleted: recordMarkers }); + try { + await Promise.race([entered.promise, run.then(() => { throw new Error("SSE was never reached"); })]); + const workspace = change === "workspace" ? "fixture-replacement-workspace" : accountId; + if (change === "missing") writeFileSync(join(home, "auth.json"), "{}"); + else writeMain("fixture-replacement-token", workspace); + reconcileMainCodexAccountRuntimeState(); + const writer = captureMainQuotaWriter(workspace); + if (!writer) throw new Error("Expected current quota owner"); + setAccountQuotaFromParsed(MAIN, { shortPercent: 77, shortWindowSeconds: 18_000, + shortResetAt: RESET_SECONDS + 900 }, undefined, writer); + const quotaBefore = { ...getAccountQuota(MAIN) }; + const policyBefore = { ...getMainPolicyQuota() }; + controller.enqueue(new TextEncoder().encode('data: {"type":"response.completed"}\n\n')); + controller.close(); + await run; + expect(calls).toEqual([responsesUrl]); + expect(getAccountQuota(MAIN)).toEqual(quotaBefore); + expect(getMainPolicyQuota()).toEqual(policyBefore); + expect(cfg.codexQuotaAutoRefresh?.[MAIN]?.lastFiveHourResetAt).toBeUndefined(); + expect(cfg.codexQuotaAutoRefresh?.[MAIN]?.lastWeeklyResetAt).toBeUndefined(); + expect(isAccountNeedsReauth(MAIN)).toBe(false); + expect(getNativeMainProfileRequestCount()).toBe(0); + } finally { + try { controller?.close(); } catch { /* Already closed after completion. */ } + await run; + } + }, + ); + + test("late main 401 cannot quarantine a replacement credential", async () => { + const cfg = config(); + const entered = deferred(); + const response = deferred(); + installFetch(async () => { entered.resolve(); return response.promise; }); + const run = runCodexQuotaAutoRefresh(cfg, now, { persistCompleted: recordMarkers }); + try { + await Promise.race([entered.promise, run.then(() => { throw new Error("Inference was never reached"); })]); + writeMain("fixture-replacement-token"); + response.resolve(new Response("{}", { status: 401 })); + await run; + expect(isAccountNeedsReauth(MAIN)).toBe(false); + expect(cfg.codexQuotaAutoRefresh?.[MAIN]?.lastWeeklyResetAt).toBeUndefined(); + expect(getNativeMainProfileRequestCount()).toBe(0); + } finally { response.resolve(new Response("{}", { status: 401 })); await run; } + }); + test("owned reconciliation activates retained99 before token preparation when current identity was not observed", async () => { const cfg = config(); const writer = captureMainQuotaWriter(accountId); From b67f452c49904dbda2e0be435c2e34d5a064172f Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 19:06:44 +0900 Subject: [PATCH 092/412] test(transport): pass the test-run lease to the child fixture [skip ci] Co-authored-by: hualiny <82697947+hualiny@users.noreply.github.com> --- tests/providers/provider-outbound.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/providers/provider-outbound.test.ts b/tests/providers/provider-outbound.test.ts index 9907c23664..54c82a5435 100644 --- a/tests/providers/provider-outbound.test.ts +++ b/tests/providers/provider-outbound.test.ts @@ -436,7 +436,7 @@ describe("#3462 Mihomo IPv6 fake-IP admission is gated on the scheme-matched pro writeFileSync(childTest, `import { test } from "bun:test";\ntest("Mihomo matrix", async () => { await import(${JSON.stringify(pathToFileURL(fixturePath("provider-outbound-mihomo.ts")).href)}); });\n`); try { const child = Bun.spawn([process.execPath, "test", childTest], { - cwd: repoRoot(), stdout: "pipe", stderr: "pipe", + cwd: repoRoot(), env: { ...process.env }, stdout: "pipe", stderr: "pipe", }); const [stdout, stderr, exitCode] = await Promise.all([ new Response(child.stdout).text(), new Response(child.stderr).text(), child.exited, From 4136572251cdb0bcc81dab03de1cacb90d1a04d6 Mon Sep 17 00:00:00 2001 From: DaedalGames Date: Mon, 7 Sep 2026 19:24:04 +0900 Subject: [PATCH 093/412] fix(codex): preserve validation intent at quota flight settlement --- src/codex/auth-api.ts | 18 ++++++-- .../codex-integration/codex-auth-api.test.ts | 46 +++++++++++++++++++ 2 files changed, 60 insertions(+), 4 deletions(-) diff --git a/src/codex/auth-api.ts b/src/codex/auth-api.ts index 2e45fcadfb..237bbf7637 100644 --- a/src/codex/auth-api.ts +++ b/src/codex/auth-api.ts @@ -1417,7 +1417,7 @@ async function fetchFreshPoolAccountQuota( } } -async function fetchPoolAccountQuota( +export async function fetchPoolAccountQuota( accountId: string, forceRefresh = false, configuredPlan?: string, @@ -1460,6 +1460,13 @@ async function fetchPoolAccountQuota( generation => { state.resolvedCredentialGeneration = generation; }, getValidToken, ).then(async result => { + // A passive flight has consumed its validation decision. Remove it before + // promise settlement queues other continuations, so a late explicit caller + // starts fresh work instead of setting an intent nobody will read again. + if (!state.validatePending) { + releaseFlight(); + return result; + } // Only an explicit account-list refresh finishes deferred registration. Passive quota // polls and startup priming remain read-only with respect to inference spending. const generation = result.freshCredentialGeneration; @@ -1490,13 +1497,16 @@ async function fetchPoolAccountQuota( const activeFlights = flights ?? new Set(); activeFlights.add(flight); if (!flights) poolQuotaRefreshInFlight.set(accountId, activeFlights); - try { - return await refresh; - } finally { + const releaseFlight = () => { activeFlights.delete(flight); if (activeFlights.size === 0 && poolQuotaRefreshInFlight.get(accountId) === activeFlights) { poolQuotaRefreshInFlight.delete(accountId); } + }; + try { + return await refresh; + } finally { + releaseFlight(); } } diff --git a/tests/codex-integration/codex-auth-api.test.ts b/tests/codex-integration/codex-auth-api.test.ts index 43ccc82b9e..1ecbfd3cc8 100644 --- a/tests/codex-integration/codex-auth-api.test.ts +++ b/tests/codex-integration/codex-auth-api.test.ts @@ -5205,6 +5205,52 @@ describe("codex-auth API", () => { expect(isCodexAccountUsable(config, accountId)).toBe(true); }); + test.each([{ delay: 0, reads: 1 }, { delay: 3, reads: 2 }, { delay: 6, reads: 2 }])("validation joins before, during, and after quota settlement: %j", async ({ delay, reads }) => { + const { fetchPoolAccountQuota } = await import("../../src/codex/auth-api"); + const accountId = "late-validation-join"; + const config = makeConfig({ codexAccounts: [{ id: accountId, plan: "pro", isMain: false }] }); + saveConfig(config); + setLiveStateStoreConfig(config); + saveCodexAccountCredential(accountId, { accessToken: "late-access", refreshToken: "late-refresh", + expiresAt: Date.now() + 3600_000, chatgptAccountId: "late-account" }, { validationPending: true }); + let warmups = 0; + let usageReads = 0; + let scheduled = false; + let joined: Promise = Promise.resolve(); + globalThis.fetch = (async (input: RequestInfo | URL) => { + if (String(input).endsWith("/wham/usage")) { + usageReads++; + const response = Response.json({}); + response.json = async () => { + if (!scheduled) { + scheduled = true; + // Deterministic microtask ordering from JSON completion: join before + // the validation decision, after it but before flight cleanup, or + // after settlement. No timers or real network scheduling are involved. + let order = Promise.resolve(); + for (let i = 0; i < delay; i++) order = order.then(() => {}); + joined = order.then(() => Promise.all([ + fetchPoolAccountQuota(accountId, true, "pro", undefined, true), + fetchPoolAccountQuota(accountId, true, "pro", undefined, true), + ])); + } + return { plan_type: "pro", rate_limit: { secondary_window: { used_percent: 12, limit_window_seconds: 604800 } } }; + }; + return response; + } + if (String(input).endsWith("/codex/responses")) { + warmups++; + return new Response('data: {"type":"response.completed"}\n\n'); + } + throw new Error("unexpected request"); + }) as typeof fetch; + await fetchPoolAccountQuota(accountId, true, "pro"); + await joined; + expect(usageReads).toBe(reads); + expect(warmups).toBe(1); + expect(readCodexAccountRecord(accountId)?.codexValidationPending).toBeUndefined(); + }); + test("quota-pending reauth replaces only the same identity and clears stale validation", async () => { const accountId = "quota-reauth"; const config = makeConfig({ codexAccounts: [{ id: accountId, email: "quota@example.test", plan: "pro", isMain: false }] }); From 255fa828baf8c32b78d0ecc115f5c596e6456e58 Mon Sep 17 00:00:00 2001 From: DaedalGames Date: Mon, 7 Sep 2026 19:46:19 +0900 Subject: [PATCH 094/412] test: keep quota registration PR scoped to account readiness --- gui/tests/apikeys-mutation-timeout.test.tsx | 11 ++-- tests/routing/combo-management-api.test.ts | 72 +++++++++------------ 2 files changed, 35 insertions(+), 48 deletions(-) diff --git a/gui/tests/apikeys-mutation-timeout.test.tsx b/gui/tests/apikeys-mutation-timeout.test.tsx index 76bf9909a3..55f3623f74 100644 --- a/gui/tests/apikeys-mutation-timeout.test.tsx +++ b/gui/tests/apikeys-mutation-timeout.test.tsx @@ -16,7 +16,6 @@ let restoreGlobals: (() => void) | undefined; let previousLanguageDescriptor: PropertyDescriptor | undefined; let previousAbortTimeout: PropertyDescriptor | undefined; let testWindow: Window; -let expireTimeouts: Array<() => void>; const AUTH_MATRIX = [ { endpoint: "/v1/responses", bearer: "rejected", dedicated: "required", xApiKey: "rejected" }, @@ -42,20 +41,18 @@ beforeEach(() => { testWindow = new Window({ url: "http://localhost/" }); previousLanguageDescriptor = Object.getOwnPropertyDescriptor(globalThis.navigator, "language"); Object.defineProperty(globalThis.navigator, "language", { configurable: true, value: "en-US" }); - // Control expiry rather than racing a 30ms wall-clock fuse under suite load. - // `createBoundedFetch` still runs, + // Shorten the fuse rather than the wiring. `createBoundedFetch` still runs, // still builds the combined signal, and the page still has to pass it to // `fetch` — waiting the real 15s would only prove the clock works, at the // price of half a minute on every suite run. The timer itself is covered in // tests/bounded-fetch.test.ts. previousAbortTimeout = Object.getOwnPropertyDescriptor(AbortSignal, "timeout"); - expireTimeouts = []; Object.defineProperty(AbortSignal, "timeout", { configurable: true, value: (ms: number) => { expect(ms).toBe(15_000); const controller = new AbortController(); - expireTimeouts.push(() => controller.abort(new DOMException("TimeoutError", "TimeoutError"))); + setTimeout(() => controller.abort(new DOMException("TimeoutError", "TimeoutError")), 30); return controller.signal; }, }); @@ -183,7 +180,7 @@ test("a delete that never answers gives navigation back instead of locking it", expect(backButton(container).disabled).toBe(true); // The bound fires and the page is usable again — no reload required. - await act(async () => { for (const expire of expireTimeouts) expire(); }); + await tick(120); await tick(); expect(seen.aborted).toBe(true); @@ -225,7 +222,7 @@ test("a rename that never answers releases the lock and keeps the draft", async expect(backButton(container).disabled).toBe(true); - await act(async () => { for (const expire of expireTimeouts) expire(); }); + await tick(120); await tick(); expect(seen.aborted).toBe(true); diff --git a/tests/routing/combo-management-api.test.ts b/tests/routing/combo-management-api.test.ts index e0c21f2957..85f6be0ff6 100644 --- a/tests/routing/combo-management-api.test.ts +++ b/tests/routing/combo-management-api.test.ts @@ -42,7 +42,6 @@ import { syncCatalogModels } from "../../src/codex/catalog"; import { injectClaudeAgentDefs } from "../../src/claude/agents-inject"; import { catalogConvergenceFactory } from "../helpers/catalog-convergence"; import { removeTreeWithRetry } from "../helpers/remove-tree"; -import * as appServerProcesses from "../../src/codex/app-server-processes"; const VALID_COMBO = { targets: [{ provider: "a", model: "m1" }] }; @@ -832,47 +831,38 @@ describe("combo management API", () => { }); test("GET subagent models exposes a combo alias as an available round-trip value", async () => { - // Process enumeration is unrelated to roster retention and can block on Windows CIM. - const processProbe = spyOn(appServerProcesses, "collectCodexAppServerCatalogState") - .mockReturnValue({ state: "not_running", processes: [], catalogMtimeMs: null }); - try { - const config = baseConfig({ - subagentModels: ["deepseek-v4-flash"], - combos: { - free: { ...VALID_COMBO, alias: "deepseek-v4-flash" }, - }, - }); - // This exercises configured alias visibility, not live provider discovery. - for (const provider of Object.values(config.providers)) provider.liveModels = false; - config.providers.a!.modelContextWindows = { m1: 128_000 }; + const config = baseConfig({ + subagentModels: ["deepseek-v4-flash"], + combos: { + free: { ...VALID_COMBO, alias: "deepseek-v4-flash" }, + }, + }); + config.providers.a!.modelContextWindows = { m1: 128_000 }; - const response = await comboApi(config, "GET", "/api/subagent-models"); - expect(response?.status).toBe(200); - const body = await response!.json() as { chosen: string[]; available: string[] }; - expect(body.chosen).toEqual(["deepseek-v4-flash"]); - expect(body.available).toContain("deepseek-v4-flash"); - expect(body.available.filter(model => model === "deepseek-v4-flash")).toHaveLength(1); - expect(body.available).not.toContain("combo/free"); - - // Disabling an alias hides it from the pickable set, but NOT while it still holds a - // saved roster slot: the dashboard PUTs exactly the rows it can render, so dropping a - // chosen id here silently truncates the persisted roster on the next Save. Covered by - // tests/routing/subagent-roster-retention.test.ts. - config.disabledModels = ["deepseek-v4-flash"]; - const disabledResponse = await comboApi(config, "GET", "/api/subagent-models"); - const disabledBody = await disabledResponse!.json() as { chosen: string[]; available: string[] }; - expect(disabledBody.chosen).toEqual(["deepseek-v4-flash"]); - expect(disabledBody.available).toContain("deepseek-v4-flash"); - expect(disabledBody.available.filter(model => model === "deepseek-v4-flash")).toHaveLength(1); - - // Once it no longer occupies a roster slot, the disable takes full effect. - config.subagentModels = []; - const unfeaturedResponse = await comboApi(config, "GET", "/api/subagent-models"); - const unfeaturedBody = await unfeaturedResponse!.json() as { available: string[] }; - expect(unfeaturedBody.available).not.toContain("deepseek-v4-flash"); - } finally { - processProbe.mockRestore(); - } + const response = await comboApi(config, "GET", "/api/subagent-models"); + expect(response?.status).toBe(200); + const body = await response!.json() as { chosen: string[]; available: string[] }; + expect(body.chosen).toEqual(["deepseek-v4-flash"]); + expect(body.available).toContain("deepseek-v4-flash"); + expect(body.available.filter(model => model === "deepseek-v4-flash")).toHaveLength(1); + expect(body.available).not.toContain("combo/free"); + + // Disabling an alias hides it from the pickable set, but NOT while it still holds a + // saved roster slot: the dashboard PUTs exactly the rows it can render, so dropping a + // chosen id here silently truncates the persisted roster on the next Save. Covered by + // tests/routing/subagent-roster-retention.test.ts. + config.disabledModels = ["deepseek-v4-flash"]; + const disabledResponse = await comboApi(config, "GET", "/api/subagent-models"); + const disabledBody = await disabledResponse!.json() as { chosen: string[]; available: string[] }; + expect(disabledBody.chosen).toEqual(["deepseek-v4-flash"]); + expect(disabledBody.available).toContain("deepseek-v4-flash"); + expect(disabledBody.available.filter(model => model === "deepseek-v4-flash")).toHaveLength(1); + + // Once it no longer occupies a roster slot, the disable takes full effect. + config.subagentModels = []; + const unfeaturedResponse = await comboApi(config, "GET", "/api/subagent-models"); + const unfeaturedBody = await unfeaturedResponse!.json() as { available: string[] }; + expect(unfeaturedBody.available).not.toContain("deepseek-v4-flash"); }, 15_000); test("GET models round-trips a disabled combo alias for the Models GUI", async () => { From edd396c62ec349fa686309c1ee55e02ebad6b903 Mon Sep 17 00:00:00 2001 From: makesomethingshit Date: Mon, 7 Sep 2026 15:35:53 +0900 Subject: [PATCH 095/412] fix(opencode-go): carry session affinity through Pi native chat [skip ci] (cherry picked from commit fbb214f92a7dc75f89d0d835fdb95136d61f380a) Co-authored-by: makesomethingshit <246213378+makesomethingshit@users.noreply.github.com> (cherry picked from commit 7e45a95f70689dfe1eb313c4af9aecbf2c44cdb6) --- src/clients/config-export.ts | 2 + src/server/chat-completions.ts | 7 +++ src/server/responses/core.ts | 3 +- tests/config/client-config-export.test.ts | 6 ++- .../opencode-go-session-header.test.ts | 52 ++++++++++++++++++- 5 files changed, 67 insertions(+), 3 deletions(-) diff --git a/src/clients/config-export.ts b/src/clients/config-export.ts index 8fb42f311d..e1744c2209 100644 --- a/src/clients/config-export.ts +++ b/src/clients/config-export.ts @@ -695,6 +695,7 @@ export interface PiProviderBlock { baseUrl: string; api: string; apiKey: string; + compat?: { sendSessionAffinityHeaders: boolean }; models: PiModelEntry[]; } @@ -859,6 +860,7 @@ function buildPiClientConfig(ctx: ExportContext): PiGeneratedConfig { baseUrl: ctx.baseUrl, api: PI_API_DIALECT, apiKey: LOOPBACK_API_KEY_PLACEHOLDER, + compat: { sendSessionAffinityHeaders: true }, models, }, }, diff --git a/src/server/chat-completions.ts b/src/server/chat-completions.ts index e7fd04f42d..7e69010636 100644 --- a/src/server/chat-completions.ts +++ b/src/server/chat-completions.ts @@ -25,6 +25,8 @@ import { estimateTokens } from "../lib/token-estimate"; import { NoEligiblePolicyCandidateError, UnknownRoutingPolicyError, routeModel } from "../router"; import { evidenceFromBody } from "../routing/request-evidence"; import { resolveWireProtocolOverride } from "./adapter-resolve"; +import { resolveOpenCodeGoTransport } from "../providers/opencode-go-transport"; +import { normalizeLogConversationId, sessionLaneIdFromRequest } from "./request-log-conversation"; import type { OcxConfig } from "../types"; import { readJsonRequestBody } from "./request-decompress"; import { @@ -136,6 +138,8 @@ async function handleChatCompletionsWithBudget( let chatNativeRoute: ReturnType | null = null; try { const route = routeModel(config, chatBody.model as string, evidenceFromBody(chatBody)); + route.provider = resolveOpenCodeGoTransport(route.provider, + sessionLaneIdFromRequest(req.headers) ?? normalizeLogConversationId(req.headers.get("x-opencode-session"))); // Settle the wire once so every branch below reads the adapter this model will // actually use, not the provider-wide default (#404). route.provider = resolveWireProtocolOverride(route.providerName, route.modelId, route.provider, "chat"); @@ -237,6 +241,9 @@ async function handleChatCompletionsWithBudget( return chatCompletionsErrorResponse(400, CODEX_RESERVE_HELPER_UNSUPPORTED_MESSAGE, "invalid_request_error"); } const headers = new Headers({ "content-type": "application/json" }); + // Internal bridge metadata; the Go resolver scopes and hashes it before upstream use. + const openCodeSession = req.headers.get("x-opencode-session"); + if (openCodeSession) headers.set("x-opencode-session", openCodeSession); for (const name of FORWARD_HEADERS) { if (name === "authorization" && !directRoute) continue; const value = req.headers.get(name); diff --git a/src/server/responses/core.ts b/src/server/responses/core.ts index 312af7ac43..594b444c8b 100644 --- a/src/server/responses/core.ts +++ b/src/server/responses/core.ts @@ -2304,7 +2304,8 @@ async function applyFinalRouteRequestNormalization(args: { // Settle the wire once so logging, fast-mode, auth, and sidecars read the adapter // this request will actually use (#404). - route.provider = resolveOpenCodeGoTransport(route.provider, sessionLaneIdFromRequest(req.headers)); + route.provider = resolveOpenCodeGoTransport(route.provider, + sessionLaneIdFromRequest(req.headers) ?? normalizeLogConversationId(req.headers.get("x-opencode-session"))); route.provider = resolveWireProtocolOverride(route.providerName, route.modelId, route.provider, inboundWire); if (preserveAnthropicResponseModel) parsed._responseModelId = responseModelId; logCtx.model = route.modelId; diff --git a/tests/config/client-config-export.test.ts b/tests/config/client-config-export.test.ts index 6a71813e9f..4d70790403 100644 --- a/tests/config/client-config-export.test.ts +++ b/tests/config/client-config-export.test.ts @@ -315,6 +315,7 @@ describe("Pi serializer (accept criterion 2)", () => { expect(provider.baseUrl).toBe(BASE_URL); expect(provider.api).toBe("openai-completions"); expect(provider.apiKey).toBe(LOOPBACK_API_KEY_PLACEHOLDER); + expect(provider.compat?.sendSessionAffinityHeaders).toBe(true); }); test("cost is omitted on every entry — zeros would assert routed models are free", () => { @@ -899,7 +900,7 @@ describe("EXPORT_CLIENTS registry", () => { `); }); - test("pi bytes are unchanged, to the last newline", () => { + test("pi bytes include session affinity, to the last newline", () => { const built = buildClientConfigText("pi", ctx({ config: cfg() })); expect(built.format).toBe("json"); expect(built.text).toBe(`{ @@ -908,6 +909,9 @@ describe("EXPORT_CLIENTS registry", () => { "baseUrl": "http://127.0.0.1:10100/v1", "api": "openai-completions", "apiKey": "opencodex-loopback", + "compat": { + "sendSessionAffinityHeaders": true + }, "models": [ { "id": "anthropic/claude-opus-5", diff --git a/tests/providers/opencode-go-session-header.test.ts b/tests/providers/opencode-go-session-header.test.ts index 00684f065b..9b476760cd 100644 --- a/tests/providers/opencode-go-session-header.test.ts +++ b/tests/providers/opencode-go-session-header.test.ts @@ -3,6 +3,7 @@ import { providerConfigSeed } from "../../src/providers/derive"; import { resolveOpenCodeGoTransport } from "../../src/providers/opencode-go-transport"; import { getProviderRegistryEntry } from "../../src/providers/registry"; import { handleResponses } from "../../src/server/responses/core"; +import { handleChatCompletions } from "../../src/server/chat-completions"; import type { OcxConfig, OcxProviderConfig } from "../../src/types"; const MUSE_MODEL = "muse-spark-1.3-contributor"; @@ -52,6 +53,8 @@ async function captureRequest(input: { model?: string; child?: string; provider?: OcxProviderConfig; + nativeChat?: boolean; + headers?: Record; } = {}): Promise<{ url: string; headers: Headers }> { const providerName = input.providerName ?? "opencode-go"; const model = input.model ?? MUSE_MODEL; @@ -65,7 +68,15 @@ async function captureRequest(input: { const config = { providers: { [providerName]: input.provider ?? opencodeGo() }, } as unknown as OcxConfig; - const response = await handleResponses( + const response = input.nativeChat ? await handleChatCompletions( + new Request("http://localhost/v1/chat/completions", { + method: "POST", + headers: input.headers ?? codexHeaders(input.child), + body: JSON.stringify({ model: `${providerName}/${model}`, messages: [{ role: "user", content: "ping" }], stream: false }), + }), + config, + { model: "", provider: "" }, + ) : await handleResponses( new Request("http://localhost/v1/responses", { method: "POST", headers: codexHeaders(input.child), @@ -77,6 +88,7 @@ async function captureRequest(input: { ); expect(response.status).toBe(200); + await response.text(); expect(requests).toHaveLength(1); return requests[0]!; } @@ -85,6 +97,44 @@ describe("OpenCode Go session affinity (#3344)", () => { const originalFetch = globalThis.fetch; afterEach(() => { globalThis.fetch = originalFetch; }); + test("native Chat ingress preserves stable Go affinity and separates conversations", async () => { + const provider = opencodeGo(); + const input = { nativeChat: true, model: "omen-alpha", provider }; + const first = await captureRequest(input); + const continued = await captureRequest(input); + const sibling = await captureRequest({ ...input, child: "child-thread-b" }); + expect(first.url).toBe("https://opencode.ai/zen/go/v1/chat/completions"); + expect(first.headers.get(SESSION_HEADER)).toMatch(/^ocx_[0-9a-f]{32}$/); + expect(continued.headers.get(SESSION_HEADER)).toBe(first.headers.get(SESSION_HEADER)); + expect(sibling.headers.get(SESSION_HEADER)).not.toBe(first.headers.get(SESSION_HEADER)); + expect(provider.headers?.[SESSION_HEADER]).toBeUndefined(); + }); + + test("native Chat honors configured session headers on renamed Go providers", async () => { + const captured = await captureRequest({ + nativeChat: true, model: "omen-alpha", providerName: "renamed-go", + provider: opencodeGo({ headers: { "X-OpenCode-Session": "operator-session" } }), + }); + expect(captured.headers.get(SESSION_HEADER)).toBe("operator-session"); + }); + + test("uses a Pi session header without Codex headers on native and bridged Chat", async () => { + const headers = { "content-type": "application/json", "x-opencode-session": "pi-conversation-a" }; + const chat = await captureRequest({ nativeChat: true, model: "omen-alpha", headers }); + const bridged = await captureRequest({ nativeChat: true, model: MUSE_MODEL, headers }); + expect(chat.headers.get(SESSION_HEADER)).toMatch(/^ocx_[0-9a-f]{32}$/); + expect(chat.headers.get(SESSION_HEADER)).not.toContain("pi-conversation-a"); + expect(bridged.headers.get(SESSION_HEADER)).toBe(chat.headers.get(SESSION_HEADER)); + }); + + test("native Chat does not send Go affinity to an unrelated destination", async () => { + const captured = await captureRequest({ + nativeChat: true, model: "omen-alpha", providerName: "custom-go", + provider: opencodeGo({ baseUrl: "https://opencode.ai.evil.test/zen/go/v1" }), + }); + expect(captured.headers.has(SESSION_HEADER)).toBe(false); + }); + test("sends one stable opaque session header on Responses and Chat wires", async () => { const responses = await captureRequest({ model: MUSE_MODEL }); const chat = await captureRequest({ model: CHAT_MODEL }); From effba4c646408c8fd4b22936c820de37d370ce9e Mon Sep 17 00:00:00 2001 From: makesomethingshit Date: Mon, 7 Sep 2026 16:11:52 +0900 Subject: [PATCH 096/412] test(opencode-go): define inbound opaque session identity contract [skip ci] (cherry picked from commit 9f15a7c4139de294c5b0d7eddf50d885523f149e) Co-authored-by: makesomethingshit <246213378+makesomethingshit@users.noreply.github.com> (cherry picked from commit 65908008e52c5dca2eb1130d1c0cff0e0732873d) --- .../opencode-go-session-header.test.ts | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/tests/providers/opencode-go-session-header.test.ts b/tests/providers/opencode-go-session-header.test.ts index 9b476760cd..b05e526e1c 100644 --- a/tests/providers/opencode-go-session-header.test.ts +++ b/tests/providers/opencode-go-session-header.test.ts @@ -1,9 +1,10 @@ import { afterEach, describe, expect, test } from "bun:test"; import { providerConfigSeed } from "../../src/providers/derive"; -import { resolveOpenCodeGoTransport } from "../../src/providers/opencode-go-transport"; +import { deriveOpenCodeGoSessionId, resolveOpenCodeGoTransport } from "../../src/providers/opencode-go-transport"; import { getProviderRegistryEntry } from "../../src/providers/registry"; import { handleResponses } from "../../src/server/responses/core"; import { handleChatCompletions } from "../../src/server/chat-completions"; +import { normalizeLogConversationId } from "../../src/server/request-log-conversation"; import type { OcxConfig, OcxProviderConfig } from "../../src/types"; const MUSE_MODEL = "muse-spark-1.3-contributor"; @@ -79,7 +80,7 @@ async function captureRequest(input: { ) : await handleResponses( new Request("http://localhost/v1/responses", { method: "POST", - headers: codexHeaders(input.child), + headers: input.headers ?? codexHeaders(input.child), body: JSON.stringify({ model: `${providerName}/${model}`, input: "ping", stream: false }), }), config, @@ -127,6 +128,27 @@ describe("OpenCode Go session affinity (#3344)", () => { expect(bridged.headers.get(SESSION_HEADER)).toBe(chat.headers.get(SESSION_HEADER)); }); + for (const session of ["client-session-a", "ocx_0123456789abcdef0123456789abcdef"]) { + test(`treats inbound ${session.startsWith("ocx_") ? "ocx-prefixed" : "raw"} identity as client input on every ingress`, async () => { + const headers = { "content-type": "application/json", [SESSION_HEADER]: session }; + const expected = deriveOpenCodeGoSessionId(normalizeLogConversationId(session)!); + const native = await captureRequest({ nativeChat: true, model: "omen-alpha", headers }); + const bridged = await captureRequest({ nativeChat: true, model: MUSE_MODEL, headers }); + const responses = await captureRequest({ model: MUSE_MODEL, headers }); + expect(native.url).toEndWith("/chat/completions"); + expect(bridged.url).toEndWith("/responses"); + for (const request of [native, bridged, responses]) { + expect(request.headers.get(SESSION_HEADER)).toBe(expected); + expect(request.headers.get(SESSION_HEADER)).not.toBe(session); + } + const override = await captureRequest({ + nativeChat: true, model: "omen-alpha", headers, + provider: opencodeGo({ headers: { "X-OpenCode-Session": session } }), + }); + expect(override.headers.get(SESSION_HEADER)).toBe(session); + }); + } + test("native Chat does not send Go affinity to an unrelated destination", async () => { const captured = await captureRequest({ nativeChat: true, model: "omen-alpha", providerName: "custom-go", From 5b3df2ed5a0b69677c739c937ab24f5eb6061f3e Mon Sep 17 00:00:00 2001 From: Ingwannu Date: Mon, 7 Sep 2026 06:35:43 +0000 Subject: [PATCH 097/412] fix: admit reasoning envelope allocations before materialization [skip ci] (cherry picked from commit 9bcb7748facfd5495f641044adcf8e0627f9fb26) Co-authored-by: Ingwannu <186453546+Ingwannu@users.noreply.github.com> --- .../content/docs/reference/proxy-formats.md | 6 + src/claude/inbound.ts | 27 ++++- src/lib/json-byte-size.ts | 61 ++++++++++ src/responses/reasoning-envelope.ts | 72 +++++++++--- src/server/claude-messages.ts | 5 +- structure/04_transports-and-sidecars.md | 17 +++ tests/responses/reasoning-envelope.test.ts | 111 +++++++++++++++++- 7 files changed, 269 insertions(+), 30 deletions(-) create mode 100644 src/lib/json-byte-size.ts diff --git a/docs-site/src/content/docs/reference/proxy-formats.md b/docs-site/src/content/docs/reference/proxy-formats.md index cb97ad7076..0c7b8257bc 100644 --- a/docs-site/src/content/docs/reference/proxy-formats.md +++ b/docs-site/src/content/docs/reference/proxy-formats.md @@ -278,6 +278,12 @@ These endpoints speak the Anthropic Messages dialect used by Claude Code and com Most requests are translated to Responses, routed normally, then translated back to Anthropic JSON or Anthropic SSE. +On translated Messages requests, reasoning replay shares the request's translation budget. +Envelope admission includes encoding/decoding copy overhead, not just the original signature +length. Requests exceeding this budget return HTTP 413 with `translation_buffer_limit`; +signatures and opaque reasoning data are never truncated to make a request fit. Native +Anthropic passthrough retains its separate body-size contract. + Base64 and URL image sources are translated in user messages and nested tool results. File-backed images (`source.type: "file"`) require native Anthropic passthrough; translated routes return a fixed HTTP 400 error asking for base64 or URL input. OpenCodex does not resolve another provider's diff --git a/src/claude/inbound.ts b/src/claude/inbound.ts index 5e876ca6cb..c2e3ded9b2 100644 --- a/src/claude/inbound.ts +++ b/src/claude/inbound.ts @@ -18,6 +18,7 @@ import { AnthropicRequestError, isRec, type Rec } from "./inbound-records"; import { resolveInboundModel, effortForThinkingBudget, effortFromOutputConfig, formatFromOutputConfig } from "./inbound-model-options"; import { systemToInstructions, toolsToResponses, toolChoiceToResponses } from "./inbound-content-options"; import { decodeReasoningEnvelope, encodeReasoningEnvelope, OCX_REASONING_PREFIX } from "../responses/reasoning-envelope"; +import { createTranslatorBudget, type TranslatorBudget } from "../lib/translator-budget"; @@ -210,7 +211,7 @@ function userMessageToItems(content: unknown, input: Rec[], elide: SkillElisionC pushUserMessage(input, pending); } -function assistantMessageToItems(content: unknown, input: Rec[]): void { +function assistantMessageToItems(content: unknown, input: Rec[], budget: TranslatorBudget): void { if (typeof content === "string") { if (content.length > 0) input.push({ type: "message", role: "assistant", content: [{ type: "output_text", text: content }] }); return; @@ -240,11 +241,12 @@ function assistantMessageToItems(content: unknown, input: Rec[]): void { const thinking = typeof raw.thinking === "string" ? raw.thinking : ""; const signature = typeof raw.signature === "string" ? raw.signature : ""; if (signature.startsWith(OCX_REASONING_PREFIX)) { - const owned = decodeReasoningEnvelope(signature); + const owned = decodeReasoningEnvelope(signature, budget); if (!owned) throw new AnthropicRequestError("malformed ocxr1 reasoning signature"); if (Object.hasOwn(owned, "sig")) throw new AnthropicRequestError("OpenCodex reasoning continuity cannot be replayed as an Anthropic signature"); } - const encrypted = signature.length === 0 ? undefined : signature.startsWith(OCX_REASONING_PREFIX) ? signature : encodeReasoningEnvelope({ sig: signature }); + const encrypted = signature.length === 0 ? undefined : signature.startsWith(OCX_REASONING_PREFIX) ? signature : encodeReasoningEnvelope({ sig: signature }, budget); + if (encrypted) budget.chargeRetained(2 * encrypted.length, { kind: "reasoning" }); if (thinking.length === 0 && !encrypted) break; input.push({ type: "reasoning", id: `rs_${crypto.randomUUID().replace(/-/g, "")}`, summary: thinking.length > 0 ? [{ type: "summary_text", text: thinking }] : [], ...(encrypted ? { encrypted_content: encrypted } : {}) }); break; @@ -252,7 +254,11 @@ function assistantMessageToItems(content: unknown, input: Rec[]): void { case "redacted_thinking": { flush(); const data = typeof raw.data === "string" ? raw.data : ""; - if (data.length > 0) input.push({ type: "reasoning", id: `rs_${crypto.randomUUID().replace(/-/g, "")}`, summary: [], encrypted_content: encodeReasoningEnvelope({ red: [data] }) }); + if (data.length > 0) { + const encrypted = encodeReasoningEnvelope({ red: [data] }, budget); + budget.chargeRetained(2 * encrypted.length, { kind: "reasoning" }); + input.push({ type: "reasoning", id: `rs_${crypto.randomUUID().replace(/-/g, "")}`, summary: [], encrypted_content: encrypted }); + } break; } default: @@ -294,7 +300,16 @@ export function anthropicToResponsesBody(raw: unknown, cc?: OcxClaudeCodeConfig) * OUT-OF-BODY tuple (audit 133 R3#1 — an in-body marker would leak upstream through * the native Responses forward and 400). */ -export function anthropicToResponsesTranslation(raw: unknown, cc?: OcxClaudeCodeConfig): ClaudeInboundTranslation { +export function anthropicToResponsesTranslation(raw: unknown, cc?: OcxClaudeCodeConfig, budget?: TranslatorBudget): ClaudeInboundTranslation { + const activeBudget = budget ?? createTranslatorBudget(); + try { + return translateAnthropicRequest(raw, cc, activeBudget); + } finally { + if (!budget) activeBudget.dispose(); + } +} + +function translateAnthropicRequest(raw: unknown, cc: OcxClaudeCodeConfig | undefined, budget: TranslatorBudget): ClaudeInboundTranslation { if (!isRec(raw)) throw new AnthropicRequestError("request body must be a JSON object"); if (typeof raw.model !== "string" || raw.model.length === 0) { throw new AnthropicRequestError("model is required"); @@ -315,7 +330,7 @@ export function anthropicToResponsesTranslation(raw: unknown, cc?: OcxClaudeCode for (const msg of raw.messages) { if (!isRec(msg)) throw new AnthropicRequestError("each message must be an object"); if (msg.role === "user") userMessageToItems(msg.content, input, elide); - else if (msg.role === "assistant") assistantMessageToItems(msg.content, input); + else if (msg.role === "assistant") assistantMessageToItems(msg.content, input, budget); else if (msg.role === "system") { const text = systemMessageText(msg.content); if (text.length > 0) systemParts.push(text); diff --git a/src/lib/json-byte-size.ts b/src/lib/json-byte-size.ts new file mode 100644 index 0000000000..d6398718fd --- /dev/null +++ b/src/lib/json-byte-size.ts @@ -0,0 +1,61 @@ +import { TRANSLATOR_MAX_TURN_BYTES, TranslatorBudgetExceededError } from "./translator-budget"; + +/** Measure plain JSON data without allocating its serialized string or UTF-8 copy. */ +export function jsonUtf8Bytes(value: unknown, limit = TRANSLATOR_MAX_TURN_BYTES): number { + let bytes = 0; + const add = (count: number) => { + if (count > limit - bytes) throw new TranslatorBudgetExceededError("request_copies", limit); + bytes += count; + }; + const string = (text: string) => { + // Every UTF-16 code unit needs at least one JSON UTF-8 byte; reject large inputs + // before walking them. Escapes and unpaired surrogates are counted below. + if (text.length + 2 > limit - bytes) throw new TranslatorBudgetExceededError("request_copies", limit); + add(2); + for (let i = 0; i < text.length; i++) { + const code = text.charCodeAt(i); + if (code === 0x22 || code === 0x5c || code === 8 || code === 9 || code === 10 || code === 12 || code === 13) add(2); + else if (code < 0x20) add(6); + else if (code < 0x80) add(1); + else if (code < 0x800) add(2); + else if (code >= 0xd800 && code <= 0xdbff) { + const next = text.charCodeAt(i + 1); + if (next >= 0xdc00 && next <= 0xdfff) { add(4); i++; } + else add(6); + } else if (code >= 0xdc00 && code <= 0xdfff) add(6); + else add(3); + } + }; + const visit = (item: unknown): void => { + if (item === null) { add(4); return; } + if (typeof item === "string") { string(item); return; } + if (typeof item === "boolean") { add(item ? 4 : 5); return; } + if (typeof item === "number") { add(Number.isFinite(item) ? String(item).length : 4); return; } + if (Array.isArray(item)) { + add(2); + for (let i = 0; i < item.length; i++) { + if (i > 0) add(1); + if (item[i] === undefined) add(4); + else visit(item[i]); + } + return; + } + if (typeof item === "object" && item !== null) { + add(2); + let first = true; + for (const key of Object.keys(item)) { + const field = (item as Record)[key]; + if (field === undefined) continue; + if (!first) add(1); + first = false; + string(key); + add(1); + visit(field); + } + return; + } + throw new TypeError("Expected plain JSON data for translation sizing"); + }; + visit(value); + return bytes; +} diff --git a/src/responses/reasoning-envelope.ts b/src/responses/reasoning-envelope.ts index 2a56563578..ba20e800ed 100644 --- a/src/responses/reasoning-envelope.ts +++ b/src/responses/reasoning-envelope.ts @@ -12,6 +12,9 @@ * passthrough scrub strips ocxr1 envelopes before native forwarding. */ +import { createTranslatorBudget, type TranslatorBudget } from "../lib/translator-budget"; +import { jsonUtf8Bytes } from "../lib/json-byte-size"; + export const OCX_REASONING_PREFIX = "ocxr1:"; export interface ReasoningEnvelope { @@ -32,30 +35,61 @@ export interface ReasoningEnvelope { krc?: string; } -export function encodeReasoningEnvelope(envelope: ReasoningEnvelope): string { - return OCX_REASONING_PREFIX + Buffer.from(JSON.stringify(envelope), "utf-8").toString("base64"); +export function encodeReasoningEnvelope(envelope: ReasoningEnvelope, budget?: TranslatorBudget): string { + const activeBudget = budget ?? createTranslatorBudget(); + try { + const jsonBytes = jsonUtf8Bytes(envelope); + const base64Bytes = 4 * Math.ceil(jsonBytes / 3); + // Reserve before materialization: UTF-16 JSON, UTF-8 buffer, base64 string, + // and the prefixed result may coexist. Returned-value ownership stays with + // callers, whose existing retained accounting must not be charged twice here. + const reservation = activeBudget.reserveTransient( + Math.max( + 3 * jsonBytes + 4 * base64Bytes + 2 * OCX_REASONING_PREFIX.length, + 8 * (OCX_REASONING_PREFIX.length + base64Bytes), + ), + { kind: "reasoning" }, + ); + try { + return OCX_REASONING_PREFIX + Buffer.from(JSON.stringify(envelope), "utf-8").toString("base64"); + } finally { + reservation.release(); + } + } finally { + if (!budget) activeBudget.dispose(); + } } /** Decode an ocxr1 envelope; returns null for native (OpenAI-encrypted) blobs or garbage. */ -export function decodeReasoningEnvelope(encryptedContent: string): ReasoningEnvelope | null { +export function decodeReasoningEnvelope(encryptedContent: string, budget?: TranslatorBudget): ReasoningEnvelope | null { if (!encryptedContent.startsWith(OCX_REASONING_PREFIX)) return null; + const activeBudget = budget ?? createTranslatorBudget(); try { - const parsed: unknown = JSON.parse(Buffer.from(encryptedContent.slice(OCX_REASONING_PREFIX.length), "base64").toString("utf-8")); - if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null; - const obj = parsed as { sig?: unknown; red?: unknown }; - const envelope: ReasoningEnvelope = {}; - if (typeof obj.sig === "string") envelope.sig = obj.sig; - if (Array.isArray(obj.red)) { - const red = obj.red.filter((r): r is string => typeof r === "string"); - if (red.length > 0) envelope.red = red; + // Also bound already-encoded replay before slicing, decoding, or parsing it. + // Eight bytes per code unit conservatively covers the string/buffer copies. + const reservation = activeBudget.reserveTransient(8 * encryptedContent.length, { kind: "reasoning" }); + try { + const parsed: unknown = JSON.parse(Buffer.from(encryptedContent.slice(OCX_REASONING_PREFIX.length), "base64").toString("utf-8")); + if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null; + const obj = parsed as { sig?: unknown; red?: unknown }; + const envelope: ReasoningEnvelope = {}; + if (typeof obj.sig === "string") envelope.sig = obj.sig; + if (Array.isArray(obj.red)) { + const red = obj.red.filter((r): r is string => typeof r === "string"); + if (red.length > 0) envelope.red = red; + } + const txt = (parsed as { txt?: unknown }).txt; + const hasTxt = typeof txt === "string"; + if (hasTxt) envelope.txt = txt; + const krc = (parsed as { krc?: unknown }).krc; + if (typeof krc === "string" && krc.length > 0) envelope.krc = krc; + return envelope.sig || envelope.red || hasTxt || envelope.krc ? envelope : null; + } catch { + return null; + } finally { + reservation.release(); } - const txt = (parsed as { txt?: unknown }).txt; - const hasTxt = typeof txt === "string"; - if (hasTxt) envelope.txt = txt; - const krc = (parsed as { krc?: unknown }).krc; - if (typeof krc === "string" && krc.length > 0) envelope.krc = krc; - return envelope.sig || envelope.red || hasTxt || envelope.krc ? envelope : null; - } catch { - return null; + } finally { + if (!budget) activeBudget.dispose(); } } diff --git a/src/server/claude-messages.ts b/src/server/claude-messages.ts index 20bc14e195..a8af8896ff 100644 --- a/src/server/claude-messages.ts +++ b/src/server/claude-messages.ts @@ -7,6 +7,7 @@ * unchanged. The Responses output (SSE or JSON) is converted back to Anthropic shape. */ import { FORWARD_HEADERS } from "../adapters/openai-responses"; +import { jsonUtf8Bytes } from "../lib/json-byte-size"; import { sseFieldValue } from "../lib/sse-decoder"; import { enforceAnthropicImageLimits, sniffImageDimensions } from "../adapters/anthropic-image-guard"; import { normalizeAnthropicImages } from "../adapters/anthropic-image-normalize"; @@ -753,13 +754,13 @@ async function handleClaudeMessagesWithBudget( }; delete anthropicBody.thinking; } - const translation = anthropicToResponsesTranslation(anthropicBody, config.claudeCode); + const translation = anthropicToResponsesTranslation(anthropicBody, config.claudeCode, translatorBudget); internalBody = translation.body; // The Anthropic translator builds its body from model/input/store/stream plus sampling // fields only, so the caller intent is applied to the TRANSLATED body rather than the // inbound one. if (fastRow) internalBody.service_tier = "priority"; - translatorBudget.chargeRetained(new TextEncoder().encode(JSON.stringify(internalBody)).byteLength, { kind: "request_copies" }); + translatorBudget.chargeRetained(jsonUtf8Bytes(internalBody), { kind: "request_copies" }); cacheKeySource = translation.cacheKeySource; } catch (err) { const overflow = isTranslatorBudgetExceededError(err); diff --git a/structure/04_transports-and-sidecars.md b/structure/04_transports-and-sidecars.md index c568bb0151..256bd1eae5 100644 --- a/structure/04_transports-and-sidecars.md +++ b/structure/04_transports-and-sidecars.md @@ -1480,6 +1480,23 @@ Unsupported constraints remain in `description` as model guidance instead of dis ## Reasoning display parity (hideThinkingSummary) +Reasoning-envelope serialization uses preflight byte sizing and transient reservations before +creating JSON, UTF-8, or base64 copies. Encoding also admits the matching decode projection, so +a successfully encoded standalone envelope fits the standalone decoder's limit. Callers retain +ownership of returned values; the helper releases only its temporary reservation. Inbound +Anthropic translation carries one budget across all assistant blocks and accounts for retained +envelopes until the response lifecycle disposes it. Standalone translation owns a temporary +budget and disposes it on success or failure. Final translated-request sizing uses plain-JSON +measurement rather than allocating a serialized copy just to measure it. + +[Decision Log] +- 목적과 의도: Keep reasoning replay bounded while preserving opaque values exactly. +- 기존 구현 및 제약 조건: Reasoning continuity needs JSON/base64 envelopes, and existing callers already own retained accounting and typed overflow handling. +- 검토한 주요 대안: Per-field truncation, an independent fixed field limit, or shared transient admission plus cumulative inbound ownership. +- 선택한 방식: Reserve conservative copy projections in the envelope helpers and use the existing request budget across inbound blocks. +- 다른 대안 대신 이 방식을 선택한 이유: Truncation changes signed values; one field limit does not describe aggregate ownership. Existing budget errors retain the established HTTP and stream error contracts. +- 장점, 단점 및 영향: Normal replay is unchanged; envelope admission includes copy overhead and is stricter than a raw-string length ceiling. These are translator accounting limits, not a process-wide RSS guarantee. + `hideThinkingSummary` (request reasoning summary absent/"none" — the routed catalog default) is honored by BOTH reasoning paths: anthropic `thinking_delta` AND raw `reasoning_raw_delta` (openai-chat `reasoning_content`, kiro tags). Hidden reasoning emits an envelope-only reasoning diff --git a/tests/responses/reasoning-envelope.test.ts b/tests/responses/reasoning-envelope.test.ts index 2469b8e46b..4a26ce51db 100644 --- a/tests/responses/reasoning-envelope.test.ts +++ b/tests/responses/reasoning-envelope.test.ts @@ -1,7 +1,10 @@ -import { describe, expect, test } from "bun:test"; -import { anthropicToResponsesBody } from "../../src/claude/inbound"; -import { decodeReasoningEnvelope, encodeReasoningEnvelope } from "../../src/responses/reasoning-envelope"; +import { describe, expect, spyOn, test } from "bun:test"; +import { anthropicToResponsesBody, anthropicToResponsesTranslation } from "../../src/claude/inbound"; +import { decodeReasoningEnvelope, encodeReasoningEnvelope, OCX_REASONING_PREFIX, type ReasoningEnvelope } from "../../src/responses/reasoning-envelope"; import { responsesJsonToAnthropicMessage } from "../../src/claude/outbound"; +import { createTranslatorBudget, TranslatorBudgetExceededError, translatorObservedBufferSnapshot } from "../../src/lib/translator-budget"; +import { jsonUtf8Bytes } from "../../src/lib/json-byte-size"; +import * as budgets from "../../src/lib/translator-budget"; describe("reasoning and tool/result envelopes", () => { test("preserves ordered thinking blocks and genuine signatures", () => { @@ -77,3 +80,105 @@ describe("reasoning and tool/result envelopes", () => { expect(message.content).toEqual([{ type: "thinking", thinking: "", signature: "sig-only" }]); }); }); + +describe("reasoning allocation admission", () => { + test.each(["ascii", "\"\\\n\u0000", "한글😀", "\ud800", "\udc00", ""])('sizes JSON strings exactly: %j', value => { + const data = { sig: value, red: [value, ""], txt: value, krc: value, omitted: undefined }; + const expected = Buffer.byteLength(JSON.stringify(data)); + expect(jsonUtf8Bytes(data, expected)).toBe(expected); + expect(() => jsonUtf8Bytes(data, expected - 1)).toThrow(TranslatorBudgetExceededError); + }); + + test("sizes the translated plain-JSON vocabulary", () => { + const data = { arr: [undefined, null, true, false, 0, -0, 1e30, NaN, Infinity, { text: "x" }], absent: undefined }; + expect(jsonUtf8Bytes(data)).toBe(Buffer.byteLength(JSON.stringify(data))); + }); + + test.each([{ sig: "opaque" }, { red: ["one", "two"] }, { txt: "hidden" }, { krc: "opaque" }, { sig: "s", red: ["r"], txt: "t", krc: "k" }])( + "rejects before JSON/Buffer materialization and admits the exact projected boundary: %j", envelope => { + const json = JSON.stringify(envelope); + const size = Buffer.byteLength(json); + const base64Bytes = 4 * Math.ceil(size / 3); + const limit = Math.max(3 * size + 4 * base64Bytes + 2 * OCX_REASONING_PREFIX.length, 8 * (OCX_REASONING_PREFIX.length + base64Bytes)); + const budget = createTranslatorBudget({ maxTurnBytes: limit - 1 }); + const stringify = spyOn(JSON, "stringify"); + const from = spyOn(Buffer, "from"); + let error: unknown; + let serializations = 0; + let allocations = 0; + try { encodeReasoningEnvelope(envelope, budget); } catch (caught) { error = caught; } + finally { + serializations = stringify.mock.calls.length; + allocations = from.mock.calls.length; + stringify.mockRestore(); from.mockRestore(); + } + expect(error).toBeInstanceOf(TranslatorBudgetExceededError); + expect(serializations).toBe(0); + expect(allocations).toBe(0); + expect(budget.snapshot().currentBytes).toBe(0); + budget.dispose(); + const exact = createTranslatorBudget({ maxTurnBytes: limit }); + try { + const encoded = encodeReasoningEnvelope(envelope, exact); + expect(encoded).toBe(OCX_REASONING_PREFIX + Buffer.from(json).toString("base64")); + expect(decodeReasoningEnvelope(encoded, exact)).toEqual(envelope); + expect(exact.snapshot().currentBytes).toBe(0); + } finally { exact.dispose(); } + }, + ); + + test("bounds preencoded replay before decoding and preserves native blobs", () => { + const encoded = encodeReasoningEnvelope({ txt: "" }); + const budget = createTranslatorBudget({ maxTurnBytes: encoded.length * 8 - 1 }); + const from = spyOn(Buffer, "from"); + let error: unknown; + let allocations = 0; + try { decodeReasoningEnvelope(encoded, budget); } catch (caught) { error = caught; } + finally { allocations = from.mock.calls.length; from.mockRestore(); } + expect(error).toBeInstanceOf(TranslatorBudgetExceededError); + expect(allocations).toBe(0); + expect(decodeReasoningEnvelope("native-opaque", budget)).toBeNull(); + expect(budget.snapshot().currentBytes).toBe(0); + budget.dispose(); + const exact = createTranslatorBudget({ maxTurnBytes: encoded.length * 8 }); + try { expect(decodeReasoningEnvelope(encoded, exact)).toEqual({ txt: "" }); } + finally { exact.dispose(); } + }); + + test.each(["thinking", "redacted_thinking", "owned"])('accounts cumulatively for %s blocks across messages', type => { + const before = translatorObservedBufferSnapshot().currentBytes; + const block = type === "redacted_thinking" ? { type, data: "r" } + : { type: "thinking", thinking: "", signature: type === "owned" ? encodeReasoningEnvelope({ txt: "t" }) : "s" }; + const budget = createTranslatorBudget({ maxTurnBytes: 256 }); + try { + expect(() => anthropicToResponsesTranslation({ model: "m", messages: Array.from({ length: 8 }, () => ({ role: "assistant", content: [block] })) }, undefined, budget)) + .toThrow(TranslatorBudgetExceededError); + expect(budget.snapshot().highWaterBytes).toBeLessThanOrEqual(256); + } finally { budget.dispose(); } + expect(translatorObservedBufferSnapshot().currentBytes).toBe(before); + }); + + test.each(["thinking", "redacted_thinking", "owned"])("handler maps %s admission failure to 413 without dispatch and disposes its budget", async type => { + const { handleClaudeMessages } = await import("../../src/server/claude-messages"); + const signature = type === "owned" ? encodeReasoningEnvelope({ txt: "fixture" }) : "fixture"; + const content = type === "redacted_thinking" ? { type, data: "fixture" } + : { type: "thinking", thinking: "", signature }; + const request = new Request("http://localhost/v1/messages", { + method: "POST", headers: { "content-type": "application/json" }, + body: JSON.stringify({ model: "fixture/model", messages: [{ role: "assistant", content: [content] }] }), + }); + const beforeBytes = budgets.translatorObservedBufferSnapshot().currentBytes; + const beforeCount = budgets.translatorLiveBudgetCountForTests(); + const create = budgets.createTranslatorBudget; + const factory = spyOn(budgets, "createTranslatorBudget").mockImplementation(() => create({ maxTurnBytes: 64 })); + const upstream = spyOn(globalThis, "fetch").mockImplementation(async () => { throw new Error("unexpected upstream dispatch"); }); + try { + const response = await handleClaudeMessages(request, { port: 0, providers: {} }, { model: "", provider: "" }); + expect(response.status).toBe(413); + expect(await response.json()).toMatchObject({ type: "error", error: { type: "request_too_large", code: "translation_buffer_limit" } }); + expect(upstream).not.toHaveBeenCalled(); + expect(budgets.translatorObservedBufferSnapshot().currentBytes).toBe(beforeBytes); + expect(budgets.translatorLiveBudgetCountForTests()).toBe(beforeCount); + } finally { factory.mockRestore(); upstream.mockRestore(); } + }); +}); From eb8cc9ab735a3c2396cb5393bbf62dc473d5716e Mon Sep 17 00:00:00 2001 From: makesomethingshit Date: Mon, 7 Sep 2026 16:24:45 +0900 Subject: [PATCH 098/412] fix(pi): scope generated session affinity to the Pi client [skip ci] (cherry picked from commit 23d869350e9a90359f65624e41ae8e93797ae398) Co-authored-by: makesomethingshit <246213378+makesomethingshit@users.noreply.github.com> (cherry picked from commit 1e65ffd4bc9ba8befdf6e3546643b428106f4650) --- src/clients/config-export.ts | 8 ++++---- tests/clients/prime-client.test.ts | 20 ++++++++------------ tests/config/client-config-export.test.ts | 2 ++ 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/clients/config-export.ts b/src/clients/config-export.ts index e1744c2209..6a94b74d70 100644 --- a/src/clients/config-export.ts +++ b/src/clients/config-export.ts @@ -817,7 +817,7 @@ export interface GajaeGeneratedConfig { * model. The rest of this contract (omitting `cost`) is still ours rather than * a claim about Pi's acceptance. */ -function buildPiClientConfig(ctx: ExportContext): PiGeneratedConfig { +function buildPiClientConfig(ctx: ExportContext, sendSessionAffinityHeaders = false): PiGeneratedConfig { const models: PiModelEntry[] = []; for (const model of normalizeExportModels(ctx.models)) { // Text is the one modality every routed model supports; anything richer must come @@ -860,7 +860,7 @@ function buildPiClientConfig(ctx: ExportContext): PiGeneratedConfig { baseUrl: ctx.baseUrl, api: PI_API_DIALECT, apiKey: LOOPBACK_API_KEY_PLACEHOLDER, - compat: { sendSessionAffinityHeaders: true }, + ...(sendSessionAffinityHeaders ? { compat: { sendSessionAffinityHeaders: true } } : {}), models, }, }, @@ -1033,7 +1033,7 @@ function buildOpencodeContribution(ctx: ExportContext): ManagedContribution { } function buildPiContribution(ctx: ExportContext): ManagedContribution { - const doc = buildPiClientConfig(ctx); + const doc = buildPiClientConfig(ctx, true); return singleFragment("pi", ["providers", OPENCODE_PROVIDER_ID], doc.providers[OPENCODE_PROVIDER_ID]); } @@ -1129,7 +1129,7 @@ export const EXPORT_CLIENTS: Record = { destination: env => piConfigPath(env), apiKeyEnv: "", exportHint: "Pi reads a non-secret placeholder from models.json; loopback needs no key.", - build: buildPiClientConfig, + build: ctx => buildPiClientConfig(ctx, true), format: "json", summarize: summarizePi, buildContribution: buildPiContribution, diff --git a/tests/clients/prime-client.test.ts b/tests/clients/prime-client.test.ts index c88c77508a..6c7c0a2f76 100644 --- a/tests/clients/prime-client.test.ts +++ b/tests/clients/prime-client.test.ts @@ -37,18 +37,14 @@ function context(): ExportContext { } describe("Prime Agent client config", () => { - /** - * The load-bearing claim of this client: Prime Agent is the pi coding agent - * under a different brand, so it reads the SAME models.json contract rather - * than a lookalike. Locking the two documents together is what keeps that - * claim true — if a future Pi-only change diverges, this fails here instead - * of silently shipping Prime users a config their agent rejects. - */ - test("generates byte-for-byte the document Pi generates", () => { - const prime = buildClientConfigText("prime", context()); - const pi = buildClientConfigText("pi", context()); - expect(prime.format).toBe("json"); - expect(prime.text).toBe(pi.text); + test("shares Pi's model contract without opting Prime into session headers", () => { + const prime = buildClientConfig("prime", context()) as PiGeneratedConfig; + const pi = buildClientConfig("pi", context()) as PiGeneratedConfig; + expect(pi.providers[OPENCODE_PROVIDER_ID]!.compat).toEqual({ sendSessionAffinityHeaders: true }); + delete pi.providers[OPENCODE_PROVIDER_ID]!.compat; + expect(prime).toEqual(pi); + expect(buildClientContribution("prime", context()).fragments[0]!.value) + .toEqual(prime.providers[OPENCODE_PROVIDER_ID]); }); test("adds only providers.opencodex, wired to the loopback proxy", () => { diff --git a/tests/config/client-config-export.test.ts b/tests/config/client-config-export.test.ts index 4d70790403..c5a5840b82 100644 --- a/tests/config/client-config-export.test.ts +++ b/tests/config/client-config-export.test.ts @@ -11,6 +11,7 @@ import { LOOPBACK_API_KEY_PLACEHOLDER, SCHEMA_REQUIRED_OUTPUT_BUDGET, buildClientConfig, + buildClientContribution, buildClientConfigText, isExportClientId, normalizeExportModels, @@ -316,6 +317,7 @@ describe("Pi serializer (accept criterion 2)", () => { expect(provider.api).toBe("openai-completions"); expect(provider.apiKey).toBe(LOOPBACK_API_KEY_PLACEHOLDER); expect(provider.compat?.sendSessionAffinityHeaders).toBe(true); + expect(buildClientContribution("pi", ctx()).fragments[0]!.value).toEqual(provider); }); test("cost is omitted on every entry — zeros would assert routed models are free", () => { From 75415170ba2e03398baa569972c4c444683e67fe Mon Sep 17 00:00:00 2001 From: lidge-jun <243035832+lidge-jun@users.noreply.github.com> Date: Mon, 7 Sep 2026 18:27:41 +0900 Subject: [PATCH 099/412] fix: admit final Claude request copies before serialization [skip ci] Co-authored-by: Ingwannu <186453546+Ingwannu@users.noreply.github.com> --- src/server/claude-messages.ts | 26 +++++++++---- tests/responses/reasoning-envelope.test.ts | 44 ++++++++++++++++++++-- 2 files changed, 59 insertions(+), 11 deletions(-) diff --git a/src/server/claude-messages.ts b/src/server/claude-messages.ts index a8af8896ff..c5c929c519 100644 --- a/src/server/claude-messages.ts +++ b/src/server/claude-messages.ts @@ -863,13 +863,25 @@ async function handleClaudeMessagesWithBudget( headers.set("session_id", uuidFromHex(internalBody.prompt_cache_key)); } } - const internalBodyJson = JSON.stringify(internalBody); - translatorBudget.chargeRetained(new TextEncoder().encode(internalBodyJson).byteLength, { kind: "request_copies" }); - const internalReq = new Request("http://localhost/v1/responses", { - method: "POST", - headers, - body: internalBodyJson, - }); + let internalReq: Request; + try { + // The UTF-16 JSON string and the Request's UTF-8 body coexist until dispatch. + const reservation = translatorBudget.reserveTransient(3 * jsonUtf8Bytes(internalBody), { kind: "request_copies" }); + try { + internalReq = new Request("http://localhost/v1/responses", { + method: "POST", + headers, + body: JSON.stringify(internalBody), + }); + reservation.commitRetained(); + } finally { + reservation.release(); + } + } catch (err) { + if (!isTranslatorBudgetExceededError(err)) throw err; + if (logIds) addFinalRequestLog(logIds.requestId, logIds.start, logCtx, 413, { closeReason: "non_stream" }); + return anthropicErrorResponse(413, "request translation buffer exceeded the safe limit", "request_too_large", "translation_buffer_limit"); + } // Request-log wiring mirrors the /v1/responses route: native passthrough finalizes // via the terminal callbacks; routed streams get the Responses-vocabulary log tap diff --git a/tests/responses/reasoning-envelope.test.ts b/tests/responses/reasoning-envelope.test.ts index 4a26ce51db..27e21d5cff 100644 --- a/tests/responses/reasoning-envelope.test.ts +++ b/tests/responses/reasoning-envelope.test.ts @@ -160,8 +160,9 @@ describe("reasoning allocation admission", () => { test.each(["thinking", "redacted_thinking", "owned"])("handler maps %s admission failure to 413 without dispatch and disposes its budget", async type => { const { handleClaudeMessages } = await import("../../src/server/claude-messages"); - const signature = type === "owned" ? encodeReasoningEnvelope({ txt: "fixture" }) : "fixture"; - const content = type === "redacted_thinking" ? { type, data: "fixture" } + const payload = "fixture".repeat(128); + const signature = type === "owned" ? encodeReasoningEnvelope({ txt: payload }) : payload; + const content = type === "redacted_thinking" ? { type, data: payload } : { type: "thinking", thinking: "", signature }; const request = new Request("http://localhost/v1/messages", { method: "POST", headers: { "content-type": "application/json" }, @@ -170,15 +171,50 @@ describe("reasoning allocation admission", () => { const beforeBytes = budgets.translatorObservedBufferSnapshot().currentBytes; const beforeCount = budgets.translatorLiveBudgetCountForTests(); const create = budgets.createTranslatorBudget; - const factory = spyOn(budgets, "createTranslatorBudget").mockImplementation(() => create({ maxTurnBytes: 64 })); + const budget = create({ maxTurnBytes: 4096 }); + const reserve = spyOn(budget, "reserveTransient"); + const charge = spyOn(budget, "chargeRetained"); + const factory = spyOn(budgets, "createTranslatorBudget").mockReturnValue(budget); const upstream = spyOn(globalThis, "fetch").mockImplementation(async () => { throw new Error("unexpected upstream dispatch"); }); try { const response = await handleClaudeMessages(request, { port: 0, providers: {} }, { model: "", provider: "" }); expect(response.status).toBe(413); expect(await response.json()).toMatchObject({ type: "error", error: { type: "request_too_large", code: "translation_buffer_limit" } }); expect(upstream).not.toHaveBeenCalled(); + expect(reserve.mock.calls.some(([, scope]) => scope.kind === "reasoning")).toBe(true); + expect(charge.mock.calls.filter(([, scope]) => scope.kind === "request_copies")).toHaveLength(0); expect(budgets.translatorObservedBufferSnapshot().currentBytes).toBe(beforeBytes); expect(budgets.translatorLiveBudgetCountForTests()).toBe(beforeCount); - } finally { factory.mockRestore(); upstream.mockRestore(); } + } finally { factory.mockRestore(); upstream.mockRestore(); reserve.mockRestore(); charge.mockRestore(); budget.dispose(); } }); + test("final request-copy admission returns 413 before serialization and disposes the budget", async () => { + const { handleClaudeMessages } = await import("../../src/server/claude-messages"); + const request = new Request("http://localhost/v1/messages", { + method: "POST", headers: { "content-type": "application/json" }, + body: JSON.stringify({ model: "fixture/model", messages: [{ role: "user", content: "x".repeat(200) }] }), + }); + const beforeBytes = budgets.translatorObservedBufferSnapshot().currentBytes; + const beforeCount = budgets.translatorLiveBudgetCountForTests(); + const budget = budgets.createTranslatorBudget({ maxTurnBytes: 512 }); + const reserve = spyOn(budget, "reserveTransient"); + const charge = spyOn(budget, "chargeRetained"); + const factory = spyOn(budgets, "createTranslatorBudget").mockReturnValue(budget); + const stringify = spyOn(JSON, "stringify"); + const upstream = spyOn(globalThis, "fetch").mockImplementation(async () => { throw new Error("unexpected upstream dispatch"); }); + try { + const response = await handleClaudeMessages(request, { port: 0, providers: {} }, { model: "", provider: "" }); + expect(response.status).toBe(413); + expect(await response.json()).toMatchObject({ type: "error", error: { type: "request_too_large", code: "translation_buffer_limit" } }); + expect(charge.mock.calls.filter(([, scope]) => scope.kind === "request_copies")).toHaveLength(1); + expect(reserve.mock.calls.filter(([, scope]) => scope.kind === "request_copies")).toHaveLength(1); + expect(stringify.mock.calls.some(([value]) => value && typeof value === "object" && "input" in value)).toBe(false); + expect(upstream).not.toHaveBeenCalled(); + expect(budgets.translatorObservedBufferSnapshot().currentBytes).toBe(beforeBytes); + expect(budgets.translatorLiveBudgetCountForTests()).toBe(beforeCount); + } finally { + factory.mockRestore(); stringify.mockRestore(); upstream.mockRestore(); + reserve.mockRestore(); charge.mockRestore(); budget.dispose(); + } + }); + }); From 697a500339f323157ff20370e6be6bb65803e318 Mon Sep 17 00:00:00 2001 From: lidge-jun <243035832+lidge-jun@users.noreply.github.com> Date: Mon, 7 Sep 2026 18:29:47 +0900 Subject: [PATCH 100/412] test: pin Go affinity identity and header precedence [skip ci] Co-authored-by: makesomethingshit <246213378+makesomethingshit@users.noreply.github.com> --- .../opencode-go-session-header.test.ts | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/tests/providers/opencode-go-session-header.test.ts b/tests/providers/opencode-go-session-header.test.ts index b05e526e1c..ab28c8475f 100644 --- a/tests/providers/opencode-go-session-header.test.ts +++ b/tests/providers/opencode-go-session-header.test.ts @@ -1,10 +1,9 @@ import { afterEach, describe, expect, test } from "bun:test"; import { providerConfigSeed } from "../../src/providers/derive"; -import { deriveOpenCodeGoSessionId, resolveOpenCodeGoTransport } from "../../src/providers/opencode-go-transport"; +import { resolveOpenCodeGoTransport } from "../../src/providers/opencode-go-transport"; import { getProviderRegistryEntry } from "../../src/providers/registry"; import { handleResponses } from "../../src/server/responses/core"; import { handleChatCompletions } from "../../src/server/chat-completions"; -import { normalizeLogConversationId } from "../../src/server/request-log-conversation"; import type { OcxConfig, OcxProviderConfig } from "../../src/types"; const MUSE_MODEL = "muse-spark-1.3-contributor"; @@ -128,10 +127,13 @@ describe("OpenCode Go session affinity (#3344)", () => { expect(bridged.headers.get(SESSION_HEADER)).toBe(chat.headers.get(SESSION_HEADER)); }); - for (const session of ["client-session-a", "ocx_0123456789abcdef0123456789abcdef"]) { + // Fixed vectors independently calculated with SHA-256, including the domain separator. + for (const [session, expected] of [ + ["client-session-a", "ocx_516d593899f34b7baca2db37c7b0c8c5"], + ["ocx_0123456789abcdef0123456789abcdef", "ocx_60bcbfb9a85d3dc23b9b2b1cef3b0882"], + ] as const) { test(`treats inbound ${session.startsWith("ocx_") ? "ocx-prefixed" : "raw"} identity as client input on every ingress`, async () => { const headers = { "content-type": "application/json", [SESSION_HEADER]: session }; - const expected = deriveOpenCodeGoSessionId(normalizeLogConversationId(session)!); const native = await captureRequest({ nativeChat: true, model: "omen-alpha", headers }); const bridged = await captureRequest({ nativeChat: true, model: MUSE_MODEL, headers }); const responses = await captureRequest({ model: MUSE_MODEL, headers }); @@ -149,6 +151,23 @@ describe("OpenCode Go session affinity (#3344)", () => { }); } + test("operator override precedes the Codex lane, which precedes client fallback on every ingress", async () => { + const headers = { ...codexHeaders(), [SESSION_HEADER]: "different-client-fallback" }; + for (const ingress of [ + { nativeChat: true, model: "omen-alpha" }, + { nativeChat: true, model: MUSE_MODEL }, + { model: MUSE_MODEL }, + ]) { + const codex = await captureRequest({ ...ingress, headers }); + expect(codex.headers.get(SESSION_HEADER)).toBe("ocx_67b70584fb755130286eff5488a3be9d"); + const operator = await captureRequest({ + ...ingress, headers, + provider: opencodeGo({ headers: { "X-OpenCode-Session": "different-operator-override" } }), + }); + expect(operator.headers.get(SESSION_HEADER)).toBe("different-operator-override"); + } + }); + test("native Chat does not send Go affinity to an unrelated destination", async () => { const captured = await captureRequest({ nativeChat: true, model: "omen-alpha", providerName: "custom-go", From e0e8d26bb86927fac378d88807f191843a9cf339 Mon Sep 17 00:00:00 2001 From: lidge-jun <243035832+lidge-jun@users.noreply.github.com> Date: Mon, 7 Sep 2026 18:31:24 +0900 Subject: [PATCH 101/412] fix: fall back from native compact 404 to routed compaction [skip ci] Reimplements only the residual compaction portion of #3769; quota attribution remains the implementation already landed through #3791. Co-authored-by: ideabib <221318067+ideabib@users.noreply.github.com> --- .../content/docs/reference/proxy-formats.md | 7 + src/server/responses/compact.ts | 5 +- .../responses-compaction-routing.test.ts | 141 ++++++++++++++++++ 3 files changed, 151 insertions(+), 2 deletions(-) diff --git a/docs-site/src/content/docs/reference/proxy-formats.md b/docs-site/src/content/docs/reference/proxy-formats.md index 0c7b8257bc..593c8ae7a3 100644 --- a/docs-site/src/content/docs/reference/proxy-formats.md +++ b/docs-site/src/content/docs/reference/proxy-formats.md @@ -405,6 +405,13 @@ conversation. | Canonical ChatGPT or official OpenAI route | Forwards the request to the native `/responses/compact` endpoint with the resolved account and model authentication | | Other routed model | Runs an internal, non-streaming, no-tools compaction turn with a `compaction_trigger`; requires exactly one synthetic `compaction` item whose `encrypted_content` is an `ocx1:` envelope; decodes that summary into v1 replacement history | +If the native compact endpoint returns HTTP 404, OpenCodex retries compaction through a regular +Responses turn with the same model selector and session headers. Canonical ChatGPT fallback +turns use upstream SSE; the compact caller still receives JSON. A completed native opaque +compaction item is preserved, while an `ocx1:` summary is decoded into replacement user history. +Failed or incomplete fallback turns return an error instead of replacement history. Other +native compact statuses retain their existing handling. + Codex names a bare OpenAI-family model (for example `gpt-5.6-sol`) for its compaction turns regardless of which provider the operator routes ordinary turns to. Ordinary requests reserve such ids for the canonical `openai` provider. On the compaction surface only — `POST diff --git a/src/server/responses/compact.ts b/src/server/responses/compact.ts index c914dcb4b2..4e7481bb2e 100644 --- a/src/server/responses/compact.ts +++ b/src/server/responses/compact.ts @@ -1094,7 +1094,8 @@ export async function handleResponsesCompact( } } } - return buffered; + // A native compact 404 falls back to a regular Responses compaction turn. + if (buffered.status !== 404) return buffered; } finally { releaseUpstreamHostAdmission(compactHostAdmissionLease); releaseCodexAuthContextProbeLease(authCtx); @@ -1111,7 +1112,7 @@ export async function handleResponsesCompact( // the completed event back into the v1 compact JSON contract below. Combo-dispatched // turns also go out as SSE: failover can land on a canonical child that rejects a // non-streaming turn, and every combo-capable provider already serves streaming traffic. - stream: accountGatedCompactWireModel || route.combo ? true : false, + stream: isCanonicalOpenAiForwardProvider(route.provider) || accountGatedCompactWireModel || route.combo ? true : false, input: [...inputItems, { type: "compaction_trigger" }], }; const internalHeaders = new Headers({ "content-type": "application/json" }); diff --git a/tests/responses/responses-compaction-routing.test.ts b/tests/responses/responses-compaction-routing.test.ts index a787024d95..2a1f69be1e 100644 --- a/tests/responses/responses-compaction-routing.test.ts +++ b/tests/responses/responses-compaction-routing.test.ts @@ -9,6 +9,7 @@ import { mkdtempSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { handleResponses, handleResponsesCompact } from "../../src/server/responses"; +import { OPAQUE_COMPACTION_NOTE, SUMMARY_PREFIX } from "../../src/responses/compaction"; import { looksLikeBackendCiphertext } from "../../src/server/responses/encrypted-payload"; import * as adapterResolveModule from "../../src/server/adapter-resolve"; import * as visionModule from "../../src/vision"; @@ -948,6 +949,146 @@ describe("compact alternate-account attempt (#913)", () => { }); } + for (const [model, account] of [["gpt-5.5", "pool-a"], ["side/gpt-5.5", "pool-b"]] as const) { + test(`native 404 falls back to canonical SSE with ${model} account and session identity`, async () => { + await withPoolEnv("ocx-compact-404-canonical-", async config => { + config.codexAccountNamespaces = { side: "pool-b" }; + const item = { type: "compaction", id: "cmp_native_3769", encrypted_content: "native-opaque-3769" }; + const calls: Array<{ url: string; headers: Headers; body: Record }> = []; + globalThis.fetch = (async (input: string | URL | Request, init?: RequestInit) => { + const request = new Request(input, init); + calls.push({ url: request.url, headers: request.headers, body: await request.json() as Record }); + if (request.url.endsWith("/responses/compact")) return Response.json({ detail: "Not Found" }, { status: 404 }); + return sseResponse([{ type: "response.completed", response: { + id: "resp_compact_3769", status: "completed", output: [item], + } }]); + }) as typeof fetch; + const headers = { "session-id": "compact-3769-session", "thread-id": `compact-3769-${account}`, "x-codex-parent-thread-id": "compact-3769-parent" }; + const response = await handleResponsesCompact(compactionRequest({ + model, input: [{ role: "user", content: "retain this history" }], + }, undefined, headers), config, { model: "", provider: "" }); + expect(response.status).toBe(200); + expect(response.headers.get("content-type")).toContain("application/json"); + expect(await response.json()).toEqual({ output: [item] }); + expect(calls.map(call => call.url)).toEqual([ + "https://chatgpt.com/backend-api/codex/responses/compact", + "https://chatgpt.com/backend-api/codex/responses", + ]); + expect(calls[1]!.body.stream).toBe(true); + expect(calls[1]!.body.model).toBe("gpt-5.5"); + expect((calls[1]!.body.input as Array<{ type?: string }>).filter(value => value.type === "compaction_trigger")).toHaveLength(1); + for (const call of calls) { + expect(call.headers.get("authorization")).toBe(`Bearer ${account}-access-token`); + expect(call.headers.get("chatgpt-account-id")).toBe(account === "pool-a" ? "pool_acc_a" : "pool_acc_b"); + for (const [name, value] of Object.entries(headers)) expect(call.headers.get(name)).toBe(value); + } + }); + }); + } + + test("official key-auth native 404 decodes synthetic fallback into replacement user history", async () => { + const config = { providers: { "openai-apikey": { + adapter: "openai-responses", baseUrl: "https://api.openai.com/v1", authMode: "key", apiKey: "test-key", + } } } as OcxConfig; + const calls: Array<{ url: string; body: Record }> = []; + globalThis.fetch = (async (input: string | URL | Request, init?: RequestInit) => { + const request = new Request(input, init); + calls.push({ url: request.url, body: await request.json() as Record }); + return request.url.endsWith("/responses/compact") + ? Response.json({ detail: "Not Found" }, { status: 404 }) + : jsonResponse(completedPayload("handoff-3769")); + }) as typeof fetch; + const response = await handleResponsesCompact(compactionRequest({ + model: "openai-apikey/gpt-5.5", input: [{ role: "user", content: "retain-3769" }], + tools: [{ type: "function", name: "shell", parameters: { type: "object" } }], + }), config, { model: "", provider: "" }); + expect(response.status).toBe(200); + expect(await response.json()).toEqual({ output: [ + { type: "message", role: "user", content: [{ type: "input_text", text: "retain-3769" }] }, + { type: "message", role: "user", content: [{ type: "input_text", text: `${SUMMARY_PREFIX}\nhandoff-3769` }] }, + ] }); + expect(calls.map(call => call.url)).toEqual(["https://api.openai.com/v1/responses/compact", "https://api.openai.com/v1/responses"]); + expect(calls[1]!.body.tools).toBeUndefined(); + expect(JSON.stringify(calls[1]!.body.input)).not.toContain("compaction_trigger"); + expect(JSON.stringify(calls[1]!.body.input)).toContain("CONTEXT CHECKPOINT COMPACTION"); + }); + + for (const status of [200, 400]) { + test(`native compact ${status} retains its body without the 404 fallback`, async () => { + await withPoolEnv("ocx-compact-404-control-", async config => { + const payload = status === 200 ? { output: [{ type: "compaction", encrypted_content: "native-control" }] } : { error: { message: "invalid compact" } }; + const urls: string[] = []; + globalThis.fetch = (async (input: string | URL | Request) => { + urls.push(typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url); + return Response.json(payload, { status }); + }) as typeof fetch; + const response = await handleResponsesCompact(compactionRequest({ model: "gpt-5.5", input: [] }), config, { model: "", provider: "" }); + expect(response.status).toBe(status); + expect(await response.json()).toEqual(payload); + expect(urls).toEqual(["https://chatgpt.com/backend-api/codex/responses/compact"]); + }); + }); + } + + for (const status of ["failed", "incomplete"] as const) { + test(`native 404 followed by ${status} SSE does not install replacement history`, async () => { + await withPoolEnv("ocx-compact-404-terminal-", async config => { + let calls = 0; + globalThis.fetch = (async () => { + calls++; + if (calls === 1) return Response.json({ detail: "Not Found" }, { status: 404 }); + return sseResponse([{ type: `response.${status}`, response: { + id: "resp_compact_rejected_3769", status, output: [], + } }]); + }) as typeof fetch; + const response = await handleResponsesCompact(compactionRequest({ model: "gpt-5.5", input: [] }), config, { model: "", provider: "" }); + expect(response.status).toBe(502); + const payload = await response.json() as { output?: unknown; error?: unknown }; + expect(payload.output).toBeUndefined(); + expect(payload.error).toBeDefined(); + expect(calls).toBe(2); + }); + }); + } + + test("404 fallback records the compaction serving account for subsequent opaque replay", async () => { + await withPoolEnv("ocx-compact-404-replay-", async config => { + config.codexAccountNamespaces = { side: "pool-b", first: "pool-a" }; + const headers = { "thread-id": `compact-replay-${crypto.randomUUID()}` }; + const item = { type: "compaction", encrypted_content: "native-account-b-3769" }; + const calls: Array<{ body: Record; headers: Headers }> = []; + let compacting = false; + globalThis.fetch = (async (input: string | URL | Request, init?: RequestInit) => { + const request = new Request(input, init); + if (request.url.endsWith("/responses/compact")) return Response.json({ detail: "Not Found" }, { status: 404 }); + calls.push({ body: await request.json() as Record, headers: request.headers }); + return sseResponse([{ type: "response.completed", response: compacting + ? { id: "resp_identity_compact_3769", status: "completed", output: [item] } + : completedPayload("ordinary turn") }]); + }) as typeof fetch; + const turn = async (model: string, input: unknown[]) => { + const response = await handleResponses(compactionRequest({ model, input, stream: true, store: false }, undefined, headers), config, { model: "", provider: "" }); + expect(response.status).toBe(200); + await response.text(); + }; + await turn("first/gpt-5.5", [{ role: "user", content: "seed account A" }]); + compacting = true; + const compact = await handleResponsesCompact(compactionRequest({ model: "side/gpt-5.5", input: [{ role: "user", content: "compact on B" }] }, undefined, headers), config, { model: "", provider: "" }); + expect(compact.status).toBe(200); + const output = (await compact.json() as { output: unknown[] }).output; + expect(output).toEqual([item]); + compacting = false; + await turn("side/gpt-5.5", [...output, { role: "user", content: "continue on B" }]); + expect(calls.at(-1)!.headers.get("authorization")).toBe("Bearer pool-b-access-token"); + expect(JSON.stringify(calls.at(-1)!.body.input)).toContain("native-account-b-3769"); + await turn("first/gpt-5.5", [...output, { role: "user", content: "switch back to A" }]); + expect(calls.at(-1)!.headers.get("authorization")).toBe("Bearer pool-a-access-token"); + expect(JSON.stringify(calls.at(-1)!.body.input)).not.toContain("native-account-b-3769"); + expect(JSON.stringify(calls.at(-1)!.body.input)).toContain(OPAQUE_COMPACTION_NOTE); + expect(calls).toHaveLength(4); + }); + }); + test("native compact headers followed by a stalled body return 504 without retry and release account cleanup", async () => { await withPoolEnv("ocx-compact-body-deadline-", async config => { config.stallTimeoutSec = 2; From d8b18b1ecb013f46585c9e6dadac0b95caa49836 Mon Sep 17 00:00:00 2001 From: lidge-jun <243035832+lidge-jun@users.noreply.github.com> Date: Mon, 7 Sep 2026 18:49:44 +0900 Subject: [PATCH 102/412] fix: share envelope admission budgets and release transient request copies [skip ci] Thread live budgets through bridge and outbound callers, keep abnormal bridge cleanup on the typed overflow path, and retain only the constructed request body after serialization. Sync the authorized adapter and reference locale contracts. Co-authored-by: Ingwannu <186453546+Ingwannu@users.noreply.github.com> --- .../docs/ja/reference/proxy-formats.md | 5 + .../docs/ko/reference/proxy-formats.md | 5 + .../src/content/docs/reference/adapters.md | 4 + .../docs/ru/reference/proxy-formats.md | 6 + .../docs/zh-cn/reference/proxy-formats.md | 4 + src/bridge.ts | 64 ++++--- src/claude/outbound.ts | 10 +- src/server/claude-messages.ts | 13 +- tests/responses/reasoning-envelope.test.ts | 163 +++++++++++++++++- 9 files changed, 241 insertions(+), 33 deletions(-) diff --git a/docs-site/src/content/docs/ja/reference/proxy-formats.md b/docs-site/src/content/docs/ja/reference/proxy-formats.md index 68d7ce5c75..8f0a03bc09 100644 --- a/docs-site/src/content/docs/ja/reference/proxy-formats.md +++ b/docs-site/src/content/docs/ja/reference/proxy-formats.md @@ -131,6 +131,11 @@ WebSocket が無効になっている場合、アップグレード試行では これらのエンドポイントは、Claude Code および互換性のあるクライアントによって使用される Anthropic Messages 言語を話します。ほとんどのリクエストはレスポンスに変換され、通常どおりルーティングされてから、Anthropic JSON または Anthropic SSE に変換されます。 +変換される Messages リクエストでは、推論の再送もリクエスト共通の変換バジェットを使います。 +この制限にはエンコード・デコード時のコピー分も含まれます。超過時は +`translation_buffer_limit` を伴う HTTP 413 を返し、署名や不透明な推論データを切り詰めません。 +ネイティブ Anthropic パススルーには、別の本文サイズ制限が適用されます。 + ネイティブ Anthropic パススルーは、次のすべてが当てはまる場合にのみ適格です。 - ネイティブ パススルーはクロード コード設定で無効になっていません。 diff --git a/docs-site/src/content/docs/ko/reference/proxy-formats.md b/docs-site/src/content/docs/ko/reference/proxy-formats.md index f7ff7f5f27..7837ae4d22 100644 --- a/docs-site/src/content/docs/ko/reference/proxy-formats.md +++ b/docs-site/src/content/docs/ko/reference/proxy-formats.md @@ -174,6 +174,11 @@ SSE 객체, choice delta, `finish_reason`이 있는 종료 choice, `data: [DONE] 이 엔드포인트는 Claude Code와 호환 클라이언트가 사용하는 Anthropic Messages 방언을 말합니다. 대부분의 요청은 Responses로 변환되어 일반적으로 라우팅된 뒤, Anthropic JSON 또는 Anthropic SSE로 다시 변환됩니다. +변환되는 Messages 요청의 reasoning 재전송은 요청 전체의 번역 예산을 공유합니다. 이 예산에는 +인코딩·디코딩 과정에서 생기는 복사본도 포함됩니다. 한도를 초과하면 `translation_buffer_limit`과 +HTTP 413을 반환하며, 한도에 맞추려고 서명이나 불투명 reasoning 데이터를 자르지 않습니다. +네이티브 Anthropic passthrough에는 별도의 본문 크기 제한이 적용됩니다. + 네이티브 Anthropic passthrough는 다음이 모두 참일 때만 적용됩니다. - Claude Code 설정에서 native passthrough가 비활성화되어 있지 않습니다. diff --git a/docs-site/src/content/docs/reference/adapters.md b/docs-site/src/content/docs/reference/adapters.md index 03c56f329b..b1d6029ca9 100644 --- a/docs-site/src/content/docs/reference/adapters.md +++ b/docs-site/src/content/docs/reference/adapters.md @@ -195,6 +195,10 @@ header and does not guarantee a provider cache hit. **Auth:** `key` (`x-api-key` by default, or `Authorization: Bearer` with `apiKeyTransport: "bearer"`) or `oauth` (Bearer + `anthropic-beta`, for Claude Pro/Max). - Converts messages to Anthropic content blocks (text, base64 image, `tool_use`, `thinking`). +- Translated Anthropic Messages reasoning replay shares the request translation budget, including + encoding/decoding copy overhead. Requests exceeding it return HTTP 413 with + `translation_buffer_limit`; signatures and opaque reasoning data are never truncated to fit. + Native Anthropic passthrough uses its separate body-size contract. - **Extended thinking math:** Anthropic requires `max_tokens > thinking.budget_tokens`. The adapter maps reasoning effort to a budget (minimal 1024 … max 32000), then computes a safe `max_tokens` with output headroom, and **drops `temperature`/`top_p`** when thinking is enabled (Anthropic forbids diff --git a/docs-site/src/content/docs/ru/reference/proxy-formats.md b/docs-site/src/content/docs/ru/reference/proxy-formats.md index 26d4db5709..a3ef007784 100644 --- a/docs-site/src/content/docs/ru/reference/proxy-formats.md +++ b/docs-site/src/content/docs/ru/reference/proxy-formats.md @@ -179,6 +179,12 @@ adapter, вместо тихого изменения смысла вернёт клиенты. Большинство запросов переводится в Responses, маршрутизируется обычным образом, а затем обратно в Anthropic JSON или Anthropic SSE. +Повторная передача reasoning в преобразуемых запросах Messages использует общий бюджет +преобразования запроса, включая копии при кодировании и декодировании. При превышении лимита +возвращается HTTP 413 с `translation_buffer_limit`; подписи и непрозрачные данные reasoning +не обрезаются для соблюдения лимита. Для нативного Anthropic passthrough действует отдельный +контракт ограничения размера тела. + Нативный Anthropic passthrough допустим только когда одновременно выполняются все условия: - native passthrough не отключён в конфигурации Claude Code; diff --git a/docs-site/src/content/docs/zh-cn/reference/proxy-formats.md b/docs-site/src/content/docs/zh-cn/reference/proxy-formats.md index 21948d6264..9736aeaff9 100644 --- a/docs-site/src/content/docs/zh-cn/reference/proxy-formats.md +++ b/docs-site/src/content/docs/zh-cn/reference/proxy-formats.md @@ -149,6 +149,10 @@ choice 增量、带 `finish_reason` 的终止 choice,以及 `data: [DONE]`。 这些端点使用 Claude Code 和兼容客户端所采用的 Anthropic Messages 方言。大多数请求会被转换为 Responses,按常规路由,然后再转换回 Anthropic JSON 或 Anthropic SSE。 +转换后的 Messages 请求在重放推理数据时共享整个请求的转换预算,其中包含编码和解码产生的副本开销。 +超出预算时返回 HTTP 413 和 `translation_buffer_limit`,不会为了满足限制而截断签名或不透明推理数据。 +原生 Anthropic 透传使用独立的请求体大小限制。 + 只有在满足以下全部条件时,原生 Anthropic 透传才有资格启用: - Claude Code 配置中尚未禁用原生透传; diff --git a/src/bridge.ts b/src/bridge.ts index ff044a5e52..20e7c3fe09 100644 --- a/src/bridge.ts +++ b/src/bridge.ts @@ -493,7 +493,7 @@ export function bridgeToResponsesSSE( const previousBytes = pendingSignatureBytes + pendingRedacted.reduce((sum, value) => sum + bytesOf(value), 0) + (hiddenText ? hiddenThinkingBytes : 0); - const encoded = encodeReasoningEnvelope(envelope); + const encoded = encodeReasoningEnvelope(envelope, budget); const reservation = budget?.reserveTransient(bytesOf(encoded), { kind: "reasoning" }); pendingSignature = undefined; pendingSignatureBytes = 0; @@ -533,7 +533,7 @@ export function bridgeToResponsesSSE( if (!hiddenRawReasoningText) return; rawReasoningForNextToolCall = hiddenRawReasoningText; const previousBytes = hiddenRawReasoningBytes; - const encrypted = encodeReasoningEnvelope({ txt: hiddenRawReasoningText }); + const encrypted = encodeReasoningEnvelope({ txt: hiddenRawReasoningText }, budget); const reservation = budget?.reserveTransient(bytesOf(encrypted), { kind: "reasoning" }); hiddenRawReasoningText = ""; hiddenRawReasoningBytes = 0; @@ -556,7 +556,7 @@ export function bridgeToResponsesSSE( const flushKiroRedactedReasoning = () => { if (!pendingKiroRedacted) return; const previousBytes = pendingKiroRedactedBytes; - const encrypted = encodeReasoningEnvelope({ krc: pendingKiroRedacted }); + const encrypted = encodeReasoningEnvelope({ krc: pendingKiroRedacted }, budget); const reservation = budget?.reserveTransient(bytesOf(encrypted), { kind: "reasoning" }); pendingKiroRedacted = undefined; pendingKiroRedactedBytes = 0; @@ -902,6 +902,16 @@ export function bridgeToResponsesSSE( gated = true; stepping = false; }; + const attemptTerminationCleanup = (action: () => void): boolean => { + try { + action(); + return !terminated && !closed; + } catch (error) { + if (!isTranslatorBudgetExceededError(error)) throw error; + terminateForTranslatorOverflow(error); + return false; + } + }; const step = async () => { if (stepping || closed) return; stepping = true; @@ -1415,10 +1425,12 @@ export function bridgeToResponsesSSE( return; } if (!terminated) { - flushHiddenRawReasoning(); - if (currentToolCall) failCurrentToolCall(); - if (currentWebSearch) closeCurrentWebSearch("failed", []); - releasePendingWebSources(); + if (!attemptTerminationCleanup(() => { + flushHiddenRawReasoning(); + if (currentToolCall) failCurrentToolCall(); + if (currentWebSearch) closeCurrentWebSearch("failed", []); + releasePendingWebSources(); + })) return; const failure = responseError( 500, "proxy_error", @@ -1448,13 +1460,15 @@ export function bridgeToResponsesSSE( if (!terminated) { // The adapter generator ended without an explicit done/error event. Mark as incomplete // rather than completed so Codex can distinguish a clean finish from a truncated stream. - if (currentMsg) closeCurrentMessage(); - if (currentReasoning) closeCurrentReasoning(); - if (currentRawReasoning) closeCurrentRawReasoning(); - flushHiddenRawReasoning(); - if (currentToolCall) failCurrentToolCall(); - if (currentWebSearch) closeCurrentWebSearch("failed", []); - releasePendingWebSources(); + if (!attemptTerminationCleanup(() => { + if (currentMsg) closeCurrentMessage(); + if (currentReasoning) closeCurrentReasoning(); + if (currentRawReasoning) closeCurrentRawReasoning(); + flushHiddenRawReasoning(); + if (currentToolCall) failCurrentToolCall(); + if (currentWebSearch) closeCurrentWebSearch("failed", []); + releasePendingWebSources(); + })) return; options?.onUsage?.(undefined); await awaitThoughtSignatureDurability(); emit("response.incomplete", { @@ -1493,13 +1507,15 @@ export function bridgeToResponsesSSE( upstreamActivity = false; stallTicks = 0; } else if (++stallTicks >= maxStallTicks) { - if (currentMsg) closeCurrentMessage(); - if (currentReasoning) closeCurrentReasoning(); - if (currentRawReasoning) closeCurrentRawReasoning(); - flushHiddenRawReasoning(); - if (currentToolCall) failCurrentToolCall(); - if (currentWebSearch) closeCurrentWebSearch("failed", []); - releasePendingWebSources(); + if (!attemptTerminationCleanup(() => { + if (currentMsg) closeCurrentMessage(); + if (currentReasoning) closeCurrentReasoning(); + if (currentRawReasoning) closeCurrentRawReasoning(); + flushHiddenRawReasoning(); + if (currentToolCall) failCurrentToolCall(); + if (currentWebSearch) closeCurrentWebSearch("failed", []); + releasePendingWebSources(); + })) return; // #1926 gap 2 residual: this beat callback is synchronous, so the durability // barrier is not awaited on the stall-timeout kill path. The in-memory store is // already updated; only a crash between here and the queued write loses it, @@ -1728,7 +1744,7 @@ function buildResponseJSONWithBudget( if (batchRedacted.length > 0) envelope.red = batchRedacted; const hidden = options?.hideThinkingSummary === true; if (hidden && currentSummaryReasoning && (envelope.sig || envelope.red)) envelope.txt = currentSummaryReasoning; - const encrypted = envelope.sig || envelope.red || envelope.txt ? encodeReasoningEnvelope(envelope) : undefined; + const encrypted = envelope.sig || envelope.red || envelope.txt ? encodeReasoningEnvelope(envelope, budget) : undefined; const sourceBytes = currentSummaryReasoningBytes + batchSignatureBytes + batchRedactedBytes; batchSignature = undefined; batchSignatureBytes = 0; @@ -1756,7 +1772,7 @@ function buildResponseJSONWithBudget( // Same contract as the streaming path: no visible reasoning, txt-only envelope round-trip. pushOutput({ type: "reasoning", id: `rs_${uuid()}`, summary: [], - encrypted_content: encodeReasoningEnvelope({ txt: currentRawReasoning }), + encrypted_content: encodeReasoningEnvelope({ txt: currentRawReasoning }, budget), }, currentRawReasoningBytes, "reasoning"); currentRawReasoning = ""; currentRawReasoningBytes = 0; @@ -2044,7 +2060,7 @@ function buildResponseJSONWithBudget( // pushOutput reserves the item itself and releases the retained raw blob it replaces. pushOutput({ type: "reasoning", id: `rs_${uuid()}`, summary: [], - encrypted_content: encodeReasoningEnvelope({ krc: batchKiroRedacted }), + encrypted_content: encodeReasoningEnvelope({ krc: batchKiroRedacted }, budget), }, batchKiroRedactedBytes, "reasoning"); batchKiroRedacted = undefined; batchKiroRedactedBytes = 0; diff --git a/src/claude/outbound.ts b/src/claude/outbound.ts index ac06afac2d..1975d5b390 100644 --- a/src/claude/outbound.ts +++ b/src/claude/outbound.ts @@ -308,7 +308,7 @@ export function responsesSseToAnthropicSse( open.webSearchArgsEmitted = true; } if (open.kind === "thinking") { - const signature = open.reasoningSig ?? encodeReasoningEnvelope({ txt: open.thinkingBuf ?? "" }); + const signature = open.reasoningSig ?? encodeReasoningEnvelope({ txt: open.thinkingBuf ?? "" }, translatorBudget); emit("content_block_delta", { type: "content_block_delta", index: open.index, delta: { type: "signature_delta", signature }, @@ -561,7 +561,7 @@ export function responsesSseToAnthropicSse( else if (open && open.kind === "text" && item.type === "message") closeOpenBlock(); else if (item.type === "reasoning") { const encrypted = typeof item.encrypted_content === "string" ? item.encrypted_content : ""; - const env = encrypted ? decodeReasoningEnvelope(encrypted) : null; + const env = encrypted ? decodeReasoningEnvelope(encrypted, translatorBudget) : null; const red = env?.red ?? []; if (env?.sig && open?.kind !== "thinking") ensureBlock("thinking"); if (open?.kind === "thinking") { @@ -785,7 +785,7 @@ export function responsesSseToAnthropicSse( } /** Non-streaming: /v1/responses JSON -> Anthropic message JSON. */ -export function responsesJsonToAnthropicMessage(json: unknown, model: string): Rec { +export function responsesJsonToAnthropicMessage(json: unknown, model: string, translatorBudget?: TranslatorBudget): Rec { const body = isRec(json) ? json : {}; const output = Array.isArray(body.output) ? body.output : []; const content: Rec[] = []; @@ -817,14 +817,14 @@ export function responsesJsonToAnthropicMessage(json: unknown, model: string): R } } const encrypted = typeof raw.encrypted_content === "string" ? raw.encrypted_content : ""; - const env = encrypted ? decodeReasoningEnvelope(encrypted) : null; + const env = encrypted ? decodeReasoningEnvelope(encrypted, translatorBudget) : null; // Legacy combined envelopes place redacted blocks before the signed block, // matching the Anthropic adapter. New bridge output uses separate items. for (const data of env?.red ?? []) content.push({ type: "redacted_thinking", data }); // env.txt may be locally hidden text. Do not expose it here or manufacture // a new signed continuity carrier; hidden-summary replay remains limited. if (parts.length > 0 || env?.sig) { - content.push({ type: "thinking", thinking: parts.join("\n\n"), signature: env?.sig ?? encodeReasoningEnvelope({ txt: parts.join("\n\n") }) }); + content.push({ type: "thinking", thinking: parts.join("\n\n"), signature: env?.sig ?? encodeReasoningEnvelope({ txt: parts.join("\n\n") }, translatorBudget) }); } break; } diff --git a/src/server/claude-messages.ts b/src/server/claude-messages.ts index c5c929c519..f6906de7e0 100644 --- a/src/server/claude-messages.ts +++ b/src/server/claude-messages.ts @@ -866,17 +866,18 @@ async function handleClaudeMessagesWithBudget( let internalReq: Request; try { // The UTF-16 JSON string and the Request's UTF-8 body coexist until dispatch. - const reservation = translatorBudget.reserveTransient(3 * jsonUtf8Bytes(internalBody), { kind: "request_copies" }); + const bodyBytes = jsonUtf8Bytes(internalBody); + const reservation = translatorBudget.reserveTransient(3 * bodyBytes, { kind: "request_copies" }); try { internalReq = new Request("http://localhost/v1/responses", { method: "POST", headers, body: JSON.stringify(internalBody), }); - reservation.commitRetained(); } finally { reservation.release(); } + translatorBudget.chargeRetained(bodyBytes, { kind: "request_copies" }); } catch (err) { if (!isTranslatorBudgetExceededError(err)) throw err; if (logIds) addFinalRequestLog(logIds.requestId, logIds.start, logCtx, 413, { closeReason: "non_stream" }); @@ -1019,7 +1020,13 @@ async function handleClaudeMessagesWithBudget( } return anthropicErrorResponse(502, error?.message ?? "upstream request failed", "api_error"); } - const message = responsesJsonToAnthropicMessage(json, requestedModel); + let message: Rec; + try { + message = responsesJsonToAnthropicMessage(json, requestedModel, translatorBudget); + } catch (err) { + if (!isTranslatorBudgetExceededError(err)) throw err; + return anthropicErrorResponse(413, "upstream translation buffer exceeded the safe limit", "request_too_large", "translation_buffer_limit"); + } if ((message as Rec).type === "error") { return new Response(JSON.stringify(message), { status: 529, diff --git a/tests/responses/reasoning-envelope.test.ts b/tests/responses/reasoning-envelope.test.ts index 27e21d5cff..6ffc2d750f 100644 --- a/tests/responses/reasoning-envelope.test.ts +++ b/tests/responses/reasoning-envelope.test.ts @@ -1,7 +1,9 @@ import { describe, expect, spyOn, test } from "bun:test"; +import { bridgeToResponsesSSE, buildResponseJSON } from "../../src/bridge"; +import type { AdapterEvent } from "../../src/types"; import { anthropicToResponsesBody, anthropicToResponsesTranslation } from "../../src/claude/inbound"; import { decodeReasoningEnvelope, encodeReasoningEnvelope, OCX_REASONING_PREFIX, type ReasoningEnvelope } from "../../src/responses/reasoning-envelope"; -import { responsesJsonToAnthropicMessage } from "../../src/claude/outbound"; +import { responsesJsonToAnthropicMessage, responsesSseToAnthropicSse } from "../../src/claude/outbound"; import { createTranslatorBudget, TranslatorBudgetExceededError, translatorObservedBufferSnapshot } from "../../src/lib/translator-budget"; import { jsonUtf8Bytes } from "../../src/lib/json-byte-size"; import * as budgets from "../../src/lib/translator-budget"; @@ -217,4 +219,163 @@ describe("reasoning allocation admission", () => { } }); + test("successful Request construction retains only its UTF-8 body after releasing temporary copies", async () => { + const { handleClaudeMessages } = await import("../../src/server/claude-messages"); + const request = new Request("http://localhost/v1/messages", { + method: "POST", headers: { "content-type": "application/json" }, + body: JSON.stringify({ model: "fixture/model", messages: [{ role: "user", content: "hello" }] }), + }); + const budget = budgets.createTranslatorBudget({ maxTurnBytes: 4096 }); + const originalCharge = budget.chargeRetained.bind(budget); + const copies: Array<{ bytes: number; before: number; after: number }> = []; + const charge = spyOn(budget, "chargeRetained").mockImplementation((bytes, scope) => { + const before = budget.snapshot().currentBytes; + originalCharge(bytes, scope); + if (scope.kind === "request_copies") copies.push({ bytes, before, after: budget.snapshot().currentBytes }); + }); + const reserve = spyOn(budget, "reserveTransient"); + const factory = spyOn(budgets, "createTranslatorBudget").mockReturnValue(budget); + const stringify = spyOn(JSON, "stringify"); + try { + const response = await handleClaudeMessages(request, { port: 0, providers: {} }, { model: "", provider: "" }); + expect(response.status).toBe(404); // Serialization succeeded; the synthetic model is deliberately absent. + await response.text(); + const serialized = stringify.mock.calls.find(([value]) => value && typeof value === "object" && "input" in value)?.[0]; + expect(serialized).toBeDefined(); + const expected = Buffer.byteLength(JSON.stringify(serialized)); + expect(copies).toHaveLength(2); + expect(copies[1]!.bytes).toBe(expected); + expect(copies[1]!.before).toBe(copies[0]!.after); + expect(reserve.mock.calls.filter(([, scope]) => scope.kind === "request_copies").map(([bytes]) => bytes)).toEqual([3 * expected]); + expect(budget.snapshot().currentBytes).toBe(0); + } finally { stringify.mockRestore(); factory.mockRestore(); reserve.mockRestore(); charge.mockRestore(); budget.dispose(); } + }); + + for (const event of [ + { type: "thinking_signature", signature: "r".repeat(256) }, + { type: "redacted_thinking", data: "r".repeat(256) }, + { type: "reasoning_raw_delta", text: "r".repeat(256) }, + { type: "kiro_redacted_reasoning", data: "r".repeat(256) }, + ] as const) { + for (const mode of ["batch", "stream"] as const) { + test(`${mode} ${event.type} admits envelope copies against the already charged turn`, async () => { + const budget = createTranslatorBudget({ maxTurnBytes: 4096 }); + budget.chargeRetained(2048, { kind: "request_copies" }); + const stringify = spyOn(JSON, "stringify"); + try { + const events: AdapterEvent[] = [event, { type: "done" }]; + if (mode === "batch") { + expect(() => buildResponseJSON(events, "fixture/model", { translatorBudget: budget, hideThinkingSummary: true })) + .toThrow(TranslatorBudgetExceededError); + } else { + async function* source() { yield* events; } + const wire = await new Response(bridgeToResponsesSSE(source(), "fixture/model", undefined, undefined, undefined, undefined, undefined, + { translatorBudget: budget, hideThinkingSummary: true })).text(); + expect(wire).toContain('"code":"translation_buffer_limit"'); + expect(wire).not.toContain('event: response.completed'); + } + expect(stringify.mock.calls.some(([value]) => value && typeof value === "object" + && ("sig" in value || "txt" in value || "red" in value || "krc" in value))).toBe(false); + } finally { stringify.mockRestore(); budget.dispose(); } + }); + } + } + + for (const encoded of [false, true]) { + test(`JSON outbound ${encoded ? "decoding" : "encoding"} uses the caller budget before allocation`, () => { + const item = encoded + ? { type: "reasoning", encrypted_content: encodeReasoningEnvelope({ sig: "r".repeat(256) }), summary: [] } + : { type: "reasoning", summary: [{ type: "summary_text", text: "r".repeat(256) }] }; + const budget = createTranslatorBudget({ maxTurnBytes: 4096 }); + budget.chargeRetained(2048, { kind: "request_copies" }); + const from = spyOn(Buffer, "from"); + try { + expect(() => responsesJsonToAnthropicMessage({ output: [item] }, "fixture/model", budget)).toThrow(TranslatorBudgetExceededError); + expect(from).not.toHaveBeenCalled(); + } finally { from.mockRestore(); budget.dispose(); } + }); + } + + for (const ending of ["throw", "eof", "stall"] as const) { + for (const overflow of [false, true]) { + test(`hidden reasoning ${ending} cleanup ${overflow ? "reports one budget failure" : "preserves its admitted terminal"}`, async () => { + const budget = createTranslatorBudget({ maxTurnBytes: overflow ? 4096 : 65536 }); + budget.chargeRetained(2048, { kind: "request_copies" }); + const accumulated = Promise.withResolvers(); + const pending = Promise.withResolvers>(); + let reads = 0; + let returns = 0; + let cancelled = 0; + let clears = 0; + let beat = () => {}; + const source: AsyncIterableIterator = { + [Symbol.asyncIterator]() { return this; }, + async next() { + if (++reads === 1) return { done: false, value: { type: "reasoning_raw_delta", text: "r".repeat(256) } }; + accumulated.resolve(); + if (ending === "throw") throw new Error("synthetic generator failure"); + if (ending === "eof") return { done: true, value: undefined }; + return pending.promise; + }, + async return() { returns++; pending.resolve({ done: true, value: undefined }); return { done: true, value: undefined }; }, + }; + const stringify = spyOn(JSON, "stringify"); + try { + const stream = bridgeToResponsesSSE(source, "fixture/model", undefined, undefined, undefined, + () => { cancelled++; }, 500, { + translatorBudget: budget, hideThinkingSummary: true, stallTimeoutSec: 1, + timers: { setInterval(callback) { beat = callback; return 1; }, clearInterval() { clears++; beat = () => {}; } }, + }); + const result = new Response(stream).text(); + await accumulated.promise; + if (ending === "stall") { beat(); beat(); beat(); } + const wire = await result; + const envelopes = stringify.mock.calls.filter(([value]) => value && typeof value === "object" && "txt" in value); + expect(wire.match(/data: \[DONE\]/g)).toHaveLength(1); + expect(wire).not.toContain("event: response.completed"); + expect(clears).toBe(1); + if (overflow) { + expect(envelopes).toHaveLength(0); + expect(wire.match(/event: response.failed/g)).toHaveLength(1); + expect(wire).toContain('"code":"translation_buffer_limit"'); + expect(wire).not.toContain("event: response.incomplete"); + expect(cancelled).toBe(1); + expect(returns).toBe(1); + } else { + expect(envelopes).toHaveLength(1); + expect(wire).not.toContain("translation_buffer_limit"); + expect(wire.match(new RegExp(`event: response.${ending === "throw" ? "failed" : "incomplete"}`, "g"))).toHaveLength(1); + expect(cancelled).toBe(ending === "eof" ? 0 : 1); + } + } finally { stringify.mockRestore(); pending.resolve({ done: true, value: undefined }); budget.dispose(); } + }); + } + } + + for (const encoded of [false, true]) { + test(`SSE outbound ${encoded ? "decoding" : "encoding"} admits against its live turn budget`, async () => { + const text = "r".repeat(512); + const events = encoded ? [{ type: "response.output_item.done", item: { + type: "reasoning", encrypted_content: encodeReasoningEnvelope({ sig: text }), summary: [], + } }] : [ + { type: "response.reasoning_summary_text.delta", delta: text }, + { type: "response.completed", response: { status: "completed", output: [] } }, + ]; + const frames = events.map(event => new TextEncoder().encode(`event: ${event.type}\ndata: ${JSON.stringify(event)}\n\n`)); + const budget = createTranslatorBudget({ maxTurnBytes: 8192 }); + budget.chargeRetained(4096, { kind: "request_copies" }); + const reserve = spyOn(budget, "reserveTransient"); + const from = spyOn(Buffer, "from"); + try { + const upstream = new ReadableStream({ start(controller) { frames.forEach(frame => controller.enqueue(frame)); controller.close(); } }); + const wire = await new Response(responsesSseToAnthropicSse(upstream, "fixture/model", { translatorBudget: budget, pingIntervalMs: 0 })).text(); + expect(reserve.mock.calls.some(([bytes, scope]) => scope.kind === "reasoning" && bytes > 4096)).toBe(true); + expect(from).not.toHaveBeenCalled(); + expect(wire.match(/event: error/g)).toHaveLength(1); + expect(wire).toContain('"code":"translation_buffer_limit"'); + expect(wire).not.toContain("event: message_stop"); + } finally { reserve.mockRestore(); from.mockRestore(); budget.dispose(); } + }); + } + }); From feb1855df91e5db351699d959d88d7e6c21c0f93 Mon Sep 17 00:00:00 2001 From: lidge-jun <243035832+lidge-jun@users.noreply.github.com> Date: Mon, 7 Sep 2026 18:59:23 +0900 Subject: [PATCH 103/412] docs: include Pi session affinity in every guide example [skip ci] Co-authored-by: makesomethingshit <246213378+makesomethingshit@users.noreply.github.com> --- docs-site/src/content/docs/fr/guides/pi.md | 5 +++++ docs-site/src/content/docs/guides/pi.md | 5 +++++ docs-site/src/content/docs/ja/guides/pi.md | 5 +++++ docs-site/src/content/docs/ko/guides/pi.md | 5 +++++ docs-site/src/content/docs/ru/guides/pi.md | 5 +++++ docs-site/src/content/docs/tr/guides/pi.md | 5 +++++ docs-site/src/content/docs/zh-cn/guides/pi.md | 5 +++++ docs-site/src/content/docs/zh-tw/guides/pi.md | 5 +++++ 8 files changed, 40 insertions(+) diff --git a/docs-site/src/content/docs/fr/guides/pi.md b/docs-site/src/content/docs/fr/guides/pi.md index eab8960063..030d91679c 100644 --- a/docs-site/src/content/docs/fr/guides/pi.md +++ b/docs-site/src/content/docs/fr/guides/pi.md @@ -27,6 +27,9 @@ d’exportation de la variable d’environnement et le nombre de modèles dotés "baseUrl": "http://127.0.0.1:10100/v1", "api": "openai-completions", "apiKey": "$OPENCODEX_API_KEY", + "compat": { + "sendSessionAffinityHeaders": true + }, "models": [ { "id": "anthropic/claude-opus-5", @@ -41,6 +44,8 @@ d’exportation de la variable d’environnement et le nombre de modèles dotés } ``` +Les fournisseurs Pi générés activent `compat.sendSessionAffinityHeaders`. Conservez ce réglage lors de la fusion ou de la modification manuelle du fournisseur : Pi transmet un identifiant de session stable, dont OpenCodex dérive l’affinité pour la destination canonique OpenCode Go. Pi peut omettre cet identifiant lorsque `cacheRetention` vaut `none`. + Les identifiants de modèle sont les sélecteurs canoniques du proxy : les modèles routés apparaissent donc sous la forme `provider/model` (`anthropic/claude-opus-5`) et les slugs natifs OpenAI restent sans préfixe (`gpt-5.6-sol`). Le `name` suffixe — `(anthropic)`, `(native)`, `(routed)` — permet de distinguer, dans le sélecteur de Pi, deux modèles de même nom diff --git a/docs-site/src/content/docs/guides/pi.md b/docs-site/src/content/docs/guides/pi.md index c44b97f12a..f44e4be381 100644 --- a/docs-site/src/content/docs/guides/pi.md +++ b/docs-site/src/content/docs/guides/pi.md @@ -27,6 +27,9 @@ export line, and how many models carry authoritative context limits. "baseUrl": "http://127.0.0.1:10100/v1", "api": "openai-completions", "apiKey": "$OPENCODEX_API_KEY", + "compat": { + "sendSessionAffinityHeaders": true + }, "models": [ { "id": "anthropic/claude-opus-5", @@ -41,6 +44,8 @@ export line, and how many models carry authoritative context limits. } ``` +Generated Pi providers enable `compat.sendSessionAffinityHeaders`. Keep this flag when merging or manually editing the provider: Pi supplies a stable session identity and OpenCodex derives canonical OpenCode Go affinity from it. Pi may omit the identity when `cacheRetention` is `none`. + Model ids are the proxy's canonical selectors, so routed models appear as `provider/model` (`anthropic/claude-opus-5`) and native OpenAI slugs stay unprefixed (`gpt-5.6-sol`). The `name` suffix — `(anthropic)`, `(native)`, `(routed)` — is what makes two same-named models from diff --git a/docs-site/src/content/docs/ja/guides/pi.md b/docs-site/src/content/docs/ja/guides/pi.md index 788fe48c60..9b637e84e4 100644 --- a/docs-site/src/content/docs/ja/guides/pi.md +++ b/docs-site/src/content/docs/ja/guides/pi.md @@ -23,6 +23,9 @@ ocx export --client pi "baseUrl": "http://127.0.0.1:10100/v1", "api": "openai-completions", "apiKey": "$OPENCODEX_API_KEY", + "compat": { + "sendSessionAffinityHeaders": true + }, "models": [ { "id": "anthropic/claude-opus-5", @@ -37,6 +40,8 @@ ocx export --client pi } ``` +生成される Pi プロバイダーでは `compat.sendSessionAffinityHeaders` が有効です。設定をマージしたり手動で編集したりする際も、このフラグを保持してください。Pi が送る安定したセッション識別子から、OpenCodex が正規の OpenCode Go 接続先用の affinity を生成します。`cacheRetention` が `none` の場合、Pi は識別子を送信しないことがあります。 + モデル ID はプロキシの正規セレクターであるため、ルーティングされたモデルは `provider/model` (`anthropic/claude-opus-5`) として表示され、ネイティブ OpenAI スラグはプレフィックスなし (`gpt-5.6-sol`) のままになります。 `name` サフィックス (`(anthropic)`、`(native)`、`(routed)`) により、異なるアップストリームの 2 つの同じ名前のモデルが Pi のピッカーで区別できるようになります。 ## どこへ行くのか diff --git a/docs-site/src/content/docs/ko/guides/pi.md b/docs-site/src/content/docs/ko/guides/pi.md index 648d71060e..6bda9c2b36 100644 --- a/docs-site/src/content/docs/ko/guides/pi.md +++ b/docs-site/src/content/docs/ko/guides/pi.md @@ -27,6 +27,9 @@ ocx export --client pi "baseUrl": "http://127.0.0.1:10100/v1", "api": "openai-completions", "apiKey": "$OPENCODEX_API_KEY", + "compat": { + "sendSessionAffinityHeaders": true + }, "models": [ { "id": "anthropic/claude-opus-5", @@ -41,6 +44,8 @@ ocx export --client pi } ``` +생성된 Pi provider에는 `compat.sendSessionAffinityHeaders`가 활성화됩니다. provider를 병합하거나 직접 수정할 때 이 설정을 유지하세요. Pi가 안정적인 세션 식별자를 보내면 OpenCodex가 이를 바탕으로 정규 OpenCode Go 대상의 affinity를 계산합니다. `cacheRetention`이 `none`이면 Pi가 식별자를 보내지 않을 수 있습니다. + 모델 id는 프록시의 정규 선택자이므로, 라우팅된 모델은 `provider/model` (`anthropic/claude-opus-5`) 형태로 나타나고, 네이티브 OpenAI slug는 접두사 없이 (`gpt-5.6-sol`) 유지됩니다. `name` 접미사인 `(anthropic)`, `(native)`, `(routed)`는 diff --git a/docs-site/src/content/docs/ru/guides/pi.md b/docs-site/src/content/docs/ru/guides/pi.md index 0960ecf49a..e36a73da7e 100644 --- a/docs-site/src/content/docs/ru/guides/pi.md +++ b/docs-site/src/content/docs/ru/guides/pi.md @@ -27,6 +27,9 @@ ocx export --client pi "baseUrl": "http://127.0.0.1:10100/v1", "api": "openai-completions", "apiKey": "$OPENCODEX_API_KEY", + "compat": { + "sendSessionAffinityHeaders": true + }, "models": [ { "id": "anthropic/claude-opus-5", @@ -41,6 +44,8 @@ ocx export --client pi } ``` +В создаваемой конфигурации Pi включён `compat.sendSessionAffinityHeaders`. Сохраняйте этот флаг при объединении или ручном редактировании провайдера: Pi передаёт стабильный идентификатор сессии, из которого OpenCodex формирует affinity для канонического OpenCode Go. При `cacheRetention: none` Pi может не передавать идентификатор. + Id моделей — это канонические селекторы прокси, поэтому маршрутизируемые модели появляются как `provider/model` (`anthropic/claude-opus-5`), а нативные slug OpenAI остаются без префикса (`gpt-5.6-sol`). Суффикс в `name` — `(anthropic)`, `(native)`, `(routed)` — как раз и позволяет diff --git a/docs-site/src/content/docs/tr/guides/pi.md b/docs-site/src/content/docs/tr/guides/pi.md index 0741f7be51..fe6044de28 100644 --- a/docs-site/src/content/docs/tr/guides/pi.md +++ b/docs-site/src/content/docs/tr/guides/pi.md @@ -31,6 +31,9 @@ export line, and how many models carry authoritative context limits. "baseUrl": "http://127.0.0.1:10100/v1", "api": "openai-completions", "apiKey": "$OPENCODEX_API_KEY", + "compat": { + "sendSessionAffinityHeaders": true + }, "models": [ { "id": "anthropic/claude-opus-5", @@ -45,6 +48,8 @@ export line, and how many models carry authoritative context limits. } ``` +Oluşturulan Pi sağlayıcılarında `compat.sendSessionAffinityHeaders` etkinleştirilir. Sağlayıcıyı birleştirirken veya elle düzenlerken bu ayarı koruyun: Pi sabit bir oturum kimliği gönderir ve OpenCodex bu kimlikten kanonik OpenCode Go hedefi için oturum yakınlığı üretir. `cacheRetention` değeri `none` olduğunda Pi kimliği göndermeyebilir. + Model ids are the proxy's canonical selectors, so routed models appear as `provider/model` (`anthropic/claude-opus-5`) and native OpenAI slugs stay unprefixed diff --git a/docs-site/src/content/docs/zh-cn/guides/pi.md b/docs-site/src/content/docs/zh-cn/guides/pi.md index ad868e3194..c9ebf7b4a6 100644 --- a/docs-site/src/content/docs/zh-cn/guides/pi.md +++ b/docs-site/src/content/docs/zh-cn/guides/pi.md @@ -23,6 +23,9 @@ ocx export --client pi "baseUrl": "http://127.0.0.1:10100/v1", "api": "openai-completions", "apiKey": "$OPENCODEX_API_KEY", + "compat": { + "sendSessionAffinityHeaders": true + }, "models": [ { "id": "anthropic/claude-opus-5", @@ -37,6 +40,8 @@ ocx export --client pi } ``` +生成的 Pi 提供方配置启用了 `compat.sendSessionAffinityHeaders`。合并或手动编辑提供方时请保留该设置:Pi 提供稳定的会话标识,OpenCodex 据此为规范的 OpenCode Go 目标生成会话亲和标识。`cacheRetention` 为 `none` 时,Pi 可能不发送会话标识。 + 模型 id 是代理的规范选择器,因此已路由模型会显示为 `provider/model`(`anthropic/claude-opus-5`),而原生 OpenAI slug 会保持不带前缀(`gpt-5.6-sol`)。`name` 后缀 - `(anthropic)`、`(native)`、`(routed)` - 负责让两个同名但来自不同上游的模型在 Pi 的选择器中可区分。 ## 放置位置 diff --git a/docs-site/src/content/docs/zh-tw/guides/pi.md b/docs-site/src/content/docs/zh-tw/guides/pi.md index 0353338574..d8e9b62510 100644 --- a/docs-site/src/content/docs/zh-tw/guides/pi.md +++ b/docs-site/src/content/docs/zh-tw/guides/pi.md @@ -23,6 +23,9 @@ ocx export --client pi "baseUrl": "http://127.0.0.1:10100/v1", "api": "openai-completions", "apiKey": "$OPENCODEX_API_KEY", + "compat": { + "sendSessionAffinityHeaders": true + }, "models": [ { "id": "anthropic/claude-opus-5", @@ -37,6 +40,8 @@ ocx export --client pi } ``` +產生的 Pi 供應商設定會啟用 `compat.sendSessionAffinityHeaders`。合併或手動編輯供應商時請保留此設定:Pi 提供穩定的工作階段識別碼,OpenCodex 據此為標準 OpenCode Go 目標產生工作階段親和識別碼。當 `cacheRetention` 為 `none` 時,Pi 可能不傳送識別碼。 + 模型 id 是代理的規範選擇器,因此路由模型顯示為 `provider/model`(`anthropic/claude-opus-5`),而原生 OpenAI slug 保持無前綴(`gpt-5.6-sol`)。`name` 後綴 — `(anthropic)`、`(native)`、`(routed)` — 正是讓來自不同上游的兩個同名模型在 Pi 的 picker 中可區分的關鍵。 ## 放置位置 From c84cc3b3e076b6c49cf93a6ca267f6303a698f5b Mon Sep 17 00:00:00 2001 From: lidge-jun <243035832+lidge-jun@users.noreply.github.com> Date: Mon, 7 Sep 2026 18:33:18 +0900 Subject: [PATCH 104/412] docs: describe native compact 404 fallback in route table [skip ci] Co-authored-by: ideabib <221318067+ideabib@users.noreply.github.com> --- docs-site/src/content/docs/reference/proxy-formats.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs-site/src/content/docs/reference/proxy-formats.md b/docs-site/src/content/docs/reference/proxy-formats.md index 593c8ae7a3..1f2e589252 100644 --- a/docs-site/src/content/docs/reference/proxy-formats.md +++ b/docs-site/src/content/docs/reference/proxy-formats.md @@ -402,7 +402,7 @@ conversation. | Route type | Behavior | | --- | --- | -| Canonical ChatGPT or official OpenAI route | Forwards the request to the native `/responses/compact` endpoint with the resolved account and model authentication | +| Canonical ChatGPT or official OpenAI route | Tries the native `/responses/compact` endpoint with the resolved account and model authentication; HTTP 404 falls back to a regular Responses compaction turn | | Other routed model | Runs an internal, non-streaming, no-tools compaction turn with a `compaction_trigger`; requires exactly one synthetic `compaction` item whose `encrypted_content` is an `ocx1:` envelope; decodes that summary into v1 replacement history | If the native compact endpoint returns HTTP 404, OpenCodex retries compaction through a regular From e96b5c52e05e9fd6f5b9cb4aedc96b171f4a4872 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 19:19:06 +0900 Subject: [PATCH 105/412] fix(responses): make whole-string citation stripping agree with the streaming filter After #3868 the streaming filter keeps a malformed START verbatim when a later START opens a real span, but stripCitationMarkers still paired the first START with that later span's END and deleted everything between. bridge.ts re-strips the accumulated text for output_text.done and output_item.done, so the terminal text disagreed with the concatenated deltas. Walk START-delimited segments in the whole-string path too, and share the 4096 span bound with the whole-string path (an over-bound span that is terminated late is malformed text in both), and assert delta-vs-whole equality across several chunkings. Found by the lane A fresh-base composition audit on dev d00615d56. Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com> --- src/responses/citation-markers.ts | 53 +++++++++++++----------- tests/responses/citation-markers.test.ts | 33 +++++++++++++++ 2 files changed, 62 insertions(+), 24 deletions(-) diff --git a/src/responses/citation-markers.ts b/src/responses/citation-markers.ts index 3e3943cad5..9c56c7a197 100644 --- a/src/responses/citation-markers.ts +++ b/src/responses/citation-markers.ts @@ -42,23 +42,24 @@ export function hasCitationMarker(text: string): boolean { */ export function stripCitationMarkers(text: string): string { if (!text.includes(CITATION_MARKER_START)) return text; - let out = ""; - let index = 0; - for (;;) { - const start = text.indexOf(CITATION_MARKER_START, index); - if (start === -1) { - out += text.slice(index); - return out; - } - const end = text.indexOf(CITATION_MARKER_END, start + 1); - if (end === -1) { - // Unterminated: keep the rest verbatim. - out += text.slice(index); - return out; - } - out += text.slice(index, start); - index = end + 1; + // Walk START-delimited segments exactly like the streaming filter below: a START whose + // own segment (up to the next START) contains an END within the span bound is a span and + // is removed; a START that is superseded by another START before any END, or whose span + // exceeds MAX_CITATION_SPAN_LENGTH, is malformed text and stays verbatim. Pairing an + // earlier malformed START with a later span's END would delete real answer text and, + // worse, disagree with what the streaming deltas already emitted (#3843). The bound is + // shared with the streaming filter for the same reason: a span it has already released + // as over-bound must not be swallowed here when the END finally arrives. + let start = text.indexOf(CITATION_MARKER_START); + let out = text.slice(0, start); + while (start !== -1) { + const nextStart = text.indexOf(CITATION_MARKER_START, start + 1); + const segment = text.slice(start, nextStart === -1 ? text.length : nextStart); + const end = segment.indexOf(CITATION_MARKER_END, 1); + out += end === -1 || end + 1 > MAX_CITATION_SPAN_LENGTH ? segment : segment.slice(end + 1); + start = nextStart; } + return out; } export interface CitationMarkerFilter { @@ -69,13 +70,16 @@ export interface CitationMarkerFilter { } /** - * Upper bound on the text withheld for one unterminated START. + * Upper bound on the length of a citation span (START through END inclusive), and therefore + * on the text the streaming filter withholds for one unterminated START. * * A real span is `cite` plus a few turn-scoped ids, so it is far under this. Without a * bound, a backend that emits a START and never terminates it makes `held` grow for the - * whole response, and every later delta re-scans that accumulated prefix. + * whole response, and every later delta re-scans that accumulated prefix. The whole-string + * strip applies the same bound so both paths classify a span identically regardless of how + * the text was chunked. */ -const MAX_STREAMING_MARKER_SPAN_LENGTH = 4_096; +const MAX_CITATION_SPAN_LENGTH = 4_096; /** * Streaming filter. @@ -85,7 +89,7 @@ const MAX_STREAMING_MARKER_SPAN_LENGTH = 4_096; * This holds back the text from an unterminated START and releases it once the END arrives * (removed) or the stream ends (verbatim, so nothing the model actually said is lost). * - * A span that grows past `MAX_STREAMING_MARKER_SPAN_LENGTH` is malformed ordinary text, so + * A span that grows past `MAX_CITATION_SPAN_LENGTH` is malformed ordinary text, so * it is released verbatim instead of withheld; a later START can still open a valid span. */ export function createCitationMarkerFilter(): CitationMarkerFilter { @@ -104,15 +108,16 @@ export function createCitationMarkerFilter(): CitationMarkerFilter { const nextStart = combined.indexOf(CITATION_MARKER_START, start + 1); const segment = combined.slice(start, nextStart === -1 ? combined.length : nextStart); const end = segment.indexOf(CITATION_MARKER_END, 1); - if (end !== -1) { + if (end !== -1 && end + 1 <= MAX_CITATION_SPAN_LENGTH) { // A complete span: drop it, keep whatever trails it inside this segment. out += segment.slice(end + 1); - } else if (nextStart === -1 && segment.length <= MAX_STREAMING_MARKER_SPAN_LENGTH) { + } else if (end === -1 && nextStart === -1 && segment.length <= MAX_CITATION_SPAN_LENGTH) { // Only a bounded trailing span can still be completed by a later delta. held = segment; } else { - // Superseded by a later START, or over the bound: ordinary text, emitted verbatim - // so neither the retained text nor the per-delta rescan grows without limit. + // Superseded by a later START, or over the bound (with or without a late END): + // ordinary text, emitted verbatim so neither the retained text nor the per-delta + // rescan grows without limit. out += segment; } start = nextStart; diff --git a/tests/responses/citation-markers.test.ts b/tests/responses/citation-markers.test.ts index dcc7f9abc6..b0d92d0fad 100644 --- a/tests/responses/citation-markers.test.ts +++ b/tests/responses/citation-markers.test.ts @@ -52,6 +52,15 @@ describe("citation marker stripping (#3150)", () => { expect(stripCitationMarkers(`a${P}b`)).toBe(`a${P}b`); expect(stripCitationMarkers(`a${E}b`)).toBe(`a${E}b`); }); + + test("a malformed START before a later valid span is kept, not paired with that span's END", () => { + // Whole-string stripping must agree with the streaming filter: the malformed prefix + // survives and only the real span is removed (bridge re-strips the accumulated text + // for output_text.done, so any disagreement would make done != concatenated deltas). + const malformed = `${S}${"y".repeat(5_000)}`; + expect(stripCitationMarkers(`a${malformed}${S}cite${P}turn1view0${E} tail`)).toBe(`a${malformed} tail`); + expect(stripCitationMarkers(`a${S}cite${S}cite${P}turn1view0${E}b`)).toBe(`a${S}citeb`); + }); }); describe("streaming citation marker filter (#3150)", () => { @@ -117,4 +126,28 @@ describe("streaming citation marker filter (#3150)", () => { .toBe(`a${malformed} tail`); expect(filter.flush()).toBe(""); }); + + test("concatenated streaming output equals whole-string stripping for every chunking", () => { + // The bridge emits deltas through the filter and then re-strips the accumulated text for + // output_text.done / output_item.done, so the two contracts must produce identical text. + const malformed = `${S}${"y".repeat(5_000)}`; + const inputs = [ + `a${span}${malformed}${S}cite${P}turn1view0${E} tail`, + `kept ${S}cite${"x".repeat(5_000)}`, + `a${S}cite${S}cite${P}turn1view0${E}b`, + `a${span}b${S}cite${P}turn2view0${E}c`, + // An over-bound span that is eventually terminated: the streaming filter has already + // released it verbatim, so whole-string stripping must keep it too. + `late ${S}${"z".repeat(4_096)}${E} end`, + // Exactly at the bound (4096 chars START..END inclusive) is still a span. + `edge ${S}${"z".repeat(4_094)}${E} end`, + ]; + for (const input of inputs) { + for (const size of [1, 7, 4_097, input.length]) { + const chunks: string[] = []; + for (let i = 0; i < input.length; i += size) chunks.push(input.slice(i, i + size)); + expect(drain(chunks)).toBe(stripCitationMarkers(input)); + } + } + }); }); From 413600dc79817a34d141d5f8037fc1495b456aa1 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 20:04:47 +0900 Subject: [PATCH 106/412] docs(providers): describe OpenCode Go session affinity and the Pi compat flag [skip ci] Docs hunk from the #3858 carry (#3880) that lane A handed off because guides/providers.md is owned by the main lane in this train. Co-authored-by: makesomethingshit <246213378+makesomethingshit@users.noreply.github.com> --- docs-site/src/content/docs/guides/providers.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs-site/src/content/docs/guides/providers.md b/docs-site/src/content/docs/guides/providers.md index 8a9477a759..7ac2e4502b 100644 --- a/docs-site/src/content/docs/guides/providers.md +++ b/docs-site/src/content/docs/guides/providers.md @@ -379,6 +379,22 @@ free-experimentation model. | Cloudflare AI Gateway | `https://gateway.ai.cloudflare.com/v1/{account-id}/{gateway}/anthropic` | | …and more | opencode zen, Vercel AI Gateway, Venice, NanoGPT, Synthetic, Qianfan, Alibaba, Parallel, ZenMux, LiteLLM | +**OpenCode Go** requires a stable session identifier for routing. OpenCodex derives +its Go session header from Codex thread/session headers, or from a client's +`x-opencode-session` header when Codex headers are absent. This applies to direct +Chat Completions requests and requests bridged to Responses. Even an `ocx_`-prefixed +inbound value is treated as client input and +hashed into Go affinity; the internal bridge carries the original value, so native +Chat, bridged Chat, and Responses derive the same result. Explicit provider-config +session headers are operator overrides and are sent unchanged. Clients must keep the +identifier stable within a conversation and distinct across conversations; requests +without a session identifier cannot receive automatic session affinity. +Generated Pi provider configurations enable `compat.sendSessionAffinityHeaders` +so Pi sends its per-session identity to the proxy. Existing manually managed Pi +configurations can set this option on their `opencodex` provider as well. +Pi can omit session affinity when `cacheRetention` is `none`; enable cache retention +when a stable upstream session is required. + **OpenCode Zen** (`opencode-zen`) and the keyless **OpenCode Free** preset share `https://opencode.ai/zen/v1`. Free models on that gateway often hit a short-window burst limit around 15–20 requests/minute (community-measured; OpenCode does not publish RPM). From 451fbffb02407cd73e9cf62bff6c40ad09ba3e12 Mon Sep 17 00:00:00 2001 From: x3M3x Date: Wed, 2 Sep 2026 03:42:09 +0400 Subject: [PATCH 107/412] feat gui: expose subagent fallback settings [skip ci] (cherry picked from commit b0d86fa3be8aec324974dc4471d5a98b35102459) Co-authored-by: x3M3x <98298256+x3M3x@users.noreply.github.com> --- .../SubagentDelegationSection.tsx | 33 ++++++++++++ .../SubagentsWorkspace.tsx | 14 +++++ gui/src/i18n/de.ts | 6 +++ gui/src/i18n/en.ts | 6 +++ gui/src/i18n/fr.ts | 6 +++ gui/src/i18n/ja.ts | 6 +++ gui/src/i18n/ko.ts | 6 +++ gui/src/i18n/ru.ts | 6 +++ gui/src/i18n/tr.ts | 6 +++ gui/src/i18n/zh-TW.ts | 6 +++ gui/src/i18n/zh.ts | 6 +++ gui/src/pages/Subagents.tsx | 53 ++++++++++++++++--- 12 files changed, 147 insertions(+), 7 deletions(-) diff --git a/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx b/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx index 46c0447a7c..7c3b0e9425 100644 --- a/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx +++ b/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx @@ -28,6 +28,13 @@ export interface SubagentDelegationSectionProps { onUltraModeSave: (patch: UltraModePatch) => void; ultraLoadFailed: boolean; onUltraModeRetry: () => void; + fallback: string[]; + fallbackPollMs: number; + fallbackBusy: boolean; + availableModels: string[]; + onFallbackChange: (models: string[]) => void; + onFallbackPollMsChange: (pollMs: number) => void; + onFallbackSave: () => void; } export default function SubagentDelegationSection({ @@ -44,6 +51,7 @@ export default function SubagentDelegationSection({ onUltraModeSave, ultraLoadFailed, onUltraModeRetry, + fallback, fallbackPollMs, fallbackBusy, availableModels, onFallbackChange, onFallbackPollMsChange, onFallbackSave, }: SubagentDelegationSectionProps) { const t = useT(); // A present empty/whitespace hint is an upstream override that suppresses the @@ -97,6 +105,31 @@ export default function SubagentDelegationSection({ +
+
+
{t("sub.fallbackLabel")}
+
{t("sub.fallbackHint")}
+
+
+ {fallback.map((modelName, index) => ( +
+ {index + 1}. {modelName} + + + +
+ ))} + + + +
+
+
{t("dash.syncCodexSubagentDefaults")}
diff --git a/gui/src/components/subagents-workspace/SubagentsWorkspace.tsx b/gui/src/components/subagents-workspace/SubagentsWorkspace.tsx index a22bd2a305..30b722b2bf 100644 --- a/gui/src/components/subagents-workspace/SubagentsWorkspace.tsx +++ b/gui/src/components/subagents-workspace/SubagentsWorkspace.tsx @@ -37,6 +37,12 @@ export interface SubagentsWorkspaceProps { onToggle: (m: string) => void; onMove: (i: number, dir: -1 | 1) => void; onSave: () => void; + fallback: string[]; + fallbackPollMs: number; + fallbackBusy: boolean; + onFallbackChange: (models: string[]) => void; + onFallbackPollMsChange: (pollMs: number) => void; + onFallbackSave: () => void; delegation: { model: string; effort: string; @@ -63,6 +69,7 @@ export default function SubagentsWorkspace({ onToggle, onMove, onSave, + fallback, fallbackPollMs, fallbackBusy, onFallbackChange, onFallbackPollMsChange, onFallbackSave, delegation, }: SubagentsWorkspaceProps) { const t = useT(); @@ -237,6 +244,13 @@ export default function SubagentsWorkspace({ onUltraModeSave={delegation.onUltraModeSave} ultraLoadFailed={delegation.ultraLoadFailed} onUltraModeRetry={delegation.onUltraModeRetry} + fallback={fallback} + fallbackPollMs={fallbackPollMs} + fallbackBusy={fallbackBusy} + availableModels={available} + onFallbackChange={onFallbackChange} + onFallbackPollMsChange={onFallbackPollMsChange} + onFallbackSave={onFallbackSave} />
diff --git a/gui/src/i18n/de.ts b/gui/src/i18n/de.ts index 74533a04d3..8985d342a0 100644 --- a/gui/src/i18n/de.ts +++ b/gui/src/i18n/de.ts @@ -686,6 +686,12 @@ export const de: Record = { "sub.ultraModeLoadFail": "Ultra-Modus-Einstellungen konnten nicht geladen werden — läuft der Proxy?", "sub.ultraModeSaveFail": "Ultra-Modus-Einstellungen konnten nicht gespeichert werden", "sub.ultraModeSaved": "Ultra-Modus gespeichert. Gilt für neue Codex-Sitzungen.", + "sub.fallbackLabel": "Fallback-Kette für Sub-Agenten", + "sub.fallbackHint": "Geordnete Modelle, die versucht werden, wenn ein Sub-Agent-Modell nicht verfügbar ist oder fehlschlägt.", + "sub.fallbackAdd": "Fallback-Modell hinzufügen…", + "sub.fallbackPoll": "Intervall der Verfügbarkeitsprüfung", + "sub.fallbackSaved": "Fallback-Einstellungen für Sub-Agenten gespeichert.", + "sub.fallbackSaveFailed": "Fallback-Einstellungen konnten nicht gespeichert werden", "logs.title": "Anfrage-Protokolle", "logs.tabLogs": "Protokolle", "logs.tabDebug": "Diagnose", diff --git a/gui/src/i18n/en.ts b/gui/src/i18n/en.ts index 2197dcb735..a33c195e82 100644 --- a/gui/src/i18n/en.ts +++ b/gui/src/i18n/en.ts @@ -329,6 +329,12 @@ export const en = { "dash.visionTimeout": "Timeout", "dash.visionTimeoutInvalid": "Enter an integer from {min} to {max} milliseconds.", "dash.visionAdvancedPopover": "Advanced vision settings", + "sub.fallbackLabel": "Sub-agent fallback chain", + "sub.fallbackHint": "Ordered models tried when a sub-agent model is unavailable or fails.", + "sub.fallbackAdd": "Add fallback model…", + "sub.fallbackPoll": "Availability check interval", + "sub.fallbackSaved": "Sub-agent fallback settings saved.", + "sub.fallbackSaveFailed": "Failed to save fallback settings", "dash.shadowCallIntercept": "Shadow Call Intercept", "dash.shadowCallInterceptHint": "Intercepts Codex App's background helper calls ({models}) for title generation and commit messages and redirects them to your chosen model.", "dash.shadowCallWarning": "⚠ When enabled, ALL requests for {models} will be replaced with the selected model.", diff --git a/gui/src/i18n/fr.ts b/gui/src/i18n/fr.ts index cca4b70347..fa32925c02 100644 --- a/gui/src/i18n/fr.ts +++ b/gui/src/i18n/fr.ts @@ -319,6 +319,12 @@ export const fr: Record = { "dash.visionTimeout": "Délai d’expiration", "dash.visionTimeoutInvalid": "Saisissez un entier compris entre {min} et {max} millisecondes.", "dash.visionAdvancedPopover": "Paramètres de vision avancés", + "sub.fallbackLabel": "Chaîne de secours des sous-agents", + "sub.fallbackHint": "Modèles essayés dans l’ordre lorsqu’un modèle de sous-agent est indisponible ou échoue.", + "sub.fallbackAdd": "Ajouter un modèle de secours…", + "sub.fallbackPoll": "Intervalle de vérification de disponibilité", + "sub.fallbackSaved": "Paramètres de secours des sous-agents enregistrés.", + "sub.fallbackSaveFailed": "Échec de l’enregistrement des paramètres de secours", "dash.shadowCallIntercept": "Interception des appels fantômes", "dash.shadowCallInterceptHint": "Intercepte les appels auxiliaires en arrière-plan de l’application Codex ({models}) pour générer les titres et les messages de commit, puis les redirige vers le modèle choisi.", "dash.shadowCallWarning": "⚠ Lorsque cette option est activée, TOUTES les requêtes destinées à {models} sont remplacées par le modèle sélectionné.", diff --git a/gui/src/i18n/ja.ts b/gui/src/i18n/ja.ts index 97aa85a6fb..81cd40bca9 100644 --- a/gui/src/i18n/ja.ts +++ b/gui/src/i18n/ja.ts @@ -646,6 +646,12 @@ export const ja: Record = { "sub.ultraModeLoadFail": "ウルトラモード設定を読み込めませんでした — プロキシは実行中ですか?", "sub.ultraModeSaveFail": "ウルトラモード設定の保存に失敗しました", "sub.ultraModeSaved": "ウルトラモードを保存しました。新しい Codex セッションから適用されます。", + "sub.fallbackLabel": "サブエージェントのフォールバックチェーン", + "sub.fallbackHint": "サブエージェントモデルが利用できないか失敗した場合に順番に試すモデルです。", + "sub.fallbackAdd": "フォールバックモデルを追加…", + "sub.fallbackPoll": "利用可能性チェック間隔", + "sub.fallbackSaved": "サブエージェントのフォールバック設定を保存しました。", + "sub.fallbackSaveFailed": "フォールバック設定の保存に失敗しました", // logs "logs.title": "リクエストログ", diff --git a/gui/src/i18n/ko.ts b/gui/src/i18n/ko.ts index 4e66544528..35a726e6ba 100644 --- a/gui/src/i18n/ko.ts +++ b/gui/src/i18n/ko.ts @@ -703,6 +703,12 @@ export const ko: Record = { "sub.ultraModeLoadFail": "울트라 모드 설정을 불러오지 못했습니다 — 프록시가 실행 중인가요?", "sub.ultraModeSaveFail": "울트라 모드 설정 저장에 실패했습니다", "sub.ultraModeSaved": "울트라 모드가 저장되었습니다. 새 Codex 세션부터 적용됩니다.", + "sub.fallbackLabel": "서브에이전트 폴백 체인", + "sub.fallbackHint": "서브에이전트 모델을 사용할 수 없거나 실패할 때 순서대로 시도할 모델입니다.", + "sub.fallbackAdd": "폴백 모델 추가…", + "sub.fallbackPoll": "가용성 확인 간격", + "sub.fallbackSaved": "서브에이전트 폴백 설정을 저장했습니다.", + "sub.fallbackSaveFailed": "폴백 설정을 저장하지 못했습니다", // logs "logs.title": "요청 로그", diff --git a/gui/src/i18n/ru.ts b/gui/src/i18n/ru.ts index e7f199a06a..a7cc5f72e8 100644 --- a/gui/src/i18n/ru.ts +++ b/gui/src/i18n/ru.ts @@ -701,6 +701,12 @@ export const ru: Record = { "sub.ultraModeLoadFail": "Не удалось загрузить настройки ультра-режима — работает ли прокси?", "sub.ultraModeSaveFail": "Не удалось сохранить настройки ультра-режима", "sub.ultraModeSaved": "Ультра-режим сохранён. Применяется к новым сеансам Codex.", + "sub.fallbackLabel": "Цепочка резервных моделей субагента", + "sub.fallbackHint": "Модели, которые последовательно пробуются, если модель субагента недоступна или завершается ошибкой.", + "sub.fallbackAdd": "Добавить резервную модель…", + "sub.fallbackPoll": "Интервал проверки доступности", + "sub.fallbackSaved": "Настройки резервных моделей субагента сохранены.", + "sub.fallbackSaveFailed": "Не удалось сохранить настройки резервных моделей", // logs "logs.title": "Журнал запросов", diff --git a/gui/src/i18n/tr.ts b/gui/src/i18n/tr.ts index 8c8f9ff802..5c0ade9077 100644 --- a/gui/src/i18n/tr.ts +++ b/gui/src/i18n/tr.ts @@ -708,6 +708,12 @@ export const tr: Record = { "sub.ultraModeLoadFail": "Ultra modu ayarları yüklenemedi — proxy çalışıyor mu?", "sub.ultraModeSaveFail": "Ultra modu ayarları kaydedilemedi", "sub.ultraModeSaved": "Ultra modu kaydedildi. Yeni Codex oturumlarına uygulanır.", + "sub.fallbackLabel": "Alt ajan yedek zinciri", + "sub.fallbackHint": "Alt ajan modeli kullanılamadığında veya başarısız olduğunda sırayla denenecek modeller.", + "sub.fallbackAdd": "Yedek model ekle…", + "sub.fallbackPoll": "Kullanılabilirlik kontrol aralığı", + "sub.fallbackSaved": "Alt ajan yedek ayarları kaydedildi.", + "sub.fallbackSaveFailed": "Yedek ayarlar kaydedilemedi", // logs "logs.title": "İstek Günlükleri", diff --git a/gui/src/i18n/zh-TW.ts b/gui/src/i18n/zh-TW.ts index eeec289911..cae0175057 100644 --- a/gui/src/i18n/zh-TW.ts +++ b/gui/src/i18n/zh-TW.ts @@ -555,6 +555,12 @@ export const zhTW: Record = { "sub.ultraModeLoadFail": "無法載入超級模式設定 — 代理是否在執行?", "sub.ultraModeSaveFail": "儲存超級模式設定失敗", "sub.ultraModeSaved": "超級模式已儲存。適用於新的 Codex 會話。", + "sub.fallbackLabel": "子代理備援鏈", + "sub.fallbackHint": "子代理模型無法使用或失敗時,依序嘗試的模型。", + "sub.fallbackAdd": "新增備援模型…", + "sub.fallbackPoll": "可用性檢查間隔", + "sub.fallbackSaved": "子代理備援設定已儲存。", + "sub.fallbackSaveFailed": "備援設定儲存失敗", "logs.title": "請求日誌", "logs.tabLogs": "日誌", "logs.tabDebug": "除錯", diff --git a/gui/src/i18n/zh.ts b/gui/src/i18n/zh.ts index a62e9b2d6b..ce44edc693 100644 --- a/gui/src/i18n/zh.ts +++ b/gui/src/i18n/zh.ts @@ -696,6 +696,12 @@ export const zh: Record = { "sub.ultraModeLoadFail": "无法加载超级模式设置 — 代理是否在运行?", "sub.ultraModeSaveFail": "保存超级模式设置失败", "sub.ultraModeSaved": "超级模式已保存。适用于新的 Codex 会话。", + "sub.fallbackLabel": "子代理回退链", + "sub.fallbackHint": "子代理模型不可用或失败时按顺序尝试的模型。", + "sub.fallbackAdd": "添加回退模型…", + "sub.fallbackPoll": "可用性检查间隔", + "sub.fallbackSaved": "子代理回退设置已保存。", + "sub.fallbackSaveFailed": "保存回退设置失败", // logs "logs.title": "请求日志", diff --git a/gui/src/pages/Subagents.tsx b/gui/src/pages/Subagents.tsx index 6b54d39ffd..299c9306fe 100644 --- a/gui/src/pages/Subagents.tsx +++ b/gui/src/pages/Subagents.tsx @@ -8,7 +8,7 @@ import { useDataSurface } from "../data-surface"; import { DataSurfaceSkeleton } from "../components/data-surface"; import { useSubagentDelegation, type UltraModePatch, type UltraModeState } from "./use-subagent-delegation"; -type CachedSubagents = { available: string[]; chosen: string[] }; +type CachedSubagents = { available: string[]; chosen: string[]; fallback: string[]; pollMs: number }; function seedSubagents(cacheKey: string): CachedSubagents | null { return readSessionListCache(cacheKey); @@ -19,6 +19,9 @@ export default function Subagents({ apiBase }: { apiBase: string }) { const cacheKey = `ocx.subagents.v1:${apiBase}`; const cached = seedSubagents(cacheKey); const [chosen, setChosen] = useState(() => cached?.chosen ?? []); + const [fallback, setFallback] = useState(() => cached?.fallback ?? []); + const [fallbackPollMs, setFallbackPollMs] = useState(() => cached?.pollMs ?? 60000); + const [fallbackBusy, setFallbackBusy] = useState(false); const [status, setStatus] = useState(""); const [ok, setOk] = useState(false); const [busy, setBusy] = useState(false); @@ -117,16 +120,24 @@ export default function Subagents({ apiBase }: { apiBase: string }) { const loadSubagents = useCallback(async (signal?: AbortSignal): Promise => { // The resource layer's deadline abort must reach the wire — a signal dropped // here is a store that can only settle by race timeout. - const res = await fetch(`${apiBase}/api/subagent-models`, { signal }); - const response = await readJsonOrThrow<{ available?: string[]; chosen?: string[] }>(res, t("sub.loadFail")); - if (!response) throw new Error(t("sub.loadFail")); - const available = response.available ?? []; + const [rosterRes, fallbackRes] = await Promise.all([ + fetch(`${apiBase}/api/subagent-models`, { signal }), + fetch(`${apiBase}/api/subagent-model-fallback`, { signal }), + ]); + const response = await readJsonOrThrow<{ available?: string[]; chosen?: string[] }>(rosterRes, t("sub.loadFail")); + const fallbackResponse = await readJsonOrThrow<{ available?: string[]; models?: string[]; pollMs?: number }>(fallbackRes, t("sub.loadFail")); + if (!response || !fallbackResponse) throw new Error(t("sub.loadFail")); + const available = response.available ?? fallbackResponse.available ?? []; const availableSet = new Set(available); const next = { available, chosen: (response.chosen ?? []).filter(model => availableSet.has(model)), + fallback: (fallbackResponse.models ?? []).filter(model => availableSet.has(model)), + pollMs: fallbackResponse.pollMs ?? 60000, }; setChosen(next.chosen); + setFallback(next.fallback); + setFallbackPollMs(next.pollMs); writeSessionListCache(cacheKey, next); return next; }, [apiBase, cacheKey, t]); @@ -174,7 +185,7 @@ export default function Subagents({ apiBase }: { apiBase: string }) { const d = await readJsonOrThrow<{ applied?: string[] }>(r, t("sub.saveFailed")); const applied = d?.applied ?? chosen; if (d?.applied) setChosen(d.applied); - writeSessionListCache(cacheKey, { available, chosen: applied }); + writeSessionListCache(cacheKey, { available, chosen: applied, fallback, pollMs: fallbackPollMs }); setOk(true); setStatus(t("sub.saved", { n: applied.length, cmd: "ocx sync" })); } catch (error) { @@ -186,6 +197,28 @@ export default function Subagents({ apiBase }: { apiBase: string }) { } }; + const saveFallback = async () => { + if (fallbackBusy) return; + setFallbackBusy(true); + try { + const r = await fetch(`${apiBase}/api/subagent-model-fallback`, { + method: "PUT", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ models: fallback, pollMs: fallbackPollMs }), + }); + const d = await readJsonOrThrow<{ models?: string[]; pollMs?: number }>(r, t("sub.fallbackSaveFailed")); + if (d?.models) setFallback(d.models); + if (d?.pollMs) setFallbackPollMs(d.pollMs); + setOk(true); + setStatus(t("sub.fallbackSaved")); + } catch (error) { + setOk(false); + setStatus(error instanceof Error && error.message ? error.message : t("sub.networkError")); + } finally { + setFallbackBusy(false); + } + }; + // The skeleton owns the live region while this resource has no content yet. if (state.showSkeleton && !snapshot) { return ; @@ -214,7 +247,13 @@ export default function Subagents({ apiBase }: { apiBase: string }) { busy={busy} onToggle={toggle} onMove={move} - onSave={() => { void save(); }} + onSave={() => { void save(); }} + fallback={fallback} + fallbackPollMs={fallbackPollMs} + fallbackBusy={fallbackBusy} + onFallbackChange={setFallback} + onFallbackPollMsChange={setFallbackPollMs} + onFallbackSave={() => { void saveFallback(); }} delegation={{ model: delegation.model, effort: delegation.effort, From 2e6ef45530353cdf78d08b39cc3d914ea0139ed9 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 18:22:48 +0900 Subject: [PATCH 108/412] docs: record lane C manual-chain roadmap [skip ci] --- devlog/_plan/260907_lane_c/000_plan.md | 7 + devlog/_plan/260907_lane_c/010_web_search.md | 155 +++++++ devlog/_plan/260907_lane_c/020_vision.md | 135 +++++++ devlog/_plan/260907_lane_c/030_health.md | 119 ++++++ devlog/_plan/260907_lane_c/040_desktop.md | 404 +++++++++++++++++++ devlog/_plan/260907_lane_c/050_fallback.md | 368 +++++++++++++++++ 6 files changed, 1188 insertions(+) create mode 100644 devlog/_plan/260907_lane_c/000_plan.md create mode 100644 devlog/_plan/260907_lane_c/010_web_search.md create mode 100644 devlog/_plan/260907_lane_c/020_vision.md create mode 100644 devlog/_plan/260907_lane_c/030_health.md create mode 100644 devlog/_plan/260907_lane_c/040_desktop.md create mode 100644 devlog/_plan/260907_lane_c/050_fallback.md diff --git a/devlog/_plan/260907_lane_c/000_plan.md b/devlog/_plan/260907_lane_c/000_plan.md new file mode 100644 index 0000000000..d26120ae29 --- /dev/null +++ b/devlog/_plan/260907_lane_c/000_plan.md @@ -0,0 +1,7 @@ +# Lane C release train roadmap + +Satisfy-spec HOTL, explicitly delegated by release-train main task. Goal: prepare five manual dependent PRs for main-session landing. No merge/release/publish/main/preview changes; no local tests, typecheck, build or install. All such checks NOT RUN. Remote Cross-platform CI dispatch lane=all at top head is the verifier. Stop after exact-head green CI, Astra review verdicts, screenshots, credit and SHA handoff; unresolved material blockers are reported with evidence. No user-specified token/cost/time bound. Tools: local scoped git/files, gh read/PR/push/CI, Astra explorer audits and browser inspection. New security findings stay in .tmp/lane-c. Main owns config-routes.ts; no edits there. Escalate cross-owner collisions; reclaim delegated slices after two distinct worker failures. + +Dependency order: roadmap → 3839 → 3841 → 3863 → 3860 → 3252/1533 → top CI and handoff. Lower-layer commit subjects include [skip ci]; stack:null. Every carry uses cherry-pick -x and source PR author Co-authored-by. Existing configuration field contracts are reused. Rollback is revert of a layer with descendant cascade, within main-authorized integration. Current source and read-only git/gh are evidence; no claimed local execution of product verifiers. Public original diffs are recorded in decade documents; private audit notes stay in scratch. + +Main steering: all gui/src/i18n/*.ts are append-only multiwriter; C adds namespaced keys at feature-section ends, never edits/deletes existing keys. Final cascade resolves append collisions. diff --git a/devlog/_plan/260907_lane_c/010_web_search.md b/devlog/_plan/260907_lane_c/010_web_search.md new file mode 100644 index 0000000000..ccb7217ea3 --- /dev/null +++ b/devlog/_plan/260907_lane_c/010_web_search.md @@ -0,0 +1,155 @@ +# 3839 implementation contract + +Carry public source patch with -x. Add deterministic 64KiB SSE and HTTP error-body regressions including cancel that never settles. Preserve complete prefix frames and discard incomplete tail. Tests use public run/parse APIs and controlled byte streams. + +Validation: local tests/typecheck/build/install NOT RUN by instruction. Read diff and source; top remote CI exercises changed test paths. Each conditional branch listed above is exercised by controlled fixtures; screenshot inspects GUI state. No new enforcement layer; existing API guards remain authoritative. + +## Public source diff (MODIFY/NEW paths) + +```diff +diff --git a/src/web-search/anthropic-executor.ts b/src/web-search/anthropic-executor.ts +index 1eb206afa..cd3893900 100644 +--- a/src/web-search/anthropic-executor.ts ++++ b/src/web-search/anthropic-executor.ts +@@ -5,7 +5,11 @@ import { CLAUDE_CODE_HEADERS, claudeCodeSessionId } from "../adapters/client-fin + import { signalWithTimeout, cancelBodyOnAbort } from "../lib/abort"; + import { sidecarEnter } from "../lib/sidecar-tracker"; + import { applyUpstreamRecoveryInit, fetchWithResetRetry } from "../lib/upstream-retry"; +-import type { WebSearchSource } from "./parse"; ++import { ++ MAX_SIDECAR_RESPONSE_BYTES, ++ cancelReaderWithoutWaiting, ++ type WebSearchSource, ++} from "./parse"; + import { BASE_INSTRUCTION, IMAGE_INSTRUCTION, type SidecarOutcome, type SidecarSettings } from "./executor"; + + /** Hardcoded per-turn search bound handed to the server tool (mirrors the loop's maxSearches intent). */ +@@ -17,6 +21,33 @@ function isRec(v: unknown): v is Record { + return !!v && typeof v === "object" && !Array.isArray(v); + } + ++/** Read at most `MAX_SIDECAR_RESPONSE_BYTES` of an untrusted upstream body, then stop reading. */ ++async function readBoundedText(res: Response): Promise { ++ if (!res.body) return ""; ++ const reader = res.body.getReader(); ++ const decoder = new TextDecoder(); ++ let out = ""; ++ let seen = 0; ++ try { ++ for (;;) { ++ const { done, value } = await reader.read(); ++ if (done) break; ++ const remaining = MAX_SIDECAR_RESPONSE_BYTES - seen; ++ const accepted = value.byteLength <= remaining ? value : value.subarray(0, remaining); ++ seen += accepted.byteLength; ++ out += decoder.decode(accepted, { stream: true }); ++ if (seen >= MAX_SIDECAR_RESPONSE_BYTES) { ++ cancelReaderWithoutWaiting(reader, "sidecar error body byte limit reached"); ++ break; ++ } ++ } ++ out += decoder.decode(); ++ } catch { ++ /* a failed error-body read must not mask the HTTP status we are about to report */ ++ } ++ return out; ++} ++ + /** + * Fold an Anthropic Messages SSE stream (a web_search_20250305 turn) into a WebSearchResult. + * +@@ -41,6 +72,7 @@ export async function parseAnthropicSidecarSSE(res: Response): Promise): void => { + const type = typeof data.type === "string" ? data.type : ""; +@@ -82,15 +114,27 @@ export async function parseAnthropicSidecarSSE(res: Response): Promise= MAX_SIDECAR_RESPONSE_BYTES) { ++ // Keep the frames already folded above, drop the unterminated tail, and do not wait on ++ // upstream teardown. ++ cancelReaderWithoutWaiting(reader, "sidecar response byte limit reached"); ++ buffer = ""; ++ break; ++ } + } + // Flush the decoder and process any final unterminated frame (a stream that ends without \n\n). + buffer = (buffer + decoder.decode()).replace(/\r\n/g, "\n"); +@@ -177,7 +221,9 @@ export async function runAnthropicWebSearch( + // (found investigating #1419). + const detachBodyGuard = cancelBodyOnAbort(res.body, linkedSignal.signal); + if (!res.ok) { +- const t = await res.text().catch(() => ""); ++ // Untrusted upstream error bodies are only used for an auth-failure message, so read a ++ // bounded prefix instead of buffering an arbitrarily large response. ++ const t = await readBoundedText(res); + detachBodyGuard(); + console.warn(`[web-search] anthropic sidecar HTTP ${res.status} for query "${query.slice(0, 80)}" (${Date.now() - t0}ms)`); + if (res.status === 401) { +diff --git a/src/web-search/parse.ts b/src/web-search/parse.ts +index 757c309f3..7ba5d2607 100644 +--- a/src/web-search/parse.ts ++++ b/src/web-search/parse.ts +@@ -193,7 +193,7 @@ function fromOutputArray(output: OutputItem[], seen: Set): WebSearchResu + return { text, sources }; + } + +-function cancelReaderWithoutWaiting( ++export function cancelReaderWithoutWaiting( + reader: ReadableStreamDefaultReader, + reason: string, + ): void { +diff --git a/tests/web-search/web-search-anthropic.test.ts b/tests/web-search/web-search-anthropic.test.ts +index f5b7f1df2..33f2616cc 100644 +--- a/tests/web-search/web-search-anthropic.test.ts ++++ b/tests/web-search/web-search-anthropic.test.ts +@@ -130,6 +130,27 @@ describe("parseAnthropicSidecarSSE", () => { + expect(out.error).toBeDefined(); + }); + ++ test("an unterminated frame cannot buffer the stream without bound", async () => { ++ // A sidecar that never emits a frame separator: without a cap the parser would accumulate ++ // the whole stream in memory before it could fold anything. ++ let produced = 0; ++ let cancelled = false; ++ const chunk = new TextEncoder().encode(`data: {"filler":"${"x".repeat(64 * 1024)}"}`); ++ const body = new ReadableStream({ ++ pull(c) { ++ if (produced > 8 * 1024 * 1024) { c.close(); return; } ++ produced += chunk.byteLength; ++ c.enqueue(chunk); ++ }, ++ cancel() { cancelled = true; }, ++ }); ++ const out = await parseAnthropicSidecarSSE(new Response(body, { status: 200 })); ++ expect(cancelled).toBe(true); ++ // The cap stops the read long before the producer would have finished on its own. ++ expect(produced).toBeLessThan(1024 * 1024); ++ expect(out.text).toBe(""); ++ }); ++ + test("empty results (content:[]) with answer text is a success, not an error", async () => { + const res = sseResponse([ + { type: "content_block_start", index: 0, content_block: { type: "web_search_tool_result", tool_use_id: "srvtoolu_3", content: [] } }, + +``` diff --git a/devlog/_plan/260907_lane_c/020_vision.md b/devlog/_plan/260907_lane_c/020_vision.md new file mode 100644 index 0000000000..9dab5d18e2 --- /dev/null +++ b/devlog/_plan/260907_lane_c/020_vision.md @@ -0,0 +1,135 @@ +# 3841 implementation contract + +Carry public source patch with -x. Add 64KiB HTTP error-body and non-settling cancel regressions. Preserve complete description frames before cap; discard unfinished frame even at exact cap; retain downstream clamp. No credential-policy changes. + +Validation: local tests/typecheck/build/install NOT RUN by instruction. Read diff and source; top remote CI exercises changed test paths. Each conditional branch listed above is exercised by controlled fixtures; screenshot inspects GUI state. No new enforcement layer; existing API guards remain authoritative. + +## Public source diff (MODIFY/NEW paths) + +```diff +diff --git a/src/vision/anthropic-describe.ts b/src/vision/anthropic-describe.ts +index 4f41017ef..280096f03 100644 +--- a/src/vision/anthropic-describe.ts ++++ b/src/vision/anthropic-describe.ts +@@ -10,6 +10,8 @@ import type { DescribeOutcome, VisionSettings } from "./describe"; + const ANTHROPIC_VISION_MAX_TOKENS = 1024; + const ALLOWED_IMAGE_MIME = new Set(["image/png", "image/jpeg", "image/jpg", "image/webp", "image/gif"]); + const MAX_IMAGE_BYTES = 20 * 1024 * 1024; ++/** Bound the sidecar SSE stream and its untrusted error body; the description is clamped downstream. */ ++const MAX_SIDECAR_RESPONSE_BYTES = 64 * 1024; + const DESCRIBE_INSTRUCTION = + "You are a vision describer for a text-only model that cannot see the image. Describe the image " + + "thoroughly and factually so that model can fully reason about it: transcribe any visible text " + +@@ -43,6 +45,34 @@ function buildImageBlock(imageUrl: string): { block?: AnthropicImageBlock; error + return { error: "unsupported image URL scheme (expected data: or https:)" }; + } + ++/** Read at most `MAX_SIDECAR_RESPONSE_BYTES` of an untrusted upstream body, then stop reading. */ ++async function readBoundedText(res: Response): Promise { ++ if (!res.body) return ""; ++ const reader = res.body.getReader(); ++ const decoder = new TextDecoder(); ++ let out = ""; ++ let seen = 0; ++ try { ++ for (;;) { ++ const { done, value } = await reader.read(); ++ if (done) break; ++ const remaining = MAX_SIDECAR_RESPONSE_BYTES - seen; ++ const accepted = value.byteLength <= remaining ? value : value.subarray(0, remaining); ++ seen += accepted.byteLength; ++ out += decoder.decode(accepted, { stream: true }); ++ if (seen >= MAX_SIDECAR_RESPONSE_BYTES) { ++ try { void reader.cancel("vision sidecar error body byte limit reached").catch(() => undefined); } ++ catch { /* best-effort body teardown */ } ++ break; ++ } ++ } ++ out += decoder.decode(); ++ } catch { ++ /* a failed error-body read must not mask the HTTP status we are about to report */ ++ } ++ return out; ++} ++ + /** Fold Anthropic Messages text deltas into one description. Malformed frames are ignored. */ + export async function parseAnthropicVisionSSE(res: Response): Promise { + if (!res.body) return { text: "", error: "anthropic vision sidecar returned no response body" }; +@@ -52,6 +82,7 @@ export async function parseAnthropicVisionSSE(res: Response): Promise { + let dataLine = ""; +@@ -76,12 +107,24 @@ export async function parseAnthropicVisionSSE(res: Response): Promise= MAX_SIDECAR_RESPONSE_BYTES) { ++ // Keep the frames folded above, drop the unterminated tail, and do not wait on teardown. ++ try { void reader.cancel("vision sidecar response byte limit reached").catch(() => undefined); } ++ catch { /* best-effort body teardown */ } ++ buffer = ""; ++ break; ++ } + } + buffer = (buffer + decoder.decode()).replace(/\r\n/g, "\n"); + if (buffer.trim()) processFrame(buffer); +@@ -164,7 +207,8 @@ export async function describeImageAnthropic( + { abortSignal: linkedSignal.signal, label: "vision-sidecar-anthropic" }, + ); + if (!res.ok) { +- const responseText = await res.text().catch(() => ""); ++ // The body is untrusted and only feeds one auth-failure message, so read a bounded prefix. ++ const responseText = await readBoundedText(res); + console.warn(`[vision] anthropic sidecar HTTP ${res.status} (${Date.now() - startedAt}ms)`); + if (res.status === 401) { + return { text: "", error: `anthropic vision sidecar auth failed: ${publicOAuthAuthenticationErrorMessage(new Error(responseText))}` }; +diff --git a/tests/vision/vision-anthropic.test.ts b/tests/vision/vision-anthropic.test.ts +index ee4b01b42..30ed17af9 100644 +--- a/tests/vision/vision-anthropic.test.ts ++++ b/tests/vision/vision-anthropic.test.ts +@@ -225,6 +225,27 @@ describe("Anthropic vision executor", () => { + expect(result).toEqual({ text: "first second" }); + }); + ++ test("an unterminated frame cannot buffer the stream without bound", async () => { ++ // A sidecar that never emits a frame separator: without a cap the parser accumulates the ++ // whole response in memory before it can fold anything. ++ let produced = 0; ++ let cancelled = false; ++ const chunk = new TextEncoder().encode(`data: {"filler":"${"x".repeat(64 * 1024)}"}`); ++ const body = new ReadableStream({ ++ pull(c) { ++ if (produced > 8 * 1024 * 1024) { c.close(); return; } ++ produced += chunk.byteLength; ++ c.enqueue(chunk); ++ }, ++ cancel() { cancelled = true; }, ++ }); ++ const out = await parseAnthropicVisionSSE(new Response(body, { status: 200 })); ++ expect(cancelled).toBe(true); ++ // The cap stops the read long before the producer would have finished on its own. ++ expect(produced).toBeLessThan(1024 * 1024); ++ expect(out.text).toBe(""); ++ }); ++ + test("malformed and terminal-error streams degrade to explicit errors", async () => { + const malformed = await parseAnthropicVisionSSE(sseResponse(["{not-json", { type: "message_stop" }])); + expect(malformed.text).toBe(""); + +``` diff --git a/devlog/_plan/260907_lane_c/030_health.md b/devlog/_plan/260907_lane_c/030_health.md new file mode 100644 index 0000000000..2e01551e34 --- /dev/null +++ b/devlog/_plan/260907_lane_c/030_health.md @@ -0,0 +1,119 @@ +# 3863 implementation contract + +Carry with -x excluding config-routes.ts. getStartupHealthSnapshot returns fresh cached value unchanged; stale/empty read schedules refresh and returns immediately. Catch rejected or synchronously thrown detached probe and retain stale conservative health; invalidation generation cannot overwrite newer reading. Replace 100ms production settings assertion with controlled probe fixtures. Exact route wiring remains main responsibility. + +Validation: local tests/typecheck/build/install NOT RUN by instruction. Read diff and source; top remote CI exercises changed test paths. Each conditional branch listed above is exercised by controlled fixtures; screenshot inspects GUI state. No new enforcement layer; existing API guards remain authoritative. + +## Public source diff (MODIFY/NEW paths) + +```diff +diff --git a/src/server/management/config-routes.ts b/src/server/management/config-routes.ts +index 4d551a886..9ddd02300 100644 +--- a/src/server/management/config-routes.ts ++++ b/src/server/management/config-routes.ts +@@ -107,7 +107,7 @@ import type { PersistedUsageAttempt } from "../../usage/log"; + import { isAllowedRequestOrigin, jsonResponse, providerManagementConfigError, publicProviderBaseUrl, safeConfigDTO } from "../auth-cors"; + import { withProviderServiceTierDTO } from "./provider-capability-config"; + import { applySystemEnvToggle } from "../system-env"; +-import { getCachedStartupHealth, invalidateStartupHealthCache } from "../startup-health-cache"; ++import { getCachedStartupHealth, getStartupHealthSnapshot, invalidateStartupHealthCache } from "../startup-health-cache"; + import { runWindowsTrayAction } from "../windows-tray-control"; + import { runStartupInstallAction, type StartupInstallAction } from "../startup-action-control"; + import { displayCodexRuntimePath, effortClampAppliesToRuntime, loadLastEffortClamp, resolveCodexRuntime } from "../../codex/runtime"; +@@ -329,7 +329,9 @@ export async function handleConfigRoutes(ctx: ManagementContext): Promise Promise; + } + ++/** ++ * Return the last completed probe immediately and refresh it in the background. ++ * ++ * Settings are consumed by several dashboard controls. They must not block on a ++ * Windows service-manager probe; the dedicated /api/startup-health route owns ++ * the fresh, bounded diagnostic read. ++ */ ++export function getStartupHealthSnapshot( ++ config: Pick, ++ deps: StartupHealthCacheDeps = {}, ++): StartupHealth { ++ const now = deps.now ?? Date.now; ++ if (!cached || now() - cached.timestamp >= CACHE_TTL_MS) refreshInBackground(config, deps); ++ return cached ? markStartupHealthDiagnosticStale(cached.value) : conservativeFallback(config); ++} ++ + export function markStartupHealthDiagnosticStale(value: StartupHealth): StartupHealth { + if (!value.localRoutingDependency) return { ...value, diagnosticStale: true }; + return { +diff --git a/tests/service/autostart-health.test.ts b/tests/service/autostart-health.test.ts +index 639f1b34c..48bb7b539 100644 +--- a/tests/service/autostart-health.test.ts ++++ b/tests/service/autostart-health.test.ts +@@ -3,7 +3,7 @@ import { deriveStartupHealth, formatStartupRoutingDetail, startupHealthSummary } + import { unusedProxyWarningLines } from "../../src/cli/status"; + import { classifyCodexRouting, hasInjectedCodexRouting } from "../../src/codex/inject"; + import { handleManagementAPI } from "../../src/server/management-api"; +-import { getCachedStartupHealth, invalidateStartupHealthCache, markStartupHealthDiagnosticStale } from "../../src/server/startup-health-cache"; ++import { getCachedStartupHealth, getStartupHealthSnapshot, invalidateStartupHealthCache, markStartupHealthDiagnosticStale } from "../../src/server/startup-health-cache"; + import type { OcxConfig } from "../../src/types"; + + const base = { +@@ -277,6 +277,43 @@ describe("Codex startup health", () => { + await pendingProbe; + invalidateStartupHealthCache(); + }); ++ ++ test("settings snapshot starts a probe without waiting for it", async () => { ++ invalidateStartupHealthCache(); ++ let releaseProbe!: (value: ReturnType) => void; ++ const pendingProbe = new Promise>(resolve => { ++ releaseProbe = resolve; ++ }); ++ ++ const health = getStartupHealthSnapshot( ++ { codexAutoStart: true }, ++ { probe: async () => pendingProbe }, ++ ); ++ ++ expect(health.diagnosticStale).toBe(true); ++ releaseProbe(deriveStartupHealth({ ...base, routingKind: "native" })); ++ await pendingProbe; ++ invalidateStartupHealthCache(); ++ }); ++ ++ test("settings GET uses the non-blocking startup-health snapshot in production", async () => { ++ invalidateStartupHealthCache(); ++ const url = new URL("http://localhost/api/settings"); ++ ++ const response = await Promise.race([ ++ handleManagementAPI( ++ new Request(url), ++ url, ++ { port: 10100, providers: {}, defaultProvider: "openai", codexAutoStart: true } as OcxConfig, ++ ), ++ new Promise(resolve => setTimeout(() => resolve(null), 100)), ++ ]); ++ ++ expect(response?.status).toBe(200); ++ const body = await response!.json() as { startupHealth?: { diagnosticStale?: boolean } }; ++ expect(body.startupHealth?.diagnosticStale).toBe(true); ++ invalidateStartupHealthCache(); ++ }); + }); + import { ManagementRequest as Request } from "../helpers/management-auth"; + + +``` diff --git a/devlog/_plan/260907_lane_c/040_desktop.md b/devlog/_plan/260907_lane_c/040_desktop.md new file mode 100644 index 0000000000..ad7fb60177 --- /dev/null +++ b/devlog/_plan/260907_lane_c/040_desktop.md @@ -0,0 +1,404 @@ +# 3860 implementation contract + +Carry source patch plus skipped-sync correction with -x. Default false/absent OFF, true remains true; persist preference before sync and surface sync failures. All nine locales and existing screenshot. Independent auth boundary review confirms remote admission/upstream credentials unchanged. + +Validation: local tests/typecheck/build/install NOT RUN by instruction. Read diff and source; top remote CI exercises changed test paths. Each conditional branch listed above is exercised by controlled fixtures; screenshot inspects GUI state. No new enforcement layer; existing API guards remain authoritative. + +## Public source diff (MODIFY/NEW paths) + +```diff +diff --git a/docs-site/src/content/docs/guides/codex-integration.md b/docs-site/src/content/docs/guides/codex-integration.md +index 7d66e72c3..ff2df04fd 100644 +--- a/docs-site/src/content/docs/guides/codex-integration.md ++++ b/docs-site/src/content/docs/guides/codex-integration.md +@@ -215,6 +215,15 @@ HTTP/SSE. + + ### Authless Codex Desktop (opt-in) + ++In **Dashboard → Overview**, **Open Codex without signing in** controls this existing ++opt-in preference. The switch defaults to **off** when the setting is absent or false; ++an existing explicit `codexDesktopAuthless: true` stays enabled. The dashboard saves ++the preference and runs a full sync. Restart Codex Desktop after changing it. ++If synchronization fails, the saved preference remains and the dashboard shows the error; ++retry **Sync** before restarting. Account-gated Desktop features may be unavailable ++when enabled. Upstream credentials, local eligibility, remote admission authentication ++and user-owned gateway settings retain their existing requirements. ++ + Codex Desktop shows its ChatGPT login screen whenever the active provider requires OpenAI auth. If + your OpenCodex setup never uses ChatGPT credentials (routed providers only, or a blocked + `chatgpt.com`), you can opt out of that gate: +diff --git a/gui/src/i18n/de.ts b/gui/src/i18n/de.ts +index 5faab4b35..495104bd4 100644 +--- a/gui/src/i18n/de.ts ++++ b/gui/src/i18n/de.ts +@@ -299,6 +299,8 @@ export const de: Record = { + "models.staleBanner": "Codex zeigt eine ältere Modellliste als dieser Katalog. Starte Codex neu, um sie neu zu laden.", + "dash.codexAutoStart": "opencodex mit Codex starten", + "dash.codexAutoStartHint": "Erlaubt einem installierten Launcher-Shim, ocx ensure auszuführen. Diese Einstellung installiert keinen Neustartschutz; prüfe den effektiven Zustand unter Startsicherheit.", ++ "dash.codexDesktopAuthless": "Codex ohne Anmeldung öffnen", ++ "dash.codexDesktopAuthlessHint": "Standardmäßig aus. Überspringt die separate Desktop-Anmeldung bei geeigneten lokalen Verbindungen. Zugangsdaten für den Anbieter bleiben erforderlich. Codex nach einer Änderung neu starten. Kontogebundene Desktop-Funktionen können fehlen.", + "dash.searchModel": "Such-Sidecar-Modell", + "dash.searchModelHint": "Modell für web_search bei nicht über OpenAI gerouteten Modellen. Erfordert ChatGPT-Login.", + "dash.searchReasoning": "Such-Reasoning-Aufwand", +diff --git a/gui/src/i18n/en.ts b/gui/src/i18n/en.ts +index c71208942..22a380785 100644 +--- a/gui/src/i18n/en.ts ++++ b/gui/src/i18n/en.ts +@@ -311,6 +311,8 @@ export const en = { + "models.staleBanner": "Codex is showing an older model list than this catalog. Restart Codex to reload it.", + "dash.codexAutoStart": "Start opencodex with Codex", + "dash.codexAutoStartHint": "Allows an installed launcher shim to run ocx ensure. This setting does not install restart protection; check Startup safety for the effective state.", ++ "dash.codexDesktopAuthless": "Open Codex without signing in", ++ "dash.codexDesktopAuthlessHint": "Off by default. Skip the separate Desktop sign-in for eligible local connections. Upstream credentials are still required. Restart Codex after changing this setting. Account-gated Desktop features may be unavailable.", + "dash.searchModel": "Search sidecar model", + "dash.searchModelHint": "Model used for web_search on non-OpenAI routed models. Requires ChatGPT login.", + "dash.searchReasoning": "Search reasoning effort", +diff --git a/gui/src/i18n/fr.ts b/gui/src/i18n/fr.ts +index e1b3519ef..9f0f26517 100644 +--- a/gui/src/i18n/fr.ts ++++ b/gui/src/i18n/fr.ts +@@ -301,6 +301,8 @@ export const fr: Record = { + "models.staleBanner": "Codex affiche une liste de modèles plus ancienne que ce catalogue. Redémarrez Codex pour la recharger.", + "dash.codexAutoStart": "Démarrer opencodex avec Codex", + "dash.codexAutoStartHint": "Permet à un mécanisme de lancement installé d’exécuter ocx ensure. Ce réglage n’installe pas de protection au redémarrage ; consultez Sécurité du démarrage pour connaître l’état effectif.", ++ "dash.codexDesktopAuthless": "Ouvrir Codex sans se connecter", ++ "dash.codexDesktopAuthlessHint": "Désactivé par défaut. Ignore la connexion Desktop séparée pour les connexions locales admissibles. Les identifiants du fournisseur restent nécessaires. Redémarrez Codex après toute modification. Certaines fonctions Desktop liées au compte peuvent être indisponibles.", + "dash.searchModel": "Modèle auxiliaire de recherche", + "dash.searchModelHint": "Modèle utilisé pour web_search sur les modèles routés autres qu’OpenAI. Nécessite une connexion à ChatGPT.", + "dash.searchReasoning": "Effort de raisonnement pour la recherche", +diff --git a/gui/src/i18n/ja.ts b/gui/src/i18n/ja.ts +index cf9483158..55a6fe249 100644 +--- a/gui/src/i18n/ja.ts ++++ b/gui/src/i18n/ja.ts +@@ -308,6 +308,8 @@ export const ja: Record = { + "models.staleBanner": "Codex はこのカタログより古いモデル一覧を表示しています。Codex を再起動すると読み直されます。", + "dash.codexAutoStart": "Codex と一緒に opencodex を起動", + "dash.codexAutoStartHint": "インストール済み launcher shim に ocx ensure の実行を許可します。この設定だけでは再起動保護はインストールされません。起動安全性で実際の状態を確認してください。", ++ "dash.codexDesktopAuthless": "ログインせずに Codex を開く", ++ "dash.codexDesktopAuthlessHint": "既定ではオフです。対象のローカル接続で Desktop の個別ログインを省略します。上流プロバイダーの認証情報は引き続き必要です。変更後は Codex を再起動してください。アカウントに依存する Desktop 機能が利用できない場合があります。", + "dash.searchModel": "検索サイドカーモデル", + "dash.searchModelHint": "非 OpenAI ルーティングモデルで web_search に使うモデル。ChatGPT ログインが必要です。", + "dash.searchReasoning": "検索の推論負荷", +diff --git a/gui/src/i18n/ko.ts b/gui/src/i18n/ko.ts +index c1959482b..19285b150 100644 +--- a/gui/src/i18n/ko.ts ++++ b/gui/src/i18n/ko.ts +@@ -303,6 +303,8 @@ export const ko: Record = { + "models.staleBanner": "Codex가 이 카탈로그보다 오래된 모델 목록을 보여주고 있습니다. Codex를 재시작하면 새로 읽습니다.", + "dash.codexAutoStart": "Codex 실행 시 opencodex 시작", + "dash.codexAutoStartHint": "설치된 launcher shim이 ocx ensure를 실행하도록 허용합니다. 이 설정은 재부팅 보호를 설치하지 않으므로 시작 안전성에서 실제 상태를 확인하세요.", ++ "dash.codexDesktopAuthless": "로그인 없이 Codex 열기", ++ "dash.codexDesktopAuthlessHint": "기본값은 꺼짐입니다. 지원되는 로컬 연결에서 별도의 Desktop 로그인을 건너뜁니다. 업스트림 인증 정보는 여전히 필요합니다. 변경 후 Codex를 다시 시작하세요. 계정에 연결된 Desktop 기능을 사용하지 못할 수 있습니다.", + "dash.searchModel": "서치 사이드카 모델", + "dash.searchModelHint": "비-OpenAI 라우팅 모델의 web_search에 사용되는 모델입니다. ChatGPT 로그인 필요.", + "dash.searchReasoning": "서치 추론 강도", +diff --git a/gui/src/i18n/ru.ts b/gui/src/i18n/ru.ts +index 0109f5ebd..87704912a 100644 +--- a/gui/src/i18n/ru.ts ++++ b/gui/src/i18n/ru.ts +@@ -308,6 +308,8 @@ export const ru: Record = { + "models.staleBanner": "Codex показывает список моделей старее этого каталога. Перезапустите Codex, чтобы перечитать его.", + "dash.codexAutoStart": "Запускать opencodex вместе с Codex", + "dash.codexAutoStartHint": "Разрешает установленному launcher shim выполнять ocx ensure. Эта настройка не устанавливает защиту перезапуска; проверьте фактическое состояние в разделе безопасности запуска.", ++ "dash.codexDesktopAuthless": "Открывать Codex без входа", ++ "dash.codexDesktopAuthlessHint": "По умолчанию выключено. Пропускает отдельный вход в Desktop для допустимых локальных подключений. Учётные данные провайдера по-прежнему нужны. После изменения перезапустите Codex. Функции Desktop, связанные с аккаунтом, могут быть недоступны.", + "dash.searchModel": "Модель сайдкара поиска", + "dash.searchModelHint": "Модель, используемая для web_search на маршрутизируемых моделях, отличных от OpenAI. Требуется вход в аккаунт ChatGPT.", + "dash.searchReasoning": "Уровень рассуждений для поиска", +diff --git a/gui/src/i18n/tr.ts b/gui/src/i18n/tr.ts +index fa8b8e9c2..807eeae32 100644 +--- a/gui/src/i18n/tr.ts ++++ b/gui/src/i18n/tr.ts +@@ -309,6 +309,8 @@ export const tr: Record = { + "models.staleBanner": "Codex, bu katalogdan daha eski bir model listesi gösteriyor. Yeniden okumak için Codex'i yeniden başlatın.", + "dash.codexAutoStart": "opencodex'i Codex ile başlat", + "dash.codexAutoStartHint": "Yüklü bir shim'in ocx ensure çalıştırmasına izin verir. Arka plan servisi veya yeniden başlatma koruması kurmaz; sistem durumu için Başlatma Güvenliği'ne bakın.", ++ "dash.codexDesktopAuthless": "Codex’i oturum açmadan başlat", ++ "dash.codexDesktopAuthlessHint": "Varsayılan olarak kapalıdır. Uygun yerel bağlantılarda ayrı Desktop oturum açma adımını atlar. Sağlayıcı kimlik bilgileri yine gereklidir. Değişiklikten sonra Codex’i yeniden başlatın. Hesaba bağlı Desktop özellikleri kullanılamayabilir.", + "dash.searchModel": "Arama yan araç modeli", + "dash.searchModelHint": "OpenAI dışı yönlendirilen modellerde web_search için kullanılan model. ChatGPT girişi gerektirir.", + "dash.searchReasoning": "Arama akıl yürütme çabası", +diff --git a/gui/src/i18n/zh-TW.ts b/gui/src/i18n/zh-TW.ts +index 3bc246543..62e1f0711 100644 +--- a/gui/src/i18n/zh-TW.ts ++++ b/gui/src/i18n/zh-TW.ts +@@ -200,6 +200,8 @@ export const zhTW: Record = { + "models.staleBanner": "Codex 顯示的模型清單比目前的目錄舊。重新啟動 Codex 即可重新讀取。", + "dash.codexAutoStart": "隨 Codex 啟動 opencodex", + "dash.codexAutoStartHint": "允許已安裝的 launcher shim 執行 ocx ensure。此設定不會安裝重新啟動保護;請在啟動安全中檢查實際狀態。", ++ "dash.codexDesktopAuthless": "無需登入即可開啟 Codex", ++ "dash.codexDesktopAuthlessHint": "預設關閉。為符合條件的本機連線略過獨立的 Desktop 登入。仍需上游供應商憑證。變更後請重新啟動 Codex。依賴帳戶的 Desktop 功能可能無法使用。", + "dash.searchModel": "搜尋附屬模型", + "dash.searchModelHint": "用於非 OpenAI 路由模型的 web_search 的模型。需要 ChatGPT 登入。", + "dash.searchReasoning": "搜尋推理強度", +diff --git a/gui/src/i18n/zh.ts b/gui/src/i18n/zh.ts +index b10c48688..994691442 100644 +--- a/gui/src/i18n/zh.ts ++++ b/gui/src/i18n/zh.ts +@@ -303,6 +303,8 @@ export const zh: Record = { + "models.staleBanner": "Codex 显示的模型列表比当前目录旧。重启 Codex 即可重新读取。", + "dash.codexAutoStart": "随 Codex 启动 opencodex", + "dash.codexAutoStartHint": "允许已安装的 launcher shim 运行 ocx ensure。此设置不会安装重启保护;请在启动安全中检查实际状态。", ++ "dash.codexDesktopAuthless": "无需登录即可打开 Codex", ++ "dash.codexDesktopAuthlessHint": "默认关闭。为符合条件的本地连接跳过单独的 Desktop 登录。仍需上游提供商凭据。更改后请重启 Codex。依赖账户的 Desktop 功能可能不可用。", + "dash.searchModel": "搜索附属模型", + "dash.searchModelHint": "用于非 OpenAI 路由模型的 web_search 的模型。需要 ChatGPT 登录。", + "dash.searchReasoning": "搜索推理强度", +diff --git a/gui/src/pages/dashboard-overview-sections.tsx b/gui/src/pages/dashboard-overview-sections.tsx +index 8da531f97..6606c4f56 100644 +--- a/gui/src/pages/dashboard-overview-sections.tsx ++++ b/gui/src/pages/dashboard-overview-sections.tsx +@@ -163,7 +163,7 @@ export function DashboardInjectionPanel({ d }: { apiBase: string; d: Dash }) { + + export function DashboardMaintenancePanel({ d }: { d: Dash }) { + const { +- t, runSync, syncing, updateTriggerRef, openUpdateDialog, updateLoading, updateOpen, ++ t, runSync, syncing, settingsSaving, updateTriggerRef, openUpdateDialog, updateLoading, updateOpen, + syncResult, syncError, updateJob, reconnecting, clearSyncFeedback, + } = d; + const syncHoldsWarning = !!syncResult && ( +@@ -211,7 +211,7 @@ export function DashboardMaintenancePanel({ d }: { d: Dash }) { +
{t("dash.syncModelsHint")}
+
+
+- +
+ + ++
++
++
++
{t("dash.codexDesktopAuthless")}
++
{t("dash.codexDesktopAuthlessHint")}
++ {settings?.catalogRefreshPending &&
{t("codexAuth.catalogRefreshPending")}
} ++
++ ++
++
++ +
+ {/* Both sidecar cards wear the DashboardInjectionPanel shell: the PANEL is + the flex row, copy left, controls right. */} +diff --git a/gui/src/pages/dashboard-shared.ts b/gui/src/pages/dashboard-shared.ts +index 0793a7def..d24051028 100644 +--- a/gui/src/pages/dashboard-shared.ts ++++ b/gui/src/pages/dashboard-shared.ts +@@ -48,6 +48,8 @@ export interface ProviderInfo { name: string; adapter: string; baseUrl: string; + export interface ModelInfo { id: string; provider: string; namespaced: string; owned_by?: string; reasoningEfforts?: string[] } + export interface SettingsData { + codexAutoStart: boolean; ++ codexDesktopAuthless?: boolean; ++ catalogRefreshPending?: boolean; + /** Whether a login may open a browser on the machine running the proxy. */ + oauthOpenBrowser?: boolean; + port: number; +diff --git a/gui/src/pages/use-dashboard-data.ts b/gui/src/pages/use-dashboard-data.ts +index 6f84950ce..6da776ea1 100644 +--- a/gui/src/pages/use-dashboard-data.ts ++++ b/gui/src/pages/use-dashboard-data.ts +@@ -607,23 +607,24 @@ export function useDashboardData(apiBase: string) { + finally { setInjectionSaving(false); } + }; + +- const toggleCodexAutoStart = async () => { +- if (!settings || settingsSaving) return; +- const next = !settings.codexAutoStart; ++ const toggleCodexSetting = async (key: "codexAutoStart" | "codexDesktopAuthless") => { ++ if (!settings || settingsSaving || syncing) return; ++ const next = !(settings[key] ?? (key === "codexAutoStart")); + setSettingsSaving(true); + settingsMutationInFlightRef.current = true; +- setSettings({ ...settings, codexAutoStart: next }); ++ setSettings({ ...settings, [key]: next }); + try { + const res = await fetch(`${apiBase}/api/settings`, { + method: "PUT", + headers: { "Content-Type": "application/json" }, +- body: JSON.stringify({ codexAutoStart: next }), ++ body: JSON.stringify({ [key]: next }), + }); +- const data = await requireJson<{ codexAutoStart: boolean; startupHealth?: SettingsData["startupHealth"] }>(res, "save failed"); ++ const data = await requireJson(res, "save failed"); + settingsMutationEpochRef.current += 1; +- setSettings(prev => prev ? { ...prev, codexAutoStart: data.codexAutoStart, startupHealth: data.startupHealth ?? prev.startupHealth } : prev); ++ setSettings(prev => prev ? { ...prev, [key]: data[key], catalogRefreshPending: key === "codexDesktopAuthless" ? data.catalogRefreshPending : prev.catalogRefreshPending, startupHealth: data.startupHealth ?? prev.startupHealth } : prev); ++ if (key === "codexDesktopAuthless") await runSync(); + } catch { +- setSettings(prev => prev ? { ...prev, codexAutoStart: !next } : prev); ++ setSettings(prev => prev ? { ...prev, [key]: !next } : prev); + setError(true); + } finally { + settingsMutationInFlightRef.current = false; +@@ -631,6 +632,9 @@ export function useDashboardData(apiBase: string) { + } + }; + ++ const toggleCodexAutoStart = () => toggleCodexSetting("codexAutoStart"); ++ const toggleCodexDesktopAuthless = () => toggleCodexSetting("codexDesktopAuthless"); ++ + // Clears the sync result/error in this hook. The dashboard toast owns its own dismissal + // timer but must publish the dismissal here: syncResult/syncError live above the dashboard + // tabs, so a component-local flag alone would let a stale result remount as a fresh toast +@@ -649,6 +653,7 @@ export function useDashboardData(apiBase: string) { + const res = await fetch(`${apiBase}/api/sync`, { method: "POST" }); + const data = await requireJson(res, "sync failed"); + setSyncResult(data); ++ setSettings(prev => prev ? { ...prev, catalogRefreshPending: false } : prev); + if (data.projectConfigGrouped) setProjectConfigWarnings(data.projectConfigGrouped); + } catch (err) { + setSyncError(err instanceof Error ? err.message : String(err)); +@@ -789,7 +794,7 @@ export function useDashboardData(apiBase: string) { + effortCapHelpTriggerRef, updateTriggerRef, maHelpTriggerRef, shadowCallHelpTriggerRef, + effortCapHelpDialogRef, updateDialogRef, maHelpDialogRef, shadowCallHelpDialogRef, + filteredGroups, sidecarModels, visionModels, +- saveSidecar, saveShadowCall, switchMaMode, toggleCodexAutoStart, runSync, clearSyncFeedback, ++ saveSidecar, saveShadowCall, switchMaMode, toggleCodexAutoStart, toggleCodexDesktopAuthless, runSync, clearSyncFeedback, + fetchUpdateCheck, closeUpdateDialog, openUpdateDialog, changeUpdateChannel, runUpdate, + }; + } +diff --git a/gui/tests/vision-sidecar-dashboard.test.tsx b/gui/tests/vision-sidecar-dashboard.test.tsx +index dc762de58..994a40912 100644 +--- a/gui/tests/vision-sidecar-dashboard.test.tsx ++++ b/gui/tests/vision-sidecar-dashboard.test.tsx +@@ -12,7 +12,7 @@ import { LanguageProvider } from "../src/i18n/provider"; + import { DashboardSidecarPanels } from "../src/pages/dashboard-overview-sections"; + import type { SidecarData, SidecarPatch } from "../src/pages/dashboard-shared"; + import { mergeSidecarSetting } from "../src/pages/dashboard-shared"; +-import type { useDashboardData } from "../src/pages/use-dashboard-data"; ++import { useDashboardData } from "../src/pages/use-dashboard-data"; + + const globals = ["document", "window", "navigator", "IS_REACT_ACT_ENVIRONMENT"] as const; + let previousGlobals: Record<(typeof globals)[number], PropertyDescriptor | undefined>; +@@ -382,4 +382,79 @@ test("model and reasoning saves still omit enabled, limit, and timeout", async ( + expect(patches).toHaveLength(2); + expect(patches[1]).toEqual({ vision: { reasoning: "high" } }); + assertVisionControlFieldsOmitted(patches[1]!); +-}); +\ No newline at end of file ++}); ++ ++test("Desktop login switch defaults off, preserves explicit opt-in, and disables while saving", async () => { ++ const { d } = harness(); ++ let clicks = 0; ++ d.toggleCodexDesktopAuthless = async () => { clicks += 1; }; ++ d.settings = { codexAutoStart: true, port: 10100, hostname: "127.0.0.1" }; ++ await mount(d); ++ const toggle = () => host.querySelector(`button[aria-label="${en["dash.codexDesktopAuthless"]}"]`)!; ++ expect(toggle().getAttribute("aria-pressed")).toBe("false"); ++ d.settings.codexDesktopAuthless = true; ++ await mount(d); ++ expect(toggle().getAttribute("aria-pressed")).toBe("true"); ++ await act(async () => { toggle().click(); }); ++ expect(clicks).toBe(1); ++ d.settings.codexDesktopAuthless = false; ++ d.settings.catalogRefreshPending = true; ++ d.settingsSaving = true; ++ await mount(d); ++ expect(toggle().getAttribute("aria-pressed")).toBe("false"); ++ expect(toggle().disabled).toBe(true); ++ expect(host.textContent).toContain(en["codexAuth.catalogRefreshPending"]); ++}); ++ ++ ++test.each([undefined, false, true])("Desktop login preference %s persists before full sync; sync failure keeps the saved preference", async (initial) => { ++ const originalFetch = globalThis.fetch; ++ const writes: Array<{ path: string; body: unknown }> = []; ++ let latest: Dash | undefined; ++ let saved = initial; ++ const apiBase = `/authless-test-${String(initial)}`; ++ globalThis.fetch = (async (input: RequestInfo | URL, init?: RequestInit) => { ++ const path = String(input); ++ if (init?.method === "PUT") { ++ const body = JSON.parse(String(init.body)); ++ writes.push({ path, body }); ++ if (body.codexDesktopAuthless !== undefined) { ++ saved = body.codexDesktopAuthless; ++ return Response.json({ codexDesktopAuthless: saved, catalogRefreshPending: true }); ++ } ++ return Response.json({ codexAutoStart: body.codexAutoStart, catalogRefreshPending: false }); ++ } ++ if (path.endsWith("/api/sync")) { ++ writes.push({ path, body: null }); ++ return Response.json({ error: "sync unavailable" }, { status: 503 }); ++ } ++ if (path.endsWith("/api/settings")) { ++ return Response.json({ codexAutoStart: true, codexDesktopAuthless: saved, port: 10100, hostname: "127.0.0.1" }); ++ } ++ return Response.json({}, { status: 503 }); ++ }) as typeof fetch; ++ function Harness() { latest = useDashboardData(apiBase); return null; } ++ try { ++ const { createRoot } = await import("react-dom/client"); ++ await act(async () => { ++ root = createRoot(host); ++ root.render(); ++ }); ++ expect(latest?.settings?.codexDesktopAuthless).toBe(initial); ++ await act(async () => { await latest!.toggleCodexDesktopAuthless(); }); ++ expect(writes).toEqual([ ++ { path: `${apiBase}/api/settings`, body: { codexDesktopAuthless: !initial } }, ++ { path: `${apiBase}/api/sync`, body: null }, ++ ]); ++ expect(latest?.settings?.codexDesktopAuthless).toBe(!initial); ++ expect(latest?.syncError).toBe("sync unavailable"); ++ expect(latest?.settings?.catalogRefreshPending).toBe(true); ++ await act(async () => { await latest!.toggleCodexAutoStart(); }); ++ expect(latest?.settings?.codexAutoStart).toBe(false); ++ expect(latest?.settings?.catalogRefreshPending).toBe(true); ++ } finally { ++ await act(async () => { root?.unmount(); }); ++ root = null; ++ globalThis.fetch = originalFetch; ++ } ++}); +diff --git a/tests/codex-integration/codex-inject.test.ts b/tests/codex-integration/codex-inject.test.ts +index 84ac5f67b..b6be3c2f6 100644 +--- a/tests/codex-integration/codex-inject.test.ts ++++ b/tests/codex-integration/codex-inject.test.ts +@@ -31,8 +31,8 @@ describe("Codex config injection", () => { + }); + + describe("authless Codex Desktop opt-in (#1107)", () => { +- test("default target on loopback stays Design B and byte-identical", () => { +- const target = standaloneCodexRoutingTarget(10100, {}); ++ test.each([undefined, false])("disabled preference %s on loopback stays Design B and byte-identical", (codexDesktopAuthless) => { ++ const target = standaloneCodexRoutingTarget(10100, { codexDesktopAuthless }); + expect(target.desktopAuthless).toBeUndefined(); + expect(buildProfileFile(target, null)).toBe(buildProfileFile(10100, null)); + expect(buildProviderTableBlock(target)).toContain("requires_openai_auth = true"); + +``` + +Audit amendment: clear catalogRefreshPending only if sync status is affirmative success, not HTTP 200 skipped. Add skipped/no-write regression. diff --git a/devlog/_plan/260907_lane_c/050_fallback.md b/devlog/_plan/260907_lane_c/050_fallback.md new file mode 100644 index 0000000000..6bf165a96c --- /dev/null +++ b/devlog/_plan/260907_lane_c/050_fallback.md @@ -0,0 +1,368 @@ +# 3252 implementation contract + +Carry source commits with -x. Preserve configured fallback models absent from availability. Add focused GUI tests for add/remove/reorder/save and unavailable model round-trip. Reuse existing /api/v2 (enabled, multiAgentMode, keepNativeChatGptOnV1) and report recovery enabled/eligibility as unknown when the server does not expose it, never fabricate recovery settings state for contextual native-parent/routed-child V2 guidance. Never infer all workflows are native; warn conditionally, show disabled/eligible/experimental/unknown state truthfully, link issue 92. No roster-reuse switch. Update all locales and codex-integration docs; actual UI screenshot. New PR body is valid Markdown, removes unsupported roster-switch claims. + +Validation: local tests/typecheck/build/install NOT RUN by instruction. Read diff and source; top remote CI exercises changed test paths. Each conditional branch listed above is exercised by controlled fixtures; screenshot inspects GUI state. No new enforcement layer; existing API guards remain authoritative. + +## Public source diff (MODIFY/NEW paths) + +```diff +diff --git a/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx b/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx +index 46c0447a7..7c3b0e942 100644 +--- a/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx ++++ b/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx +@@ -28,6 +28,13 @@ export interface SubagentDelegationSectionProps { + onUltraModeSave: (patch: UltraModePatch) => void; + ultraLoadFailed: boolean; + onUltraModeRetry: () => void; ++ fallback: string[]; ++ fallbackPollMs: number; ++ fallbackBusy: boolean; ++ availableModels: string[]; ++ onFallbackChange: (models: string[]) => void; ++ onFallbackPollMsChange: (pollMs: number) => void; ++ onFallbackSave: () => void; + } + + export default function SubagentDelegationSection({ +@@ -44,6 +51,7 @@ export default function SubagentDelegationSection({ + onUltraModeSave, + ultraLoadFailed, + onUltraModeRetry, ++ fallback, fallbackPollMs, fallbackBusy, availableModels, onFallbackChange, onFallbackPollMsChange, onFallbackSave, + }: SubagentDelegationSectionProps) { + const t = useT(); + // A present empty/whitespace hint is an upstream override that suppresses the +@@ -97,6 +105,31 @@ export default function SubagentDelegationSection({ +
+ + ++
++
++
{t("sub.fallbackLabel")}
++
{t("sub.fallbackHint")}
++
++
++ {fallback.map((modelName, index) => ( ++
++ {index + 1}. {modelName} ++ ++ ++ ++
++ ))} ++ ++ ++ ++
++
++ +
+
+
{t("dash.syncCodexSubagentDefaults")}
+diff --git a/gui/src/components/subagents-workspace/SubagentsWorkspace.tsx b/gui/src/components/subagents-workspace/SubagentsWorkspace.tsx +index a22bd2a30..30b722b2b 100644 +--- a/gui/src/components/subagents-workspace/SubagentsWorkspace.tsx ++++ b/gui/src/components/subagents-workspace/SubagentsWorkspace.tsx +@@ -37,6 +37,12 @@ export interface SubagentsWorkspaceProps { + onToggle: (m: string) => void; + onMove: (i: number, dir: -1 | 1) => void; + onSave: () => void; ++ fallback: string[]; ++ fallbackPollMs: number; ++ fallbackBusy: boolean; ++ onFallbackChange: (models: string[]) => void; ++ onFallbackPollMsChange: (pollMs: number) => void; ++ onFallbackSave: () => void; + delegation: { + model: string; + effort: string; +@@ -63,6 +69,7 @@ export default function SubagentsWorkspace({ + onToggle, + onMove, + onSave, ++ fallback, fallbackPollMs, fallbackBusy, onFallbackChange, onFallbackPollMsChange, onFallbackSave, + delegation, + }: SubagentsWorkspaceProps) { + const t = useT(); +@@ -237,6 +244,13 @@ export default function SubagentsWorkspace({ + onUltraModeSave={delegation.onUltraModeSave} + ultraLoadFailed={delegation.ultraLoadFailed} + onUltraModeRetry={delegation.onUltraModeRetry} ++ fallback={fallback} ++ fallbackPollMs={fallbackPollMs} ++ fallbackBusy={fallbackBusy} ++ availableModels={available} ++ onFallbackChange={onFallbackChange} ++ onFallbackPollMsChange={onFallbackPollMsChange} ++ onFallbackSave={onFallbackSave} + /> + +
+diff --git a/gui/src/i18n/de.ts b/gui/src/i18n/de.ts +index 429379396..2bb0b10c1 100644 +--- a/gui/src/i18n/de.ts ++++ b/gui/src/i18n/de.ts +@@ -672,6 +672,12 @@ export const de: Record = { + "sub.ultraModeLoadFail": "Ultra-Modus-Einstellungen konnten nicht geladen werden — läuft der Proxy?", + "sub.ultraModeSaveFail": "Ultra-Modus-Einstellungen konnten nicht gespeichert werden", + "sub.ultraModeSaved": "Ultra-Modus gespeichert. Gilt für neue Codex-Sitzungen.", ++ "sub.fallbackLabel": "Fallback-Kette für Sub-Agenten", ++ "sub.fallbackHint": "Geordnete Modelle, die versucht werden, wenn ein Sub-Agent-Modell nicht verfügbar ist oder fehlschlägt.", ++ "sub.fallbackAdd": "Fallback-Modell hinzufügen…", ++ "sub.fallbackPoll": "Intervall der Verfügbarkeitsprüfung", ++ "sub.fallbackSaved": "Fallback-Einstellungen für Sub-Agenten gespeichert.", ++ "sub.fallbackSaveFailed": "Fallback-Einstellungen konnten nicht gespeichert werden", + "logs.title": "Anfrage-Protokolle", + "logs.tabLogs": "Protokolle", + "logs.tabDebug": "Diagnose", +diff --git a/gui/src/i18n/en.ts b/gui/src/i18n/en.ts +index 9cbf8699f..e1346616a 100644 +--- a/gui/src/i18n/en.ts ++++ b/gui/src/i18n/en.ts +@@ -315,6 +315,12 @@ export const en = { + "dash.visionTimeout": "Timeout", + "dash.visionTimeoutInvalid": "Enter an integer from {min} to {max} milliseconds.", + "dash.visionAdvancedPopover": "Advanced vision settings", ++ "sub.fallbackLabel": "Sub-agent fallback chain", ++ "sub.fallbackHint": "Ordered models tried when a sub-agent model is unavailable or fails.", ++ "sub.fallbackAdd": "Add fallback model…", ++ "sub.fallbackPoll": "Availability check interval", ++ "sub.fallbackSaved": "Sub-agent fallback settings saved.", ++ "sub.fallbackSaveFailed": "Failed to save fallback settings", + "dash.shadowCallIntercept": "Shadow Call Intercept", + "dash.shadowCallInterceptHint": "Intercepts Codex App's background helper calls ({models}) for title generation and commit messages and redirects them to your chosen model.", + "dash.shadowCallWarning": "⚠ When enabled, ALL requests for {models} will be replaced with the selected model.", +diff --git a/gui/src/i18n/fr.ts b/gui/src/i18n/fr.ts +index ec171e627..d5d29b0be 100644 +--- a/gui/src/i18n/fr.ts ++++ b/gui/src/i18n/fr.ts +@@ -305,6 +305,12 @@ export const fr: Record = { + "dash.visionTimeout": "Délai d’expiration", + "dash.visionTimeoutInvalid": "Saisissez un entier compris entre {min} et {max} millisecondes.", + "dash.visionAdvancedPopover": "Paramètres de vision avancés", ++ "sub.fallbackLabel": "Chaîne de secours des sous-agents", ++ "sub.fallbackHint": "Modèles essayés dans l’ordre lorsqu’un modèle de sous-agent est indisponible ou échoue.", ++ "sub.fallbackAdd": "Ajouter un modèle de secours…", ++ "sub.fallbackPoll": "Intervalle de vérification de disponibilité", ++ "sub.fallbackSaved": "Paramètres de secours des sous-agents enregistrés.", ++ "sub.fallbackSaveFailed": "Échec de l’enregistrement des paramètres de secours", + "dash.shadowCallIntercept": "Interception des appels fantômes", + "dash.shadowCallInterceptHint": "Intercepte les appels auxiliaires en arrière-plan de l’application Codex ({models}) pour générer les titres et les messages de commit, puis les redirige vers le modèle choisi.", + "dash.shadowCallWarning": "⚠ Lorsque cette option est activée, TOUTES les requêtes destinées à {models} sont remplacées par le modèle sélectionné.", +diff --git a/gui/src/i18n/ja.ts b/gui/src/i18n/ja.ts +index c71bd7a04..747438bdc 100644 +--- a/gui/src/i18n/ja.ts ++++ b/gui/src/i18n/ja.ts +@@ -632,6 +632,12 @@ export const ja: Record = { + "sub.ultraModeLoadFail": "ウルトラモード設定を読み込めませんでした — プロキシは実行中ですか?", + "sub.ultraModeSaveFail": "ウルトラモード設定の保存に失敗しました", + "sub.ultraModeSaved": "ウルトラモードを保存しました。新しい Codex セッションから適用されます。", ++ "sub.fallbackLabel": "サブエージェントのフォールバックチェーン", ++ "sub.fallbackHint": "サブエージェントモデルが利用できないか失敗した場合に順番に試すモデルです。", ++ "sub.fallbackAdd": "フォールバックモデルを追加…", ++ "sub.fallbackPoll": "利用可能性チェック間隔", ++ "sub.fallbackSaved": "サブエージェントのフォールバック設定を保存しました。", ++ "sub.fallbackSaveFailed": "フォールバック設定の保存に失敗しました", + + // logs + "logs.title": "リクエストログ", +diff --git a/gui/src/i18n/ko.ts b/gui/src/i18n/ko.ts +index 63ac30442..ecc0e4560 100644 +--- a/gui/src/i18n/ko.ts ++++ b/gui/src/i18n/ko.ts +@@ -689,6 +689,12 @@ export const ko: Record = { + "sub.ultraModeLoadFail": "울트라 모드 설정을 불러오지 못했습니다 — 프록시가 실행 중인가요?", + "sub.ultraModeSaveFail": "울트라 모드 설정 저장에 실패했습니다", + "sub.ultraModeSaved": "울트라 모드가 저장되었습니다. 새 Codex 세션부터 적용됩니다.", ++ "sub.fallbackLabel": "서브에이전트 폴백 체인", ++ "sub.fallbackHint": "서브에이전트 모델을 사용할 수 없거나 실패할 때 순서대로 시도할 모델입니다.", ++ "sub.fallbackAdd": "폴백 모델 추가…", ++ "sub.fallbackPoll": "가용성 확인 간격", ++ "sub.fallbackSaved": "서브에이전트 폴백 설정을 저장했습니다.", ++ "sub.fallbackSaveFailed": "폴백 설정을 저장하지 못했습니다", + + // logs + "logs.title": "요청 로그", +diff --git a/gui/src/i18n/ru.ts b/gui/src/i18n/ru.ts +index 9f220ba2b..852eb4467 100644 +--- a/gui/src/i18n/ru.ts ++++ b/gui/src/i18n/ru.ts +@@ -687,6 +687,12 @@ export const ru: Record = { + "sub.ultraModeLoadFail": "Не удалось загрузить настройки ультра-режима — работает ли прокси?", + "sub.ultraModeSaveFail": "Не удалось сохранить настройки ультра-режима", + "sub.ultraModeSaved": "Ультра-режим сохранён. Применяется к новым сеансам Codex.", ++ "sub.fallbackLabel": "Цепочка резервных моделей субагента", ++ "sub.fallbackHint": "Модели, которые последовательно пробуются, если модель субагента недоступна или завершается ошибкой.", ++ "sub.fallbackAdd": "Добавить резервную модель…", ++ "sub.fallbackPoll": "Интервал проверки доступности", ++ "sub.fallbackSaved": "Настройки резервных моделей субагента сохранены.", ++ "sub.fallbackSaveFailed": "Не удалось сохранить настройки резервных моделей", + + // logs + "logs.title": "Журнал запросов", +diff --git a/gui/src/i18n/tr.ts b/gui/src/i18n/tr.ts +index aee152cd3..71d9e7313 100644 +--- a/gui/src/i18n/tr.ts ++++ b/gui/src/i18n/tr.ts +@@ -694,6 +694,12 @@ export const tr: Record = { + "sub.ultraModeLoadFail": "Ultra modu ayarları yüklenemedi — proxy çalışıyor mu?", + "sub.ultraModeSaveFail": "Ultra modu ayarları kaydedilemedi", + "sub.ultraModeSaved": "Ultra modu kaydedildi. Yeni Codex oturumlarına uygulanır.", ++ "sub.fallbackLabel": "Alt ajan yedek zinciri", ++ "sub.fallbackHint": "Alt ajan modeli kullanılamadığında veya başarısız olduğunda sırayla denenecek modeller.", ++ "sub.fallbackAdd": "Yedek model ekle…", ++ "sub.fallbackPoll": "Kullanılabilirlik kontrol aralığı", ++ "sub.fallbackSaved": "Alt ajan yedek ayarları kaydedildi.", ++ "sub.fallbackSaveFailed": "Yedek ayarlar kaydedilemedi", + + // logs + "logs.title": "İstek Günlükleri", +diff --git a/gui/src/i18n/zh-TW.ts b/gui/src/i18n/zh-TW.ts +index 39c9e2f0b..50659c2e6 100644 +--- a/gui/src/i18n/zh-TW.ts ++++ b/gui/src/i18n/zh-TW.ts +@@ -541,6 +541,12 @@ export const zhTW: Record = { + "sub.ultraModeLoadFail": "無法載入超級模式設定 — 代理是否在執行?", + "sub.ultraModeSaveFail": "儲存超級模式設定失敗", + "sub.ultraModeSaved": "超級模式已儲存。適用於新的 Codex 會話。", ++ "sub.fallbackLabel": "子代理備援鏈", ++ "sub.fallbackHint": "子代理模型無法使用或失敗時,依序嘗試的模型。", ++ "sub.fallbackAdd": "新增備援模型…", ++ "sub.fallbackPoll": "可用性檢查間隔", ++ "sub.fallbackSaved": "子代理備援設定已儲存。", ++ "sub.fallbackSaveFailed": "備援設定儲存失敗", + "logs.title": "請求日誌", + "logs.tabLogs": "日誌", + "logs.tabDebug": "除錯", +diff --git a/gui/src/i18n/zh.ts b/gui/src/i18n/zh.ts +index 1ba4cabfa..ded94d699 100644 +--- a/gui/src/i18n/zh.ts ++++ b/gui/src/i18n/zh.ts +@@ -682,6 +682,12 @@ export const zh: Record = { + "sub.ultraModeLoadFail": "无法加载超级模式设置 — 代理是否在运行?", + "sub.ultraModeSaveFail": "保存超级模式设置失败", + "sub.ultraModeSaved": "超级模式已保存。适用于新的 Codex 会话。", ++ "sub.fallbackLabel": "子代理回退链", ++ "sub.fallbackHint": "子代理模型不可用或失败时按顺序尝试的模型。", ++ "sub.fallbackAdd": "添加回退模型…", ++ "sub.fallbackPoll": "可用性检查间隔", ++ "sub.fallbackSaved": "子代理回退设置已保存。", ++ "sub.fallbackSaveFailed": "保存回退设置失败", + + // logs + "logs.title": "请求日志", +diff --git a/gui/src/pages/Subagents.tsx b/gui/src/pages/Subagents.tsx +index 6b54d39ff..299c9306f 100644 +--- a/gui/src/pages/Subagents.tsx ++++ b/gui/src/pages/Subagents.tsx +@@ -8,7 +8,7 @@ import { useDataSurface } from "../data-surface"; + import { DataSurfaceSkeleton } from "../components/data-surface"; + import { useSubagentDelegation, type UltraModePatch, type UltraModeState } from "./use-subagent-delegation"; + +-type CachedSubagents = { available: string[]; chosen: string[] }; ++type CachedSubagents = { available: string[]; chosen: string[]; fallback: string[]; pollMs: number }; + + function seedSubagents(cacheKey: string): CachedSubagents | null { + return readSessionListCache(cacheKey); +@@ -19,6 +19,9 @@ export default function Subagents({ apiBase }: { apiBase: string }) { + const cacheKey = `ocx.subagents.v1:${apiBase}`; + const cached = seedSubagents(cacheKey); + const [chosen, setChosen] = useState(() => cached?.chosen ?? []); ++ const [fallback, setFallback] = useState(() => cached?.fallback ?? []); ++ const [fallbackPollMs, setFallbackPollMs] = useState(() => cached?.pollMs ?? 60000); ++ const [fallbackBusy, setFallbackBusy] = useState(false); + const [status, setStatus] = useState(""); + const [ok, setOk] = useState(false); + const [busy, setBusy] = useState(false); +@@ -117,16 +120,24 @@ export default function Subagents({ apiBase }: { apiBase: string }) { + const loadSubagents = useCallback(async (signal?: AbortSignal): Promise => { + // The resource layer's deadline abort must reach the wire — a signal dropped + // here is a store that can only settle by race timeout. +- const res = await fetch(`${apiBase}/api/subagent-models`, { signal }); +- const response = await readJsonOrThrow<{ available?: string[]; chosen?: string[] }>(res, t("sub.loadFail")); +- if (!response) throw new Error(t("sub.loadFail")); +- const available = response.available ?? []; ++ const [rosterRes, fallbackRes] = await Promise.all([ ++ fetch(`${apiBase}/api/subagent-models`, { signal }), ++ fetch(`${apiBase}/api/subagent-model-fallback`, { signal }), ++ ]); ++ const response = await readJsonOrThrow<{ available?: string[]; chosen?: string[] }>(rosterRes, t("sub.loadFail")); ++ const fallbackResponse = await readJsonOrThrow<{ available?: string[]; models?: string[]; pollMs?: number }>(fallbackRes, t("sub.loadFail")); ++ if (!response || !fallbackResponse) throw new Error(t("sub.loadFail")); ++ const available = response.available ?? fallbackResponse.available ?? []; + const availableSet = new Set(available); + const next = { + available, + chosen: (response.chosen ?? []).filter(model => availableSet.has(model)), ++ fallback: (fallbackResponse.models ?? []).filter(model => availableSet.has(model)), ++ pollMs: fallbackResponse.pollMs ?? 60000, + }; + setChosen(next.chosen); ++ setFallback(next.fallback); ++ setFallbackPollMs(next.pollMs); + writeSessionListCache(cacheKey, next); + return next; + }, [apiBase, cacheKey, t]); +@@ -174,7 +185,7 @@ export default function Subagents({ apiBase }: { apiBase: string }) { + const d = await readJsonOrThrow<{ applied?: string[] }>(r, t("sub.saveFailed")); + const applied = d?.applied ?? chosen; + if (d?.applied) setChosen(d.applied); +- writeSessionListCache(cacheKey, { available, chosen: applied }); ++ writeSessionListCache(cacheKey, { available, chosen: applied, fallback, pollMs: fallbackPollMs }); + setOk(true); + setStatus(t("sub.saved", { n: applied.length, cmd: "ocx sync" })); + } catch (error) { +@@ -186,6 +197,28 @@ export default function Subagents({ apiBase }: { apiBase: string }) { + } + }; + ++ const saveFallback = async () => { ++ if (fallbackBusy) return; ++ setFallbackBusy(true); ++ try { ++ const r = await fetch(`${apiBase}/api/subagent-model-fallback`, { ++ method: "PUT", ++ headers: { "Content-Type": "application/json" }, ++ body: JSON.stringify({ models: fallback, pollMs: fallbackPollMs }), ++ }); ++ const d = await readJsonOrThrow<{ models?: string[]; pollMs?: number }>(r, t("sub.fallbackSaveFailed")); ++ if (d?.models) setFallback(d.models); ++ if (d?.pollMs) setFallbackPollMs(d.pollMs); ++ setOk(true); ++ setStatus(t("sub.fallbackSaved")); ++ } catch (error) { ++ setOk(false); ++ setStatus(error instanceof Error && error.message ? error.message : t("sub.networkError")); ++ } finally { ++ setFallbackBusy(false); ++ } ++ }; ++ + // The skeleton owns the live region while this resource has no content yet. + if (state.showSkeleton && !snapshot) { + return ; +@@ -214,7 +247,13 @@ export default function Subagents({ apiBase }: { apiBase: string }) { + busy={busy} + onToggle={toggle} + onMove={move} +- onSave={() => { void save(); }} ++ onSave={() => { void save(); }} ++ fallback={fallback} ++ fallbackPollMs={fallbackPollMs} ++ fallbackBusy={fallbackBusy} ++ onFallbackChange={setFallback} ++ onFallbackPollMsChange={setFallbackPollMs} ++ onFallbackSave={() => { void saveFallback(); }} + delegation={{ + model: delegation.model, + effort: delegation.effort, + +``` + +Audit amendment: cache server-confirmed fallback values after fallback Save; roster Save preserves committed fallback snapshot, never draft. Add independent-save and remount regressions. Existing dashboard density, CSS tokens, Select and icon library retained; no concept art needed for utility editor. From eb5ff6c582d694db96e94e5d0a58ed5dbc6843f3 Mon Sep 17 00:00:00 2001 From: Robin Bially <7304732+RobinBially@users.noreply.github.com> Date: Mon, 7 Sep 2026 09:57:05 +0200 Subject: [PATCH 109/412] feat(gui): add opt-in Codex Desktop sign-in toggle [skip ci] (cherry picked from commit 0f21769f346e64c2c6b2a03ff8d09b3deaab9562) Co-authored-by: RobinBially <7304732+RobinBially@users.noreply.github.com> --- .../content/docs/guides/codex-integration.md | 9 ++ docs/pr-assets/codex-desktop-opt-in.jpg | Bin 0 -> 29051 bytes gui/src/i18n/de.ts | 2 + gui/src/i18n/en.ts | 2 + gui/src/i18n/fr.ts | 2 + gui/src/i18n/ja.ts | 2 + gui/src/i18n/ko.ts | 2 + gui/src/i18n/ru.ts | 2 + gui/src/i18n/tr.ts | 2 + gui/src/i18n/zh-TW.ts | 2 + gui/src/i18n/zh.ts | 2 + gui/src/pages/dashboard-overview-sections.tsx | 28 ++++++- gui/src/pages/dashboard-shared.ts | 2 + gui/src/pages/use-dashboard-data.ts | 23 +++-- gui/tests/vision-sidecar-dashboard.test.tsx | 79 +++++++++++++++++- tests/codex-integration/codex-inject.test.ts | 4 +- 16 files changed, 146 insertions(+), 17 deletions(-) create mode 100644 docs/pr-assets/codex-desktop-opt-in.jpg diff --git a/docs-site/src/content/docs/guides/codex-integration.md b/docs-site/src/content/docs/guides/codex-integration.md index 7d66e72c3f..ff2df04fdd 100644 --- a/docs-site/src/content/docs/guides/codex-integration.md +++ b/docs-site/src/content/docs/guides/codex-integration.md @@ -215,6 +215,15 @@ HTTP/SSE. ### Authless Codex Desktop (opt-in) +In **Dashboard → Overview**, **Open Codex without signing in** controls this existing +opt-in preference. The switch defaults to **off** when the setting is absent or false; +an existing explicit `codexDesktopAuthless: true` stays enabled. The dashboard saves +the preference and runs a full sync. Restart Codex Desktop after changing it. +If synchronization fails, the saved preference remains and the dashboard shows the error; +retry **Sync** before restarting. Account-gated Desktop features may be unavailable +when enabled. Upstream credentials, local eligibility, remote admission authentication +and user-owned gateway settings retain their existing requirements. + Codex Desktop shows its ChatGPT login screen whenever the active provider requires OpenAI auth. If your OpenCodex setup never uses ChatGPT credentials (routed providers only, or a blocked `chatgpt.com`), you can opt out of that gate: diff --git a/docs/pr-assets/codex-desktop-opt-in.jpg b/docs/pr-assets/codex-desktop-opt-in.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d06203e7113cc54e87b1272e272d8f943c5b4805 GIT binary patch literal 29051 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 literal 0 HcmV?d00001 diff --git a/gui/src/i18n/de.ts b/gui/src/i18n/de.ts index 5faab4b356..495104bd42 100644 --- a/gui/src/i18n/de.ts +++ b/gui/src/i18n/de.ts @@ -299,6 +299,8 @@ export const de: Record = { "models.staleBanner": "Codex zeigt eine ältere Modellliste als dieser Katalog. Starte Codex neu, um sie neu zu laden.", "dash.codexAutoStart": "opencodex mit Codex starten", "dash.codexAutoStartHint": "Erlaubt einem installierten Launcher-Shim, ocx ensure auszuführen. Diese Einstellung installiert keinen Neustartschutz; prüfe den effektiven Zustand unter Startsicherheit.", + "dash.codexDesktopAuthless": "Codex ohne Anmeldung öffnen", + "dash.codexDesktopAuthlessHint": "Standardmäßig aus. Überspringt die separate Desktop-Anmeldung bei geeigneten lokalen Verbindungen. Zugangsdaten für den Anbieter bleiben erforderlich. Codex nach einer Änderung neu starten. Kontogebundene Desktop-Funktionen können fehlen.", "dash.searchModel": "Such-Sidecar-Modell", "dash.searchModelHint": "Modell für web_search bei nicht über OpenAI gerouteten Modellen. Erfordert ChatGPT-Login.", "dash.searchReasoning": "Such-Reasoning-Aufwand", diff --git a/gui/src/i18n/en.ts b/gui/src/i18n/en.ts index c71208942f..22a3807858 100644 --- a/gui/src/i18n/en.ts +++ b/gui/src/i18n/en.ts @@ -311,6 +311,8 @@ export const en = { "models.staleBanner": "Codex is showing an older model list than this catalog. Restart Codex to reload it.", "dash.codexAutoStart": "Start opencodex with Codex", "dash.codexAutoStartHint": "Allows an installed launcher shim to run ocx ensure. This setting does not install restart protection; check Startup safety for the effective state.", + "dash.codexDesktopAuthless": "Open Codex without signing in", + "dash.codexDesktopAuthlessHint": "Off by default. Skip the separate Desktop sign-in for eligible local connections. Upstream credentials are still required. Restart Codex after changing this setting. Account-gated Desktop features may be unavailable.", "dash.searchModel": "Search sidecar model", "dash.searchModelHint": "Model used for web_search on non-OpenAI routed models. Requires ChatGPT login.", "dash.searchReasoning": "Search reasoning effort", diff --git a/gui/src/i18n/fr.ts b/gui/src/i18n/fr.ts index e1b3519ef1..9f0f265173 100644 --- a/gui/src/i18n/fr.ts +++ b/gui/src/i18n/fr.ts @@ -301,6 +301,8 @@ export const fr: Record = { "models.staleBanner": "Codex affiche une liste de modèles plus ancienne que ce catalogue. Redémarrez Codex pour la recharger.", "dash.codexAutoStart": "Démarrer opencodex avec Codex", "dash.codexAutoStartHint": "Permet à un mécanisme de lancement installé d’exécuter ocx ensure. Ce réglage n’installe pas de protection au redémarrage ; consultez Sécurité du démarrage pour connaître l’état effectif.", + "dash.codexDesktopAuthless": "Ouvrir Codex sans se connecter", + "dash.codexDesktopAuthlessHint": "Désactivé par défaut. Ignore la connexion Desktop séparée pour les connexions locales admissibles. Les identifiants du fournisseur restent nécessaires. Redémarrez Codex après toute modification. Certaines fonctions Desktop liées au compte peuvent être indisponibles.", "dash.searchModel": "Modèle auxiliaire de recherche", "dash.searchModelHint": "Modèle utilisé pour web_search sur les modèles routés autres qu’OpenAI. Nécessite une connexion à ChatGPT.", "dash.searchReasoning": "Effort de raisonnement pour la recherche", diff --git a/gui/src/i18n/ja.ts b/gui/src/i18n/ja.ts index cf94831583..55a6fe2495 100644 --- a/gui/src/i18n/ja.ts +++ b/gui/src/i18n/ja.ts @@ -308,6 +308,8 @@ export const ja: Record = { "models.staleBanner": "Codex はこのカタログより古いモデル一覧を表示しています。Codex を再起動すると読み直されます。", "dash.codexAutoStart": "Codex と一緒に opencodex を起動", "dash.codexAutoStartHint": "インストール済み launcher shim に ocx ensure の実行を許可します。この設定だけでは再起動保護はインストールされません。起動安全性で実際の状態を確認してください。", + "dash.codexDesktopAuthless": "ログインせずに Codex を開く", + "dash.codexDesktopAuthlessHint": "既定ではオフです。対象のローカル接続で Desktop の個別ログインを省略します。上流プロバイダーの認証情報は引き続き必要です。変更後は Codex を再起動してください。アカウントに依存する Desktop 機能が利用できない場合があります。", "dash.searchModel": "検索サイドカーモデル", "dash.searchModelHint": "非 OpenAI ルーティングモデルで web_search に使うモデル。ChatGPT ログインが必要です。", "dash.searchReasoning": "検索の推論負荷", diff --git a/gui/src/i18n/ko.ts b/gui/src/i18n/ko.ts index c1959482b7..19285b150e 100644 --- a/gui/src/i18n/ko.ts +++ b/gui/src/i18n/ko.ts @@ -303,6 +303,8 @@ export const ko: Record = { "models.staleBanner": "Codex가 이 카탈로그보다 오래된 모델 목록을 보여주고 있습니다. Codex를 재시작하면 새로 읽습니다.", "dash.codexAutoStart": "Codex 실행 시 opencodex 시작", "dash.codexAutoStartHint": "설치된 launcher shim이 ocx ensure를 실행하도록 허용합니다. 이 설정은 재부팅 보호를 설치하지 않으므로 시작 안전성에서 실제 상태를 확인하세요.", + "dash.codexDesktopAuthless": "로그인 없이 Codex 열기", + "dash.codexDesktopAuthlessHint": "기본값은 꺼짐입니다. 지원되는 로컬 연결에서 별도의 Desktop 로그인을 건너뜁니다. 업스트림 인증 정보는 여전히 필요합니다. 변경 후 Codex를 다시 시작하세요. 계정에 연결된 Desktop 기능을 사용하지 못할 수 있습니다.", "dash.searchModel": "서치 사이드카 모델", "dash.searchModelHint": "비-OpenAI 라우팅 모델의 web_search에 사용되는 모델입니다. ChatGPT 로그인 필요.", "dash.searchReasoning": "서치 추론 강도", diff --git a/gui/src/i18n/ru.ts b/gui/src/i18n/ru.ts index 0109f5ebdc..87704912ac 100644 --- a/gui/src/i18n/ru.ts +++ b/gui/src/i18n/ru.ts @@ -308,6 +308,8 @@ export const ru: Record = { "models.staleBanner": "Codex показывает список моделей старее этого каталога. Перезапустите Codex, чтобы перечитать его.", "dash.codexAutoStart": "Запускать opencodex вместе с Codex", "dash.codexAutoStartHint": "Разрешает установленному launcher shim выполнять ocx ensure. Эта настройка не устанавливает защиту перезапуска; проверьте фактическое состояние в разделе безопасности запуска.", + "dash.codexDesktopAuthless": "Открывать Codex без входа", + "dash.codexDesktopAuthlessHint": "По умолчанию выключено. Пропускает отдельный вход в Desktop для допустимых локальных подключений. Учётные данные провайдера по-прежнему нужны. После изменения перезапустите Codex. Функции Desktop, связанные с аккаунтом, могут быть недоступны.", "dash.searchModel": "Модель сайдкара поиска", "dash.searchModelHint": "Модель, используемая для web_search на маршрутизируемых моделях, отличных от OpenAI. Требуется вход в аккаунт ChatGPT.", "dash.searchReasoning": "Уровень рассуждений для поиска", diff --git a/gui/src/i18n/tr.ts b/gui/src/i18n/tr.ts index fa8b8e9c25..807eeae32b 100644 --- a/gui/src/i18n/tr.ts +++ b/gui/src/i18n/tr.ts @@ -309,6 +309,8 @@ export const tr: Record = { "models.staleBanner": "Codex, bu katalogdan daha eski bir model listesi gösteriyor. Yeniden okumak için Codex'i yeniden başlatın.", "dash.codexAutoStart": "opencodex'i Codex ile başlat", "dash.codexAutoStartHint": "Yüklü bir shim'in ocx ensure çalıştırmasına izin verir. Arka plan servisi veya yeniden başlatma koruması kurmaz; sistem durumu için Başlatma Güvenliği'ne bakın.", + "dash.codexDesktopAuthless": "Codex’i oturum açmadan başlat", + "dash.codexDesktopAuthlessHint": "Varsayılan olarak kapalıdır. Uygun yerel bağlantılarda ayrı Desktop oturum açma adımını atlar. Sağlayıcı kimlik bilgileri yine gereklidir. Değişiklikten sonra Codex’i yeniden başlatın. Hesaba bağlı Desktop özellikleri kullanılamayabilir.", "dash.searchModel": "Arama yan araç modeli", "dash.searchModelHint": "OpenAI dışı yönlendirilen modellerde web_search için kullanılan model. ChatGPT girişi gerektirir.", "dash.searchReasoning": "Arama akıl yürütme çabası", diff --git a/gui/src/i18n/zh-TW.ts b/gui/src/i18n/zh-TW.ts index 3bc246543a..62e1f07110 100644 --- a/gui/src/i18n/zh-TW.ts +++ b/gui/src/i18n/zh-TW.ts @@ -200,6 +200,8 @@ export const zhTW: Record = { "models.staleBanner": "Codex 顯示的模型清單比目前的目錄舊。重新啟動 Codex 即可重新讀取。", "dash.codexAutoStart": "隨 Codex 啟動 opencodex", "dash.codexAutoStartHint": "允許已安裝的 launcher shim 執行 ocx ensure。此設定不會安裝重新啟動保護;請在啟動安全中檢查實際狀態。", + "dash.codexDesktopAuthless": "無需登入即可開啟 Codex", + "dash.codexDesktopAuthlessHint": "預設關閉。為符合條件的本機連線略過獨立的 Desktop 登入。仍需上游供應商憑證。變更後請重新啟動 Codex。依賴帳戶的 Desktop 功能可能無法使用。", "dash.searchModel": "搜尋附屬模型", "dash.searchModelHint": "用於非 OpenAI 路由模型的 web_search 的模型。需要 ChatGPT 登入。", "dash.searchReasoning": "搜尋推理強度", diff --git a/gui/src/i18n/zh.ts b/gui/src/i18n/zh.ts index b10c48688d..9946914426 100644 --- a/gui/src/i18n/zh.ts +++ b/gui/src/i18n/zh.ts @@ -303,6 +303,8 @@ export const zh: Record = { "models.staleBanner": "Codex 显示的模型列表比当前目录旧。重启 Codex 即可重新读取。", "dash.codexAutoStart": "随 Codex 启动 opencodex", "dash.codexAutoStartHint": "允许已安装的 launcher shim 运行 ocx ensure。此设置不会安装重启保护;请在启动安全中检查实际状态。", + "dash.codexDesktopAuthless": "无需登录即可打开 Codex", + "dash.codexDesktopAuthlessHint": "默认关闭。为符合条件的本地连接跳过单独的 Desktop 登录。仍需上游提供商凭据。更改后请重启 Codex。依赖账户的 Desktop 功能可能不可用。", "dash.searchModel": "搜索附属模型", "dash.searchModelHint": "用于非 OpenAI 路由模型的 web_search 的模型。需要 ChatGPT 登录。", "dash.searchReasoning": "搜索推理强度", diff --git a/gui/src/pages/dashboard-overview-sections.tsx b/gui/src/pages/dashboard-overview-sections.tsx index 8da531f97c..6606c4f560 100644 --- a/gui/src/pages/dashboard-overview-sections.tsx +++ b/gui/src/pages/dashboard-overview-sections.tsx @@ -163,7 +163,7 @@ export function DashboardInjectionPanel({ d }: { apiBase: string; d: Dash }) { export function DashboardMaintenancePanel({ d }: { d: Dash }) { const { - t, runSync, syncing, updateTriggerRef, openUpdateDialog, updateLoading, updateOpen, + t, runSync, syncing, settingsSaving, updateTriggerRef, openUpdateDialog, updateLoading, updateOpen, syncResult, syncError, updateJob, reconnecting, clearSyncFeedback, } = d; const syncHoldsWarning = !!syncResult && ( @@ -211,7 +211,7 @@ export function DashboardMaintenancePanel({ d }: { d: Dash }) {
{t("dash.syncModelsHint")}
-
+
+
+
+
{t("dash.codexDesktopAuthless")}
+
{t("dash.codexDesktopAuthlessHint")}
+ {settings?.catalogRefreshPending &&
{t("codexAuth.catalogRefreshPending")}
} +
+ +
+
+
{/* Both sidecar cards wear the DashboardInjectionPanel shell: the PANEL is the flex row, copy left, controls right. */} diff --git a/gui/src/pages/dashboard-shared.ts b/gui/src/pages/dashboard-shared.ts index 0793a7def2..d240510286 100644 --- a/gui/src/pages/dashboard-shared.ts +++ b/gui/src/pages/dashboard-shared.ts @@ -48,6 +48,8 @@ export interface ProviderInfo { name: string; adapter: string; baseUrl: string; export interface ModelInfo { id: string; provider: string; namespaced: string; owned_by?: string; reasoningEfforts?: string[] } export interface SettingsData { codexAutoStart: boolean; + codexDesktopAuthless?: boolean; + catalogRefreshPending?: boolean; /** Whether a login may open a browser on the machine running the proxy. */ oauthOpenBrowser?: boolean; port: number; diff --git a/gui/src/pages/use-dashboard-data.ts b/gui/src/pages/use-dashboard-data.ts index 6f84950ce1..6da776ea18 100644 --- a/gui/src/pages/use-dashboard-data.ts +++ b/gui/src/pages/use-dashboard-data.ts @@ -607,23 +607,24 @@ export function useDashboardData(apiBase: string) { finally { setInjectionSaving(false); } }; - const toggleCodexAutoStart = async () => { - if (!settings || settingsSaving) return; - const next = !settings.codexAutoStart; + const toggleCodexSetting = async (key: "codexAutoStart" | "codexDesktopAuthless") => { + if (!settings || settingsSaving || syncing) return; + const next = !(settings[key] ?? (key === "codexAutoStart")); setSettingsSaving(true); settingsMutationInFlightRef.current = true; - setSettings({ ...settings, codexAutoStart: next }); + setSettings({ ...settings, [key]: next }); try { const res = await fetch(`${apiBase}/api/settings`, { method: "PUT", headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ codexAutoStart: next }), + body: JSON.stringify({ [key]: next }), }); - const data = await requireJson<{ codexAutoStart: boolean; startupHealth?: SettingsData["startupHealth"] }>(res, "save failed"); + const data = await requireJson(res, "save failed"); settingsMutationEpochRef.current += 1; - setSettings(prev => prev ? { ...prev, codexAutoStart: data.codexAutoStart, startupHealth: data.startupHealth ?? prev.startupHealth } : prev); + setSettings(prev => prev ? { ...prev, [key]: data[key], catalogRefreshPending: key === "codexDesktopAuthless" ? data.catalogRefreshPending : prev.catalogRefreshPending, startupHealth: data.startupHealth ?? prev.startupHealth } : prev); + if (key === "codexDesktopAuthless") await runSync(); } catch { - setSettings(prev => prev ? { ...prev, codexAutoStart: !next } : prev); + setSettings(prev => prev ? { ...prev, [key]: !next } : prev); setError(true); } finally { settingsMutationInFlightRef.current = false; @@ -631,6 +632,9 @@ export function useDashboardData(apiBase: string) { } }; + const toggleCodexAutoStart = () => toggleCodexSetting("codexAutoStart"); + const toggleCodexDesktopAuthless = () => toggleCodexSetting("codexDesktopAuthless"); + // Clears the sync result/error in this hook. The dashboard toast owns its own dismissal // timer but must publish the dismissal here: syncResult/syncError live above the dashboard // tabs, so a component-local flag alone would let a stale result remount as a fresh toast @@ -649,6 +653,7 @@ export function useDashboardData(apiBase: string) { const res = await fetch(`${apiBase}/api/sync`, { method: "POST" }); const data = await requireJson(res, "sync failed"); setSyncResult(data); + setSettings(prev => prev ? { ...prev, catalogRefreshPending: false } : prev); if (data.projectConfigGrouped) setProjectConfigWarnings(data.projectConfigGrouped); } catch (err) { setSyncError(err instanceof Error ? err.message : String(err)); @@ -789,7 +794,7 @@ export function useDashboardData(apiBase: string) { effortCapHelpTriggerRef, updateTriggerRef, maHelpTriggerRef, shadowCallHelpTriggerRef, effortCapHelpDialogRef, updateDialogRef, maHelpDialogRef, shadowCallHelpDialogRef, filteredGroups, sidecarModels, visionModels, - saveSidecar, saveShadowCall, switchMaMode, toggleCodexAutoStart, runSync, clearSyncFeedback, + saveSidecar, saveShadowCall, switchMaMode, toggleCodexAutoStart, toggleCodexDesktopAuthless, runSync, clearSyncFeedback, fetchUpdateCheck, closeUpdateDialog, openUpdateDialog, changeUpdateChannel, runUpdate, }; } diff --git a/gui/tests/vision-sidecar-dashboard.test.tsx b/gui/tests/vision-sidecar-dashboard.test.tsx index dc762de58f..994a409126 100644 --- a/gui/tests/vision-sidecar-dashboard.test.tsx +++ b/gui/tests/vision-sidecar-dashboard.test.tsx @@ -12,7 +12,7 @@ import { LanguageProvider } from "../src/i18n/provider"; import { DashboardSidecarPanels } from "../src/pages/dashboard-overview-sections"; import type { SidecarData, SidecarPatch } from "../src/pages/dashboard-shared"; import { mergeSidecarSetting } from "../src/pages/dashboard-shared"; -import type { useDashboardData } from "../src/pages/use-dashboard-data"; +import { useDashboardData } from "../src/pages/use-dashboard-data"; const globals = ["document", "window", "navigator", "IS_REACT_ACT_ENVIRONMENT"] as const; let previousGlobals: Record<(typeof globals)[number], PropertyDescriptor | undefined>; @@ -382,4 +382,79 @@ test("model and reasoning saves still omit enabled, limit, and timeout", async ( expect(patches).toHaveLength(2); expect(patches[1]).toEqual({ vision: { reasoning: "high" } }); assertVisionControlFieldsOmitted(patches[1]!); -}); \ No newline at end of file +}); + +test("Desktop login switch defaults off, preserves explicit opt-in, and disables while saving", async () => { + const { d } = harness(); + let clicks = 0; + d.toggleCodexDesktopAuthless = async () => { clicks += 1; }; + d.settings = { codexAutoStart: true, port: 10100, hostname: "127.0.0.1" }; + await mount(d); + const toggle = () => host.querySelector(`button[aria-label="${en["dash.codexDesktopAuthless"]}"]`)!; + expect(toggle().getAttribute("aria-pressed")).toBe("false"); + d.settings.codexDesktopAuthless = true; + await mount(d); + expect(toggle().getAttribute("aria-pressed")).toBe("true"); + await act(async () => { toggle().click(); }); + expect(clicks).toBe(1); + d.settings.codexDesktopAuthless = false; + d.settings.catalogRefreshPending = true; + d.settingsSaving = true; + await mount(d); + expect(toggle().getAttribute("aria-pressed")).toBe("false"); + expect(toggle().disabled).toBe(true); + expect(host.textContent).toContain(en["codexAuth.catalogRefreshPending"]); +}); + + +test.each([undefined, false, true])("Desktop login preference %s persists before full sync; sync failure keeps the saved preference", async (initial) => { + const originalFetch = globalThis.fetch; + const writes: Array<{ path: string; body: unknown }> = []; + let latest: Dash | undefined; + let saved = initial; + const apiBase = `/authless-test-${String(initial)}`; + globalThis.fetch = (async (input: RequestInfo | URL, init?: RequestInit) => { + const path = String(input); + if (init?.method === "PUT") { + const body = JSON.parse(String(init.body)); + writes.push({ path, body }); + if (body.codexDesktopAuthless !== undefined) { + saved = body.codexDesktopAuthless; + return Response.json({ codexDesktopAuthless: saved, catalogRefreshPending: true }); + } + return Response.json({ codexAutoStart: body.codexAutoStart, catalogRefreshPending: false }); + } + if (path.endsWith("/api/sync")) { + writes.push({ path, body: null }); + return Response.json({ error: "sync unavailable" }, { status: 503 }); + } + if (path.endsWith("/api/settings")) { + return Response.json({ codexAutoStart: true, codexDesktopAuthless: saved, port: 10100, hostname: "127.0.0.1" }); + } + return Response.json({}, { status: 503 }); + }) as typeof fetch; + function Harness() { latest = useDashboardData(apiBase); return null; } + try { + const { createRoot } = await import("react-dom/client"); + await act(async () => { + root = createRoot(host); + root.render(); + }); + expect(latest?.settings?.codexDesktopAuthless).toBe(initial); + await act(async () => { await latest!.toggleCodexDesktopAuthless(); }); + expect(writes).toEqual([ + { path: `${apiBase}/api/settings`, body: { codexDesktopAuthless: !initial } }, + { path: `${apiBase}/api/sync`, body: null }, + ]); + expect(latest?.settings?.codexDesktopAuthless).toBe(!initial); + expect(latest?.syncError).toBe("sync unavailable"); + expect(latest?.settings?.catalogRefreshPending).toBe(true); + await act(async () => { await latest!.toggleCodexAutoStart(); }); + expect(latest?.settings?.codexAutoStart).toBe(false); + expect(latest?.settings?.catalogRefreshPending).toBe(true); + } finally { + await act(async () => { root?.unmount(); }); + root = null; + globalThis.fetch = originalFetch; + } +}); diff --git a/tests/codex-integration/codex-inject.test.ts b/tests/codex-integration/codex-inject.test.ts index 84ac5f67b6..b6be3c2f69 100644 --- a/tests/codex-integration/codex-inject.test.ts +++ b/tests/codex-integration/codex-inject.test.ts @@ -31,8 +31,8 @@ describe("Codex config injection", () => { }); describe("authless Codex Desktop opt-in (#1107)", () => { - test("default target on loopback stays Design B and byte-identical", () => { - const target = standaloneCodexRoutingTarget(10100, {}); + test.each([undefined, false])("disabled preference %s on loopback stays Design B and byte-identical", (codexDesktopAuthless) => { + const target = standaloneCodexRoutingTarget(10100, { codexDesktopAuthless }); expect(target.desktopAuthless).toBeUndefined(); expect(buildProfileFile(target, null)).toBe(buildProfileFile(10100, null)); expect(buildProviderTableBlock(target)).toContain("requires_openai_auth = true"); From 2b14053ff625e1750583269829bbbecf0a100b6c Mon Sep 17 00:00:00 2001 From: x3M3x Date: Wed, 2 Sep 2026 09:49:07 +0400 Subject: [PATCH 110/412] docs: add subagent fallback settings screenshot [skip ci] (cherry picked from commit aba57a074941b7cdae3074eca9a0256d0621eb22) Co-authored-by: x3M3x <98298256+x3M3x@users.noreply.github.com> --- .../subagent-fallback-settings.png | Bin 0 -> 215189 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs-site/public/pr-screenshots/subagent-fallback-settings.png diff --git a/docs-site/public/pr-screenshots/subagent-fallback-settings.png b/docs-site/public/pr-screenshots/subagent-fallback-settings.png new file mode 100644 index 0000000000000000000000000000000000000000..04f72f140cd0d904d63ff72f9da7e0a0300e1a5e GIT binary patch literal 215189 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

UR?jC!(*%I%`utfvcyOR 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 Date: Mon, 7 Sep 2026 10:34:15 +0900 Subject: [PATCH 111/412] fix(web-search): bound the Anthropic sidecar SSE and error bodies [skip ci] `parseAnthropicSidecarSSE` folded frames only when it found a `\n\n` separator, and appended every decoded chunk to `buffer` until then. An upstream that streams without ever emitting a separator therefore grew the buffer for the whole response. The non-OK branch had the same shape: it read the untrusted error body with an unbounded `res.text()` just to build one auth-failure message. Reuse the existing `MAX_SIDECAR_RESPONSE_BYTES` cap and the reader-cancel helper that `parseSidecarSSE` already applies in the same folder, so both paths stop reading at the same 64 KiB bound. Frames folded before the cap are kept; only the unterminated tail is dropped. `cancelReaderWithoutWaiting` is exported for this, unchanged. The regression drives a stream that never terminates a frame and asserts the read is cancelled well before the producer finishes. It fails without the cap and passes with it. (cherry picked from commit c25bdab6dd955bc2ccfb9f952403009ac560b13e) Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com> --- src/web-search/anthropic-executor.ts | 52 +++++++++++++++++-- src/web-search/parse.ts | 2 +- tests/web-search/web-search-anthropic.test.ts | 21 ++++++++ 3 files changed, 71 insertions(+), 4 deletions(-) diff --git a/src/web-search/anthropic-executor.ts b/src/web-search/anthropic-executor.ts index 1eb206afa8..cd3893900c 100644 --- a/src/web-search/anthropic-executor.ts +++ b/src/web-search/anthropic-executor.ts @@ -5,7 +5,11 @@ import { CLAUDE_CODE_HEADERS, claudeCodeSessionId } from "../adapters/client-fin import { signalWithTimeout, cancelBodyOnAbort } from "../lib/abort"; import { sidecarEnter } from "../lib/sidecar-tracker"; import { applyUpstreamRecoveryInit, fetchWithResetRetry } from "../lib/upstream-retry"; -import type { WebSearchSource } from "./parse"; +import { + MAX_SIDECAR_RESPONSE_BYTES, + cancelReaderWithoutWaiting, + type WebSearchSource, +} from "./parse"; import { BASE_INSTRUCTION, IMAGE_INSTRUCTION, type SidecarOutcome, type SidecarSettings } from "./executor"; /** Hardcoded per-turn search bound handed to the server tool (mirrors the loop's maxSearches intent). */ @@ -17,6 +21,33 @@ function isRec(v: unknown): v is Record { return !!v && typeof v === "object" && !Array.isArray(v); } +/** Read at most `MAX_SIDECAR_RESPONSE_BYTES` of an untrusted upstream body, then stop reading. */ +async function readBoundedText(res: Response): Promise { + if (!res.body) return ""; + const reader = res.body.getReader(); + const decoder = new TextDecoder(); + let out = ""; + let seen = 0; + try { + for (;;) { + const { done, value } = await reader.read(); + if (done) break; + const remaining = MAX_SIDECAR_RESPONSE_BYTES - seen; + const accepted = value.byteLength <= remaining ? value : value.subarray(0, remaining); + seen += accepted.byteLength; + out += decoder.decode(accepted, { stream: true }); + if (seen >= MAX_SIDECAR_RESPONSE_BYTES) { + cancelReaderWithoutWaiting(reader, "sidecar error body byte limit reached"); + break; + } + } + out += decoder.decode(); + } catch { + /* a failed error-body read must not mask the HTTP status we are about to report */ + } + return out; +} + /** * Fold an Anthropic Messages SSE stream (a web_search_20250305 turn) into a WebSearchResult. * @@ -41,6 +72,7 @@ export async function parseAnthropicSidecarSSE(res: Response): Promise): void => { const type = typeof data.type === "string" ? data.type : ""; @@ -82,15 +114,27 @@ export async function parseAnthropicSidecarSSE(res: Response): Promise= MAX_SIDECAR_RESPONSE_BYTES) { + // Keep the frames already folded above, drop the unterminated tail, and do not wait on + // upstream teardown. + cancelReaderWithoutWaiting(reader, "sidecar response byte limit reached"); + buffer = ""; + break; + } } // Flush the decoder and process any final unterminated frame (a stream that ends without \n\n). buffer = (buffer + decoder.decode()).replace(/\r\n/g, "\n"); @@ -177,7 +221,9 @@ export async function runAnthropicWebSearch( // (found investigating #1419). const detachBodyGuard = cancelBodyOnAbort(res.body, linkedSignal.signal); if (!res.ok) { - const t = await res.text().catch(() => ""); + // Untrusted upstream error bodies are only used for an auth-failure message, so read a + // bounded prefix instead of buffering an arbitrarily large response. + const t = await readBoundedText(res); detachBodyGuard(); console.warn(`[web-search] anthropic sidecar HTTP ${res.status} for query "${query.slice(0, 80)}" (${Date.now() - t0}ms)`); if (res.status === 401) { diff --git a/src/web-search/parse.ts b/src/web-search/parse.ts index 757c309f3e..7ba5d2607c 100644 --- a/src/web-search/parse.ts +++ b/src/web-search/parse.ts @@ -193,7 +193,7 @@ function fromOutputArray(output: OutputItem[], seen: Set): WebSearchResu return { text, sources }; } -function cancelReaderWithoutWaiting( +export function cancelReaderWithoutWaiting( reader: ReadableStreamDefaultReader, reason: string, ): void { diff --git a/tests/web-search/web-search-anthropic.test.ts b/tests/web-search/web-search-anthropic.test.ts index f5b7f1df26..33f2616cc2 100644 --- a/tests/web-search/web-search-anthropic.test.ts +++ b/tests/web-search/web-search-anthropic.test.ts @@ -130,6 +130,27 @@ describe("parseAnthropicSidecarSSE", () => { expect(out.error).toBeDefined(); }); + test("an unterminated frame cannot buffer the stream without bound", async () => { + // A sidecar that never emits a frame separator: without a cap the parser would accumulate + // the whole stream in memory before it could fold anything. + let produced = 0; + let cancelled = false; + const chunk = new TextEncoder().encode(`data: {"filler":"${"x".repeat(64 * 1024)}"}`); + const body = new ReadableStream({ + pull(c) { + if (produced > 8 * 1024 * 1024) { c.close(); return; } + produced += chunk.byteLength; + c.enqueue(chunk); + }, + cancel() { cancelled = true; }, + }); + const out = await parseAnthropicSidecarSSE(new Response(body, { status: 200 })); + expect(cancelled).toBe(true); + // The cap stops the read long before the producer would have finished on its own. + expect(produced).toBeLessThan(1024 * 1024); + expect(out.text).toBe(""); + }); + test("empty results (content:[]) with answer text is a success, not an error", async () => { const res = sseResponse([ { type: "content_block_start", index: 0, content_block: { type: "web_search_tool_result", tool_use_id: "srvtoolu_3", content: [] } }, From c1f96f0a5af6bf98e663d287eeffaabcdb0d0028 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 18:25:44 +0900 Subject: [PATCH 112/412] fix(gui): retain pending Desktop preference when sync is skipped [skip ci] Co-authored-by: RobinBially <7304732+RobinBially@users.noreply.github.com> --- gui/src/i18n/de.ts | 4 +-- gui/src/i18n/en.ts | 4 +-- gui/src/i18n/fr.ts | 4 +-- gui/src/i18n/ja.ts | 4 +-- gui/src/i18n/ko.ts | 4 +-- gui/src/i18n/ru.ts | 4 +-- gui/src/i18n/tr.ts | 4 +-- gui/src/i18n/zh-TW.ts | 4 +-- gui/src/i18n/zh.ts | 4 +-- gui/src/pages/dashboard-shared.ts | 1 + gui/src/pages/use-dashboard-data.ts | 4 ++- gui/tests/vision-sidecar-dashboard.test.tsx | 27 +++++++++++++++++++++ 12 files changed, 49 insertions(+), 19 deletions(-) diff --git a/gui/src/i18n/de.ts b/gui/src/i18n/de.ts index 495104bd42..74533a04d3 100644 --- a/gui/src/i18n/de.ts +++ b/gui/src/i18n/de.ts @@ -299,8 +299,6 @@ export const de: Record = { "models.staleBanner": "Codex zeigt eine ältere Modellliste als dieser Katalog. Starte Codex neu, um sie neu zu laden.", "dash.codexAutoStart": "opencodex mit Codex starten", "dash.codexAutoStartHint": "Erlaubt einem installierten Launcher-Shim, ocx ensure auszuführen. Diese Einstellung installiert keinen Neustartschutz; prüfe den effektiven Zustand unter Startsicherheit.", - "dash.codexDesktopAuthless": "Codex ohne Anmeldung öffnen", - "dash.codexDesktopAuthlessHint": "Standardmäßig aus. Überspringt die separate Desktop-Anmeldung bei geeigneten lokalen Verbindungen. Zugangsdaten für den Anbieter bleiben erforderlich. Codex nach einer Änderung neu starten. Kontogebundene Desktop-Funktionen können fehlen.", "dash.searchModel": "Such-Sidecar-Modell", "dash.searchModelHint": "Modell für web_search bei nicht über OpenAI gerouteten Modellen. Erfordert ChatGPT-Login.", "dash.searchReasoning": "Such-Reasoning-Aufwand", @@ -2471,6 +2469,8 @@ export const de: Record = { "dash.visionTimeout": "Timeout", "dash.visionTimeoutInvalid": "Geben Sie eine ganze Zahl von {min} bis {max} Millisekunden ein.", "dash.visionAdvancedPopover": "Erweiterte Vision-Einstellungen", + "dash.codexDesktopAuthless": "Codex ohne Anmeldung öffnen", + "dash.codexDesktopAuthlessHint": "Standardmäßig aus. Überspringt die separate Desktop-Anmeldung bei geeigneten lokalen Verbindungen. Zugangsdaten für den Anbieter bleiben erforderlich. Codex nach einer Änderung neu starten. Kontogebundene Desktop-Funktionen können fehlen.", "models.newPolicyGlobal": "Neue Modelle zunächst deaktivieren", "models.newPolicyProvider": "Richtlinie für neue Modelle", "models.newPolicy_inherit": "Übernehmen", "models.newPolicy_off": "Aus", "models.newPolicy_on": "An", "models.newBadge": "NEU", "models.newCount": "{count} neu, aus", "models.aliases": "Aliase", diff --git a/gui/src/i18n/en.ts b/gui/src/i18n/en.ts index 22a3807858..2197dcb735 100644 --- a/gui/src/i18n/en.ts +++ b/gui/src/i18n/en.ts @@ -311,8 +311,6 @@ export const en = { "models.staleBanner": "Codex is showing an older model list than this catalog. Restart Codex to reload it.", "dash.codexAutoStart": "Start opencodex with Codex", "dash.codexAutoStartHint": "Allows an installed launcher shim to run ocx ensure. This setting does not install restart protection; check Startup safety for the effective state.", - "dash.codexDesktopAuthless": "Open Codex without signing in", - "dash.codexDesktopAuthlessHint": "Off by default. Skip the separate Desktop sign-in for eligible local connections. Upstream credentials are still required. Restart Codex after changing this setting. Account-gated Desktop features may be unavailable.", "dash.searchModel": "Search sidecar model", "dash.searchModelHint": "Model used for web_search on non-OpenAI routed models. Requires ChatGPT login.", "dash.searchReasoning": "Search reasoning effort", @@ -577,6 +575,8 @@ export const en = { "models.keepNativeOnV1Hint": "ChatGPT encrypts v2 child tasks only when a ChatGPT-native parent stays on v2, so Grok and Claude cannot read them. Turn this on to keep Sol/Terra on v1 and avoid that encryption. Routed parents keep v2.", "models.v2Help": "Controls the multi-agent surface for all models.\n\nv1: Classic single-thread agent. Every model uses the v1 collab surface.\nbase: Upstream defaults — sol/terra use v2, luna uses v1, others follow the codex feature flag.\nv2: Multi-thread agent with spawn_agent. Every model uses the v2 collab surface.\n\nOn v2, Keep ChatGPT on v1 leaves Sol/Terra on the v1 surface so they can still spawn Grok or Claude. ChatGPT encrypts v2 child tasks; routed models cannot read them. Routed parents stay on v2.\n\nChanges apply to new sessions.", "dash.multiAgent": "Sub-agent", + "dash.codexDesktopAuthless": "Open Codex without signing in", + "dash.codexDesktopAuthlessHint": "Off by default. Skip the separate Desktop sign-in for eligible local connections. Upstream credentials are still required. Restart Codex after changing this setting. Account-gated Desktop features may be unavailable.", "models.v2Conflict": "[agents] max_threads is set — codex will refuse to start; remove it from config.toml", "models.v2Applied": "Sub-agent mode updated — applies to new sessions (restart the Codex app to refresh the picker)", "models.v2ThreadsLabel": "Max threads", diff --git a/gui/src/i18n/fr.ts b/gui/src/i18n/fr.ts index 9f0f265173..cca4b70347 100644 --- a/gui/src/i18n/fr.ts +++ b/gui/src/i18n/fr.ts @@ -301,8 +301,6 @@ export const fr: Record = { "models.staleBanner": "Codex affiche une liste de modèles plus ancienne que ce catalogue. Redémarrez Codex pour la recharger.", "dash.codexAutoStart": "Démarrer opencodex avec Codex", "dash.codexAutoStartHint": "Permet à un mécanisme de lancement installé d’exécuter ocx ensure. Ce réglage n’installe pas de protection au redémarrage ; consultez Sécurité du démarrage pour connaître l’état effectif.", - "dash.codexDesktopAuthless": "Ouvrir Codex sans se connecter", - "dash.codexDesktopAuthlessHint": "Désactivé par défaut. Ignore la connexion Desktop séparée pour les connexions locales admissibles. Les identifiants du fournisseur restent nécessaires. Redémarrez Codex après toute modification. Certaines fonctions Desktop liées au compte peuvent être indisponibles.", "dash.searchModel": "Modèle auxiliaire de recherche", "dash.searchModelHint": "Modèle utilisé pour web_search sur les modèles routés autres qu’OpenAI. Nécessite une connexion à ChatGPT.", "dash.searchReasoning": "Effort de raisonnement pour la recherche", @@ -562,6 +560,8 @@ export const fr: Record = { "models.keepNativeOnV1Hint": "ChatGPT chiffre les tâches enfants v2 uniquement lorsqu’un parent natif ChatGPT reste sur v2, de sorte que Grok et Claude ne peuvent pas les lire. Activez cette option pour garder Sol/Terra sur v1 et éviter ce chiffrement. Les parents routés restent sur v2.", "models.v2Help": "Contrôle l’interface multi-agent pour tous les modèles.\n\nv1 : agent classique à fil unique. Tous les modèles utilisent l’interface collab v1.\nbase : valeurs par défaut en amont — sol/terra utilisent v2, luna utilise v1 et les autres suivent l’indicateur de fonctionnalité codex.\nv2 : agent multifil avec spawn_agent. Tous les modèles utilisent l’interface collab v2.\n\nEn v2, « Garder ChatGPT sur v1 » laisse Sol/Terra sur l’interface v1 afin qu’ils puissent encore lancer Grok ou Claude. ChatGPT chiffre les tâches enfants v2 ; les modèles routés ne peuvent pas les lire. Les parents routés restent sur v2.\n\nLes modifications s’appliquent aux nouvelles sessions.", "dash.multiAgent": "Sous-agent", + "dash.codexDesktopAuthless": "Ouvrir Codex sans se connecter", + "dash.codexDesktopAuthlessHint": "Désactivé par défaut. Ignore la connexion Desktop séparée pour les connexions locales admissibles. Les identifiants du fournisseur restent nécessaires. Redémarrez Codex après toute modification. Certaines fonctions Desktop liées au compte peuvent être indisponibles.", "models.v2Conflict": "[agents] max_threads est défini — codex refusera de démarrer ; supprimez-le de config.toml", "models.v2Applied": "Mode sous-agent mis à jour — s’applique aux nouvelles sessions (redémarrez l’application Codex pour actualiser le sélecteur)", "models.v2ThreadsLabel": "Nombre maximal de fils", diff --git a/gui/src/i18n/ja.ts b/gui/src/i18n/ja.ts index 55a6fe2495..97aa85a6fb 100644 --- a/gui/src/i18n/ja.ts +++ b/gui/src/i18n/ja.ts @@ -308,8 +308,6 @@ export const ja: Record = { "models.staleBanner": "Codex はこのカタログより古いモデル一覧を表示しています。Codex を再起動すると読み直されます。", "dash.codexAutoStart": "Codex と一緒に opencodex を起動", "dash.codexAutoStartHint": "インストール済み launcher shim に ocx ensure の実行を許可します。この設定だけでは再起動保護はインストールされません。起動安全性で実際の状態を確認してください。", - "dash.codexDesktopAuthless": "ログインせずに Codex を開く", - "dash.codexDesktopAuthlessHint": "既定ではオフです。対象のローカル接続で Desktop の個別ログインを省略します。上流プロバイダーの認証情報は引き続き必要です。変更後は Codex を再起動してください。アカウントに依存する Desktop 機能が利用できない場合があります。", "dash.searchModel": "検索サイドカーモデル", "dash.searchModelHint": "非 OpenAI ルーティングモデルで web_search に使うモデル。ChatGPT ログインが必要です。", "dash.searchReasoning": "検索の推論負荷", @@ -2492,6 +2490,8 @@ export const ja: Record = { "dash.visionTimeout": "タイムアウト", "dash.visionTimeoutInvalid": "{min} から {max} ミリ秒の整数を入力してください。", "dash.visionAdvancedPopover": "詳細なビジョン設定", + "dash.codexDesktopAuthless": "ログインせずに Codex を開く", + "dash.codexDesktopAuthlessHint": "既定ではオフです。対象のローカル接続で Desktop の個別ログインを省略します。上流プロバイダーの認証情報は引き続き必要です。変更後は Codex を再起動してください。アカウントに依存する Desktop 機能が利用できない場合があります。", "models.newPolicyGlobal": "新しいモデルを無効で追加", "models.newPolicyProvider": "新しいモデルのポリシー", "models.newPolicy_inherit": "継承", "models.newPolicy_off": "オフ", "models.newPolicy_on": "オン", "models.newBadge": "新着", "models.newCount": "新着 {count} 件、オフ", "models.aliases": "エイリアス", diff --git a/gui/src/i18n/ko.ts b/gui/src/i18n/ko.ts index 19285b150e..4e66544528 100644 --- a/gui/src/i18n/ko.ts +++ b/gui/src/i18n/ko.ts @@ -303,8 +303,6 @@ export const ko: Record = { "models.staleBanner": "Codex가 이 카탈로그보다 오래된 모델 목록을 보여주고 있습니다. Codex를 재시작하면 새로 읽습니다.", "dash.codexAutoStart": "Codex 실행 시 opencodex 시작", "dash.codexAutoStartHint": "설치된 launcher shim이 ocx ensure를 실행하도록 허용합니다. 이 설정은 재부팅 보호를 설치하지 않으므로 시작 안전성에서 실제 상태를 확인하세요.", - "dash.codexDesktopAuthless": "로그인 없이 Codex 열기", - "dash.codexDesktopAuthlessHint": "기본값은 꺼짐입니다. 지원되는 로컬 연결에서 별도의 Desktop 로그인을 건너뜁니다. 업스트림 인증 정보는 여전히 필요합니다. 변경 후 Codex를 다시 시작하세요. 계정에 연결된 Desktop 기능을 사용하지 못할 수 있습니다.", "dash.searchModel": "서치 사이드카 모델", "dash.searchModelHint": "비-OpenAI 라우팅 모델의 web_search에 사용되는 모델입니다. ChatGPT 로그인 필요.", "dash.searchReasoning": "서치 추론 강도", @@ -2493,6 +2491,8 @@ export const ko: Record = { "dash.visionTimeout": "제한 시간", "dash.visionTimeoutInvalid": "{min}에서 {max} 밀리초 사이의 정수를 입력하세요.", "dash.visionAdvancedPopover": "고급 비전 설정", + "dash.codexDesktopAuthless": "로그인 없이 Codex 열기", + "dash.codexDesktopAuthlessHint": "기본값은 꺼짐입니다. 지원되는 로컬 연결에서 별도의 Desktop 로그인을 건너뜁니다. 업스트림 인증 정보는 여전히 필요합니다. 변경 후 Codex를 다시 시작하세요. 계정에 연결된 Desktop 기능을 사용하지 못할 수 있습니다.", "models.newPolicyGlobal": "새 모델을 비활성화 상태로 추가", "models.newPolicyProvider": "새 모델 정책", "models.newPolicy_inherit": "상속", "models.newPolicy_off": "끔", "models.newPolicy_on": "켬", "models.newBadge": "신규", "models.newCount": "신규 {count}개, 꺼짐", "models.aliases": "별칭", diff --git a/gui/src/i18n/ru.ts b/gui/src/i18n/ru.ts index 87704912ac..e7f199a06a 100644 --- a/gui/src/i18n/ru.ts +++ b/gui/src/i18n/ru.ts @@ -308,8 +308,6 @@ export const ru: Record = { "models.staleBanner": "Codex показывает список моделей старее этого каталога. Перезапустите Codex, чтобы перечитать его.", "dash.codexAutoStart": "Запускать opencodex вместе с Codex", "dash.codexAutoStartHint": "Разрешает установленному launcher shim выполнять ocx ensure. Эта настройка не устанавливает защиту перезапуска; проверьте фактическое состояние в разделе безопасности запуска.", - "dash.codexDesktopAuthless": "Открывать Codex без входа", - "dash.codexDesktopAuthlessHint": "По умолчанию выключено. Пропускает отдельный вход в Desktop для допустимых локальных подключений. Учётные данные провайдера по-прежнему нужны. После изменения перезапустите Codex. Функции Desktop, связанные с аккаунтом, могут быть недоступны.", "dash.searchModel": "Модель сайдкара поиска", "dash.searchModelHint": "Модель, используемая для web_search на маршрутизируемых моделях, отличных от OpenAI. Требуется вход в аккаунт ChatGPT.", "dash.searchReasoning": "Уровень рассуждений для поиска", @@ -2494,6 +2492,8 @@ export const ru: Record = { "dash.visionTimeout": "Таймаут", "dash.visionTimeoutInvalid": "Введите целое число от {min} до {max} миллисекунд.", "dash.visionAdvancedPopover": "Дополнительные настройки изображений", + "dash.codexDesktopAuthless": "Открывать Codex без входа", + "dash.codexDesktopAuthlessHint": "По умолчанию выключено. Пропускает отдельный вход в Desktop для допустимых локальных подключений. Учётные данные провайдера по-прежнему нужны. После изменения перезапустите Codex. Функции Desktop, связанные с аккаунтом, могут быть недоступны.", "models.newPolicyGlobal": "Добавлять новые модели выключенными", "models.newPolicyProvider": "Политика новых моделей", "models.newPolicy_inherit": "Наследовать", "models.newPolicy_off": "Выкл.", "models.newPolicy_on": "Вкл.", "models.newBadge": "НОВАЯ", "models.newCount": "Новых: {count}, выкл.", "models.aliases": "Псевдонимы", diff --git a/gui/src/i18n/tr.ts b/gui/src/i18n/tr.ts index 807eeae32b..8c8f9ff802 100644 --- a/gui/src/i18n/tr.ts +++ b/gui/src/i18n/tr.ts @@ -309,8 +309,6 @@ export const tr: Record = { "models.staleBanner": "Codex, bu katalogdan daha eski bir model listesi gösteriyor. Yeniden okumak için Codex'i yeniden başlatın.", "dash.codexAutoStart": "opencodex'i Codex ile başlat", "dash.codexAutoStartHint": "Yüklü bir shim'in ocx ensure çalıştırmasına izin verir. Arka plan servisi veya yeniden başlatma koruması kurmaz; sistem durumu için Başlatma Güvenliği'ne bakın.", - "dash.codexDesktopAuthless": "Codex’i oturum açmadan başlat", - "dash.codexDesktopAuthlessHint": "Varsayılan olarak kapalıdır. Uygun yerel bağlantılarda ayrı Desktop oturum açma adımını atlar. Sağlayıcı kimlik bilgileri yine gereklidir. Değişiklikten sonra Codex’i yeniden başlatın. Hesaba bağlı Desktop özellikleri kullanılamayabilir.", "dash.searchModel": "Arama yan araç modeli", "dash.searchModelHint": "OpenAI dışı yönlendirilen modellerde web_search için kullanılan model. ChatGPT girişi gerektirir.", "dash.searchReasoning": "Arama akıl yürütme çabası", @@ -2494,6 +2492,8 @@ export const tr: Record = { "dash.visionTimeout": "Zaman aşımı", "dash.visionTimeoutInvalid": "{min} ile {max} milisaniye arasında bir tam sayı girin.", "dash.visionAdvancedPopover": "Gelişmiş görsel ayarları", + "dash.codexDesktopAuthless": "Codex’i oturum açmadan başlat", + "dash.codexDesktopAuthlessHint": "Varsayılan olarak kapalıdır. Uygun yerel bağlantılarda ayrı Desktop oturum açma adımını atlar. Sağlayıcı kimlik bilgileri yine gereklidir. Değişiklikten sonra Codex’i yeniden başlatın. Hesaba bağlı Desktop özellikleri kullanılamayabilir.", "models.newPolicyGlobal": "Yeni modeller devre dışı başlasın", "models.newPolicyProvider": "Yeni model ilkesi", "models.newPolicy_inherit": "Devral", "models.newPolicy_off": "Kapalı", "models.newPolicy_on": "Açık", "models.newBadge": "YENİ", "models.newCount": "{count} yeni, kapalı", "models.aliases": "Takma adlar", diff --git a/gui/src/i18n/zh-TW.ts b/gui/src/i18n/zh-TW.ts index 62e1f07110..eeec289911 100644 --- a/gui/src/i18n/zh-TW.ts +++ b/gui/src/i18n/zh-TW.ts @@ -200,8 +200,6 @@ export const zhTW: Record = { "models.staleBanner": "Codex 顯示的模型清單比目前的目錄舊。重新啟動 Codex 即可重新讀取。", "dash.codexAutoStart": "隨 Codex 啟動 opencodex", "dash.codexAutoStartHint": "允許已安裝的 launcher shim 執行 ocx ensure。此設定不會安裝重新啟動保護;請在啟動安全中檢查實際狀態。", - "dash.codexDesktopAuthless": "無需登入即可開啟 Codex", - "dash.codexDesktopAuthlessHint": "預設關閉。為符合條件的本機連線略過獨立的 Desktop 登入。仍需上游供應商憑證。變更後請重新啟動 Codex。依賴帳戶的 Desktop 功能可能無法使用。", "dash.searchModel": "搜尋附屬模型", "dash.searchModelHint": "用於非 OpenAI 路由模型的 web_search 的模型。需要 ChatGPT 登入。", "dash.searchReasoning": "搜尋推理強度", @@ -2456,6 +2454,8 @@ export const zhTW: Record = { "dash.visionTimeout": "逾時", "dash.visionTimeoutInvalid": "請輸入 {min} 到 {max} 毫秒之間的整數。", "dash.visionAdvancedPopover": "進階視覺設定", + "dash.codexDesktopAuthless": "無需登入即可開啟 Codex", + "dash.codexDesktopAuthlessHint": "預設關閉。為符合條件的本機連線略過獨立的 Desktop 登入。仍需上游供應商憑證。變更後請重新啟動 Codex。依賴帳戶的 Desktop 功能可能無法使用。", "models.newPolicyGlobal": "新模型預設停用", "models.newPolicyProvider": "新模型策略", "models.newPolicy_inherit": "繼承", "models.newPolicy_off": "關閉", "models.newPolicy_on": "開啟", "models.newBadge": "新增", "models.newCount": "{count} 個新增,已關閉", "models.aliases": "別名", diff --git a/gui/src/i18n/zh.ts b/gui/src/i18n/zh.ts index 9946914426..a62e9b2d6b 100644 --- a/gui/src/i18n/zh.ts +++ b/gui/src/i18n/zh.ts @@ -303,8 +303,6 @@ export const zh: Record = { "models.staleBanner": "Codex 显示的模型列表比当前目录旧。重启 Codex 即可重新读取。", "dash.codexAutoStart": "随 Codex 启动 opencodex", "dash.codexAutoStartHint": "允许已安装的 launcher shim 运行 ocx ensure。此设置不会安装重启保护;请在启动安全中检查实际状态。", - "dash.codexDesktopAuthless": "无需登录即可打开 Codex", - "dash.codexDesktopAuthlessHint": "默认关闭。为符合条件的本地连接跳过单独的 Desktop 登录。仍需上游提供商凭据。更改后请重启 Codex。依赖账户的 Desktop 功能可能不可用。", "dash.searchModel": "搜索附属模型", "dash.searchModelHint": "用于非 OpenAI 路由模型的 web_search 的模型。需要 ChatGPT 登录。", "dash.searchReasoning": "搜索推理强度", @@ -2492,6 +2490,8 @@ export const zh: Record = { "dash.visionTimeout": "超时", "dash.visionTimeoutInvalid": "请输入 {min} 到 {max} 毫秒之间的整数。", "dash.visionAdvancedPopover": "高级视觉设置", + "dash.codexDesktopAuthless": "无需登录即可打开 Codex", + "dash.codexDesktopAuthlessHint": "默认关闭。为符合条件的本地连接跳过单独的 Desktop 登录。仍需上游提供商凭据。更改后请重启 Codex。依赖账户的 Desktop 功能可能不可用。", "models.newPolicyGlobal": "新模型默认停用", "models.newPolicyProvider": "新模型策略", "models.newPolicy_inherit": "继承", "models.newPolicy_off": "关闭", "models.newPolicy_on": "开启", "models.newBadge": "新增", "models.newCount": "{count} 个新增,已关闭", "models.aliases": "别名", diff --git a/gui/src/pages/dashboard-shared.ts b/gui/src/pages/dashboard-shared.ts index d240510286..b6914586b6 100644 --- a/gui/src/pages/dashboard-shared.ts +++ b/gui/src/pages/dashboard-shared.ts @@ -128,6 +128,7 @@ export type Installer = "npm" | "bun" | "source"; export type UpdateJobStatus = "running" | "restarting" | "succeeded" | "failed"; export interface SyncResult { ok: boolean; + status?: "applied" | "skipped" | "catalog-only" | "refused"; added: number; catalogPath: string | null; catalogExists: boolean; diff --git a/gui/src/pages/use-dashboard-data.ts b/gui/src/pages/use-dashboard-data.ts index 6da776ea18..e87e6494bd 100644 --- a/gui/src/pages/use-dashboard-data.ts +++ b/gui/src/pages/use-dashboard-data.ts @@ -653,7 +653,9 @@ export function useDashboardData(apiBase: string) { const res = await fetch(`${apiBase}/api/sync`, { method: "POST" }); const data = await requireJson(res, "sync failed"); setSyncResult(data); - setSettings(prev => prev ? { ...prev, catalogRefreshPending: false } : prev); + if (data.ok && data.status === "applied") { + setSettings(prev => prev ? { ...prev, catalogRefreshPending: false } : prev); + } if (data.projectConfigGrouped) setProjectConfigWarnings(data.projectConfigGrouped); } catch (err) { setSyncError(err instanceof Error ? err.message : String(err)); diff --git a/gui/tests/vision-sidecar-dashboard.test.tsx b/gui/tests/vision-sidecar-dashboard.test.tsx index 994a409126..386196cc77 100644 --- a/gui/tests/vision-sidecar-dashboard.test.tsx +++ b/gui/tests/vision-sidecar-dashboard.test.tsx @@ -458,3 +458,30 @@ test.each([undefined, false, true])("Desktop login preference %s persists before globalThis.fetch = originalFetch; } }); + + +test.each(["skipped", "catalog-only", "applied"])("Desktop preference pending state follows %s sync application evidence", async (syncStatus) => { + const originalFetch = globalThis.fetch; + let latest: Dash | undefined; + const apiBase = `/authless-sync-${syncStatus}`; + globalThis.fetch = (async (input: RequestInfo | URL, init?: RequestInit) => { + const path = String(input); + if (init?.method === "PUT") return Response.json({ codexDesktopAuthless: true, catalogRefreshPending: true }); + if (path.endsWith("/api/sync")) return Response.json({ ok: true, status: syncStatus, message: syncStatus }); + if (path.endsWith("/api/settings")) return Response.json({ codexAutoStart: true, codexDesktopAuthless: false, port: 10100, hostname: "127.0.0.1" }); + return Response.json({}, { status: 503 }); + }) as typeof fetch; + function Harness() { latest = useDashboardData(apiBase); return null; } + try { + const { createRoot } = await import("react-dom/client"); + await act(async () => { root = createRoot(host); root.render(); }); + await act(async () => { await latest!.toggleCodexDesktopAuthless(); }); + expect(latest?.settings?.codexDesktopAuthless).toBe(true); + expect(latest?.settings?.catalogRefreshPending).toBe(syncStatus !== "applied"); + expect(latest?.syncResult?.status).toBe(syncStatus); + } finally { + await act(async () => { root?.unmount(); }); + root = null; + globalThis.fetch = originalFetch; + } +}); From f8d3545a0d77ab625f090e6e13f7924760e098d5 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 18:30:58 +0900 Subject: [PATCH 113/412] fix(gui): preserve fallback choices and explain native-parent V2 compatibility [skip ci] Co-authored-by: x3M3x <98298256+x3M3x@users.noreply.github.com> --- .../content/docs/guides/codex-integration.md | 7 + .../SubagentDelegationSection.tsx | 53 ++- gui/src/i18n/de.ts | 18 +- gui/src/i18n/en.ts | 18 +- gui/src/i18n/fr.ts | 18 +- gui/src/i18n/ja.ts | 18 +- gui/src/i18n/ko.ts | 6 + gui/src/i18n/ru.ts | 18 +- gui/src/i18n/tr.ts | 6 + gui/src/i18n/zh-TW.ts | 18 +- gui/src/i18n/zh.ts | 18 +- gui/src/pages/Subagents.tsx | 29 +- gui/src/pages/use-subagent-delegation.ts | 2 + gui/src/styles-subagents-workspace.css | 13 + gui/tests/multi-agent-guidance.test.tsx | 9 +- gui/tests/subagents-fallback.test.tsx | 422 ++++++++++++++++++ 16 files changed, 613 insertions(+), 60 deletions(-) create mode 100644 gui/tests/subagents-fallback.test.tsx diff --git a/docs-site/src/content/docs/guides/codex-integration.md b/docs-site/src/content/docs/guides/codex-integration.md index ff2df04fdd..f5592c0a72 100644 --- a/docs-site/src/content/docs/guides/codex-integration.md +++ b/docs-site/src/content/docs/guides/codex-integration.md @@ -586,3 +586,10 @@ ocx restore back # point plain Codex at the running proxy again When opencodex runs as a managed [background service](/reference/cli/#ocx-service), it sets `OCX_SERVICE=1` so a service-driven restart does **not** thrash the Codex config — only an explicit `ocx stop` / `ocx service stop` restores native Codex. + + +### Sub-agent fallback and V2 compatibility + +In **Subagents → Delegation settings**, edit the ordered fallback chain and its availability polling interval (5000–600000 ms), then save it separately from the featured roster. A configured target that is no longer advertised remains in the chain until you remove it. The roster and fallback chain are separate settings; this editor does not make the roster replace the fallback policy. + +When a routed preferred model may receive V2 work from a native ChatGPT parent, the panel explains the upstream encrypted-task limitation. Readable tasks from routed parents are unaffected. The guidance uses `/api/v2` mode and native V1 pin state; the current API does not expose recovery activation or request-specific eligibility, so the panel reports those as unknown. V1/plaintext-compatible delegation remains an alternative. Experimental V2 recovery, where eligible and explicitly enabled, adds quota usage, latency, backend dependence and possible fidelity loss; it does not repair the upstream protocol. See [sub-agent surfaces](/guides/sub-agent-surface/) and [the upstream limitation](https://github.com/lidge-jun/opencodex/issues/92). diff --git a/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx b/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx index 7c3b0e9425..dbbbd99948 100644 --- a/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx +++ b/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx @@ -8,7 +8,7 @@ */ import { useState } from "react"; import { Select, Tooltip } from "../../ui"; -import { IconInfo } from "../../icons"; +import { IconArrowDown, IconArrowUp, IconInfo, IconX } from "../../icons"; import { useT, type TKey } from "../../i18n/shared"; import { formatNamespacedModelId } from "../../provider-icons"; import type { DelegationPatch, DelegationModelOption } from "../../pages/use-subagent-delegation"; @@ -58,6 +58,19 @@ export default function SubagentDelegationSection({ // Proactive message, so it must render as OFF (and the toggle can install the // preset). Only a nonblank hint is "on". const ultraOn = (ultraMode.hintText ?? "").trim().length > 0; + const routedPreferred = available.some(option => option.namespaced === model + && !(option.provider === "openai" && option.namespaced === option.model)); + const nativeMayUseV2 = ultraMode.enabled || (ultraMode.multiAgentMode !== "v1" + && !(ultraMode.multiAgentMode === "v2" && ultraMode.keepNativeChatGptOnV1)); + const showV2Compatibility = !ultraLoadFailed && ultraMode.loaded === true && routedPreferred && nativeMayUseV2; + const validPollMs = Number.isInteger(fallbackPollMs) && fallbackPollMs >= 5000 && fallbackPollMs <= 600000; + const moveFallback = (index: number, direction: -1 | 1) => { + const next = [...fallback]; + const target = index + direction; + if (fallbackBusy || target < 0 || target >= next.length) return; + [next[index], next[target]] = [next[target], next[index]]; + onFallbackChange(next); + }; return (

@@ -105,6 +118,17 @@ export default function SubagentDelegationSection({
+ {showV2Compatibility && ( +
+ )} +
{t("sub.fallbackLabel")}
@@ -112,21 +136,26 @@ export default function SubagentDelegationSection({
{fallback.map((modelName, index) => ( -
- {index + 1}. {modelName} - - - +
+ {index + 1}. {modelName} + {!availableModels.includes(modelName) && {t("sub.fallbackUnavailable")}} + + + + + +
))} - + onFallbackPollMsChange(Number(e.target.value) || 60000)} disabled={fallbackBusy} /> ms + onFallbackPollMsChange(Number(e.target.value))} disabled={fallbackBusy} aria-invalid={!validPollMs} /> ms - + {!validPollMs &&
{t("sub.fallbackPollInvalid")}
} +
diff --git a/gui/src/i18n/de.ts b/gui/src/i18n/de.ts index 8985d342a0..4145cb8032 100644 --- a/gui/src/i18n/de.ts +++ b/gui/src/i18n/de.ts @@ -686,12 +686,6 @@ export const de: Record = { "sub.ultraModeLoadFail": "Ultra-Modus-Einstellungen konnten nicht geladen werden — läuft der Proxy?", "sub.ultraModeSaveFail": "Ultra-Modus-Einstellungen konnten nicht gespeichert werden", "sub.ultraModeSaved": "Ultra-Modus gespeichert. Gilt für neue Codex-Sitzungen.", - "sub.fallbackLabel": "Fallback-Kette für Sub-Agenten", - "sub.fallbackHint": "Geordnete Modelle, die versucht werden, wenn ein Sub-Agent-Modell nicht verfügbar ist oder fehlschlägt.", - "sub.fallbackAdd": "Fallback-Modell hinzufügen…", - "sub.fallbackPoll": "Intervall der Verfügbarkeitsprüfung", - "sub.fallbackSaved": "Fallback-Einstellungen für Sub-Agenten gespeichert.", - "sub.fallbackSaveFailed": "Fallback-Einstellungen konnten nicht gespeichert werden", "logs.title": "Anfrage-Protokolle", "logs.tabLogs": "Protokolle", "logs.tabDebug": "Diagnose", @@ -2414,6 +2408,18 @@ export const de: Record = { "sub.sections": "Subagent-Abschnitte", "sub.delegation.model": "Zuerst aufgerufenes Modell", "sub.delegation.modelHint": "Das Modell, zu dem Codex zuerst greift, wenn es Arbeit übergibt. Oben steht, wen es überhaupt aufrufen darf; hier wählst du den Ersten davon.", + "sub.fallbackLabel": "Fallback-Kette für Sub-Agenten", + "sub.fallbackHint": "Geordnete Modelle, die versucht werden, wenn ein Sub-Agent-Modell nicht verfügbar ist oder fehlschlägt.", + "sub.fallbackAdd": "Fallback-Modell hinzufügen…", + "sub.fallbackPoll": "Intervall der Verfügbarkeitsprüfung", + "sub.fallbackSaved": "Fallback-Einstellungen für Sub-Agenten gespeichert.", + "sub.fallbackSaveFailed": "Fallback-Einstellungen konnten nicht gespeichert werden", + "sub.fallbackUnavailable": "Derzeit nicht gelistet; bleibt in der Kette.", + "sub.fallbackPollInvalid": "Eine ganze Zahl von 5000 bis 600000 ms eingeben.", + "sub.v2Compatibility.title": "V2-Kompatibilität nativer Eltern", + "sub.v2Compatibility.risk": "Delegiert ein nativer ChatGPT-Elternagent über V2 an dieses geroutete Modell, kann die Aufgabe verschlüsselt sein und vor der Ausführung scheitern. Lesbare Aufgaben gerouteter Eltern sind nicht betroffen.", + "sub.v2Compatibility.recoveryUnknown": "Dieser Server meldet weder Aktivierung noch Eignung der Wiederherstellung. V1/Klartext verwenden oder experimentelle V2-Wiederherstellung nur bei Eignung aktivieren. Sie kostet Kontingent und Latenz, hängt vom Backend ab und kann Wiedergabetreue verlieren; das Upstream-Protokoll bleibt unverändert.", + "sub.v2Compatibility.details": "Details zur Kompatibilität", "dash.syncModelsHint": "Schreibt Codex' Modellkatalog anhand deiner verbundenen Provider neu.", "dash.syncRun": "Jetzt synchronisieren", "lab.title": "Kompatibilitäts-Labor", diff --git a/gui/src/i18n/en.ts b/gui/src/i18n/en.ts index a33c195e82..2a31ec7947 100644 --- a/gui/src/i18n/en.ts +++ b/gui/src/i18n/en.ts @@ -329,12 +329,6 @@ export const en = { "dash.visionTimeout": "Timeout", "dash.visionTimeoutInvalid": "Enter an integer from {min} to {max} milliseconds.", "dash.visionAdvancedPopover": "Advanced vision settings", - "sub.fallbackLabel": "Sub-agent fallback chain", - "sub.fallbackHint": "Ordered models tried when a sub-agent model is unavailable or fails.", - "sub.fallbackAdd": "Add fallback model…", - "sub.fallbackPoll": "Availability check interval", - "sub.fallbackSaved": "Sub-agent fallback settings saved.", - "sub.fallbackSaveFailed": "Failed to save fallback settings", "dash.shadowCallIntercept": "Shadow Call Intercept", "dash.shadowCallInterceptHint": "Intercepts Codex App's background helper calls ({models}) for title generation and commit messages and redirects them to your chosen model.", "dash.shadowCallWarning": "⚠ When enabled, ALL requests for {models} will be replaced with the selected model.", @@ -725,6 +719,18 @@ export const en = { "sub.workspace.selectModel": "Select a model", "sub.workspace.selectModelDesc": "Pick a model from the list to see details and feature it for spawn_agent.", "sub.workspace.selector": "Public selector", + "sub.fallbackLabel": "Sub-agent fallback chain", + "sub.fallbackHint": "Ordered models tried when a sub-agent model is unavailable or fails.", + "sub.fallbackAdd": "Add fallback model…", + "sub.fallbackPoll": "Availability check interval", + "sub.fallbackSaved": "Sub-agent fallback settings saved.", + "sub.fallbackSaveFailed": "Failed to save fallback settings", + "sub.fallbackUnavailable": "Not currently advertised; kept in the chain.", + "sub.fallbackPollInvalid": "Enter an integer from 5000 to 600000 ms.", + "sub.v2Compatibility.title": "Native-parent V2 compatibility", + "sub.v2Compatibility.risk": "If a native ChatGPT parent delegates to this routed model using V2, its task may be encrypted and fail before execution. Readable tasks from routed parents are unaffected.", + "sub.v2Compatibility.recoveryUnknown": "Recovery enabled/eligibility state is not exposed by this server. Use V1/plaintext-compatible delegation, or enable experimental V2 recovery only if eligible. Recovery adds quota, latency, backend dependence and possible fidelity loss; it does not fix the upstream protocol.", + "sub.v2Compatibility.details": "Compatibility details", // logs "logs.title": "Request Logs", diff --git a/gui/src/i18n/fr.ts b/gui/src/i18n/fr.ts index fa32925c02..753982c1bf 100644 --- a/gui/src/i18n/fr.ts +++ b/gui/src/i18n/fr.ts @@ -319,12 +319,6 @@ export const fr: Record = { "dash.visionTimeout": "Délai d’expiration", "dash.visionTimeoutInvalid": "Saisissez un entier compris entre {min} et {max} millisecondes.", "dash.visionAdvancedPopover": "Paramètres de vision avancés", - "sub.fallbackLabel": "Chaîne de secours des sous-agents", - "sub.fallbackHint": "Modèles essayés dans l’ordre lorsqu’un modèle de sous-agent est indisponible ou échoue.", - "sub.fallbackAdd": "Ajouter un modèle de secours…", - "sub.fallbackPoll": "Intervalle de vérification de disponibilité", - "sub.fallbackSaved": "Paramètres de secours des sous-agents enregistrés.", - "sub.fallbackSaveFailed": "Échec de l’enregistrement des paramètres de secours", "dash.shadowCallIntercept": "Interception des appels fantômes", "dash.shadowCallInterceptHint": "Intercepte les appels auxiliaires en arrière-plan de l’application Codex ({models}) pour générer les titres et les messages de commit, puis les redirige vers le modèle choisi.", "dash.shadowCallWarning": "⚠ Lorsque cette option est activée, TOUTES les requêtes destinées à {models} sont remplacées par le modèle sélectionné.", @@ -708,6 +702,18 @@ export const fr: Record = { "sub.workspace.selectModel": "Sélectionner un modèle", "sub.workspace.selectModelDesc": "Choisissez un modèle dans la liste pour afficher ses détails et le mettre à la une pour spawn_agent.", "sub.workspace.selector": "Sélecteur public", + "sub.fallbackLabel": "Chaîne de secours des sous-agents", + "sub.fallbackHint": "Modèles essayés dans l’ordre lorsqu’un modèle de sous-agent est indisponible ou échoue.", + "sub.fallbackAdd": "Ajouter un modèle de secours…", + "sub.fallbackPoll": "Intervalle de vérification de disponibilité", + "sub.fallbackSaved": "Paramètres de secours des sous-agents enregistrés.", + "sub.fallbackSaveFailed": "Échec de l’enregistrement des paramètres de secours", + "sub.fallbackUnavailable": "Absent du catalogue actuel ; conservé dans la chaîne.", + "sub.fallbackPollInvalid": "Saisissez un entier de 5000 à 600000 ms.", + "sub.v2Compatibility.title": "Compatibilité V2 du parent natif", + "sub.v2Compatibility.risk": "Si un parent ChatGPT natif délègue à ce modèle routé via V2, la tâche peut être chiffrée et échouer avant son exécution. Les tâches lisibles des parents routés ne sont pas affectées.", + "sub.v2Compatibility.recoveryUnknown": "Ce serveur ne fournit pas l’activation ni l’éligibilité de la récupération. Utilisez V1/texte clair, ou activez la récupération V2 expérimentale uniquement si éligible. Elle ajoute quota, latence, dépendance au backend et risque de perte de fidélité ; elle ne corrige pas le protocole amont.", + "sub.v2Compatibility.details": "Détails de compatibilité", "logs.title": "Journaux des requêtes", "logs.tabLogs": "Journaux", "logs.tabDebug": "Débogage", diff --git a/gui/src/i18n/ja.ts b/gui/src/i18n/ja.ts index 81cd40bca9..300d1f8c51 100644 --- a/gui/src/i18n/ja.ts +++ b/gui/src/i18n/ja.ts @@ -646,12 +646,6 @@ export const ja: Record = { "sub.ultraModeLoadFail": "ウルトラモード設定を読み込めませんでした — プロキシは実行中ですか?", "sub.ultraModeSaveFail": "ウルトラモード設定の保存に失敗しました", "sub.ultraModeSaved": "ウルトラモードを保存しました。新しい Codex セッションから適用されます。", - "sub.fallbackLabel": "サブエージェントのフォールバックチェーン", - "sub.fallbackHint": "サブエージェントモデルが利用できないか失敗した場合に順番に試すモデルです。", - "sub.fallbackAdd": "フォールバックモデルを追加…", - "sub.fallbackPoll": "利用可能性チェック間隔", - "sub.fallbackSaved": "サブエージェントのフォールバック設定を保存しました。", - "sub.fallbackSaveFailed": "フォールバック設定の保存に失敗しました", // logs "logs.title": "リクエストログ", @@ -2435,6 +2429,18 @@ export const ja: Record = { "sub.sections": "サブエージェントのセクション", "sub.delegation.model": "最初に呼ぶモデル", "sub.delegation.modelHint": "Codex が作業を任せるとき、最初に呼ぶモデルです。上のおすすめが呼べる候補で、ここで選んだものがその中の第一候補になります。", + "sub.fallbackLabel": "サブエージェントのフォールバックチェーン", + "sub.fallbackHint": "サブエージェントモデルが利用できないか失敗した場合に順番に試すモデルです。", + "sub.fallbackAdd": "フォールバックモデルを追加…", + "sub.fallbackPoll": "利用可能性チェック間隔", + "sub.fallbackSaved": "サブエージェントのフォールバック設定を保存しました。", + "sub.fallbackSaveFailed": "フォールバック設定の保存に失敗しました", + "sub.fallbackUnavailable": "現在の一覧にはありませんが、チェーンに保持されます。", + "sub.fallbackPollInvalid": "5000〜600000 ms の整数を入力してください。", + "sub.v2Compatibility.title": "ネイティブ親の V2 互換性", + "sub.v2Compatibility.risk": "ネイティブ ChatGPT 親が V2 でこのルーティングモデルに委任すると、タスクが暗号化され実行前に失敗する場合があります。ルーティング親からの読み取り可能なタスクは影響を受けません。", + "sub.v2Compatibility.recoveryUnknown": "このサーバーは復旧の有効状態や適格性を公開していません。V1・平文互換の委任を使うか、適格な場合のみ実験的 V2 復旧を有効にしてください。復旧にはクォータ、遅延、バックエンド依存、忠実度低下の可能性があり、上流プロトコルは修正されません。", + "sub.v2Compatibility.details": "互換性の詳細", "dash.syncModelsHint": "接続済みのプロバイダーをもとに Codex のモデルカタログを書き直します。", "dash.syncRun": "今すぐ同期", "lab.title": "Compatibility Lab", diff --git a/gui/src/i18n/ko.ts b/gui/src/i18n/ko.ts index 35a726e6ba..42c000c6bb 100644 --- a/gui/src/i18n/ko.ts +++ b/gui/src/i18n/ko.ts @@ -709,6 +709,12 @@ export const ko: Record = { "sub.fallbackPoll": "가용성 확인 간격", "sub.fallbackSaved": "서브에이전트 폴백 설정을 저장했습니다.", "sub.fallbackSaveFailed": "폴백 설정을 저장하지 못했습니다", + "sub.fallbackUnavailable": "현재 목록에 없지만 체인에 유지됩니다.", + "sub.fallbackPollInvalid": "5000~600000ms 범위의 정수를 입력하세요.", + "sub.v2Compatibility.title": "네이티브 부모의 V2 호환성", + "sub.v2Compatibility.risk": "네이티브 ChatGPT 부모가 V2로 이 라우팅 모델에 위임하면 작업이 암호화되어 실행 전에 실패할 수 있습니다. 라우팅 부모가 보내는 읽을 수 있는 작업에는 영향이 없습니다.", + "sub.v2Compatibility.recoveryUnknown": "이 서버는 복구 활성화 여부와 사용 가능 상태를 제공하지 않습니다. V1·평문 호환 위임을 사용하거나, 조건을 충족할 때만 실험적 V2 복구를 켜세요. 복구에는 할당량·지연·백엔드 의존성과 원문 충실도 손실 가능성이 따르며, 업스트림 프로토콜을 고치지는 않습니다.", + "sub.v2Compatibility.details": "호환성 자세히 보기", // logs "logs.title": "요청 로그", diff --git a/gui/src/i18n/ru.ts b/gui/src/i18n/ru.ts index a7cc5f72e8..51fcaef210 100644 --- a/gui/src/i18n/ru.ts +++ b/gui/src/i18n/ru.ts @@ -701,12 +701,6 @@ export const ru: Record = { "sub.ultraModeLoadFail": "Не удалось загрузить настройки ультра-режима — работает ли прокси?", "sub.ultraModeSaveFail": "Не удалось сохранить настройки ультра-режима", "sub.ultraModeSaved": "Ультра-режим сохранён. Применяется к новым сеансам Codex.", - "sub.fallbackLabel": "Цепочка резервных моделей субагента", - "sub.fallbackHint": "Модели, которые последовательно пробуются, если модель субагента недоступна или завершается ошибкой.", - "sub.fallbackAdd": "Добавить резервную модель…", - "sub.fallbackPoll": "Интервал проверки доступности", - "sub.fallbackSaved": "Настройки резервных моделей субагента сохранены.", - "sub.fallbackSaveFailed": "Не удалось сохранить настройки резервных моделей", // logs "logs.title": "Журнал запросов", @@ -2437,6 +2431,18 @@ export const ru: Record = { "sub.sections": "Разделы подагентов", "sub.delegation.model": "Модель, которую вызывать первой", "sub.delegation.modelHint": "Модель, к которой Codex обращается первой, когда передаёт работу. Список выше — кого он вообще может вызвать, а здесь выбирается первый в очереди.", + "sub.fallbackLabel": "Цепочка резервных моделей субагента", + "sub.fallbackHint": "Модели, которые последовательно пробуются, если модель субагента недоступна или завершается ошибкой.", + "sub.fallbackAdd": "Добавить резервную модель…", + "sub.fallbackPoll": "Интервал проверки доступности", + "sub.fallbackSaved": "Настройки резервных моделей субагента сохранены.", + "sub.fallbackSaveFailed": "Не удалось сохранить настройки резервных моделей", + "sub.fallbackUnavailable": "Сейчас отсутствует в каталоге; сохранена в цепочке.", + "sub.fallbackPollInvalid": "Введите целое число от 5000 до 600000 мс.", + "sub.v2Compatibility.title": "Совместимость V2 с нативным родителем", + "sub.v2Compatibility.risk": "Если нативный родитель ChatGPT делегирует этой маршрутизируемой модели через V2, задача может быть зашифрована и завершиться ошибкой до выполнения. Читаемые задачи маршрутизируемых родителей не затрагиваются.", + "sub.v2Compatibility.recoveryUnknown": "Сервер не сообщает, включено ли восстановление и доступно ли оно. Используйте V1/открытый текст или включите экспериментальное восстановление V2 только при соответствии условиям. Оно расходует квоту, увеличивает задержку, зависит от бэкенда и может снизить точность; исходный протокол не исправляется.", + "sub.v2Compatibility.details": "Подробнее о совместимости", "dash.syncModelsHint": "Перезаписывает каталог моделей Codex по подключённым провайдерам.", "dash.syncRun": "Синхронизировать", "lab.title": "Compatibility Lab", diff --git a/gui/src/i18n/tr.ts b/gui/src/i18n/tr.ts index 5c0ade9077..c764bf11ca 100644 --- a/gui/src/i18n/tr.ts +++ b/gui/src/i18n/tr.ts @@ -714,6 +714,12 @@ export const tr: Record = { "sub.fallbackPoll": "Kullanılabilirlik kontrol aralığı", "sub.fallbackSaved": "Alt ajan yedek ayarları kaydedildi.", "sub.fallbackSaveFailed": "Yedek ayarlar kaydedilemedi", + "sub.fallbackUnavailable": "Şu anda listelenmiyor; zincirde korunur.", + "sub.fallbackPollInvalid": "5000–600000 ms arasında bir tam sayı girin.", + "sub.v2Compatibility.title": "Yerel üst ajanın V2 uyumluluğu", + "sub.v2Compatibility.risk": "Yerel ChatGPT üst ajanı V2 ile bu yönlendirilmiş modele görev verirse görev şifrelenmiş olabilir ve yürütülmeden başarısız olabilir. Yönlendirilmiş üst ajanların okunabilir görevleri etkilenmez.", + "sub.v2Compatibility.recoveryUnknown": "Bu sunucu kurtarmanın etkinliğini veya uygunluğunu bildirmez. V1/düz metin kullanın ya da deneysel V2 kurtarmayı yalnızca uygunsa açın. Kurtarma kota, gecikme, arka uç bağımlılığı ve aslına uygunluk kaybı getirebilir; üst sistem protokolünü düzeltmez.", + "sub.v2Compatibility.details": "Uyumluluk ayrıntıları", // logs "logs.title": "İstek Günlükleri", diff --git a/gui/src/i18n/zh-TW.ts b/gui/src/i18n/zh-TW.ts index cae0175057..ab6aedd67a 100644 --- a/gui/src/i18n/zh-TW.ts +++ b/gui/src/i18n/zh-TW.ts @@ -555,12 +555,6 @@ export const zhTW: Record = { "sub.ultraModeLoadFail": "無法載入超級模式設定 — 代理是否在執行?", "sub.ultraModeSaveFail": "儲存超級模式設定失敗", "sub.ultraModeSaved": "超級模式已儲存。適用於新的 Codex 會話。", - "sub.fallbackLabel": "子代理備援鏈", - "sub.fallbackHint": "子代理模型無法使用或失敗時,依序嘗試的模型。", - "sub.fallbackAdd": "新增備援模型…", - "sub.fallbackPoll": "可用性檢查間隔", - "sub.fallbackSaved": "子代理備援設定已儲存。", - "sub.fallbackSaveFailed": "備援設定儲存失敗", "logs.title": "請求日誌", "logs.tabLogs": "日誌", "logs.tabDebug": "除錯", @@ -1972,6 +1966,18 @@ export const zhTW: Record = { "sub.sections": "子代理分區", "sub.delegation.model": "優先調用的模型", "sub.delegation.modelHint": "Codex 分派工作時最先調用的模型。上面的推薦是可調用的名單,這裡選的是其中第一順位。", + "sub.fallbackLabel": "子代理備援鏈", + "sub.fallbackHint": "子代理模型無法使用或失敗時,依序嘗試的模型。", + "sub.fallbackAdd": "新增備援模型…", + "sub.fallbackPoll": "可用性檢查間隔", + "sub.fallbackSaved": "子代理備援設定已儲存。", + "sub.fallbackSaveFailed": "備援設定儲存失敗", + "sub.fallbackUnavailable": "目前未列出,仍保留在回退鏈中。", + "sub.fallbackPollInvalid": "請輸入 5000 到 600000 ms 之間的整數。", + "sub.v2Compatibility.title": "原生父代理的 V2 相容性", + "sub.v2Compatibility.risk": "原生 ChatGPT 父代理透過 V2 委派給此路由模型時,任務可能被加密並在執行前失敗。路由父代理傳送的可讀任務不受影響。", + "sub.v2Compatibility.recoveryUnknown": "此伺服器未提供復原功能的啟用或適用狀態。請使用 V1/明文相容委派,或僅在符合條件時啟用實驗性 V2 復原。復原會增加配額消耗、延遲、後端依賴及保真度損失風險,並不修復上游協定。", + "sub.v2Compatibility.details": "相容性詳情", "debug.loadFailed": "無法載入偵錯設定。", "provider.name.volcengine": "Volcengine Ark", "provider.name.volcengineCodingPlan": "Volcengine Ark Coding Plan", diff --git a/gui/src/i18n/zh.ts b/gui/src/i18n/zh.ts index ce44edc693..052f449855 100644 --- a/gui/src/i18n/zh.ts +++ b/gui/src/i18n/zh.ts @@ -696,12 +696,6 @@ export const zh: Record = { "sub.ultraModeLoadFail": "无法加载超级模式设置 — 代理是否在运行?", "sub.ultraModeSaveFail": "保存超级模式设置失败", "sub.ultraModeSaved": "超级模式已保存。适用于新的 Codex 会话。", - "sub.fallbackLabel": "子代理回退链", - "sub.fallbackHint": "子代理模型不可用或失败时按顺序尝试的模型。", - "sub.fallbackAdd": "添加回退模型…", - "sub.fallbackPoll": "可用性检查间隔", - "sub.fallbackSaved": "子代理回退设置已保存。", - "sub.fallbackSaveFailed": "保存回退设置失败", // logs "logs.title": "请求日志", @@ -2435,6 +2429,18 @@ export const zh: Record = { "sub.sections": "子代理分区", "sub.delegation.model": "优先调用的模型", "sub.delegation.modelHint": "Codex 分派工作时最先调用的模型。上面的推荐是可调用的名单,这里选的是其中第一顺位。", + "sub.fallbackLabel": "子代理回退链", + "sub.fallbackHint": "子代理模型不可用或失败时按顺序尝试的模型。", + "sub.fallbackAdd": "添加回退模型…", + "sub.fallbackPoll": "可用性检查间隔", + "sub.fallbackSaved": "子代理回退设置已保存。", + "sub.fallbackSaveFailed": "保存回退设置失败", + "sub.fallbackUnavailable": "当前未列出,仍保留在回退链中。", + "sub.fallbackPollInvalid": "请输入 5000 到 600000 ms 之间的整数。", + "sub.v2Compatibility.title": "原生父代理的 V2 兼容性", + "sub.v2Compatibility.risk": "原生 ChatGPT 父代理通过 V2 委派给此路由模型时,任务可能被加密并在执行前失败。路由父代理发送的可读任务不受影响。", + "sub.v2Compatibility.recoveryUnknown": "此服务器未提供恢复功能的启用或适用状态。请使用 V1/明文兼容委派,或仅在符合条件时启用实验性 V2 恢复。恢复会增加配额消耗、延迟、后端依赖及保真度损失风险,并不修复上游协议。", + "sub.v2Compatibility.details": "兼容性详情", "dash.syncModelsHint": "按已连接的提供商重写 Codex 的模型目录。", "dash.syncRun": "立即同步", "lab.title": "Compatibility Lab", diff --git a/gui/src/pages/Subagents.tsx b/gui/src/pages/Subagents.tsx index 299c9306fe..cbdb138e33 100644 --- a/gui/src/pages/Subagents.tsx +++ b/gui/src/pages/Subagents.tsx @@ -22,6 +22,8 @@ export default function Subagents({ apiBase }: { apiBase: string }) { const [fallback, setFallback] = useState(() => cached?.fallback ?? []); const [fallbackPollMs, setFallbackPollMs] = useState(() => cached?.pollMs ?? 60000); const [fallbackBusy, setFallbackBusy] = useState(false); + const fallbackSaveInFlight = useRef(false); + const committed = useRef(cached); const [status, setStatus] = useState(""); const [ok, setOk] = useState(false); const [busy, setBusy] = useState(false); @@ -49,12 +51,15 @@ export default function Subagents({ apiBase }: { apiBase: string }) { enabled?: boolean; multiAgentMode?: "v1" | "default" | "v2"; multiAgentModeHintText?: string | null; + keepNativeChatGptOnV1?: boolean; }>(res, t("sub.ultraModeLoadFail")); if (!data) return false; if (signal?.aborted || generation !== ultraLoadGeneration.current || currentUltraApiBase.current !== apiBase) return false; setUltraLoadFailed(false); setUltraMode({ enabled: data.enabled ?? false, + loaded: true, + keepNativeChatGptOnV1: data.keepNativeChatGptOnV1 === true, hintText: data.multiAgentModeHintText ?? null, // Ultra mode replaces Codex's effort-derived policy for every model. The // `default` surface still preserves upstream V1 pins (for example luna), @@ -132,9 +137,12 @@ export default function Subagents({ apiBase }: { apiBase: string }) { const next = { available, chosen: (response.chosen ?? []).filter(model => availableSet.has(model)), - fallback: (fallbackResponse.models ?? []).filter(model => availableSet.has(model)), + // Configured targets remain editable even when discovery no longer advertises them. + fallback: fallbackResponse.models ?? [], pollMs: fallbackResponse.pollMs ?? 60000, }; + if (signal?.aborted) throw signal.reason; + committed.current = next; setChosen(next.chosen); setFallback(next.fallback); setFallbackPollMs(next.pollMs); @@ -185,7 +193,9 @@ export default function Subagents({ apiBase }: { apiBase: string }) { const d = await readJsonOrThrow<{ applied?: string[] }>(r, t("sub.saveFailed")); const applied = d?.applied ?? chosen; if (d?.applied) setChosen(d.applied); - writeSessionListCache(cacheKey, { available, chosen: applied, fallback, pollMs: fallbackPollMs }); + const next = { available, chosen: applied, fallback: committed.current?.fallback ?? [], pollMs: committed.current?.pollMs ?? 60000 }; + committed.current = next; + writeSessionListCache(cacheKey, next); setOk(true); setStatus(t("sub.saved", { n: applied.length, cmd: "ocx sync" })); } catch (error) { @@ -198,8 +208,11 @@ export default function Subagents({ apiBase }: { apiBase: string }) { }; const saveFallback = async () => { - if (fallbackBusy) return; + if (fallbackSaveInFlight.current || !Number.isInteger(fallbackPollMs) || fallbackPollMs < 5000 || fallbackPollMs > 600000) return; + fallbackSaveInFlight.current = true; + const requestApiBase = apiBase; setFallbackBusy(true); + setStatus(""); try { const r = await fetch(`${apiBase}/api/subagent-model-fallback`, { method: "PUT", @@ -207,14 +220,20 @@ export default function Subagents({ apiBase }: { apiBase: string }) { body: JSON.stringify({ models: fallback, pollMs: fallbackPollMs }), }); const d = await readJsonOrThrow<{ models?: string[]; pollMs?: number }>(r, t("sub.fallbackSaveFailed")); - if (d?.models) setFallback(d.models); - if (d?.pollMs) setFallbackPollMs(d.pollMs); + if (currentUltraApiBase.current !== requestApiBase) return; + if (!d || !Array.isArray(d.models) || typeof d.pollMs !== "number") throw new Error(t("sub.fallbackSaveFailed")); + setFallback(d.models); + setFallbackPollMs(d.pollMs); + const next = { available, chosen: committed.current?.chosen ?? [], fallback: d.models, pollMs: d.pollMs }; + committed.current = next; + writeSessionListCache(cacheKey, next); setOk(true); setStatus(t("sub.fallbackSaved")); } catch (error) { setOk(false); setStatus(error instanceof Error && error.message ? error.message : t("sub.networkError")); } finally { + fallbackSaveInFlight.current = false; setFallbackBusy(false); } }; diff --git a/gui/src/pages/use-subagent-delegation.ts b/gui/src/pages/use-subagent-delegation.ts index 716eb11482..9baa5baa9a 100644 --- a/gui/src/pages/use-subagent-delegation.ts +++ b/gui/src/pages/use-subagent-delegation.ts @@ -21,6 +21,8 @@ export type DelegationPatch = { /** Ultra mode (Proactive delegation for every model/effort) via /api/v2. */ export type UltraModeState = { + loaded?: boolean; + keepNativeChatGptOnV1?: boolean; enabled: boolean; hintText: string | null; multiAgentV2Enabled: boolean; diff --git a/gui/src/styles-subagents-workspace.css b/gui/src/styles-subagents-workspace.css index c6292077b7..a9f9466ce7 100644 --- a/gui/src/styles-subagents-workspace.css +++ b/gui/src/styles-subagents-workspace.css @@ -575,3 +575,16 @@ } } } + + +/* Fallback targets keep their identifiers readable next to row actions. */ +.swi-fallback-controls { display: flex; flex-direction: column; align-items: stretch; gap: var(--space-2); flex: 1 1 55%; min-width: 0; } +.swi-fallback-row { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); } +.swi-fallback-model { min-width: 0; overflow-wrap: anywhere; } +.swi-fallback-model .setting-hint { display: block; } +.swi-fallback-actions { display: inline-flex; flex-shrink: 0; } +.swi-fallback-controls > .btn { align-self: flex-end; } +@media (max-width: 640px) { + .swi-fallback-editor { flex-direction: column; } + .swi-fallback-controls { width: 100%; } +} diff --git a/gui/tests/multi-agent-guidance.test.tsx b/gui/tests/multi-agent-guidance.test.tsx index 16470385b8..8907406f0e 100644 --- a/gui/tests/multi-agent-guidance.test.tsx +++ b/gui/tests/multi-agent-guidance.test.tsx @@ -65,7 +65,14 @@ function props(overrides: Partial = {}): Props { guidanceEnabled: false, syncCodexDefaults: true, onSave: (patch) => { requests.push(patch); }, - ultraMode: { enabled: false, hintText: null, multiAgentV2Enabled: false }, + ultraMode: { enabled: false, hintText: null, multiAgentV2Enabled: false, multiAgentMode: "default" }, + fallback: [], + fallbackPollMs: 60000, + fallbackBusy: false, + availableModels: [], + onFallbackChange: () => {}, + onFallbackPollMsChange: () => {}, + onFallbackSave: () => {}, ultraSaving: false, onUltraModeSave: () => {}, ultraLoadFailed: false, diff --git a/gui/tests/subagents-fallback.test.tsx b/gui/tests/subagents-fallback.test.tsx new file mode 100644 index 0000000000..20badc4980 --- /dev/null +++ b/gui/tests/subagents-fallback.test.tsx @@ -0,0 +1,422 @@ +import { afterEach, beforeEach, expect, test } from "bun:test"; +import { Window } from "happy-dom"; +import { act } from "react"; +import type { Root } from "react-dom/client"; +import { clearClientResourceStoresForTests } from "../src/client-resource"; +import { en } from "../src/i18n/en"; +import { LanguageProvider } from "../src/i18n/provider"; +import Subagents from "../src/pages/Subagents"; +import { readSessionListCache } from "../src/session-list-cache"; + +const CACHE_KEY = "ocx.subagents.v1:"; +const FALLBACK_PATH = "/api/subagent-model-fallback"; +const ROSTER_PATH = "/api/subagent-models"; +const UNAVAILABLE_MODEL = "retired-provider/configured-model"; +const globals = [ + "document", "window", "navigator", "localStorage", "sessionStorage", "fetch", "IS_REACT_ACT_ENVIRONMENT", +] as const; + +type CachedSubagents = { available: string[]; chosen: string[]; fallback: string[]; pollMs: number }; +type FallbackSettings = { models: string[]; pollMs: number }; +type SentRequest = { path: string; method: string; init?: RequestInit }; +type V2Settings = { + enabled: boolean; + multiAgentMode: "v1" | "default" | "v2"; + multiAgentModeHintText: string | null; + keepNativeChatGptOnV1: boolean; +}; + +let previousGlobals: Record<(typeof globals)[number], PropertyDescriptor | undefined>; +let testWindow: Window; +let container: HTMLElement; +let root: Root | null = null; +let requests: SentRequest[]; +let available: string[]; +let chosen: string[]; +let fallbackSettings: FallbackSettings; +let failFallbackPut: boolean; +let v2Settings: V2Settings; +let preferredModel: string | null; +let fallbackGetGate: Promise | null; + +beforeEach(() => { + clearClientResourceStoresForTests(); + previousGlobals = Object.fromEntries(globals.map(key => [key, Object.getOwnPropertyDescriptor(globalThis, key)])) as typeof previousGlobals; + testWindow = new Window({ url: "http://localhost/" }); + Object.defineProperty(testWindow.navigator, "language", { configurable: true, value: "en-US" }); + Object.defineProperties(globalThis, { + document: { configurable: true, value: testWindow.document }, + window: { configurable: true, value: testWindow }, + navigator: { configurable: true, value: testWindow.navigator }, + localStorage: { configurable: true, value: testWindow.localStorage }, + sessionStorage: { configurable: true, value: testWindow.sessionStorage }, + IS_REACT_ACT_ENVIRONMENT: { configurable: true, value: true }, + }); + + requests = []; + available = ["a-1", "a-2", "a-3"]; + chosen = ["a-1"]; + fallbackSettings = { models: ["a-2"], pollMs: 45_000 }; + failFallbackPut = false; + v2Settings = { enabled: true, multiAgentMode: "v2", multiAgentModeHintText: null, keepNativeChatGptOnV1: false }; + preferredModel = null; + fallbackGetGate = null; + Object.defineProperty(globalThis, "fetch", { + configurable: true, + value: async (input: RequestInfo | URL, init?: RequestInit) => { + const path = new URL(String(input), "http://localhost/").pathname; + const method = init?.method ?? "GET"; + requests.push({ path, method, init }); + // Match agent-settings-routes: fallback uses models, roster uses chosen/applied. + if (path === FALLBACK_PATH && method === "GET") { + if (fallbackGetGate) await fallbackGetGate; + return Response.json({ ...fallbackSettings, available }); + } + if (path === FALLBACK_PATH && method === "PUT") { + if (failFallbackPut) return Response.json({ error: "Fallback settings could not be persisted" }, { status: 500 }); + fallbackSettings = JSON.parse(String(init?.body)) as FallbackSettings; + return Response.json({ ok: true, ...fallbackSettings }); + } + if (path === ROSTER_PATH && method === "GET") return Response.json({ available, chosen }); + if (path === ROSTER_PATH && method === "PUT") { + chosen = (JSON.parse(String(init?.body)) as { models: string[] }).models; + return Response.json({ applied: chosen }); + } + if (path === "/api/v2" && method === "GET") { + return Response.json(v2Settings); + } + if (path === "/api/injection-model" && method === "GET") { + return Response.json({ + model: preferredModel, + effort: null, + available: [ + { provider: "openai", model: "gpt-5.4", namespaced: "gpt-5.4" }, + { provider: "anthropic", model: "claude-sonnet-4-6", namespaced: "anthropic/claude-sonnet-4-6" }, + ], + efforts: [], + }); + } + throw new Error(`Unexpected request: ${method} ${path}`); + }, + }); + container = testWindow.document.createElement("div") as unknown as HTMLElement; + testWindow.document.body.appendChild(container); +}); + +afterEach(async () => { + try { + if (root) { + const current = root; + await act(async () => { current.unmount(); }); + root = null; + } + } finally { + clearClientResourceStoresForTests(); + testWindow.close(); + for (const key of globals) { + const descriptor = previousGlobals[key]; + if (descriptor) Object.defineProperty(globalThis, key, descriptor); + else Reflect.deleteProperty(globalThis, key); + } + } +}); + +async function mount() { + // Match sibling input tests: initialize ReactDOM's event support after installing the DOM. + const { createRoot } = await import("react-dom/client"); + await act(async () => { + root = createRoot(container); + root.render(); + }); + expect(requests.some(request => request.path === FALLBACK_PATH && request.method === "GET")).toBe(true); + expect(editor()).toBeTruthy(); +} + +function editor(): HTMLElement { + const element = container.querySelector(".swi-fallback-editor"); + if (!element) throw new Error("Fallback editor not found"); + return element; +} + +function rows(): HTMLElement[] { + return Array.from(editor().querySelectorAll(".swi-fallback-row")); +} + +function expectOrder(models: string[]) { + expect(rows()).toHaveLength(models.length); + models.forEach((model, index) => { + // The model span can also contain the unavailable-model warning. + expect(rows()[index]?.querySelector("span")?.textContent?.trim().startsWith(`${index + 1}. ${model}`)).toBe(true); + expect(rowButton(index, "sub.removeAria", model)).toBeTruthy(); + }); +} + +function labelledButton(scope: ParentNode, label: string): HTMLButtonElement { + const button = Array.from(scope.querySelectorAll("button")) + .find(candidate => candidate.getAttribute("aria-label") === label); + if (!button) throw new Error(`Button not found: ${label}`); + return button; +} + +function rowButton(index: number, key: "sub.moveUp" | "sub.moveDown" | "sub.removeAria", model: string) { + const row = rows()[index]; + if (!row) throw new Error(`Fallback row not found: ${index}`); + return labelledButton(row, en[key].replace("{m}", model)); +} + +function saveButton(scope: ParentNode = editor()): HTMLButtonElement { + const button = Array.from(scope.querySelectorAll("button")) + .find(candidate => candidate.textContent?.trim() === en["common.save"]); + if (!button) throw new Error("Save button not found"); + return button; +} + +async function click(button: HTMLButtonElement) { + expect(button.disabled).toBe(false); + await act(async () => { button.click(); }); +} + +async function addFallback(model: string) { + const trigger = labelledButton(editor(), en["sub.fallbackAdd"]); + expect(trigger.getAttribute("role")).toBe("combobox"); + await click(trigger); + // Select portals its listbox into document.body, outside the page container. + const listbox = testWindow.document.getElementById(trigger.getAttribute("aria-controls") ?? ""); + if (!listbox) throw new Error("Fallback model listbox not found"); + const option = Array.from(listbox.querySelectorAll('[role="option"]')) + .find(candidate => candidate.textContent?.trim() === model); + if (!option) throw new Error(`Fallback option not found: ${model}`); + await click(option as unknown as HTMLButtonElement); + expect(trigger.getAttribute("aria-expanded")).toBe("false"); +} + +function pollInput(): HTMLInputElement { + const input = editor().querySelector('input[type="number"]'); + if (!input) throw new Error("Fallback polling interval input not found"); + return input; +} + +async function changePollMs(value: number) { + await act(async () => { + const input = pollInput(); + Object.getOwnPropertyDescriptor(testWindow.HTMLInputElement.prototype, "value")!.set!.call(input, String(value)); + input.dispatchEvent(new testWindow.Event("input", { bubbles: true })); + input.dispatchEvent(new testWindow.Event("change", { bubbles: true })); + }); +} + +function putBodies(path = FALLBACK_PATH): unknown[] { + return requests.filter(request => request.path === path && request.method === "PUT") + .map(request => JSON.parse(String(request.init?.body)) as unknown); +} + +function cached(): CachedSubagents | null { + return readSessionListCache(CACHE_KEY); +} + +test("preserves an unavailable configured fallback ID on load and save", async () => { + fallbackSettings = { models: [UNAVAILABLE_MODEL, "a-2"], pollMs: 45_000 }; + expect(available).not.toContain(UNAVAILABLE_MODEL); + await mount(); + + expectOrder([UNAVAILABLE_MODEL, "a-2"]); + expect(rows()[0]?.textContent).toContain(en["sub.fallbackUnavailable"]); + expect(rows()[1]?.textContent).not.toContain(en["sub.fallbackUnavailable"]); + expect(cached()?.fallback).toEqual([UNAVAILABLE_MODEL, "a-2"]); + await click(saveButton()); + expect(putBodies()).toEqual([{ models: [UNAVAILABLE_MODEL, "a-2"], pollMs: 45_000 }]); + expectOrder([UNAVAILABLE_MODEL, "a-2"]); + expect(container.textContent).toContain(en["sub.fallbackSaved"]); +}); + +test("adds, reorders in both directions, and removes fallback models before saving their exact order", async () => { + await mount(); + await addFallback("a-3"); + expectOrder(["a-2", "a-3"]); + expect(rowButton(0, "sub.moveUp", "a-2").disabled).toBe(true); + expect(rowButton(1, "sub.moveDown", "a-3").disabled).toBe(true); + + await click(rowButton(1, "sub.moveUp", "a-3")); + expectOrder(["a-3", "a-2"]); + await click(rowButton(0, "sub.moveDown", "a-3")); + expectOrder(["a-2", "a-3"]); + await addFallback("a-1"); + await click(rowButton(0, "sub.removeAria", "a-2")); + expectOrder(["a-3", "a-1"]); + expect(putBodies()).toEqual([]); + + await click(saveButton()); + expect(putBodies()).toEqual([{ models: ["a-3", "a-1"], pollMs: 45_000 }]); + expect(putBodies(ROSTER_PATH)).toEqual([]); +}); + +test("removes only the selected duplicate fallback occurrence by index", async () => { + fallbackSettings.models = ["a-2", "a-1", "a-2", "a-3"]; + await mount(); + expectOrder(["a-2", "a-1", "a-2", "a-3"]); + + await click(rowButton(2, "sub.removeAria", "a-2")); + expectOrder(["a-2", "a-1", "a-3"]); + await click(saveButton()); + expect(putBodies()).toEqual([{ models: ["a-2", "a-1", "a-3"], pollMs: 45_000 }]); +}); + +test("a failed fallback PUT retains the editable draft and leaves the committed cache unchanged", async () => { + await mount(); + const committed = cached(); + expect(committed).toEqual({ available, chosen: ["a-1"], fallback: ["a-2"], pollMs: 45_000 }); + await addFallback("a-3"); + await changePollMs(90_000); + failFallbackPut = true; + await click(saveButton()); + + expect(putBodies()).toEqual([{ models: ["a-2", "a-3"], pollMs: 90_000 }]); + expectOrder(["a-2", "a-3"]); + expect(pollInput().value).toBe("90000"); + expect(container.textContent).toContain("Fallback settings could not be persisted"); + expect(container.textContent).not.toContain(en["sub.fallbackSaved"]); + expect(saveButton().disabled).toBe(false); + expect(cached()).toEqual(committed); + + failFallbackPut = false; + await click(saveButton()); + expect(putBodies()).toEqual([ + { models: ["a-2", "a-3"], pollMs: 90_000 }, + { models: ["a-2", "a-3"], pollMs: 90_000 }, + ]); + expect(cached()?.fallback).toEqual(["a-2", "a-3"]); + expect(cached()?.pollMs).toBe(90_000); +}); + +test("a successful fallback save updates committed session data without committing a roster draft", async () => { + await mount(); + await click(labelledButton(container, en["sub.workspace.addToFeatured"].replace("{m}", "a-3"))); + await addFallback("a-3"); + await changePollMs(120_000); + await click(saveButton()); + + expect(putBodies()).toEqual([{ models: ["a-2", "a-3"], pollMs: 120_000 }]); + expect(putBodies(ROSTER_PATH)).toEqual([]); + expect(cached()).toEqual({ available, chosen: ["a-1"], fallback: ["a-2", "a-3"], pollMs: 120_000 }); + expectOrder(["a-2", "a-3"]); + expect(container.querySelectorAll(".swi-featured-row").length).toBe(2); +}); + +test("independent roster Save never caches an unsaved fallback draft", async () => { + await mount(); + await addFallback("a-3"); + await changePollMs(90_000); + await click(labelledButton(container, en["sub.workspace.addToFeatured"].replace("{m}", "a-3"))); + const rosterSaveRow = container.querySelector(".swi-save-row"); + if (!rosterSaveRow) throw new Error("Roster Save row not found"); + await click(saveButton(rosterSaveRow)); + + expect(putBodies(ROSTER_PATH)).toEqual([{ models: ["a-1", "a-3"] }]); + expect(putBodies()).toEqual([]); + expect(cached()).toEqual({ available, chosen: ["a-1", "a-3"], fallback: ["a-2"], pollMs: 45_000 }); + expectOrder(["a-2", "a-3"]); + expect(pollInput().value).toBe("90000"); + + // Saving the fallback afterward must retain the already committed roster. + await click(saveButton()); + expect(putBodies()).toEqual([{ models: ["a-2", "a-3"], pollMs: 90_000 }]); + expect(cached()).toEqual({ available, chosen: ["a-1", "a-3"], fallback: ["a-2", "a-3"], pollMs: 90_000 }); +}); + +test("remount shows the committed fallback and roster while a fresh fallback GET is pending", async () => { + await mount(); + await addFallback("a-3"); + await changePollMs(120_000); + await click(saveButton()); + + // A later roster save must not commit these newer fallback edits. + await click(rowButton(0, "sub.removeAria", "a-2")); + await changePollMs(90_000); + await click(labelledButton(container, en["sub.workspace.addToFeatured"].replace("{m}", "a-3"))); + const rosterSaveRow = container.querySelector(".swi-save-row"); + if (!rosterSaveRow) throw new Error("Roster Save row not found"); + await click(saveButton(rosterSaveRow)); + expectOrder(["a-3"]); + expect(pollInput().value).toBe("90000"); + + const current = root!; + await act(async () => { current.unmount(); }); + root = null; + // Keep sessionStorage, but discard the resource store so it cannot mask a stale session seed. + clearClientResourceStoresForTests(); + const getsBefore = requests.filter(request => request.path === FALLBACK_PATH && request.method === "GET").length; + let releaseGet!: () => void; + fallbackGetGate = new Promise(resolve => { releaseGet = resolve; }); + try { + await mount(); + expect(requests.filter(request => request.path === FALLBACK_PATH && request.method === "GET")).toHaveLength(getsBefore + 1); + // These assertions run before the fresh GET can return any data. + expectOrder(["a-2", "a-3"]); + expect(pollInput().value).toBe("120000"); + expect(Array.from(container.querySelectorAll(".swi-featured-name"), node => node.textContent?.trim())) + .toEqual(["a-1", "a-3"]); + expect(cached()).toEqual({ available, chosen: ["a-1", "a-3"], fallback: ["a-2", "a-3"], pollMs: 120_000 }); + } finally { + await act(async () => { releaseGet(); }); + fallbackGetGate = null; + } + expectOrder(["a-2", "a-3"]); + expect(pollInput().value).toBe("120000"); +}); + +test("invalid polling intervals disable Save without a PUT or cache mutation, and a valid interval recovers", async () => { + await mount(); + const committed = cached(); + for (const interval of [0, 4_999, 600_001, 5_000.5]) { + await changePollMs(interval); + expect(pollInput().getAttribute("aria-invalid")).toBe("true"); + expect(editor().querySelector('[role="alert"]')?.textContent).toContain(en["sub.fallbackPollInvalid"]); + expect(saveButton().disabled).toBe(true); + await act(async () => { saveButton().click(); }); + expect(putBodies()).toEqual([]); + expect(cached()).toEqual(committed); + } + + await changePollMs(5_000); + expect(pollInput().getAttribute("aria-invalid")).toBe("false"); + expect(editor().querySelector('[role="alert"]')).toBeNull(); + await click(saveButton()); + expect(putBodies()).toEqual([{ models: ["a-2"], pollMs: 5_000 }]); + expect(cached()?.pollMs).toBe(5_000); +}); + +const compatibilityCases: Array<{ + name: string; + model: string; + enabled: boolean; + mode: V2Settings["multiAgentMode"]; + keepNative: boolean; + warning: boolean; +}> = [ + { name: "native preferred model", model: "gpt-5.4", enabled: true, mode: "v2", keepNative: false, warning: false }, + { name: "routed preferred model on the default surface", model: "anthropic/claude-sonnet-4-6", enabled: false, mode: "default", keepNative: false, warning: true }, + { name: "routed preferred model on V1", model: "anthropic/claude-sonnet-4-6", enabled: false, mode: "v1", keepNative: false, warning: false }, + { name: "forced V2 preserving native V1 with global V2 disabled", model: "anthropic/claude-sonnet-4-6", enabled: false, mode: "v2", keepNative: true, warning: false }, + { name: "global V2 enabled despite native V1 preservation", model: "anthropic/claude-sonnet-4-6", enabled: true, mode: "v2", keepNative: true, warning: true }, +]; + +test.each(compatibilityCases)("V2 compatibility guidance: $name", async ({ model, enabled, mode, keepNative, warning }) => { + preferredModel = model; + v2Settings = { enabled, multiAgentMode: mode, multiAgentModeHintText: null, keepNativeChatGptOnV1: keepNative }; + await mount(); + + const note = container.querySelector('.swi-v2-compatibility[role="note"]'); + if (warning) { + expect(note).toBeTruthy(); + expect(note?.textContent).toContain(en["sub.v2Compatibility.title"]); + expect(note?.textContent).toContain(en["sub.v2Compatibility.risk"]); + // The response exposes no recovery state: guidance must explicitly say it is unknown. + expect(note?.textContent).toContain(en["sub.v2Compatibility.recoveryUnknown"]); + expect(note?.querySelector("a")?.getAttribute("href")).toBe("https://github.com/lidge-jun/opencodex/issues/92"); + expect(note?.querySelector('[role="switch"], [aria-pressed], input[type="checkbox"]')).toBeNull(); + } else { + expect(note).toBeNull(); + expect(container.textContent).not.toContain(en["sub.v2Compatibility.recoveryUnknown"]); + } + expect(requests.filter(request => request.method !== "GET")).toEqual([]); +}); From 71315281bdbb3131104911508d1cce0f70a8e7d3 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 18:23:15 +0900 Subject: [PATCH 114/412] docs: pin lane C health wiring handoff [skip ci] --- devlog/_plan/260907_lane_c/030_health.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/devlog/_plan/260907_lane_c/030_health.md b/devlog/_plan/260907_lane_c/030_health.md index 2e01551e34..eaeb4bbcd6 100644 --- a/devlog/_plan/260907_lane_c/030_health.md +++ b/devlog/_plan/260907_lane_c/030_health.md @@ -117,3 +117,7 @@ index 639f1b34c..48bb7b539 100644 ``` + +## Main-owned route handoff + +At current dev, settings GET uses `startupHealth: await readStartupHealth(config)` at `src/server/management/config-routes.ts:332`. M changes only this settings read to the exported immediate snapshot and retains the dedicated `/api/startup-health` bounded read. Settings PUT at line 625 is separately present; it must remain reviewed explicitly rather than blindly replaced. C does not modify either call site. From 2b158e9bada538a6f3779ae47154ba150554218b Mon Sep 17 00:00:00 2001 From: luvs01 <27862058+luvs01@users.noreply.github.com> Date: Mon, 7 Sep 2026 10:50:46 +0900 Subject: [PATCH 115/412] fix(vision): bound the Anthropic vision sidecar SSE and error bodies [skip ci] (cherry picked from commit 55b009bdec123a79924a9c40c97f94bf49e62591) Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com> --- src/vision/anthropic-describe.ts | 48 +++++++++++++++++++++++++-- tests/vision/vision-anthropic.test.ts | 21 ++++++++++++ 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/src/vision/anthropic-describe.ts b/src/vision/anthropic-describe.ts index 4f41017ef5..280096f033 100644 --- a/src/vision/anthropic-describe.ts +++ b/src/vision/anthropic-describe.ts @@ -10,6 +10,8 @@ import type { DescribeOutcome, VisionSettings } from "./describe"; const ANTHROPIC_VISION_MAX_TOKENS = 1024; const ALLOWED_IMAGE_MIME = new Set(["image/png", "image/jpeg", "image/jpg", "image/webp", "image/gif"]); const MAX_IMAGE_BYTES = 20 * 1024 * 1024; +/** Bound the sidecar SSE stream and its untrusted error body; the description is clamped downstream. */ +const MAX_SIDECAR_RESPONSE_BYTES = 64 * 1024; const DESCRIBE_INSTRUCTION = "You are a vision describer for a text-only model that cannot see the image. Describe the image " + "thoroughly and factually so that model can fully reason about it: transcribe any visible text " + @@ -43,6 +45,34 @@ function buildImageBlock(imageUrl: string): { block?: AnthropicImageBlock; error return { error: "unsupported image URL scheme (expected data: or https:)" }; } +/** Read at most `MAX_SIDECAR_RESPONSE_BYTES` of an untrusted upstream body, then stop reading. */ +async function readBoundedText(res: Response): Promise { + if (!res.body) return ""; + const reader = res.body.getReader(); + const decoder = new TextDecoder(); + let out = ""; + let seen = 0; + try { + for (;;) { + const { done, value } = await reader.read(); + if (done) break; + const remaining = MAX_SIDECAR_RESPONSE_BYTES - seen; + const accepted = value.byteLength <= remaining ? value : value.subarray(0, remaining); + seen += accepted.byteLength; + out += decoder.decode(accepted, { stream: true }); + if (seen >= MAX_SIDECAR_RESPONSE_BYTES) { + try { void reader.cancel("vision sidecar error body byte limit reached").catch(() => undefined); } + catch { /* best-effort body teardown */ } + break; + } + } + out += decoder.decode(); + } catch { + /* a failed error-body read must not mask the HTTP status we are about to report */ + } + return out; +} + /** Fold Anthropic Messages text deltas into one description. Malformed frames are ignored. */ export async function parseAnthropicVisionSSE(res: Response): Promise { if (!res.body) return { text: "", error: "anthropic vision sidecar returned no response body" }; @@ -52,6 +82,7 @@ export async function parseAnthropicVisionSSE(res: Response): Promise { let dataLine = ""; @@ -76,12 +107,24 @@ export async function parseAnthropicVisionSSE(res: Response): Promise= MAX_SIDECAR_RESPONSE_BYTES) { + // Keep the frames folded above, drop the unterminated tail, and do not wait on teardown. + try { void reader.cancel("vision sidecar response byte limit reached").catch(() => undefined); } + catch { /* best-effort body teardown */ } + buffer = ""; + break; + } } buffer = (buffer + decoder.decode()).replace(/\r\n/g, "\n"); if (buffer.trim()) processFrame(buffer); @@ -164,7 +207,8 @@ export async function describeImageAnthropic( { abortSignal: linkedSignal.signal, label: "vision-sidecar-anthropic" }, ); if (!res.ok) { - const responseText = await res.text().catch(() => ""); + // The body is untrusted and only feeds one auth-failure message, so read a bounded prefix. + const responseText = await readBoundedText(res); console.warn(`[vision] anthropic sidecar HTTP ${res.status} (${Date.now() - startedAt}ms)`); if (res.status === 401) { return { text: "", error: `anthropic vision sidecar auth failed: ${publicOAuthAuthenticationErrorMessage(new Error(responseText))}` }; diff --git a/tests/vision/vision-anthropic.test.ts b/tests/vision/vision-anthropic.test.ts index 086e5df7bb..05df35662e 100644 --- a/tests/vision/vision-anthropic.test.ts +++ b/tests/vision/vision-anthropic.test.ts @@ -225,6 +225,27 @@ describe("Anthropic vision executor", () => { expect(result).toEqual({ text: "first second" }); }); + test("an unterminated frame cannot buffer the stream without bound", async () => { + // A sidecar that never emits a frame separator: without a cap the parser accumulates the + // whole response in memory before it can fold anything. + let produced = 0; + let cancelled = false; + const chunk = new TextEncoder().encode(`data: {"filler":"${"x".repeat(64 * 1024)}"}`); + const body = new ReadableStream({ + pull(c) { + if (produced > 8 * 1024 * 1024) { c.close(); return; } + produced += chunk.byteLength; + c.enqueue(chunk); + }, + cancel() { cancelled = true; }, + }); + const out = await parseAnthropicVisionSSE(new Response(body, { status: 200 })); + expect(cancelled).toBe(true); + // The cap stops the read long before the producer would have finished on its own. + expect(produced).toBeLessThan(1024 * 1024); + expect(out.text).toBe(""); + }); + test("malformed and terminal-error streams degrade to explicit errors", async () => { const malformed = await parseAnthropicVisionSSE(sseResponse(["{not-json", { type: "message_stop" }])); expect(malformed.text).toBe(""); From 9d8d11abdee0151c2a283ff4c3ace728a02a0455 Mon Sep 17 00:00:00 2001 From: x3M3x <98298256+x3M3x@users.noreply.github.com> Date: Mon, 7 Sep 2026 18:24:13 +0900 Subject: [PATCH 116/412] fix(service): carry startup-health cache portion of #3863 [skip ci] Path-filtered source commit: 960621616c439e69b967981c290f2377ba9465fa. Config-route wiring excluded under lane ownership. Co-authored-by: x3M3x <98298256+x3M3x@users.noreply.github.com> (cherry picked from commit 197bf2e2bff362b9a135389741f1acf91670ded0) --- src/server/startup-health-cache.ts | 16 +++++++++++ tests/service/autostart-health.test.ts | 39 +++++++++++++++++++++++++- 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/src/server/startup-health-cache.ts b/src/server/startup-health-cache.ts index 70380eb4ed..571d81b549 100644 --- a/src/server/startup-health-cache.ts +++ b/src/server/startup-health-cache.ts @@ -50,6 +50,22 @@ export interface StartupHealthCacheDeps { ) => Promise; } +/** + * Return the last completed probe immediately and refresh it in the background. + * + * Settings are consumed by several dashboard controls. They must not block on a + * Windows service-manager probe; the dedicated /api/startup-health route owns + * the fresh, bounded diagnostic read. + */ +export function getStartupHealthSnapshot( + config: Pick, + deps: StartupHealthCacheDeps = {}, +): StartupHealth { + const now = deps.now ?? Date.now; + if (!cached || now() - cached.timestamp >= CACHE_TTL_MS) refreshInBackground(config, deps); + return cached ? markStartupHealthDiagnosticStale(cached.value) : conservativeFallback(config); +} + export function markStartupHealthDiagnosticStale(value: StartupHealth): StartupHealth { if (!value.localRoutingDependency) return { ...value, diagnosticStale: true }; return { diff --git a/tests/service/autostart-health.test.ts b/tests/service/autostart-health.test.ts index 639f1b34c3..48bb7b5395 100644 --- a/tests/service/autostart-health.test.ts +++ b/tests/service/autostart-health.test.ts @@ -3,7 +3,7 @@ import { deriveStartupHealth, formatStartupRoutingDetail, startupHealthSummary } import { unusedProxyWarningLines } from "../../src/cli/status"; import { classifyCodexRouting, hasInjectedCodexRouting } from "../../src/codex/inject"; import { handleManagementAPI } from "../../src/server/management-api"; -import { getCachedStartupHealth, invalidateStartupHealthCache, markStartupHealthDiagnosticStale } from "../../src/server/startup-health-cache"; +import { getCachedStartupHealth, getStartupHealthSnapshot, invalidateStartupHealthCache, markStartupHealthDiagnosticStale } from "../../src/server/startup-health-cache"; import type { OcxConfig } from "../../src/types"; const base = { @@ -277,6 +277,43 @@ describe("Codex startup health", () => { await pendingProbe; invalidateStartupHealthCache(); }); + + test("settings snapshot starts a probe without waiting for it", async () => { + invalidateStartupHealthCache(); + let releaseProbe!: (value: ReturnType) => void; + const pendingProbe = new Promise>(resolve => { + releaseProbe = resolve; + }); + + const health = getStartupHealthSnapshot( + { codexAutoStart: true }, + { probe: async () => pendingProbe }, + ); + + expect(health.diagnosticStale).toBe(true); + releaseProbe(deriveStartupHealth({ ...base, routingKind: "native" })); + await pendingProbe; + invalidateStartupHealthCache(); + }); + + test("settings GET uses the non-blocking startup-health snapshot in production", async () => { + invalidateStartupHealthCache(); + const url = new URL("http://localhost/api/settings"); + + const response = await Promise.race([ + handleManagementAPI( + new Request(url), + url, + { port: 10100, providers: {}, defaultProvider: "openai", codexAutoStart: true } as OcxConfig, + ), + new Promise(resolve => setTimeout(() => resolve(null), 100)), + ]); + + expect(response?.status).toBe(200); + const body = await response!.json() as { startupHealth?: { diagnosticStale?: boolean } }; + expect(body.startupHealth?.diagnosticStale).toBe(true); + invalidateStartupHealthCache(); + }); }); import { ManagementRequest as Request } from "../helpers/management-auth"; From 734d41c528039a29b4002d455405afacfecf922c Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 18:31:54 +0900 Subject: [PATCH 117/412] fix(gui): retain unapplied Desktop status across settings polls [skip ci] Co-authored-by: RobinBially <7304732+RobinBially@users.noreply.github.com> --- gui/src/pages/use-dashboard-data.ts | 7 ++++++- gui/tests/vision-sidecar-dashboard.test.tsx | 9 +++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/gui/src/pages/use-dashboard-data.ts b/gui/src/pages/use-dashboard-data.ts index e87e6494bd..8634e7caa8 100644 --- a/gui/src/pages/use-dashboard-data.ts +++ b/gui/src/pages/use-dashboard-data.ts @@ -361,7 +361,12 @@ export function useDashboardData(apiBase: string) { useEffect(() => { const data = settingsPoll.data; if (!data) return; - if (data.settings !== undefined) setSettings(data.settings); + if (data.settings !== undefined) { + const next = data.settings; + // GET settings does not report application receipts. Keep a saved preference's + // pending indication until an affirmative sync result clears it. + setSettings(prev => ({ ...next, catalogRefreshPending: prev?.catalogRefreshPending === true || next.catalogRefreshPending })); + } // Latest-wins: only seed from settings when no newer dedicated probe has committed // while this settings poll was in flight. Always merge against the live ref. if ( diff --git a/gui/tests/vision-sidecar-dashboard.test.tsx b/gui/tests/vision-sidecar-dashboard.test.tsx index 386196cc77..738ed866e6 100644 --- a/gui/tests/vision-sidecar-dashboard.test.tsx +++ b/gui/tests/vision-sidecar-dashboard.test.tsx @@ -13,6 +13,7 @@ import { DashboardSidecarPanels } from "../src/pages/dashboard-overview-sections import type { SidecarData, SidecarPatch } from "../src/pages/dashboard-shared"; import { mergeSidecarSetting } from "../src/pages/dashboard-shared"; import { useDashboardData } from "../src/pages/use-dashboard-data"; +import { setClientResourceData } from "../src/client-resource"; const globals = ["document", "window", "navigator", "IS_REACT_ACT_ENVIRONMENT"] as const; let previousGlobals: Record<(typeof globals)[number], PropertyDescriptor | undefined>; @@ -479,6 +480,14 @@ test.each(["skipped", "catalog-only", "applied"])("Desktop preference pending st expect(latest?.settings?.codexDesktopAuthless).toBe(true); expect(latest?.settings?.catalogRefreshPending).toBe(syncStatus !== "applied"); expect(latest?.syncResult?.status).toBe(syncStatus); + // A fresh settings poll has no application receipt and cannot erase pending. + await act(async () => { + setClientResourceData(`dashboard-settings:${apiBase}`, { + settings: { codexAutoStart: true, codexDesktopAuthless: true, port: 10100, hostname: "127.0.0.1" }, + }); + }); + expect(latest?.settings?.codexDesktopAuthless).toBe(true); + expect(latest?.settings?.catalogRefreshPending === true).toBe(syncStatus !== "applied"); } finally { await act(async () => { root?.unmount(); }); root = null; From ffcd7abbaa210fad6ab235047d190248c5d6d52d Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 18:36:13 +0900 Subject: [PATCH 118/412] fix(gui): guard fallback hydration races and preserve row focus [skip ci] Co-authored-by: x3M3x <98298256+x3M3x@users.noreply.github.com> --- .../SubagentDelegationSection.tsx | 40 ++++- gui/src/pages/Subagents.tsx | 42 +++-- gui/tests/subagents-fallback.test.tsx | 151 +++++++++++++++++- 3 files changed, 214 insertions(+), 19 deletions(-) diff --git a/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx b/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx index dbbbd99948..6fe043461c 100644 --- a/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx +++ b/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx @@ -6,7 +6,7 @@ * better next to the roster it affects: the roster picks who may be called, this picks who * gets called first. */ -import { useState } from "react"; +import { useLayoutEffect, useRef, useState } from "react"; import { Select, Tooltip } from "../../ui"; import { IconArrowDown, IconArrowUp, IconInfo, IconX } from "../../icons"; import { useT, type TKey } from "../../i18n/shared"; @@ -63,12 +63,36 @@ export default function SubagentDelegationSection({ const nativeMayUseV2 = ultraMode.enabled || (ultraMode.multiAgentMode !== "v1" && !(ultraMode.multiAgentMode === "v2" && ultraMode.keepNativeChatGptOnV1)); const showV2Compatibility = !ultraLoadFailed && ultraMode.loaded === true && routedPreferred && nativeMayUseV2; + const fallbackControlsRef = useRef(null); + const nextRowId = useRef(0); + const rowIdentity = useRef>([]); + // Reuse each configured occurrence across reorder; duplicates have distinct IDs. + if (rowIdentity.current.length !== fallback.length || rowIdentity.current.some((row, i) => row.model !== fallback[i])) { + const remaining = [...rowIdentity.current]; + rowIdentity.current = fallback.map(modelName => { + const old = remaining.findIndex(row => row.model === modelName); + return old >= 0 ? remaining.splice(old, 1)[0] : { model: modelName, id: nextRowId.current++ }; + }); + } + const pendingFocus = useRef<{ row: number; action: string } | null>(null); + useLayoutEffect(() => { + const target = pendingFocus.current; + if (!target) return; + pendingFocus.current = null; + const row = fallbackControlsRef.current?.querySelectorAll(".swi-fallback-row")[target.row]; + const action = row?.querySelector(`button[data-action="${target.action}"]:not(:disabled)`) + ?? row?.querySelector("button:not(:disabled)") + ?? fallbackControlsRef.current?.querySelector('button[role="combobox"]'); + action?.focus(); + }, [fallback]); const validPollMs = Number.isInteger(fallbackPollMs) && fallbackPollMs >= 5000 && fallbackPollMs <= 600000; const moveFallback = (index: number, direction: -1 | 1) => { const next = [...fallback]; const target = index + direction; if (fallbackBusy || target < 0 || target >= next.length) return; [next[index], next[target]] = [next[target], next[index]]; + [rowIdentity.current[index], rowIdentity.current[target]] = [rowIdentity.current[target], rowIdentity.current[index]]; + pendingFocus.current = { row: target, action: direction === -1 ? "up" : "down" }; onFallbackChange(next); }; @@ -134,16 +158,20 @@ export default function SubagentDelegationSection({
{t("sub.fallbackLabel")}
{t("sub.fallbackHint")}
-
+
{fallback.map((modelName, index) => ( -
+
{index + 1}. {modelName} {!availableModels.includes(modelName) && {t("sub.fallbackUnavailable")}} - - - + + +
))} diff --git a/gui/src/pages/Subagents.tsx b/gui/src/pages/Subagents.tsx index cbdb138e33..cf9f1b33d0 100644 --- a/gui/src/pages/Subagents.tsx +++ b/gui/src/pages/Subagents.tsx @@ -8,7 +8,7 @@ import { useDataSurface } from "../data-surface"; import { DataSurfaceSkeleton } from "../components/data-surface"; import { useSubagentDelegation, type UltraModePatch, type UltraModeState } from "./use-subagent-delegation"; -type CachedSubagents = { available: string[]; chosen: string[]; fallback: string[]; pollMs: number }; +type CachedSubagents = { available: string[]; chosen: string[]; fallback?: string[]; pollMs?: number }; function seedSubagents(cacheKey: string): CachedSubagents | null { return readSessionListCache(cacheKey); @@ -22,6 +22,9 @@ export default function Subagents({ apiBase }: { apiBase: string }) { const [fallback, setFallback] = useState(() => cached?.fallback ?? []); const [fallbackPollMs, setFallbackPollMs] = useState(() => cached?.pollMs ?? 60000); const [fallbackBusy, setFallbackBusy] = useState(false); + const [fallbackLoaded, setFallbackLoaded] = useState(() => Array.isArray(cached?.fallback) && Number.isInteger(cached?.pollMs)); + const fallbackRevision = useRef(0); + const rosterRevision = useRef(0); const fallbackSaveInFlight = useRef(false); const committed = useRef(cached); const [status, setStatus] = useState(""); @@ -125,6 +128,8 @@ export default function Subagents({ apiBase }: { apiBase: string }) { const loadSubagents = useCallback(async (signal?: AbortSignal): Promise => { // The resource layer's deadline abort must reach the wire — a signal dropped // here is a store that can only settle by race timeout. + const rosterReadRevision = rosterRevision.current; + const fallbackReadRevision = fallbackRevision.current; const [rosterRes, fallbackRes] = await Promise.all([ fetch(`${apiBase}/api/subagent-models`, { signal }), fetch(`${apiBase}/api/subagent-model-fallback`, { signal }), @@ -134,18 +139,23 @@ export default function Subagents({ apiBase }: { apiBase: string }) { if (!response || !fallbackResponse) throw new Error(t("sub.loadFail")); const available = response.available ?? fallbackResponse.available ?? []; const availableSet = new Set(available); + const rosterCurrent = rosterReadRevision === rosterRevision.current && !saveInFlight.current; + const fallbackCurrent = fallbackReadRevision === fallbackRevision.current && !fallbackSaveInFlight.current; const next = { available, - chosen: (response.chosen ?? []).filter(model => availableSet.has(model)), + chosen: rosterCurrent ? (response.chosen ?? []).filter(model => availableSet.has(model)) : committed.current?.chosen ?? [], // Configured targets remain editable even when discovery no longer advertises them. - fallback: fallbackResponse.models ?? [], - pollMs: fallbackResponse.pollMs ?? 60000, + fallback: fallbackCurrent ? fallbackResponse.models ?? [] : committed.current?.fallback ?? [], + pollMs: fallbackCurrent ? fallbackResponse.pollMs ?? 60000 : committed.current?.pollMs ?? 60000, }; if (signal?.aborted) throw signal.reason; committed.current = next; - setChosen(next.chosen); - setFallback(next.fallback); - setFallbackPollMs(next.pollMs); + if (rosterCurrent) setChosen(next.chosen); + if (fallbackCurrent) { + setFallback(next.fallback); + setFallbackPollMs(next.pollMs); + setFallbackLoaded(true); + } writeSessionListCache(cacheKey, next); return next; }, [apiBase, cacheKey, t]); @@ -166,10 +176,12 @@ export default function Subagents({ apiBase }: { apiBase: string }) { const toggle = (m: string) => { if (busy) return; setStatus(""); + rosterRevision.current += 1; setChosen(prev => prev.includes(m) ? prev.filter(x => x !== m) : (prev.length >= FEATURED_MAX ? prev : [...prev, m])); }; const move = (i: number, dir: -1 | 1) => { if (busy) return; + rosterRevision.current += 1; setChosen(prev => { const next = [...prev]; const j = i + dir; @@ -182,6 +194,7 @@ export default function Subagents({ apiBase }: { apiBase: string }) { const save = async () => { if (busy || saveInFlight.current) return; saveInFlight.current = true; + rosterRevision.current += 1; setBusy(true); setStatus(""); try { @@ -191,9 +204,11 @@ export default function Subagents({ apiBase }: { apiBase: string }) { body: JSON.stringify({ models: chosen }), }); const d = await readJsonOrThrow<{ applied?: string[] }>(r, t("sub.saveFailed")); + rosterRevision.current += 1; const applied = d?.applied ?? chosen; if (d?.applied) setChosen(d.applied); - const next = { available, chosen: applied, fallback: committed.current?.fallback ?? [], pollMs: committed.current?.pollMs ?? 60000 }; + // A legacy roster-only seed does not prove that an empty fallback was loaded. + const next = { ...committed.current, available, chosen: applied }; committed.current = next; writeSessionListCache(cacheKey, next); setOk(true); @@ -208,8 +223,9 @@ export default function Subagents({ apiBase }: { apiBase: string }) { }; const saveFallback = async () => { - if (fallbackSaveInFlight.current || !Number.isInteger(fallbackPollMs) || fallbackPollMs < 5000 || fallbackPollMs > 600000) return; + if (!fallbackLoaded || fallbackSaveInFlight.current || !Number.isInteger(fallbackPollMs) || fallbackPollMs < 5000 || fallbackPollMs > 600000) return; fallbackSaveInFlight.current = true; + fallbackRevision.current += 1; const requestApiBase = apiBase; setFallbackBusy(true); setStatus(""); @@ -222,6 +238,7 @@ export default function Subagents({ apiBase }: { apiBase: string }) { const d = await readJsonOrThrow<{ models?: string[]; pollMs?: number }>(r, t("sub.fallbackSaveFailed")); if (currentUltraApiBase.current !== requestApiBase) return; if (!d || !Array.isArray(d.models) || typeof d.pollMs !== "number") throw new Error(t("sub.fallbackSaveFailed")); + fallbackRevision.current += 1; setFallback(d.models); setFallbackPollMs(d.pollMs); const next = { available, chosen: committed.current?.chosen ?? [], fallback: d.models, pollMs: d.pollMs }; @@ -260,6 +277,7 @@ export default function Subagents({ apiBase }: { apiBase: string }) {
{status && {status}} {state.showError && {t("sub.loadFail")}} + {!fallbackLoaded && state.showError && } { void save(); }} fallback={fallback} fallbackPollMs={fallbackPollMs} - fallbackBusy={fallbackBusy} - onFallbackChange={setFallback} - onFallbackPollMsChange={setFallbackPollMs} + fallbackBusy={fallbackBusy || !fallbackLoaded} + onFallbackChange={models => { fallbackRevision.current += 1; setFallback(models); }} + onFallbackPollMsChange={pollMs => { fallbackRevision.current += 1; setFallbackPollMs(pollMs); }} onFallbackSave={() => { void saveFallback(); }} delegation={{ model: delegation.model, diff --git a/gui/tests/subagents-fallback.test.tsx b/gui/tests/subagents-fallback.test.tsx index 20badc4980..ad794b8261 100644 --- a/gui/tests/subagents-fallback.test.tsx +++ b/gui/tests/subagents-fallback.test.tsx @@ -16,7 +16,7 @@ const globals = [ "document", "window", "navigator", "localStorage", "sessionStorage", "fetch", "IS_REACT_ACT_ENVIRONMENT", ] as const; -type CachedSubagents = { available: string[]; chosen: string[]; fallback: string[]; pollMs: number }; +type CachedSubagents = { available: string[]; chosen: string[]; fallback?: string[]; pollMs?: number }; type FallbackSettings = { models: string[]; pollMs: number }; type SentRequest = { path: string; method: string; init?: RequestInit }; type V2Settings = { @@ -38,6 +38,7 @@ let failFallbackPut: boolean; let v2Settings: V2Settings; let preferredModel: string | null; let fallbackGetGate: Promise | null; +let pendingFallbackResponse: Promise | null; beforeEach(() => { clearClientResourceStoresForTests(); @@ -61,6 +62,7 @@ beforeEach(() => { v2Settings = { enabled: true, multiAgentMode: "v2", multiAgentModeHintText: null, keepNativeChatGptOnV1: false }; preferredModel = null; fallbackGetGate = null; + pendingFallbackResponse = null; Object.defineProperty(globalThis, "fetch", { configurable: true, value: async (input: RequestInfo | URL, init?: RequestInit) => { @@ -69,6 +71,11 @@ beforeEach(() => { requests.push({ path, method, init }); // Match agent-settings-routes: fallback uses models, roster uses chosen/applied. if (path === FALLBACK_PATH && method === "GET") { + if (pendingFallbackResponse) { + const pending = pendingFallbackResponse; + pendingFallbackResponse = null; + return pending; + } if (fallbackGetGate) await fallbackGetGate; return Response.json({ ...fallbackSettings, available }); } @@ -250,6 +257,51 @@ test("adds, reorders in both directions, and removes fallback models before savi expect(putBodies(ROSTER_PATH)).toEqual([]); }); +test("keyboard moves retain row focus and removal moves focus to the next row or add control", async () => { + fallbackSettings.models = ["a-1", "a-2", "a-3"]; + await mount(); + + const activateWithEnter = async (button: HTMLButtonElement) => { + expect(button.disabled).toBe(false); + await act(async () => { + button.focus(); + expect(testWindow.document.activeElement).toBe(button); + button.dispatchEvent(new testWindow.KeyboardEvent("keydown", { key: "Enter", code: "Enter", bubbles: true })); + // happy-dom does not synthesize native button activation from Enter. Supply the + // keyboard-generated click (detail 0) explicitly; this test covers focus restoration. + button.dispatchEvent(new testWindow.MouseEvent("click", { bubbles: true, detail: 0 })); + button.dispatchEvent(new testWindow.KeyboardEvent("keyup", { key: "Enter", code: "Enter", bubbles: true })); + }); + }; + + const middleRow = rows()[1]; + await activateWithEnter(rowButton(1, "sub.moveDown", "a-2")); + expectOrder(["a-1", "a-3", "a-2"]); + expect(rows()[2]).toBe(middleRow); + expect(rowButton(2, "sub.moveDown", "a-2").disabled).toBe(true); + // The requested direction is disabled at the boundary; focus an enabled action + // in the moved row, rather than the neighboring row or document.body. + expect(testWindow.document.activeElement).toBe(rowButton(2, "sub.moveUp", "a-2")); + + await activateWithEnter(rowButton(2, "sub.moveUp", "a-2")); + expectOrder(["a-1", "a-2", "a-3"]); + expect(rows()[1]).toBe(middleRow); + expect(testWindow.document.activeElement).toBe(rowButton(1, "sub.moveUp", "a-2")); + + await activateWithEnter(rowButton(1, "sub.removeAria", "a-2")); + expectOrder(["a-1", "a-3"]); + expect(testWindow.document.activeElement).toBe(rowButton(1, "sub.removeAria", "a-3")); + + await activateWithEnter(rowButton(1, "sub.removeAria", "a-3")); + expectOrder(["a-1"]); + expect(testWindow.document.activeElement).toBe(rowButton(0, "sub.removeAria", "a-1")); + + await activateWithEnter(rowButton(0, "sub.removeAria", "a-1")); + expectOrder([]); + expect(testWindow.document.activeElement).toBe(labelledButton(editor(), en["sub.fallbackAdd"])); + expect(putBodies()).toEqual([]); +}); + test("removes only the selected duplicate fallback occurrence by index", async () => { fallbackSettings.models = ["a-2", "a-1", "a-2", "a-3"]; await mount(); @@ -364,6 +416,103 @@ test("remount shows the committed fallback and roster while a fresh fallback GET expect(pollInput().value).toBe("120000"); }); +test("a legacy cache keeps fallback disabled through GET failure, roster Save, and remount", async () => { + const legacyCache = { available, chosen: ["a-1"] }; + testWindow.sessionStorage.setItem(CACHE_KEY, JSON.stringify(legacyCache)); + let releaseGet!: (response: Response) => void; + pendingFallbackResponse = new Promise(resolve => { releaseGet = resolve; }); + + const assertBlocked = async (expectedCache = legacyCache) => { + expect(labelledButton(editor(), en["sub.fallbackAdd"]).disabled).toBe(true); + expect(pollInput().disabled).toBe(true); + expect(saveButton().disabled).toBe(true); + expect(Array.from(editor().querySelectorAll("input, button")) + .every(control => control.disabled)).toBe(true); + await act(async () => { saveButton().click(); }); + expect(putBodies()).toEqual([]); + expect(cached()).toEqual(expectedCache); + expect(cached()).not.toHaveProperty("fallback"); + expect(cached()).not.toHaveProperty("pollMs"); + // A failed read must never turn the page's empty placeholder into a saved empty chain. + expect(fallbackSettings).toEqual({ models: ["a-2"], pollMs: 45_000 }); + }; + + try { + await mount(); + expect(rows()).toHaveLength(0); + expect(pendingFallbackResponse).toBeNull(); + await assertBlocked(); + } finally { + await act(async () => { + releaseGet(Response.json({ error: "Fallback discovery failed" }, { status: 503 })); + }); + } + expect(container.textContent).toContain(en["sub.loadFail"]); + await assertBlocked(); + + await click(labelledButton(container, en["sub.workspace.addToFeatured"].replace("{m}", "a-3"))); + const rosterSaveRow = container.querySelector(".swi-save-row"); + if (!rosterSaveRow) throw new Error("Roster Save row not found"); + await click(saveButton(rosterSaveRow)); + const savedRosterCache = { available, chosen: ["a-1", "a-3"] }; + expect(putBodies(ROSTER_PATH)).toEqual([{ models: ["a-1", "a-3"] }]); + await assertBlocked(savedRosterCache); + + const current = root!; + await act(async () => { current.unmount(); }); + root = null; + clearClientResourceStoresForTests(); + const getsBefore = requests.filter(request => request.path === FALLBACK_PATH && request.method === "GET").length; + pendingFallbackResponse = new Promise(resolve => { releaseGet = resolve; }); + try { + await mount(); + expect(requests.filter(request => request.path === FALLBACK_PATH && request.method === "GET")).toHaveLength(getsBefore + 1); + expect(pendingFallbackResponse).toBeNull(); + await assertBlocked(savedRosterCache); + } finally { + await act(async () => { + releaseGet(Response.json({ error: "Fallback discovery still unavailable" }, { status: 503 })); + }); + } + expect(container.textContent).toContain(en["sub.loadFail"]); + await assertBlocked(savedRosterCache); + expect(putBodies(ROSTER_PATH)).toEqual([{ models: ["a-1", "a-3"] }]); +}); + +test.each([false, true])("a captured old fallback GET cannot overwrite a newer draft or save (saved=%s)", async (saveNewer) => { + const committedA = { available, chosen: ["a-1"], fallback: ["a-2"], pollMs: 45_000 }; + testWindow.sessionStorage.setItem(CACHE_KEY, JSON.stringify(committedA)); + // Serialize A before any edit or PUT. Reading mutable fallbackSettings after the gate + // would accidentally return B and let the stale-response regression pass. + const capturedOldResponse = Response.json({ models: ["a-2"], pollMs: 45_000, available }); + let releaseGet!: (response: Response) => void; + pendingFallbackResponse = new Promise(resolve => { releaseGet = resolve; }); + const committedB = { available, chosen: ["a-1"], fallback: ["a-3"], pollMs: 90_000 }; + + try { + await mount(); + expect(pendingFallbackResponse).toBeNull(); + expectOrder(["a-2"]); + await addFallback("a-3"); + await click(rowButton(0, "sub.removeAria", "a-2")); + await changePollMs(90_000); + if (saveNewer) await click(saveButton()); + expectOrder(["a-3"]); + expect(pollInput().value).toBe("90000"); + expect(cached()).toEqual(saveNewer ? committedB : committedA); + } finally { + await act(async () => { releaseGet(capturedOldResponse); }); + } + + // The delayed GET has now settled; both UI fields and the committed session seed + // must retain their respective newer-draft / newer-save semantics. + expect(capturedOldResponse.bodyUsed).toBe(true); + expectOrder(["a-3"]); + expect(pollInput().value).toBe("90000"); + expect(cached()).toEqual(saveNewer ? committedB : committedA); + expect(putBodies()).toEqual(saveNewer ? [{ models: ["a-3"], pollMs: 90_000 }] : []); +}); + test("invalid polling intervals disable Save without a PUT or cache mutation, and a valid interval recovers", async () => { await mount(); const committed = cached(); From 51b44371860b2ec933d66de1b68ca790be3b81fb Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 18:23:39 +0900 Subject: [PATCH 119/412] test(web-search): cover bounded partial frames and detached cancellation [skip ci] Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com> --- tests/web-search/web-search-anthropic.test.ts | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/web-search/web-search-anthropic.test.ts b/tests/web-search/web-search-anthropic.test.ts index 33f2616cc2..980eacddaa 100644 --- a/tests/web-search/web-search-anthropic.test.ts +++ b/tests/web-search/web-search-anthropic.test.ts @@ -193,6 +193,26 @@ describe("parseAnthropicSidecarSSE", () => { }); }); +describe("Anthropic sidecar byte boundaries", () => { + test.each([64 * 1024, 80 * 1024])("preserves complete prefix frames at %i bytes without awaiting cancel", async (size) => { + const prefix = `data: ${JSON.stringify({ type: "content_block_delta", delta: { type: "text_delta", text: "prefix 한글" } })}\n\n`; + const tail = `data: ${JSON.stringify({ type: "content_block_delta", delta: { type: "text_delta", text: "discard" } })}`; + const encoder = new TextEncoder(); + // The final unterminated frame is syntactically valid exactly at the cap. + // EOF flush must not fold it after cancellation. + const body = prefix + ":" + "x".repeat(64 * 1024 - encoder.encode(prefix + "\n\n" + tail).length - 1) + "\n\n" + tail; + const bytes = encoder.encode(body + "z".repeat(size - 64 * 1024)); + let cancelled = false; + const res = new Response(new ReadableStream({ + start(controller) { controller.enqueue(bytes); }, + cancel() { cancelled = true; return new Promise(() => {}); }, + }, { highWaterMark: 0 })); + const out = await parseAnthropicSidecarSSE(res); + expect(cancelled).toBe(true); + expect(out).toEqual({ text: "prefix 한글", sources: [] }); + }); +}); + describe("runAnthropicWebSearch request shape", () => { const originalFetch = globalThis.fetch; afterEach(() => { @@ -200,6 +220,21 @@ describe("runAnthropicWebSearch request shape", () => { oauthAccessError = undefined; }); + test.each([401, 503])("bounds HTTP %i error bodies and never awaits non-settling cancellation", async (status) => { + let reads = 0; + let cancelled = false; + globalThis.fetch = (async () => new Response(new ReadableStream({ + pull(controller) { reads += 1; controller.enqueue(new Uint8Array(4096).fill(120)); }, + cancel() { cancelled = true; return new Promise(() => {}); }, + }, { highWaterMark: 0 }), { status })) as typeof fetch; + const out = await runAnthropicWebSearch("bounded fixture", "anthropic", anthropicProvider, + { model: "claude-sonnet-5", reasoning: "low", timeoutMs: 5000, describeImages: false }); + expect(reads).toBe(16); + expect(cancelled).toBe(true); + expect(out.error).toBe(status === 401 + ? `anthropic sidecar auth failed: ${PUBLIC_OAUTH_ERROR}` : "sidecar HTTP 503"); + }); + test("projects OAuth, upstream-auth, and transport failures onto safe public errors", async () => { oauthAccessError = new Error(`credential read failed at ${AUTH_ERROR_CANARY}`); const credentialFailure = await runAnthropicWebSearch( From 8eaa5641902b84bec6c97a94de6c2fe6d810c31d Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 18:24:12 +0900 Subject: [PATCH 120/412] test(vision): pin capped descriptions and non-settling error-body cancel [skip ci] Co-authored-by: luvs01 <27862058+luvs01@users.noreply.github.com> --- tests/vision/vision-anthropic.test.ts | 28 +++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/vision/vision-anthropic.test.ts b/tests/vision/vision-anthropic.test.ts index 05df35662e..0c0ef3c095 100644 --- a/tests/vision/vision-anthropic.test.ts +++ b/tests/vision/vision-anthropic.test.ts @@ -73,6 +73,34 @@ describe("Anthropic vision executor", () => { oauthAccessError = undefined; }); + test.each([64 * 1024, 80 * 1024])("keeps only complete partial description frames at %i bytes without waiting for cancel", async (size) => { + const prefix = `data: ${JSON.stringify({ type: "content_block_delta", delta: { type: "text_delta", text: "partial 한글" } })}\n\n`; + const tail = `data: ${JSON.stringify({ type: "content_block_delta", delta: { type: "text_delta", text: "discard" } })}`; + const encoder = new TextEncoder(); + const body = prefix + ":" + "x".repeat(64 * 1024 - encoder.encode(prefix + "\n\n" + tail).length - 1) + "\n\n" + tail; + let cancelled = false; + const out = await parseAnthropicVisionSSE(new Response(new ReadableStream({ + start(controller) { controller.enqueue(encoder.encode(body + "z".repeat(size - 64 * 1024))); }, + cancel() { cancelled = true; return new Promise(() => {}); }, + }, { highWaterMark: 0 }))); + expect(cancelled).toBe(true); + expect(out).toEqual({ text: "partial 한글" }); + }); + + test.each([401, 503])("bounds HTTP %i error bodies even when cancellation never settles", async (status) => { + let reads = 0; + let cancelled = false; + globalThis.fetch = (async () => new Response(new ReadableStream({ + pull(controller) { reads += 1; controller.enqueue(new Uint8Array(4096).fill(120)); }, + cancel() { cancelled = true; return new Promise(() => {}); }, + }, { highWaterMark: 0 }), { status })) as typeof fetch; + const out = await describeImageAnthropic(DATA_IMAGE, "high", "", "anthropic-vision-test", anthropicProvider, settings); + expect(reads).toBe(16); + expect(cancelled).toBe(true); + expect(out.error).toBe(status === 401 + ? `anthropic vision sidecar auth failed: ${PUBLIC_OAUTH_ERROR}` : "anthropic vision sidecar HTTP 503"); + }); + test("projects OAuth, upstream-auth, and transport failures onto safe replacement errors", async () => { oauthAccessError = new Error(`credential read failed at ${AUTH_ERROR_CANARY}`); const credentialFailure = await describeImageAnthropic( From 91b54b79bc780011031b00354621cc9fcaef360e Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 18:25:01 +0900 Subject: [PATCH 121/412] fix(service): preserve fresh health and contain detached probe failures [skip ci] Co-authored-by: x3M3x <98298256+x3M3x@users.noreply.github.com> --- src/server/startup-health-cache.ts | 26 ++++++---- tests/service/autostart-health.test.ts | 72 +++++++++++++++++++++----- 2 files changed, 75 insertions(+), 23 deletions(-) diff --git a/src/server/startup-health-cache.ts b/src/server/startup-health-cache.ts index 571d81b549..2c12e0bbc3 100644 --- a/src/server/startup-health-cache.ts +++ b/src/server/startup-health-cache.ts @@ -62,7 +62,8 @@ export function getStartupHealthSnapshot( deps: StartupHealthCacheDeps = {}, ): StartupHealth { const now = deps.now ?? Date.now; - if (!cached || now() - cached.timestamp >= CACHE_TTL_MS) refreshInBackground(config, deps); + if (cached && now() - cached.timestamp < CACHE_TTL_MS) return cached.value; + refreshInBackground(config, deps); return cached ? markStartupHealthDiagnosticStale(cached.value) : conservativeFallback(config); } @@ -150,15 +151,20 @@ function refreshInBackground( ): void { if (inflight) return; const startedGeneration = generation; - const probe = (deps.probe ?? runProbe)(config).then(value => { - if (startedGeneration === generation) { - cached = { timestamp: (deps.now ?? Date.now)(), value }; - } - return value; - }); - inflight = probe.finally(() => { - if (inflight === probe || startedGeneration === generation) inflight = null; - }); + const probe: Promise = Promise.resolve() + .then(() => (deps.probe ?? runProbe)(config)) + .then(value => { + if (startedGeneration === generation) { + cached = { timestamp: (deps.now ?? Date.now)(), value }; + } + return value; + }) + .catch(() => cached ? markStartupHealthDiagnosticStale(cached.value) : conservativeFallback(config)) + .finally(() => { + // An invalidated probe must never clear the newer generation's flight. + if (inflight === probe) inflight = null; + }); + inflight = probe; } /** Stale-while-revalidate: service-manager probes never hold open a model/UI request. */ diff --git a/tests/service/autostart-health.test.ts b/tests/service/autostart-health.test.ts index 48bb7b5395..213a118e2b 100644 --- a/tests/service/autostart-health.test.ts +++ b/tests/service/autostart-health.test.ts @@ -296,22 +296,68 @@ describe("Codex startup health", () => { invalidateStartupHealthCache(); }); - test("settings GET uses the non-blocking startup-health snapshot in production", async () => { + test("snapshot preserves fresh protection and returns expired protection before a controlled probe settles", async () => { invalidateStartupHealthCache(); - const url = new URL("http://localhost/api/settings"); + let now = 1_000; + const config = { codexAutoStart: true }; + const protectedHealth = deriveStartupHealth({ ...base, serviceInstalled: true, serviceViable: true, serviceEnabled: true, serviceRunning: true }); + await getCachedStartupHealth(config, { now: () => now, probe: async () => protectedHealth, waitForProbe: probe => probe }); + let calls = 0; + let release!: (value: typeof protectedHealth) => void; + const pending = new Promise(resolve => { release = resolve; }); + const deps = { now: () => now, probe: () => { calls += 1; return pending; }, waitForProbe: (probe: Promise) => probe }; + expect(getStartupHealthSnapshot(config, deps)).toBe(protectedHealth); + expect(calls).toBe(0); + now += 30_000; + const snapshot = getStartupHealthSnapshot(config, deps); + expect(snapshot).toMatchObject({ diagnosticStale: true, status: "at-risk", rebootSafe: false }); + // Snapshot has returned while the manually controlled probe remains unresolved. + expect(getStartupHealthSnapshot(config, deps)).toEqual(snapshot); + const fresh = getCachedStartupHealth(config, deps); + const replacement = deriveStartupHealth({ ...base, routingKind: "custom-remote" }); + release(replacement); + expect(await fresh).toBe(replacement); + expect(calls).toBe(1); + invalidateStartupHealthCache(); + }); - const response = await Promise.race([ - handleManagementAPI( - new Request(url), - url, - { port: 10100, providers: {}, defaultProvider: "openai", codexAutoStart: true } as OcxConfig, - ), - new Promise(resolve => setTimeout(() => resolve(null), 100)), - ]); + test.each(["reject", "throw"])("detached snapshot probe handles %s and permits a later retry", async (failure) => { + invalidateStartupHealthCache(); + const config = { codexAutoStart: true }; + const failed = getStartupHealthSnapshot(config, { probe: () => { + if (failure === "throw") throw new Error("controlled probe failure"); + return Promise.reject(new Error("controlled probe failure")); + } }); + expect(failed.diagnosticStale).toBe(true); + const settled = await getCachedStartupHealth(config, { waitForProbe: probe => probe }); + expect(settled.diagnosticStale).toBe(true); + const replacement = deriveStartupHealth({ ...base, routingKind: "native" }); + expect(await getCachedStartupHealth(config, { probe: async () => replacement, waitForProbe: probe => probe })).toBe(replacement); + invalidateStartupHealthCache(); + }); - expect(response?.status).toBe(200); - const body = await response!.json() as { startupHealth?: { diagnosticStale?: boolean } }; - expect(body.startupHealth?.diagnosticStale).toBe(true); + test("invalidated probe cannot replace or clear a newer flight", async () => { + invalidateStartupHealthCache(); + const config = { codexAutoStart: true }; + type Health = ReturnType; + let oldRelease!: (value: Health) => void; + let newRelease!: (value: Health) => void; + const oldProbe = new Promise(resolve => { oldRelease = resolve; }); + const newProbe = new Promise(resolve => { newRelease = resolve; }); + getStartupHealthSnapshot(config, { probe: () => oldProbe }); + const oldWait = getCachedStartupHealth(config, { waitForProbe: probe => probe }); + invalidateStartupHealthCache(); + getStartupHealthSnapshot(config, { probe: () => newProbe }); + const newer = getCachedStartupHealth(config, { waitForProbe: probe => probe }); + oldRelease(deriveStartupHealth(base)); + await oldWait; + let spuriousCalls = 0; + getStartupHealthSnapshot(config, { probe: async () => { spuriousCalls += 1; return deriveStartupHealth(base); } }); + const expected = deriveStartupHealth({ ...base, routingKind: "native" }); + newRelease(expected); + expect(await newer).toBe(expected); + expect(getStartupHealthSnapshot(config)).toBe(expected); + expect(spuriousCalls).toBe(0); invalidateStartupHealthCache(); }); }); From abbdb227f385443228656c8440282187cb5dec75 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 19:07:56 +0900 Subject: [PATCH 122/412] docs: translate code-mode host rules; docs handoff from lane E [skip ci] --- devlog/_plan/260907_lane_c/040_desktop.md | 4 ++++ docs-site/src/content/docs/fr/guides/codex-integration.md | 8 ++++++++ docs-site/src/content/docs/ja/guides/codex-integration.md | 8 ++++++++ docs-site/src/content/docs/ko/guides/codex-integration.md | 7 +++++++ docs-site/src/content/docs/ru/guides/codex-integration.md | 8 ++++++++ docs-site/src/content/docs/tr/guides/codex-integration.md | 8 ++++++++ .../src/content/docs/zh-cn/guides/codex-integration.md | 6 ++++++ .../src/content/docs/zh-tw/guides/codex-integration.md | 6 ++++++ 8 files changed, 55 insertions(+) diff --git a/devlog/_plan/260907_lane_c/040_desktop.md b/devlog/_plan/260907_lane_c/040_desktop.md index ad7fb60177..4eb4ebffd5 100644 --- a/devlog/_plan/260907_lane_c/040_desktop.md +++ b/devlog/_plan/260907_lane_c/040_desktop.md @@ -402,3 +402,7 @@ index 84ac5f67b..b6be3c2f6 100644 ``` Audit amendment: clear catalogRefreshPending only if sync status is affirmative success, not HTTP 200 skipped. Add skipped/no-write regression. + +## Lane E documentation handoff + +After run 34106956362 reported a GUI lint failure, include the separately prepared code-mode host-rule translations in the seven fr/ja/ko/ru/tr/zh-cn/zh-tw Codex integration guides. The patch adds 51 documentation lines matching the existing English paragraph; it does not modify runtime code or provider guides. Apply on the Desktop layer, record `docs handoff from lane E` and `[skip ci]` in its own commit, then cascade the fallback layer and dispatch the top CI again. Local documentation install/build remains NOT RUN. diff --git a/docs-site/src/content/docs/fr/guides/codex-integration.md b/docs-site/src/content/docs/fr/guides/codex-integration.md index 02ffa8a211..a351adeae5 100644 --- a/docs-site/src/content/docs/fr/guides/codex-integration.md +++ b/docs-site/src/content/docs/fr/guides/codex-integration.md @@ -233,6 +233,14 @@ opencodex encode cette déclaration et son historique sous forme d'outil de fonc cycle de vie diffusé de l'appel de fonction en `custom_tool_call` avant que Codex ne le reçoive. Le routage natif par transfert OpenAI et l'outil personnalisé `apply_patch`, qui est pris en charge, restent inchangés. +Avant le premier appel, les tours routés en mode code reçoivent aussi les règles de l'hôte pour les +outils auxiliaires imbriqués : `tools.apply_patch` prend une seule chaîne qui commence et se termine +par les lignes de marqueur de patch seules, sans habillage ; l'isolate ne dispose pas de `import`, +et les commandes longues sont interrogées via `write_stdin`. Lorsqu'un résultat exec en mode code +sur le chemin natif Responses routé, Kiro ou Cursor contient encore l'un des messages d'échec de +l'hôte, opencodex ajoute une indication d'une ligne qui nomme la règle. Cette modification ne +réécrit ni le code du modèle ni le texte de son patch. + Le fournisseur sélectionné doit prendre en charge les appels de fonctions ou d'outils. Un fournisseur purement textuel dépourvu de cette prise en charge ne peut pas utiliser `exec`, Browser ni Computer Use. Les lignes OpenAI natives conservent leur mode d'outil en amont. diff --git a/docs-site/src/content/docs/ja/guides/codex-integration.md b/docs-site/src/content/docs/ja/guides/codex-integration.md index d1d977b35c..46c33320f2 100644 --- a/docs-site/src/content/docs/ja/guides/codex-integration.md +++ b/docs-site/src/content/docs/ja/guides/codex-integration.md @@ -147,6 +147,14 @@ Codex の `exec` custom-tool grammar を受け付けない key-auth Responses pr `custom_tool_call` へ復元します。ネイティブ OpenAI の forward routing と、対応済みの `apply_patch` custom tool は 変更されません。 +ルーティングされた code-mode のターンには、最初の呼び出し前に、ネストされたヘルパーに関する +ホストの規則も伝えられます。`tools.apply_patch` は、装飾を付けないパッチマーカー行で始まり、 +同様のマーカー行で終わる単一の文字列を受け取ります。isolate では `import` を使用できず、 +長時間実行されるコマンドは `write_stdin` でポーリングします。ネイティブのルーティング済み Responses、 +Kiro、または Cursor の経路で、code-mode の exec 結果にホストの失敗メッセージがまだ含まれている場合、 +opencodex は該当する規則を示す 1 行のヒントを追加します。この変更でモデルのコードやパッチのテキストを +書き換えることはありません。 + 選択した provider は function/tool calling をサポートしている必要があります。tool call に対応しない text-only provider では `exec`、Browser、Computer Use は使用できません。ネイティブ OpenAI の項目は上流の tool mode を そのまま維持します。 diff --git a/docs-site/src/content/docs/ko/guides/codex-integration.md b/docs-site/src/content/docs/ko/guides/codex-integration.md index 44551de837..1f324adaf2 100644 --- a/docs-site/src/content/docs/ko/guides/codex-integration.md +++ b/docs-site/src/content/docs/ko/guides/codex-integration.md @@ -149,6 +149,13 @@ history를 업스트림 function tool로 인코딩한 다음 스트리밍된 fun `custom_tool_call`로 복원합니다. 네이티브 OpenAI forward routing과 지원되는 `apply_patch` custom tool은 변경되지 않습니다. +라우팅된 code-mode 턴에는 첫 호출 전에 중첩 helper에 대한 호스트 규칙도 전달됩니다. +`tools.apply_patch`는 별도 장식 없이 패치 마커만 있는 줄로 시작하고 끝나는 하나의 문자열을 받습니다. +isolate에서는 `import`를 사용할 수 없으며, 오래 실행되는 명령은 `write_stdin`으로 폴링합니다. +네이티브 라우팅 Responses, Kiro 또는 Cursor 경로의 code-mode exec 결과에 호스트의 실패 메시지 중 +하나가 여전히 포함되어 있으면, opencodex는 해당 규칙을 명시하는 한 줄짜리 힌트를 덧붙입니다. +이 변경은 모델의 코드나 패치 텍스트를 다시 작성하지 않습니다. + 선택한 provider는 function/tool calling을 지원해야 합니다. tool call을 지원하지 않는 text-only provider에서는 `exec`, Browser 또는 Computer Use를 사용할 수 없습니다. 네이티브 OpenAI 항목은 업스트림 tool mode를 그대로 유지합니다. diff --git a/docs-site/src/content/docs/ru/guides/codex-integration.md b/docs-site/src/content/docs/ru/guides/codex-integration.md index 9707a3ea44..23581e56f6 100644 --- a/docs-site/src/content/docs/ru/guides/codex-integration.md +++ b/docs-site/src/content/docs/ru/guides/codex-integration.md @@ -224,6 +224,14 @@ opencodex кодирует объявление и историю как functio потоковый lifecycle function call в `custom_tool_call` до передачи в Codex. Нативная forward- маршрутизация OpenAI и поддерживаемый custom tool `apply_patch` остаются без изменений. +Перед первым вызовом маршрутизируемые ходы в code-mode также получают правила хоста для вложенных +вспомогательных инструментов: `tools.apply_patch` принимает одну строку, которая начинается и +заканчивается отдельными строками маркеров патча без дополнительного оформления; в isolate нет +`import`, а длительные команды опрашиваются через `write_stdin`. Если результат exec в code-mode +на нативном маршрутизируемом пути Responses, Kiro или Cursor всё ещё содержит одно из сообщений +хоста об ошибке, opencodex добавляет однострочную подсказку с указанием правила. Это изменение +не переписывает код модели или текст её патча. + Выбранный provider должен поддерживать function/tool calling. Text-only provider без tool calls не может использовать `exec`, Browser или Computer Use. Нативные записи OpenAI сохраняют свой upstream tool mode без изменений. diff --git a/docs-site/src/content/docs/tr/guides/codex-integration.md b/docs-site/src/content/docs/tr/guides/codex-integration.md index 02fae0f468..d13af52274 100644 --- a/docs-site/src/content/docs/tr/guides/codex-integration.md +++ b/docs-site/src/content/docs/tr/guides/codex-integration.md @@ -262,6 +262,14 @@ fonksiyon aracı olarak kodlar, ardından akışlı fonksiyon çağrısı yaşam Codex görmeden önce `custom_tool_call`'a geri yükler. Yerel OpenAI iletme yönlendirmesi ve desteklenen `apply_patch` özel aracı değişmeden kalır. +Yönlendirilen code-mode turlarına, ilk çağrıdan önce iç içe geçmiş yardımcılar için geçerli olan +ana makine kuralları da bildirilir: `tools.apply_patch`, yalnızca yama işaretçilerinden oluşan +satırlarla başlayan ve biten tek bir dize alır; isolate içinde `import` yoktur ve uzun süren +komutlar `write_stdin` üzerinden yoklanır. Yerel yönlendirilmiş Responses, Kiro veya Cursor yolundaki +bir code-mode exec sonucu hâlâ ana makinenin hata mesajlarından birini içeriyorsa opencodex, +ilgili kuralı belirten tek satırlık bir ipucu ekler. Bu değişiklik modelin kodunu veya yama metnini +yeniden yazmaz. + Seçilen sağlayıcı fonksiyon/araç çağrısını desteklemelidir. Araç çağrısı desteği olmayan salt metin bir sağlayıcı `exec`, Tarayıcı veya Bilgisayar Kullanımını kullanamaz. Yerel OpenAI satırları yukarı akış araç modunu değiştirmeden tutar. diff --git a/docs-site/src/content/docs/zh-cn/guides/codex-integration.md b/docs-site/src/content/docs/zh-cn/guides/codex-integration.md index 552c0c3f53..0c3df0c0e2 100644 --- a/docs-site/src/content/docs/zh-cn/guides/codex-integration.md +++ b/docs-site/src/content/docs/zh-cn/guides/codex-integration.md @@ -196,6 +196,12 @@ Codex 显示的模型来自一个磁盘上的 catalog(默认是 `$CODEX_HOME/o 历史记录编码成上游 function tool,再在 Codex 收到结果前,把流式 function-call lifecycle 还原成 `custom_tool_call`。原生 OpenAI forward routing 和已支持的 `apply_patch` custom tool 保持不变。 +路由的 code-mode 轮次还会在首次调用前收到宿主对嵌套辅助工具的规则:`tools.apply_patch` +接收一个字符串,首尾必须是没有额外包装的独立补丁标记行;isolate 中没有 `import`,长时间运行的 +命令通过 `write_stdin` 轮询。如果原生路由 Responses、Kiro 或 Cursor 路径上的 code-mode exec +结果仍包含宿主的某条失败消息,opencodex 会追加一行提示,指出对应规则。此变更不会重写模型的 +代码或补丁文本。 + 所选 provider 必须支持 function/tool calling。不支持 tool call 的 text-only provider 无法使用 `exec`、 Browser 或 Computer Use。原生 OpenAI 条目会保持其上游 tool mode 不变。 diff --git a/docs-site/src/content/docs/zh-tw/guides/codex-integration.md b/docs-site/src/content/docs/zh-tw/guides/codex-integration.md index f371457be9..44ee5bbb3b 100644 --- a/docs-site/src/content/docs/zh-tw/guides/codex-integration.md +++ b/docs-site/src/content/docs/zh-tw/guides/codex-integration.md @@ -201,6 +201,12 @@ metadata,使用 Codex 的 `low | medium | high | xhigh | max | ultra` 檔位 歷史編碼成上游 function tool,再於 Codex 看見前將串流 function-call lifecycle 還原成 `custom_tool_call`。原生 OpenAI forward 路由與受支援的 `apply_patch` custom tool 維持不變。 +路由的 code-mode 回合也會在首次呼叫前收到主機對巢狀輔助工具的規則:`tools.apply_patch` +接收一個字串,開頭與結尾必須是沒有額外包裝的獨立補丁標記行;isolate 中沒有 `import`,長時間執行的 +命令透過 `write_stdin` 輪詢。如果原生路由 Responses、Kiro 或 Cursor 路徑上的 code-mode exec +結果仍包含主機的某則失敗訊息,opencodex 會附加一行提示,指出對應規則。這項變更不會重寫模型的 +程式碼或補丁文字。 + 所選 provider 必須支援 function/tool calling。不支援 tool call 的純文字 provider 無法使用 `exec`、 Browser 或 Computer Use。原生 OpenAI 列保留上游 tool mode 不變。 From f1b8f2d2f1edee55b68202469f86a5334710688d Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 19:07:57 +0900 Subject: [PATCH 123/412] fix(gui): keep fallback render identities in state [skip ci] CI 34106956362 gates101697798420: remove render-time ref access and dynamic selector construction while preserving occurrence identity and keyboard focus. Co-authored-by: x3M3x <98298256+x3M3x@users.noreply.github.com> --- .../SubagentDelegationSection.tsx | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx b/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx index 6fe043461c..a1b405c2d9 100644 --- a/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx +++ b/gui/src/components/subagents-workspace/SubagentDelegationSection.tsx @@ -64,15 +64,22 @@ export default function SubagentDelegationSection({ && !(ultraMode.multiAgentMode === "v2" && ultraMode.keepNativeChatGptOnV1)); const showV2Compatibility = !ultraLoadFailed && ultraMode.loaded === true && routedPreferred && nativeMayUseV2; const fallbackControlsRef = useRef(null); - const nextRowId = useRef(0); - const rowIdentity = useRef>([]); - // Reuse each configured occurrence across reorder; duplicates have distinct IDs. - if (rowIdentity.current.length !== fallback.length || rowIdentity.current.some((row, i) => row.model !== fallback[i])) { - const remaining = [...rowIdentity.current]; - rowIdentity.current = fallback.map(modelName => { + const [identity, setIdentity] = useState(() => ({ + models: fallback, + rows: fallback.map((rowModel, id) => ({ model: rowModel, id })), + nextId: fallback.length, + })); + let rows = identity.rows; + // Keys are render state. Guarded prop reconciliation retains each occurrence; + // event handlers move the same identities with their corresponding models. + if (identity.models !== fallback) { + const remaining = [...identity.rows]; + let nextId = identity.nextId; + rows = fallback.map(modelName => { const old = remaining.findIndex(row => row.model === modelName); - return old >= 0 ? remaining.splice(old, 1)[0] : { model: modelName, id: nextRowId.current++ }; + return old >= 0 ? remaining.splice(old, 1)[0] : { model: modelName, id: nextId++ }; }); + setIdentity({ models: fallback, rows, nextId }); } const pendingFocus = useRef<{ row: number; action: string } | null>(null); useLayoutEffect(() => { @@ -80,7 +87,8 @@ export default function SubagentDelegationSection({ if (!target) return; pendingFocus.current = null; const row = fallbackControlsRef.current?.querySelectorAll(".swi-fallback-row")[target.row]; - const action = row?.querySelector(`button[data-action="${target.action}"]:not(:disabled)`) + const enabledActions = row?.querySelectorAll("button[data-action]:not(:disabled)"); + const action = Array.from(enabledActions ?? []).find(button => button.dataset.action === target.action) ?? row?.querySelector("button:not(:disabled)") ?? fallbackControlsRef.current?.querySelector('button[role="combobox"]'); action?.focus(); @@ -91,7 +99,9 @@ export default function SubagentDelegationSection({ const target = index + direction; if (fallbackBusy || target < 0 || target >= next.length) return; [next[index], next[target]] = [next[target], next[index]]; - [rowIdentity.current[index], rowIdentity.current[target]] = [rowIdentity.current[target], rowIdentity.current[index]]; + const nextRows = [...rows]; + [nextRows[index], nextRows[target]] = [nextRows[target], nextRows[index]]; + setIdentity({ ...identity, models: next, rows: nextRows }); pendingFocus.current = { row: target, action: direction === -1 ? "up" : "down" }; onFallbackChange(next); }; @@ -160,7 +170,7 @@ export default function SubagentDelegationSection({
{fallback.map((modelName, index) => ( -
+
{index + 1}. {modelName} {!availableModels.includes(modelName) && {t("sub.fallbackUnavailable")}} @@ -168,9 +178,10 @@ export default function SubagentDelegationSection({
From 1ca1a56615e779407e85bcda93f2e27f280d8a26 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 18:24:07 +0900 Subject: [PATCH 124/412] fix(release): recover registry reads after acknowledged publication [skip ci] --- .github/workflows/release.yml | 40 ++++++--- tests/ci-workflows/ci-workflows.test.ts | 105 ++++++++++++++++++++++++ 2 files changed, 133 insertions(+), 12 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 685a13876b..339de6d9ea 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -334,40 +334,56 @@ jobs: } - name: Publish (or dry-run) + id: publication env: DRY_RUN: ${{ inputs.dry-run }} NPM_DIST_TAG: ${{ inputs.tag }} run: | + set -euo pipefail if [ "$DRY_RUN" = "true" ]; then echo "::notice::DRY RUN — building + packing, not publishing" npm run prepublishOnly npm pack --dry-run else npm publish --tag "$NPM_DIST_TAG" --access public + echo "published=true" >> "$GITHUB_OUTPUT" fi - # Confirm the registry actually has the new version (real publishes only). + # Publication is acknowledged before registry reads, which can lag or fail. + # Recover only observation failures in this run; never retry npm publish. - name: Post-publish registry smoke - if: ${{ inputs.dry-run != true }} + id: registry-smoke + if: ${{ inputs.dry-run != true && steps.publication.outputs.published == 'true' }} env: RELEASE_VERSION: ${{ inputs.version }} + PUBLISHED: ${{ steps.publication.outputs.published }} run: | - for attempt in $(seq 1 30); do - if VERSION=$(npm view "@bitkyc08/opencodex@${RELEASE_VERSION}" version 2>/dev/null); then + set -euo pipefail + test "$PUBLISHED" = "true" || { + echo "::error::No successful publication receipt; refusing registry recovery" + exit 1 + } + for attempt in $(seq 1 6); do + if VERSION=$(timeout --kill-after=2s 10s npm view "@bitkyc08/opencodex@${RELEASE_VERSION}" version --fetch-retries=0 --fetch-timeout=8000 2>/dev/null); then + if [ "$VERSION" != "$RELEASE_VERSION" ]; then + echo "::error::Registry returned an unexpected version; refusing to create a release" + exit 1 + fi echo "registry version=$VERSION" - test "$VERSION" = "$RELEASE_VERSION" - npm dist-tag ls @bitkyc08/opencodex + echo "verification=verified" >> "$GITHUB_OUTPUT" + echo "Registry verified @bitkyc08/opencodex@${RELEASE_VERSION}." >> "$GITHUB_STEP_SUMMARY" + timeout --kill-after=2s 10s npm dist-tag ls @bitkyc08/opencodex --fetch-retries=0 --fetch-timeout=8000 || echo "::warning::Could not read npm dist-tags; exact version was verified" exit 0 fi - echo "::notice::@bitkyc08/opencodex@${RELEASE_VERSION} not visible in npm registry yet (attempt $attempt/30)" - sleep 10 + echo "::notice::Registry lookup not confirmed (attempt $attempt/6)" + if [ "$attempt" -lt 6 ]; then sleep 5; fi done - echo "::error::npm registry smoke failed after 30 attempts" - npm view @bitkyc08/opencodex versions dist-tags --json || true - exit 1 + echo "verification=pending" >> "$GITHUB_OUTPUT" + echo "::warning::npm publish succeeded, but registry verification remains pending; continuing GitHub release creation without republishing" + echo "Publication acknowledged for @bitkyc08/opencodex@${RELEASE_VERSION}; registry verification pending after bounded reads. Inspect the registry before announcing availability. Do not republish this version." >> "$GITHUB_STEP_SUMMARY" - name: Create GitHub release - if: ${{ inputs.dry-run != true }} + if: ${{ inputs.dry-run != true && steps.publication.outputs.published == 'true' }} env: GH_TOKEN: ${{ github.token }} RELEASE_VERSION: ${{ inputs.version }} diff --git a/tests/ci-workflows/ci-workflows.test.ts b/tests/ci-workflows/ci-workflows.test.ts index c967f9d4c0..d2bef0d24f 100644 --- a/tests/ci-workflows/ci-workflows.test.ts +++ b/tests/ci-workflows/ci-workflows.test.ts @@ -1,5 +1,8 @@ import { describe, expect, test } from "bun:test"; import { fileURLToPath } from "node:url"; +import { mkdtempSync, readFileSync, writeFileSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; import { SCRIPT_BINDINGS, callsTo, @@ -5514,3 +5517,105 @@ describe("gui exhaustive-deps suppression stays scoped and effective", () => { expect(models).not.toContain("react-doctor-disable-next-line"); }); }); + + +interface PublicationStep { name: string; id?: string; if?: string; run?: string } +async function publicationSteps(): Promise { + const yaml = Bun.YAML.parse(await readText(".github/workflows/release.yml")) as { + jobs: { publish: { steps: PublicationStep[] } }; + }; + return yaml.jobs.publish.steps; +} + +test("release recovery requires same-run publication and preserves successful-step gating", async () => { + const steps = await publicationSteps(); + const publish = steps.find(step => step.name === "Publish (or dry-run)")!; + const smoke = steps.find(step => step.name === "Post-publish registry smoke")!; + const release = steps.find(step => step.name === "Create GitHub release")!; + expect(publish.id).toBe("publication"); + expect(smoke.id).toBe("registry-smoke"); + for (const step of [smoke, release]) { + expect(step.if).toBe("${{ inputs.dry-run != true && steps.publication.outputs.published == 'true' }}"); + } + expect(steps.indexOf(publish)).toBeLessThan(steps.indexOf(smoke)); + expect(steps.indexOf(smoke)).toBeLessThan(steps.indexOf(release)); +}); + +// This executes the ubuntu-latest release job's Bash, not the Windows runtime. +// Structural workflow guards above still execute on every platform. +test.skipIf(process.platform === "win32")("release shell recovers only unverified reads after acknowledged publication", async () => { + const steps = await publicationSteps(); + const publish = steps.find(step => step.name === "Publish (or dry-run)")!.run!; + const smoke = steps.find(step => step.name === "Post-publish registry smoke")!.run!; + const scenarios = [ + { mode: "match", dry: false, status: 0, receipt: true, verification: "verified", reads: 1 }, + { mode: "delayed", dry: false, status: 0, receipt: true, verification: "verified", reads: 3 }, + { mode: "unavailable", dry: false, status: 0, receipt: true, verification: "pending", reads: 6 }, + { mode: "timeout", dry: false, status: 0, receipt: true, verification: "pending", reads: 6 }, + { mode: "wrong", dry: false, status: 1, receipt: true, verification: "", reads: 1 }, + { mode: "empty", dry: false, status: 1, receipt: true, verification: "", reads: 1 }, + { mode: "dist-failure", dry: false, status: 0, receipt: true, verification: "verified", reads: 1 }, + { mode: "publish-failure", dry: false, status: 23, receipt: false, verification: "", reads: 0 }, + { mode: "match", dry: true, status: 0, receipt: false, verification: "", reads: 0 }, + { mode: "missing-receipt", dry: false, status: 1, receipt: false, verification: "", reads: 0 }, + ]; + for (const scenario of scenarios) { + const dir = mkdtempSync(join(tmpdir(), "ocx-publication-")); + const output = join(dir, "output"); + const summary = join(dir, "summary"); + const calls = join(dir, "calls"); + for (const path of [output, summary, calls]) writeFileSync(path, ""); + const prelude = String.raw` + npm() { + echo "$*" >> "$CALLS" + case "$1" in + publish) [ "$SCENARIO" != "publish-failure" ] || return 23 ;; + view) + count=$(cat "$COUNTER" 2>/dev/null || echo 0) + count=$((count + 1)); echo "$count" > "$COUNTER" + case "$SCENARIO" in + unavailable) return 1 ;; + timeout) return 124 ;; + delayed) [ "$count" -ge 3 ] || return 1 ;; + wrong) echo 0.0.0; return 0 ;; + empty) return 0 ;; + esac + echo "$RELEASE_VERSION" ;; + dist-tag) [ "$SCENARIO" != "dist-failure" ] || return 1 ;; + esac + } + timeout() { + # The wrapper is stubbed, but its production process bounds are asserted. + [ "$1" = "--kill-after=2s" ] && [ "$2" = "10s" ] || return 99 + shift 2; "$@" + } + sleep() { echo "sleep $*" >> "$CALLS"; } + `; + try { + const script = prelude + (scenario.mode === "missing-receipt" ? "" : publish) + '\n' + + (scenario.dry ? "" : `PUBLISHED=$(sed -n 's/^published=//p' "$GITHUB_OUTPUT")\n${smoke}`); + const child = Bun.spawn(["bash", "--noprofile", "--norc", "-e", "-o", "pipefail", "-c", script], { + env: { ...process.env, SCENARIO: scenario.mode, DRY_RUN: String(scenario.dry), + NPM_DIST_TAG: "latest", RELEASE_VERSION: "9.8.7", GITHUB_OUTPUT: output, + GITHUB_STEP_SUMMARY: summary, CALLS: calls, COUNTER: join(dir, "counter") }, + stdin: "ignore", stdout: "pipe", stderr: "pipe", + }); + const [status, stdout, stderr] = await Promise.all([ + child.exited, new Response(child.stdout).text(), new Response(child.stderr).text(), + ]); + expect({ scenario: scenario.mode, status, stderr }).toEqual({ scenario: scenario.mode, status: scenario.status, stderr: "" }); + const receipt = readFileSync(output, "utf8"); + const log = readFileSync(calls, "utf8").trim().split("\n"); + expect(receipt.includes("published=true")).toBe(scenario.receipt); + expect(receipt.includes("verification=")).toBe(scenario.verification !== ""); + if (scenario.verification) expect(receipt).toContain(`verification=${scenario.verification}`); + expect(log.filter(line => line.startsWith("view "))).toHaveLength(scenario.reads); + expect(log.filter(line => line.startsWith("publish "))).toHaveLength(scenario.dry || scenario.mode === "missing-receipt" ? 0 : 1); + if (scenario.verification === "pending") { + expect(stdout).toContain("::warning::npm publish succeeded"); + expect(readFileSync(summary, "utf8")).toContain("registry verification pending"); + expect(log.filter(line => line === "sleep 5")).toHaveLength(5); + } + } finally { rmSync(dir, { recursive: true, force: true }); } + } +}); From 56f356d65f153533164e52c549e77baa0e7a8650 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 19:07:45 +0900 Subject: [PATCH 125/412] fix(release): bind registry checks to package metadata [skip ci] --- .github/workflows/release.yml | 9 +++++---- tests/ci-workflows/ci-workflows.test.ts | 11 +++++++++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 339de6d9ea..7b565b6800 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -363,16 +363,17 @@ jobs: echo "::error::No successful publication receipt; refusing registry recovery" exit 1 } + pkg_name="$(node -p "require('./package.json').name")" for attempt in $(seq 1 6); do - if VERSION=$(timeout --kill-after=2s 10s npm view "@bitkyc08/opencodex@${RELEASE_VERSION}" version --fetch-retries=0 --fetch-timeout=8000 2>/dev/null); then + if VERSION=$(timeout --kill-after=2s 10s npm view "${pkg_name}@${RELEASE_VERSION}" version --fetch-retries=0 --fetch-timeout=8000 2>/dev/null); then if [ "$VERSION" != "$RELEASE_VERSION" ]; then echo "::error::Registry returned an unexpected version; refusing to create a release" exit 1 fi echo "registry version=$VERSION" echo "verification=verified" >> "$GITHUB_OUTPUT" - echo "Registry verified @bitkyc08/opencodex@${RELEASE_VERSION}." >> "$GITHUB_STEP_SUMMARY" - timeout --kill-after=2s 10s npm dist-tag ls @bitkyc08/opencodex --fetch-retries=0 --fetch-timeout=8000 || echo "::warning::Could not read npm dist-tags; exact version was verified" + echo "Registry verified ${pkg_name}@${RELEASE_VERSION}." >> "$GITHUB_STEP_SUMMARY" + timeout --kill-after=2s 10s npm dist-tag ls "$pkg_name" --fetch-retries=0 --fetch-timeout=8000 || echo "::warning::Could not read npm dist-tags; exact version was verified" exit 0 fi echo "::notice::Registry lookup not confirmed (attempt $attempt/6)" @@ -380,7 +381,7 @@ jobs: done echo "verification=pending" >> "$GITHUB_OUTPUT" echo "::warning::npm publish succeeded, but registry verification remains pending; continuing GitHub release creation without republishing" - echo "Publication acknowledged for @bitkyc08/opencodex@${RELEASE_VERSION}; registry verification pending after bounded reads. Inspect the registry before announcing availability. Do not republish this version." >> "$GITHUB_STEP_SUMMARY" + echo "Publication acknowledged for ${pkg_name}@${RELEASE_VERSION}; registry verification pending after bounded reads. Inspect the registry before announcing availability. Do not republish this version." >> "$GITHUB_STEP_SUMMARY" - name: Create GitHub release if: ${{ inputs.dry-run != true && steps.publication.outputs.published == 'true' }} diff --git a/tests/ci-workflows/ci-workflows.test.ts b/tests/ci-workflows/ci-workflows.test.ts index d2bef0d24f..b098220521 100644 --- a/tests/ci-workflows/ci-workflows.test.ts +++ b/tests/ci-workflows/ci-workflows.test.ts @@ -5519,7 +5519,7 @@ describe("gui exhaustive-deps suppression stays scoped and effective", () => { }); -interface PublicationStep { name: string; id?: string; if?: string; run?: string } +interface PublicationStep { name: string; id?: string; if?: string; run?: string; env?: Record } async function publicationSteps(): Promise { const yaml = Bun.YAML.parse(await readText(".github/workflows/release.yml")) as { jobs: { publish: { steps: PublicationStep[] } }; @@ -5534,6 +5534,7 @@ test("release recovery requires same-run publication and preserves successful-st const release = steps.find(step => step.name === "Create GitHub release")!; expect(publish.id).toBe("publication"); expect(smoke.id).toBe("registry-smoke"); + expect(smoke.env?.PUBLISHED).toBe("${{ steps.publication.outputs.published }}"); for (const step of [smoke, release]) { expect(step.if).toBe("${{ inputs.dry-run != true && steps.publication.outputs.published == 'true' }}"); } @@ -5566,6 +5567,7 @@ test.skipIf(process.platform === "win32")("release shell recovers only unverifie const calls = join(dir, "calls"); for (const path of [output, summary, calls]) writeFileSync(path, ""); const prelude = String.raw` + node() { echo "@fixture/renamed"; } npm() { echo "$*" >> "$CALLS" case "$1" in @@ -5609,7 +5611,12 @@ test.skipIf(process.platform === "win32")("release shell recovers only unverifie expect(receipt.includes("published=true")).toBe(scenario.receipt); expect(receipt.includes("verification=")).toBe(scenario.verification !== ""); if (scenario.verification) expect(receipt).toContain(`verification=${scenario.verification}`); - expect(log.filter(line => line.startsWith("view "))).toHaveLength(scenario.reads); + const reads = log.filter(line => line.startsWith("view ")); + expect(reads).toHaveLength(scenario.reads); + for (const read of reads) expect(read).toBe("view @fixture/renamed@9.8.7 version --fetch-retries=0 --fetch-timeout=8000"); + const tags = log.filter(line => line.startsWith("dist-tag ")); + expect(tags).toEqual(scenario.verification === "verified" + ? ["dist-tag ls @fixture/renamed --fetch-retries=0 --fetch-timeout=8000"] : []); expect(log.filter(line => line.startsWith("publish "))).toHaveLength(scenario.dry || scenario.mode === "missing-receipt" ? 0 : 1); if (scenario.verification === "pending") { expect(stdout).toContain("::warning::npm publish succeeded"); From 609105cf9148ca18decfc81e8d1859e30af3aff9 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 18:22:37 +0900 Subject: [PATCH 126/412] docs: plan lane D manual release chain [skip ci] --- devlog/_plan/260907_lane_d/000_plan.md | 32 +++++++++++++++++++ devlog/_plan/260907_lane_d/010_thinking.md | 24 ++++++++++++++ devlog/_plan/260907_lane_d/020_receipt.md | 12 +++++++ .../_plan/260907_lane_d/030_account_prices.md | 13 ++++++++ .../_plan/260907_lane_d/040_price_editor.md | 23 +++++++++++++ .../_plan/260907_lane_d/050_usage_ranges.md | 30 +++++++++++++++++ 6 files changed, 134 insertions(+) create mode 100644 devlog/_plan/260907_lane_d/000_plan.md create mode 100644 devlog/_plan/260907_lane_d/010_thinking.md create mode 100644 devlog/_plan/260907_lane_d/020_receipt.md create mode 100644 devlog/_plan/260907_lane_d/030_account_prices.md create mode 100644 devlog/_plan/260907_lane_d/040_price_editor.md create mode 100644 devlog/_plan/260907_lane_d/050_usage_ranges.md diff --git a/devlog/_plan/260907_lane_d/000_plan.md b/devlog/_plan/260907_lane_d/000_plan.md new file mode 100644 index 0000000000..97f6761463 --- /dev/null +++ b/devlog/_plan/260907_lane_d/000_plan.md @@ -0,0 +1,32 @@ +# Lane D release-train roadmap + +Satisfy-spec HOTL for delegated recommendations #16 → #17 → #15 → #21 → #25. +Goal: independently audited manual dependent PRs ready for main-session integration. +Scope: Claude outbound, display-name dialog, usage costs/overlays/summary, usage GUI, +plus directly required CLI/API/tests/docs. i18n files are append-only shared per main's +2026-09-07 correction. No other lane-owned files; no merge/release/main/preview. +No local test/typecheck/build/install. Remote ci.yml lane=all at final top SHA is +sole product verifier. Local source and diff checks are not execution evidence. +No user token or wall-clock bound supplied. Use existing repo/GitHub authorization. +Stop: top-head green with reviewer verdicts and layer PR/SHA evidence; otherwise +record exact DEFER/BLOCKED reasons without claiming implementation passes. +Memory/evidence: this unit plus .tmp/lane-d for review drafts. Unpublished security +material stays in scratch. Reclaim failed delegated work after two distinct agents; +other-lane file collision requires main coordination. + +## Dependency and publication map + +| Phase | Item | Outcome | Branch | +|---|---|---|---| +| 0 | Roadmap | Lock all diff plans before code | first layer docs | +| 1 | #3719 slice | Legacy redacted-before-signed SSE/JSON parity | codex/260907-d1-thinking | +| 2 | receipt guard | Prevent new intent while recovery is pending | codex/260907-d2-receipt | +| 3 | #3817 | Exact account identity resolves provider overlays | codex/260907-d3-account-prices | +| 4 | #3667 | Price editor + CLI + authoritative explicit zero | codex/260907-d4-price-editor | +| 5 | #3379 slice / #2956 | Inclusive custom usage bounds + GUI | codex/260907-d5-usage-ranges | +| 6 | readiness | Fresh top CI, screenshots and implementation audits | top branch | + +All lower subjects include [skip ci]; every push uses --no-verify. Native stack null. +Only phase 6 dispatches ci.yml lane=all; failures get Astra-high exact-log diagnosis, +fixes on their owning layer and rebase --update-refs cascade. Main alone merges. +#3719 and #3379 stay open. #2956 credit uses verified GitHub author identity. diff --git a/devlog/_plan/260907_lane_d/010_thinking.md b/devlog/_plan/260907_lane_d/010_thinking.md new file mode 100644 index 0000000000..e321ac03ce --- /dev/null +++ b/devlog/_plan/260907_lane_d/010_thinking.md @@ -0,0 +1,24 @@ +# 010 Thinking ordering +MODIFY src/claude/outbound.ts ensureBlock/closeOpenBlock and reasoning done. +Before: thinking start/deltas are emitted immediately; done closes thinking then red. +After: retain already-budgeted thinking text, defer its start/index/delta until close; +reasoning done emits red blocks before flushing pending signed thinking. Preserve text +and tool order, hidden env.txt non-disclosure, genuine signature and budget release. +MODIFY tests/claude-integration/claude-outbound.test.ts: compare collected SSE against +literal expected content and JSON for combined envelopes with preceding deltas, +multiple summary parts/red blocks, text prefix, signed-only, red-only. Check sequential +non-overlapping block indices and cancellation/overflow existing assertions. +Independent Astra audit must resolve streaming latency and allocation implications. + +Verification: NOT RUN locally by user instruction; focused tests execute in final top-head Cross-platform CI. + +## A audit fold-back +Astra Dirac found two blockers: unmatched-item reordering and closure memory overlap. +Track bounded reasoningItemKey separately from part identity; flush on changed explicit +item identity, and close unrelated pending thinking before another item's red blocks. +Only same identity (including both omitted) reorders red before pending thinking. +Release retained thinkingBuf after text frame enqueue, before signature frame enqueue; +queued frame budget stays authoritative, never weakened. Add near-limit valid control, +shared-budget collector control, overflow/cancel regressions. Deferred thinking is an +accepted visible-latency tradeoff; text/tool frames remain live with incremental-reader +coverage. Late done after a different emitted block cannot reorder earlier content. diff --git a/devlog/_plan/260907_lane_d/020_receipt.md b/devlog/_plan/260907_lane_d/020_receipt.md new file mode 100644 index 0000000000..7b710df91e --- /dev/null +++ b/devlog/_plan/260907_lane_d/020_receipt.md @@ -0,0 +1,12 @@ +# 020 Display-name receipt recovery +MODIFY gui/src/components/ModelDisplayNameDialog.tsx. +Before: input/reset enabled whenever saving=false; input onEdit clears recovery. +After: new mutationOutcomeUnknown prop from Models.tsx recovery.confirmed===false +disables draft editing and reset, submit retains +read/retry action. Handler guards prevent synthetic events bypassing disabled controls. +Close/cancel stays available. This is bounded UI recovery, not server request ordering. +MODIFY gui/tests/models-display-name-editor.test.tsx: unknown receipt cannot replace intent; retry recovers; confirmed saved:true +and ordinary validation error remain +editable. Screenshot changed disabled input/reset with retry available. + +Verification: NOT RUN locally by user instruction; focused tests execute in final top-head Cross-platform CI. diff --git a/devlog/_plan/260907_lane_d/030_account_prices.md b/devlog/_plan/260907_lane_d/030_account_prices.md new file mode 100644 index 0000000000..4806657cdb --- /dev/null +++ b/devlog/_plan/260907_lane_d/030_account_prices.md @@ -0,0 +1,13 @@ +# 030 Account price identity +MODIFY src/usage/user-cost-overlays.ts registry refresh and signature/version. +Before: configured provider set and overlay rows only. +After: exact account identifiers/log labels from config mapped to established provider +identity. Include mapping in signature for memo and aggregate cache invalidation. +MODIFY src/usage/cost.ts resolveMatchedPrice: exact configured namespace and exact +user overlay precede account identity; unresolved suffix is never guessed/stripped. +MODIFY tests/usage/usage-cost.test.ts or existing provider-overlay tests: custom account +id, qualified id, stable log label, configured collision, unrelated hyphenated provider, +account rename/removal invalidation. Account aliases never become identity authority. +Audit determines precise supported historical labels from actual producer evidence. + +Verification: NOT RUN locally by user instruction; focused tests execute in final top-head Cross-platform CI. diff --git a/devlog/_plan/260907_lane_d/040_price_editor.md b/devlog/_plan/260907_lane_d/040_price_editor.md new file mode 100644 index 0000000000..4628710d0d --- /dev/null +++ b/devlog/_plan/260907_lane_d/040_price_editor.md @@ -0,0 +1,23 @@ +# 040 Manual price editor +MODIFY src/usage/cost.ts userOverlayMatch: valid operator all-zero row returns user +price, while generated catalog zeros keep unknown/fallback semantics. +MODIFY src/server/management/model-routes.ts: exact-provider model-costs GET/PUT, +validate four finite nonnegative bounded rates or null reset, preserve siblings, +rollback on persist failure, no routing/catalog mutation required for price-only edits. +MODIFY src/cli/models-runtime.ts, models-runtime-subcommands.ts and capabilities.ts: +models set-price provider/model --input N --output N [--cache-read N --cache-write N] +or --auto. GET for show and PUT for set/reset through existing management client. +ADD gui/src/components/ModelPriceDialog.tsx; MODIFY Models.tsx and models-shared.ts +only as needed: edit action, load exact saved override, inputs 4 rates USD/1M, +save/reset and manual indicator. Reuse dialog/fetch/i18n patterns. All locale keys +append-only pricing.override.*. Add endpoint, CLI, estimator and GUI regressions; +register new test files in both append-only layout manifests. Public docs and generated +CLI surface map mirror actual capability entries; source-generation commands NOT RUN +locally so map is updated by its source contract without claiming verification. + +Verification: NOT RUN locally by user instruction; focused tests execute in final top-head Cross-platform CI. + +A fold-back: add GET/PUT entries in src/server/management/route-registry.ts. +Reuse providerModelCostsConfigError. GET returns sanitized per-provider modelCosts map; +Models owns a typed map loaded with catalog or dedicated GET, so manual badges survive +reload. CLI omitted cache-read/cache-write rates default to zero, explicitly documented. diff --git a/devlog/_plan/260907_lane_d/050_usage_ranges.md b/devlog/_plan/260907_lane_d/050_usage_ranges.md new file mode 100644 index 0000000000..35b6758a76 --- /dev/null +++ b/devlog/_plan/260907_lane_d/050_usage_ranges.md @@ -0,0 +1,30 @@ +# 050 Custom usage windows +REIMPLEMENT range slice from PR #2956 with Manson2438 credit; do not carry offline reports. +ADD src/usage/time-range.ts strict timestamp parser and inclusive since/until bounds; +MODIFY summary.ts accumulator interface to support bounded windows without poisoning +preset daily aggregates. Use stream ledger filtering for partial days if compact daily +partitions cannot answer exact boundaries. Reject malformed/reversed bounds at API/CLI. +MODIFY src/server/management/logs-usage-routes.ts custom-window path before preset cache, +stream/filter into isolated accumulator preserving surface/provider/model and truncation +metadata. Do not persist normalized ledger rows. Include bounds in response. +MODIFY CLI observe/capabilities usage flags and GUI Usage.tsx custom datetime inputs, +independent draft/applied bounds, cache key includes bounds, grid anchored to effective +window, clear returns to preset. All locale keys append-only usage.range.*. +Tests: inclusive boundaries, partial same-day, reversed/invalid, empty ledger, existing +provider/model/surface filters, preset cache after custom query; GUI apply/clear/errors. +Public API/CLI docs describe epoch/ISO contract and local datetime conversion. + +Verification: NOT RUN locally by user instruction; focused tests execute in final top-head Cross-platform CI. + +A fold-back: immutable window option on createUsageSummaryAccumulator; add() checks +inclusive bounds AFTER recording whole-scan snapshot timestamps but BEFORE partitioning. +clone preserves window. summarize uses window endpoint for grid, actual now for generatedAt; +retain 366-day grid cap. Custom queries use isolated row-unique accumulator via existing +getFilteredUsageAggregate with window in key. Reuse overlay/timezone revision restart +and scanner identity controls. Preserve apiKeyId and current filter echo alongside all +other filters. USAGE_RANGES remains preset-only; response range stays selected preset +with customWindow:true, since/until explicit bounds (bounds override preset). API accepts +integer epoch milliseconds or full ISO-8601 with timezone only; require both bounds; +reject negative/unsafe/date-invalid/reversed, never normalize overflow dates. +MODIFY src/cli/usage-report.ts heading prints since/until for customWindow responses. +GUI datetime values become epoch ms locally; end selected minute includes 59.999s. From b462cc54f223a34a10003873870dcc0aa92353b9 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 18:23:28 +0900 Subject: [PATCH 127/412] docs: record lane D roadmap audit decisions [skip ci] --- devlog/_plan/260907_lane_d/001_roadmap_audit.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 devlog/_plan/260907_lane_d/001_roadmap_audit.md diff --git a/devlog/_plan/260907_lane_d/001_roadmap_audit.md b/devlog/_plan/260907_lane_d/001_roadmap_audit.md new file mode 100644 index 0000000000..c14a08d2da --- /dev/null +++ b/devlog/_plan/260907_lane_d/001_roadmap_audit.md @@ -0,0 +1,16 @@ +# Roadmap audit resolution + +Astra Herschel (01a07b2b-5148-73c0-a067-a13485ab32c9) returned +GO-WITH-FIXES with four bounded roadmap corrections. All are incorporated in +040_price_editor.md and 050_usage_ranges.md: register management routes; persist +manual-price display state; filter individual ledger entries before daily aggregation; +preserve apiKeyId and scan consistency; define milliseconds and explicit window bounds. + +Astra Dirac identified two thinking design blockers, recorded in 010 for re-audit: +item ownership and simultaneous reasoning/frame retention. Astra Ohm limits the account +mapping to evidenced Codex identities and requires consistent tier-namespace resolution. +The first implementation phase must finish those fold-backs before code changes. + +Only documentation has changed. Source references were inspected; product tests, +typecheck, builds and installs are NOT RUN by delegation instruction. Product acceptance +remains open until top-head Cross-platform CI executes lane=all. From bf1536607a3036285939f7d2915fb5533f32a53b Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 18:35:28 +0900 Subject: [PATCH 128/412] fix(usage): resolve account prices through provider identity [skip ci] Apply base provider overlays to exact configured Codex account identities without widening arbitrary suffix matching. Preserve pricing namespaces, cache invalidation and tier parity. Refs #3817. Co-authored-by: rrmlima <137737127+rrmlima@users.noreply.github.com> --- .../_plan/260907_lane_d/030_account_prices.md | 14 ++ src/usage/cost.ts | 48 +++-- src/usage/user-cost-overlays.ts | 38 +++- tests/usage/usage-cost.test.ts | 178 ++++++++++++++++++ 4 files changed, 249 insertions(+), 29 deletions(-) diff --git a/devlog/_plan/260907_lane_d/030_account_prices.md b/devlog/_plan/260907_lane_d/030_account_prices.md index 4806657cdb..2ac6e9ccf4 100644 --- a/devlog/_plan/260907_lane_d/030_account_prices.md +++ b/devlog/_plan/260907_lane_d/030_account_prices.md @@ -11,3 +11,17 @@ account rename/removal invalidation. Account aliases never become identity autho Audit determines precise supported historical labels from actual producer evidence. Verification: NOT RUN locally by user instruction; focused tests execute in final top-head Cross-platform CI. + +Astra Ohm audit corrections: config-only identity mapping supports selectable Codex +accounts, effective codexAccountLogLabel, exact ID compatibility aliases, and built-in +main/__main__. Generic OAuth stores are separate and excluded; no free-form inference. +Use exact configured provider before canonical account identity, exact override first. +Apply same namespace for context/priority/lower-bound modifiers, preserving attribution. +Include sorted mapping in version signature, but aliases/plan/reordering stay no-ops. + +Implementation: exact selectable account IDs, effective labels and main forms are resolved +from config at overlay refresh. Only identity changes bump cache versions. Exact configured +providers and explicit user rows remain isolated; context/Fast/lower-bound use the selected +price namespace while request attribution is unchanged. Existing memo fast path is retained. +Regression fixtures cover mappings, collisions, ignored aliases/invalid rows, add/remove/ +label invalidation, presentation no-ops, estimate/attempt/combo and tier parity. diff --git a/src/usage/cost.ts b/src/usage/cost.ts index f7004634c9..2a3b2ae6d3 100644 --- a/src/usage/cost.ts +++ b/src/usage/cost.ts @@ -16,10 +16,10 @@ import { } from "../generated/model-metadata"; import type { AttemptTierOutcome, OcxUsage } from "../types"; import { canonicalFastTierMarker } from "../providers/fastwire"; -import { baseProviderLabel, canonicalUsageProviderLabel } from "../providers/label"; +import { baseProviderLabel } from "../providers/label"; import type { PersistedUsageAttempt, UsageStatus } from "./log"; import { canonicalAntigravityUsageModel } from "../providers/antigravity-models"; -import { activeConfiguredProviders, activeUserCostOverlays, userCostOverlayVersion } from "./user-cost-overlays"; +import { activeAccountPricingProviders, activeConfiguredProviders, activeUserCostOverlays, userCostOverlayVersion } from "./user-cost-overlays"; import { EXPECTED_PRICE_OVERLAYS, findExpectedPriceOverlay, @@ -187,21 +187,18 @@ export function resolveMatchedPrice( userOverlays: readonly ExpectedPriceOverlay[] = activeUserCostOverlays(), options: PriceResolutionOptions = {}, ): MatchedPrice | null { - // User-configured overlays are keyed by the EXACT configured provider name. - // A provider that literally exists in config.providers keeps its own pricing - // namespace: a real custom provider can legitimately end with a label-shaped - // suffix (e.g. acme-pabcdef) and must not inherit the base provider's user - // overlay. Only NON-configured names (generated account log labels) collapse - // to their label base. chatgpt/openai-multi are the same OpenAI usage surface - // and always canonicalize to openai. - const collapsed = baseProviderLabel(provider); - if (collapsed !== provider && (canonicalUsageProviderLabel(provider) !== provider || !activeConfiguredProviders().has(provider))) { + // Literal configured providers win over account identities. Only then use + // config-owned Codex identities, followed by the existing historical suffix + // grammar. Never infer an account by stripping an arbitrary suffix. + const namespace = activeConfiguredProviders().has(provider) + ? provider + : activeAccountPricingProviders().get(provider) ?? baseProviderLabel(provider); + if (namespace !== provider) { + // An exact override (including caller-supplied rows) owns its namespace. + // Unchanged names use the memoized inner lookup's existing user-first order. const exactUserOverlay = userOverlayMatch(provider, modelId, userOverlays); if (exactUserOverlay) return exactUserOverlay; - // Pool/account log suffixes (e.g. google-antigravity-p442fff) must collapse - // before the compiled/overlay lookup; configured providers keep their own - // namespace above. - provider = collapsed; + provider = namespace; } // Memoize by (provider, model): usage summaries iterate hundreds of thousands of // rows that share a handful of provider/model keys, so resolving each time would @@ -466,7 +463,7 @@ function applyContextTier( tier?: ServiceTierInput, ): [Cost4, ContextTierName | undefined, boolean] { if (rawInputTokens === undefined) return [cost4, undefined, false]; - const rule = findContextTier(baseProviderLabel(provider), modelId); + const rule = findContextTier(provider, modelId); if (!rule || !isLongContext(rule, rawInputTokens)) return [cost4, undefined, false]; const confirmedFast = isConfirmedFast(tier); if (confirmedFast && rule.confirmedPriorityRelation === "exclusive") { @@ -494,9 +491,8 @@ function applyPriorityMultiplier( contextTier?: ContextTierName, ): [Cost4, number] { if (canonicalFastTierMarker(tierScalar(serviceTier)) !== "priority") return [cost4, 1]; - const base = baseProviderLabel(provider); - if (contextTier && findContextTier(base, modelId)?.confirmedPriorityRelation !== "stack") return [cost4, 1]; - const rule = findPriorityPricingRule(base, modelId); + if (contextTier && findContextTier(provider, modelId)?.confirmedPriorityRelation !== "stack") return [cost4, 1]; + const rule = findPriorityPricingRule(provider, modelId); if (rule?.requiresResponseConfirmation && !isConfirmedFast(serviceTier)) return [cost4, 1]; const multiplier = rule?.multiplier ?? 1; if (multiplier === 1) return [cost4, 1]; @@ -524,7 +520,7 @@ function isOpenRouterPriorityLowerBound( provider: string, outcome: AttemptTierOutcome | undefined, ): boolean { - return baseProviderLabel(provider) === "openrouter" + return provider === "openrouter" && outcome?.canonical === "priority" && outcome.fastOutcome === "applied" && (outcome.confirmation === "confirmed" || outcome.confirmation === "assumed"); @@ -550,13 +546,13 @@ export function estimateAttemptCost( ? serviceTierContextFromOutcome(attempt.tierOutcome) : serviceTier; const [tieredCost4, contextTier, contextPriorityLowerBound] = applyContextTier( - price.cost4, attempt.provider, attempt.model, attempt.usage.inputTokens, attemptServiceTier, + price.cost4, price.provider, attempt.model, attempt.usage.inputTokens, attemptServiceTier, ); const [effectiveCost4, multiplier] = applyPriorityMultiplier( - tieredCost4, attempt.provider, attempt.model, attemptServiceTier, contextTier, + tieredCost4, price.provider, attempt.model, attemptServiceTier, contextTier, ); const priorityLowerBound = contextPriorityLowerBound - || isOpenRouterPriorityLowerBound(attempt.provider, attempt.tierOutcome); + || isOpenRouterPriorityLowerBound(price.provider, attempt.tierOutcome); return { ordinal: attempt.ordinal, provider: attempt.provider, @@ -635,13 +631,13 @@ export function estimateRequestCost( const price = resolveMatchedPrice(input.provider, input.model, overlays, userOverlays, input); if (!price) return null; const [tieredCost4, contextTier, contextPriorityLowerBound] = applyContextTier( - price.cost4, input.provider, input.model, input.usage.inputTokens, input.serviceTier, + price.cost4, price.provider, input.model, input.usage.inputTokens, input.serviceTier, ); const [effectiveCost4, multiplier] = applyPriorityMultiplier( - tieredCost4, input.provider, input.model, input.serviceTier, contextTier, + tieredCost4, price.provider, input.model, input.serviceTier, contextTier, ); const priorityLowerBound = contextPriorityLowerBound || isOpenRouterPriorityLowerBound( - input.provider, + price.provider, typeof input.serviceTier === "object" ? input.serviceTier.tierOutcome : undefined, ); return { diff --git a/src/usage/user-cost-overlays.ts b/src/usage/user-cost-overlays.ts index 22af57e87a..6024e17596 100644 --- a/src/usage/user-cost-overlays.ts +++ b/src/usage/user-cost-overlays.ts @@ -13,19 +13,23 @@ * must not churn the version (see refreshUserCostOverlays). The configured * provider-name set is part of the change identity: adding or removing a * provider changes which names may collapse to a label base in the resolver, - * so it bumps the version even when no overlay row changed. + * so it bumps the version even when no overlay row changed. Exact selectable + * Codex IDs and effective log labels also participate in that identity. * * Display-time estimation only — these rows never affect billing. */ import type { OcxConfig, OcxProviderConfig, ProviderCostOverlay } from "../types"; import { MAX_COST4_RATE, type ExpectedPriceOverlay } from "./expected-prices"; import { redactSecretString } from "../lib/redact"; +import { isSelectableCodexPoolAccount, MAIN_CODEX_ACCOUNT_ID } from "../codex/account-id"; +import { codexAccountLogLabel } from "../codex/account-label"; const EMPTY: readonly ExpectedPriceOverlay[] = []; let active: readonly ExpectedPriceOverlay[] = EMPTY; let activeSignature = ""; let activeConfigured = new Set(); +let activeAccountProviders = codexAccountProviders([]); let version = 0; let preservedDiskOnlyProviders: Record | null = null; @@ -54,6 +58,24 @@ function providerNames(config: OcxConfig): Set { return new Set(Object.keys(config.providers ?? {})); } +/** Exact config-owned identities only; aliases and generic OAuth stores are not authority. */ +function codexAccountProviders(accounts: OcxConfig["codexAccounts"]): Map { + const identities = new Set(["main", MAIN_CODEX_ACCOUNT_ID]); + for (const account of accounts ?? []) { + if (!isSelectableCodexPoolAccount(account)) continue; + identities.add(account.id); + identities.add(codexAccountLogLabel(account)); + } + const mapping = new Map(); + for (const identity of identities) { + mapping.set(identity, "openai"); + for (const provider of ["openai", "chatgpt", "openai-multi"]) { + mapping.set(`${provider}-${identity}`, "openai"); + } + } + return mapping; +} + /** Register one active live-config owner. Multiple server leases may share one config object. */ export function registerPreservedProviderOwner(config: OcxConfig): void { const tagged = config as PreservationTaggedConfig; @@ -289,12 +311,17 @@ export function refreshUserCostOverlays(config: OcxConfig): void { // removing a provider (even one without an overlay) changes which names are // allowed to collapse to a label base, so the resolver memo and the // /api/usage summary cache must be invalidated on that change as well. + // Sort effective account identities so account order, aliases and plan + // metadata do not churn caches; add/remove/label changes still invalidate. const configuredNames = Object.keys(providers ?? {}).sort(); - const signature = `${JSON.stringify(configuredNames)}\u0000${JSON.stringify(rows)}`; + const accountProviders = codexAccountProviders(config.codexAccounts); + const accountEntries = [...accountProviders].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0); + const signature = `${JSON.stringify(configuredNames)}\u0000${JSON.stringify(rows)}\u0000${JSON.stringify(accountEntries)}`; if (signature === activeSignature) return; activeSignature = signature; active = rows; activeConfigured = new Set(configuredNames); + activeAccountProviders = accountProviders; version++; } @@ -303,7 +330,7 @@ export function activeUserCostOverlays(): readonly ExpectedPriceOverlay[] { return active; } -/** Monotonic version bumped on every refresh; used by the estimator memo key. */ +/** Monotonic version bumped on pricing-identity changes; used by the estimator memo key. */ export function userCostOverlayVersion(): number { return version; } @@ -312,3 +339,8 @@ export function userCostOverlayVersion(): number { export function activeConfiguredProviders(): ReadonlySet { return activeConfigured; } + +/** Account pricing identities built at refresh, without reading credential stores. */ +export function activeAccountPricingProviders(): ReadonlyMap { + return activeAccountProviders; +} diff --git a/tests/usage/usage-cost.test.ts b/tests/usage/usage-cost.test.ts index 387ed3c01d..e21c4276e9 100644 --- a/tests/usage/usage-cost.test.ts +++ b/tests/usage/usage-cost.test.ts @@ -1327,6 +1327,184 @@ describe("provider cost overlay (user-configured)", () => { }); }); +describe("Codex account pricing identity", () => { + const modelId = "wp3-synthetic-account-model"; + const account = { id: "cost-account", logLabel: "p123abc", alias: "display-name", email: "fixture@example.invalid", isMain: false }; + const row: ExpectedPriceOverlay = { + provider: "openai", modelId, cost4: RATE, + source: "fixture", verifiedAt: "2026-09-07", status: "verified", + }; + const config = (accounts = [account], providers = {}) => ({ + providers, codexAccounts: accounts, + }) as unknown as OcxConfig; + const forms = (id: string) => [id, ...["openai", "chatgpt", "openai-multi"].map(provider => `${provider}-${id}`)]; + + afterEach(() => refreshUserCostOverlays(config([]))); + + test("exact selectable IDs, effective labels and built-in main forms resolve without model fallback", () => { + refreshUserCostOverlays(config([ + account, + // SHA-256('abc') begins ba7816: an invalid stored label must use the producer's fallback. + { ...account, id: "abc", logLabel: "invalid-label" }, + ])); + for (const id of [account.id, account.logLabel, "abc", "pba7816", "main", "__main__"]) { + for (const provider of forms(id)) { + expect(resolveMatchedPrice(provider, modelId, [row], [], { allowModelLevelFallback: false })) + .toMatchObject({ provider: "openai", cost4: RATE, source: "expected" }); + } + } + }); + + test("aliases, email, invalid rows, unknown IDs, case variants and non-Codex identities stay unmapped", () => { + refreshUserCostOverlays(config([ + account, + { ...account, id: "invalid/id", logLabel: "p111aaa" }, + { ...account, id: "constructor", logLabel: "p222aaa" }, + { ...account, id: "desktop-row", logLabel: "p333aaa", isMain: true }, + { ...account, id: "abc", logLabel: "invalid-label" }, + ])); + for (const provider of [ + ...forms("unknown-account"), ...forms(account.alias), ...forms(account.email), + ...forms("Cost-account"), ...forms("invalid-label"), ...forms("invalid/id"), + "constructor", "desktop-row", "p111aaa", "p222aaa", "p333aaa", "p123abC", + "Openai-cost-account", "openai-cost-account-extra", "anthropic-cost-account", + "xai-cost-account", "oauth-account", "o123abc", "xai-o123abc", "unrelated-hyphen-provider", + ]) { + expect(resolveMatchedPrice(provider, modelId, [row], [], { allowModelLevelFallback: false })).toBeNull(); + } + }); + + test("configured literal namespaces beat account mapping and historical collapse", () => { + const names = [...forms(account.id), ...forms(account.logLabel), ...forms("main"), ...forms("__main__"), "chatgpt", "openai-multi"]; + refreshUserCostOverlays(config([account], Object.fromEntries(names.map(name => [name, {}])))); + for (const provider of names) { + expect(resolveMatchedPrice(provider, modelId, [row], [])).toBeNull(); + const literal = { ...row, provider, cost4: { ...RATE, input: 7 } }; + expect(resolveMatchedPrice(provider, modelId, [row, literal], [])) + .toMatchObject({ provider, cost4: literal.cost4 }); + } + }); + + test("caller-supplied exact user rows beat both canonical user and compiled rows", () => { + refreshUserCostOverlays(config()); + for (const provider of [...forms(account.id), ...forms(account.logLabel)]) { + const canonicalUser = { ...row, cost4: { ...RATE, input: 11 } }; + const exactUser = { ...row, provider, cost4: { ...RATE, input: 17 } }; + expect(resolveMatchedPrice(provider, modelId, [row], [canonicalUser, exactUser])) + .toMatchObject({ provider, source: "user", cost4: exactUser.cost4 }); + } + }); + + test("only recognized historical phex and main suffixes retain the existing fallback", () => { + refreshUserCostOverlays(config([])); + const custom = { ...row, provider: "legacy" }; + for (const provider of ["legacy-pabcdef", "legacy-main"]) { + expect(resolveMatchedPrice(provider, modelId, [custom], [])?.cost4).toEqual(RATE); + } + for (const provider of ["legacy-unknown", "legacy-pABCDEF", "legacy-pabcde", "legacy-oabcdef", "legacy-__main__"]) { + expect(resolveMatchedPrice(provider, modelId, [custom], [])).toBeNull(); + } + }); + + test("account add, effective-label change and removal invalidate memo; presentation and order do not", () => { + const providers = { openai: { modelCosts: { [modelId]: RATE } } }; + refreshUserCostOverlays(config([], providers)); + expect(resolveMatchedPrice(account.id, modelId)).toBeNull(); + expect(resolveMatchedPrice(account.logLabel, modelId)).toBeNull(); + const before = userCostOverlayVersion(); + const second = { ...account, id: "other-account", logLabel: "p456def" }; + refreshUserCostOverlays(config([account, second], providers)); + expect(userCostOverlayVersion()).toBe(before + 1); + for (const provider of [...forms(account.id), account.logLabel]) { + expect(resolveMatchedPrice(provider, modelId)?.cost4).toEqual(RATE); + } + const rows = activeUserCostOverlays(); + const memo = resolveMatchedPrice(account.id, modelId); + const renamed = { ...account, alias: "new-display", email: "new@example.invalid", plan: "pro" }; + refreshUserCostOverlays(config([second, renamed], providers)); + expect(userCostOverlayVersion()).toBe(before + 1); + expect(activeUserCostOverlays()).toBe(rows); + expect(resolveMatchedPrice(account.id, modelId)).toBe(memo); + refreshUserCostOverlays(config([{ ...renamed, logLabel: "p789abc" }, second], providers)); + expect(userCostOverlayVersion()).toBe(before + 2); + expect(resolveMatchedPrice(account.logLabel, modelId)).toBeNull(); + expect(resolveMatchedPrice("p789abc", modelId)?.cost4).toEqual(RATE); + refreshUserCostOverlays(config([second], providers)); + expect(userCostOverlayVersion()).toBe(before + 3); + for (const provider of [...forms(account.id), "p789abc"]) { + expect(resolveMatchedPrice(provider, modelId)).toBeNull(); + } + }); + + test("mapped accounts share request, attempt and combo long-context/Fast pricing with original attribution", () => { + refreshUserCostOverlays(config()); + const usage = { inputTokens: 300_000, outputTokens: 10_000 }; + for (const provider of [...forms(account.id), ...forms(account.logLabel), ...forms("__main__")]) { + for (const serviceTier of [undefined, { responseServiceTier: "priority" }, { responseServiceTier: "default", requestedServiceTier: "priority" }]) { + const input = { provider, model: "gpt-6-astra", usageStatus: "reported" as const, usage, serviceTier }; + const request = estimateRequestCost(input)!; + const attempt = estimateAttemptCost({ ...input, ordinal: 1 }, undefined, serviceTier)!; + const combo = estimateComboCost([{ ...input, ordinal: 1 }, { ...input, ordinal: 2 }], undefined, serviceTier)!; + // 300k * $20/M input + 10k * $75/M output; Fast doubles both. + const expected = serviceTier?.responseServiceTier === "priority" ? 13.5 : 6.75; + expect(request.cost.total).toBeCloseTo(expected, 9); + expect(request.contextTier).toBe("long"); + expect(request.priorityMultiplier).toBe(expected === 13.5 ? 2 : undefined); + expect(attempt.cost).toEqual(request.cost); + expect(attempt.contextTier).toBe(request.contextTier); + expect(attempt.priorityMultiplier).toBe(request.priorityMultiplier); + expect(attempt.provider).toBe(provider); + expect(combo.cost.total).toBeCloseTo(expected * 2, 9); + expect(combo.attempts?.map(entry => entry.provider)).toEqual([provider, provider]); + } + } + }); + + test("literal and direct override namespaces do not inherit OpenAI context or Fast modifiers", () => { + const provider = "openai-p123abc"; + const input = { provider, model: "gpt-6-astra", usageStatus: "reported" as const, + usage: { inputTokens: 300_000, outputTokens: 10_000 }, serviceTier: "priority" }; + const literal = { ...row, provider, modelId: input.model }; + refreshUserCostOverlays(config([account], { [provider]: {} })); + for (const estimate of [estimateRequestCost(input, [literal], []), estimateAttemptCost({ ...input, ordinal: 1 }, [literal], "priority", [])]) { + expect(estimate?.cost.total).toBeCloseTo(1.05, 9); + expect(estimate?.contextTier).toBeUndefined(); + expect(estimate?.priorityMultiplier).toBeUndefined(); + } + refreshUserCostOverlays(config()); + const direct = estimateRequestCost(input, [], [literal]); + expect(direct?.cost.total).toBeCloseTo(1.05, 9); + expect(direct?.contextTier).toBeUndefined(); + expect(direct?.priorityMultiplier).toBeUndefined(); + const combo = estimateComboCost([{ ...input, ordinal: 1 }], [], "priority", [literal]); + expect(combo?.cost.total).toBeCloseTo(1.05, 9); + expect(combo?.contextTier).toBeUndefined(); + expect(combo?.priorityMultiplier).toBeUndefined(); + }); + + test("OpenRouter lower-bound uses the selected namespace, including Codex-name collisions", () => { + const provider = "openrouter-p123abc"; + const tracker = createAdapterTierMetadata({ capability: true, eligibility: "eligible", + fastWire: { kind: "service-tier", canonicalToWire: { priority: "priority" }, foreignCallerTiers: "verbatim" }, + demandDecision: "force-fast" }, { kind: "set", value: "priority" }, "service-tier", "priority")!; + tracker.observeResponseServiceTier("priority"); + const input = { provider, model: modelId, usageStatus: "reported" as const, + usage: { inputTokens: 100, outputTokens: 10 }, ordinal: 1, tierOutcome: tracker.outcome }; + const router = { ...row, provider: "openrouter" }; + refreshUserCostOverlays(config([])); + expect(estimateAttemptCost(input, [router], undefined, [])?.priorityLowerBound).toBe(true); + refreshUserCostOverlays(config([{ ...account, id: provider }])); + expect(estimateAttemptCost(input, [row, router], undefined, [])?.priorityLowerBound).toBeUndefined(); + refreshUserCostOverlays(config([], { [provider]: {} })); + const literal = { ...row, provider }; + const request = estimateRequestCost({ ...input, serviceTier: { tierOutcome: tracker.outcome } }, [literal], []); + expect(request).not.toBeNull(); + expect(request?.priorityLowerBound).toBeUndefined(); + expect(estimateAttemptCost(input, [literal], undefined, [])?.priorityLowerBound).toBeUndefined(); + expect(estimateComboCost([input], [literal], undefined, [])?.priorityLowerBound).toBeUndefined(); + }); +}); + describe("aggregator vendor-prefixed model ids (#3136)", () => { test("restricted resolution partitions memoization and only removes vendor fallback", () => { const model = "anthropic/claude-3-haiku-20240307"; From c35b5a6e504a4513ad59957f5c81b7db45f8bec6 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 18:29:46 +0900 Subject: [PATCH 129/412] fix(claude): preserve legacy thinking block order [skip ci] Defer item-bound thinking emission until its envelope can place redacted blocks first. Preserve budget enforcement and live text/tool output. Refs #3719; replay/cache acceptance remains open. Co-authored-by: lidge-jun <243035832+lidge-jun@users.noreply.github.com> --- devlog/_plan/260907_lane_d/010_thinking.md | 4 +- src/claude/outbound.ts | 59 ++-- .../claude-outbound.test.ts | 306 +++++++++++++++++- 3 files changed, 343 insertions(+), 26 deletions(-) diff --git a/devlog/_plan/260907_lane_d/010_thinking.md b/devlog/_plan/260907_lane_d/010_thinking.md index e321ac03ce..f2bb7e18bf 100644 --- a/devlog/_plan/260907_lane_d/010_thinking.md +++ b/devlog/_plan/260907_lane_d/010_thinking.md @@ -17,8 +17,10 @@ Astra Dirac found two blockers: unmatched-item reordering and closure memory ove Track bounded reasoningItemKey separately from part identity; flush on changed explicit item identity, and close unrelated pending thinking before another item's red blocks. Only same identity (including both omitted) reorders red before pending thinking. -Release retained thinkingBuf after text frame enqueue, before signature frame enqueue; +Retain thinkingBuf through signature emission as before; queued frame budget stays authoritative, never weakened. Add near-limit valid control, shared-budget collector control, overflow/cancel regressions. Deferred thinking is an accepted visible-latency tradeoff; text/tool frames remain live with incremental-reader coverage. Late done after a different emitted block cannot reorder earlier content. + +Re-audit Dirac: VERDICT PASS, blockers=0. Accept tight artificial budget capacity reduction; retain original overflow assertions and production limits. diff --git a/src/claude/outbound.ts b/src/claude/outbound.ts index 1975d5b390..d4e7758ee0 100644 --- a/src/claude/outbound.ts +++ b/src/claude/outbound.ts @@ -215,6 +215,8 @@ interface OpenBlock { callId?: string; /** Last fixed-size reasoning identity (item + summary/content index) seen by this block. */ reasoningPartKey?: string; + /** Fixed-size item identity; missing IDs only match other missing IDs. */ + reasoningItemKey?: string; thinkingBuf?: string; thinkingBufBytes?: number; reasoningSig?: string; @@ -308,6 +310,20 @@ export function responsesSseToAnthropicSse( open.webSearchArgsEmitted = true; } if (open.kind === "thinking") { + // Delay the index and all thinking frames until closure so a matching + // done envelope can put its redacted blocks first. The existing buffer + // remains charged through signature emission, including queued frames. + open.index = blockIndex++; + emit("content_block_start", { + type: "content_block_start", index: open.index, + content_block: { type: "thinking", thinking: "", signature: "" }, + }); + if (open.thinkingBuf) { + emit("content_block_delta", { + type: "content_block_delta", index: open.index, + delta: { type: "thinking_delta", thinking: open.thinkingBuf }, + }); + } const signature = open.reasoningSig ?? encodeReasoningEnvelope({ txt: open.thinkingBuf ?? "" }, translatorBudget); emit("content_block_delta", { type: "content_block_delta", index: open.index, @@ -323,12 +339,13 @@ export function responsesSseToAnthropicSse( ensureStarted(); if (open && open.kind === kind) return; closeOpenBlock(); + if (kind === "thinking") { + open = { kind, index: -1, thinkingBuf: "", thinkingBufBytes: 0 }; + return; + } const index = blockIndex++; - const contentBlock: Rec = kind === "text" - ? { type: "text", text: "" } - : { type: "thinking", thinking: "", signature: "" }; - emit("content_block_start", { type: "content_block_start", index, content_block: contentBlock }); - open = { kind, index, thinkingBuf: "", thinkingBufBytes: 0 }; + emit("content_block_start", { type: "content_block_start", index, content_block: { type: "text", text: "" } }); + open = { kind, index }; }; const finish = (stopReason: string, usage: unknown) => { if (terminated) return; @@ -405,11 +422,13 @@ export function responsesSseToAnthropicSse( case "response.reasoning_summary_text.delta": case "response.reasoning_text.delta": { if (typeof data.delta !== "string" || data.delta.length === 0) break; + const itemKey = boundedReasoningIdentity(data.item_id); + if (open?.kind === "thinking" && open.reasoningItemKey !== itemKey) closeOpenBlock(); ensureBlock("thinking"); const active = open; if (!active || active.kind !== "thinking") break; // The JSON path joins reasoning summary/content parts with "\n\n" - // (responsesJsonToAnthropicMessage); mirror that at part and item boundaries + // (responsesJsonToAnthropicMessage); mirror that at part boundaries // so multi-part summaries do not glue into one run-on paragraph. Frames // without part indices produce a constant key and never get a separator. const slot = eventName === "response.reasoning_summary_text.delta" @@ -418,7 +437,7 @@ export function responsesSseToAnthropicSse( // Upstream string metadata can be arbitrarily large. Hash strings into fixed-size // components while retaining item and part equality, rather than dropping item_id and // accidentally joining distinct malformed reasoning items. - const partKey = `${boundedReasoningIdentity(data.item_id)}:${slot}`; + const partKey = `${itemKey}:${slot}`; const needsPartSeparator = active.reasoningPartKey !== undefined && active.reasoningPartKey !== partKey; const appended = `${needsPartSeparator ? "\n\n" : ""}${data.delta}`; @@ -436,17 +455,8 @@ export function responsesSseToAnthropicSse( reservation.release(); throw error; } - if (needsPartSeparator) { - emit("content_block_delta", { - type: "content_block_delta", index: active.index, - delta: { type: "thinking_delta", thinking: "\n\n" }, - }); - } + active.reasoningItemKey = itemKey; active.reasoningPartKey = partKey; - emit("content_block_delta", { - type: "content_block_delta", index: active.index, - delta: { type: "thinking_delta", thinking: data.delta }, - }); break; } case "response.output_item.added": { @@ -563,20 +573,27 @@ export function responsesSseToAnthropicSse( const encrypted = typeof item.encrypted_content === "string" ? item.encrypted_content : ""; const env = encrypted ? decodeReasoningEnvelope(encrypted, translatorBudget) : null; const red = env?.red ?? []; - if (env?.sig && open?.kind !== "thinking") ensureBlock("thinking"); - if (open?.kind === "thinking") { - if (env?.sig) open.reasoningSig = env.sig; + const itemKey = boundedReasoningIdentity(item.id); + // A late/unrelated done cannot reorder or sign another item's text. + if (open?.kind === "thinking" && open.reasoningItemKey !== itemKey) { closeOpenBlock(); } if (red.length > 0) { ensureStarted(); - closeOpenBlock(); + if (open?.kind !== "thinking") closeOpenBlock(); } for (const data of red) { const idx = blockIndex++; emit("content_block_start", { type: "content_block_start", index: idx, content_block: { type: "redacted_thinking", data } }); emit("content_block_stop", { type: "content_block_stop", index: idx }); } + if (env?.sig && open?.kind !== "thinking") { + ensureBlock("thinking"); + } + if (open?.kind === "thinking") { + if (env?.sig) open.reasoningSig = env.sig; + closeOpenBlock(); + } } break; } diff --git a/tests/claude-integration/claude-outbound.test.ts b/tests/claude-integration/claude-outbound.test.ts index 67380bb44a..72f7a22bdf 100644 --- a/tests/claude-integration/claude-outbound.test.ts +++ b/tests/claude-integration/claude-outbound.test.ts @@ -483,8 +483,8 @@ describe("claude outbound SSE", () => { responsesSseToAnthropicSse(streamFromChunks([upstream]), "m"), "m", ) as Record; - expect(msg.content.find((b: Record) => b.type === "thinking").thinking) - .toBe("AB\n\nC\n\nD"); + expect(msg.content.filter((b: Record) => b.type === "thinking") + .map((b: Record) => b.thinking)).toEqual(["AB", "C\n\nD"]); }); test("malformed array reasoning identities retain distinct boundaries", async () => { @@ -505,8 +505,8 @@ describe("claude outbound SSE", () => { responsesSseToAnthropicSse(streamFromChunks([upstream]), "m"), "m", ) as Record; - expect(msg.content.find((b: Record) => b.type === "thinking").thinking) - .toBe("A\n\nB"); + expect(msg.content.filter((b: Record) => b.type === "thinking") + .map((b: Record) => b.thinking)).toEqual(["A", "B"]); }); test("data-only Responses frames infer event names from payload types", async () => { @@ -1304,3 +1304,301 @@ describe("sanitizeWebSearchInput (#381)", () => { expect(events[3].data.delta).toEqual({ type: "signature_delta", signature: "sig-only" }); }); }); + +describe("deferred Claude thinking order", () => { + const fixtures = [ + { + name: "combined envelope with preceding multipart deltas", + envelope: { sig: "signed-visible", red: ["opaque-1", "opaque-2"], txt: "hidden-only" }, + deltas: [ + sse("response.reasoning_summary_text.delta", { item_id: "rs", summary_index: 0, delta: "Fir" }), + sse("response.reasoning_summary_text.delta", { item_id: "rs", summary_index: 0, delta: "st" }), + sse("response.reasoning_summary_text.delta", { item_id: "rs", summary_index: 1, delta: "Second" }), + sse("response.reasoning_text.delta", { item_id: "rs", content_index: 0, delta: "Third" }), + ], + summary: [{ text: "First" }, { text: "Second" }], + content: [{ text: "Third" }], + expected: [ + { type: "text", text: "prefix" }, + { type: "redacted_thinking", data: "opaque-1" }, + { type: "redacted_thinking", data: "opaque-2" }, + { type: "thinking", thinking: "First\n\nSecond\n\nThird", signature: "signed-visible" }, + ], + }, + { + name: "combined envelope without deltas keeps signed thinking empty", + envelope: { sig: "signed-empty", red: ["opaque-1", "opaque-2"], txt: "hidden-only" }, + deltas: [], summary: [], content: [], + expected: [ + { type: "text", text: "prefix" }, + { type: "redacted_thinking", data: "opaque-1" }, + { type: "redacted_thinking", data: "opaque-2" }, + { type: "thinking", thinking: "", signature: "signed-empty" }, + ], + }, + { + name: "signed-only envelope", + envelope: { sig: "signed-only", txt: "hidden-only" }, + deltas: [], summary: [], content: [], + expected: [ + { type: "text", text: "prefix" }, + { type: "thinking", thinking: "", signature: "signed-only" }, + ], + }, + { + name: "red-only envelope", + envelope: { red: ["opaque-1", "opaque-2"], txt: "hidden-only" }, + deltas: [], summary: [], content: [], + expected: [ + { type: "text", text: "prefix" }, + { type: "redacted_thinking", data: "opaque-1" }, + { type: "redacted_thinking", data: "opaque-2" }, + ], + }, + ]; + + for (const fixture of fixtures) { + test(`${fixture.name}: JSON and collected SSE match literal content`, async () => { + const item = { + type: "reasoning", id: "rs", summary: fixture.summary, content: fixture.content, + encrypted_content: encodeReasoningEnvelope(fixture.envelope), + }; + const frames = [ + sse("response.output_text.delta", { delta: "prefix" }), + ...fixture.deltas, + sse("response.output_item.done", { item }), + sse("response.completed", { response: { status: "completed" } }), + ]; + const json = responsesJsonToAnthropicMessage({ status: "completed", output: [ + { type: "message", content: [{ type: "output_text", text: "prefix" }] }, item, + ] }, "m"); + const message = await collectAnthropicMessage( + responsesSseToAnthropicSse(streamFromChunks(frames), "m", { pingIntervalMs: 0 }), "m", + ); + expect(json.content).toEqual(fixture.expected); + expect(message.content).toEqual(fixture.expected); + expect(JSON.stringify(message)).not.toContain("hidden-only"); + expect(message.stop_reason).toBe("end_turn"); + + const events = await collectEvents(responsesSseToAnthropicSse(streamFromChunks(frames), "m", { pingIntervalMs: 0 })); + let active: number | null = null; + let next = 0; + for (const event of events) { + if (event.name === "content_block_start") { + expect(active).toBeNull(); + expect(event.data.index).toBe(next); + active = next++; + } else if (event.name === "content_block_delta" || event.name === "content_block_stop") { + expect(active).not.toBeNull(); + expect(event.data.index).toBe(active); + if (event.name === "content_block_stop") active = null; + } + } + expect(active).toBeNull(); + expect(next).toBe(fixture.expected.length); + expect(events.at(-1)?.name).toBe("message_stop"); + }); + } + + for (const [deltaId, doneId, matching] of [ + ["a", "a", true], ["a", "b", false], + [undefined, undefined, true], ["a", undefined, false], [undefined, "b", false], + ] as const) { + test(`done item boundary ${String(deltaId)} -> ${String(doneId)}`, async () => { + const message = await collectAnthropicMessage(responsesSseToAnthropicSse(streamFromChunks([ + sse("response.reasoning_text.delta", { item_id: deltaId, delta: "A" }), + sse("response.output_item.done", { item: { + type: "reasoning", id: doneId, + encrypted_content: encodeReasoningEnvelope({ sig: "done-signature", red: ["done-red"] }), + } }), + sse("response.completed", { response: { status: "completed" } }), + ]), "m", { pingIntervalMs: 0 }), "m"); + expect(message.content).toEqual(matching ? [ + { type: "redacted_thinking", data: "done-red" }, + { type: "thinking", thinking: "A", signature: "done-signature" }, + ] : [ + { type: "thinking", thinking: "A", signature: "ocxr1:eyJ0eHQiOiJBIn0=" }, + { type: "redacted_thinking", data: "done-red" }, + { type: "thinking", thinking: "", signature: "done-signature" }, + ]); + }); + } + + for (const [firstId, secondId] of [["a", "b"], ["a", undefined], [undefined, "b"]] as const) { + test(`delta item boundary ${String(firstId)} -> ${String(secondId)} flushes first`, async () => { + const message = await collectAnthropicMessage(responsesSseToAnthropicSse(streamFromChunks([ + sse("response.reasoning_text.delta", { item_id: firstId, delta: "A" }), + sse("response.reasoning_text.delta", { item_id: secondId, delta: "B" }), + sse("response.output_item.done", { item: { + type: "reasoning", id: secondId, + encrypted_content: encodeReasoningEnvelope({ sig: "second-signature", red: ["second-red"] }), + } }), + sse("response.completed", { response: { status: "completed" } }), + ]), "m", { pingIntervalMs: 0 }), "m"); + expect(message.content).toEqual([ + { type: "thinking", thinking: "A", signature: "ocxr1:eyJ0eHQiOiJBIn0=" }, + { type: "redacted_thinking", data: "second-red" }, + { type: "thinking", thinking: "B", signature: "second-signature" }, + ]); + }); + } + + test("separate red and signed items preserve their stream order", async () => { + const items = [ + { type: "reasoning", id: "red", encrypted_content: encodeReasoningEnvelope({ red: ["first-red"] }) }, + { type: "reasoning", id: "signed", summary: [{ text: "A" }], encrypted_content: encodeReasoningEnvelope({ sig: "sig-A" }) }, + { type: "reasoning", id: "red-last", encrypted_content: encodeReasoningEnvelope({ red: ["last-red"] }) }, + ]; + const message = await collectAnthropicMessage(responsesSseToAnthropicSse(streamFromChunks([ + sse("response.output_item.done", { item: items[0] }), + sse("response.reasoning_text.delta", { item_id: "signed", delta: "A" }), + sse("response.output_item.done", { item: items[1] }), + sse("response.output_item.done", { item: items[2] }), + sse("response.completed", { response: { status: "completed" } }), + ]), "m", { pingIntervalMs: 0 }), "m"); + const expected = [ + { type: "redacted_thinking", data: "first-red" }, + { type: "thinking", thinking: "A", signature: "sig-A" }, + { type: "redacted_thinking", data: "last-red" }, + ]; + expect(message.content).toEqual(expected); + expect(responsesJsonToAnthropicMessage({ output: items }, "m").content).toEqual(expected); + }); + + for (const genuineSignature of [false, true]) { + for (const buffered of [false, true]) { + test(`near-limit valid thinking: ${genuineSignature ? "genuine" : "fallback"}, ${buffered ? "shared collector" : "stream"}`, async () => { + // The live collector also retains the emitted content/signature, unlike + // the stream-only near-limit control. Both use one budget throughout. + // Shared encoding admission needs ~254 KiB for the 20 KiB fallback + // including source and queued text; genuine signatures bypass encoding. + const maxTurnBytes = (genuineSignature ? (buffered ? 128 : 70) : (buffered ? 320 : 280)) * 1024; + const budget = createTestTranslatorBudget({ maxTurnBytes }); + const text = "x".repeat((genuineSignature ? 32 : 20) * 1024); + const frames = Array.from({ length: text.length / 256 }, () => sse("response.reasoning_text.delta", { + item_id: "rs_control", content_index: 0, delta: text.slice(0, 256), + })); + frames.push(sse("response.output_item.done", { item: { + type: "reasoning", id: "rs_control", + ...(genuineSignature ? { encrypted_content: encodeReasoningEnvelope({ sig: "control-signature", red: ["control-red"] }) } : {}), + } })); + frames.push(sse("response.completed", { response: { status: "completed" } })); + const stream = responsesSseToAnthropicSse(streamFromChunks(frames), "m", { + translatorBudget: budget, pingIntervalMs: 0, + }); + if (buffered) { + // Collect live with the exact translator budget; no capture/reset/new budget. + const message = await collectAnthropicMessage(stream, "m", budget); + expect(message.type).toBe("message"); + const content = message.content as Record[]; + expect(content.map(block => block.type)).toEqual(genuineSignature + ? ["redacted_thinking", "thinking"] : ["thinking"]); + const thinking = content.at(-1)!; + expect(thinking.thinking).toBe(text); + if (genuineSignature) expect(thinking.signature).toBe("control-signature"); + else expect(decodeReasoningEnvelope(thinking.signature as string)?.txt).toBe(text); + expect(message.stop_reason).toBe("end_turn"); + } else { + const events = await collectEvents(stream); + expect(events.filter(event => event.data.delta?.type === "thinking_delta") + .map(event => event.data.delta.thinking).join("")).toBe(text); + const signature = events.find(event => event.data.delta?.type === "signature_delta")?.data.delta.signature; + if (genuineSignature) expect(signature).toBe("control-signature"); + else expect(decodeReasoningEnvelope(signature)?.txt).toBe(text); + expect(events.at(-1)?.name).toBe("message_stop"); + expect(events.some(event => event.name === "error")).toBe(false); + } + expect(budget.snapshot().overflows).toBe(0); + expect(budget.snapshot().highWaterBytes).toBeGreaterThan(60 * 1024); + expect(budget.snapshot().highWaterBytes).toBeLessThanOrEqual(maxTurnBytes); + }); + } + } + + test("cancelling deferred thinking releases its buffer and cancels upstream", async () => { + const budget = createTestTranslatorBudget(); + const text = "pending".repeat(1024); + let signalConsumed!: () => void; + const consumed = new Promise(resolve => { signalConsumed = resolve; }); + let sent = false; + let cancelReason: unknown; + const upstream = new ReadableStream({ + pull(controller) { + if (sent) { + // A second read proves the first delta has passed through handleFrame. + signalConsumed(); + return; + } + sent = true; + controller.enqueue(new TextEncoder().encode(sse("response.reasoning_text.delta", { + item_id: "pending", delta: text, + }))); + }, + cancel(reason) { cancelReason = reason; }, + }, { highWaterMark: 0 }); + const stream = responsesSseToAnthropicSse(upstream, "m", { translatorBudget: budget, pingIntervalMs: 0 }); + await consumed; + expect(budget.snapshot().currentBytes).toBeGreaterThanOrEqual(text.length); + await stream.cancel("client cancelled"); + expect(cancelReason).toBe("client cancelled"); + expect(budget.snapshot().currentBytes).toBe(0); + expect(budget.snapshot().overflows).toBe(0); + }); + + test("thinking waits for closure while text and tool arguments remain incremental; late done stays late", async () => { + let controller!: ReadableStreamDefaultController; + const upstream = new ReadableStream({ start(value) { controller = value; } }); + const reader = responsesSseToAnthropicSse(upstream, "m", { pingIntervalMs: 0 }).getReader(); + const send = (name: string, data: Record) => controller.enqueue(new TextEncoder().encode(sse(name, data))); + const next = async () => { + const { done, value } = await reader.read(); + expect(done).toBe(false); + return JSON.parse(new TextDecoder().decode(value).split("\ndata: ")[1]!.trim()) as Record; + }; + try { + send("response.reasoning_text.delta", { item_id: "early", delta: "A" }); + expect(await next()).toMatchObject({ type: "message_start" }); + expect(await next()).toEqual({ type: "ping" }); + // An explicit transport checkpoint proves no thinking start/index/text escaped. + send("response.heartbeat", {}); + expect(await next()).toEqual({ type: "ping" }); + + send("response.output_text.delta", { delta: "live-1" }); + expect(await next()).toMatchObject({ type: "content_block_start", index: 0, content_block: { type: "thinking" } }); + expect(await next()).toEqual({ type: "content_block_delta", index: 0, delta: { type: "thinking_delta", thinking: "A" } }); + expect(await next()).toEqual({ type: "content_block_delta", index: 0, delta: { type: "signature_delta", signature: "ocxr1:eyJ0eHQiOiJBIn0=" } }); + expect(await next()).toEqual({ type: "content_block_stop", index: 0 }); + expect(await next()).toMatchObject({ type: "content_block_start", index: 1, content_block: { type: "text" } }); + expect(await next()).toEqual({ type: "content_block_delta", index: 1, delta: { type: "text_delta", text: "live-1" } }); + send("response.output_text.delta", { delta: "live-2" }); + expect(await next()).toEqual({ type: "content_block_delta", index: 1, delta: { type: "text_delta", text: "live-2" } }); + + send("response.output_item.added", { item: { type: "function_call", id: "fc", call_id: "call", name: "Read" } }); + expect(await next()).toEqual({ type: "content_block_stop", index: 1 }); + expect(await next()).toMatchObject({ type: "content_block_start", index: 2, content_block: { type: "tool_use", name: "Read" } }); + for (const fragment of ['{"path":', '"/x"}']) { + send("response.function_call_arguments.delta", { item_id: "fc", delta: fragment }); + expect(await next()).toEqual({ type: "content_block_delta", index: 2, delta: { type: "input_json_delta", partial_json: fragment } }); + } + send("response.output_item.done", { item: { type: "function_call", id: "fc" } }); + expect(await next()).toEqual({ type: "content_block_stop", index: 2 }); + + send("response.output_item.done", { item: { + type: "reasoning", id: "early", encrypted_content: encodeReasoningEnvelope({ sig: "late-sig", red: ["late-red"] }), + } }); + expect(await next()).toEqual({ type: "content_block_start", index: 3, content_block: { type: "redacted_thinking", data: "late-red" } }); + expect(await next()).toEqual({ type: "content_block_stop", index: 3 }); + expect(await next()).toEqual({ type: "content_block_start", index: 4, content_block: { type: "thinking", thinking: "", signature: "" } }); + expect(await next()).toEqual({ type: "content_block_delta", index: 4, delta: { type: "signature_delta", signature: "late-sig" } }); + expect(await next()).toEqual({ type: "content_block_stop", index: 4 }); + send("response.completed", { response: { status: "completed" } }); + controller.close(); + expect(await next()).toMatchObject({ type: "message_delta", delta: { stop_reason: "tool_use" } }); + expect(await next()).toEqual({ type: "message_stop" }); + expect((await reader.read()).done).toBe(true); + } finally { + await reader.cancel(); + reader.releaseLock(); + } + }); +}); From c5fb7e3332432c6546bffa9990bce5b971653139 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 18:30:46 +0900 Subject: [PATCH 130/412] fix(models): guard edits during unknown receipt recovery [skip ci] Co-authored-by: lidge-jun <243035832+lidge-jun@users.noreply.github.com> --- devlog/_plan/260907_lane_d/020_receipt.md | 5 +++++ gui/src/components/ModelDisplayNameDialog.tsx | 20 +++++++++++++------ gui/src/pages/Models.tsx | 1 + gui/tests/models-display-name-editor.test.tsx | 12 +++++++++-- 4 files changed, 30 insertions(+), 8 deletions(-) diff --git a/devlog/_plan/260907_lane_d/020_receipt.md b/devlog/_plan/260907_lane_d/020_receipt.md index 7b710df91e..97568c39a8 100644 --- a/devlog/_plan/260907_lane_d/020_receipt.md +++ b/devlog/_plan/260907_lane_d/020_receipt.md @@ -10,3 +10,8 @@ and ordinary validation error remain editable. Screenshot changed disabled input/reset with retry available. Verification: NOT RUN locally by user instruction; focused tests execute in final top-head Cross-platform CI. + +Implementation: unknown outcome guards input/reset handlers and submit, and focuses Retry +when saving fails without a receipt. Saved:true remains editable. Transport/body failure +matrix attempts a replacement intent and asserts no second PUT before read-only retry. +Astra Herschel plan verdict PASS. Screenshots and product execution await top CI artifact. diff --git a/gui/src/components/ModelDisplayNameDialog.tsx b/gui/src/components/ModelDisplayNameDialog.tsx index 2a57ff8279..09854e104d 100644 --- a/gui/src/components/ModelDisplayNameDialog.tsx +++ b/gui/src/components/ModelDisplayNameDialog.tsx @@ -10,6 +10,7 @@ interface ModelDisplayNameDialogProps { saving: boolean; requestError: string | null; currentNamePending?: boolean; + mutationOutcomeUnknown?: boolean; onRetry?: () => void; onEdit?: () => void; onSave: (displayName: string) => void; @@ -28,6 +29,7 @@ export default function ModelDisplayNameDialog({ saving, requestError, currentNamePending = false, + mutationOutcomeUnknown = false, onRetry, onEdit, onSave, @@ -37,6 +39,7 @@ export default function ModelDisplayNameDialog({ const t = useT(); const dialogRef = useRef(null); const inputRef = useRef(null); + const submitRef = useRef(null); const wasSavingRef = useRef(saving); const titleId = useId(); const helpId = useId(); @@ -55,8 +58,11 @@ export default function ModelDisplayNameDialog({ useEffect(() => { const saveFailed = wasSavingRef.current && !saving && Boolean(requestError); wasSavingRef.current = saving; - if (saveFailed) inputRef.current?.focus(); - }, [requestError, saving]); + if (saveFailed) { + if (mutationOutcomeUnknown) submitRef.current?.focus(); + else inputRef.current?.focus(); + } + }, [requestError, saving, mutationOutcomeUnknown]); // Parent replaces this snapshot only after a confirmed mutation, not typing or polling. // Adjust before committing children, preserving the mounted dialog and its focus refs. @@ -102,6 +108,7 @@ export default function ModelDisplayNameDialog({ event.preventDefault(); if (saving) return; if (onRetry) { onRetry(); return; } + if (mutationOutcomeUnknown) return; const nextValidationKey = modelDisplayNameValidationKey(draft); setValidationKey(nextValidationKey); if (!nextValidationKey) onSave(draft.trim()); @@ -137,8 +144,9 @@ export default function ModelDisplayNameDialog({ placeholder={t("models.displayNamePlaceholder")} aria-describedby={`${helpId}${visibleError ? ` ${errorId}` : ""}`} aria-invalid={validationError ? true : undefined} - disabled={saving} + disabled={saving || mutationOutcomeUnknown} onChange={event => { + if (saving || mutationOutcomeUnknown) return; onEdit?.(); setDraft(event.target.value); setValidationKey(null); @@ -157,15 +165,15 @@ export default function ModelDisplayNameDialog({ -
diff --git a/gui/src/pages/Models.tsx b/gui/src/pages/Models.tsx index c342866d7e..fc8db5626e 100644 --- a/gui/src/pages/Models.tsx +++ b/gui/src/pages/Models.tsx @@ -2643,6 +2643,7 @@ export default function Models({ apiBase, restartEpoch = 0 }: { apiBase: string; saving={displayNameSaving} requestError={displayNameRequestError} currentNamePending={displayNameCurrentPending} + mutationOutcomeUnknown={displayNameRecovery?.confirmed === false} onRetry={displayNameRecovery ? () => void saveDisplayName(displayNameRecovery.value) : undefined} onEdit={() => setDisplayNameRecovery(null)} onSave={value => void saveDisplayName(value)} diff --git a/gui/tests/models-display-name-editor.test.tsx b/gui/tests/models-display-name-editor.test.tsx index b0656391ed..9d67f986e0 100644 --- a/gui/tests/models-display-name-editor.test.tsx +++ b/gui/tests/models-display-name-editor.test.tsx @@ -448,8 +448,16 @@ describe("Models dashboard discovered display name integration", () => { expect(currentNameText()).toContain("Current name unavailable until refresh"); expect(currentNameText()).not.toContain("Your name"); expect(container.textContent).toContain("The change may have been saved"); + expect(dialogInput().disabled).toBe(true); + expect(dialogButton("Reset name").disabled).toBe(true); expect(dialogButton("Retry").disabled).toBe(false); expect(dialogButton("Cancel").disabled).toBe(false); + await act(async () => { + setInputValue(dialogInput(), "Replacement intent"); + dialogButton("Reset name").dispatchEvent(new testWindow.MouseEvent("click", { bubbles: true })); + }); + expect(dialogButton("Retry").disabled).toBe(false); + expect(mutationBodies).toHaveLength(1); await act(async () => container.querySelector("dialog form")!.dispatchEvent( new testWindow.Event("submit", { bubbles: true, cancelable: true }), )); @@ -522,12 +530,12 @@ describe("Models dashboard discovered display name integration", () => { if (stage === "reload") expect(seenSignals[1]).toBe(seenSignals[0]); await act(async () => deadline.abort(new DOMException("Timed out", "TimeoutError"))); await flush(); - expect(dialogInput().disabled).toBe(false); + expect(dialogInput().disabled).toBe(stage === "mutation"); expect(dialogButton("Cancel").disabled).toBe(false); expect(dialogInput().value).toBe("Possibly saved"); expect(container.textContent).toContain(stage === "mutation" ? "The change may have been saved" : "The change was saved"); - expect(testWindow.document.activeElement).toBe(dialogInput()); + expect(testWindow.document.activeElement).toBe(stage === "mutation" ? dialogButton("Retry") : dialogInput()); stall = false; if (descriptor) Object.defineProperty(AbortSignal, "timeout", descriptor); await act(async () => dialogButton("Retry").click()); From c44c6de87389a95ab798b648659fbc0838af170b Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 19:11:13 +0900 Subject: [PATCH 131/412] test(usage): use approved synthetic email domains [skip ci] Exact top CI logs on macOS and Windows identified the same privacy-scan fixture rejection. Keep scanner rules and assertions unchanged. Co-authored-by: rrmlima <137737127+rrmlima@users.noreply.github.com> --- tests/usage/usage-cost.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/usage/usage-cost.test.ts b/tests/usage/usage-cost.test.ts index e21c4276e9..f234622e07 100644 --- a/tests/usage/usage-cost.test.ts +++ b/tests/usage/usage-cost.test.ts @@ -1329,7 +1329,7 @@ describe("provider cost overlay (user-configured)", () => { describe("Codex account pricing identity", () => { const modelId = "wp3-synthetic-account-model"; - const account = { id: "cost-account", logLabel: "p123abc", alias: "display-name", email: "fixture@example.invalid", isMain: false }; + const account = { id: "cost-account", logLabel: "p123abc", alias: "display-name", email: "fixture@example.test", isMain: false }; const row: ExpectedPriceOverlay = { provider: "openai", modelId, cost4: RATE, source: "fixture", verifiedAt: "2026-09-07", status: "verified", @@ -1420,7 +1420,7 @@ describe("Codex account pricing identity", () => { } const rows = activeUserCostOverlays(); const memo = resolveMatchedPrice(account.id, modelId); - const renamed = { ...account, alias: "new-display", email: "new@example.invalid", plan: "pro" }; + const renamed = { ...account, alias: "new-display", email: "new@example.test", plan: "pro" }; refreshUserCostOverlays(config([second, renamed], providers)); expect(userCostOverlayVersion()).toBe(before + 1); expect(activeUserCostOverlays()).toBe(rows); From 341d71dd553fdf65dde3e52038a0327a96e56354 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 18:45:22 +0900 Subject: [PATCH 132/412] feat(models): edit manual token prices and preserve explicit zero [skip ci] Expose modelCosts via the Models editor and models price/set-price CLI. Preserve sibling prices, support automatic reset, and treat explicit zero user rates as known-zero display estimates. Refs #3667. Co-authored-by: nordz0r <6949669+nordz0r@users.noreply.github.com> --- .../_plan/260907_lane_d/040_price_editor.md | 21 + .../fr/reference/configuration/providers.md | 2 +- .../ja/reference/configuration/providers.md | 2 +- .../ko/reference/configuration/providers.md | 2 +- .../docs/reference/cli/providers-accounts.md | 2 + .../docs/reference/configuration/providers.md | 2 +- .../content/docs/reference/management-api.md | 23 + .../ru/reference/configuration/providers.md | 2 +- .../tr/reference/configuration/providers.md | 2 +- .../reference/configuration/providers.md | 2 +- gui/src/components/ModelPriceDialog.tsx | 235 ++++++++++ gui/src/i18n/de.ts | 24 + gui/src/i18n/en.ts | 24 + gui/src/i18n/fr.ts | 24 + gui/src/i18n/ja.ts | 24 + gui/src/i18n/ko.ts | 24 + gui/src/i18n/ru.ts | 24 + gui/src/i18n/tr.ts | 24 + gui/src/i18n/zh-TW.ts | 24 + gui/src/i18n/zh.ts | 24 + gui/src/pages/Models.tsx | 35 ++ gui/src/pages/models-shared.ts | 1 + gui/tests/models-price-editor.test.tsx | 427 ++++++++++++++++++ scripts/test-layout/layout.json | 4 +- .../ocx/references/01_management_surface.md | 41 +- src/cli/capabilities.ts | 25 + src/cli/models-runtime-subcommands.ts | 2 + src/cli/models-runtime.ts | 68 ++- src/server/management/model-routes.ts | 59 ++- src/server/management/model-rows.ts | 5 + src/server/management/route-registry.ts | 2 + src/usage/cost.ts | 10 +- tests/cli/cli-models-price.test.ts | 153 +++++++ tests/cli/cli-models-runtime-dispatch.test.ts | 17 +- tests/fixtures/test-layout-expected.json | 4 +- .../server/model-costs-management-api.test.ts | 270 +++++++++++ tests/usage/usage-cost.test.ts | 25 +- 37 files changed, 1627 insertions(+), 32 deletions(-) create mode 100644 gui/src/components/ModelPriceDialog.tsx create mode 100644 gui/tests/models-price-editor.test.tsx create mode 100644 tests/cli/cli-models-price.test.ts create mode 100644 tests/server/model-costs-management-api.test.ts diff --git a/devlog/_plan/260907_lane_d/040_price_editor.md b/devlog/_plan/260907_lane_d/040_price_editor.md index 4628710d0d..8d79b2160e 100644 --- a/devlog/_plan/260907_lane_d/040_price_editor.md +++ b/devlog/_plan/260907_lane_d/040_price_editor.md @@ -21,3 +21,24 @@ A fold-back: add GET/PUT entries in src/server/management/route-registry.ts. Reuse providerModelCostsConfigError. GET returns sanitized per-provider modelCosts map; Models owns a typed map loaded with catalog or dedicated GET, so manual badges survive reload. CLI omitted cache-read/cache-write rates default to zero, explicitly documented. + +P revalidation/API contract: GET /api/providers/{provider}/model-costs returns +{provider,modelCosts}; PUT accepts {modelId,cost:Cost4|null}, returns +{ok:true,provider,modelId,cost}. Null deletes only that model key. Models API adds +manualPricing boolean on applicable rows so badges survive reload, while the dialog +GET owns editable rates. CLI models price reads; models set-price writes/resets. +Same C2 phase splits disjoint workers: backend API/CLI/model-row/tests; frontend dialog/ +Models/types/i18n/tests; main owns explicit-zero cost semantics, docs and manifests. +No worker commits/pushes/runs local checks. Main integrates once both return. +Main granted D exactly the zero sentence in all seven translated providers config +reference pages; leave all other sections to E/M. New i18n keys are append-only. + +Implementation checkpoint: GET/PUT editor and two CLI verbs share the four-rate store; +manualPricing is emitted only for exact stored overrides. All-zero user prices are +known-zero estimates while catalog zero fallbacks remain unchanged. API/CLI and dialog +regressions cover persistence, reset, sibling isolation, invalid input and unknown receipts. +All 9 locale catalogs gained matching append-only keys. Seven existing configuration +rows (English plus six translations) had only the zero sentence updated; zh-tw has no +modelCosts row on this baseline and was left untouched. CLI surface regenerated by its +own generator, not a build or test. New backend test names appended to both manifests. +Local suites/typecheck/build/install NOT RUN; final top CI and screenshot remain open. diff --git a/docs-site/src/content/docs/fr/reference/configuration/providers.md b/docs-site/src/content/docs/fr/reference/configuration/providers.md index 96d00e5668..1d043fc7fd 100644 --- a/docs-site/src/content/docs/fr/reference/configuration/providers.md +++ b/docs-site/src/content/docs/fr/reference/configuration/providers.md @@ -104,7 +104,7 @@ sauvegarde dont le contenu diffère, puis réécrit en identifiants sans préfix | `modelAutoCompactTokenLimits?` | `Record` | Budgets souples de compactage automatique par modèle, sous forme d'entiers sûrs positifs. Ils peuvent uniquement abaisser l'enveloppe effective de 90 % du contexte ou de l'entrée maximale et sont omis lorsqu'aucune fenêtre de contexte faisant autorité n'est connue. Pour le fournisseur canonique `openai`, les clés doivent être les identifiants exacts de modèles natifs pris en charge, sans préfixe de fournisseur ni de sélecteur de compte. PATCH fusionne les entrées ; `null` supprime une clé, tandis que `null` pour le champ entier efface la table. Ces marqueurs `null` sont réservés à PATCH. | | `defaultMaxOutputTokens?` | `number` | Solution de secours `openai-chat` à l’échelle du fournisseur lorsque le client omet `max_output_tokens`. | | `modelMaxOutputTokens?` | `Record` | Budgets de repli `openai-chat` positifs par modèle ; les correspondances exactes ou par motif priment sur la valeur par défaut du fournisseur. | -| `modelCosts?` | `Record` | Prix affichés par modèle (USD par 1M de jetons), indexés par l'identifiant exact du modèle en amont de ce fournisseur — et non par un identifiant de fournisseur ni par une étiquette routée `provider/model`, par exemple `{ "deepseek-v4-flash": { "input": 0.14, "output": 0.28, "cacheRead": 0.0028, "cacheWrite": 0 } }`. Tout identifiant de modèle constitue une clé valide : les fournisseurs personnalisés peuvent cibler n'importe quel point de terminaison compatible avec OpenAI au moyen de l'adaptateur `openai-chat`, et les identifiants de fournisseur locaux ou internes fonctionnent même s'ils sont absents des catalogues intégrés. Les prix configurés par l'utilisateur priment sur les catalogues intégrés dans les estimations des pages Journaux (`~$`) et Utilisation. Les entrées historiques sont recalculées à partir de la surcharge actuelle ; modifier un prix peut donc changer les totaux antérieurs. L'ordre de repli est le suivant : `modelCosts` défini par l'utilisateur → catalogue jawcode → surcharge des prix attendus → repli propre au fournisseur au niveau du modèle. Une entrée entièrement nulle passe à la source suivante. Chaque tarif doit être un nombre fini positif ou nul, inférieur ou égal à 1 000 000 (USD par 1M de jetons) ; les lignes hors plage sont rejetées par l'interface de gestion et ignorées au chargement. Ces valeurs servent uniquement à l'estimation lors de l'affichage : les surcharges n'affectent jamais le routage, la sélection des comptes, les quotas ni la facturation. | +| `modelCosts?` | `Record` | Prix affichés par modèle (USD par 1M de jetons), indexés par l'identifiant exact du modèle en amont de ce fournisseur — et non par un identifiant de fournisseur ni par une étiquette routée `provider/model`, par exemple `{ "deepseek-v4-flash": { "input": 0.14, "output": 0.28, "cacheRead": 0.0028, "cacheWrite": 0 } }`. Tout identifiant de modèle constitue une clé valide : les fournisseurs personnalisés peuvent cibler n'importe quel point de terminaison compatible avec OpenAI au moyen de l'adaptateur `openai-chat`, et les identifiants de fournisseur locaux ou internes fonctionnent même s'ils sont absents des catalogues intégrés. Les prix configurés par l'utilisateur priment sur les catalogues intégrés dans les estimations des pages Journaux (`~$`) et Utilisation. Les entrées historiques sont recalculées à partir de la surcharge actuelle ; modifier un prix peut donc changer les totaux antérieurs. L'ordre de repli est le suivant : `modelCosts` défini par l'utilisateur → catalogue jawcode → surcharge des prix attendus → repli propre au fournisseur au niveau du modèle. Une surcharge utilisateur explicitement définie à zéro produit une estimation nulle connue ; supprimez cette entrée pour rétablir la tarification automatique. Les prix de catalogue entièrement nuls restent soumis au repli. Chaque tarif doit être un nombre fini positif ou nul, inférieur ou égal à 1 000 000 (USD par 1M de jetons) ; les lignes hors plage sont rejetées par l'interface de gestion et ignorées au chargement. Ces valeurs servent uniquement à l'estimation lors de l'affichage : les surcharges n'affectent jamais le routage, la sélection des comptes, les quotas ni la facturation. | | `headers?` | `Record` | En-têtes supplémentaires en amont. L'autorisation, les cookies, les en-têtes de clé API, les nouvelles lignes intégrées et les noms invalides sont rejetés. | | `openRouterRouting?` | `OpenRouterProviderRouting` | Préférences OpenRouter `order`, `only` et `allowFallbacks` par défaut ; valable uniquement pour les OpenRouter canoniques avec `openai-chat`. | | `modelOpenRouterRouting?` | `Record` | Remplacements exacts de l'ID de modèle qui remplacent la préférence OpenRouter à l'échelle du fournisseur. | diff --git a/docs-site/src/content/docs/ja/reference/configuration/providers.md b/docs-site/src/content/docs/ja/reference/configuration/providers.md index 8938073e6c..e298d36559 100644 --- a/docs-site/src/content/docs/ja/reference/configuration/providers.md +++ b/docs-site/src/content/docs/ja/reference/configuration/providers.md @@ -93,7 +93,7 @@ account を削除しても mapping は保持され、同じ id を再追加す | `modelAutoCompactTokenLimits?` | `Record` | モデルごとの正の安全な整数によるソフト自動圧縮予算。実効値であるコンテキストまたは最大入力の 90% の上限を下げることだけができ、信頼できるコンテキストウィンドウが不明な場合は出力されません。canonical `openai` では、キーは provider や account-selector の接頭辞を含まない、サポート対象の正確なネイティブモデル ID でなければなりません。provider PATCH はエントリをマージし、キーを `null` にするとそのキーを削除し、フィールド全体を `null` にするとマップを消去します。これらの `null` tombstone は PATCH 専用です。 | | `defaultMaxOutputTokens?` | `number` |クライアントが `max_output_tokens` を省略した場合の、プロバイダー全体の `openai-chat` フォールバック。 | | `modelMaxOutputTokens?` | `Record` |モデルごとの `openai-chat` フォールバック バジェットがプラスになります。正確な/パターン一致はプロバイダーのデフォルトを上回ります。 | -| `modelCosts?` | `Record` | モデルごとの表示価格(100万トークンあたりの米ドル)。そのプロバイダーの正確なアップストリーム モデル ID をキーにします(プロバイダー識別子やルーティングされた `provider/model` ラベルではありません)。値は `input`, `output`, `cacheRead`, `cacheWrite` の 4 フィールドです(例: `{ "deepseek-v4-flash": { "input": 0.14, "output": 0.28, "cacheRead": 0.0028, "cacheWrite": 0 } }`)。組み込みカタログにないモデル ID も、任意の OpenAI 互換エンドポイントを対象とするカスタムプロバイダーや、ローカル・内部プロバイダーで有効です。ユーザー設定の価格は Logs の `~$` と Usage の見積もりで組み込みカタログより優先されます。過去のエントリも現在のオーバーレイで再計算されるため、価格を編集すると過去の合計が変わることがあります(フォールバック順: ユーザー設定 → jawcode カタログ → expected-price オーバーレイ → モデル別ベンダー価格)。全ゼロのエントリは次のソースにフォールバックします。各レートは 0 以上の有限数で、最大 1,000,000(100万トークンあたりの米ドル)です。範囲外の行は管理境界で拒否され、読み込み時に破棄されます。表示専用の見積もりであり、ルーティング・アカウント選択・クォータ・請求には影響しません。 | +| `modelCosts?` | `Record` | モデルごとの表示価格(100万トークンあたりの米ドル)。そのプロバイダーの正確なアップストリーム モデル ID をキーにします(プロバイダー識別子やルーティングされた `provider/model` ラベルではありません)。値は `input`, `output`, `cacheRead`, `cacheWrite` の 4 フィールドです(例: `{ "deepseek-v4-flash": { "input": 0.14, "output": 0.28, "cacheRead": 0.0028, "cacheWrite": 0 } }`)。組み込みカタログにないモデル ID も、任意の OpenAI 互換エンドポイントを対象とするカスタムプロバイダーや、ローカル・内部プロバイダーで有効です。ユーザー設定の価格は Logs の `~$` と Usage の見積もりで組み込みカタログより優先されます。過去のエントリも現在のオーバーレイで再計算されるため、価格を編集すると過去の合計が変わることがあります(フォールバック順: ユーザー設定 → jawcode カタログ → expected-price オーバーレイ → モデル別ベンダー価格)。ユーザーが明示的に全レートを 0 にした場合は、既知のゼロ料金として見積もります。自動料金に戻すにはそのモデルの設定を削除してください。カタログの全ゼロ料金は引き続きフォールバックします。各レートは 0 以上の有限数で、最大 1,000,000(100万トークンあたりの米ドル)です。範囲外の行は管理境界で拒否され、読み込み時に破棄されます。表示専用の見積もりであり、ルーティング・アカウント選択・クォータ・請求には影響しません。 | | `headers?` | `Record` |追加の上流ヘッダー。認証、Cookie、API キー ヘッダー、埋め込まれた改行、および無効な名前は拒否されます。 | | `openRouterRouting?` | `OpenRouterProviderRouting` |デフォルトの OpenRouter `order`、`only`、および `allowFallbacks` 設定。 `openai-chat` を持つ正規 OpenRouter に対してのみ有効です。 | | `modelOpenRouterRouting?` | `Record` |プロバイダー全体の OpenRouter 設定を置き換える正確なモデル ID のオーバーライド。 | diff --git a/docs-site/src/content/docs/ko/reference/configuration/providers.md b/docs-site/src/content/docs/ko/reference/configuration/providers.md index 2dda27e7bf..c37191745d 100644 --- a/docs-site/src/content/docs/ko/reference/configuration/providers.md +++ b/docs-site/src/content/docs/ko/reference/configuration/providers.md @@ -93,7 +93,7 @@ managed map을 활성화하면 privacy-safe selector를 만들고, 이후 계정 | `modelAutoCompactTokenLimits?` | `Record` | 모델별 양의 안전 정수형 소프트 자동 압축 예산입니다. 유효한 컨텍스트 또는 최대 입력의 90% 한도를 낮출 수만 있으며, 신뢰할 수 있는 컨텍스트 창을 알 수 없으면 내보내지 않습니다. canonical `openai`에서는 키가 공급자나 계정 선택자 접두사가 없는 정확한 지원 네이티브 모델 ID여야 합니다. 공급자 PATCH는 항목을 병합하며, 키를 `null`로 지정하면 해당 키를 삭제하고 필드 전체를 `null`로 지정하면 맵을 지웁니다. 이 `null` tombstone은 PATCH에서만 사용할 수 있습니다. | | `defaultMaxOutputTokens?` | `number` | 클라이언트가 `max_output_tokens`를 생략했을 때 쓰는 공급자 전반의 `openai-chat` 폴백입니다. | | `modelMaxOutputTokens?` | `Record` | 양수 모델별 `openai-chat` 폴백 예산입니다. 정확한 일치와 패턴 일치가 공급자 기본값보다 우선합니다. | -| `modelCosts?` | `Record` | 모델별 표시 가격(100만 토큰당 USD). 해당 공급자의 정확한 업스트림 모델 ID를 키로 사용하며(공급자 식별자나 라우팅된 `provider/model` 레이블이 아님) 값은 `input`, `output`, `cacheRead`, `cacheWrite` 네 필드입니다(예: `{ "deepseek-v4-flash": { "input": 0.14, "output": 0.28, "cacheRead": 0.0028, "cacheWrite": 0 } }`). 커스텀 공급자는 `openai-chat` 어댑터로 임의의 OpenAI 호환 엔드포인트를 대상으로 할 수 있으며, 내장 카탈로그에 없는 로컬·내부 공급자 ID도 유효합니다. 사용자 구성 가격은 Logs `~$` 및 Usage 추정에서 내장 카탈로그보다 우선합니다. 기존 항목도 현재 오버레이로 다시 계산되므로 가격을 편집하면 과거 합계가 바뀔 수 있습니다(폴백 순서: 사용자 설정 → jawcode 카탈로그 → expected-price 오버레이 → 모델별 벤더 가격). 전부 0인 항목은 다음 소스로 폴백합니다. 각 요율은 0 이상의 유한한 숫자이며 최대 1,000,000(100만 토큰당 USD)입니다. 범위를 벗어난 행은 관리 경계에서 거부되고 로드 시 삭제됩니다. 표시 전용 추정이며 라우팅·계정 선택·할당량·청구에는 영향을 주지 않습니다. | +| `modelCosts?` | `Record` | 모델별 표시 가격(100만 토큰당 USD). 해당 공급자의 정확한 업스트림 모델 ID를 키로 사용하며(공급자 식별자나 라우팅된 `provider/model` 레이블이 아님) 값은 `input`, `output`, `cacheRead`, `cacheWrite` 네 필드입니다(예: `{ "deepseek-v4-flash": { "input": 0.14, "output": 0.28, "cacheRead": 0.0028, "cacheWrite": 0 } }`). 커스텀 공급자는 `openai-chat` 어댑터로 임의의 OpenAI 호환 엔드포인트를 대상으로 할 수 있으며, 내장 카탈로그에 없는 로컬·내부 공급자 ID도 유효합니다. 사용자 구성 가격은 Logs `~$` 및 Usage 추정에서 내장 카탈로그보다 우선합니다. 기존 항목도 현재 오버레이로 다시 계산되므로 가격을 편집하면 과거 합계가 바뀔 수 있습니다(폴백 순서: 사용자 설정 → jawcode 카탈로그 → expected-price 오버레이 → 모델별 벤더 가격). 사용자가 모든 요율을 명시적으로 0으로 설정하면 비용을 0으로 추정합니다. 자동 가격으로 되돌리려면 해당 모델 항목을 삭제하세요. 카탈로그의 전부 0인 요율은 계속 다음 소스로 폴백합니다. 각 요율은 0 이상의 유한한 숫자이며 최대 1,000,000(100만 토큰당 USD)입니다. 범위를 벗어난 행은 관리 경계에서 거부되고 로드 시 삭제됩니다. 표시 전용 추정이며 라우팅·계정 선택·할당량·청구에는 영향을 주지 않습니다. | | `headers?` | `Record` | 추가 상위 헤더입니다. Authorization, cookies, API-key 헤더, 내장 개행, 잘못된 이름은 허용하지 않습니다. | | `openRouterRouting?` | `OpenRouterProviderRouting` | 기본 OpenRouter `order`, `only`, `allowFallbacks` 선호도입니다. 정식 OpenRouter와 `openai-chat`에서만 유효합니다. | | `modelOpenRouterRouting?` | `Record` | 공급자 전반의 OpenRouter 선호도를 덮어쓰는 정확한 모델 id별 재정의입니다. | diff --git a/docs-site/src/content/docs/reference/cli/providers-accounts.md b/docs-site/src/content/docs/reference/cli/providers-accounts.md index 3d602799bb..e92bf67874 100644 --- a/docs-site/src/content/docs/reference/cli/providers-accounts.md +++ b/docs-site/src/content/docs/reference/cli/providers-accounts.md @@ -508,6 +508,8 @@ proxy to be running (`ocx start`, or an installed service). | --- | --- | --- | | `list` (default) | `--provider `, `--json` | List models seeded in configured providers. | | `live` | `--provider `, `--json` | Read the running catalog, including models discovered at runtime. Rows are flagged `native`/`routed`, `custom`, and `enabled`/`disabled`. | +| `price ` | `--json` | Read the model's saved manual price override; no override means automatic pricing. | +| `set-price ` | `--input `, `--output `, `--cache-read `, `--cache-write `, `--auto`, `--json` | Set display prices in USD per 1M tokens. Input/output are required when setting; omitted cache rates become zero. `--auto` removes only this model's override. | | `add ` | `--display-name `, `--context-window `, `--modalities ` | Register a model the provider catalog does not advertise. | | `edit ` | `--model-id `, `--display-name `, `--context-window `, `--modalities `, `--json` | Edit a custom model. `-` clears a field; `0` clears the context window. | | `remove ` | `--yes` | Delete a custom model. Requires `--yes` when stdin is not an interactive terminal. | diff --git a/docs-site/src/content/docs/reference/configuration/providers.md b/docs-site/src/content/docs/reference/configuration/providers.md index b0792b7367..0deb12616f 100644 --- a/docs-site/src/content/docs/reference/configuration/providers.md +++ b/docs-site/src/content/docs/reference/configuration/providers.md @@ -149,7 +149,7 @@ predictions. Explicit provider/model price overrides still take precedence. | `modelAutoCompactTokenLimits?` | `Record` | Positive safe-integer per-model soft auto-compaction budgets. Values can only lower the effective 90%-of-context/max-input envelope and are omitted when no authoritative context window is known. For canonical `openai`, keys must be exact supported native model IDs without provider or account-selector prefixes. Provider PATCH merges entries; set a key to `null` to delete it or the whole field to `null` to clear the map. These `null` tombstones are PATCH-only. | | `defaultMaxOutputTokens?` | `number` | Provider-wide `openai-chat` fallback when the client omits `max_output_tokens`. | | `modelMaxOutputTokens?` | `Record` | Positive per-model `openai-chat` fallback budgets; exact/pattern matches beat the provider default. | -| `modelCosts?` | `Record` | Per-model display prices (USD per 1M tokens), keyed by that provider's exact upstream model id — not a provider identifier or a routed `provider/model` label, e.g. `{ "deepseek-v4-flash": { "input": 0.14, "output": 0.28, "cacheRead": 0.0028, "cacheWrite": 0 } }`. Any model id is a valid key — custom providers may target any OpenAI-compatible endpoint through the `openai-chat` adapter, and local or internal provider ids work even when they are absent from the built-in catalogs. User-configured prices win over the built-in catalogs in the Logs `~$` and Usage estimates; historical entries are repriced from the current overlay, so editing a price can move past totals. The fallback order is user `modelCosts` → exact official correction → jawcode catalog → expected-price overlay → model-level vendor fallback, and an all-zero entry falls through to the next source in that sequence. Each rate must be a non-negative finite number at most 1,000,000 (USD per 1M tokens); out-of-range rows are rejected by the management boundary and dropped on load. Display-time estimation only: overlays never affect routing, account selection, quotas, or billing. | +| `modelCosts?` | `Record` | Per-model display prices (USD per 1M tokens), keyed by that provider's exact upstream model id — not a provider identifier or a routed `provider/model` label, e.g. `{ "deepseek-v4-flash": { "input": 0.14, "output": 0.28, "cacheRead": 0.0028, "cacheWrite": 0 } }`. Any model id is a valid key — custom providers may target any OpenAI-compatible endpoint through the `openai-chat` adapter, and local or internal provider ids work even when they are absent from the built-in catalogs. User-configured prices win over the built-in catalogs in the Logs `~$` and Usage estimates; historical entries are repriced from the current overlay, so editing a price can move past totals. The fallback order is user `modelCosts` → exact official correction → jawcode catalog → expected-price overlay → model-level vendor fallback, and an explicit all-zero user entry means a known-zero estimate; delete that model entry to restore automatic pricing. All-zero catalog metadata still falls through. Each rate must be a non-negative finite number at most 1,000,000 (USD per 1M tokens); out-of-range rows are rejected by the management boundary and dropped on load. Display-time estimation only: overlays never affect routing, account selection, quotas, or billing. | | `headers?` | `Record` | Extra upstream headers. Authorization, cookies, API-key headers, embedded newlines, and invalid names are rejected. | | `openRouterRouting?` | `OpenRouterProviderRouting` | Default OpenRouter `order`, `only`, and `allowFallbacks` preferences; valid only for canonical OpenRouter with `openai-chat`. | | `modelOpenRouterRouting?` | `Record` | Exact model-id overrides that replace the provider-wide OpenRouter preference. | diff --git a/docs-site/src/content/docs/reference/management-api.md b/docs-site/src/content/docs/reference/management-api.md index a4ea3ad3d9..0b3598eac8 100644 --- a/docs-site/src/content/docs/reference/management-api.md +++ b/docs-site/src/content/docs/reference/management-api.md @@ -228,6 +228,29 @@ re-estimated from the pricing active when the summary is read. This is an API-eq not a subscription charge. New main-pool requests use the reserved `main` label; legacy bare `openai` rows remain in an ambiguous bucket instead of being reassigned from current configuration. +Manual model prices can also be edited from **Models → Price**. A manual-pricing badge survives +catalog reloads. Prices are stored in `providers..modelCosts` and survive catalog sync. +Explicit all-zero user rates mean a known-zero estimate; **Reset to automatic** removes the +override and restores the usual catalog fallback. These remain display estimates, not bills. + +`GET /api/providers/{provider}/model-costs` returns `{ provider, modelCosts }`, with sanitized +four-rate entries keyed by exact upstream model ID. `PUT` on the same route accepts +`{ modelId, cost }`, where `cost` is `{ input, output, cacheRead, cacheWrite }` or `null` to reset. +All four rates must be finite numbers from 0 through 1,000,000, in USD per 1M tokens. +Unknown fields and malformed rates are rejected. A write preserves other models' overrides +and returns `{ ok: true, provider, modelId, cost }`; reset returns `cost: null`. + +```bash +ocx models price ollama/custom-model --json +ocx models set-price ollama/custom-model --input 0.50 --output 1.50 +ocx models set-price ollama/custom-model --input 0 --output 0 +ocx models set-price ollama/custom-model --auto +``` + +Omitted CLI cache-read/cache-write rates default to zero. Use `--cache-read` and `--cache-write` +to set them explicitly. A provider name remains an exact configuration identity; account display +labels are not editable provider names. + Rows in `models`, `providers`, and `days[].models` also carry `cacheHitRate`: the share of input tokens served from the provider's prompt cache, clamped to `[0, 1]`. It is `null` — never `0` — when the provider reported no cache telemetry or the row has no input tokens, because "no cache diff --git a/docs-site/src/content/docs/ru/reference/configuration/providers.md b/docs-site/src/content/docs/ru/reference/configuration/providers.md index 14a8b0a3ce..7704a9cbda 100644 --- a/docs-site/src/content/docs/ru/reference/configuration/providers.md +++ b/docs-site/src/content/docs/ru/reference/configuration/providers.md @@ -106,7 +106,7 @@ cross-route credential fallback не существует. Строки API GPT- | `modelAutoCompactTokenLimits?` | `Record` | Мягкие бюджеты автосжатия по моделям в виде положительных безопасных целых чисел. Они могут только уменьшать эффективную границу в 90 % контекста или максимального ввода и не выдаются, если авторитетное окно контекста неизвестно. Для канонического `openai` ключами могут быть только точные поддерживаемые ID нативных моделей без префиксов провайдера или селектора аккаунта. PATCH провайдера объединяет записи: `null` для ключа удаляет его, а `null` для всего поля очищает карту. Такие маркеры `null` допустимы только в PATCH. | | `defaultMaxOutputTokens?` | `number` | Provider-wide fallback для `openai-chat`, когда клиент не передал `max_output_tokens`. | | `modelMaxOutputTokens?` | `Record` | Положительные fallback-budget'ы `openai-chat` по моделям; exact/pattern-match имеет приоритет над provider-default. | -| `modelCosts?` | `Record` | Отображаемые цены по моделям (USD за 1M токенов), ключ — точный upstream id модели этого провайдера (не идентификатор провайдера и не маршрутизируемая метка `provider/model`), значение — четыре поля: `input`, `output`, `cacheRead`, `cacheWrite` (пример: `{ "deepseek-v4-flash": { "input": 0.14, "output": 0.28, "cacheRead": 0.0028, "cacheWrite": 0 } }`). Любой id допустим — кастомный провайдер может указывать на любой OpenAI-совместимый endpoint через адаптер `openai-chat`, а локальные и внутренние провайдеры работают даже без строки во встроенных каталогах. Пользовательские цены имеют приоритет над встроенными каталогами в оценках `~$` в Logs и Usage; исторические записи пересчитываются по текущему оверлею, поэтому изменение цены может сдвинуть прошлые суммы (порядок: пользователь → каталог jawcode → expected-price overlay → вендорская цена модели); полностью нулевая запись переходит к следующему источнику. Каждая ставка должна быть неотрицательным конечным числом не более 1 000 000 (USD за 1M токенов); строки вне диапазона отклоняются на управляющей границе и отбрасываются при загрузке. Только оценка для отображения: оверлеи не влияют на маршрутизацию, выбор аккаунта, квоты или биллинг. | +| `modelCosts?` | `Record` | Отображаемые цены по моделям (USD за 1M токенов), ключ — точный upstream id модели этого провайдера (не идентификатор провайдера и не маршрутизируемая метка `provider/model`), значение — четыре поля: `input`, `output`, `cacheRead`, `cacheWrite` (пример: `{ "deepseek-v4-flash": { "input": 0.14, "output": 0.28, "cacheRead": 0.0028, "cacheWrite": 0 } }`). Любой id допустим — кастомный провайдер может указывать на любой OpenAI-совместимый endpoint через адаптер `openai-chat`, а локальные и внутренние провайдеры работают даже без строки во встроенных каталогах. Пользовательские цены имеют приоритет над встроенными каталогами в оценках `~$` в Logs и Usage; исторические записи пересчитываются по текущему оверлею, поэтому изменение цены может сдвинуть прошлые суммы (порядок: пользователь → каталог jawcode → expected-price overlay → вендорская цена модели); явно заданный пользователем набор нулевых ставок означает известную нулевую оценку; удалите запись модели, чтобы восстановить автоматическую цену. Нулевые цены каталога по-прежнему переходят к следующему источнику. Каждая ставка должна быть неотрицательным конечным числом не более 1 000 000 (USD за 1M токенов); строки вне диапазона отклоняются на управляющей границе и отбрасываются при загрузке. Только оценка для отображения: оверлеи не влияют на маршрутизацию, выбор аккаунта, квоты или биллинг. | | `headers?` | `Record` | Дополнительные upstream-header'ы. Заголовки авторизации, cookie, API-key-header'ы, встроенные переводы строк и невалидные имена отклоняются. | | `openRouterRouting?` | `OpenRouterProviderRouting` | Предпочтения по умолчанию для OpenRouter (`order`, `only`, `allowFallbacks`); валидно только для канонического OpenRouter с `openai-chat`. | | `modelOpenRouterRouting?` | `Record` | Exact override по model id, которые полностью заменяют provider-wide preference для OpenRouter. | diff --git a/docs-site/src/content/docs/tr/reference/configuration/providers.md b/docs-site/src/content/docs/tr/reference/configuration/providers.md index 3e01051010..65d0d7eca7 100644 --- a/docs-site/src/content/docs/tr/reference/configuration/providers.md +++ b/docs-site/src/content/docs/tr/reference/configuration/providers.md @@ -111,7 +111,7 @@ alanlı seçilmiş kimlikleri yalın kimliklere yeniden yazar. | `modelAutoCompactTokenLimits?` | `Record` | Model başına pozitif güvenli tamsayı biçiminde yumuşak otomatik sıkıştırma bütçeleri. Değerler yalnızca bağlamın veya maksimum girdinin etkin %90 zarfını düşürebilir ve yetkili bir bağlam penceresi bilinmiyorsa yayımlanmaz. Canonical `openai` için anahtarlar, sağlayıcı veya hesap seçici öneki olmadan desteklenen tam yerel model kimlikleri olmalıdır. Sağlayıcı PATCH girdileri birleştirir; bir anahtarı `null` yapmak o anahtarı siler, alanın tamamını `null` yapmak haritayı temizler. Bu `null` silme işaretleri yalnızca PATCH içindir. | | `defaultMaxOutputTokens?` | `number` | İstemci `max_output_tokens` değerini atladığında sağlayıcı genelinde `openai-chat` geri dönüşü. | | `modelMaxOutputTokens?` | `Record` | Pozitif model başına `openai-chat` geri dönüş bütçeleri; tam/kalıp eşleşmeleri sağlayıcı varsayılanını yener. | -| `modelCosts?` | `Record` | Sağlayıcının tam yukarı akış model kimliğine göre anahtarlanan model başına görüntüleme fiyatları (1M token başına USD) — bir sağlayıcı tanımlayıcısı veya yönlendirilen `provider/model` etiketi değil, örn. `{ "deepseek-v4-flash": { "input": 0.14, "output": 0.28, "cacheRead": 0.0028, "cacheWrite": 0 } }`. Herhangi bir model kimliği geçerli bir anahtardır — özel sağlayıcılar `openai-chat` adaptörü aracılığıyla herhangi bir OpenAI uyumlu uç noktayı hedefleyebilir ve yerel veya dahili sağlayıcı kimlikleri yerleşik kataloglarda bulunmasalar bile çalışır. Kullanıcı tarafından yapılandırılan fiyatlar Günlükler `~$` ve Kullanım tahminlerinde yerleşik katalogları yener; geçmiş girdiler geçerli katmandan yeniden fiyatlandırılır, bu nedenle bir fiyatı düzenlemek geçmiş toplamları değiştirebilir. Geri dönüş sırası: kullanıcı `modelCosts` → jawcode kataloğu → beklenen fiyat katmanı → model düzeyinde satıcı geri dönüşü ve tamamen sıfır bir girdi bu dizideki bir sonraki kaynağa düşer. Her oran en fazla 1.000.000 (1M token başına USD) olan negatif olmayan sonlu bir sayı olmalıdır; aralık dışı satırlar yönetim sınırı tarafından reddedilir ve yükleme sırasında bırakılır. Yalnızca görüntüleme zamanı tahmini: katmanlar yönlendirmeyi, hesap seçimini, kotaları veya faturalandırmayı asla etkilemez. | +| `modelCosts?` | `Record` | Sağlayıcının tam yukarı akış model kimliğine göre anahtarlanan model başına görüntüleme fiyatları (1M token başına USD) — bir sağlayıcı tanımlayıcısı veya yönlendirilen `provider/model` etiketi değil, örn. `{ "deepseek-v4-flash": { "input": 0.14, "output": 0.28, "cacheRead": 0.0028, "cacheWrite": 0 } }`. Herhangi bir model kimliği geçerli bir anahtardır — özel sağlayıcılar `openai-chat` adaptörü aracılığıyla herhangi bir OpenAI uyumlu uç noktayı hedefleyebilir ve yerel veya dahili sağlayıcı kimlikleri yerleşik kataloglarda bulunmasalar bile çalışır. Kullanıcı tarafından yapılandırılan fiyatlar Günlükler `~$` ve Kullanım tahminlerinde yerleşik katalogları yener; geçmiş girdiler geçerli katmandan yeniden fiyatlandırılır, bu nedenle bir fiyatı düzenlemek geçmiş toplamları değiştirebilir. Geri dönüş sırası: kullanıcı `modelCosts` → jawcode kataloğu → beklenen fiyat katmanı → model düzeyinde satıcı geri dönüşü ve kullanıcının açıkça sıfır olarak belirlediği oranlar bilinen sıfır maliyetli bir tahmin üretir; otomatik fiyatlandırmaya dönmek için model girdisini silin. Tamamen sıfır katalog fiyatları bir sonraki kaynağa geçmeye devam eder. Her oran en fazla 1.000.000 (1M token başına USD) olan negatif olmayan sonlu bir sayı olmalıdır; aralık dışı satırlar yönetim sınırı tarafından reddedilir ve yükleme sırasında bırakılır. Yalnızca görüntüleme zamanı tahmini: katmanlar yönlendirmeyi, hesap seçimini, kotaları veya faturalandırmayı asla etkilemez. | | `headers?` | `Record` | Ek yukarı akış başlıkları. Yetkilendirme, çerezler, API anahtarı başlıkları, gömülü yeni satırlar ve geçersiz adlar reddedilir. | | `openRouterRouting?` | `OpenRouterProviderRouting` | Varsayılan OpenRouter `order`, `only` ve `allowFallbacks` tercihleri; yalnızca `openai-chat` ile kurallı OpenRouter için geçerlidir. | | `modelOpenRouterRouting?` | `Record` | Sağlayıcı genelindeki OpenRouter tercihinin yerini alan tam model kimliği geçersiz kılmaları. | diff --git a/docs-site/src/content/docs/zh-cn/reference/configuration/providers.md b/docs-site/src/content/docs/zh-cn/reference/configuration/providers.md index 32f2b52a69..e01ab6f51a 100644 --- a/docs-site/src/content/docs/zh-cn/reference/configuration/providers.md +++ b/docs-site/src/content/docs/zh-cn/reference/configuration/providers.md @@ -93,7 +93,7 @@ selector,而不是分配一个新名称。 | `modelAutoCompactTokenLimits?` | `Record` | 按模型设置的正安全整数软自动压缩预算。该值只能降低“上下文或最大输入的 90%”这一有效上限;没有已知的权威上下文窗口时不会输出。对于规范 `openai`,键必须是受支持的精确原生模型 ID,且不得包含提供者或账户选择器前缀。提供者 PATCH 会合并条目;将某个键设为 `null` 会删除该键,将整个字段设为 `null` 会清空映射。这些 `null` 删除标记仅适用于 PATCH。 | | `defaultMaxOutputTokens?` | `number` | 当客户端省略 `max_output_tokens` 时,`openai-chat` 的提供者级回退值。 | | `modelMaxOutputTokens?` | `Record` | 正数型、按模型设置的 `openai-chat` 回退预算;精确/模式匹配优先于提供者默认值。 | -| `modelCosts?` | `Record` | 按模型设置的显示价格(每 100 万 token 的美元数),以该提供者的精确上游模型 ID 为键(不是提供者标识符或路由后的 `provider/model` 标签),值为四个字段:`input`、`output`、`cacheRead`、`cacheWrite`(示例:`{ "deepseek-v4-flash": { "input": 0.14, "output": 0.28, "cacheRead": 0.0028, "cacheWrite": 0 } }`)。任何模型 ID 都是有效键——自定义提供者可以通过 `openai-chat` 适配器指向任意 OpenAI 兼容端点,即使不存在于内置目录中,本地 OpenAI 兼容和内部提供者的 ID 同样有效。用户配置的价格在 Logs 的 `~$` 和 Usage 估算中优先于内置目录;历史条目也会按当前覆盖项重新计价,因此修改价格可能改变过去的总额(回退顺序:用户配置 → jawcode 目录 → expected-price 覆盖 → 模型级厂商价格);全零条目会回退到该顺序中的下一个来源。每个费率必须是大于等于 0 的有限数字,且不超过 1,000,000(每 100 万 token 的美元数);超出范围的条目会在管理边界被拒绝,并在加载时被丢弃。仅用于显示的估算:覆盖项不影响路由、账户选择、配额或计费。 | +| `modelCosts?` | `Record` | 按模型设置的显示价格(每 100 万 token 的美元数),以该提供者的精确上游模型 ID 为键(不是提供者标识符或路由后的 `provider/model` 标签),值为四个字段:`input`、`output`、`cacheRead`、`cacheWrite`(示例:`{ "deepseek-v4-flash": { "input": 0.14, "output": 0.28, "cacheRead": 0.0028, "cacheWrite": 0 } }`)。任何模型 ID 都是有效键——自定义提供者可以通过 `openai-chat` 适配器指向任意 OpenAI 兼容端点,即使不存在于内置目录中,本地 OpenAI 兼容和内部提供者的 ID 同样有效。用户配置的价格在 Logs 的 `~$` 和 Usage 估算中优先于内置目录;历史条目也会按当前覆盖项重新计价,因此修改价格可能改变过去的总额(回退顺序:用户配置 → jawcode 目录 → expected-price 覆盖 → 模型级厂商价格);用户明确将所有费率设为零时,会得到已知的零费用估算;删除该模型的覆盖项即可恢复自动定价。目录中的全零价格仍会回退到下一个来源。每个费率必须是大于等于 0 的有限数字,且不超过 1,000,000(每 100 万 token 的美元数);超出范围的条目会在管理边界被拒绝,并在加载时被丢弃。仅用于显示的估算:覆盖项不影响路由、账户选择、配额或计费。 | | `headers?` | `Record` | 额外的上游请求头。会拒绝 Authorization、cookie、API key 头、嵌入换行符以及无效名称。 | | `openRouterRouting?` | `OpenRouterProviderRouting` | 默认的 OpenRouter `order`、`only` 和 `allowFallbacks` 偏好;仅对使用 `openai-chat` 的规范 OpenRouter 有效。 | | `modelOpenRouterRouting?` | `Record` | 精确模型 id 级别的覆盖项,会替换提供者级 OpenRouter 偏好。 | diff --git a/gui/src/components/ModelPriceDialog.tsx b/gui/src/components/ModelPriceDialog.tsx new file mode 100644 index 0000000000..c4e08d98b6 --- /dev/null +++ b/gui/src/components/ModelPriceDialog.tsx @@ -0,0 +1,235 @@ +import { Fragment, useCallback, useEffect, useId, useRef, useState } from "react"; +import { createBoundedFetch, type BoundedFetch } from "../bounded-fetch"; +import { readJsonOrThrow } from "../fetch-json"; +import { useT, type TKey } from "../i18n/shared"; +import type { ModelRow } from "../pages/models-shared"; + +interface Cost4 { + input: number; + output: number; + cacheRead: number; + cacheWrite: number; +} + +const RATE_FIELDS = ["input", "output", "cacheRead", "cacheWrite"] as const; +const RATE_LABELS: Record = { + input: "pricing.override.input", + output: "pricing.override.output", + cacheRead: "pricing.override.cacheRead", + cacheWrite: "pricing.override.cacheWrite", +}; +const MAX_RATE = 1_000_000; +const REQUEST_TIMEOUT_MS = 60_000; +const EMPTY_DRAFT = { input: "", output: "", cacheRead: "", cacheWrite: "" }; +type Phase = "loading" | "loadFailed" | "ready" | "saving" | "unknown" | "refreshing" | "refreshFailed"; + +function isRecord(value: unknown): value is Record { + return value !== null && typeof value === "object" && !Array.isArray(value); +} + +function isCost(value: unknown): value is Cost4 { + return isRecord(value) && RATE_FIELDS.every(field => ( + typeof value[field] === "number" && Number.isFinite(value[field]) + && value[field] >= 0 && value[field] <= MAX_RATE + )); +} + +interface ModelPriceDialogProps { + model: ModelRow; + apiBase: string; + onRefresh: (signal: AbortSignal) => Promise; + onClose: () => void; +} + +export default function ModelPriceDialog({ model, apiBase, onRefresh, onClose }: ModelPriceDialogProps) { + const t = useT(); + const id = useId(); + const dialogRef = useRef(null); + const inputRef = useRef(null); + const submitRef = useRef(null); + const requestRef = useRef(null); + const mutationPendingRef = useRef(false); + const [phase, setPhase] = useState("loading"); + const [draft, setDraft] = useState(EMPTY_DRAFT); + const [hasOverride, setHasOverride] = useState(false); + const [errorKey, setErrorKey] = useState(null); + const [recovered, setRecovered] = useState(false); + const endpoint = `${apiBase}/api/providers/${encodeURIComponent(model.provider)}/model-costs`; + const mutating = phase === "saving" || phase === "refreshing"; + const locked = phase !== "ready"; + + const readOverride = useCallback(async (recover = false) => { + if (requestRef.current) return; + const bounded = createBoundedFetch(REQUEST_TIMEOUT_MS); + requestRef.current = bounded; + setPhase("loading"); + setErrorKey(null); + try { + const response = await fetch(endpoint, { signal: bounded.signal, cache: "no-store" }); + const result = await readJsonOrThrow(response); + bounded.signal.throwIfAborted(); + if (!isRecord(result) || result.provider !== model.provider || !isRecord(result.modelCosts)) { + throw new Error("invalid model-costs response"); + } + const cost = Object.hasOwn(result.modelCosts, model.id) ? result.modelCosts[model.id] : undefined; + if (cost !== undefined && !isCost(cost)) throw new Error("invalid model cost"); + if (requestRef.current !== bounded) return; + setDraft(cost === undefined ? EMPTY_DRAFT : { + input: String(cost.input), output: String(cost.output), + cacheRead: String(cost.cacheRead), cacheWrite: String(cost.cacheWrite), + }); + setHasOverride(cost !== undefined); + // This read recovers an editable snapshot, not ordering against an earlier + // request still running on the server or writes from another client. + setRecovered(recover); + setPhase("ready"); + } catch { + if (requestRef.current !== bounded) return; + setPhase(recover ? "unknown" : "loadFailed"); + setErrorKey(recover ? "pricing.override.recoveryFailed" : "pricing.override.loadFailed"); + } finally { + bounded.clear(); + if (requestRef.current === bounded) requestRef.current = null; + } + }, [endpoint, model.id, model.provider]); + + useEffect(() => { + const dialog = dialogRef.current; + if (dialog && !dialog.open) dialog.showModal(); + void readOverride(); + return () => { + requestRef.current?.controller.abort(); + requestRef.current?.clear(); + requestRef.current = null; + if (dialog?.open) dialog.close(); + }; + }, [readOverride]); + + useEffect(() => { + if (phase === "ready") inputRef.current?.focus(); + else if (phase === "unknown" || phase === "loadFailed" || phase === "refreshFailed") submitRef.current?.focus(); + }, [phase]); + + // undefined retries only catalog refresh after a validated persistence receipt. + const save = async (cost: Cost4 | null | undefined) => { + if (requestRef.current || (cost === undefined ? phase !== "refreshFailed" : phase !== "ready")) return; + const bounded = createBoundedFetch(REQUEST_TIMEOUT_MS); + requestRef.current = bounded; + setPhase(cost === undefined ? "refreshing" : "saving"); + mutationPendingRef.current = true; + setErrorKey(null); + let confirmed = cost === undefined; + try { + if (cost !== undefined) { + const response = await fetch(endpoint, { + method: "PUT", headers: { "content-type": "application/json" }, + body: JSON.stringify({ modelId: model.id, cost }), signal: bounded.signal, + }); + const result = await readJsonOrThrow(response); + bounded.signal.throwIfAborted(); + const receiptCost = isRecord(result) ? result.cost : undefined; + if (!isRecord(result) || result.ok !== true || result.provider !== model.provider + || result.modelId !== model.id || (cost === null ? receiptCost !== null + : !isCost(receiptCost) || !RATE_FIELDS.every(field => receiptCost[field] === cost[field]))) { + throw new Error("invalid model-costs receipt"); + } + if (requestRef.current !== bounded) return; + confirmed = true; + setPhase("refreshing"); + } + if (!await onRefresh(bounded.signal)) throw new Error("catalog refresh failed"); + bounded.signal.throwIfAborted(); + if (requestRef.current === bounded) onClose(); + } catch { + if (requestRef.current !== bounded) return; + setPhase(confirmed ? "refreshFailed" : "unknown"); + setErrorKey(confirmed ? "pricing.override.refreshFailed" : "pricing.override.outcomeUnknown"); + } finally { + bounded.clear(); + if (requestRef.current === bounded) { + requestRef.current = null; + mutationPendingRef.current = false; + } + } + }; + + const requestClose = () => { + if (!mutationPendingRef.current) onClose(); + }; + + return ( + { event.preventDefault(); requestClose(); }}> + +
+
+ {t("pricing.override.modelId")} + {model.namespaced} +
+

{t("pricing.override.help")}

+ {phase === "loading" &&

{t("pricing.override.loading")}

} + {RATE_FIELDS.map(field => ( + + + { + if (locked || requestRef.current) return; + const value = event.target.value; + setDraft(current => ({ + ...current, + cacheRead: current.cacheRead || "0", cacheWrite: current.cacheWrite || "0", + [field]: value, + })); + setErrorKey(null); + }} /> + + ))} + {recovered &&

{t("pricing.override.recovered")}

} + {errorKey && } +
+ + + +
+ + + ); +} diff --git a/gui/src/i18n/de.ts b/gui/src/i18n/de.ts index 4145cb8032..a361962237 100644 --- a/gui/src/i18n/de.ts +++ b/gui/src/i18n/de.ts @@ -2591,4 +2591,28 @@ export const de: Record = { "models.displayNameTooLong": "Der Anzeigename darf höchstens 128 Zeichen lang sein.", "models.displayNameNoSlash": "Der Anzeigename darf kein / enthalten.", "models.displayNameNoControl": "Der Anzeigename darf keine Steuerzeichen enthalten.", + "pricing.override.action": "Preis", + "pricing.override.actionLabel": "Preis für {model} bearbeiten", + "pricing.override.badge": "Manueller Preis", + "pricing.override.title": "Modellpreis", + "pricing.override.modelId": "Modell-ID", + "pricing.override.help": "USD pro 1 Mio. Token. Ein- und Ausgaberaten eingeben; leere Cache-Raten gelten als 0. Vier Raten von 0 bedeuten kostenlos.", + "pricing.override.input": "Eingabe", + "pricing.override.output": "Ausgabe", + "pricing.override.cacheRead": "Cache lesen", + "pricing.override.cacheWrite": "Cache schreiben", + "pricing.override.loading": "Gespeicherten Preis laden…", + "pricing.override.loadFailed": "Der gespeicherte Preis konnte nicht geladen werden. Erneut laden.", + "pricing.override.outcomeUnknown": "Das Ergebnis der Anfrage ist unklar. Der Preis könnte geändert worden sein. Vor weiteren Änderungen den gespeicherten Preis neu laden.", + "pricing.override.recoveryFailed": "Der gespeicherte Preis konnte nicht ermittelt werden. Die Bearbeitung bleibt gesperrt; erneut laden.", + "pricing.override.recovered": "Aktueller gespeicherter Preis geladen. Die frühere Anfrage oder ein anderer Client kann ihn noch ändern.", + "pricing.override.refreshFailed": "Der Preis wurde gespeichert, aber die Modellliste konnte nicht aktualisiert werden. Die Liste erneut aktualisieren.", + "pricing.override.invalid": "Ein- und Ausgaberaten eingeben. Jede Rate muss eine endliche Zahl zwischen 0 und 1.000.000 sein.", + "pricing.override.reset": "Automatischen Preis verwenden", + "pricing.override.save": "Speichern", + "pricing.override.saving": "Speichern…", + "pricing.override.reload": "Preis neu laden", + "pricing.override.refresh": "Liste aktualisieren", + "pricing.override.cancel": "Abbrechen", + "pricing.override.close": "Schließen", }; diff --git a/gui/src/i18n/en.ts b/gui/src/i18n/en.ts index 2a31ec7947..ff45937f47 100644 --- a/gui/src/i18n/en.ts +++ b/gui/src/i18n/en.ts @@ -2625,6 +2625,30 @@ export const en = { "models.displayNameTooLong": "Friendly name must be 128 characters or fewer.", "models.displayNameNoSlash": "Friendly name cannot contain /.", "models.displayNameNoControl": "Friendly name cannot contain control characters.", + "pricing.override.action": "Price", + "pricing.override.actionLabel": "Edit price for {model}", + "pricing.override.badge": "Manual price", + "pricing.override.title": "Model price", + "pricing.override.modelId": "Model ID", + "pricing.override.help": "USD per 1M tokens. Enter input and output rates; blank cache rates use 0. All four rates set to 0 mean free.", + "pricing.override.input": "Input", + "pricing.override.output": "Output", + "pricing.override.cacheRead": "Cache read", + "pricing.override.cacheWrite": "Cache write", + "pricing.override.loading": "Loading saved price…", + "pricing.override.loadFailed": "Could not load the saved price. Reload to try again.", + "pricing.override.outcomeUnknown": "The request did not finish reliably. The price may have changed. Reload the saved price before editing again.", + "pricing.override.recoveryFailed": "Could not recover the saved price. Editing stays locked; reload to try again.", + "pricing.override.recovered": "Latest saved price loaded. The earlier request or another client may still change it.", + "pricing.override.refreshFailed": "The price was saved, but the model list could not be refreshed. Retry the list refresh.", + "pricing.override.invalid": "Enter input and output rates. Every rate must be a finite number from 0 to 1,000,000.", + "pricing.override.reset": "Reset to automatic", + "pricing.override.save": "Save", + "pricing.override.saving": "Saving…", + "pricing.override.reload": "Reload price", + "pricing.override.refresh": "Refresh list", + "pricing.override.cancel": "Cancel", + "pricing.override.close": "Close", } as const; export type TKey = keyof typeof en; diff --git a/gui/src/i18n/fr.ts b/gui/src/i18n/fr.ts index 753982c1bf..eafe430758 100644 --- a/gui/src/i18n/fr.ts +++ b/gui/src/i18n/fr.ts @@ -2578,4 +2578,28 @@ export const fr: Record = { "models.displayNameTooLong": "Le nom d’affichage doit contenir au maximum 128 caractères.", "models.displayNameNoSlash": "Le nom d’affichage ne peut pas contenir /.", "models.displayNameNoControl": "Le nom d’affichage ne peut pas contenir de caractères de contrôle.", + "pricing.override.action": "Prix", + "pricing.override.actionLabel": "Modifier le prix de {model}", + "pricing.override.badge": "Prix manuel", + "pricing.override.title": "Prix du modèle", + "pricing.override.modelId": "ID du modèle", + "pricing.override.help": "USD par million de tokens. Saisissez les tarifs d’entrée et de sortie ; un tarif de cache vide vaut 0. Quatre tarifs à 0 signifient gratuit.", + "pricing.override.input": "Entrée", + "pricing.override.output": "Sortie", + "pricing.override.cacheRead": "Lecture du cache", + "pricing.override.cacheWrite": "Écriture du cache", + "pricing.override.loading": "Chargement du prix enregistré…", + "pricing.override.loadFailed": "Impossible de charger le prix enregistré. Rechargez pour réessayer.", + "pricing.override.outcomeUnknown": "Le résultat de la requête est incertain. Le prix a peut-être changé. Rechargez le prix enregistré avant toute autre modification.", + "pricing.override.recoveryFailed": "Impossible de récupérer le prix enregistré. La modification reste verrouillée ; rechargez pour réessayer.", + "pricing.override.recovered": "Le prix actuellement enregistré est chargé. La requête précédente ou un autre client peut encore le modifier.", + "pricing.override.refreshFailed": "Le prix est enregistré, mais la liste des modèles n’a pas pu être actualisée. Réessayez l’actualisation.", + "pricing.override.invalid": "Saisissez les tarifs d’entrée et de sortie. Chaque tarif doit être un nombre fini entre 0 et 1 000 000.", + "pricing.override.reset": "Revenir au prix automatique", + "pricing.override.save": "Enregistrer", + "pricing.override.saving": "Enregistrement…", + "pricing.override.reload": "Recharger le prix", + "pricing.override.refresh": "Actualiser la liste", + "pricing.override.cancel": "Annuler", + "pricing.override.close": "Fermer", }; diff --git a/gui/src/i18n/ja.ts b/gui/src/i18n/ja.ts index 300d1f8c51..6fe289e48c 100644 --- a/gui/src/i18n/ja.ts +++ b/gui/src/i18n/ja.ts @@ -2612,4 +2612,28 @@ export const ja: Record = { "models.displayNameTooLong": "表示名は 128 文字以内にしてください。", "models.displayNameNoSlash": "表示名に / は使用できません。", "models.displayNameNoControl": "表示名に制御文字は使用できません。", + "pricing.override.action": "価格", + "pricing.override.actionLabel": "{model} の価格を編集", + "pricing.override.badge": "手動価格", + "pricing.override.title": "モデル価格", + "pricing.override.modelId": "モデル ID", + "pricing.override.help": "100万トークンあたりの USD です。入力・出力単価を入力してください。空のキャッシュ単価は 0 とし、4項目すべてが 0 なら無料です。", + "pricing.override.input": "入力", + "pricing.override.output": "出力", + "pricing.override.cacheRead": "キャッシュ読み取り", + "pricing.override.cacheWrite": "キャッシュ書き込み", + "pricing.override.loading": "保存済み価格を読み込み中…", + "pricing.override.loadFailed": "保存済み価格を読み込めませんでした。再読み込みしてください。", + "pricing.override.outcomeUnknown": "リクエストの結果を確認できませんでした。価格が変更された可能性があります。編集する前に保存済み価格を再読み込みしてください。", + "pricing.override.recoveryFailed": "保存済み価格を確認できないため、編集はロックされています。再読み込みしてください。", + "pricing.override.recovered": "現在の保存済み価格を読み込みました。先ほどのリクエストや別のクライアントが後から変更する可能性があります。", + "pricing.override.refreshFailed": "価格は保存されましたが、モデル一覧を更新できませんでした。一覧の更新を再試行してください。", + "pricing.override.invalid": "入力・出力単価を入力してください。各単価は 0 以上 1,000,000 以下の有限の数値にしてください。", + "pricing.override.reset": "自動価格に戻す", + "pricing.override.save": "保存", + "pricing.override.saving": "保存中…", + "pricing.override.reload": "価格を再読み込み", + "pricing.override.refresh": "一覧を更新", + "pricing.override.cancel": "キャンセル", + "pricing.override.close": "閉じる", }; diff --git a/gui/src/i18n/ko.ts b/gui/src/i18n/ko.ts index 42c000c6bb..20160b7ffe 100644 --- a/gui/src/i18n/ko.ts +++ b/gui/src/i18n/ko.ts @@ -2613,4 +2613,28 @@ export const ko: Record = { "models.displayNameTooLong": "표시 이름은 128자 이하여야 합니다.", "models.displayNameNoSlash": "표시 이름에 /를 사용할 수 없습니다.", "models.displayNameNoControl": "표시 이름에 제어 문자를 사용할 수 없습니다.", + "pricing.override.action": "가격", + "pricing.override.actionLabel": "{model} 가격 편집", + "pricing.override.badge": "수동 가격", + "pricing.override.title": "모델 가격", + "pricing.override.modelId": "모델 ID", + "pricing.override.help": "토큰 100만 개당 USD입니다. 입력·출력 요율을 입력하세요. 빈 캐시 요율은 0으로 처리하며, 네 요율이 모두 0이면 무료입니다.", + "pricing.override.input": "입력", + "pricing.override.output": "출력", + "pricing.override.cacheRead": "캐시 읽기", + "pricing.override.cacheWrite": "캐시 쓰기", + "pricing.override.loading": "저장된 가격을 불러오는 중…", + "pricing.override.loadFailed": "저장된 가격을 불러오지 못했습니다. 다시 불러와 주세요.", + "pricing.override.outcomeUnknown": "요청 결과를 확인하지 못했습니다. 가격이 변경되었을 수 있으니 저장된 가격을 다시 불러온 뒤 편집하세요.", + "pricing.override.recoveryFailed": "저장된 가격을 확인하지 못해 편집이 잠겨 있습니다. 다시 불러와 주세요.", + "pricing.override.recovered": "현재 저장된 가격을 불러왔습니다. 이전 요청이나 다른 클라이언트가 이후에 가격을 변경할 수 있습니다.", + "pricing.override.refreshFailed": "가격은 저장했지만 모델 목록을 갱신하지 못했습니다. 목록 갱신을 다시 시도하세요.", + "pricing.override.invalid": "입력·출력 요율을 입력하세요. 모든 요율은 0 이상 1,000,000 이하의 유한한 숫자여야 합니다.", + "pricing.override.reset": "자동 가격으로 복원", + "pricing.override.save": "저장", + "pricing.override.saving": "저장 중…", + "pricing.override.reload": "가격 다시 불러오기", + "pricing.override.refresh": "목록 갱신", + "pricing.override.cancel": "취소", + "pricing.override.close": "닫기", }; diff --git a/gui/src/i18n/ru.ts b/gui/src/i18n/ru.ts index 51fcaef210..b433aa4381 100644 --- a/gui/src/i18n/ru.ts +++ b/gui/src/i18n/ru.ts @@ -2614,4 +2614,28 @@ export const ru: Record = { "models.displayNameTooLong": "Понятное имя должно содержать не более 128 символов.", "models.displayNameNoSlash": "Понятное имя не может содержать /.", "models.displayNameNoControl": "Понятное имя не может содержать управляющие символы.", + "pricing.override.action": "Цена", + "pricing.override.actionLabel": "Изменить цену для {model}", + "pricing.override.badge": "Своя цена", + "pricing.override.title": "Цена модели", + "pricing.override.modelId": "ID модели", + "pricing.override.help": "USD за 1 млн токенов. Укажите входной и выходной тарифы; пустые тарифы кеша равны 0. Четыре нулевых тарифа означают бесплатное использование.", + "pricing.override.input": "Вход", + "pricing.override.output": "Выход", + "pricing.override.cacheRead": "Чтение кеша", + "pricing.override.cacheWrite": "Запись кеша", + "pricing.override.loading": "Загрузка сохранённой цены…", + "pricing.override.loadFailed": "Не удалось загрузить сохранённую цену. Повторите загрузку.", + "pricing.override.outcomeUnknown": "Результат запроса неизвестен. Цена могла измениться. Загрузите сохранённую цену перед следующим изменением.", + "pricing.override.recoveryFailed": "Не удалось получить сохранённую цену. Редактирование заблокировано; повторите загрузку.", + "pricing.override.recovered": "Текущая сохранённая цена загружена. Предыдущий запрос или другой клиент ещё может изменить её.", + "pricing.override.refreshFailed": "Цена сохранена, но список моделей не обновлён. Повторите обновление списка.", + "pricing.override.invalid": "Укажите входной и выходной тарифы. Каждый тариф должен быть конечным числом от 0 до 1 000 000.", + "pricing.override.reset": "Вернуть автоматическую цену", + "pricing.override.save": "Сохранить", + "pricing.override.saving": "Сохранение…", + "pricing.override.reload": "Загрузить цену", + "pricing.override.refresh": "Обновить список", + "pricing.override.cancel": "Отмена", + "pricing.override.close": "Закрыть", }; diff --git a/gui/src/i18n/tr.ts b/gui/src/i18n/tr.ts index c764bf11ca..b86b867b22 100644 --- a/gui/src/i18n/tr.ts +++ b/gui/src/i18n/tr.ts @@ -2614,4 +2614,28 @@ export const tr: Record = { "models.displayNameTooLong": "Görünen ad en fazla 128 karakter olabilir.", "models.displayNameNoSlash": "Görünen ad / içeremez.", "models.displayNameNoControl": "Görünen ad denetim karakterleri içeremez.", + "pricing.override.action": "Fiyat", + "pricing.override.actionLabel": "{model} fiyatını düzenle", + "pricing.override.badge": "Elle belirlenen fiyat", + "pricing.override.title": "Model fiyatı", + "pricing.override.modelId": "Model kimliği", + "pricing.override.help": "1 milyon token başına USD. Giriş ve çıkış ücretlerini girin; boş önbellek ücretleri 0 sayılır. Dört ücret de 0 ise ücretsizdir.", + "pricing.override.input": "Giriş", + "pricing.override.output": "Çıkış", + "pricing.override.cacheRead": "Önbellek okuma", + "pricing.override.cacheWrite": "Önbellek yazma", + "pricing.override.loading": "Kayıtlı fiyat yükleniyor…", + "pricing.override.loadFailed": "Kayıtlı fiyat yüklenemedi. Yeniden yükleyin.", + "pricing.override.outcomeUnknown": "İsteğin sonucu doğrulanamadı. Fiyat değişmiş olabilir. Yeniden düzenlemeden önce kayıtlı fiyatı yükleyin.", + "pricing.override.recoveryFailed": "Kayıtlı fiyat alınamadı. Düzenleme kilitli kalır; yeniden yükleyin.", + "pricing.override.recovered": "Güncel kayıtlı fiyat yüklendi. Önceki istek veya başka bir istemci fiyatı hâlâ değiştirebilir.", + "pricing.override.refreshFailed": "Fiyat kaydedildi ancak model listesi yenilenemedi. Listeyi yeniden yenileyin.", + "pricing.override.invalid": "Giriş ve çıkış ücretlerini girin. Her ücret 0 ile 1.000.000 arasında sonlu bir sayı olmalıdır.", + "pricing.override.reset": "Otomatik fiyata dön", + "pricing.override.save": "Kaydet", + "pricing.override.saving": "Kaydediliyor…", + "pricing.override.reload": "Fiyatı yeniden yükle", + "pricing.override.refresh": "Listeyi yenile", + "pricing.override.cancel": "İptal", + "pricing.override.close": "Kapat", }; diff --git a/gui/src/i18n/zh-TW.ts b/gui/src/i18n/zh-TW.ts index ab6aedd67a..856c4c869c 100644 --- a/gui/src/i18n/zh-TW.ts +++ b/gui/src/i18n/zh-TW.ts @@ -2576,4 +2576,28 @@ export const zhTW: Record = { "models.displayNameTooLong": "友善名稱不能超過 128 個字元。", "models.displayNameNoSlash": "友善名稱不能包含 /。", "models.displayNameNoControl": "友善名稱不能包含控制字元。", + "pricing.override.action": "價格", + "pricing.override.actionLabel": "編輯 {model} 的價格", + "pricing.override.badge": "手動價格", + "pricing.override.title": "模型價格", + "pricing.override.modelId": "模型 ID", + "pricing.override.help": "單位為每百萬 token 的美元價格。請輸入輸入與輸出費率;空白快取費率以 0 計算。四項皆為 0 表示免費。", + "pricing.override.input": "輸入", + "pricing.override.output": "輸出", + "pricing.override.cacheRead": "快取讀取", + "pricing.override.cacheWrite": "快取寫入", + "pricing.override.loading": "正在載入已儲存的價格…", + "pricing.override.loadFailed": "無法載入已儲存的價格,請重新載入。", + "pricing.override.outcomeUnknown": "無法確認請求結果,價格可能已變更。再次編輯前請重新載入已儲存的價格。", + "pricing.override.recoveryFailed": "無法取得已儲存的價格,編輯仍被鎖定。請重新載入。", + "pricing.override.recovered": "已載入目前儲存的價格。先前的請求或其他用戶端仍可能變更該價格。", + "pricing.override.refreshFailed": "價格已儲存,但無法重新整理模型清單。請重試重新整理清單。", + "pricing.override.invalid": "請輸入輸入與輸出費率。每項費率必須是 0 到 1,000,000 之間的有限數字。", + "pricing.override.reset": "恢復自動價格", + "pricing.override.save": "儲存", + "pricing.override.saving": "正在儲存…", + "pricing.override.reload": "重新載入價格", + "pricing.override.refresh": "重新整理清單", + "pricing.override.cancel": "取消", + "pricing.override.close": "關閉", }; diff --git a/gui/src/i18n/zh.ts b/gui/src/i18n/zh.ts index 052f449855..4e1fda0c2a 100644 --- a/gui/src/i18n/zh.ts +++ b/gui/src/i18n/zh.ts @@ -2612,4 +2612,28 @@ export const zh: Record = { "models.displayNameTooLong": "友好名称不能超过 128 个字符。", "models.displayNameNoSlash": "友好名称不能包含 /。", "models.displayNameNoControl": "友好名称不能包含控制字符。", + "pricing.override.action": "价格", + "pricing.override.actionLabel": "编辑 {model} 的价格", + "pricing.override.badge": "手动价格", + "pricing.override.title": "模型价格", + "pricing.override.modelId": "模型 ID", + "pricing.override.help": "单位为每百万 token 的美元价格。请输入输入和输出费率;空白缓存费率按 0 计算。四项均为 0 表示免费。", + "pricing.override.input": "输入", + "pricing.override.output": "输出", + "pricing.override.cacheRead": "缓存读取", + "pricing.override.cacheWrite": "缓存写入", + "pricing.override.loading": "正在加载已保存的价格…", + "pricing.override.loadFailed": "无法加载已保存的价格,请重新加载。", + "pricing.override.outcomeUnknown": "无法确认请求结果,价格可能已更改。再次编辑前请重新加载已保存的价格。", + "pricing.override.recoveryFailed": "无法获取已保存的价格,编辑仍被锁定。请重新加载。", + "pricing.override.recovered": "已加载当前保存的价格。之前的请求或其他客户端仍可能更改该价格。", + "pricing.override.refreshFailed": "价格已保存,但无法刷新模型列表。请重试刷新列表。", + "pricing.override.invalid": "请输入输入和输出费率。每项费率必须是 0 到 1,000,000 之间的有限数字。", + "pricing.override.reset": "恢复自动价格", + "pricing.override.save": "保存", + "pricing.override.saving": "正在保存…", + "pricing.override.reload": "重新加载价格", + "pricing.override.refresh": "刷新列表", + "pricing.override.cancel": "取消", + "pricing.override.close": "关闭", }; diff --git a/gui/src/pages/Models.tsx b/gui/src/pages/Models.tsx index fc8db5626e..bc010c4abc 100644 --- a/gui/src/pages/Models.tsx +++ b/gui/src/pages/Models.tsx @@ -1,5 +1,6 @@ import { CodexStaleBanner } from "../components/codex-stale-banner"; import ModelDisplayNameDialog from "../components/ModelDisplayNameDialog"; +import ModelPriceDialog from "../components/ModelPriceDialog"; import { fetchCodexAppServerState } from "../codex-app-server-state"; import type { AppServerStateOutcome } from "../codex-app-server-state"; import { useCodexRestart } from "../use-codex-restart"; @@ -330,6 +331,8 @@ export default function Models({ apiBase, restartEpoch = 0 }: { apiBase: string; const [v2HelpOpen, setV2HelpOpen] = useState(false); const [customModalOpen, setCustomModalOpen] = useState(false); const [displayNameModel, setDisplayNameModel] = useState(null); + const [priceModel, setPriceModel] = useState(null); + const priceTriggerRef = useRef(null); const [displayNameSaving, setDisplayNameSaving] = useState(false); const [displayNameRequestError, setDisplayNameRequestError] = useState(null); const [displayNameRecovery, setDisplayNameRecovery] = useState<{ @@ -1696,6 +1699,23 @@ export default function Models({ apiBase, restartEpoch = 0 }: { apiBase: string; {t("models.customBadge")} )} + {!m.native && m.provider !== "combo" && ( + <> + {m.manualPricing === true && {t("pricing.override.badge")}} + + + )} {!m.custom && recentIds.has(m.id) && {t("models.newBadge")}} {m.contextCapped && {t("models.contextCappedValue", { value: fmtK(m.contextCap ?? contextCapValue) })}}
@@ -2651,6 +2671,21 @@ export default function Models({ apiBase, restartEpoch = 0 }: { apiBase: string; onClose={closeDisplayNameEdit} /> )} + {priceModel && ( + load(true, signal)} + onClose={() => { + const trigger = priceTriggerRef.current; + setPriceModel(null); + window.setTimeout(() => { + if (trigger?.isConnected) trigger.focus(); + }, 0); + }} + /> + )} ); diff --git a/gui/src/pages/models-shared.ts b/gui/src/pages/models-shared.ts index 1f5ef7786b..19d9bb67f7 100644 --- a/gui/src/pages/models-shared.ts +++ b/gui/src/pages/models-shared.ts @@ -37,6 +37,7 @@ export interface ModelRow { displayName?: string; displayNameOverride?: string; displayNameSource?: "operator" | "provider" | "fallback"; + manualPricing?: boolean; inputModalities?: string[]; contextWindow?: number; contextCap?: number; diff --git a/gui/tests/models-price-editor.test.tsx b/gui/tests/models-price-editor.test.tsx new file mode 100644 index 0000000000..b759a8398e --- /dev/null +++ b/gui/tests/models-price-editor.test.tsx @@ -0,0 +1,427 @@ +import { afterEach, beforeEach, describe, expect, test } from "bun:test"; +import { Window } from "happy-dom"; +import { act } from "react"; +import type { Root } from "react-dom/client"; +import { clearClientResourceStoresForTests } from "../src/client-resource"; +import { LanguageProvider } from "../src/i18n/provider"; +import Models from "../src/pages/Models"; +import type { ModelRow } from "../src/pages/models-shared"; + +type Rates = { input: number; output: number; cacheRead: number; cacheWrite: number }; +type Mutation = { modelId: string; cost: Rates | null }; +const FREE = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }; +const SAVED = { input: 1.25, output: 9.5, cacheRead: 0.125, cacheWrite: 2.75 }; + +function deferred() { + let resolve!: () => void; + const promise = new Promise(done => { resolve = done; }); + return { promise, resolve }; +} + +describe("Models manual price editor", () => { + const globals = [ + "document", "window", "navigator", "localStorage", "sessionStorage", + "IS_REACT_ACT_ENVIRONMENT", "fetch", "setInterval", "clearInterval", + ] as const; + let previousGlobals: Record<(typeof globals)[number], PropertyDescriptor | undefined>; + let testWindow: Window; + let container: HTMLElement; + let root: Root | null; + let rows: ModelRow[]; + let modelCosts: Record; + let mutations: Mutation[]; + let reads: Array<{ url: string; init?: RequestInit }>; + let catalogReads: number; + let getFailure: boolean; + let catalogFailure: boolean; + let getGate: ReturnType | null; + let putGate: ReturnType | null; + let catalogGate: ReturnType | null; + let getResponse: (() => Response) | null; + let putResponse: ((body: Mutation) => Response) | null; + + beforeEach(() => { + clearClientResourceStoresForTests(); + previousGlobals = Object.fromEntries(globals.map(key => [key, Object.getOwnPropertyDescriptor(globalThis, key)])) as typeof previousGlobals; + testWindow = new Window({ url: "http://localhost/#models" }); + Object.defineProperties(globalThis, { + document: { configurable: true, value: testWindow.document }, + window: { configurable: true, value: testWindow }, + navigator: { configurable: true, value: testWindow.navigator }, + localStorage: { configurable: true, value: testWindow.localStorage }, + sessionStorage: { configurable: true, value: testWindow.sessionStorage }, + IS_REACT_ACT_ENVIRONMENT: { configurable: true, value: true }, + setInterval: { configurable: true, value: () => 1 }, + clearInterval: { configurable: true, value: () => {} }, + }); + rows = [ + { provider: "xai-demo", id: "grok-4.6", namespaced: "xai-demo/grok-4.6", disabled: false, manualPricing: true }, + { provider: "xai-demo", id: "vendor/custom", namespaced: "xai-demo/vendor/custom", disabled: false, custom: true, customId: "custom-1" }, + { provider: "openai", id: "gpt-5.5", namespaced: "openai/gpt-5.5", disabled: false, native: true, manualPricing: true }, + { provider: "combo", id: "balanced", namespaced: "combo/balanced", disabled: false, manualPricing: true }, + ]; + const providers = [ + { name: "xai-demo", liveModels: false, models: ["grok-4.6", "vendor/custom"] }, + { name: "openai", liveModels: false, models: ["gpt-5.5"] }, + ]; + modelCosts = { "grok-4.6": { ...SAVED }, sibling: { ...FREE } }; + mutations = []; + reads = []; + catalogReads = 0; + getFailure = false; + catalogFailure = false; + getGate = null; + putGate = null; + catalogGate = null; + getResponse = null; + putResponse = null; + testWindow.localStorage.setItem("ocx-lang", "en"); + testWindow.localStorage.setItem("ocx-models-collapsed:v2", JSON.stringify([])); + testWindow.sessionStorage.setItem("ocx.models.catalog.v1:http://localhost", JSON.stringify({ + models: rows, providers, selectedModels: {}, disabled: [], contextCaps: {}, contextCapValue: 350_000, + })); + globalThis.fetch = (async (input, init) => { + const url = String(input); + if (url.endsWith("/api/providers/xai-demo/model-costs")) { + if (init?.method === "PUT") { + const body = JSON.parse(String(init.body)) as Mutation; + mutations.push(body); + if (putGate) await putGate.promise; + if (body.cost === null) delete modelCosts[body.modelId]; + else modelCosts[body.modelId] = body.cost; + rows = rows.map(row => row.provider === "xai-demo" && row.id === body.modelId + ? { ...row, manualPricing: body.cost !== null } : row); + return putResponse ? putResponse(body) : Response.json({ ok: true, provider: "xai-demo", ...body }); + } + reads.push({ url, init }); + if (getGate) await getGate.promise; + if (getFailure) return Response.json({ error: "unavailable" }, { status: 503 }); + return getResponse ? getResponse() : Response.json({ provider: "xai-demo", modelCosts }); + } + if (url.endsWith("/api/models")) { + catalogReads++; + if (catalogGate) await catalogGate.promise; + if (catalogFailure) return Response.json({ error: "unavailable" }, { status: 503 }); + return Response.json(rows); + } + if (url.endsWith("/api/providers")) return Response.json(providers); + if (url.endsWith("/api/selected-models")) return Response.json({ selected: {} }); + if (url.endsWith("/api/provider-context-caps")) return Response.json({ caps: {} }); + if (url.endsWith("/api/aliases")) return Response.json({ providers: {}, models: {}, defaults: { global: false, providers: {} } }); + if (url.endsWith("/api/combos")) return Response.json({ combos: [] }); + if (url.endsWith("/api/shadow-call-settings")) return Response.json({ enabled: false, model: "" }); + if (url.endsWith("/api/v2")) return Response.json({ enabled: false, agentsMaxThreadsConflict: false, multiAgentMode: "default" }); + return new Response(null, { status: 404 }); + }) as typeof fetch; + container = testWindow.document.createElement("div"); + testWindow.document.body.appendChild(container as never); + root = null; + }); + + afterEach(async () => { + clearClientResourceStoresForTests(); + if (root) await act(async () => root!.unmount()); + getGate?.resolve(); + putGate?.resolve(); + catalogGate?.resolve(); + testWindow.close(); + for (const key of globals) { + const descriptor = previousGlobals[key]; + if (descriptor) Object.defineProperty(globalThis, key, descriptor); + else Reflect.deleteProperty(globalThis, key); + } + }); + + async function flush() { + await act(async () => { await new Promise(resolve => testWindow.setTimeout(resolve, 0)); }); + } + + async function mount() { + const { createRoot } = await import("react-dom/client"); + await act(async () => { + root = createRoot(container); + root.render(); + }); + await flush(); + } + + function trigger(model = "xai-demo/grok-4.6"): HTMLButtonElement { + return container.querySelector(`[aria-label="Edit price for ${model}"]`)!; + } + + function inputs(): HTMLInputElement[] { + return [...container.querySelectorAll("dialog input")]; + } + + function button(label: string): HTMLButtonElement { + return [...container.querySelectorAll("dialog button")].find(node => node.textContent === label)!; + } + + async function click(label: string) { + await act(async () => button(label).click()); + await flush(); + } + + async function open(model?: string) { + await act(async () => trigger(model).click()); + await flush(); + } + + async function fill(values: string[]) { + for (const [index, value] of values.entries()) { + await act(async () => { + const input = inputs()[index]!; + Object.getOwnPropertyDescriptor(testWindow.HTMLInputElement.prototype, "value")!.set!.call(input, value); + input.dispatchEvent(new testWindow.Event("input", { bubbles: true })); + }); + } + } + + test("real routed and custom rows expose Price; badges use manualPricing and exclude native/combo aliases", async () => { + await mount(); + expect(container.querySelectorAll('[aria-label^="Edit price for "]')).toHaveLength(2); + expect(trigger("openai/gpt-5.5")).toBeNull(); + expect(trigger("combo/balanced")).toBeNull(); + expect(trigger().closest(".models-model-row")!.textContent).toContain("Manual price"); + expect(trigger("xai-demo/vendor/custom").closest(".models-model-row")!.textContent).not.toContain("Manual price"); + expect(reads).toHaveLength(0); + }); + + test("opening loads exact fresh rates, focuses input, and closing aborts a pending read", async () => { + await mount(); + await open(); + expect(inputs().map(input => input.value)).toEqual(["1.25", "9.5", "0.125", "2.75"]); + expect(testWindow.document.activeElement).toBe(inputs()[0]); + expect(reads[0]!.init?.cache).toBe("no-store"); + await click("Cancel"); + expect(testWindow.document.activeElement).toBe(trigger()); + + modelCosts["grok-4.6"] = { input: 3, output: 7, cacheRead: 2, cacheWrite: 4 }; + await open(); + expect(inputs().map(input => input.value)).toEqual(["3", "7", "2", "4"]); + await click("Cancel"); + getGate = deferred(); + await open(); + expect(inputs().every(input => input.disabled)).toBe(true); + expect(button("Save").disabled).toBe(true); + const signal = reads.at(-1)!.init!.signal!; + await act(async () => container.querySelector("dialog")!.dispatchEvent(new testWindow.Event("cancel", { cancelable: true }))); + expect(signal.aborted).toBe(true); + expect(container.querySelector("dialog")).toBeNull(); + await act(async () => getGate!.resolve()); + expect(container.querySelector("dialog")).toBeNull(); + }); + + test("missing override starts empty; explicit free saves exact slash-containing ID, refreshes, then closes", async () => { + await mount(); + await open("xai-demo/vendor/custom"); + expect(inputs().map(input => input.value)).toEqual(["", "", "", ""]); + expect(button("Reset to automatic").disabled).toBe(true); + await click("Save"); + expect(mutations).toHaveLength(0); + expect(container.querySelector('[role="alert"]')!.textContent).toContain("Enter input and output rates"); + await fill(["0", "0"]); + expect(inputs().map(input => input.value)).toEqual(["0", "0", "0", "0"]); + const before = catalogReads; + catalogGate = deferred(); + await click("Save"); + expect(mutations).toEqual([{ modelId: "vendor/custom", cost: FREE }]); + expect(catalogReads).toBeGreaterThan(before); + expect(container.querySelector("dialog")).not.toBeNull(); + expect(button("Cancel").disabled).toBe(true); + await act(async () => catalogGate!.resolve()); + await flush(); + expect(container.querySelector("dialog")).toBeNull(); + expect(trigger("xai-demo/vendor/custom").closest(".models-model-row")!.textContent).toContain("Manual price"); + await open("xai-demo/vendor/custom"); + expect(inputs().map(input => input.value)).toEqual(["0", "0", "0", "0"]); + expect(button("Reset to automatic").disabled).toBe(false); + }); + + test("reset sends null and refresh removes the badge without changing sibling rates", async () => { + await mount(); + await open(); + await click("Reset to automatic"); + expect(mutations).toEqual([{ modelId: "grok-4.6", cost: null }]); + expect(modelCosts.sibling).toEqual(FREE); + expect(trigger().closest(".models-model-row")!.textContent).not.toContain("Manual price"); + await open(); + expect(inputs().map(input => input.value)).toEqual(["", "", "", ""]); + }); + + test("finite bounds are enforced and the maximum with fractional cache rates is accepted", async () => { + await mount(); + await open(); + for (const invalid of ["-1", "1000001", ""]) { + await fill([invalid]); + await click("Save"); + expect(mutations).toHaveLength(0); + expect(container.querySelector('[role="alert"]')!.textContent).toContain("finite number"); + } + await fill(["1000000", "0", "0.000001", "0.5"]); + await click("Save"); + expect(mutations).toEqual([{ modelId: "grok-4.6", cost: { input: 1000000, output: 0, cacheRead: 0.000001, cacheWrite: 0.5 } }]); + }); + + test("failed initial reads keep editing locked until a successful reload", async () => { + getFailure = true; + await mount(); + await open(); + expect(inputs().every(input => input.disabled)).toBe(true); + expect(container.querySelector('[role="alert"]')!.textContent).toContain("Could not load"); + expect(testWindow.document.activeElement).toBe(button("Reload price")); + await click("Reload price"); + expect(mutations).toHaveLength(0); + expect(inputs()[0]!.disabled).toBe(true); + getFailure = false; + await click("Reload price"); + expect(inputs()[0]!.value).toBe("1.25"); + expect(inputs()[0]!.disabled).toBe(false); + }); + + for (const failure of ["transport", "malformed", "wrong identity", "wrong cost", "http"] as const) { + test(`${failure} mutation outcome requires read recovery before new edits`, async () => { + await mount(); + await open(); + putResponse = body => { + if (failure === "transport") throw new TypeError("connection dropped"); + if (failure === "malformed") return new Response("{", { status: 200 }); + if (failure === "http") return Response.json({ error: "failed" }, { status: 503 }); + return Response.json({ ok: true, provider: "xai-demo", ...body, + ...(failure === "wrong identity" ? { modelId: "other" } : { cost: SAVED }), + }); + }; + await fill(["0", "0", "0", "0"]); + await click("Save"); + expect(mutations).toHaveLength(1); + expect(inputs().every(input => input.disabled)).toBe(true); + expect(button("Reset to automatic").disabled).toBe(true); + expect(container.querySelector('[role="alert"]')!.textContent).toContain("may have changed"); + await act(async () => button("Reset to automatic").dispatchEvent(new testWindow.MouseEvent("click", { bubbles: true }))); + expect(mutations).toHaveLength(1); + getFailure = true; + await click("Reload price"); + expect(mutations).toHaveLength(1); + expect(inputs()[0]!.disabled).toBe(true); + expect(container.querySelector('[role="alert"]')!.textContent).toContain("Editing stays locked"); + getFailure = false; + await click("Reload price"); + expect(inputs().map(input => input.value)).toEqual(["0", "0", "0", "0"]); + expect(inputs()[0]!.disabled).toBe(false); + expect(container.textContent).toContain("may still change it"); + expect(mutations).toHaveLength(1); + putResponse = null; + await fill(["2", "3"]); + await click("Save"); + expect(mutations[1]).toEqual({ modelId: "grok-4.6", cost: { input: 2, output: 3, cacheRead: 0, cacheWrite: 0 } }); + expect(container.querySelector("dialog")).toBeNull(); + }); + } + + test("malformed GET cost or provider is never treated as an empty override", async () => { + await mount(); + for (const payload of [ + { provider: "other", modelCosts }, + { provider: "xai-demo", modelCosts: { "grok-4.6": { ...SAVED, input: -1 } } }, + { provider: "xai-demo", modelCosts: { "grok-4.6": { input: 1, output: 2 } } }, + { provider: "xai-demo", modelCosts: [] }, + ]) { + getResponse = () => Response.json(payload); + await open(); + expect(inputs().every(input => input.disabled)).toBe(true); + expect(button("Reset to automatic").disabled).toBe(true); + await click("Cancel"); + } + expect(mutations).toHaveLength(0); + }); + + test("a reset with a lost receipt recovers empty rates without replaying the reset", async () => { + await mount(); + await open(); + putResponse = () => { throw new TypeError("receipt lost"); }; + await click("Reset to automatic"); + expect(inputs()[0]!.disabled).toBe(true); + await click("Reload price"); + expect(inputs().map(input => input.value)).toEqual(["", "", "", ""]); + expect(inputs()[0]!.disabled).toBe(false); + expect(button("Reset to automatic").disabled).toBe(true); + expect(mutations).toEqual([{ modelId: "grok-4.6", cost: null }]); + }); + + test("the mutation deadline unlocks cancellation but requires a fresh read before editing", async () => { + await mount(); + await open(); + const descriptor = Object.getOwnPropertyDescriptor(AbortSignal, "timeout"); + const deadline = new AbortController(); + const timeoutBudgets: number[] = []; + const transport = globalThis.fetch; + let pendingSignal: AbortSignal | null | undefined; + try { + Object.defineProperty(AbortSignal, "timeout", { configurable: true, value: (ms: number) => { + timeoutBudgets.push(ms); + return deadline.signal; + } }); + globalThis.fetch = (async (input: RequestInfo | URL, init?: RequestInit) => { + if (init?.method === "PUT" && String(input).endsWith("/model-costs")) { + pendingSignal = init.signal; + return new Promise((_resolve, reject) => { + init.signal!.addEventListener("abort", () => reject(new Error("request deadline")), { once: true }); + }); + } + return transport(input, init); + }) as typeof fetch; + await click("Save"); + expect(button("Cancel").disabled).toBe(true); + expect(timeoutBudgets).toEqual([60_000]); + await act(async () => deadline.abort()); + await flush(); + expect(pendingSignal?.aborted).toBe(true); + expect(button("Cancel").disabled).toBe(false); + expect(inputs().every(input => input.disabled)).toBe(true); + expect(button("Reload price").disabled).toBe(false); + } finally { + globalThis.fetch = transport; + if (descriptor) Object.defineProperty(AbortSignal, "timeout", descriptor); + else Reflect.deleteProperty(AbortSignal, "timeout"); + } + await click("Reload price"); + expect(inputs()[0]!.disabled).toBe(false); + expect(reads).toHaveLength(2); + }); + + test("confirmed receipt survives repeated failed catalog refreshes and retries never PUT again", async () => { + await mount(); + await open(); + catalogFailure = true; + await click("Reset to automatic"); + expect(mutations).toHaveLength(1); + expect(inputs().every(input => input.disabled)).toBe(true); + expect(container.querySelector('[role="alert"]')!.textContent).toContain("price was saved"); + await click("Refresh list"); + expect(mutations).toHaveLength(1); + expect(container.querySelector('[role="alert"]')!.textContent).toContain("price was saved"); + expect(reads).toHaveLength(1); + catalogFailure = false; + await click("Refresh list"); + expect(mutations).toEqual([{ modelId: "grok-4.6", cost: null }]); + expect(container.querySelector("dialog")).toBeNull(); + }); + + test("pending mutations reject duplicate submit and dismissal", async () => { + await mount(); + await open(); + putGate = deferred(); + await click("Save"); + await act(async () => { + container.querySelector("dialog form")!.dispatchEvent(new testWindow.Event("submit", { bubbles: true, cancelable: true })); + container.querySelector("dialog")!.dispatchEvent(new testWindow.Event("cancel", { cancelable: true })); + button("Cancel").dispatchEvent(new testWindow.MouseEvent("click", { bubbles: true })); + }); + expect(mutations).toHaveLength(1); + expect(container.querySelector("dialog")).not.toBeNull(); + expect(inputs().every(input => input.disabled)).toBe(true); + await act(async () => putGate!.resolve()); + await flush(); + expect(container.querySelector("dialog")).toBeNull(); + }); +}); diff --git a/scripts/test-layout/layout.json b/scripts/test-layout/layout.json index 60e0f22a0d..ffb001a82d 100644 --- a/scripts/test-layout/layout.json +++ b/scripts/test-layout/layout.json @@ -1298,7 +1298,9 @@ "zhipu-bigmodel-provider.test.ts": "providers", "zz-ci-api-usage-isolation.test.ts": "ci-workflows", "zz-ci-storage-policy-isolation.test.ts": "ci-workflows", - "zz-pr-coderabbit-readiness-revalidation.test.ts": "ci-workflows" + "zz-pr-coderabbit-readiness-revalidation.test.ts": "ci-workflows", + "cli-models-price.test.ts": "cli", + "model-costs-management-api.test.ts": "server" }, "migrated": [ "adapters", diff --git a/skills/ocx/references/01_management_surface.md b/skills/ocx/references/01_management_surface.md index 10b0cd9e89..485ed745ba 100644 --- a/skills/ocx/references/01_management_surface.md +++ b/skills/ocx/references/01_management_surface.md @@ -28,6 +28,22 @@ These answer in the CLI head and never reach the proxy, so they work with nothin Safe to run at any time; none of these change state. +### `ocx models price` + +Read the saved manual price for an exact provider/model selector. + +| Method | Route | +|---|---| +| GET | `/api/providers/{provider}/model-costs` | + +| Flag | Value | Meaning | +|---|---|---| +| `--json` | boolean | Emit provider, modelId, and cost (null for automatic pricing). | + +JSON mode: `envelope`. + +- The provider must be configured; everything after the first slash is the exact upstream model ID. + ### `ocx status` Proxy status, injection state, and version skew between this CLI and the running proxy. @@ -353,6 +369,27 @@ JSON mode: `payload`. Each of these writes. Check the flags column before running one unattended. +### `ocx models set-price` + +Save four manual USD-per-1M-token rates, or restore automatic pricing for one model. + +| Method | Route | +|---|---| +| PUT | `/api/providers/{provider}/model-costs` | + +| Flag | Value | Meaning | +|---|---|---| +| `--input` | number | Input rate; required unless --auto is used. | +| `--output` | number | Output rate; required unless --auto is used. | +| `--cache-read` | number | Cache read rate; defaults to 0. | +| `--cache-write` | number | Cache write rate; defaults to 0. | +| `--auto` | boolean | Remove this model's override; cannot be combined with rates. | +| `--json` | boolean | Emit the saved price or reset result as JSON. | + +JSON mode: `payload`. + +- Uses the exact upstream model ID after the first slash. Omitted cache rates default to zero; sibling model prices are preserved. + ### `ocx connect rotate` Rotate the connected client's data key against the hub, with commit and abort. @@ -648,6 +685,6 @@ JSON mode: `payload`. ## Counts -- declared capabilities: 35 -- of those, state-changing: 15 +- declared capabilities: 37 +- of those, state-changing: 16 - head-resolved invocations: 2 diff --git a/src/cli/capabilities.ts b/src/cli/capabilities.ts index ff1f5fb9a2..e34b8ec79b 100644 --- a/src/cli/capabilities.ts +++ b/src/cli/capabilities.ts @@ -95,6 +95,31 @@ export const HEAD_CAPABILITIES: readonly HeadCapability[] = [ * A capability must not name a route the command does not actually fetch. */ export const CAPABILITIES: readonly Capability[] = [ + { + command: ["models", "price"], + summary: "Read the saved manual price for an exact provider/model selector.", + routes: [{ method: "GET", path: "/api/providers/{provider}/model-costs" }], + flags: [{ name: "--json", value: "boolean", summary: "Emit provider, modelId, and cost (null for automatic pricing)." }], + mutates: false, + json: "envelope", + details: ["The provider must be configured; everything after the first slash is the exact upstream model ID."], + }, + { + command: ["models", "set-price"], + summary: "Save four manual USD-per-1M-token rates, or restore automatic pricing for one model.", + routes: [{ method: "PUT", path: "/api/providers/{provider}/model-costs" }], + flags: [ + { name: "--input", value: "number", summary: "Input rate; required unless --auto is used." }, + { name: "--output", value: "number", summary: "Output rate; required unless --auto is used." }, + { name: "--cache-read", value: "number", summary: "Cache read rate; defaults to 0." }, + { name: "--cache-write", value: "number", summary: "Cache write rate; defaults to 0." }, + { name: "--auto", value: "boolean", summary: "Remove this model's override; cannot be combined with rates." }, + { name: "--json", value: "boolean", summary: "Emit the saved price or reset result as JSON." }, + ], + mutates: true, + json: "payload", + details: ["Uses the exact upstream model ID after the first slash. Omitted cache rates default to zero; sibling model prices are preserved."], + }, { command: ["status"], summary: "Proxy status, injection state, and version skew between this CLI and the running proxy.", diff --git a/src/cli/models-runtime-subcommands.ts b/src/cli/models-runtime-subcommands.ts index a49828d203..4aa6d7b77a 100644 --- a/src/cli/models-runtime-subcommands.ts +++ b/src/cli/models-runtime-subcommands.ts @@ -15,6 +15,8 @@ */ export const MODELS_RUNTIME_SUBCOMMANDS = [ "live", + "price", + "set-price", "edit", "enable", "disable", diff --git a/src/cli/models-runtime.ts b/src/cli/models-runtime.ts index e21fa25d9e..d71ce84e47 100644 --- a/src/cli/models-runtime.ts +++ b/src/cli/models-runtime.ts @@ -13,9 +13,18 @@ import { type RuntimeApiDeps, } from "./runtime-api"; import { isModelsRuntimeSubcommand } from "./models-runtime-subcommands"; +import { isValidProviderName } from "../config/provider-name"; +import { isValidModelDiscoveryModelId } from "../providers/model-discovery-limits"; +import { redactSecretString } from "../lib/redact"; +import type { ProviderCostOverlay } from "../types"; +import { MAX_COST4_RATE } from "../usage/expected-prices"; +import { isValidCost4Rate } from "../usage/user-cost-overlays"; const USAGE = `Usage: ocx models live [--provider ] [--json] + ocx models price [--json] + ocx models set-price --input N --output N [--cache-read N] [--cache-write N] [--json] + ocx models set-price --auto [--json] ocx models edit [--model-id ] [--display-name ] [--context-window ] [--modalities ] [--reasoning-efforts ] @@ -28,7 +37,10 @@ const USAGE = `Usage: ocx models new-policy [on|off] [--provider ] [--json] ocx models new-arrivals [--json] ocx models context [--set-all]|provider on [--value ]|provider off|all > [--json] - ocx models shadow [model|-] [--enabled ] [--json]`; + ocx models shadow [model|-] [--enabled ] [--json] + +Prices are USD per 1M tokens. Omitted cache rates default to 0. +Price selectors use the exact upstream model ID after the first slash.`; type ModelRow = { provider?: string; @@ -55,6 +67,58 @@ async function live(argv: string[], deps: RuntimeApiDeps): Promise { })); } +async function price(write: boolean, argv: string[], deps: RuntimeApiDeps): Promise { + const args = [...argv]; + const selector = args.shift() ?? ""; + const slash = selector.indexOf("/"); + const provider = selector.slice(0, slash); + const modelId = selector.slice(slash + 1); + if (slash < 1 || !isValidProviderName(provider) || !isValidModelDiscoveryModelId(modelId)) { + throw new CliUsageError("model selector must be provider/model with an exact upstream model id", USAGE); + } + if (redactSecretString(modelId) !== modelId) { + throw new CliUsageError("modelId cannot be displayed safely", USAGE); + } + const wantsJson = takeFlag(args, "--json"); + const path = `/api/providers/${encodeURIComponent(provider)}/model-costs`; + if (!write) { + rejectArgs(args, USAGE); + const result = await runtimeRequest<{ provider: string; modelCosts: Record }>(path, {}, deps); + const cost = Object.hasOwn(result.modelCosts, modelId) ? result.modelCosts[modelId]! : null; + printData({ provider: result.provider, modelId, cost }, wantsJson, [ + cost === null ? `${selector}: automatic pricing` : `${selector}: ${JSON.stringify(cost)} USD per 1M tokens`, + ]); + return; + } + const auto = takeFlag(args, "--auto"); + const input = takeOption(args, "--input"); + const output = takeOption(args, "--output"); + const cacheRead = takeOption(args, "--cache-read"); + const cacheWrite = takeOption(args, "--cache-write"); + rejectArgs(args, USAGE); + if (auto && [input, output, cacheRead, cacheWrite].some(value => value !== undefined)) { + throw new CliUsageError("--auto cannot be combined with price rates", USAGE); + } + if (!auto && (input === undefined || output === undefined)) { + throw new CliUsageError("--input and --output are required unless --auto is used", USAGE); + } + const rate = (raw: string, flag: string): number => { + const value = Number(raw); + if (!raw.trim() || !isValidCost4Rate(value)) { + throw new CliUsageError(`${flag} must be a finite number between 0 and ${MAX_COST4_RATE}`, USAGE); + } + return value; + }; + const cost: ProviderCostOverlay | null = auto ? null : { + input: rate(input!, "--input"), + output: rate(output!, "--output"), + cacheRead: rate(cacheRead ?? "0", "--cache-read"), + cacheWrite: rate(cacheWrite ?? "0", "--cache-write"), + }; + const result = await runtimeRequest(path, { method: "PUT", body: JSON.stringify({ modelId, cost }) }, deps); + printData(result, wantsJson, [auto ? `${selector}: automatic pricing restored.` : `${selector}: manual pricing saved.`]); +} + async function edit(argv: string[], deps: RuntimeApiDeps): Promise { const args = [...argv]; const id = args.shift()?.trim(); @@ -328,6 +392,8 @@ export async function handleModelsRuntimeCommand(sub: string, argv: string[], de if (!isModelsRuntimeSubcommand(sub)) return null; let action: (() => Promise) | undefined; if (sub === "live") action = () => live(argv, deps); + else if (sub === "price") action = () => price(false, argv, deps); + else if (sub === "set-price") action = () => price(true, argv, deps); else if (sub === "edit") action = () => edit(argv, deps); else if (sub === "enable") action = () => visibility(true, argv, deps); else if (sub === "disable") action = () => visibility(false, argv, deps); diff --git a/src/server/management/model-routes.ts b/src/server/management/model-routes.ts index dd84d8af8c..cc7a732a88 100644 --- a/src/server/management/model-routes.ts +++ b/src/server/management/model-routes.ts @@ -85,6 +85,8 @@ import { multiAgentGuidanceEnabled, providerBaseUrlConfigError, providerHeadersConfigError, + providerModelCostsConfigError, + sanitizeModelCostsForDisplay, saveConfigPreservingClaudeCode, } from "../../config"; import { @@ -98,6 +100,7 @@ import { } from "../../oauth"; import { removeCredential } from "../../oauth/store"; import { providerDestinationResolvedError } from "../../lib/destination-policy"; +import { redactSecretString } from "../../lib/redact"; import { enrichProviderFromCatalog, listKeyLoginProviders } from "../../oauth/key-providers"; import { deriveProviderPresets } from "../../providers/derive"; import { providerCodexAccountMode } from "../../providers/registry"; @@ -128,7 +131,7 @@ import { setDebugSettings, type DebugFlag, } from "../../lib/debug-settings"; -import type { OcxClaudeCodeConfig, OcxConfig, OcxCustomModel, OcxProviderConfig } from "../../types"; +import type { OcxClaudeCodeConfig, OcxConfig, OcxCustomModel, OcxProviderConfig, ProviderCostOverlay } from "../../types"; import { drainAndShutdown } from "../lifecycle"; import { filterRequestLogs, getRequestLogEntries, type RequestLogEntry } from "../request-log"; import { estimateComboCost, estimateRequestCost, normalizeCostTokens, tokensPerSecond } from "../../usage/cost"; @@ -369,6 +372,60 @@ export async function handleModelRoutes(ctx: ManagementContext): Promise key !== "modelId" && key !== "cost")) { + return jsonResponse({ error: "only a valid modelId and cost object or null are allowed" }, 400, req, config); + } + const modelId = body.modelId; + if (redactSecretString(modelId) !== modelId) { + return jsonResponse({ error: "modelId cannot be displayed safely" }, 400, req, config); + } + const submitted = { [modelId]: body.cost }; + const validationError = body.cost === null ? null : providerModelCostsConfigError(submitted); + if (validationError) return jsonResponse({ error: validationError }, 400, req, config); + // Copy only validated rate fields; never echo a secret-shaped model key that the + // shared display boundary suppresses. Model IDs remain exact, including slashes. + const cost = body.cost === null ? null : sanitizeModelCostsForDisplay(submitted)?.[modelId]; + if (cost === undefined) return jsonResponse({ error: "modelId cannot be displayed safely" }, 400, req, config); + + const hadModelCosts = Object.hasOwn(provider, "modelCosts"); + const previousModelCosts = provider.modelCosts; + const nextModelCosts = Object.assign( + Object.create(null) as Record, + previousModelCosts ?? {}, + ); + if (cost === null) delete nextModelCosts[modelId]; + else nextModelCosts[modelId] = cost; + const mergedError = providerModelCostsConfigError(nextModelCosts); + if (mergedError) return jsonResponse({ error: mergedError }, 400, req, config); + if (Object.keys(nextModelCosts).length > 0) provider.modelCosts = nextModelCosts; + else delete provider.modelCosts; + try { + // The persistence owner refreshes usage overlays after its atomic write. + // Price-only edits do not change routing or require catalog convergence. + persistConfig(config); + } catch (error) { + if (hadModelCosts) provider.modelCosts = previousModelCosts; + else delete provider.modelCosts; + throw error; + } + return jsonResponse({ ok: true, provider: name, modelId, cost }, 200, req, config); + } + const displayNameMatch = url.pathname.match(/^\/api\/providers\/([^/]+)\/model-display-names$/); if (displayNameMatch && req.method === "PUT") { let name: string; diff --git a/src/server/management/model-rows.ts b/src/server/management/model-rows.ts index 6d9ec08853..07405c4362 100644 --- a/src/server/management/model-rows.ts +++ b/src/server/management/model-rows.ts @@ -46,6 +46,7 @@ export type ManagementModelRow = Partial & { native?: boolean; custom?: boolean; customId?: string; + manualPricing?: boolean; fastRowAvailable?: boolean; displayNameOverride?: string; displayNameSource?: "operator" | "provider" | "fallback"; @@ -181,8 +182,12 @@ export async function listManagementModelRows( for (const row of rows) knownIds.add(row.namespaced); return rows.map(row => { const pending = initialModelSelectionPending(config.providers[row.provider]); + const modelCosts = Object.hasOwn(config.providers, row.provider) + ? config.providers[row.provider]?.modelCosts : undefined; return { ...row, + ...(!row.native && modelCosts !== undefined && Object.hasOwn(modelCosts, row.id) + ? { manualPricing: true } : {}), ...(pending ? { disabled: true, initialSelectionPending: true } : {}), fastRowAvailable: !row.disabled && !pending && !knownIds.has(fastRowId(row.namespaced)) && catalogFastRowEligible(config, row), diff --git a/src/server/management/route-registry.ts b/src/server/management/route-registry.ts index 421ead31e0..6c7d57547b 100644 --- a/src/server/management/route-registry.ts +++ b/src/server/management/route-registry.ts @@ -334,6 +334,8 @@ export const MANAGEMENT_ROUTES: readonly ManagementRoute[] = [ { method: "GET", path: "/api/request-history/{id}/route-decision", module: "server/management/request-history-routes", mutates: false, mechanism: "ends-with" }, { method: "PUT", path: "/api/providers/{provider}/alias", module: "server/management/model-routes", mutates: true, mechanism: "regex" }, { method: "PUT", path: "/api/providers/{provider}/model-aliases", module: "server/management/model-routes", mutates: true, mechanism: "regex" }, + { method: "GET", path: "/api/providers/{provider}/model-costs", module: "server/management/model-routes", mutates: false, mechanism: "regex" }, + { method: "PUT", path: "/api/providers/{provider}/model-costs", module: "server/management/model-routes", mutates: true, mechanism: "regex" }, { method: "PUT", path: "/api/custom-models/{id}", module: "server/management/model-routes", mutates: true, mechanism: "regex" }, { method: "DELETE", path: "/api/custom-models/{id}", module: "server/management/model-routes", mutates: true, mechanism: "regex" }, { method: "GET", path: "/api/lab/subjects/{id}", module: "server/management/lab-routes", mutates: false, mechanism: "regex", exempt: { reason: "local-transport", why: "ocx lab reads the same rows from the local SQLite projection; src/cli/lab.ts imports ../lab/query directly and never fetches /api/lab." } }, diff --git a/src/usage/cost.ts b/src/usage/cost.ts index 2a3b2ae6d3..deb7f6f20b 100644 --- a/src/usage/cost.ts +++ b/src/usage/cost.ts @@ -177,8 +177,8 @@ export function calculateCost(tokens: CostTokens, cost4: Cost4): CostBreakdown { * bundle) nonzero -> overlay verified -> overlay verified-derived -> jawcode * model-level vendor price (cross-provider fallback: a model follows its official * vendor price — WP5 policy, e.g. kiro/claude-opus-4-6 uses the anthropic price) - * -> null. All-zero rows are overlay candidates (zero is "not billable here", - * not "free"). + * -> null. An explicit all-zero user override means free; all-zero catalog + * rows remain overlay candidates rather than evidence of free pricing. */ export function resolveMatchedPrice( provider: string, @@ -244,7 +244,7 @@ function resolveMatchedPriceInner( /** * Exact provider/model price lookup: user-configured `modelCosts` first, then * an exact official correction, the jawcode provider bundle, the expected-price overlay, then the - * model-level vendor fallback. All-zero rows fall through ("not billable"). + * model-level vendor fallback. All-zero catalog rows fall through; user zeros win. */ function resolveMatchedPriceExact( provider: string, @@ -302,14 +302,14 @@ function resolveMatchedPriceExact( }; } -/** User-configured overlay match (all-zero rows fall through like any other source). */ +/** User-configured overlay match; explicit zero rates are authoritative too. */ function userOverlayMatch( provider: string, modelId: string, userOverlays: readonly ExpectedPriceOverlay[], ): MatchedPrice | null { const overlay = findExpectedPriceOverlay(provider, modelId, userOverlays); - if (!overlay || !validCost4(overlay.cost4) || !hasNonZeroCost(overlay.cost4)) return null; + if (!overlay || !validCost4(overlay.cost4)) return null; return { provider, modelId, diff --git a/tests/cli/cli-models-price.test.ts b/tests/cli/cli-models-price.test.ts new file mode 100644 index 0000000000..c36b049ce5 --- /dev/null +++ b/tests/cli/cli-models-price.test.ts @@ -0,0 +1,153 @@ +import { describe, expect, test } from "bun:test"; +import { handleModelsRuntimeCommand } from "../../src/cli/models-runtime"; +import { CAPABILITIES } from "../../src/cli/capabilities"; +import { MANAGEMENT_ROUTES } from "../../src/server/management/route-registry"; + +const COST = { input: 1.25, output: 5, cacheRead: 0.125, cacheWrite: 2 }; + +async function invoke(sub: string, args: string[], response: unknown = { ok: true }, status = 200) { + const calls: Array<{ path: string; method: string; body: unknown }> = []; + const stdout: string[] = []; + const stderr: string[] = []; + const log = console.log; + const error = console.error; + console.log = (...values: unknown[]) => { stdout.push(values.map(String).join(" ")); }; + console.error = (...values: unknown[]) => { stderr.push(values.map(String).join(" ")); }; + try { + const code = await handleModelsRuntimeCommand(sub, args, { + baseUrl: "http://127.0.0.1:1", + fetchImpl: async (url, init) => { + calls.push({ + path: new URL(String(url)).pathname, + method: init?.method ?? "GET", + body: init?.body ? JSON.parse(String(init.body)) : undefined, + }); + return Response.json(response, { status }); + }, + }); + return { code, calls, stdout: stdout.join("\n"), stderr: stderr.join("\n") }; + } finally { + console.log = log; + console.error = error; + } +} + +describe("models manual price commands", () => { + test("price reads the map and selects the exact ID after the first slash", async () => { + const result = await invoke("price", ["custom-price/org/model--fast", "--json"], { + provider: "custom-price", + modelCosts: { "org/model--fast": COST, "org--model--fast": { input: 9, output: 9, cacheRead: 9, cacheWrite: 9 } }, + }); + expect(result.code).toBe(0); + expect(result.calls).toEqual([{ path: "/api/providers/custom-price/model-costs", method: "GET", body: undefined }]); + expect(JSON.parse(result.stdout)).toEqual({ provider: "custom-price", modelId: "org/model--fast", cost: COST }); + }); + + test("missing own keys read as automatic, including prototype-shaped selectors", async () => { + for (const modelId of ["missing", "__proto__", "constructor", "toString"]) { + const result = await invoke("price", [`custom-price/${modelId}`, "--json"], { provider: "custom-price", modelCosts: {} }); + expect(result.code).toBe(0); + expect(JSON.parse(result.stdout)).toEqual({ provider: "custom-price", modelId, cost: null }); + } + const automatic = await invoke("price", ["custom-price/missing"], { provider: "custom-price", modelCosts: {} }); + expect(automatic.stdout).toContain("automatic pricing"); + }); + + test("set-price sends four numeric rates with omitted cache rates defaulted to zero", async () => { + const result = await invoke("set-price", ["custom-price/org/model", "--input", "1.25", "--output", "5", "--json"]); + expect(result.code).toBe(0); + expect(result.calls).toEqual([{ + path: "/api/providers/custom-price/model-costs", method: "PUT", + body: { modelId: "org/model", cost: { input: 1.25, output: 5, cacheRead: 0, cacheWrite: 0 } }, + }]); + }); + + test("explicit cache rates, all-zero pricing, and the maximum rate are transmitted unchanged", async () => { + const explicit = await invoke("set-price", ["custom-price/org/model", "--input", "1.25", "--output", "5", "--cache-read", "0.125", "--cache-write", "2"]); + expect(explicit.code).toBe(0); + expect(explicit.calls[0]!.body).toEqual({ modelId: "org/model", cost: COST }); + const zero = await invoke("set-price", ["custom-price/model", "--input", "0", "--output", "0"]); + expect(zero.code).toBe(0); + expect(zero.calls[0]!.body).toEqual({ modelId: "model", cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 } }); + const max = await invoke("set-price", ["custom-price/model", "--input", "1000000", "--output", "1e6"]); + expect(max.code).toBe(0); + expect(max.calls[0]!.body).toEqual({ modelId: "model", cost: { input: 1_000_000, output: 1_000_000, cacheRead: 0, cacheWrite: 0 } }); + }); + + test("--auto sends null and preserves the exact upstream ID", async () => { + const payload = { ok: true, provider: "custom-price", modelId: "org/model", cost: null }; + const result = await invoke("set-price", ["custom-price/org/model", "--auto", "--json"], payload); + expect(result.code).toBe(0); + expect(result.calls).toEqual([{ + path: "/api/providers/custom-price/model-costs", method: "PUT", body: { modelId: "org/model", cost: null }, + }]); + expect(JSON.parse(result.stdout)).toEqual(payload); + }); + + test("invalid selectors and read options fail before any request", async () => { + for (const selector of ["", "native-model", "/model", "provider/", " provider/model", "provider/ model", "provider/model ", "provider/bad\nmodel", "provider/" + "x".repeat(1025), "__proto__/model"]) { + for (const sub of ["price", "set-price"]) { + const result = await invoke(sub, [selector, ...(sub === "set-price" ? ["--auto"] : [])]); + expect(result.code).toBe(2); + expect(result.calls).toHaveLength(0); + } + } + for (const args of [["--auto"], ["--input", "1"], ["extra"], ["--json", "--json"]]) { + const result = await invoke("price", ["custom-price/model", ...args]); + expect(result.code).toBe(2); + expect(result.calls).toHaveLength(0); + } + }); + + test("missing, conflicting, repeated, unknown and invalid rate arguments make no requests", async () => { + const cases = [ + [], ["--input", "1"], ["--output", "2"], ["--input"], ["--input", "--output", "2"], + ["--auto", "--input", "0"], ["--auto", "--cache-read", "0"], ["--auto", "--cache-write", "0"], + ["--auto", "--auto"], ["--auto", "--unknown"], ["--auto", "extra"], + ["--input", "1", "--input", "2", "--output", "3"], + ...["", " ", "NaN", "Infinity", "1e309", "-1", "1000001", "1x", "1,2"].map(rate => ["--input", rate, "--output", "1"]), + ...["--output", "--cache-read", "--cache-write"].map(flag => flag === "--output" + ? ["--input", "1", flag, "-1"] : ["--input", "1", "--output", "2", flag, "-1"]), + ]; + for (const args of cases) { + const result = await invoke("set-price", ["custom-price/model", ...args]); + expect(result.code).toBe(2); + expect(result.calls).toHaveLength(0); + expect(result.stderr.length).toBeGreaterThan(0); + } + }); + + test("API rejection is reported with a nonzero exit and no success message", async () => { + const result = await invoke("set-price", ["custom-price/model", "--auto"], { error: "provider not found" }, 404); + expect(result.code).toBe(1); + expect(result.stderr).toContain("provider not found"); + expect(result.stdout).toBe(""); + }); + + test("secret-shaped model selectors fail before request or output for read, set and reset", async () => { + const modelId = "sk-" + "a".repeat(40); + for (const [sub, flags] of [ + ["price", []], + ["set-price", ["--input", "1", "--output", "2"]], + ["set-price", ["--auto"]], + ] as const) { + const result = await invoke(sub, [`custom-price/${modelId}`, ...flags, "--json"]); + expect(result.code).toBe(2); + expect(result.calls).toHaveLength(0); + expect(result.stdout).toBe(""); + expect(result.stderr).not.toContain(modelId); + expect(result.stderr).toContain("modelId cannot be displayed safely"); + } + }); + + test("capabilities map both CLI verbs onto the registered route methods", () => { + for (const [sub, method, mutates] of [["price", "GET", false], ["set-price", "PUT", true]] as const) { + const capability = CAPABILITIES.find(entry => entry.command.join(" ") === `models ${sub}`); + expect(capability?.routes).toEqual([{ method, path: "/api/providers/{provider}/model-costs" }]); + expect(capability?.mutates).toBe(mutates); + expect(MANAGEMENT_ROUTES.find(route => route.method === method && route.path === "/api/providers/{provider}/model-costs")).toMatchObject({ + module: "server/management/model-routes", mutates, mechanism: "regex", + }); + } + }); +}); diff --git a/tests/cli/cli-models-runtime-dispatch.test.ts b/tests/cli/cli-models-runtime-dispatch.test.ts index 3608fe9457..8145ec701e 100644 --- a/tests/cli/cli-models-runtime-dispatch.test.ts +++ b/tests/cli/cli-models-runtime-dispatch.test.ts @@ -37,6 +37,22 @@ describe("models runtime subcommand dispatch (#3094)", () => { expect(isModelsRuntimeSubcommand("new-arrivals")).toBe(true); }); + test("price and set-price are routed through the runtime dispatcher", async () => { + expect(isModelsRuntimeSubcommand("price")).toBe(true); + expect(isModelsRuntimeSubcommand("set-price")).toBe(true); + const methods: string[] = []; + const deps = { + baseUrl: "http://127.0.0.1:1", + fetchImpl: async (_url: string | URL | Request, init?: RequestInit) => { + methods.push(init?.method ?? "GET"); + return Response.json({ provider: "dispatch-test", modelCosts: {}, ok: true }); + }, + }; + expect(await handleModelsRuntimeCommand("price", ["dispatch-test/model"], deps)).toBe(0); + expect(await handleModelsRuntimeCommand("set-price", ["dispatch-test/model", "--auto"], deps)).toBe(0); + expect(methods).toEqual(["GET", "PUT"]); + }); + test("handleModels routes exactly the shared set to the runtime module", () => { // Reading the source keeps this honest without booting the CLI: the dispatch must // consult the shared predicate rather than re-listing names inline. @@ -54,4 +70,3 @@ describe("models runtime subcommand dispatch (#3094)", () => { expect(new Set(MODELS_RUNTIME_SUBCOMMANDS).size).toBe(MODELS_RUNTIME_SUBCOMMANDS.length); }); }); - diff --git a/tests/fixtures/test-layout-expected.json b/tests/fixtures/test-layout-expected.json index fe613ac71f..496d51ea31 100644 --- a/tests/fixtures/test-layout-expected.json +++ b/tests/fixtures/test-layout-expected.json @@ -1133,5 +1133,7 @@ "zhipu-bigmodel-provider.test.ts": "providers", "zz-ci-api-usage-isolation.test.ts": "ci-workflows", "zz-ci-storage-policy-isolation.test.ts": "ci-workflows", - "zz-pr-coderabbit-readiness-revalidation.test.ts": "ci-workflows" + "zz-pr-coderabbit-readiness-revalidation.test.ts": "ci-workflows", + "cli-models-price.test.ts": "cli", + "model-costs-management-api.test.ts": "server" } diff --git a/tests/server/model-costs-management-api.test.ts b/tests/server/model-costs-management-api.test.ts new file mode 100644 index 0000000000..856bf9ee79 --- /dev/null +++ b/tests/server/model-costs-management-api.test.ts @@ -0,0 +1,270 @@ +import { afterEach, beforeEach, describe, expect, test } from "bun:test"; +import { mkdtempSync, readFileSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { clearModelCache } from "../../src/codex/model-cache"; +import { resetCodexModelEntitlementCacheForTests } from "../../src/codex/model-entitlements"; +import { saveConfigPreservingClaudeCode } from "../../src/config"; +import { handleManagementAPI } from "../../src/server/management-api"; +import { handleModelRoutes } from "../../src/server/management/model-routes"; +import { listManagementModelRows } from "../../src/server/management/model-rows"; +import type { OcxConfig, ProviderCostOverlay } from "../../src/types"; +import { activeUserCostOverlays, refreshUserCostOverlays } from "../../src/usage/user-cost-overlays"; +import { removeTreeWithRetry } from "../helpers/remove-tree"; + +const PROVIDER = "manual-price-test"; +const COST: ProviderCostOverlay = { input: 1.25, output: 5, cacheRead: 0.125, cacheWrite: 2 }; +const SIBLING: ProviderCostOverlay = { input: 3, output: 7, cacheRead: 0.5, cacheWrite: 4 }; +const ZERO: ProviderCostOverlay = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }; +let home: string; +let previousHome: string | undefined; +let previousCodexHome: string | undefined; + +function fixture(costs?: Record): OcxConfig { + return { + port: 10100, + defaultProvider: PROVIDER, + modelCacheTtlMs: 60_000, + providers: { + [PROVIDER]: { + adapter: "openai-chat", + baseUrl: "https://price.example.invalid/v1", + alias: "price-alias", + liveModels: false, + models: ["org/model", "org/other", "sibling", "custom"], + ...(costs ? { modelCosts: costs } : {}), + }, + }, + }; +} + +beforeEach(() => { + previousHome = process.env.OPENCODEX_HOME; + previousCodexHome = process.env.CODEX_HOME; + home = mkdtempSync(join(tmpdir(), "ocx-model-prices-")); + process.env.OPENCODEX_HOME = home; + process.env.CODEX_HOME = join(home, "codex"); +}); + +afterEach(() => { + clearModelCache(); + resetCodexModelEntitlementCacheForTests(); + refreshUserCostOverlays(fixture()); + if (previousHome === undefined) delete process.env.OPENCODEX_HOME; + else process.env.OPENCODEX_HOME = previousHome; + if (previousCodexHome === undefined) delete process.env.CODEX_HOME; + else process.env.CODEX_HOME = previousCodexHome; + removeTreeWithRetry(home); +}); + +function harness(config = fixture(), persist?: (saved: OcxConfig) => void) { + const persisted: OcxConfig[] = []; + let convergeCalls = 0; + async function call(method: "GET" | "PUT", body?: unknown, provider = PROVIDER, rawBody?: string, rawProvider?: string) { + const url = new URL(`http://127.0.0.1:10100/api/providers/${rawProvider ?? encodeURIComponent(provider)}/model-costs`); + const response = await handleModelRoutes({ + version: "test", + req: new Request(url, { + method, + headers: { "Content-Type": "application/json" }, + ...(method === "PUT" ? { body: rawBody ?? JSON.stringify(body) } : {}), + }), + url, + config, + deps: { + saveConfigPreservingClaudeCode: saved => { + persist?.(saved); + persisted.push(structuredClone(saved)); + }, + }, + convergeCodexCatalog: async () => { + convergeCalls += 1; + throw new Error("price writes must not converge catalogs"); + }, + syncClaudeAgentDefsBestEffort: async () => {}, + }); + if (!response) throw new Error("model-costs route was not dispatched"); + return response; + } + return { call, config, persisted, get convergeCalls() { return convergeCalls; } }; +} + +describe("provider model costs API", () => { + test("GET returns the exact configured provider's sanitized map or an empty map", async () => { + const h = harness(); + expect(await (await h.call("GET")).json()).toEqual({ provider: PROVIDER, modelCosts: {} }); + const costs = JSON.parse(JSON.stringify({ + "org/model": { ...COST, apiKey: "not-for-display" }, + bad: { ...COST, input: -1 }, + ["sk-" + "a".repeat(40)]: COST, + })); + h.config.providers[PROVIDER]!.modelCosts = costs; + expect(await (await h.call("GET")).json()).toEqual({ provider: PROVIDER, modelCosts: { "org/model": COST } }); + expect(h.persisted).toHaveLength(0); + }); + + test("set, replace with explicit zero, and reset persist only the exact model key", async () => { + const h = harness(fixture({ sibling: SIBLING, "org--model": SIBLING })); + for (const cost of [COST, ZERO, null]) { + const response = await h.call("PUT", { modelId: "org/model", cost }); + expect(response.status).toBe(200); + expect(await response.json()).toEqual({ ok: true, provider: PROVIDER, modelId: "org/model", cost }); + const expected = { sibling: SIBLING, "org--model": SIBLING, ...(cost ? { "org/model": cost } : {}) }; + expect(h.config.providers[PROVIDER]!.modelCosts).toEqual(expected); + expect(h.persisted.at(-1)!.providers[PROVIDER]!.modelCosts).toEqual(expected); + } + expect(h.persisted).toHaveLength(3); + expect(h.convergeCalls).toBe(0); + }); + + test("reset of the last entry removes the map and repeated reset remains successful", async () => { + const h = harness(fixture({ "org/model": COST })); + for (let attempt = 0; attempt < 2; attempt++) { + expect((await h.call("PUT", { modelId: "org/model", cost: null })).status).toBe(200); + expect(Object.hasOwn(h.config.providers[PROVIDER]!, "modelCosts")).toBe(false); + expect(await (await h.call("GET")).json()).toEqual({ provider: PROVIDER, modelCosts: {} }); + } + }); + + test("the normal persistence owner writes disk and refreshes the overlay registry", async () => { + const config = fixture({ sibling: SIBLING }); + writeFileSync(join(home, "config.json"), JSON.stringify(config)); + const h = harness(config, saveConfigPreservingClaudeCode); + await h.call("PUT", { modelId: "org/model", cost: COST }); + const disk = JSON.parse(readFileSync(join(home, "config.json"), "utf8")) as OcxConfig; + expect(disk.providers[PROVIDER]!.modelCosts).toEqual({ sibling: SIBLING, "org/model": COST }); + expect(activeUserCostOverlays().find(row => row.provider === PROVIDER && row.modelId === "org/model")?.cost4).toEqual(COST); + expect(await (await harness(disk).call("GET")).json()).toEqual({ provider: PROVIDER, modelCosts: { sibling: SIBLING, "org/model": COST } }); + await h.call("PUT", { modelId: "org/model", cost: null }); + expect(JSON.parse(readFileSync(join(home, "config.json"), "utf8")).providers[PROVIDER].modelCosts).toEqual({ sibling: SIBLING }); + expect(activeUserCostOverlays().some(row => row.provider === PROVIDER && row.modelId === "org/model")).toBe(false); + }); + + test("persist failure restores map identity and own-property absence for set and reset", async () => { + for (const costs of [undefined, {}, { "org/model": COST, sibling: SIBLING }]) { + for (const cost of [SIBLING, null]) { + const config = fixture(costs); + const provider = config.providers[PROVIDER]!; + const previous = provider.modelCosts; + const snapshot = structuredClone(previous); + const hadMap = Object.hasOwn(provider, "modelCosts"); + const h = harness(config, () => { throw new Error("disk full"); }); + await expect(h.call("PUT", { modelId: "org/model", cost })).rejects.toThrow("disk full"); + expect(provider.modelCosts).toBe(previous); + expect(provider.modelCosts).toEqual(snapshot); + expect(Object.hasOwn(provider, "modelCosts")).toBe(hadMap); + expect(h.persisted).toHaveLength(0); + expect(h.convergeCalls).toBe(0); + } + } + }); + + test("missing, alias, case-folded and inherited provider names are not resolved", async () => { + const h = harness(); + for (const method of ["GET", "PUT"] as const) { + for (const provider of ["missing", "price-alias", PROVIDER.toUpperCase(), "__proto__", "constructor", "toString"]) { + expect((await h.call(method, { modelId: "org/model", cost: COST }, provider)).status).toBe(404); + } + expect((await h.call(method, { modelId: "org/model", cost: COST }, PROVIDER, undefined, "%E0%A4%A")).status).toBe(400); + } + expect(h.persisted).toHaveLength(0); + }); + + test("malformed bodies, model IDs, rates and extra fields fail before mutation", async () => { + const h = harness(fixture({ sibling: SIBLING })); + const original = h.config.providers[PROVIDER]!.modelCosts; + const invalid: unknown[] = [null, [], 4, {}, { modelId: "org/model" }, { cost: COST }, + ...["", " ", " model", "model ", "bad\nmodel", "x".repeat(1025), 42].map(modelId => ({ modelId, cost: null })), + ...[null, [], "1", true, -1, 1_000_001].map(input => ({ modelId: "org/model", cost: { ...COST, input } })), + ...[[], "auto", 0, { input: 1, output: 2 }, { ...COST, apiKey: "extra" }].map(cost => ({ modelId: "org/model", cost })), + { modelId: "org/model", cost: COST, extra: true }, + JSON.parse('{"modelId":"org/model","cost":null,"__proto__":{"polluted":true}}'), + JSON.parse('{"modelId":"org/model","cost":{"input":1,"output":2,"cacheRead":0,"cacheWrite":0,"constructor":{}}}'), + JSON.parse('{"modelId":"org/model","cost":{"input":1,"output":2,"cacheRead":0,"cacheWrite":0,"__proto__":{}}}'), + ]; + for (const body of invalid) expect((await h.call("PUT", body)).status).toBe(400); + for (const raw of ["{", "", '{"modelId":"org/model","cost":{"input":1e309,"output":1,"cacheRead":0,"cacheWrite":0}}']) { + expect((await h.call("PUT", undefined, PROVIDER, raw)).status).toBe(400); + } + expect(h.config.providers[PROVIDER]!.modelCosts).toBe(original); + expect(h.persisted).toHaveLength(0); + }); + + test("prototype-shaped model keys are stored and reset as own data without touching prototypes", async () => { + const h = harness(fixture({ sibling: SIBLING })); + for (const modelId of ["__proto__", "constructor", "toString"]) { + expect((await h.call("PUT", { modelId, cost: COST })).status).toBe(200); + const map = h.config.providers[PROVIDER]!.modelCosts!; + expect(Object.getPrototypeOf(map)).toBeNull(); + expect(Object.hasOwn(map, modelId)).toBe(true); + expect(map[modelId]).toEqual(COST); + const body = await (await h.call("GET")).json() as { modelCosts: Record }; + expect(Object.hasOwn(body.modelCosts, modelId)).toBe(true); + expect(body.modelCosts[modelId]).toEqual(COST); + await h.call("PUT", { modelId, cost: null }); + expect(Object.hasOwn(h.config.providers[PROVIDER]!.modelCosts!, modelId)).toBe(false); + } + expect(h.config.providers[PROVIDER]!.modelCosts).toEqual({ sibling: SIBLING }); + expect(Object.hasOwn(Object.prototype, "input")).toBe(false); + }); + + test("secret-shaped model IDs are rejected without echo on both set and reset", async () => { + const modelId = "sk-" + "a".repeat(40); + const h = harness(fixture({ [modelId]: COST, sibling: SIBLING })); + const original = h.config.providers[PROVIDER]!.modelCosts; + for (const cost of [COST, null]) { + const response = await h.call("PUT", { modelId, cost }); + expect(response.status).toBe(400); + expect(await response.text()).not.toContain(modelId); + } + expect(h.config.providers[PROVIDER]!.modelCosts).toBe(original); + expect(h.persisted).toHaveLength(0); + }); + + test("management dispatch reaches GET/PUT and still rejects cross-origin writes", async () => { + const config = fixture(); + const url = new URL(`http://127.0.0.1:10100/api/providers/${PROVIDER}/model-costs`); + let writes = 0; + for (const method of ["PUT", "GET"] as const) { + const response = await handleManagementAPI(new Request(url, { + method, headers: { Host: url.host, "Content-Type": "application/json" }, + ...(method === "PUT" ? { body: JSON.stringify({ modelId: "org/model", cost: COST }) } : {}), + }), url, config, { saveConfigPreservingClaudeCode: () => { writes++; } }); + expect(response?.status).toBe(200); + } + const blocked = await handleManagementAPI(new Request(url, { + method: "PUT", headers: { Host: url.host, Origin: "https://other.example.invalid" }, + body: JSON.stringify({ modelId: "org/model", cost: null }), + }), url, config, { saveConfigPreservingClaudeCode: () => { writes++; } }); + expect(blocked?.status).toBe(403); + expect(writes).toBe(1); + expect(config.providers[PROVIDER]!.modelCosts).toEqual({ "org/model": COST }); + }); + + test("set survives reload as manualPricing true and reset omits the badge field", async () => { + const config = fixture({ "org--other": SIBLING }); + config.customModels = [{ id: "custom-row", provider: PROVIDER, modelId: "custom" }]; + const h = harness(config); + expect((await h.call("PUT", { modelId: "org/model", cost: ZERO })).status).toBe(200); + expect((await h.call("PUT", { modelId: "custom", cost: COST })).status).toBe(200); + const reloaded = JSON.parse(JSON.stringify(config)) as OcxConfig; + const rows = await listManagementModelRows(reloaded, { entitlementWaitMs: 0 }); + expect(rows.find(row => row.provider === PROVIDER && row.id === "org/model")?.manualPricing).toBe(true); + for (const modelId of ["org/other", "sibling"]) { + const row = rows.find(row => row.provider === PROVIDER && row.id === modelId); + expect(row).toBeDefined(); + expect(Object.hasOwn(row!, "manualPricing")).toBe(false); + } + expect(rows.find(row => row.customId === "custom-row")?.manualPricing).toBe(true); + expect(rows.filter(row => row.native).every(row => !Object.hasOwn(row, "manualPricing"))).toBe(true); + for (const modelId of ["org/model", "custom"]) { + expect((await harness(reloaded).call("PUT", { modelId, cost: null })).status).toBe(200); + } + const resetRows = await listManagementModelRows(reloaded, { entitlementWaitMs: 0 }); + for (const modelId of ["org/model", "custom"]) { + const row = resetRows.find(row => row.provider === PROVIDER && row.id === modelId); + expect(row).toBeDefined(); + expect(Object.hasOwn(row!, "manualPricing")).toBe(false); + } + }); +}); diff --git a/tests/usage/usage-cost.test.ts b/tests/usage/usage-cost.test.ts index f234622e07..aa5711534e 100644 --- a/tests/usage/usage-cost.test.ts +++ b/tests/usage/usage-cost.test.ts @@ -1140,7 +1140,7 @@ describe("provider cost overlay (user-configured)", () => { }); }); - test("an all-zero overlay on a suffix-shaped configured provider falls through to compiled pricing, not the base provider's overlay", () => { + test("an explicit zero overlay on a suffix-shaped configured provider wins over every fallback", () => { refreshUserCostOverlays({ providers: { acme: { modelCosts: { "claude-opus-4-6": USER_PRICE } }, @@ -1150,16 +1150,12 @@ describe("provider cost overlay (user-configured)", () => { }, } as unknown as OcxConfig); const price = resolveMatchedPrice("acme-pabcdef", "claude-opus-4-6"); - // The all-zero row falls through to compiled/catalog pricing — the - // documented fallback order — and never to acme's user-configured price. + // Operator zero is an explicit free estimate, not missing catalog metadata. expect(price).not.toBeNull(); expect(price?.provider).toBe("acme-pabcdef"); - expect(price?.source).toBe("jawcode"); + expect(price?.source).toBe("user"); expect(price?.cost4).not.toEqual(USER_PRICE); - // A real positive catalog price, without pinning the vendor's current - // rate (the catalog lives outside this PR and may change independently). - expect(price?.cost4?.input).toBeGreaterThan(0); - expect(price?.cost4?.output).toBeGreaterThan(0); + expect(price?.cost4).toEqual({ input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }); }); test("a generated account label (not a configured provider) still collapses to the base provider's overlay", () => { @@ -1200,7 +1196,7 @@ describe("provider cost overlay (user-configured)", () => { expect(resolveMatchedPrice("acme-pabcdef", "acme-custom-model")).toBeNull(); }); - test("all-zero user overlay falls through to the expected overlay price", () => { + test("all-zero user overlay gives known-zero request and combo estimates until reset", () => { const zero: ExpectedPriceOverlay[] = [{ provider: "deepseek", modelId: "deepseek-chat", @@ -1210,10 +1206,13 @@ describe("provider cost overlay (user-configured)", () => { status: "verified", }]; const price = resolveMatchedPrice("deepseek", "deepseek-chat", undefined, zero); - expect(price?.source).toBe("expected"); - // A real positive expected-overlay price, without pinning the current - // rate (the overlay table may change independently of this feature). - expect(price?.cost4.input).toBeGreaterThan(0); + expect(price?.source).toBe("user"); + expect(price?.cost4).toEqual(zero[0]!.cost4); + const input = { provider: "deepseek", model: "deepseek-chat", usageStatus: "reported" as const, + usage: { inputTokens: 1_000_000, outputTokens: 100_000 } }; + expect(estimateRequestCost(input, undefined, zero)?.cost.total).toBe(0); + expect(estimateComboCost([{ ...input, ordinal: 1 }], undefined, undefined, zero)?.cost.total).toBe(0); + expect(resolveMatchedPrice("deepseek", "deepseek-chat", undefined, [])?.cost4.input).toBeGreaterThan(0); }); test("combo fails closed when a user-priced attempt shares a combo with an unpriced one", () => { From 062e9cbd39338945a3377f4ffbf2fa1dff41c65a Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 18:56:38 +0900 Subject: [PATCH 133/412] fix(models): validate price receipts and redact CLI failures [skip ci] Address independent review findings on the manual price CLI; preserve HTTP-specific exit codes and project only acknowledged fields. Co-authored-by: nordz0r <6949669+nordz0r@users.noreply.github.com> --- src/cli/models-runtime.ts | 49 ++++++++++++-- tests/cli/cli-models-price.test.ts | 67 +++++++++++++++++-- tests/cli/cli-models-runtime-dispatch.test.ts | 4 +- 3 files changed, 110 insertions(+), 10 deletions(-) diff --git a/src/cli/models-runtime.ts b/src/cli/models-runtime.ts index d71ce84e47..129f2fb53b 100644 --- a/src/cli/models-runtime.ts +++ b/src/cli/models-runtime.ts @@ -67,7 +67,31 @@ async function live(argv: string[], deps: RuntimeApiDeps): Promise { })); } +function priceRecord(value: unknown): value is Record { + return value !== null && typeof value === "object" && !Array.isArray(value); +} + +const PRICE_RATE_KEYS = ["input", "output", "cacheRead", "cacheWrite"] as const; + +function validPriceCost(value: unknown): value is ProviderCostOverlay { + return priceRecord(value) && Object.keys(value).length === PRICE_RATE_KEYS.length + && PRICE_RATE_KEYS.every(key => Object.hasOwn(value, key) && isValidCost4Rate(value[key])); +} + async function price(write: boolean, argv: string[], deps: RuntimeApiDeps): Promise { + try { + await priceRequest(write, argv, deps); + } catch (error) { + // Duplicated, inline and stray options also reach parser diagnostics. + // Keep HTTP-specific RuntimeApiError exits while masking usage errors. + if (error instanceof CliUsageError) { + throw new CliUsageError(redactSecretString(error.message), error.usage); + } + throw error; + } +} + +async function priceRequest(write: boolean, argv: string[], deps: RuntimeApiDeps): Promise { const args = [...argv]; const selector = args.shift() ?? ""; const slash = selector.indexOf("/"); @@ -83,9 +107,18 @@ async function price(write: boolean, argv: string[], deps: RuntimeApiDeps): Prom const path = `/api/providers/${encodeURIComponent(provider)}/model-costs`; if (!write) { rejectArgs(args, USAGE); - const result = await runtimeRequest<{ provider: string; modelCosts: Record }>(path, {}, deps); - const cost = Object.hasOwn(result.modelCosts, modelId) ? result.modelCosts[modelId]! : null; - printData({ provider: result.provider, modelId, cost }, wantsJson, [ + const result = await runtimeRequest(path, {}, deps); + if (!priceRecord(result) || result.provider !== provider || !priceRecord(result.modelCosts) + || !Object.values(result.modelCosts).every(validPriceCost)) { + throw new Error("Invalid model price response"); + } + let cost: ProviderCostOverlay | null = null; + if (Object.hasOwn(result.modelCosts, modelId)) { + const stored = result.modelCosts[modelId]; + if (!validPriceCost(stored)) throw new Error("Invalid model price response"); + cost = { ...stored }; + } + printData({ provider, modelId, cost }, wantsJson, [ cost === null ? `${selector}: automatic pricing` : `${selector}: ${JSON.stringify(cost)} USD per 1M tokens`, ]); return; @@ -116,7 +149,15 @@ async function price(write: boolean, argv: string[], deps: RuntimeApiDeps): Prom cacheWrite: rate(cacheWrite ?? "0", "--cache-write"), }; const result = await runtimeRequest(path, { method: "PUT", body: JSON.stringify({ modelId, cost }) }, deps); - printData(result, wantsJson, [auto ? `${selector}: automatic pricing restored.` : `${selector}: manual pricing saved.`]); + const receivedCost = priceRecord(result) ? result.cost : undefined; + if (!priceRecord(result) || result.ok !== true || result.provider !== provider || result.modelId !== modelId + || (cost === null ? receivedCost !== null : !validPriceCost(receivedCost) + || !PRICE_RATE_KEYS.every(key => receivedCost[key] === cost[key]))) { + throw new Error("Invalid model price persistence receipt"); + } + // Project the acknowledged fields only; unrelated response fields are not CLI output. + printData({ ok: true, provider, modelId, cost }, wantsJson, + [auto ? `${selector}: automatic pricing restored.` : `${selector}: manual pricing saved.`]); } async function edit(argv: string[], deps: RuntimeApiDeps): Promise { diff --git a/tests/cli/cli-models-price.test.ts b/tests/cli/cli-models-price.test.ts index c36b049ce5..9adda79977 100644 --- a/tests/cli/cli-models-price.test.ts +++ b/tests/cli/cli-models-price.test.ts @@ -5,7 +5,7 @@ import { MANAGEMENT_ROUTES } from "../../src/server/management/route-registry"; const COST = { input: 1.25, output: 5, cacheRead: 0.125, cacheWrite: 2 }; -async function invoke(sub: string, args: string[], response: unknown = { ok: true }, status = 200) { +async function invoke(sub: string, args: string[], response?: unknown, status = 200) { const calls: Array<{ path: string; method: string; body: unknown }> = []; const stdout: string[] = []; const stderr: string[] = []; @@ -17,12 +17,17 @@ async function invoke(sub: string, args: string[], response: unknown = { ok: tru const code = await handleModelsRuntimeCommand(sub, args, { baseUrl: "http://127.0.0.1:1", fetchImpl: async (url, init) => { + const path = new URL(String(url)).pathname; + const body = init?.body ? JSON.parse(String(init.body)) : undefined; calls.push({ - path: new URL(String(url)).pathname, + path, method: init?.method ?? "GET", - body: init?.body ? JSON.parse(String(init.body)) : undefined, + body, }); - return Response.json(response, { status }); + if (response instanceof Response) return response; + return Response.json(response === undefined + ? { ok: true, provider: path.split("/")[3], modelId: body?.modelId, cost: body?.cost } + : response, { status }); }, }); return { code, calls, stdout: stdout.join("\n"), stderr: stderr.join("\n") }; @@ -119,11 +124,63 @@ describe("models manual price commands", () => { test("API rejection is reported with a nonzero exit and no success message", async () => { const result = await invoke("set-price", ["custom-price/model", "--auto"], { error: "provider not found" }, 404); - expect(result.code).toBe(1); + expect(result.code).toBe(4); expect(result.stderr).toContain("provider not found"); expect(result.stdout).toBe(""); }); + test("duplicate, inline and stray price arguments never echo credential-shaped values", async () => { + const secret = "sk-" + "a".repeat(40); + for (const extra of [["--input", secret], [`--input=${secret}`], [secret]]) { + const result = await invoke("set-price", ["custom-price/model", "--input", "1", "--output", "2", ...extra]); + expect(result.code).toBe(2); + expect(result.calls).toHaveLength(0); + expect(result.stderr).not.toContain(secret); + expect(result.stderr).toContain("Unexpected argument(s)"); + expect(result.stdout).toBe(""); + } + }); + + test("malformed or mismatched success receipts fail without printing response contents", async () => { + const secret = "sk-" + "a".repeat(40); + const cost = { input: 1, output: 2, cacheRead: 0, cacheWrite: 0 }; + const receipt = { ok: true, provider: "custom-price", modelId: "model", cost }; + for (const response of [ + null, {}, "malformed", new Response("{"), new Response(null, { status: 204 }), + { ...receipt, ok: false }, { ...receipt, provider: "other" }, { ...receipt, modelId: "other" }, + { ...receipt, cost: null }, { ...receipt, cost: { input: 1, output: 2 } }, + { ...receipt, cost: { ...cost, output: 3 } }, { ...receipt, cost: { ...cost, apiKey: secret } }, + ]) { + const result = await invoke("set-price", ["custom-price/model", "--input", "1", "--output", "2"], response); + expect(result.code).toBe(1); + expect(result.stdout).toBe(""); + expect(result.stderr).toContain("Invalid model price persistence receipt"); + expect(result.stderr).not.toContain(secret); + } + const badReset = await invoke("set-price", ["custom-price/model", "--auto"], receipt); + expect(badReset.code).toBe(1); + expect(badReset.stdout).toBe(""); + const projected = await invoke("set-price", ["custom-price/model", "--input", "1", "--output", "2", "--json"], { ...receipt, apiKey: secret }); + expect(projected.code).toBe(0); + expect(JSON.parse(projected.stdout)).toEqual(receipt); + expect(projected.stdout).not.toContain(secret); + }); + + test("invalid GET maps fail rather than appearing automatic or leaking extra rate fields", async () => { + for (const response of [ + null, {}, new Response("{"), { provider: "other", modelCosts: {} }, + { provider: "custom-price", modelCosts: [] }, + { provider: "custom-price", modelCosts: { model: null } }, + { provider: "custom-price", modelCosts: { model: { ...COST, input: -1 } } }, + { provider: "custom-price", modelCosts: { model: { ...COST, extra: "unexpected" } } }, + ]) { + const result = await invoke("price", ["custom-price/model", "--json"], response); + expect(result.code).toBe(1); + expect(result.stdout).toBe(""); + expect(result.stderr).toContain("Invalid model price response"); + } + }); + test("secret-shaped model selectors fail before request or output for read, set and reset", async () => { const modelId = "sk-" + "a".repeat(40); for (const [sub, flags] of [ diff --git a/tests/cli/cli-models-runtime-dispatch.test.ts b/tests/cli/cli-models-runtime-dispatch.test.ts index 8145ec701e..06bc8f43b1 100644 --- a/tests/cli/cli-models-runtime-dispatch.test.ts +++ b/tests/cli/cli-models-runtime-dispatch.test.ts @@ -45,7 +45,9 @@ describe("models runtime subcommand dispatch (#3094)", () => { baseUrl: "http://127.0.0.1:1", fetchImpl: async (_url: string | URL | Request, init?: RequestInit) => { methods.push(init?.method ?? "GET"); - return Response.json({ provider: "dispatch-test", modelCosts: {}, ok: true }); + return Response.json(init?.method === "PUT" + ? { provider: "dispatch-test", modelId: "model", cost: null, ok: true } + : { provider: "dispatch-test", modelCosts: {} }); }, }; expect(await handleModelsRuntimeCommand("price", ["dispatch-test/model"], deps)).toBe(0); From a6e1227c8c6909eba8efc85d4a1ee3a992288bd7 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 19:14:02 +0900 Subject: [PATCH 134/412] fix(models): start price reload state from user actions [skip ci] Address exact-head GUI lint diagnosis without disabling the rule; initial loading uses initialized state and effects update only after the fetch. Co-authored-by: nordz0r <6949669+nordz0r@users.noreply.github.com> --- gui/src/components/ModelPriceDialog.tsx | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/gui/src/components/ModelPriceDialog.tsx b/gui/src/components/ModelPriceDialog.tsx index c4e08d98b6..f6e1a58200 100644 --- a/gui/src/components/ModelPriceDialog.tsx +++ b/gui/src/components/ModelPriceDialog.tsx @@ -62,8 +62,6 @@ export default function ModelPriceDialog({ model, apiBase, onRefresh, onClose }: if (requestRef.current) return; const bounded = createBoundedFetch(REQUEST_TIMEOUT_MS); requestRef.current = bounded; - setPhase("loading"); - setErrorKey(null); try { const response = await fetch(endpoint, { signal: bounded.signal, cache: "no-store" }); const result = await readJsonOrThrow(response); @@ -168,7 +166,12 @@ export default function ModelPriceDialog({ model, apiBase, onRefresh, onClose }: onSubmit={event => { event.preventDefault(); if (requestRef.current) return; - if (phase === "unknown" || phase === "loadFailed") { void readOverride(phase === "unknown"); return; } + if (phase === "unknown" || phase === "loadFailed") { + setPhase("loading"); + setErrorKey(null); + void readOverride(phase === "unknown"); + return; + } if (phase === "refreshFailed") { void save(undefined); return; } if (locked) return; const cost = { From 568a3e89cb4bc67987d86acbf5e9d63fb3015c9b Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 19:36:04 +0900 Subject: [PATCH 135/412] docs: record code-mode delivery and qualify Desktop model switching [skip ci] --- .../040_delivery_record.md | 100 ++++++++++++++++++ .../src/content/docs/guides/claude-code.md | 12 ++- 2 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 devlog/_plan/260907_code_mode_host_contract/040_delivery_record.md diff --git a/devlog/_plan/260907_code_mode_host_contract/040_delivery_record.md b/devlog/_plan/260907_code_mode_host_contract/040_delivery_record.md new file mode 100644 index 0000000000..3c2b28e23d --- /dev/null +++ b/devlog/_plan/260907_code_mode_host_contract/040_delivery_record.md @@ -0,0 +1,100 @@ +# 040 — Delivery record: code-mode host contract + +Recorded 2026-09-07 from GitHub PR and Actions API responses. This records the delivery requested +by [030_docs_and_delivery.md](030_docs_and_delivery.md#d-record). + +## Delivered revision and CI identity + +- [PR #3854](https://github.com/lidge-jun/opencodex/pull/3854) is merged into `dev`; + GitHub records `merged_at: 2026-09-07T06:41:03Z`. +- Final PR head: `6bdcba5bff4196debf3cd159c7af3d34e35a24e0`. +- Merge commit: `ece556a6ed32dc811bd660ddd8ef9e829512457a`. +- [Pre-merge CI run 34090946313](https://github.com/lidge-jun/opencodex/actions/runs/34090946313), + attempt 1: `event: pull_request`, `head_sha: 6bdcba5bff4196debf3cd159c7af3d34e35a24e0`, + `status: completed`, `conclusion: success`; updated `2026-09-07T06:39:04Z`. +- [Merge-head CI run 34091933836](https://github.com/lidge-jun/opencodex/actions/runs/34091933836), attempt 1: + `event: push`, `head_sha: ece556a6ed32dc811bd660ddd8ef9e829512457a`, + `status: completed`, `conclusion: success`; updated `2026-09-07T06:50:18Z`. + +The pre-merge run matches the final PR head; the later push run matches the merge commit. +These are distinct CI records. This API check does not attest that the separate local receipt +required by 030 was recorded. + +## Per-job results + +Each run has 21 completed jobs: 19 success, 2 skipped. Every job has the same conclusion in both +runs. Names below are the literal Actions job names; each evidence link identifies its own run. + +| Job | Conclusion in both runs | Pre-merge evidence | Merge-head evidence | +|---|---|---|---| +| `select windows runner` | success | [job 101644191502](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644191502) | [job 101647069433](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647069433) | +| `changes` | success | [job 101644191303](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644191303) | [job 101647069779](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647069779) | +| `windows ${{ matrix.shard }}/6` | skipped | [job 101644212182](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644212182) | [job 101647096144](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647096144) | +| `macos 1/2` | success | [job 101644233998](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644233998) | [job 101647111898](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647111898) | +| `api usage` | success | [job 101644234038](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644234038) | [job 101647111914](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647111914) | +| `storage policy` | success | [job 101644234034](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644234034) | [job 101647111922](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647111922) | +| `docker smoke` | success | [job 101644234277](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644234277) | [job 101647111928](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647111928) | +| `keyring ubuntu` | success | [job 101644234063](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644234063) | [job 101647111929](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647111929) | +| `test 3/4` | success | [job 101644234103](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644234103) | [job 101647111932](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647111932) | +| `test 4/4` | success | [job 101644234047](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644234047) | [job 101647111936](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647111936) | +| `keyring macos` | success | [job 101644233982](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644233982) | [job 101647111942](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647111942) | +| `test 1/4` | success | [job 101644234139](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644234139) | [job 101647111951](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647111951) | +| `gates` | success | [job 101644233985](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644233985) | [job 101647111970](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647111970) | +| `keyring windows` | success | [job 101644234037](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644234037) | [job 101647111972](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647111972) | +| `macos 2/2` | success | [job 101644234066](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644234066) | [job 101647111974](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647111974) | +| `npm-global ubuntu-latest` | success | [job 101644234059](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644234059) | [job 101647111980](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647111980) | +| `npm-global windows-latest` | success | [job 101644234098](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644234098) | [job 101647111990](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647111990) | +| `test 2/4` | success | [job 101644234167](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644234167) | [job 101647112003](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647112003) | +| `npm-global macos-latest` | success | [job 101644234033](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644234033) | [job 101647112012](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647112012) | +| `macos control` | skipped | [job 101644235362](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101644235362) | [job 101647112696](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101647112696) | +| `ci` | success | [job 101646588871](https://github.com/lidge-jun/opencodex/actions/runs/34090946313/job/101646588871) | [job 101649082610](https://github.com/lidge-jun/opencodex/actions/runs/34091933836/job/101649082610) | + +The Windows full-suite matrix was **SKIPPED in both runs**. Windows keyring create/read/delete smoke and +npm-global packaging/install/help smoke passed; those focused passes do not establish Windows +full-suite coverage. The `ci` aggregate accepts successful or skipped prerequisites, so its green +result does not turn skipped jobs into passes. On the merge-head run, `gates` includes successful Typecheck, GUI tests, +Privacy scan, skill-surface check, release-helper syntax check, and CLI help smoke; its GUI lint, +GUI build, and dashboard-preview steps were skipped. + +Evidence retrieval (read-only): + +```sh +gh api repos/lidge-jun/opencodex/pulls/3854 +gh api repos/lidge-jun/opencodex/actions/runs/34090946313 +gh api 'repos/lidge-jun/opencodex/actions/runs/34090946313/jobs?per_page=100' +gh api repos/lidge-jun/opencodex/actions/runs/34091933836 +gh api 'repos/lidge-jun/opencodex/actions/runs/34091933836/jobs?per_page=100' +``` + +## Limits and residuals + +The delivered scope is the pre-call guidance and post-hoc recovery annotations described in +[030](030_docs_and_delivery.md). Guidance cannot force model compliance, repair the model's +JavaScript or patch payload, or replace the host's validation. The effect on the live Grok defect +rate remains **unmeasured** until a live re-probe; CI success is not a defect-rate measurement. + +Anthropic, Google, OpenAI-chat, and command-code tool-result paths still lack exec-result +annotation seams and do not annotate these host failures. Existing coverage is limited to native +routed Responses, Kiro, and Cursor. + +Two public review threads were **OPEN / UNRESOLVED in the recorded 2026-09-07 audit snapshot**: GitHub's review-thread API returned +`isResolved: false` for both on 2026-09-07. The merge and green CI do not resolve these findings. +Source inspected for that snapshot was read at worktree HEAD `0fd3408b99994f74bd509975df7ee89823ddfecd`: + +- [discussion_r3947178410](https://github.com/lidge-jun/opencodex/pull/3854#discussion_r3947178410): + `src/adapters/exec-tool-result-normalize.ts:196` searches arbitrary output for a marker substring. + Successful output from a command such as `rg` or `cat` can therefore receive a misleading + recovery hint when it quotes that phrase, even though the command did not fail. The requested + host-error status/envelope or exact diagnostic check remains unimplemented at this anchor. +- [discussion_r3947178418](https://github.com/lidge-jun/opencodex/pull/3854#discussion_r3947178418): + `src/adapters/cursor/tool-result-normalize.ts:114` gates annotation on tool name/namespace + without request-catalog or freeform provenance. A structured tool named `exec` can receive + unrelated host guidance. The requested code-mode provenance check remains unimplemented at + this anchor. + +These limitations were also recorded in [000](000_plan.md). Recording them here is not a fix, +review resolution, or claim that successful output is left byte-identical. + +Local runtime, tests, typecheck, build, and install: **NOT RUN** by instruction. No live model +re-probe was performed for this record. The remote results above belong to the recorded PR head +and merge commit and do not validate later candidate documentation or test patches. diff --git a/docs-site/src/content/docs/guides/claude-code.md b/docs-site/src/content/docs/guides/claude-code.md index 0b1c0e9db4..0c3cb32697 100644 --- a/docs-site/src/content/docs/guides/claude-code.md +++ b/docs-site/src/content/docs/guides/claude-code.md @@ -309,8 +309,16 @@ canonical ids. The synthetic 2026 date is an internal slot, not a release date. and `claude-ocx---` ids from older configs still resolve. If Claude Desktop's footer picker does not change the model for an already-running 3P -conversation, use `/model ` in that conversation. OpenCodex cannot observe picker state; it -routes the model id carried by each request. Confirm the result under **Logs → requestedModel**. +conversation, you can try `/model `, but this workaround may also fail on affected Desktop +builds. [Issue #3782](https://github.com/lidge-jun/opencodex/issues/3782) reports that on Windows +with Claude Desktop 1.46388.4, the conversation continues using its initial model after both +footer-picker and `/model` changes. The report does not establish which client or routing +component causes the behavior. + +You can also try selecting the intended default model in the OpenCodex Claude Desktop profile, +reapplying the profile, and starting a new conversation. This is a troubleshooting step, not a +guaranteed fix. OpenCodex cannot observe picker state; it routes the model id carried by each +request. Confirm what the client sends under **Logs → requestedModel**. Models with an authoritative 1M context window get an extra `…[1m]` picker row: selecting it makes Claude Code account a full 1M context for that model (auto-compaction stays on) — the proxy strips From e0a1a8836e447ece3010ba98813e6feb3161eefd Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 19:33:29 +0900 Subject: [PATCH 136/412] docs: complete Raycast status and model-name recovery guidance [skip ci] --- .../content/docs/fr/guides/integrations.md | 2 +- .../fr/reference/configuration/providers.md | 18 +++++++++ .../src/content/docs/guides/integrations.md | 24 ++++++++---- .../ja/reference/configuration/providers.md | 16 ++++++++ .../ko/reference/configuration/providers.md | 14 +++++++ .../ru/reference/configuration/providers.md | 18 +++++++++ .../tr/reference/configuration/providers.md | 17 ++++++++ .../reference/configuration/providers.md | 12 ++++++ .../reference/configuration/providers.md | 12 ++++++ src/cli/integrations.ts | 2 +- tests/cli/cli-headless-parity.test.ts | 39 +++++++++++++++++++ 11 files changed, 164 insertions(+), 10 deletions(-) diff --git a/docs-site/src/content/docs/fr/guides/integrations.md b/docs-site/src/content/docs/fr/guides/integrations.md index c718801ddc..97babedd18 100644 --- a/docs-site/src/content/docs/fr/guides/integrations.md +++ b/docs-site/src/content/docs/fr/guides/integrations.md @@ -128,7 +128,7 @@ niveaux. Dans ces cas, le commutateur est verrouillé afin que rien ne soit modi **OMP** n'est pas affecté non plus par les modifications voisines, mais pour une autre raison : son outil d'écriture ne modifie, octet par octet, que sa propre plage `providers.opencodex` ; le reste du fichier n'est jamais réécrit. Pour les autres formats susceptibles de contenir des commentaires (Hermes, OpenClaw, -Kimi Code, Gajae Code, MiniMax Code, ZCode, Prime Agent, Aside et Raycast — documents YAML, JSON5 et TOML réécrits en entier), ou lorsque les propres entrées +Kimi Code, Gajae Code, MiniMax Code et Raycast — documents YAML, JSON5 et TOML réécrits en entier), ou lorsque les propres entrées d'opencodex ont été modifiées, le commutateur se verrouille et la désactivation est refusée plutôt que de deviner quelles modifications vous appartiennent. diff --git a/docs-site/src/content/docs/fr/reference/configuration/providers.md b/docs-site/src/content/docs/fr/reference/configuration/providers.md index 96d00e5668..9686bb2470 100644 --- a/docs-site/src/content/docs/fr/reference/configuration/providers.md +++ b/docs-site/src/content/docs/fr/reference/configuration/providers.md @@ -473,6 +473,24 @@ avec un contexte de `922000` et une entrée maximale de `922000` ; OpenRouter i } ``` +## Éditeur de noms d'affichage des modèles + +Dans le tableau de bord, **Models** permet d'enregistrer durablement des noms lisibles pour les modèles découverts. Développez le fournisseur, +repérez un modèle découvert et choisissez **Name**. La boîte de dialogue garde le sélecteur exact +`provider/model` visible pendant que vous enregistrez un libellé lisible. Choisissez **Reset name** +pour revenir aux métadonnées du fournisseur ou au sélecteur utilisé par défaut. **Name** ne change +que l'affichage ; le crayon distinct consacré à l'alias modifie l'alias court de routage et n'est +pas un éditeur de nom d'affichage. Les lignes OpenAI natives et celles des modèles personnalisés +conservent leurs commandes existantes. + +Si la modification est enregistrée mais que l'actualisation échoue, la boîte de dialogue reflète +la valeur enregistrée et garde **Retry** disponible. Retry relance la convergence du catalogue +si le serveur a signalé son échec, ou recharge la liste si seule la requête de liste a échoué. +La reprise d'une réinitialisation conserve cette opération ; elle ne rétablit pas l'ancien nom. +Les requêtes ont un délai maximal de 60 secondes couvrant l'écriture et l'actualisation de la liste +qui suit. Un dépassement de délai n'annule pas une écriture : utilisez **Retry** pour vérifier +le nom actuel avant d'effectuer une autre modification. + ## Exemple complet ```json diff --git a/docs-site/src/content/docs/guides/integrations.md b/docs-site/src/content/docs/guides/integrations.md index ea3c93f2dd..b475b71e20 100644 --- a/docs-site/src/content/docs/guides/integrations.md +++ b/docs-site/src/content/docs/guides/integrations.md @@ -62,14 +62,22 @@ One caveat specific to Aside: the running app rewrites `models.json` itself, so fully quit and reopen Aside after applying, the same way Claude Desktop needs a restart. Aside's block is loopback-only and never carries a real credential. -Raycast has two prerequisites. Custom Providers is a **Raycast Pro** feature: on a -free plan the file is still written, but `ocx integration client status --client -raycast` and the Integrations page report a warning, because Raycast will not -read it. And Raycast only creates its `ai` folder when you open Raycast → -Settings → AI → **Reveal Providers Config** once; opencodex uses that folder as -the install signal and reports the client as not installed until then. Raycast -reads `~/.config/raycast/ai/providers.yaml` on macOS and Windows alike and does -not honor `XDG_CONFIG_HOME`, so that path is not relocatable. +The managed Raycast integration supports **macOS and Windows**. Custom Providers +is a **Raycast Pro** feature: on a free plan the file is still written, but +`ocx integration client status --client raycast` and the Integrations page report +a warning, because Raycast will not read it. On macOS or Windows, open Raycast → +Settings → AI → **Reveal Providers Config** once so the `ai` folder exists. +On these supported platforms, opencodex uses that folder as its install signal +and reports the client as not installed until it exists. Linux is unsupported, +even if the folder exists. + +The status field `aiDirPresent` reports only whether `~/.config/raycast/ai` exists, +independently of whether the Raycast app is installed or the platform is supported. +It does not prove that Raycast is installed or usable. The CLI prints `plan` on a +separate line and adds the macOS/Windows setup instruction when `aiDirPresent` is +false; `--json` preserves the raw status, including the nested `raycast` block. +Raycast reads `~/.config/raycast/ai/providers.yaml` on macOS and Windows alike and +does not honor `XDG_CONFIG_HOME`, so that path is not relocatable. The managed block is one element, `id: opencodex`, in the file's `providers` sequence: `name: OpenCodex`, `base_url: http://:/v1`, and every diff --git a/docs-site/src/content/docs/ja/reference/configuration/providers.md b/docs-site/src/content/docs/ja/reference/configuration/providers.md index 8938073e6c..dc7929d26e 100644 --- a/docs-site/src/content/docs/ja/reference/configuration/providers.md +++ b/docs-site/src/content/docs/ja/reference/configuration/providers.md @@ -394,6 +394,22 @@ Vercel AI Gateway は、1 つのモデルを複数の基盤となる推論プロ } ``` +## モデルの表示名エディター + +ダッシュボードの **Models** では、検出されたモデルに読みやすい名前を付けて永続的に保存できます。プロバイダーを展開し、検出された +モデルを見つけて **Name** を選択します。読みやすい名前を保存する間も、ダイアログには正確な +`provider/model` セレクターが表示されます。**Reset name** を選ぶと、プロバイダーのメタデータ、 +または通常のセレクター表示に戻ります。**Name** が変更するのは表示だけです。別のエイリアス用 +鉛筆アイコンは短いルーティングエイリアスを変更するもので、表示名エディターではありません。 +ネイティブ OpenAI とカスタムモデルの行では、既存の操作方法が維持されます。 + +変更は保存されたものの更新に失敗した場合、ダイアログは保存済みの上書き設定を反映し、**Retry** を +引き続き利用できます。サーバーがカタログの収束処理の失敗を報告した場合、Retry はその処理を再実行し、 +一覧取得のリクエストだけが失敗した場合は一覧を再読み込みします。リセット後の復旧でもリセット操作を +維持し、以前の名前には戻しません。リクエストには、書き込みとその後の一覧更新を合わせて 60 秒の +期限があります。タイムアウトしても書き込みは取り消されません。次の変更を行う前に **Retry** で +現在の名前を確認してください。 + ## 完全な例 ```json diff --git a/docs-site/src/content/docs/ko/reference/configuration/providers.md b/docs-site/src/content/docs/ko/reference/configuration/providers.md index 2dda27e7bf..75ae5055b6 100644 --- a/docs-site/src/content/docs/ko/reference/configuration/providers.md +++ b/docs-site/src/content/docs/ko/reference/configuration/providers.md @@ -401,6 +401,20 @@ Vercel AI Gateway는 하나의 모델을 여러 기반 추론 공급자에 걸 } ``` +## 모델 표시 이름 편집기 + +대시보드의 **Models**에서 발견된 모델의 읽기 쉬운 이름을 저장해 유지할 수 있습니다. 공급자를 펼치고 발견된 모델을 +찾아 **Name**을 선택하세요. 읽기 쉬운 이름을 저장하는 동안에도 대화 상자는 정확한 `provider/model` +선택자를 표시합니다. **Reset name**을 선택하면 공급자 메타데이터 또는 기본 선택자 표시로 돌아갑니다. +**Name**은 표시만 바꿉니다. 별도의 별칭 연필 아이콘은 짧은 라우팅 별칭을 바꾸며, 표시 이름 편집기가 +아닙니다. 네이티브 OpenAI와 사용자 지정 모델 행은 기존 조작 방식을 유지합니다. + +변경은 저장됐지만 새로고침에 실패하면 대화 상자는 저장된 재정의를 반영하고 **Retry**를 계속 제공합니다. +서버가 카탈로그 수렴 실패를 보고했다면 Retry는 수렴을 다시 실행하고, 목록 요청만 실패했다면 목록을 +다시 불러옵니다. 초기화 후 복구는 초기화 작업을 유지하며 이전 이름을 복원하지 않습니다. 요청에는 +쓰기와 후속 목록 새로고침을 모두 포함하는 60초 제한이 있습니다. 시간 초과가 쓰기를 취소하지는 않습니다. +다른 변경을 하기 전에 **Retry**로 현재 이름을 확인하세요. + ## 전체 예시 ```json diff --git a/docs-site/src/content/docs/ru/reference/configuration/providers.md b/docs-site/src/content/docs/ru/reference/configuration/providers.md index 14a8b0a3ce..3ddb29c806 100644 --- a/docs-site/src/content/docs/ru/reference/configuration/providers.md +++ b/docs-site/src/content/docs/ru/reference/configuration/providers.md @@ -488,6 +488,24 @@ Pool/Direct рекламирует `922000`; синхронизированны } ``` +## Редактор отображаемых имён моделей + +На странице **Models** в дашборде можно задать понятные имена для обнаруженных моделей и сохранить их для дальнейшего использования. Разверните провайдера, +найдите обнаруженную модель и выберите **Name**. При сохранении понятной подписи диалог оставляет +видимым точный селектор `provider/model`. Выберите **Reset name**, чтобы вернуться к metadata +провайдера или обычному селектору, используемому по умолчанию. **Name** меняет только отображение; +отдельный значок карандаша для alias меняет короткий routing alias и не является редактором +отображаемого имени. Нативные строки OpenAI и строки пользовательских моделей сохраняют +существующие элементы управления. + +Если изменение сохранено, но обновление не удалось, диалог отражает сохранённое переопределение +и оставляет **Retry** доступным. Retry повторяет приведение каталога к согласованному состоянию, +если сервер сообщил о сбое этого процесса, или перезагружает список, если не удался только запрос +списка. Восстановление после сброса сохраняет операцию сброса и не возвращает старое имя. +Для запросов действует общий срок в 60 секунд, включающий запись и последующее обновление списка. +Тайм-аут не отменяет запись: используйте **Retry**, чтобы проверить текущее имя перед следующим +изменением. + ## Полный пример ```json diff --git a/docs-site/src/content/docs/tr/reference/configuration/providers.md b/docs-site/src/content/docs/tr/reference/configuration/providers.md index 3e01051010..daffcd2120 100644 --- a/docs-site/src/content/docs/tr/reference/configuration/providers.md +++ b/docs-site/src/content/docs/tr/reference/configuration/providers.md @@ -518,6 +518,23 @@ bildirir; senkronize edilen katalog `xhigh`'ı ayrı tutarken `max` bildirir. } ``` +## Model görünen adı düzenleyicisi + +Kontrol panelindeki **Models**, keşfedilen modeller için okunabilir adları kalıcı olarak kaydetmenizi sağlar. Sağlayıcıyı genişletin, keşfedilen +bir modeli bulun ve **Name** seçeneğini seçin. Okunabilir bir etiket kaydederken iletişim kutusu +tam `provider/model` seçicisini görünür tutar. Sağlayıcı meta verilerine veya varsayılan seçici +gösterimine dönmek için **Reset name** seçeneğini seçin. **Name** yalnızca görünümü değiştirir; +ayrı takma ad kalemi kısa yönlendirme takma adını değiştirir ve bir görünen ad düzenleyicisi +değildir. Yerel OpenAI ve özel model satırları mevcut kontrollerini korur. + +Değişiklik kaydedildiği halde yenileme başarısız olursa iletişim kutusu kaydedilen geçersiz kılma +değerini yansıtır ve **Retry** kullanılabilir kalır. Sunucu katalog yakınsamasının başarısız +olduğunu bildirdiyse Retry bu işlemi tekrarlar; yalnızca liste isteği başarısız olduysa listeyi +yeniden yükler. Sıfırlama sonrası kurtarma, sıfırlama işlemini korur ve eski adı geri getirmez. +İsteklerin, yazma işlemini ve ardından gelen liste yenilemesini kapsayan 60 saniyelik bir süresi +vardır. Zaman aşımı yazma işlemini geri almaz: başka bir değişiklik yapmadan önce **Retry** ile +geçerli adı kontrol edin. + ## Tam örnek ```json diff --git a/docs-site/src/content/docs/zh-cn/reference/configuration/providers.md b/docs-site/src/content/docs/zh-cn/reference/configuration/providers.md index 32f2b52a69..313663f346 100644 --- a/docs-site/src/content/docs/zh-cn/reference/configuration/providers.md +++ b/docs-site/src/content/docs/zh-cn/reference/configuration/providers.md @@ -395,6 +395,18 @@ Vercel AI Gateway 可以在多个底层推理提供者之间路由一个模型 } ``` +## 模型显示名称编辑器 + +仪表板的 **Models** 可让你为已发现的模型持久保存易读名称。展开提供者,找到一个已发现的模型,然后选择 **Name**。 +保存易读名称时,对话框会一直显示精确的 `provider/model` 选择器。选择 **Reset name** 可恢复为 +提供者元数据中的名称,或默认的选择器显示。**Name** 只改变显示;单独的别名铅笔图标用于修改 +短路由别名,并不是显示名称编辑器。原生 OpenAI 和自定义模型条目保留现有控件。 + +如果更改已保存但刷新失败,对话框会反映已保存的覆盖值,并继续提供 **Retry**。如果服务器报告 +目录收敛失败,Retry 会重新执行目录收敛;如果只是列表请求失败,则重新加载列表。重置后的恢复 +会保留重置操作,不会恢复旧名称。请求的总时限为 60 秒,涵盖写入及后续的列表刷新。超时不会撤销 +写入:进行其他更改前,请使用 **Retry** 检查当前名称。 + ## 完整示例 ```json diff --git a/docs-site/src/content/docs/zh-tw/reference/configuration/providers.md b/docs-site/src/content/docs/zh-tw/reference/configuration/providers.md index 2a53c4d33a..74ee860ff1 100644 --- a/docs-site/src/content/docs/zh-tw/reference/configuration/providers.md +++ b/docs-site/src/content/docs/zh-tw/reference/configuration/providers.md @@ -352,6 +352,18 @@ Vercel AI Gateway 可在多個底層推論供應商之間路由一個模型。`v } ``` +## 模型顯示名稱編輯器 + +儀表板的 **Models** 可讓你為已探索到的模型持久儲存易讀名稱。展開供應商,找到已探索到的模型,然後選擇 **Name**。 +儲存易讀名稱時,對話方塊會持續顯示精確的 `provider/model` 選擇器。選擇 **Reset name** 可回到 +供應商中繼資料中的名稱,或預設的選擇器顯示。**Name** 只改變顯示;獨立的別名鉛筆圖示用來修改 +短路由別名,並不是顯示名稱編輯器。原生 OpenAI 與自訂模型列保留既有控制項。 + +若變更已儲存但重新整理失敗,對話方塊會反映已儲存的覆寫值,並繼續提供 **Retry**。若伺服器回報 +目錄收斂失敗,Retry 會重新執行目錄收斂;若只有清單請求失敗,則重新載入清單。重設後的復原 +會保留重設操作,不會還原舊名稱。請求的總期限為 60 秒,涵蓋寫入及後續的清單重新整理。逾時不會 +撤銷寫入:進行其他變更前,請使用 **Retry** 檢查目前名稱。 + ## 完整範例 ```json diff --git a/src/cli/integrations.ts b/src/cli/integrations.ts index 89ab3ee046..5b690a6c8b 100644 --- a/src/cli/integrations.ts +++ b/src/cli/integrations.ts @@ -189,7 +189,7 @@ function singleClientStatusLines(result: unknown): string[] { const rest = Object.fromEntries(Object.entries(result as Record).filter(([key]) => key !== "raycast")); const lines = [...summaryLines(rest), `plan: ${raycast.plan}`]; if (!raycast.aiDirPresent) { - lines.push('Open Raycast → Settings → AI → "Reveal Providers Config" once so the ai folder exists.'); + lines.push('On macOS or Windows, open Raycast → Settings → AI → "Reveal Providers Config" once so the ai folder exists.'); } return lines; } diff --git a/tests/cli/cli-headless-parity.test.ts b/tests/cli/cli-headless-parity.test.ts index dab85a132c..78f0cc04a1 100644 --- a/tests/cli/cli-headless-parity.test.ts +++ b/tests/cli/cli-headless-parity.test.ts @@ -609,6 +609,45 @@ describe("headless GUI parity CLI", () => { expect(runtime.requests[1]).toEqual({ path: "/api/grok/selection", method: "PUT", body: { excluded: ["b"] } }); }); + for (const plan of ["pro", "free", "unknown"] as const) { + for (const aiDirPresent of [true, false]) { + test(`Raycast status keeps plan ${plan} separate with aiDirPresent=${aiDirPresent}`, async () => { + const payload = { + clientId: "raycast", + installed: aiDirPresent, + raycast: { plan, aiDirPresent }, + }; + const runtime = fakeRuntime(() => payload); + const logSpy = spyOn(console, "log").mockImplementation(() => {}); + try { + expect(await handleClientIntegrationCommand(["status", "--client", "raycast"], runtime.deps)).toBe(0); + const out = logSpy.mock.calls.map(call => String(call[0])).join("\n"); + const lines = out.split("\n"); + expect(lines.filter(line => line.startsWith("plan:"))).toEqual([`plan: ${plan}`]); + expect(out).not.toContain("raycast."); + if (aiDirPresent) { + expect(out).not.toContain("Reveal Providers Config"); + } else { + expect(lines).toContain('On macOS or Windows, open Raycast → Settings → AI → "Reveal Providers Config" once so the ai folder exists.'); + } + + logSpy.mockClear(); + expect(await handleClientIntegrationCommand(["status", "--client", "raycast", "--json"], runtime.deps)).toBe(0); + expect(logSpy.mock.calls).toHaveLength(1); + const jsonOut = String(logSpy.mock.calls[0]![0]); + expect(JSON.parse(jsonOut)).toEqual(payload); + expect(jsonOut).not.toContain("Reveal Providers Config"); + expect(runtime.requests).toEqual([ + { path: "/api/client-integrations/raycast", method: "GET", body: null }, + { path: "/api/client-integrations/raycast", method: "GET", body: null }, + ]); + } finally { + logSpy.mockRestore(); + } + }); + } + } + test("client integration toggles hit the exact management routes", async () => { const runtime = fakeRuntime(); expect(await handleClientIntegrationCommand(["enable", "--client", "hermes", "--json"], runtime.deps)).toBe(0); From f8c8f6dd15b1518f25a3b1cd7b15c9b6c8b24f62 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 20:29:56 +0900 Subject: [PATCH 137/412] docs: qualify Desktop model switching in translated guides [skip ci] --- .../src/content/docs/fr/guides/claude-code.md | 12 ++++++++++-- .../src/content/docs/ja/guides/claude-code.md | 15 ++++++++++++--- .../src/content/docs/ko/guides/claude-code.md | 14 +++++++++++--- .../src/content/docs/ru/guides/claude-code.md | 12 ++++++++++-- .../src/content/docs/tr/guides/claude-code.md | 16 +++++++++++++--- .../src/content/docs/zh-cn/guides/claude-code.md | 12 +++++++++--- 6 files changed, 65 insertions(+), 16 deletions(-) diff --git a/docs-site/src/content/docs/fr/guides/claude-code.md b/docs-site/src/content/docs/fr/guides/claude-code.md index 2ae3940254..e11e6a06d8 100644 --- a/docs-site/src/content/docs/fr/guides/claude-code.md +++ b/docs-site/src/content/docs/fr/guides/claude-code.md @@ -290,8 +290,16 @@ anciens alias hachés et les identifiants `claude-ocx---` des c toujours résolus. Si le sélecteur situé au bas de Claude Desktop ne modifie pas le modèle d'une conversation 3P déjà en cours, -utilisez `/model ` dans cette conversation. OpenCodex ne peut pas observer l'état du sélecteur ; il -achemine l’identifiant du modèle porté par chaque requête. Confirmez le résultat sous **Journaux → requestModel**. +vous pouvez essayer `/model `, mais ce contournement peut également échouer sur les versions de Desktop +concernées. Le [ticket #3782](https://github.com/lidge-jun/opencodex/issues/3782) rapporte que sous Windows, +avec Claude Desktop 1.46388.4, la conversation continue d'utiliser son modèle initial après des changements +via le sélecteur du bas comme via `/model`. Ce signalement ne permet pas d'établir quel composant du client +ou du routage est à l'origine de ce comportement. + +Vous pouvez aussi essayer de sélectionner le modèle par défaut souhaité dans le profil Claude Desktop +d'OpenCodex, de réappliquer ce profil et de démarrer une nouvelle conversation. Il s'agit d'une étape de +dépannage, sans garantie de résolution. OpenCodex ne peut pas observer l'état du sélecteur ; il achemine +l'identifiant du modèle porté par chaque requête. Vérifiez ce que le client envoie sous **Logs → requestedModel**. Les modèles dont la fenêtre de contexte de référence atteint 1M obtiennent une ligne supplémentaire `…[1m]` dans le sélecteur. Sa sélection indique à Claude Code la fenêtre complète de 1M pour ce modèle, tout en maintenant le compactage automatique ; le proxy retire diff --git a/docs-site/src/content/docs/ja/guides/claude-code.md b/docs-site/src/content/docs/ja/guides/claude-code.md index 384c3f50df..adc8703340 100644 --- a/docs-site/src/content/docs/ja/guides/claude-code.md +++ b/docs-site/src/content/docs/ja/guides/claude-code.md @@ -163,9 +163,18 @@ Claude Code 2.1.129 以降は `GET /v1/models?limit=1000` でゲートウェイ 提供します。両系列は継続してデコードできるため、どちらの形式でも `settings.json` に保存したモデルは 引き続き動作します。 -Claude Desktop のフッターピッカーで実行中の 3P 会話のモデルが切り替わらない場合は、その会話で -`/model ` を使用してください。OpenCodex はピッカーの状態を直接参照できず、各リクエストに -含まれるモデル ID をルーティングします。結果は **Logs → requestedModel** で確認できます。 +Claude Desktop のフッターピッカーで実行中の 3P 会話のモデルが切り替わらない場合は、 +`/model ` を試せますが、影響を受ける Desktop ビルドではこの回避策も失敗することがあります。 +[Issue #3782](https://github.com/lidge-jun/opencodex/issues/3782) では、Windows 上の +Claude Desktop 1.46388.4 で、フッターピッカーと `/model` のどちらで変更しても、会話が最初の +モデルを使い続けると報告されています。この報告だけでは、クライアントやルーティングのどの +コンポーネントがこの動作の原因なのかは確定できません。 + +OpenCodex の Claude Desktop プロファイルで希望するデフォルトモデルを選択し、プロファイルを +再適用して、新しい会話を開始することも試せます。これはトラブルシューティングの手順であり、 +解決を保証するものではありません。OpenCodex はピッカーの状態を参照できず、各リクエストに +含まれるモデル ID をルーティングします。クライアントが何を送信しているかは +**Logs → requestedModel** で確認してください。 **エイリアス構文ルール:** provider には `/` や `--` を含められず `native` と同じでもいけません。 `/` も `~` も含まない plain な model ID は v1 接頭辞 `claude-ocx-…` のままです。`/` または `~` を含む diff --git a/docs-site/src/content/docs/ko/guides/claude-code.md b/docs-site/src/content/docs/ko/guides/claude-code.md index 676800d1e6..90857854f0 100644 --- a/docs-site/src/content/docs/ko/guides/claude-code.md +++ b/docs-site/src/content/docs/ko/guides/claude-code.md @@ -199,9 +199,17 @@ Claude Code 2.1.129 이상은 `GET /v1/models?limit=1000`에서 게이트웨이 제공해요. 두 계열은 계속 디코딩할 수 있으므로 어느 형식이든 `settings.json`에 저장한 모델이 계속 작동해요. -Claude Desktop의 하단 선택기로 이미 실행 중인 3P 대화의 모델이 바뀌지 않는다면, 그 대화에서 -`/model `를 사용하세요. OpenCodex는 선택기 상태를 따로 볼 수 없고 각 요청에 실린 모델 ID를 -라우팅해요. 적용 결과는 **Logs → requestedModel**에서 확인할 수 있어요. +Claude Desktop의 하단 선택기로 이미 실행 중인 3P 대화의 모델이 바뀌지 않는다면, +`/model `를 시도할 수 있지만, 문제가 있는 Desktop 빌드에서는 이 우회 방법도 실패할 수 있어요. +[이슈 #3782](https://github.com/lidge-jun/opencodex/issues/3782)에는 Windows의 +Claude Desktop 1.46388.4에서 하단 선택기와 `/model`로 각각 변경해도 대화가 처음 모델을 계속 +사용한다는 보고가 있어요. 이 보고만으로는 클라이언트나 라우팅의 어느 구성 요소가 이 동작을 +일으키는지 확정할 수 없어요. + +OpenCodex의 Claude Desktop 프로필에서 원하는 기본 모델을 선택하고, 프로필을 다시 적용한 뒤 +새 대화를 시작하는 방법도 시도할 수 있어요. 이는 문제 해결을 위한 시도이며 해결을 보장하지는 +않아요. OpenCodex는 선택기 상태를 볼 수 없고 각 요청에 실린 모델 ID를 라우팅해요. +클라이언트가 실제로 무엇을 보내는지는 **Logs → requestedModel**에서 확인하세요. **별칭 문법 규칙:** provider에는 `/`나 `--`를 넣을 수 없고 `native`와 같아도 안 돼요. `/`와 `~`가 없는 plain model ID는 v1 접두사 `claude-ocx-…`를 유지해요. `/` 또는 `~`가 있는 model ID는 v2 diff --git a/docs-site/src/content/docs/ru/guides/claude-code.md b/docs-site/src/content/docs/ru/guides/claude-code.md index 60464bfb90..f5504c9dc2 100644 --- a/docs-site/src/content/docs/ru/guides/claude-code.md +++ b/docs-site/src/content/docs/ru/guides/claude-code.md @@ -176,8 +176,16 @@ user-agent `claude-code/*` получает читаемую CLI-форму, а продолжает работать. Если нижний селектор Claude Desktop не переключает модель в уже запущенном 3P-диалоге, -используйте `/model ` внутри этого диалога. OpenCodex не видит состояние селектора и -маршрутизирует id модели из каждого запроса. Результат можно проверить в **Logs → requestedModel**. +можно попробовать `/model `, но в затронутых сборках Desktop этот обходной способ тоже может +не сработать. В [issue #3782](https://github.com/lidge-jun/opencodex/issues/3782) сообщается, что +в Windows с Claude Desktop 1.46388.4 диалог продолжает использовать исходную модель после изменений +как через нижний селектор, так и через `/model`. Это сообщение не устанавливает, какой компонент +клиента или маршрутизации вызывает такое поведение. + +Можно также попробовать выбрать нужную модель по умолчанию в профиле Claude Desktop в OpenCodex, +повторно применить профиль и начать новый диалог. Это шаг по устранению неполадки, а не гарантированное +решение. OpenCodex не видит состояние селектора; он маршрутизирует id модели, переданный в каждом +запросе. Проверьте, что отправляет клиент, в **Logs → requestedModel**. **Правила грамматики алиасов:** provider не может содержать `/` или `--` и не может быть равен `native`. Обычные id моделей (без `/` и `~`) остаются с префиксом v1 `claude-ocx-…`. Id с `/` diff --git a/docs-site/src/content/docs/tr/guides/claude-code.md b/docs-site/src/content/docs/tr/guides/claude-code.md index 4be81a4de8..497f5e635b 100644 --- a/docs-site/src/content/docs/tr/guides/claude-code.md +++ b/docs-site/src/content/docs/tr/guides/claude-code.md @@ -332,9 +332,19 @@ takma adlar ve eski yapılandırmalardan gelen `claude-ocx---` kimlikleri hala çözümlenir. Claude Desktop'ın altbilgi seçicisi zaten çalışan bir 3P görüşmesi için modeli -değiştirmezse, o görüşmede `/model ` komutunu kullanın. OpenCodex seçici -durumunu gözlemleyemez; her isteğin taşıdığı model kimliğini yönlendirir. Sonucu -**Logs → requestedModel** altında onaylayın. +değiştirmezse, `/model ` komutunu deneyebilirsiniz; ancak bu geçici çözüm de +etkilenen Desktop derlemelerinde başarısız olabilir. +[Sorun #3782](https://github.com/lidge-jun/opencodex/issues/3782), Windows üzerinde +Claude Desktop 1.46388.4 ile hem altbilgi seçicisi hem de `/model` üzerinden yapılan +değişikliklerden sonra görüşmenin ilk modelini kullanmaya devam ettiğini bildiriyor. +Bu bildirim, davranışa hangi istemci veya yönlendirme bileşeninin neden olduğunu +ortaya koymuyor. + +OpenCodex Claude Desktop profilinde istediğiniz varsayılan modeli seçmeyi, profili +yeniden uygulamayı ve yeni bir görüşme başlatmayı da deneyebilirsiniz. Bu bir sorun +giderme adımıdır; kesin çözüm değildir. OpenCodex seçici durumunu gözlemleyemez; +her isteğin taşıdığı model kimliğini yönlendirir. İstemcinin ne gönderdiğini +**Logs → requestedModel** altında kontrol edin. Yetkili 1M bağlam penceresine sahip modeller fazladan bir `…[1m]` seçici satırı alır: bunu seçmek Claude Code'un bu model için tam 1M bağlam hesabı yapmasını diff --git a/docs-site/src/content/docs/zh-cn/guides/claude-code.md b/docs-site/src/content/docs/zh-cn/guides/claude-code.md index dd8bc740b8..216766f70c 100644 --- a/docs-site/src/content/docs/zh-cn/guides/claude-code.md +++ b/docs-site/src/content/docs/zh-cn/guides/claude-code.md @@ -157,9 +157,15 @@ opencodex 会将已路由模型公开为稳定且可逆的别名: user-agent 会获得易读的 CLI 形式,其他客户端会获得 Desktop 哈希形式。两种别名族都会永久 保持可解码——以任一形式保存在 `settings.json` 中的模型都能继续工作。 -如果 Claude Desktop 底部的选择器没有切换已运行 3P 对话的模型,请在该对话中使用 -`/model `。OpenCodex 无法读取选择器状态,只会路由每个请求实际携带的模型 ID;可在 -**Logs → requestedModel** 中确认结果。 +如果 Claude Desktop 底部的选择器没有切换正在进行的 3P 对话的模型,可以尝试 +`/model `,但在受影响的 Desktop 版本中,这种变通方法也可能失败。 +[Issue #3782](https://github.com/lidge-jun/opencodex/issues/3782) 报告称,在 Windows 上使用 +Claude Desktop 1.46388.4 时,无论通过底部选择器还是 `/model` 更改模型,对话都会继续使用 +最初的模型。该报告并未确定是哪个客户端组件或路由组件导致了这一行为。 + +也可以尝试在 OpenCodex 的 Claude Desktop 配置档案中选择所需的默认模型,重新应用配置档案, +然后开始新对话。这是一项排查步骤,不保证能解决问题。OpenCodex 无法读取选择器状态, +而是根据每个请求携带的模型 ID 进行路由。请在 **Logs → requestedModel** 中确认客户端实际发送的内容。 **别名语法规则:**provider 不得包含 `/` 或 `--`,也不得等于 `native`。 不含 `/` 或 `~` 的普通 model ID 继续使用 v1 前缀 `claude-ocx-…`。包含 `/` 或 `~` 的 model ID From 209c88b16fb13d495029d005855006eceb3d20b7 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 21:10:26 +0900 Subject: [PATCH 138/412] fix(models): isolate async price-read state callbacks [skip ci] Exact CI gates diagnosis: keep effect request setup synchronous and update state only from registered fetch settlement callbacks; retain cancellation and identity guards. Co-authored-by: nordz0r <6949669+nordz0r@users.noreply.github.com> --- gui/src/components/ModelPriceDialog.tsx | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/gui/src/components/ModelPriceDialog.tsx b/gui/src/components/ModelPriceDialog.tsx index f6e1a58200..59f385a841 100644 --- a/gui/src/components/ModelPriceDialog.tsx +++ b/gui/src/components/ModelPriceDialog.tsx @@ -58,12 +58,11 @@ export default function ModelPriceDialog({ model, apiBase, onRefresh, onClose }: const mutating = phase === "saving" || phase === "refreshing"; const locked = phase !== "ready"; - const readOverride = useCallback(async (recover = false) => { + const readOverride = useCallback((recover = false) => { if (requestRef.current) return; const bounded = createBoundedFetch(REQUEST_TIMEOUT_MS); requestRef.current = bounded; - try { - const response = await fetch(endpoint, { signal: bounded.signal, cache: "no-store" }); + void fetch(endpoint, { signal: bounded.signal, cache: "no-store" }).then(async response => { const result = await readJsonOrThrow(response); bounded.signal.throwIfAborted(); if (!isRecord(result) || result.provider !== model.provider || !isRecord(result.modelCosts)) { @@ -81,14 +80,14 @@ export default function ModelPriceDialog({ model, apiBase, onRefresh, onClose }: // request still running on the server or writes from another client. setRecovered(recover); setPhase("ready"); - } catch { + }).catch(() => { if (requestRef.current !== bounded) return; setPhase(recover ? "unknown" : "loadFailed"); setErrorKey(recover ? "pricing.override.recoveryFailed" : "pricing.override.loadFailed"); - } finally { + }).finally(() => { bounded.clear(); if (requestRef.current === bounded) requestRef.current = null; - } + }); }, [endpoint, model.id, model.provider]); useEffect(() => { From c4924740bd21add8357747da7f7c7f91baa119e1 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 18:54:08 +0900 Subject: [PATCH 139/412] feat(usage): add inclusive custom time windows [skip ci] Reimplement the range slice of #2956 with exact ledger filtering, bounded cache identity and localized datetime controls. Keep #3379 open for its other dashboard controls and hourly reporting scope; offline reports are not included. Co-authored-by: Manson2438 <183030642+Manson2438@users.noreply.github.com> --- .../_plan/260907_lane_d/050_usage_ranges.md | 19 ++ .../src/content/docs/reference/cli/agents.md | 9 +- .../content/docs/reference/management-api.md | 19 +- gui/src/i18n/de.ts | 10 + gui/src/i18n/en.ts | 10 + gui/src/i18n/fr.ts | 10 + gui/src/i18n/ja.ts | 10 + gui/src/i18n/ko.ts | 10 + gui/src/i18n/ru.ts | 10 + gui/src/i18n/tr.ts | 10 + gui/src/i18n/zh-TW.ts | 10 + gui/src/i18n/zh.ts | 10 + gui/src/pages/Usage.tsx | 114 +++++-- gui/src/usage-time-range.ts | 31 ++ gui/tests/usage-custom-range.test.tsx | 279 ++++++++++++++++++ gui/tests/usage-time-range.test.ts | 34 +++ scripts/test-layout/layout.json | 3 +- .../ocx/references/01_management_surface.md | 2 + src/cli/capabilities.ts | 2 + src/cli/observe.ts | 15 +- src/cli/usage-report.ts | 7 +- src/server/management/logs-usage-routes.ts | 14 +- .../management/usage-aggregate-cache.ts | 21 +- src/usage/summary.ts | 53 +++- src/usage/time-range.ts | 48 +++ structure/05_gui-and-management-api.md | 8 + tests/cli/cli-usage-report.test.ts | 58 ++++ tests/fixtures/test-layout-expected.json | 3 +- tests/server/api-usage.test.ts | 105 +++++++ tests/usage/usage-aggregate-cache.test.ts | 49 +++ tests/usage/usage-summary.test.ts | 96 ++++++ tests/usage/usage-time-range.test.ts | 36 +++ 32 files changed, 1072 insertions(+), 43 deletions(-) create mode 100644 gui/src/usage-time-range.ts create mode 100644 gui/tests/usage-custom-range.test.tsx create mode 100644 gui/tests/usage-time-range.test.ts create mode 100644 src/usage/time-range.ts create mode 100644 tests/usage/usage-time-range.test.ts diff --git a/devlog/_plan/260907_lane_d/050_usage_ranges.md b/devlog/_plan/260907_lane_d/050_usage_ranges.md index 35b6758a76..e08d758e5b 100644 --- a/devlog/_plan/260907_lane_d/050_usage_ranges.md +++ b/devlog/_plan/260907_lane_d/050_usage_ranges.md @@ -28,3 +28,22 @@ integer epoch milliseconds or full ISO-8601 with timezone only; require both bou reject negative/unsafe/date-invalid/reversed, never normalize overflow dates. MODIFY src/cli/usage-report.ts heading prints since/until for customWindow responses. GUI datetime values become epoch ms locally; end selected minute includes 59.999s. + +P revalidation: custom windows always filter rows before aggregation. Introduce exported +UsageTimeWindow {since:number,until:number} and immutable optional accumulator window; +snapshot timestamps update first, clone retains the window, summary returns customWindow:true +and exact since/until while actual generatedAt stays now. Partition/day filtering must not +drop the partial first day. Grid uses local calendar day boundaries and caps at 366 days. +getFilteredUsageAggregate accepts window, keys both bounds, passes window to factory and +reuses existing revision/timezone/overlay guards. Only-window queries preserve account rows. +GUI skips held/session report caching for custom windows (arbitrary keys must not grow the +preset cache); useDataSurface key still includes bounds and unsubscribed stores already evict. +Workers split backend/API/CLI/tests and GUI/i18n/tests; main owns docs/manifests/generated map. + +Implementation checkpoint: shared strict ISO/epoch-ms parser, immutable per-entry window, +window-keyed filtered cache, API and CLI inclusive bounds, exact interval heading, and +localized Usage date/time controls are implemented. Custom GUI reports bypass held caches; +calendar grid stays within the server's bounded days. Tests cover partial/inclusive bounds, +filters/accounts, cache invalidation, clone/snapshot behavior, empty/error responses and UI +apply/clear/stale-response paths. New parser test registered in both manifests. ISO fractions +beyond millisecond precision reject instead of truncating. Product execution NOT RUN locally. diff --git a/docs-site/src/content/docs/reference/cli/agents.md b/docs-site/src/content/docs/reference/cli/agents.md index 300bb7d5e2..4b95d1bcd2 100644 --- a/docs-site/src/content/docs/reference/cli/agents.md +++ b/docs-site/src/content/docs/reference/cli/agents.md @@ -111,14 +111,21 @@ Inspect proxy requests, usage, storage, memory, and debug data. The direct alias | Alias | Equivalent resource | | --- | --- | | `ocx logs [filters] [--follow] [--json|--jsonl]` | `ocx observe logs` | -| `ocx usage [--range ] [--surface ] [--provider ] [--model ] [--json]` | `ocx observe usage` | +| `ocx usage [--range ] [--since --until ] [--surface ] [--provider ] [--model ] [--json]` | `ocx observe usage` | | `ocx storage [--json]` | `ocx observe storage` | | `ocx memory [--json]` | `ocx observe memory` | ```bash ocx observe usage --range 30d --json +ocx usage --since 2026-09-01T09:00:00Z --until 2026-09-01T10:59:59.999Z --json ``` +`--since` and `--until` must be supplied together. They accept integer epoch milliseconds or +full ISO datetimes with an explicit timezone, include both endpoints, and override `--range`. +Invalid or reversed bounds fail before the request. Human output prints the requested interval; +`--json` includes `customWindow`, `since`, and `until`. Existing surface/provider/model filters +still apply. These commands query the running proxy; they do not provide offline reports. + `--range today` (alias `1d`) reports the current local day. `--provider` and `--model` narrow the report to one upstream target — distinct from `--surface`, which selects the calling client (Codex, Claude Code, Grok) diff --git a/docs-site/src/content/docs/reference/management-api.md b/docs-site/src/content/docs/reference/management-api.md index 0b3598eac8..238d23b336 100644 --- a/docs-site/src/content/docs/reference/management-api.md +++ b/docs-site/src/content/docs/reference/management-api.md @@ -182,7 +182,7 @@ by the current window size. | `GET /api/debug/usage-logs` | Read bounded usage-debug entries | — | | `GET /api/debug/injection-logs` | Read bounded guidance-injection debug entries | — | | `GET /api/claude/inbound-debug` | Read Claude inbound debug state and entries | — | -| `GET /api/usage` | Stream the complete usage ledger into compact aggregates, then incrementally fold verified appends; summarize by range and client surface, with a Codex `accounts` breakdown keyed by stable non-PII log labels | Returns an `error: "read_failed"` summary if storage cannot be read | +| `GET /api/usage` | Stream the complete usage ledger into compact aggregates, then incrementally fold verified appends; summarize by preset or inclusive custom window and client surface, with a Codex `accounts` breakdown keyed by stable non-PII log labels | 400 invalid custom bounds; returns an `error: "read_failed"` summary if storage cannot be read | | `GET /api/storage` | Scan Codex storage usage by bucket | Returns an `error: "scan_failed"` payload on scan failure | | `POST /api/storage/cleanup/preview` | Preview archived-session cleanup and return a binding digest | 400 `invalid_json` or `invalid_percent` | | `POST /api/storage/cleanup` | Quarantine or permanently remove the previewed archived set | 400 invalid input; 409 stale/busy/referenced state; 500 filesystem/database failure | @@ -210,6 +210,23 @@ an earlier file prefix from 7-day, 30-day, or all-history totals. `managementUsa accepted for compatibility with bounded legacy readers, but changing it no longer expands or reduces the history summarized by this endpoint. +Pass both `since` and `until` to select an inclusive custom interval. Each accepts integer Unix +epoch **milliseconds**, or a full ISO datetime with an explicit timezone. Invalid dates, negative +or out-of-range values, reversed bounds, and a single bound are rejected. Custom bounds override +`range`; the response keeps the preset `range` field for compatibility and adds `customWindow: true`, +the exact `since`, and `until`. `generatedAt` remains the time the report was produced. + +Custom windows filter individual ledger entries before daily aggregation, including partial first +and last days. They preserve `surface`, `provider`, `model`, and `apiKeyId` filtering and never reuse +or overwrite unfiltered preset summaries. The daily chart remains capped at 366 local calendar days; +totals cover the full requested interval. Snapshot-window fields describe the scanned ledger before +the time filter, so they can extend beyond the requested bounds. + +The Usage page accepts local date/time inputs. Its selected ending minute includes the entire +minute through `:59.999`. Choosing a preset or clearing the custom window restores preset behavior. +This adds exact range selection and existing cost estimates; it does not add hourly chart buckets +or offline reporting. + The runtime ledger is append-only. Replacing or truncating it, or changing local pricing/time-zone inputs, triggers a complete rebuild. If you manually edit an older row in place while the proxy is running, restart the proxy (or replace the file) before relying on the new total; incremental refreshes diff --git a/gui/src/i18n/de.ts b/gui/src/i18n/de.ts index a361962237..79d1591728 100644 --- a/gui/src/i18n/de.ts +++ b/gui/src/i18n/de.ts @@ -2615,4 +2615,14 @@ export const de: Record = { "pricing.override.refresh": "Liste aktualisieren", "pricing.override.cancel": "Abbrechen", "pricing.override.close": "Schließen", + "usage.range.custom": "Eigener Zeitraum", + "usage.range.start": "Beginn (Ortszeit)", + "usage.range.end": "Ende (Ortszeit)", + "usage.range.apply": "Anwenden", + "usage.range.clear": "Zurücksetzen", + "usage.range.help": "Ortszeit. Die gesamte Endminute ist enthalten.", + "usage.range.required": "Geben Sie Datum und Uhrzeit für Beginn und Ende ein.", + "usage.range.invalid": "Geben Sie gültige lokale Daten und Uhrzeiten ab 1970-01-01 UTC ein.", + "usage.range.reversed": "Das Ende muss auf oder nach dem Beginn liegen.", + "usage.range.applied": "Ausgewählter Zeitraum: {start} – {end} (beide Grenzen eingeschlossen).", }; diff --git a/gui/src/i18n/en.ts b/gui/src/i18n/en.ts index ff45937f47..cceef53d12 100644 --- a/gui/src/i18n/en.ts +++ b/gui/src/i18n/en.ts @@ -2649,6 +2649,16 @@ export const en = { "pricing.override.refresh": "Refresh list", "pricing.override.cancel": "Cancel", "pricing.override.close": "Close", + "usage.range.custom": "Custom date range", + "usage.range.start": "Start (local time)", + "usage.range.end": "End (local time)", + "usage.range.apply": "Apply", + "usage.range.clear": "Clear", + "usage.range.help": "Local time. Includes the entire end minute.", + "usage.range.required": "Enter both a start and an end date and time.", + "usage.range.invalid": "Enter valid local dates and times, on or after 1970-01-01 UTC.", + "usage.range.reversed": "The end must be at or after the start.", + "usage.range.applied": "Selected interval: {start} – {end} (both inclusive).", } as const; export type TKey = keyof typeof en; diff --git a/gui/src/i18n/fr.ts b/gui/src/i18n/fr.ts index eafe430758..67b2586fe4 100644 --- a/gui/src/i18n/fr.ts +++ b/gui/src/i18n/fr.ts @@ -2602,4 +2602,14 @@ export const fr: Record = { "pricing.override.refresh": "Actualiser la liste", "pricing.override.cancel": "Annuler", "pricing.override.close": "Fermer", + "usage.range.custom": "Période personnalisée", + "usage.range.start": "Début (heure locale)", + "usage.range.end": "Fin (heure locale)", + "usage.range.apply": "Appliquer", + "usage.range.clear": "Effacer", + "usage.range.help": "Heure locale. La dernière minute est entièrement incluse.", + "usage.range.required": "Saisissez la date et l’heure de début et de fin.", + "usage.range.invalid": "Saisissez des dates et heures locales valides à partir du 1970-01-01 UTC.", + "usage.range.reversed": "La fin doit être égale ou postérieure au début.", + "usage.range.applied": "Période sélectionnée : {start} – {end} (bornes incluses).", }; diff --git a/gui/src/i18n/ja.ts b/gui/src/i18n/ja.ts index 6fe289e48c..92bb516827 100644 --- a/gui/src/i18n/ja.ts +++ b/gui/src/i18n/ja.ts @@ -2636,4 +2636,14 @@ export const ja: Record = { "pricing.override.refresh": "一覧を更新", "pricing.override.cancel": "キャンセル", "pricing.override.close": "閉じる", + "usage.range.custom": "期間を指定", + "usage.range.start": "開始(現地時間)", + "usage.range.end": "終了(現地時間)", + "usage.range.apply": "適用", + "usage.range.clear": "解除", + "usage.range.help": "現地時間です。終了時刻の分全体を含みます。", + "usage.range.required": "開始と終了の日時を両方入力してください。", + "usage.range.invalid": "1970-01-01 UTC以降の有効な現地日時を入力してください。", + "usage.range.reversed": "終了日時は開始日時と同じか、それ以降にしてください。", + "usage.range.applied": "選択した期間:{start} – {end}(両端を含む)。", }; diff --git a/gui/src/i18n/ko.ts b/gui/src/i18n/ko.ts index 20160b7ffe..7f02d3792f 100644 --- a/gui/src/i18n/ko.ts +++ b/gui/src/i18n/ko.ts @@ -2637,4 +2637,14 @@ export const ko: Record = { "pricing.override.refresh": "목록 갱신", "pricing.override.cancel": "취소", "pricing.override.close": "닫기", + "usage.range.custom": "기간 직접 지정", + "usage.range.start": "시작 (현지 시간)", + "usage.range.end": "종료 (현지 시간)", + "usage.range.apply": "적용", + "usage.range.clear": "해제", + "usage.range.help": "현지 시간 기준이며, 종료 시각의 마지막 분 전체를 포함합니다.", + "usage.range.required": "시작과 종료 날짜 및 시간을 모두 입력하세요.", + "usage.range.invalid": "1970-01-01 UTC 이후의 유효한 현지 날짜와 시간을 입력하세요.", + "usage.range.reversed": "종료 시각은 시작 시각과 같거나 이후여야 합니다.", + "usage.range.applied": "선택한 기간: {start} – {end} (양 끝 시각 포함).", }; diff --git a/gui/src/i18n/ru.ts b/gui/src/i18n/ru.ts index b433aa4381..9548be7d64 100644 --- a/gui/src/i18n/ru.ts +++ b/gui/src/i18n/ru.ts @@ -2638,4 +2638,14 @@ export const ru: Record = { "pricing.override.refresh": "Обновить список", "pricing.override.cancel": "Отмена", "pricing.override.close": "Закрыть", + "usage.range.custom": "Произвольный период", + "usage.range.start": "Начало (местное время)", + "usage.range.end": "Конец (местное время)", + "usage.range.apply": "Применить", + "usage.range.clear": "Сбросить", + "usage.range.help": "Местное время. Последняя минута включена целиком.", + "usage.range.required": "Введите дату и время начала и конца.", + "usage.range.invalid": "Введите допустимые местные дату и время не ранее 1970-01-01 UTC.", + "usage.range.reversed": "Конец не может быть раньше начала.", + "usage.range.applied": "Выбранный период: {start} – {end} (обе границы включены).", }; diff --git a/gui/src/i18n/tr.ts b/gui/src/i18n/tr.ts index b86b867b22..7b835eb03e 100644 --- a/gui/src/i18n/tr.ts +++ b/gui/src/i18n/tr.ts @@ -2638,4 +2638,14 @@ export const tr: Record = { "pricing.override.refresh": "Listeyi yenile", "pricing.override.cancel": "İptal", "pricing.override.close": "Kapat", + "usage.range.custom": "Özel tarih aralığı", + "usage.range.start": "Başlangıç (yerel saat)", + "usage.range.end": "Bitiş (yerel saat)", + "usage.range.apply": "Uygula", + "usage.range.clear": "Temizle", + "usage.range.help": "Yerel saat. Bitiş dakikasının tamamı dahildir.", + "usage.range.required": "Başlangıç ve bitiş için tarih ve saat girin.", + "usage.range.invalid": "1970-01-01 UTC veya sonrasına ait geçerli yerel tarih ve saat girin.", + "usage.range.reversed": "Bitiş, başlangıçla aynı veya daha sonra olmalıdır.", + "usage.range.applied": "Seçilen aralık: {start} – {end} (iki sınır da dahil).", }; diff --git a/gui/src/i18n/zh-TW.ts b/gui/src/i18n/zh-TW.ts index 856c4c869c..cd0b7e17d3 100644 --- a/gui/src/i18n/zh-TW.ts +++ b/gui/src/i18n/zh-TW.ts @@ -2600,4 +2600,14 @@ export const zhTW: Record = { "pricing.override.refresh": "重新整理清單", "pricing.override.cancel": "取消", "pricing.override.close": "關閉", + "usage.range.custom": "自訂時間範圍", + "usage.range.start": "開始(本地時間)", + "usage.range.end": "結束(本地時間)", + "usage.range.apply": "套用", + "usage.range.clear": "清除", + "usage.range.help": "使用本地時間,包含結束時刻的整分鐘。", + "usage.range.required": "請輸入開始和結束的日期及時間。", + "usage.range.invalid": "請輸入不早於 1970-01-01 UTC 的有效本地日期和時間。", + "usage.range.reversed": "結束時間必須等於或晚於開始時間。", + "usage.range.applied": "所選範圍:{start} – {end}(包含兩端)。", }; diff --git a/gui/src/i18n/zh.ts b/gui/src/i18n/zh.ts index 4e1fda0c2a..d9f93f20c7 100644 --- a/gui/src/i18n/zh.ts +++ b/gui/src/i18n/zh.ts @@ -2636,4 +2636,14 @@ export const zh: Record = { "pricing.override.refresh": "刷新列表", "pricing.override.cancel": "取消", "pricing.override.close": "关闭", + "usage.range.custom": "自定义时间范围", + "usage.range.start": "开始(本地时间)", + "usage.range.end": "结束(本地时间)", + "usage.range.apply": "应用", + "usage.range.clear": "清除", + "usage.range.help": "使用本地时间,包含结束时刻的整分钟。", + "usage.range.required": "请输入开始和结束的日期及时间。", + "usage.range.invalid": "请输入不早于 1970-01-01 UTC 的有效本地日期和时间。", + "usage.range.reversed": "结束时间必须等于或晚于开始时间。", + "usage.range.applied": "所选范围:{start} – {end}(包含两端)。", }; diff --git a/gui/src/pages/Usage.tsx b/gui/src/pages/Usage.tsx index bd7537073b..44ecce0c98 100644 --- a/gui/src/pages/Usage.tsx +++ b/gui/src/pages/Usage.tsx @@ -10,6 +10,7 @@ import { useDataSurface } from "../data-surface"; import { DataSurfaceSkeleton } from "../components/data-surface"; import { SectionTabs } from "../components/section-tabs"; import { sectionAnchorId } from "../section-anchors"; +import { parseUsageTimeRange, type UsageRangeError, type UsageTimeWindow } from "../usage-time-range"; type Range = "all" | "30d" | "7d"; type UsageSurface = "all" | "codex" | "claude" | "grok"; @@ -79,6 +80,8 @@ interface UsageResponse { range: Range; surface: UsageSurface; since: number | null; + until?: number; + customWindow?: boolean; generatedAt: number; summary: UsageSummaryTotals; days: UsageDay[]; @@ -156,16 +159,18 @@ interface HeatmapCell { dayOfWeek: number; } -function buildHeatmap(days: UsageDay[]): { weeks: HeatmapCell[][]; months: { label: string; col: number }[]; buckets: number[] } { +function buildHeatmap(days: UsageDay[], customWindow = false): { weeks: HeatmapCell[][]; months: { label: string; col: number }[]; buckets: number[] } { const buckets = quantileBuckets(days.map(d => d.totalTokens)); + if (customWindow && days.length === 0) return { weeks: [], months: [], buckets }; const dayMap = new Map(days.map(d => [d.date, d])); - const today = new Date(); + const today = customWindow ? new Date(`${days[days.length - 1].date}T00:00:00`) : new Date(); today.setHours(0, 0, 0, 0); - const start = new Date(today); - start.setDate(start.getDate() - 364); - // Align to Sunday - start.setDate(start.getDate() - start.getDay()); + const start = customWindow ? new Date(`${days[0].date}T00:00:00`) : new Date(today); + if (!customWindow) { + start.setDate(start.getDate() - 364); + start.setDate(start.getDate() - start.getDay()); + } const weeks: HeatmapCell[][] = []; const months: { label: string; col: number }[] = []; @@ -173,6 +178,12 @@ function buildHeatmap(days: UsageDay[]): { weeks: HeatmapCell[][]; months: { lab let lastMonthCol = -4; let prevMonthIdx = -1; let week: HeatmapCell[] = []; + // Align a custom grid without inventing report dates outside the server's bounded days. + if (customWindow) { + while (week.length < start.getDay()) { + week.push({ date: "", requests: 0, totalTokens: 0, level: 0, dayOfWeek: week.length }); + } + } const cursor = new Date(start); while (cursor <= today) { @@ -214,7 +225,7 @@ function UsageFilters({ t, }: { surface: UsageSurface; - range: Range; + range: Range | null; onSurface: (surface: UsageSurface) => void; onRange: (range: Range) => void; t: TFn; @@ -378,7 +389,7 @@ function UsageHeatmapPanel({ locale, t, }: { - range: Range; + range: Range | null; heatmap: ReturnType; weekBars: UsageDay[]; locale: Locale; @@ -671,7 +682,7 @@ function UsageWorkspaceBody({ modelQuery: string; onModelQuery: (query: string) => void; sortedProviders: UsageProvider[]; - range: Range; + range: Range | null; locale: Locale; t: TFn; }) { @@ -762,31 +773,52 @@ export default function Usage({ apiBase, connected = false, apiKeyId }: { apiBas const [surface, setSurface] = useState("all"); const [scope, setScope] = useState("machine"); const [modelQuery, setModelQuery] = useState(""); + const [draftWindow, setDraftWindow] = useState({ since: "", until: "" }); + const [customWindow, setCustomWindow] = useState(null); + const [rangeError, setRangeError] = useState(null); + const since = customWindow?.since; + const until = customWindow?.until; + + const clearCustomWindow = () => { + setCustomWindow(null); + setDraftWindow({ since: "", until: "" }); + setRangeError(null); + }; + const selectRange = (next: Range) => { + setRange(next); + clearCustomWindow(); + }; const loadUsage = useCallback(async (signal: AbortSignal): Promise => { const query = new URLSearchParams({ range, surface }); if (connected && scope === "machine" && apiKeyId) query.set("apiKeyId", apiKeyId); + if (since !== undefined && until !== undefined) { + query.set("since", String(since)); + query.set("until", String(until)); + } const response = await fetch(`${apiBase}/api/usage?${query}`, { signal }); if (!response.ok) throw new Error(`${response.status} ${response.statusText}`.trim()); const next = await response.json() as UsageResponse; - writeHeldUsage(apiBase, range, surface, connected, scope, apiKeyId, next); + if (since === undefined) writeHeldUsage(apiBase, range, surface, connected, scope, apiKeyId, next); return next; - }, [apiBase, apiKeyId, connected, range, scope, surface]); + }, [apiBase, apiKeyId, connected, range, scope, surface, since, until]); - const resourceKey = usageCacheKey(apiBase, range, surface, connected, scope, apiKeyId); - const cached = readHeldUsage(apiBase, range, surface, connected, scope, apiKeyId); + const presetKey = usageCacheKey(apiBase, range, surface, connected, scope, apiKeyId); + const resourceKey = customWindow ? `${presetKey}:custom:${since}:${until}` : presetKey; + // Arbitrary custom windows belong only to the subscription-scoped resource store. + const cached = customWindow ? null : readHeldUsage(apiBase, range, surface, connected, scope, apiKeyId); // Range and surface identify different reports, so the key changes with both. That prevents // a force-loading dependency revalidation from ever showing a previous report as this one. const resource = useDataSurface( resourceKey, - [apiBase, apiKeyId, connected, range, scope, surface], + [apiBase, apiKeyId, connected, range, scope, surface, since, until], loadUsage, { isEmpty: () => false, initialData: cached ?? undefined }, ); const { state } = resource; const data = state.data ?? cached ?? null; - const heatmap = useMemo(() => buildHeatmap(data?.days ?? []), [data?.days]); + const heatmap = useMemo(() => buildHeatmap(data?.days ?? [], !!customWindow), [data?.days, customWindow]); const weekBars = useMemo(() => lastSevenDays(data?.days ?? []), [data?.days]); const activeDays = useMemo(() => (data?.days ?? []).filter(d => d.requests > 0).length, [data?.days]); const filteredModels = useMemo(() => { @@ -810,9 +842,57 @@ export default function Usage({ apiBase, connected = false, apiKeyId }: { apiBas <>

{t("usage.title")}

- +

{t("usage.subtitle")}

+
{ + event.preventDefault(); + const result = parseUsageTimeRange(draftWindow.since, draftWindow.until); + if (result.ok === false) { + setRangeError(result.error); + return; + } + setRangeError(null); + setCustomWindow(result.window); + }}> +
+ + + + +
+

{t("usage.range.help")}

+ {rangeError && } + {customWindow &&

{(() => { + const formatter = new Intl.DateTimeFormat(locale, { + year: "numeric", month: "short", day: "numeric", hour: "2-digit", minute: "2-digit", + second: "2-digit", fractionalSecondDigits: 3, timeZoneName: "short", + }); + return t("usage.range.applied", { start: formatter.format(customWindow.since), end: formatter.format(customWindow.until) }); + })()}

} +
{/* Only shown when connected. Naming the source is a two-plane concept: it answers "which store served these numbers", and that question only exists once there are @@ -869,7 +949,7 @@ export default function Usage({ apiBase, connected = false, apiKeyId }: { apiBas modelQuery={modelQuery} onModelQuery={setModelQuery} sortedProviders={sortedProviders} - range={range} + range={customWindow ? null : range} locale={locale} t={t} /> diff --git a/gui/src/usage-time-range.ts b/gui/src/usage-time-range.ts new file mode 100644 index 0000000000..eebc445ad2 --- /dev/null +++ b/gui/src/usage-time-range.ts @@ -0,0 +1,31 @@ +export interface UsageTimeWindow { + since: number; + until: number; +} + +export type UsageRangeError = "required" | "invalid" | "reversed"; + +function localMinute(value: string): number | null { + const parts = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})$/.exec(value); + if (!parts) return null; + const [year, month, day, hour, minute] = parts.slice(1).map(Number); + const date = new Date(`${value}:00`); + const timestamp = date.getTime(); + // Reject calendar overflow and nonexistent local times (including DST gaps). + if (!Number.isSafeInteger(timestamp) || timestamp < 0 + || date.getFullYear() !== year || date.getMonth() !== month - 1 + || date.getDate() !== day || date.getHours() !== hour || date.getMinutes() !== minute) return null; + return timestamp; +} + +export function parseUsageTimeRange(start: string, end: string): + | { ok: true; window: UsageTimeWindow } + | { ok: false; error: UsageRangeError } { + if (!start || !end) return { ok: false, error: "required" }; + const since = localMinute(start); + const endMinute = localMinute(end); + if (since === null || endMinute === null) return { ok: false, error: "invalid" }; + if (since > endMinute) return { ok: false, error: "reversed" }; + // Both bounds are inclusive: the selected end minute includes its final millisecond. + return { ok: true, window: { since, until: endMinute + 59_999 } }; +} diff --git a/gui/tests/usage-custom-range.test.tsx b/gui/tests/usage-custom-range.test.tsx new file mode 100644 index 0000000000..c06b27eb33 --- /dev/null +++ b/gui/tests/usage-custom-range.test.tsx @@ -0,0 +1,279 @@ +import { afterEach, beforeEach, expect, test } from "bun:test"; +import { Window } from "happy-dom"; +import { act } from "react"; +import type { Root } from "react-dom/client"; +import { LanguageProvider } from "../src/i18n/provider"; +import { clearClientResourceStoresForTests } from "../src/client-resource"; +import Usage from "../src/pages/Usage"; + +const globals = ["document", "window", "navigator", "localStorage", "sessionStorage", "ResizeObserver", "IS_REACT_ACT_ENVIRONMENT"] as const; +const originalFetch = globalThis.fetch; +let previousGlobals: Record<(typeof globals)[number], unknown>; +let testWindow: Window; +let root: Root | undefined; +let container: HTMLElement; +let apiBase: string; +let sequence = 0; +type RequestGate = { url: string; resolve: (response: Response) => void }; +let requests: RequestGate[]; + +beforeEach(() => { + previousGlobals = Object.fromEntries(globals.map(key => [key, Reflect.get(globalThis, key)])) as typeof previousGlobals; + clearClientResourceStoresForTests(); + testWindow = new Window({ url: "http://localhost/" }); + testWindow.localStorage.setItem("ocx-lang", "en"); + Object.defineProperties(globalThis, { + document: { configurable: true, value: testWindow.document }, + window: { configurable: true, value: testWindow }, + navigator: { configurable: true, value: testWindow.navigator }, + localStorage: { configurable: true, value: testWindow.localStorage }, + sessionStorage: { configurable: true, value: testWindow.sessionStorage }, + ResizeObserver: { configurable: true, value: testWindow.ResizeObserver }, + IS_REACT_ACT_ENVIRONMENT: { configurable: true, value: true }, + }); + // The page also has a held memory cache: each test gets a distinct report identity. + apiBase = `http://usage-custom-${++sequence}`; + requests = []; + globalThis.fetch = ((input: RequestInfo | URL) => new Promise(resolve => { + requests.push({ url: String(input), resolve }); + })) as typeof fetch; +}); + +afterEach(async () => { + if (root) await act(async () => { root!.unmount(); }); + root = undefined; + globalThis.fetch = originalFetch; + clearClientResourceStoresForTests(); + testWindow.close(); + for (const key of globals) Object.defineProperty(globalThis, key, { configurable: true, value: previousGlobals[key] }); +}); + +async function mount(connected = false) { + const previousRequests = requests.length; + container = document.createElement("div"); + document.body.append(container); + const { createRoot } = await import("react-dom/client"); + await act(async () => { + root = createRoot(container); + root.render(); + }); + expect(requests).toHaveLength(previousRequests + 1); +} + +function report(gate: RequestGate, marker: string, date = "2020-09-15") { + const query = new URL(gate.url).searchParams; + const custom = query.has("since"); + return { + range: query.get("range"), surface: query.get("surface"), + since: custom ? Number(query.get("since")) : null, + ...(custom ? { customWindow: true, until: Number(query.get("until")) } : {}), + generatedAt: Date.now(), + summary: { + requests: 1, measuredRequests: 1, reportedRequests: 1, unreportedRequests: 0, + unsupportedRequests: 0, estimatedRequests: 0, inputTokens: 10, outputTokens: 20, + cachedInputTokens: 0, reasoningOutputTokens: 0, totalTokens: 30, coverageRatio: 1, + }, + days: [{ date, requests: 1, measuredRequests: 1, reportedRequests: 1, totalTokens: 30, models: [] }], + models: [{ model: marker, provider: "openai", requests: 1, measuredRequests: 1, reportedRequests: 1, + estimatedRequests: 0, totalTokens: 30, inputTokens: 10, outputTokens: 20, shareRatio: 1 }], + providers: [], historyTruncated: false, truncatedPrefixBytes: 0, entriesTruncated: false, entriesDropped: 0, + }; +} + +async function respond(index: number, marker: string, date?: string) { + await act(async () => { requests[index].resolve(Response.json(report(requests[index], marker, date))); }); +} + +const form = () => container.querySelector('form[aria-label="Custom date range"]')!; +const startInput = () => form().querySelectorAll('input[type="datetime-local"]')[0]; +const endInput = () => form().querySelectorAll('input[type="datetime-local"]')[1]; +const interval = () => form().querySelector('[role="status"]')?.textContent; +const error = () => form().querySelector('[role="alert"]')?.textContent; +const preset = (name: string) => container.querySelector(`button.usage-segmented-btn[aria-label="${name}"]`)!; + +async function click(button: HTMLButtonElement) { + expect(button).toBeTruthy(); + await act(async () => { button.click(); }); +} + +async function enter(start: string, end: string) { + await act(async () => { + for (const [input, value] of [[startInput(), start], [endInput(), end]] as const) { + Object.getOwnPropertyDescriptor(testWindow.HTMLInputElement.prototype, "value")!.set!.call(input, value); + input.dispatchEvent(new testWindow.Event("input", { bubbles: true })); + input.dispatchEvent(new testWindow.Event("change", { bubbles: true })); + } + }); +} + +const apply = () => click(form().querySelector('button[type="submit"]')!); +const clear = () => click(form().querySelector('button[type="button"]')!); +const since = new Date(2020, 8, 15, 10, 20, 0, 0).getTime(); +const until = new Date(2020, 8, 15, 10, 21, 59, 999).getTime(); +const boundsQuery = `since=${since}&until=${until}`; + +function sessionEntries() { + return Array.from({ length: sessionStorage.length }, (_, index) => { + const key = sessionStorage.key(index)!; + return [key, sessionStorage.getItem(key)]; + }); +} + +test("Apply submits inclusive bounds once; Clear restores the held preset without custom cache entries", async () => { + await mount(); + expect(requests[0].url).toBe(`${apiBase}/api/usage?range=30d&surface=all`); + await respond(0, "preset-report-marker"); + const held = sessionEntries(); + expect(held).toHaveLength(1); + await enter("2020-09-15T10:20", "2020-09-15T10:21"); + expect(requests).toHaveLength(1); + expect(container.textContent).toContain("preset-report-marker"); + await apply(); + expect(requests).toHaveLength(2); + expect(requests[1].url).toBe(`${apiBase}/api/usage?range=30d&surface=all&${boundsQuery}`); + for (const name of ["Available history", "30d", "7d"]) expect(preset(name).getAttribute("aria-pressed")).toBe("false"); + expect(container.textContent).not.toContain("preset-report-marker"); + expect(container.textContent).toContain("Loading usage data"); + expect(interval()).toContain("both inclusive"); + expect(interval()).toContain(".999"); + const appliedInterval = interval(); + await respond(1, "custom-report-marker"); + expect(container.textContent).toContain("custom-report-marker"); + expect(sessionEntries()).toEqual(held); + // Resource eviction is scheduled on a zero-delay timer. Drain that turn before Clear + // so this explicitly covers restoring a held preset after its resource store was evicted. + await act(async () => { await new Promise(resolve => setTimeout(resolve, 0)); }); + // A one-day historical window must not produce a year grid anchored to today's date. + expect(container.querySelectorAll(".heatmap-grid .heatmap-cell")).toHaveLength(7); + const activeCell = container.querySelector(".heatmap-grid .heatmap-cell-1")!; + await act(async () => { activeCell.dispatchEvent(new testWindow.MouseEvent("mouseover", { bubbles: true })); }); + expect(container.querySelector('[role="tooltip"]')?.textContent).toContain("2020-09-15"); + await enter("2020-09-16T10:20", "2020-09-16T10:21"); + expect(interval()).toBe(appliedInterval); + expect(requests).toHaveLength(2); + await clear(); + expect(startInput().value).toBe(""); + expect(endInput().value).toBe(""); + expect(interval()).toBeUndefined(); + expect(preset("30d").getAttribute("aria-pressed")).toBe("true"); + expect(container.textContent).toContain("preset-report-marker"); + expect(container.textContent).not.toContain("custom-report-marker"); + expect(requests.at(-1)!.url).toBe(`${apiBase}/api/usage?range=30d&surface=all`); + await act(async () => { root!.unmount(); }); + root = undefined; + container.remove(); + clearClientResourceStoresForTests(); + await mount(); + expect(container.textContent).toContain("preset-report-marker"); + await enter("2020-09-15T10:20", "2020-09-15T10:21"); + await apply(); + // Reopening that exact custom window must not resurrect a module/session-held report. + expect(container.textContent).not.toContain("custom-report-marker"); + expect(container.textContent).not.toContain("preset-report-marker"); + expect(container.textContent).toContain("Loading usage data"); + expect(requests.at(-1)!.url).toBe(`${apiBase}/api/usage?range=30d&surface=all&${boundsQuery}`); +}); + +test("missing, partial, invalid and reversed drafts make no request or applied-state change", async () => { + await mount(); + await respond(0, "held-valid-report"); + for (const [start, end, expected] of [ + ["", "", "Enter both"], + ["2020-09-15T10:20", "", "Enter both"], + ["", "2020-09-15T10:20", "Enter both"], + ["1969-01-01T12:00", "2020-09-15T10:20", "Enter valid"], + ["2020-09-16T10:20", "2020-09-15T10:20", "The end must"], + ]) { + await enter(start, end); + await apply(); + expect(error()).toContain(expected); + expect(startInput().getAttribute("aria-invalid")).toBe("true"); + expect(requests).toHaveLength(1); + expect(container.textContent).toContain("held-valid-report"); + expect(interval()).toBeUndefined(); + } + await enter("2020-09-15T10:20", "2020-09-15T10:21"); + await apply(); + await respond(1, "applied-valid-report"); + const previousInterval = interval(); + await enter("2020-09-16T10:20", "2020-09-15T10:20"); + await apply(); + expect(requests).toHaveLength(2); + expect(interval()).toBe(previousInterval); + expect(container.textContent).toContain("applied-valid-report"); + await clear(); + expect(error()).toBeUndefined(); +}); + +test("new bounds never show a held report or a superseded request that settles late", async () => { + await mount(); + await respond(0, "preset-stale-marker"); + await enter("2020-09-15T10:20", "2020-09-15T10:21"); + await apply(); + await respond(1, "first-custom-marker"); + // Change only until, then only since: each bound independently owns a new request. + await enter("2020-09-15T10:20", "2020-09-15T10:22"); + await apply(); + expect(requests[2].url).toBe(`${apiBase}/api/usage?range=30d&surface=all&since=${since}&until=${until + 60_000}`); + expect(container.textContent).not.toContain("first-custom-marker"); + await enter("2020-09-15T10:21", "2020-09-15T10:22"); + await apply(); + expect(requests[3].url).toBe(`${apiBase}/api/usage?range=30d&surface=all&since=${since + 60_000}&until=${until + 60_000}`); + await respond(2, "late-superseded-marker"); + expect(container.textContent).not.toContain("late-superseded-marker"); + expect(container.textContent).not.toContain("preset-stale-marker"); + expect(container.textContent).toContain("Loading usage data"); + await respond(3, "latest-custom-marker"); + expect(container.textContent).toContain("latest-custom-marker"); + expect(sessionEntries()).toHaveLength(1); +}); + +test("Apply preserves machine key, surface and hub scope; choosing a preset clears custom", async () => { + await mount(true); + await respond(0, "machine-report"); + await click(preset("Grok")); + await respond(1, "machine-grok-report"); + await enter("2020-09-15T10:20", "2020-09-15T10:21"); + await apply(); + expect(requests[2].url).toBe(`${apiBase}/api/usage?range=30d&surface=grok&apiKeyId=machine%2Fkey+%2B+one&${boundsQuery}`); + await respond(2, "machine-custom-report"); + const hub = [...container.querySelectorAll(".usage-scope-control button")].find(button => button.textContent === "Hub-wide")!; + await click(hub); + expect(requests[3].url).toBe(`${apiBase}/api/usage?range=30d&surface=grok&${boundsQuery}`); + await respond(3, "hub-custom-report"); + await enter("2020-09-15T10:20", "2020-09-15T10:22"); + await apply(); + expect(requests[4].url).toBe(`${apiBase}/api/usage?range=30d&surface=grok&since=${since}&until=${until + 60_000}`); + await respond(4, "hub-new-custom-report"); + await click(preset("7d")); + expect(requests.at(-1)!.url).toBe(`${apiBase}/api/usage?range=7d&surface=grok`); + expect(interval()).toBeUndefined(); + expect(startInput().value).toBe(""); + expect(endInput().value).toBe(""); + expect(preset("7d").getAttribute("aria-pressed")).toBe("true"); + expect(hub.getAttribute("aria-pressed")).toBe("true"); +}); + +test("each preset clears custom, including the retained preset; 7d never replaces custom days with this week", async () => { + await mount(); + await respond(0, "preset-marker"); + for (const [index, name] of ["30d", "Available history", "7d"].entries()) { + await enter("2020-09-15T10:20", `2020-09-15T10:${21 + index}`); + const previousRequests = requests.length; + await apply(); + expect(requests).toHaveLength(previousRequests + 1); + await respond(requests.length - 1, "custom-marker"); + await click(preset(name)); + expect(preset(name).getAttribute("aria-pressed")).toBe("true"); + expect(interval()).toBeUndefined(); + expect(startInput().value).toBe(""); + expect(endInput().value).toBe(""); + } + await enter("2020-09-15T10:20", "2020-09-15T10:21"); + await apply(); + expect(requests.at(-1)!.url).toBe(`${apiBase}/api/usage?range=7d&surface=all&${boundsQuery}`); + await respond(requests.length - 1, "custom-from-7d-marker"); + expect(container.querySelector(".daybars")).toBeNull(); + expect(container.querySelectorAll(".heatmap-grid .heatmap-cell")).toHaveLength(7); + expect(preset("7d").getAttribute("aria-pressed")).toBe("false"); +}); diff --git a/gui/tests/usage-time-range.test.ts b/gui/tests/usage-time-range.test.ts new file mode 100644 index 0000000000..8ef289ef31 --- /dev/null +++ b/gui/tests/usage-time-range.test.ts @@ -0,0 +1,34 @@ +import { expect, test } from "bun:test"; +import { parseUsageTimeRange } from "../src/usage-time-range"; + +test("local minutes become inclusive epoch-ms bounds, including a single minute", () => { + expect(parseUsageTimeRange("2024-02-29T12:34", "2024-02-29T12:34")).toEqual({ + ok: true, + window: { + since: new Date(2024, 1, 29, 12, 34, 0, 0).getTime(), + until: new Date(2024, 1, 29, 12, 34, 59, 999).getTime(), + }, + }); +}); + +test("both local datetime bounds are required", () => { + for (const [start, end] of [["", ""], ["2024-02-29T12:34", ""], ["", "2024-02-29T12:34"]]) { + expect(parseUsageTimeRange(start, end)).toEqual({ ok: false, error: "required" }); + } +}); + +test("malformed, overflowing and negative dates are rejected rather than normalized", () => { + for (const invalid of [ + "not-a-date", "2023-02-29T12:34", "2024-02-30T12:34", "2024-13-01T12:34", + "2024-02-29T24:00", "2024-02-29T12:60", "1969-01-01T12:00", + "2024-02-29", "2024-02-29T12:34Z", "2024-02-29T12:34:30", "2024-02-29T12:34+09:00", + ]) { + expect(parseUsageTimeRange(invalid, "2024-03-01T12:34")).toEqual({ ok: false, error: "invalid" }); + expect(parseUsageTimeRange("2024-02-01T12:34", invalid)).toEqual({ ok: false, error: "invalid" }); + } +}); + +test("reversed dates are rejected before extending the end minute", () => { + expect(parseUsageTimeRange("2024-03-01T12:35", "2024-03-01T12:34")) + .toEqual({ ok: false, error: "reversed" }); +}); diff --git a/scripts/test-layout/layout.json b/scripts/test-layout/layout.json index ffb001a82d..d46f547867 100644 --- a/scripts/test-layout/layout.json +++ b/scripts/test-layout/layout.json @@ -1300,7 +1300,8 @@ "zz-ci-storage-policy-isolation.test.ts": "ci-workflows", "zz-pr-coderabbit-readiness-revalidation.test.ts": "ci-workflows", "cli-models-price.test.ts": "cli", - "model-costs-management-api.test.ts": "server" + "model-costs-management-api.test.ts": "server", + "usage-time-range.test.ts": "usage" }, "migrated": [ "adapters", diff --git a/skills/ocx/references/01_management_surface.md b/skills/ocx/references/01_management_surface.md index 485ed745ba..512aa3a7e2 100644 --- a/skills/ocx/references/01_management_surface.md +++ b/skills/ocx/references/01_management_surface.md @@ -132,6 +132,8 @@ Token and estimated-cost report over a time range. | Flag | Value | Meaning | |---|---|---| | `--range` | string | today | 1d | 7d | 30d | all | +| `--since` | string | Inclusive start: epoch milliseconds or full ISO datetime with timezone; requires --until and overrides --range. | +| `--until` | string | Inclusive end: epoch milliseconds or full ISO datetime with timezone; requires --since. | | `--provider` | string | Restrict to one provider. | | `--model` | string | Restrict to one model id. | | `--json` | boolean | Emit the usage report as JSON. | diff --git a/src/cli/capabilities.ts b/src/cli/capabilities.ts index e34b8ec79b..86aa5438df 100644 --- a/src/cli/capabilities.ts +++ b/src/cli/capabilities.ts @@ -225,6 +225,8 @@ export const CAPABILITIES: readonly Capability[] = [ routes: [{ method: "GET", path: "/api/usage" }], flags: [ { name: "--range", value: "string", summary: "today | 1d | 7d | 30d | all" }, + { name: "--since", value: "string", summary: "Inclusive start: epoch milliseconds or full ISO datetime with timezone; requires --until and overrides --range." }, + { name: "--until", value: "string", summary: "Inclusive end: epoch milliseconds or full ISO datetime with timezone; requires --since." }, { name: "--provider", value: "string", summary: "Restrict to one provider." }, { name: "--model", value: "string", summary: "Restrict to one model id." }, { name: "--json", value: "boolean", summary: "Emit the usage report as JSON." }, diff --git a/src/cli/observe.ts b/src/cli/observe.ts index 46e264d2a8..10a77254d0 100644 --- a/src/cli/observe.ts +++ b/src/cli/observe.ts @@ -12,6 +12,8 @@ import { } from "./runtime-api"; import { formatUsageReport } from "./usage-report"; import { USAGE_RANGES, USAGE_SURFACES } from "../usage/summary"; +import { parseUsageTimeWindow, type UsageTimeWindow } from "../usage/time-range"; +import { redactSecretString } from "../lib/redact"; const USAGE = `Usage: ocx observe logs [--provider ] [--model ] [--status ] @@ -20,6 +22,7 @@ const USAGE = `Usage: ocx logs rebuild-index ocx logs index-status ocx observe usage [--range ] [--surface ] + [--since ] [--until ] [--provider ] [--model ] [--json] ocx observe storage [codex-logs [status|protect|unprotect|repair|compact] [--mode ]] [--json] ocx observe memory [--json] @@ -146,6 +149,14 @@ async function usage(argv: string[], deps: RuntimeApiDeps): Promise { const surface = takeOption(args, "--surface") ?? "all"; const provider = takeOption(args, "--provider"); const model = takeOption(args, "--model"); + const since = takeOption(args, "--since"); + const until = takeOption(args, "--until"); + let window: UsageTimeWindow | undefined; + try { + window = parseUsageTimeWindow(since, until); + } catch (error) { + throw new CliUsageError(error instanceof Error ? error.message : "invalid usage time window", USAGE); + } // `1d` is accepted here as well as server-side so the CLI does not reject an // alias the API would have understood. const ranges = [...USAGE_RANGES, "1d"]; @@ -153,8 +164,8 @@ async function usage(argv: string[], deps: RuntimeApiDeps): Promise { if (!USAGE_SURFACES.includes(surface as (typeof USAGE_SURFACES)[number])) { throw new CliUsageError(`--surface must be one of ${USAGE_SURFACES.join(", ")}`, USAGE); } - rejectArgs(args, USAGE); - const result = await runtimeRequest(`/api/usage${query({ range, surface, provider, model })}`, {}, deps); + rejectArgs(args.map(redactSecretString), USAGE); + const result = await runtimeRequest(`/api/usage${query({ range, surface, provider, model, since: window?.since, until: window?.until })}`, {}, deps); // Built only when it will be printed: JavaScript evaluates arguments before // the call, so passing formatUsageReport(...) inline would run the human // renderer during --json and let its assumptions affect a path that is meant diff --git a/src/cli/usage-report.ts b/src/cli/usage-report.ts index e9f92f442d..6b684277c0 100644 --- a/src/cli/usage-report.ts +++ b/src/cli/usage-report.ts @@ -24,6 +24,8 @@ interface UsageReportInput { range?: string; surface?: string; since?: number | null; + until?: number; + customWindow?: boolean; summary?: { requests?: number; totalTokens?: number; @@ -90,7 +92,10 @@ function table(header: string[], rows: string[][]): string[] { } function describeScope(data: UsageReportInput): string { - const parts = [`Usage — ${data.range ?? "?"}`]; + const interval = data.customWindow && typeof data.since === "number" && typeof data.until === "number" + ? `custom ${new Date(data.since).toISOString()} to ${new Date(data.until).toISOString()} (inclusive)` + : data.range ?? "?"; + const parts = [`Usage — ${interval}`]; if (data.surface && data.surface !== "all") parts.push(`surface=${data.surface}`); if (data.filter?.provider) parts.push(`provider=${data.filter.provider}`); if (data.filter?.model) parts.push(`model=${data.filter.model}`); diff --git a/src/server/management/logs-usage-routes.ts b/src/server/management/logs-usage-routes.ts index ecbd6f655d..0177e56776 100644 --- a/src/server/management/logs-usage-routes.ts +++ b/src/server/management/logs-usage-routes.ts @@ -51,6 +51,7 @@ import { usageLogRevisionKey, } from "../../usage/log"; import { getUsageDebugLogEntries } from "../../usage/debug"; +import { parseUsageTimeWindow, type UsageTimeWindow } from "../../usage/time-range"; import { USAGE_RANGES, USAGE_SURFACES, parseRange, parseUsageSurface, rangeWindow, type UsageRange, type UsageSummary, type UsageSurface } from "../../usage/summary"; import { stripCodexRuntimeProviderFields } from "../../codex/auth-context"; import { getProviderRegistryEntry } from "../../providers/registry"; @@ -177,6 +178,12 @@ export async function handleLogsUsageRoutes(ctx: ManagementContext): Promise typeof value === "string" && value.trim() !== ""); const now = Date.now(); try { @@ -211,7 +218,7 @@ export async function handleLogsUsageRoutes(ctx: ManagementContext): Promise { +}, window?: UsageTimeWindow): Promise { + const fixedWindow = window ? Object.freeze({ ...window }) : undefined; const normalizedFilter = { provider: normalizeFilterValue(filter.provider), model: normalizeFilterValue(filter.model), @@ -273,11 +275,13 @@ export async function getFilteredUsageAggregate(filter: { normalizedFilter.provider, normalizedFilter.model, normalizedFilter.apiKeyId, + fixedWindow?.since ?? null, + fixedWindow?.until ?? null, ]); const existing = filteredFlights.get(key); if (existing) return existing; - const flight = refreshFilteredAggregate(key, normalizedFilter); + const flight = refreshFilteredAggregate(key, normalizedFilter, fixedWindow); filteredFlights.set(key, flight); try { return await flight; @@ -316,12 +320,13 @@ function publishFilteredAggregate( async function rebuildFilteredAggregate( key: string, filter: NormalizedUsageFilter, + window?: UsageTimeWindow, ): Promise { let lastError: unknown; for (let attempt = 0; attempt < MAX_REBUILD_ATTEMPTS; attempt += 1) { const overlayVersion = userCostOverlayVersion(); const timeZone = currentTimeZone(); - const accumulator = createUsageSummaryAccumulator({ filter, mode: "row-unique" }); + const accumulator = createUsageSummaryAccumulator({ filter, mode: "row-unique", window }); try { const scan = await scanUsageLedgerCooperatively({ onEntry: entry => accumulator.add(entry) }); if (scan.oversizedRows > 0) throw new Error("usage ledger contains an oversized row"); @@ -345,6 +350,7 @@ async function appendFilteredAggregate( key: string, state: RetainedUsageAggregate, filter: NormalizedUsageFilter, + window?: UsageTimeWindow, ): Promise { pinnedAggregates.add(state); let rebuildAfterUnpin = false; @@ -384,28 +390,29 @@ async function appendFilteredAggregate( pinnedAggregates.delete(state); trimRetainedFilteredAggregates(); } - if (rebuildAfterUnpin) return rebuildFilteredAggregate(key, filter); + if (rebuildAfterUnpin) return rebuildFilteredAggregate(key, filter, window); throw new Error("filtered usage append did not settle"); } async function refreshFilteredAggregate( key: string, filter: NormalizedUsageFilter, + window?: UsageTimeWindow, ): Promise { const state = retainedFilteredAggregates.get(key); - if (!state) return rebuildFilteredAggregate(key, filter); + if (!state) return rebuildFilteredAggregate(key, filter, window); const observed = currentUsageLogRevision(); const overlayVersion = userCostOverlayVersion(); const timeZone = currentTimeZone(); if (requiresRebuild(state, observed, overlayVersion, timeZone)) { retainedFilteredAggregates.delete(key); - return rebuildFilteredAggregate(key, filter); + return rebuildFilteredAggregate(key, filter, window); } if (state.revisionKey === usageLogRevisionKey(observed)) { state.retainedAt = Date.now(); return resultFrom(state, "unchanged"); } - return appendFilteredAggregate(key, state, filter); + return appendFilteredAggregate(key, state, filter, window); } export function usageAggregateRetainedStats(): UsageAggregateRetainedStats { diff --git a/src/usage/summary.ts b/src/usage/summary.ts index 6390db38c1..d7e678ab4f 100644 --- a/src/usage/summary.ts +++ b/src/usage/summary.ts @@ -1,6 +1,7 @@ import { baseProviderLabel } from "../providers/label"; import { canonicalAntigravityUsageModel } from "../providers/antigravity-models"; import { usageDisplayTotalTokens } from "./totals"; +import type { UsageTimeWindow } from "./time-range"; import { isUnresolvedRequestedModel, usageModelPriceOptions } from "./model-identity"; import { isCodexUsageAccountLogLabel, type PersistedUsageEntry, type UsageStatus } from "./log"; import { type AttemptCostEstimate, type CostEstimate, estimateAttemptCost, estimateRequestCost, serviceTierContext, type ServiceTierContext } from "./cost"; @@ -145,6 +146,8 @@ export interface UsageSummary { range: UsageRange; surface: UsageSurface; since: number | null; + customWindow?: true; + until?: number; generatedAt: number; summary: UsageSummaryTotals; days: UsageDay[]; @@ -297,6 +300,17 @@ function dayCountForAllRange(oldest: number | null, now: number): number { return Math.min(MAX_USAGE_DAY_BUCKETS, Math.max(1, days)); } +function customWindowDates(window: UsageTimeWindow): string[] { + const start = startOfLocalDay(window.since); + const date = new Date(startOfLocalDay(window.until)); + const dates: string[] = []; + while (date.getTime() >= start && dates.length < MAX_USAGE_DAY_BUCKETS) { + dates.push(localDateKey(date.getTime())); + date.setDate(date.getDate() - 1); + } + return dates.reverse(); +} + function blankTotals(): UsageSummaryTotals { return { requests: 0, @@ -1015,6 +1029,7 @@ class StreamingUsageSummaryAccumulator implements UsageSummaryAccumulator { private readonly requestIds: Map | null; private readonly filter: NormalizedUsageFilter | null; private readonly mode: UsageAccumulatorMode; + private readonly window: UsageTimeWindow | undefined; private nextRequestId = 0; private nextOrdinal = 0; private snapshotStart: number | null = null; @@ -1025,6 +1040,7 @@ class StreamingUsageSummaryAccumulator implements UsageSummaryAccumulator { constructor(options?: { filter?: { provider?: string | null; model?: string | null; apiKeyId?: string | null }; mode?: UsageAccumulatorMode; + window?: UsageTimeWindow; }) { const provider = normalizeFilterValue(options?.filter?.provider); const model = normalizeFilterValue(options?.filter?.model); @@ -1033,6 +1049,7 @@ class StreamingUsageSummaryAccumulator implements UsageSummaryAccumulator { ? null : { provider, model, apiKeyId }; this.mode = options?.mode ?? "exact"; + this.window = options?.window ? Object.freeze({ ...options.window }) : undefined; this.requestIds = this.mode === "exact" ? new Map() : null; } @@ -1048,6 +1065,7 @@ class StreamingUsageSummaryAccumulator implements UsageSummaryAccumulator { const cloned = new StreamingUsageSummaryAccumulator({ ...(this.filter ? { filter: this.filter } : {}), mode: this.mode, + window: this.window, }); cloned.nextRequestId = this.nextRequestId; cloned.nextOrdinal = this.nextOrdinal; @@ -1276,6 +1294,8 @@ class StreamingUsageSummaryAccumulator implements UsageSummaryAccumulator { ? sourceEntry.timestamp : Math.max(this.snapshotEnd, sourceEntry.timestamp); } + if (this.window && (!Number.isFinite(sourceEntry.timestamp) + || sourceEntry.timestamp < this.window.since || sourceEntry.timestamp > this.window.until)) return; const projected = this.filter ? projectedEntryForFilter(sourceEntry, this.filter) : { entry: sourceEntry, comboOverlap: false }; if (!projected) return; this.comboOverlap ||= projected.comboOverlap; @@ -1340,7 +1360,9 @@ class StreamingUsageSummaryAccumulator implements UsageSummaryAccumulator { now: number, surface: UsageSurface = "all", ): UsageSummary & { filter?: UsageFilterEcho } { - const { since, days: fixedDays } = rangeWindow(range, now); + const preset = rangeWindow(range, now); + const since = this.window?.since ?? preset.since; + const fixedDays = preset.days; const totals = blankTotals(); const models = new Map(); const providers = new Map(); @@ -1351,7 +1373,7 @@ class StreamingUsageSummaryAccumulator implements UsageSummaryAccumulator { for (const partition of this.partitions.values()) { if (!usageSurfaceMatches(partition.surface, surface)) continue; - if (since !== null && partition.dayStart < since) continue; + if (!this.window && since !== null && partition.dayStart < since) continue; mergeTotals(totals, partition.totals); mergeModelMaps(models, partition.models); if (partition.providers) mergeModelMaps(providers, partition.providers); @@ -1377,27 +1399,34 @@ class StreamingUsageSummaryAccumulator implements UsageSummaryAccumulator { } finalizeCoverage(totals); - const dayCount = range === "all" ? dayCountForAllRange(oldestTimestamp, now) : fixedDays; - const startOfToday = startOfLocalDay(now); + const customDates = this.window ? new Set(customWindowDates(this.window)) : null; + const dayCount = customDates?.size ?? (range === "all" ? dayCountForAllRange(oldestTimestamp, now) : fixedDays); + const startOfToday = startOfLocalDay(this.window?.until ?? now); const firstVisibleDay = new Date(startOfToday); firstVisibleDay.setDate(firstVisibleDay.getDate() - dayCount + 1); const firstVisibleDate = localDateKey(firstVisibleDay.getTime()); const lastVisibleDate = localDateKey(startOfToday); - for (let offset = dayCount - 1; offset >= 0; offset--) { + const visibleDates = customDates ?? new Set(); + for (let offset = dayCount - 1; !customDates && offset >= 0; offset--) { const date = new Date(startOfToday); date.setDate(date.getDate() - offset); - const key = localDateKey(date.getTime()); + visibleDates.add(localDateKey(date.getTime())); + } + for (const key of visibleDates) { if (!dayAccumulators.has(key)) { dayAccumulators.set(key, { totals: blankTotals(), models: new Map(), modelOverlaps: [] }); } } - const days = [...dayAccumulators] + const visibleDays = customDates + ? [...customDates].map(date => [date, dayAccumulators.get(date)!] as const) + : [...dayAccumulators] // All-history totals, models, providers, and accounts still cover every // retained row. Only the chart buckets are bounded so one malformed or // ancient timestamp cannot synthesize an enormous JSON response. .filter(([date]) => range !== "all" || (date >= firstVisibleDate && date <= lastVisibleDate)) - .sort(([a], [b]) => a.localeCompare(b)) + .sort(([a], [b]) => a.localeCompare(b)); + const days = visibleDays .map(([date, day]): UsageDay => ({ date, requests: day.totals.requests, @@ -1412,6 +1441,7 @@ class StreamingUsageSummaryAccumulator implements UsageSummaryAccumulator { range, surface, since, + ...(this.window ? { customWindow: true as const, until: this.window.until } : {}), generatedAt: now, summary: totals, days, @@ -1449,6 +1479,7 @@ class StreamingUsageSummaryAccumulator implements UsageSummaryAccumulator { export function createUsageSummaryAccumulator(options?: { filter?: { provider?: string | null; model?: string | null; apiKeyId?: string | null }; mode?: UsageAccumulatorMode; + window?: UsageTimeWindow; }): UsageSummaryAccumulator { return new StreamingUsageSummaryAccumulator(options); } @@ -1501,7 +1532,11 @@ export function projectUsageSummary( const model = normalizeFilterValue(filter.model); const apiKeyId = normalizeExactFilterValue(filter.apiKeyId); if (provider === null && model === null && apiKeyId === null) return summary; - const accumulator = createUsageSummaryAccumulator({ filter: { provider, model, apiKeyId } }); + const accumulator = createUsageSummaryAccumulator({ + filter: { provider, model, apiKeyId }, + ...(summary.customWindow && summary.since !== null && summary.until !== undefined + ? { window: { since: summary.since, until: summary.until } } : {}), + }); for (const entry of entries ?? []) accumulator.add(entry); const projected = accumulator.summarize(summary.range, summary.generatedAt, summary.surface); return { diff --git a/src/usage/time-range.ts b/src/usage/time-range.ts new file mode 100644 index 0000000000..01b1beec83 --- /dev/null +++ b/src/usage/time-range.ts @@ -0,0 +1,48 @@ +/** Inclusive epoch-millisecond bounds, independent of the selected preset. */ +export interface UsageTimeWindow { + readonly since: number; + readonly until: number; +} + +const MAX_DATE_MS = 8_640_000_000_000_000; +const ISO_DATETIME = /^(\d{4}|\+\d{6})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.\d{1,3})?(Z|([+-])(\d{2}):(\d{2}))$/; + +function parseTimestamp(input: string | number, name: "since" | "until"): number { + const invalid = (): never => { + throw new Error(`${name} must be nonnegative integer epoch milliseconds or a valid full ISO datetime with timezone`); + }; + let timestamp: number; + if (typeof input === "number") timestamp = input; + else if (/^\d+$/.test(input)) timestamp = Number(input); + else { + const parts = ISO_DATETIME.exec(input); + if (!parts) return invalid(); + const year = Number(parts[1]); + const month = Number(parts[2]); + const day = Number(parts[3]); + const leapYear = year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0); + const monthDays = [31, leapYear ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]; + // Date.parse normalizes some impossible dates (e.g. February 30). + // Validate the written calendar fields before applying its timezone offset. + if (month < 1 || month > 12 || day < 1 || day > monthDays[month - 1]! + || Number(parts[4]) > 23 || Number(parts[5]) > 59 || Number(parts[6]) > 59 + || (parts[7] !== "Z" && (Number(parts[9]) > 23 || Number(parts[10]) > 59))) { + return invalid(); + } + timestamp = Date.parse(input); + } + if (!Number.isSafeInteger(timestamp) || timestamp < 0 || timestamp > MAX_DATE_MS) return invalid(); + return timestamp; +} + +/** No bounds selects the preset; supplying either bound requires both. */ +export function parseUsageTimeWindow( + since: string | number | null | undefined, + until: string | number | null | undefined, +): UsageTimeWindow | undefined { + if (since == null && until == null) return undefined; + if (since == null || until == null) throw new Error("since and until must be supplied together"); + const window = { since: parseTimestamp(since, "since"), until: parseTimestamp(until, "until") }; + if (window.since > window.until) throw new Error("since must be less than or equal to until"); + return Object.freeze(window); +} diff --git a/structure/05_gui-and-management-api.md b/structure/05_gui-and-management-api.md index a151a34d42..4a697671a4 100644 --- a/structure/05_gui-and-management-api.md +++ b/structure/05_gui-and-management-api.md @@ -357,6 +357,14 @@ keeps the saved state and renders fixed `ocx sync` guidance without server/accou ## Usage accounting +Custom usage windows are immutable bounds on the streaming accumulator, applied to each +ledger entry before attribution and daily aggregation. The filtered aggregate cache includes +both inclusive millisecond bounds in its identity and retains the existing ledger revision, +overlay-version and timezone checks. Preset warming never consumes custom summaries. +The response retains its preset range discriminator for compatibility and explicitly marks +`customWindow`, `since`, and `until`; the chart uses the window's local calendar days with +the existing 366-day cap. GUI custom reports bypass the held preset/session cache. + Account quota discovery is capability-based. Cheap OAuth and provider-key lists include `quotaMode` (`probe`, `passive`, or `unsupported`) without contacting upstream quota APIs. `GET /api/oauth/accounts?provider=..."a=1` and diff --git a/tests/cli/cli-usage-report.test.ts b/tests/cli/cli-usage-report.test.ts index b20112ee12..d1fdd7b4b5 100644 --- a/tests/cli/cli-usage-report.test.ts +++ b/tests/cli/cli-usage-report.test.ts @@ -136,6 +136,64 @@ describe("formatUsageReport", () => { }); describe("ocx usage command", () => { + test("duplicate, inline and stray custom-bound arguments do not echo credential-shaped values", async () => { + const secret = "sk-" + "a".repeat(40); + const errors: string[] = []; + const errorSpy = spyOn(console, "error").mockImplementation((...args: unknown[]) => { errors.push(args.map(String).join(" ")); }); + try { + for (const extra of [["--since", secret], [`--since=${secret}`], [secret]]) { + const result = await run(["usage", "--since", "0", "--until", "1", ...extra], payload()); + expect(result.code).toBe(2); + expect(result.urls).toEqual([]); + } + expect(errors.join("\n")).not.toContain(secret); + expect(errors.join("\n")).toContain("Unexpected argument(s)"); + } finally { errorSpy.mockRestore(); } + }); + + test("normalizes custom ISO bounds and preserves the selected preset and filters", async () => { + const body = payload({ customWindow: true, since: 1709164800123, until: 1709164800123 }); + const { code, urls, out } = await run([ + "usage", "--range", "7d", "--surface", "codex", "--provider", "openai", "--model", "gpt-5.5", + "--since", "2024-02-29T09:00:00.123+09:00", "--until", "1709164800123", + ], body); + expect(code).toBe(0); + expect(urls).toHaveLength(1); + const query = new URL(urls[0]!).searchParams; + expect(Object.fromEntries(query)).toEqual({ + range: "7d", surface: "codex", provider: "openai", model: "gpt-5.5", + since: "1709164800123", until: "1709164800123", + }); + expect(out.split("\n")[0]).toContain("custom 2024-02-29T00:00:00.123Z to 2024-02-29T00:00:00.123Z (inclusive)"); + expect((await run(["usage", "--since", "0", "--until", "0", "--json"], body)).out) + .toBe(JSON.stringify(body, null, 2)); + }); + + test("rejects malformed or unpaired windows as usage errors without an API request", async () => { + const errors: string[] = []; + const errorSpy = spyOn(console, "error").mockImplementation((...args: unknown[]) => { + errors.push(args.map(String).join(" ")); + }); + try { + for (const args of [ + ["--since", "0"], ["--until", "0"], ["--since", "2", "--until", "1"], + ["--since", "-1", "--until", "0"], ["--since", "1.5", "--until", "2"], + ["--since", "0", "--until", "8640000000000001"], + ["--since", "0", "--until", "2026-02-30T00:00:00Z"], + ["--since", "0", "--until", "2026-09-01T00:00:00"], + ["--since", "0", "--until", "2026-09-01T00:00:00.0001Z"], + ]) { + const result = await run(["usage", ...args], payload()); + expect(result.code).toBe(2); + expect(result.urls).toEqual([]); + } + expect(errors.join("\n")).toContain("since and until must be supplied together"); + expect(errors.join("\n")).toContain("timezone"); + } finally { + errorSpy.mockRestore(); + } + }); + test("forwards range and provider to the API", async () => { const { code, urls } = await run(["usage", "--range", "today", "--provider", "xai"], payload()); expect(code).toBe(0); diff --git a/tests/fixtures/test-layout-expected.json b/tests/fixtures/test-layout-expected.json index 496d51ea31..05ce7e87ff 100644 --- a/tests/fixtures/test-layout-expected.json +++ b/tests/fixtures/test-layout-expected.json @@ -1135,5 +1135,6 @@ "zz-ci-storage-policy-isolation.test.ts": "ci-workflows", "zz-pr-coderabbit-readiness-revalidation.test.ts": "ci-workflows", "cli-models-price.test.ts": "cli", - "model-costs-management-api.test.ts": "server" + "model-costs-management-api.test.ts": "server", + "usage-time-range.test.ts": "usage" } diff --git a/tests/server/api-usage.test.ts b/tests/server/api-usage.test.ts index a86836a0de..fa5c0ee2e2 100644 --- a/tests/server/api-usage.test.ts +++ b/tests/server/api-usage.test.ts @@ -109,6 +109,111 @@ afterEach(() => { }); describe("GET /api/usage", () => { + test("custom bounds override presets while preserving surface, filters and accounts", async () => { + const since = new Date(2026, 1, 10, 12).getTime(); + const until = since + 3_600_000; + const rows = [ + { timestamp: since - 1, apiKeyId: "Key-A" }, + { timestamp: since, apiKeyId: "Key-A" }, + { timestamp: until, apiKeyId: "key-a" }, + { timestamp: since + 1, apiKeyId: "Key-A", surface: "claude" }, + { timestamp: until + 1, apiKeyId: "Key-A" }, + ].map((row, index) => ({ + requestId: `custom-${index}`, provider: "openai", model: "gpt-5.5", accountLogLabel: "main", + status: 200, durationMs: 1, usageStatus: "reported", usage: { inputTokens: 10, outputTokens: 5 }, + totalTokens: 15, ...row, + })); + writeFileSync(join(testDir, "usage.jsonl"), rows.map(row => JSON.stringify(row)).join("\n") + "\n"); + const server = startServer(0); + try { + const preset = await (await fetch(new URL("/api/usage?range=all", server.url))).json(); + const params = new URLSearchParams({ range: "today", since: new Date(since).toISOString(), until: String(until), surface: "codex" }); + const before = Date.now(); + const response = await fetch(new URL(`/api/usage?${params}`, server.url)); + expect(response.status).toBe(200); + const custom = await response.json(); + expect(custom).toMatchObject({ range: "today", surface: "codex", customWindow: true, since, until }); + expect(custom.generatedAt).toBeGreaterThanOrEqual(before); + expect(custom.generatedAt).toBeLessThanOrEqual(Date.now()); + expect(custom.summary.requests).toBe(2); + expect(custom.days).toHaveLength(1); + expect(custom.days[0].requests).toBe(2); + expect(custom.accounts[0]).toMatchObject({ accountLogLabel: "main", requests: 2 }); + expect(custom.filter).toBeUndefined(); + expect(custom.snapshotWindowStart).toBe(since - 1); + expect(custom.snapshotWindowEnd).toBe(until + 1); + params.set("apiKeyId", "Key-A"); + const byKey = await (await fetch(new URL(`/api/usage?${params}`, server.url))).json(); + expect(byKey.summary.requests).toBe(1); + expect(byKey.accounts[0].requests).toBe(1); + expect(byKey.filter).toMatchObject({ apiKeyId: "Key-A", matched: true }); + params.set("provider", "OpenAI"); + params.set("model", "GPT-5.5"); + const combined = await (await fetch(new URL(`/api/usage?${params}`, server.url))).json(); + expect(combined.filter).toMatchObject({ provider: "openai", model: "gpt-5.5", apiKeyId: "Key-A", matched: true }); + expect(combined.summary.requests).toBe(1); + expect(combined.accounts).toEqual([]); + params.set("since", String(until)); + const noMatch = await (await fetch(new URL(`/api/usage?${params}`, server.url))).json(); + expect(noMatch.summary.requests).toBe(0); + expect(noMatch.filter.matched).toBe(false); + const after = await (await fetch(new URL("/api/usage?range=all", server.url))).json(); + expect(after.summary).toEqual(preset.summary); + expect(after.summary.requests).toBe(5); + expect(after.customWindow).toBeUndefined(); + expect(after.until).toBeUndefined(); + } finally { + await server.stop(true); + } + }); + + test("rejects invalid custom bounds with 400 before scanning", async () => { + const scanSpy = spyOn(usageLedgerScannerModule, "scanUsageLedgerCooperatively"); + const server = startServer(0); + try { + for (const query of [ + "since=0", "until=0", "since=&until=1", "since=2&until=1", "since=-1&until=1", + "since=0&until=8640000000000001", "since=0&until=9007199254740992", + "since=0&until=2026-02-30T12:00:00Z", "since=0&until=2026-09-01T12:00:00", + "since=0&until=2026-09-01T12:00:00.0001Z", + ]) { + const response = await fetch(new URL(`/api/usage?${query}`, server.url)); + expect(response.status).toBe(400); + expect((await response.json()).error).toBeTruthy(); + } + expect(scanSpy).not.toHaveBeenCalled(); + } finally { + scanSpy.mockRestore(); + await server.stop(true); + } + }); + + test("empty custom history and read failures retain the requested interval", async () => { + const server = startServer(0); + const url = new URL("/api/usage?range=today&since=0&until=0", server.url); + try { + const empty = await (await fetch(url)).json(); + expect(empty).toMatchObject({ customWindow: true, since: 0, until: 0, summary: { requests: 0 } }); + expect(empty.days).toHaveLength(1); + expect(empty.error).toBeUndefined(); + const scanSpy = spyOn(usageLedgerScannerModule, "scanUsageLedgerCooperatively") + .mockRejectedValue(new Error("fixture scan failure")); + try { + // A distinct key forces a fresh custom scan. + url.searchParams.set("until", "1"); + const response = await fetch(url); + expect(response.status).toBe(200); // existing Usage UI reads the error field + expect(await response.json()).toMatchObject({ + range: "today", customWindow: true, since: 0, until: 1, error: "read_failed", + }); + } finally { + scanSpy.mockRestore(); + } + } finally { + await server.stop(true); + } + }); + test("concurrent cold requests share one base-ledger scan", async () => { writeFixture(Date.now()); const originalScan = usageLedgerScannerModule.scanUsageLedgerCooperatively; diff --git a/tests/usage/usage-aggregate-cache.test.ts b/tests/usage/usage-aggregate-cache.test.ts index c739d0546d..3efb5615e4 100644 --- a/tests/usage/usage-aggregate-cache.test.ts +++ b/tests/usage/usage-aggregate-cache.test.ts @@ -72,6 +72,55 @@ afterEach(() => { }); describe("retained usage aggregate cache", () => { + test("custom cache keys isolate both endpoints and never poison preset aggregates", async () => { + const path = join(testDir, "usage.jsonl"); + const rows = [NOW - 2_000, NOW - 1_000, NOW].map((timestamp, index) => ({ ...entry(String(index)), timestamp })); + writeFileSync(path, rows.map(row => JSON.stringify(row)).join("\n") + "\n"); + const base = await getUsageAggregate(); + const firstWindow = { since: NOW - 2_000, until: NOW - 1_000 }; + const first = await getFilteredUsageAggregate({}, firstWindow); + const same = await getFilteredUsageAggregate({}, { ...firstWindow }); + const differentStart = await getFilteredUsageAggregate({}, { since: NOW - 1_000, until: NOW - 1_000 }); + const differentEnd = await getFilteredUsageAggregate({}, { since: NOW - 2_000, until: NOW }); + expect(same.accumulator).toBe(first.accumulator); + expect(same.update).toBe("unchanged"); + expect(requests(first)).toBe(2); + expect(requests(differentStart)).toBe(1); + expect(requests(differentEnd)).toBe(3); + expect((await getUsageAggregate()).accumulator).toBe(base.accumulator); + expect(requests(base)).toBe(3); + expect(base.accumulator.summarize("all", NOW).customWindow).toBeUndefined(); + for (let index = 1; index <= 7; index++) { + await getFilteredUsageAggregate({}, { since: NOW, until: NOW + index }); + } + expect(usageAggregateRetainedStats().count).toBe(5); // base plus four filtered windows + }); + + test("custom incremental clones filter appended rows and rebuild with changed prices", async () => { + const path = join(testDir, "usage.jsonl"); + const window = { since: NOW - 1_000, until: NOW }; + writeFileSync(path, line("one")); + const original = await getFilteredUsageAggregate({}, window); + appendFileSync(path, [ + { ...entry("inside"), timestamp: NOW }, + { ...entry("outside"), timestamp: NOW + 1 }, + ].map(row => JSON.stringify(row)).join("\n") + "\n"); + const appended = await getFilteredUsageAggregate({}, window); + expect(appended.update).toBe("append"); + expect(requests(original)).toBe(1); + expect(requests(appended)).toBe(2); + expect(appended.accumulator.snapshotWindow.end).toBe(NOW + 1); + refreshUserCostOverlays({ providers: { openai: { modelCosts: { + "gpt-5.5": { input: 1, output: 2, cacheRead: 0.1, cacheWrite: 0.2 }, + } } } } as unknown as OcxConfig); + const rebuilt = await getFilteredUsageAggregate({}, window); + expect(rebuilt.update).toBe("rebuild"); + expect(rebuilt.accumulator.summarize("today", NOW)).toMatchObject({ + customWindow: true, ...window, summary: { requests: 2 }, + }); + expect(rebuilt.accumulator.summarize("all", NOW).summary.estimatedCostUsd).toBeCloseTo(0.000006, 10); + }); + test("append and rebuild preserve unresolved attribution and restricted pricing without ledger changes", async () => { const path = join(testDir, "usage.jsonl"); writeFileSync(path, line("ordinary")); diff --git a/tests/usage/usage-summary.test.ts b/tests/usage/usage-summary.test.ts index 6e26fb2e66..36d83c779f 100644 --- a/tests/usage/usage-summary.test.ts +++ b/tests/usage/usage-summary.test.ts @@ -16,6 +16,102 @@ import { isUnresolvedRequestedModel } from "../../src/usage/model-identity"; const FIXED_NOW = Date.UTC(2026, 5, 28, 12, 0, 0); +describe("custom usage windows", () => { + const since = new Date(2026, 1, 10, 12, 0, 0, 123).getTime(); + const until = since + 3_600_000; + + test("includes both intraday endpoints before attribution and retains whole-log snapshot", () => { + for (const mode of ["exact", "row-unique"] as const) { + const accumulator = createUsageSummaryAccumulator({ mode, window: { since, until } }); + for (const ts of [since - 1, since, until, until + 1]) { + accumulator.add(entry({ ts, usageStatus: "reported", usage: { inputTokens: 10, outputTokens: 5 }, accountLogLabel: "main" })); + } + const result = accumulator.summarize("today", FIXED_NOW, "codex"); + expect(result).toMatchObject({ range: "today", customWindow: true, since, until, generatedAt: FIXED_NOW }); + expect(result.summary).toMatchObject({ requests: 2, inputTokens: 20, outputTokens: 10 }); + expect(result.days).toHaveLength(1); + expect(result.days[0]).toMatchObject({ date: "2026-02-10", requests: 2 }); + expect(result.accounts[0]).toMatchObject({ accountLogLabel: "main", requests: 2 }); + expect(result.filter).toBeUndefined(); + expect(accumulator.snapshotWindow).toEqual({ start: since - 1, end: until + 1 }); + } + }); + + test("same-instant windows survive caller mutation and independent incremental clones", () => { + const window = { since, until: since }; + const accumulator = createUsageSummaryAccumulator({ window, mode: "row-unique" }); + window.since = 0; + window.until = FIXED_NOW; + accumulator.add(entry({ ts: since })); + const clone = accumulator.clone(); + clone.add(entry({ ts: since, requestId: "second" })); + clone.add(entry({ ts: since + 1 })); + expect(accumulator.summarize("all", FIXED_NOW).summary.requests).toBe(1); + expect(clone.summarize("7d", FIXED_NOW)).toMatchObject({ + customWindow: true, since, until: since, summary: { requests: 2 }, + }); + expect(accumulator.snapshotWindow.end).toBe(since); + expect(clone.snapshotWindow.end).toBe(since + 1); + }); + + test("empty grids use exact local calendar days across DST and include endpoint midnight", () => { + for (const [year, month, day, expected] of [ + [2026, 2, 7, ["2026-03-07", "2026-03-08", "2026-03-09"]], + [2026, 9, 31, ["2026-10-31", "2026-11-01", "2026-11-02"]], + ] as const) { + const window = { + since: new Date(year, month, day, 23, 59).getTime(), + until: new Date(year, month, day + 2, 0, 0).getTime(), + }; + const accumulator = createUsageSummaryAccumulator({ window }); + const result = accumulator.summarize("30d", FIXED_NOW); + expect(result.days.map(row => row.date)).toEqual([...expected]); + expect(result.days.every(row => row.requests === 0)).toBe(true); + expect(result.summary.requests).toBe(0); + expect(result.since).toBe(window.since); + expect(result.until).toBe(window.until); + expect(accumulator.snapshotWindow).toEqual({ start: null, end: null }); + } + }); + + test("caps only the chart at 366 calendar days ending at until", () => { + const window = { since: new Date(2020, 0, 1, 12).getTime(), until: new Date(2026, 0, 1, 12).getTime() }; + const accumulator = createUsageSummaryAccumulator({ window }); + accumulator.add(entry({ ts: window.since })); + accumulator.add(entry({ ts: window.until })); + const result = accumulator.summarize("today", FIXED_NOW); + expect(result.summary.requests).toBe(2); + expect(result.days).toHaveLength(366); + expect(result.days[0]?.date).toBe("2025-01-01"); + expect(result.days.at(-1)?.date).toBe("2026-01-01"); + expect(result.days.reduce((sum, row) => sum + row.requests, 0)).toBe(1); + }); + + test("custom calendar order remains chronological across expanded ISO years", () => { + const accumulator = createUsageSummaryAccumulator({ window: { + since: new Date(9999, 11, 31, 12).getTime(), until: new Date(10000, 0, 1, 12).getTime(), + } }); + expect(accumulator.summarize("all", FIXED_NOW).days.map(day => day.date)) + .toEqual(["9999-12-31", "10000-01-01"]); + }); + + test("window filtering preserves preset cost attribution for the same retained rows", () => { + const rows = [since - 1, since, until, until + 1].map(ts => entry({ + ts, provider: "anthropic", model: "claude-3-haiku-20240307", usageStatus: "reported", + usage: { inputTokens: 100, outputTokens: 50 }, + })); + const accumulator = createUsageSummaryAccumulator({ window: { since, until }, mode: "row-unique" }); + rows.forEach(row => accumulator.add(row)); + const result = accumulator.summarize("today", FIXED_NOW); + const baseline = summarizeUsage(rows.slice(1, 3), "all", until); + expect(result.summary.estimatedCostUsd).toBeGreaterThan(0); + expect(result.summary).toEqual(baseline.summary); + expect(result.models).toEqual(baseline.models); + expect(result.providers).toEqual(baseline.providers); + expect(result.days[0]?.estimatedCostUsd).toBeCloseTo(result.summary.estimatedCostUsd, 10); + }); +}); + function entry(overrides: Partial & { ts: number }): PersistedUsageEntry { const { ts, ...rest } = overrides; return { diff --git a/tests/usage/usage-time-range.test.ts b/tests/usage/usage-time-range.test.ts new file mode 100644 index 0000000000..3a36def2bc --- /dev/null +++ b/tests/usage/usage-time-range.test.ts @@ -0,0 +1,36 @@ +import { describe, expect, test } from "bun:test"; +import { parseUsageTimeWindow } from "../../src/usage/time-range"; + +describe("usage time window parsing", () => { + test("accepts epoch milliseconds and normalizes explicit ISO offsets", () => { + expect(parseUsageTimeWindow(undefined, null)).toBeUndefined(); + expect(parseUsageTimeWindow("0", 0)).toEqual({ since: 0, until: 0 }); + expect(parseUsageTimeWindow("1970-01-01T00:00:00.1Z", "1970-01-01T00:00:00.12Z")) + .toEqual({ since: 100, until: 120 }); + expect(parseUsageTimeWindow("2024-02-29T09:00:00.123+09:00", "2024-02-28T19:00:00.123-05:00")) + .toEqual({ since: 1709164800123, until: 1709164800123 }); + expect(parseUsageTimeWindow("1970-01-01T00:00:00Z", "8640000000000000")) + .toEqual({ since: 0, until: 8_640_000_000_000_000 }); + expect(parseUsageTimeWindow("+275760-09-13T00:00:00Z", 8_640_000_000_000_000)?.since) + .toBe(8_640_000_000_000_000); + }); + + test("rejects absent peers, reversed bounds and non-integer or invalid dates", () => { + for (const [since, until] of [[0, undefined], [null, 0], [2, 1]] as const) { + expect(() => parseUsageTimeWindow(since, until)).toThrow(); + } + for (const value of [ + "", " ", " 0", "1.5", "1e3", "0x10", "-1", -1, 0.5, NaN, Infinity, + "9007199254740992", "8640000000000001", "2026-09-01", "2026-09-01T12:00:00", + "2026-09-01T12:00Z", "2026-02-29T00:00:00Z", "2024-02-30T00:00:00Z", + "2100-02-29T00:00:00Z", "2026-04-31T00:00:00+09:00", "2026-13-01T00:00:00Z", + "2026-01-00T00:00:00Z", "2026-01-01T24:00:00Z", "2026-01-01T00:60:00Z", + "2026-01-01T00:00:60Z", "2026-01-01T00:00:00+24:00", "2026-01-01T00:00:00+01:60", + "1970-01-01T00:00:00+00:01", "+275760-09-13T00:00:00.001Z", + "2026-09-01T00:00:00.0001Z", + ]) { + expect(() => parseUsageTimeWindow(value, 8_640_000_000_000_000)).toThrow(); + expect(() => parseUsageTimeWindow(0, value)).toThrow(); + } + }); +}); From 089320e88cd32056ab491706cb37faedb4cedd24 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 18:57:31 +0900 Subject: [PATCH 140/412] docs: define lane D verification and handoff [skip ci] --- devlog/_plan/260907_lane_d/060_delivery.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 devlog/_plan/260907_lane_d/060_delivery.md diff --git a/devlog/_plan/260907_lane_d/060_delivery.md b/devlog/_plan/260907_lane_d/060_delivery.md new file mode 100644 index 0000000000..2009ba9bb9 --- /dev/null +++ b/devlog/_plan/260907_lane_d/060_delivery.md @@ -0,0 +1,18 @@ +# 060 Remote verification and delivery + +Consume D5's implementation checkpoint. Resolve remaining independent review feedback on +its owning layer, cascade all dependent refs, and preserve contributor trailers. Detailed +unpublished security-review notes stay in scratch. Reconcile A's added reasoning-envelope +budget arguments with D1 ordering when A reaches dev; preserve both changes. + +Fetch fresh dev before final dispatch. Run only the top branch's ci.yml workflow with +lane=all; require successful actual platform jobs including Windows on the exact head. +Download its dashboard-preview artifact and verify build-commit/build-gui-tree markers. +Capture the changed dialogs and custom Usage range with synthetic data through the existing +browser capability; publish proof images separately so evidence does not change tested code. + +Create D2-D5 PRs with the required template, screenshot, manual chain table and native +stack:null proof. Attach independent implementation/security verdicts and top CI URL to +each PR. Leave all merges and original issue/PR closure actions to the main task. +Local product tests/typecheck/build/install remain NOT RUN. D closes only when exact-head +remote evidence and the requested handoff table are complete. From e346d7ae03433bf1d642e9ff0172dbd0edcffca0 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 19:01:33 +0900 Subject: [PATCH 141/412] fix(usage): preserve dates across timezone calendar gaps [skip ci] Use server civil dates for custom heatmaps and guarantee backward progress when a local day is skipped. Add Santiago and Apia timezone regressions. Co-authored-by: Manson2438 <183030642+Manson2438@users.noreply.github.com> --- devlog/_plan/260907_lane_d/060_delivery.md | 6 +++ gui/src/pages/Usage.tsx | 54 ++++++++++++++++------ gui/tests/usage-custom-range.test.tsx | 27 +++++++++++ src/usage/summary.ts | 8 ++++ tests/usage/usage-summary.test.ts | 20 ++++++++ 5 files changed, 101 insertions(+), 14 deletions(-) diff --git a/devlog/_plan/260907_lane_d/060_delivery.md b/devlog/_plan/260907_lane_d/060_delivery.md index 2009ba9bb9..38bcb1c80a 100644 --- a/devlog/_plan/260907_lane_d/060_delivery.md +++ b/devlog/_plan/260907_lane_d/060_delivery.md @@ -16,3 +16,9 @@ stack:null proof. Attach independent implementation/security verdicts and top CI each PR. Leave all merges and original issue/PR closure actions to the main task. Local product tests/typecheck/build/install remain NOT RUN. D closes only when exact-head remote evidence and the requested handoff table are complete. + +Calendar audit fold-back: custom heatmaps iterate the server's returned civil dates, +using UTC only for weekday/month layout; they do not step a local midnight cursor. +The server's backward calendar walk resets midnight after decrement and explicitly +advances to the prior existing local day if a whole-day timezone jump prevented progress. +Regressions pin America/Santiago (2026-09-05..07) and Pacific/Apia (2011-12-29..31). diff --git a/gui/src/pages/Usage.tsx b/gui/src/pages/Usage.tsx index 44ecce0c98..36b0d4ba82 100644 --- a/gui/src/pages/Usage.tsx +++ b/gui/src/pages/Usage.tsx @@ -161,29 +161,55 @@ interface HeatmapCell { function buildHeatmap(days: UsageDay[], customWindow = false): { weeks: HeatmapCell[][]; months: { label: string; col: number }[]; buckets: number[] } { const buckets = quantileBuckets(days.map(d => d.totalTokens)); - if (customWindow && days.length === 0) return { weeks: [], months: [], buckets }; + const monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; + if (customWindow) { + const weeks: HeatmapCell[][] = []; + const months: { label: string; col: number }[] = []; + let week: HeatmapCell[] = []; + let weekStart: number | undefined; + let previousMonth = -1; + let lastMonthCol = -4; + const pad = (length: number) => { + while (week.length < length) week.push({ date: "", requests: 0, totalTokens: 0, level: 0, dayOfWeek: week.length }); + }; + // The server already supplied the bounded civil dates. Local midnight stepping + // can retain a shifted hour across DST and omit the final day of the report. + for (const day of days) { + const [year, month, date] = day.date.split("-").map(Number); + const calendar = new Date(Date.UTC(year, month - 1, date)); + const weekday = calendar.getUTCDay(); + const nextWeekStart = calendar.getTime() - weekday * 86_400_000; + if (weekStart !== nextWeekStart) { + if (week.length > 0) { pad(7); weeks.push(week); } + week = []; + weekStart = nextWeekStart; + } + const monthIndex = calendar.getUTCMonth(); + if (monthIndex !== previousMonth && weeks.length - lastMonthCol >= 4) { + months.push({ label: monthNames[monthIndex], col: weeks.length }); + previousMonth = monthIndex; + lastMonthCol = weeks.length; + } + pad(weekday); + week.push({ date: day.date, requests: day.requests, totalTokens: day.totalTokens, + level: bucketLevel(day.totalTokens, buckets), dayOfWeek: weekday }); + } + if (week.length > 0) { pad(7); weeks.push(week); } + return { weeks, months, buckets }; + } const dayMap = new Map(days.map(d => [d.date, d])); - const today = customWindow ? new Date(`${days[days.length - 1].date}T00:00:00`) : new Date(); + const today = new Date(); today.setHours(0, 0, 0, 0); - const start = customWindow ? new Date(`${days[0].date}T00:00:00`) : new Date(today); - if (!customWindow) { - start.setDate(start.getDate() - 364); - start.setDate(start.getDate() - start.getDay()); - } + const start = new Date(today); + start.setDate(start.getDate() - 364); + start.setDate(start.getDate() - start.getDay()); const weeks: HeatmapCell[][] = []; const months: { label: string; col: number }[] = []; - const monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]; let lastMonthCol = -4; let prevMonthIdx = -1; let week: HeatmapCell[] = []; - // Align a custom grid without inventing report dates outside the server's bounded days. - if (customWindow) { - while (week.length < start.getDay()) { - week.push({ date: "", requests: 0, totalTokens: 0, level: 0, dayOfWeek: week.length }); - } - } const cursor = new Date(start); while (cursor <= today) { diff --git a/gui/tests/usage-custom-range.test.tsx b/gui/tests/usage-custom-range.test.tsx index c06b27eb33..db441dbb83 100644 --- a/gui/tests/usage-custom-range.test.tsx +++ b/gui/tests/usage-custom-range.test.tsx @@ -119,6 +119,33 @@ function sessionEntries() { }); } +test("America/Santiago midnight DST retains final-day activity and tooltip", async () => { + const previous = process.env.TZ; + process.env.TZ = "America/Santiago"; + try { + expect(new Date(2026, 8, 6, 0).getHours()).toBe(1); + await mount(); + await respond(0, "preset-marker"); + await enter("2026-09-05T00:00", "2026-09-07T23:59"); + await apply(); + const gate = requests.at(-1)!; + const data = report(gate, "santiago-marker", "2026-09-07"); + data.days = ["2026-09-05", "2026-09-06", "2026-09-07"].map(date => ({ + date, requests: date === "2026-09-07" ? 7 : 0, measuredRequests: 0, reportedRequests: 0, + totalTokens: date === "2026-09-07" ? 700 : 0, models: [], + })); + await act(async () => gate.resolve(Response.json(data))); + const active = container.querySelector('.heatmap-grid .heatmap-cell:not(.heatmap-cell-0)'); + expect(active).not.toBeNull(); + await act(async () => active!.dispatchEvent(new testWindow.MouseEvent("mouseover", { bubbles: true }))); + expect(container.querySelector(".heatmap-tip-date")?.textContent).toBe("2026-09-07"); + expect(container.querySelector(".heatmap-tip")?.textContent).toContain("700"); + } finally { + if (previous === undefined) delete process.env.TZ; + else process.env.TZ = previous; + } +}); + test("Apply submits inclusive bounds once; Clear restores the held preset without custom cache entries", async () => { await mount(); expect(requests[0].url).toBe(`${apiBase}/api/usage?range=30d&surface=all`); diff --git a/src/usage/summary.ts b/src/usage/summary.ts index d7e678ab4f..2e731a2900 100644 --- a/src/usage/summary.ts +++ b/src/usage/summary.ts @@ -306,7 +306,15 @@ function customWindowDates(window: UsageTimeWindow): string[] { const dates: string[] = []; while (date.getTime() >= start && dates.length < MAX_USAGE_DAY_BUCKETS) { dates.push(localDateKey(date.getTime())); + const previous = date.getTime(); date.setDate(date.getDate() - 1); + date.setHours(0, 0, 0, 0); + // A skipped civil day can normalize back to this same midnight (Apia, 2011). + // Move through the preceding instant to find the prior existing local day. + if (date.getTime() >= previous) { + date.setTime(previous - 1); + date.setHours(0, 0, 0, 0); + } } return dates.reverse(); } diff --git a/tests/usage/usage-summary.test.ts b/tests/usage/usage-summary.test.ts index 36d83c779f..094e9e5a44 100644 --- a/tests/usage/usage-summary.test.ts +++ b/tests/usage/usage-summary.test.ts @@ -17,6 +17,26 @@ import { isUnresolvedRequestedModel } from "../../src/usage/model-identity"; const FIXED_NOW = Date.UTC(2026, 5, 28, 12, 0, 0); describe("custom usage windows", () => { + test("Pacific/Apia skipped day still reaches the preceding existing calendar date", () => { + const previous = process.env.TZ; + process.env.TZ = "Pacific/Apia"; + try { + const start = new Date(2011, 11, 29, 12).getTime(); + const end = new Date(2011, 11, 31, 12).getTime(); + expect(new Date(2011, 11, 30, 0).getDate()).toBe(31); + const accumulator = createUsageSummaryAccumulator({ window: { since: start, until: end } }); + accumulator.add(entry({ ts: start, requestId: "before-skip" })); + accumulator.add(entry({ ts: end, requestId: "after-skip" })); + const summary = accumulator.summarize("all", end); + expect(summary.days.map(day => day.date)).toEqual(["2011-12-29", "2011-12-31"]); + expect(summary.days.map(day => day.requests)).toEqual([1, 1]); + expect(summary.summary.requests).toBe(2); + } finally { + if (previous === undefined) delete process.env.TZ; + else process.env.TZ = previous; + } + }); + const since = new Date(2026, 1, 10, 12, 0, 0, 123).getTime(); const until = since + 3_600_000; From 5669413794ca54388782f6758171a81a2d1b361e Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 21:13:57 +0900 Subject: [PATCH 142/412] test(models): scope price errors to their dialog [skip ci] Exact gates log showed the fixture read an unrelated picker alert behind the modal. Keep all expected error text and mutation assertions. Co-authored-by: nordz0r <6949669+nordz0r@users.noreply.github.com> --- gui/tests/models-price-editor.test.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/gui/tests/models-price-editor.test.tsx b/gui/tests/models-price-editor.test.tsx index b759a8398e..a80180b893 100644 --- a/gui/tests/models-price-editor.test.tsx +++ b/gui/tests/models-price-editor.test.tsx @@ -219,7 +219,7 @@ describe("Models manual price editor", () => { expect(button("Reset to automatic").disabled).toBe(true); await click("Save"); expect(mutations).toHaveLength(0); - expect(container.querySelector('[role="alert"]')!.textContent).toContain("Enter input and output rates"); + expect(container.querySelector('dialog [role="alert"]')!.textContent).toContain("Enter input and output rates"); await fill(["0", "0"]); expect(inputs().map(input => input.value)).toEqual(["0", "0", "0", "0"]); const before = catalogReads; @@ -256,7 +256,7 @@ describe("Models manual price editor", () => { await fill([invalid]); await click("Save"); expect(mutations).toHaveLength(0); - expect(container.querySelector('[role="alert"]')!.textContent).toContain("finite number"); + expect(container.querySelector('dialog [role="alert"]')!.textContent).toContain("finite number"); } await fill(["1000000", "0", "0.000001", "0.5"]); await click("Save"); @@ -268,7 +268,7 @@ describe("Models manual price editor", () => { await mount(); await open(); expect(inputs().every(input => input.disabled)).toBe(true); - expect(container.querySelector('[role="alert"]')!.textContent).toContain("Could not load"); + expect(container.querySelector('dialog [role="alert"]')!.textContent).toContain("Could not load"); expect(testWindow.document.activeElement).toBe(button("Reload price")); await click("Reload price"); expect(mutations).toHaveLength(0); @@ -296,14 +296,14 @@ describe("Models manual price editor", () => { expect(mutations).toHaveLength(1); expect(inputs().every(input => input.disabled)).toBe(true); expect(button("Reset to automatic").disabled).toBe(true); - expect(container.querySelector('[role="alert"]')!.textContent).toContain("may have changed"); + expect(container.querySelector('dialog [role="alert"]')!.textContent).toContain("may have changed"); await act(async () => button("Reset to automatic").dispatchEvent(new testWindow.MouseEvent("click", { bubbles: true }))); expect(mutations).toHaveLength(1); getFailure = true; await click("Reload price"); expect(mutations).toHaveLength(1); expect(inputs()[0]!.disabled).toBe(true); - expect(container.querySelector('[role="alert"]')!.textContent).toContain("Editing stays locked"); + expect(container.querySelector('dialog [role="alert"]')!.textContent).toContain("Editing stays locked"); getFailure = false; await click("Reload price"); expect(inputs().map(input => input.value)).toEqual(["0", "0", "0", "0"]); @@ -396,10 +396,10 @@ describe("Models manual price editor", () => { await click("Reset to automatic"); expect(mutations).toHaveLength(1); expect(inputs().every(input => input.disabled)).toBe(true); - expect(container.querySelector('[role="alert"]')!.textContent).toContain("price was saved"); + expect(container.querySelector('dialog [role="alert"]')!.textContent).toContain("price was saved"); await click("Refresh list"); expect(mutations).toHaveLength(1); - expect(container.querySelector('[role="alert"]')!.textContent).toContain("price was saved"); + expect(container.querySelector('dialog [role="alert"]')!.textContent).toContain("price was saved"); expect(reads).toHaveLength(1); catalogFailure = false; await click("Refresh list"); From fe9460372597061f572beee6c325009fef618c42 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 19:14:02 +0900 Subject: [PATCH 143/412] fix(usage): encode custom report identity as a tuple [skip ci] Keep cache identity as technical data rather than a UI-string-shaped template. No locale or lint-rule changes. Co-authored-by: Manson2438 <183030642+Manson2438@users.noreply.github.com> --- gui/src/pages/Usage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/src/pages/Usage.tsx b/gui/src/pages/Usage.tsx index 36b0d4ba82..7895ce9370 100644 --- a/gui/src/pages/Usage.tsx +++ b/gui/src/pages/Usage.tsx @@ -830,7 +830,7 @@ export default function Usage({ apiBase, connected = false, apiKeyId }: { apiBas }, [apiBase, apiKeyId, connected, range, scope, surface, since, until]); const presetKey = usageCacheKey(apiBase, range, surface, connected, scope, apiKeyId); - const resourceKey = customWindow ? `${presetKey}:custom:${since}:${until}` : presetKey; + const resourceKey = customWindow ? JSON.stringify([presetKey, since, until]) : presetKey; // Arbitrary custom windows belong only to the subscription-scoped resource store. const cached = customWindow ? null : readHeldUsage(apiBase, range, surface, connected, scope, apiKeyId); // Range and surface identify different reports, so the key changes with both. That prevents From 8ecf91fc88d8dc07f429f590b74880f25f9f4a3a Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 19:48:57 +0900 Subject: [PATCH 144/412] feat(gui): add guarded routed model picker drag ordering [skip ci] Add Custom routed ordering with fixed featured rows, keyboard controls, fresh settings snapshots and accepted-receipt recovery. Preserve native complete orders until an explicit preset/reset is accepted. Include source regressions and all nine locale strings; runtime checks await central CI. Implements the routed slice requested in #3774; native/featured full-picker placement remains open. Co-authored-by: leonclab <26379556+leonclab@users.noreply.github.com> --- .../src/content/docs/guides/model-ordering.md | 21 + gui/src/components/ModelPickerOrderEditor.tsx | 172 +++++++++ gui/src/i18n/de.ts | 15 + gui/src/i18n/en.ts | 15 + gui/src/i18n/fr.ts | 15 + gui/src/i18n/ja.ts | 15 + gui/src/i18n/ko.ts | 15 + gui/src/i18n/ru.ts | 15 + gui/src/i18n/tr.ts | 15 + gui/src/i18n/zh-TW.ts | 15 + gui/src/i18n/zh.ts | 15 + gui/src/model-picker-order.ts | 76 +++- gui/src/pages/Models.tsx | 61 ++- gui/src/styles-models-workspace.css | 7 + gui/tests/model-picker-order-editor.test.tsx | 358 ++++++++++++++++++ gui/tests/model-picker-order.test.ts | 109 +++++- 16 files changed, 917 insertions(+), 22 deletions(-) create mode 100644 gui/src/components/ModelPickerOrderEditor.tsx create mode 100644 gui/tests/model-picker-order-editor.test.tsx diff --git a/docs-site/src/content/docs/guides/model-ordering.md b/docs-site/src/content/docs/guides/model-ordering.md index 2d33b409d8..5333b839ce 100644 --- a/docs-site/src/content/docs/guides/model-ordering.md +++ b/docs-site/src/content/docs/guides/model-ordering.md @@ -178,3 +178,24 @@ On **Models**, choose **Default**, **A–Z by model**, **Group by provider**, or The controls use `GET/PUT /api/subagent-models`: `chosen` and `available` retain saved roster choices, including disabled or missing models; `pickerAvailable` contains only eligible routed catalog ids. The Models page sends `pickerOrder` and `pickerOrderMode`, never `models`. Roster-only saves preserve picker settings. Invalid combined updates and failed persistence leave the previous picker/roster state intact. Routed-only presets keep the existing featured/native priority bands. They affect the Codex catalog and Claude discovery's routed groups; Claude's native prefix and explicit Desktop profile/alias ownership remain unchanged. OpenCodex guidance ranks and configured fallback settings are preserved, but native Codex's advertised five and recommended default can change with display priority. Saving does not restart clients; a catalog refresh may remain pending, and clients holding an old catalog may need reopening. + + +### Custom routed order + +Choose **Custom order** on Models to load a fresh routed snapshot. Drag a movable row before +another row, or use its Up/Down buttons, then **Save draft**. Featured routed rows stay at the +front in their configured rank and cannot move. Native rows are not shown; this is not a preview +of the complete native picker. Surviving saved rows keep their relative order and new candidates +follow the current candidate list. Every save sends the complete routed list, without changing +the featured roster. + +An order containing bare native ids remains protected until you explicitly apply a routed preset +or Default. Selecting a different option alone does not replace it. Unknown featured state blocks +editing. Before saving, the editor checks a fresh snapshot; changes preserve your draft and block +saving until **Reload and discard draft** loads current settings. Request failures retain the +draft. Accepted saves can still have a pending catalog refresh; reload before editing again. + +The editor also requires an unambiguous model identity for every routed candidate. If the model +catalog is incomplete, refresh the Models page before editing; reloading picker settings alone +cannot restore missing catalog identities. Featured choices are matched exactly without trimming; +duplicate choices use their last configured position, and canonical ids take precedence over raw ids. diff --git a/gui/src/components/ModelPickerOrderEditor.tsx b/gui/src/components/ModelPickerOrderEditor.tsx new file mode 100644 index 0000000000..3c379f8cce --- /dev/null +++ b/gui/src/components/ModelPickerOrderEditor.tsx @@ -0,0 +1,172 @@ +import { useCallback, useEffect, useEffectEvent, useLayoutEffect, useRef, useState } from "react"; +import { createBoundedFetch, type BoundedFetch } from "../bounded-fetch"; +import { readJsonOrThrow } from "../fetch-json"; +import { IconArrowDown, IconArrowUp, IconGrip } from "../icons"; +import { useT, type TKey } from "../i18n/shared"; +import { + customPickerRows, isPickerOrderSaved, isPickerOrderSettings, movePickerBefore, + pickerSnapshotSignature, stepPickerOrder, type PickerModelIdentity, type PickerOrderSaved, +} from "../model-picker-order"; + +type Receipt = PickerOrderSaved & { catalogRefresh?: unknown }; +type Snapshot = { signature: string; identities: string; order: string[]; fixed: string[] }; +const DRAG_TYPE = "application/x-ocx-picker-order"; +let dragSequence = 0; +/** Local drag identity, not a security token. Like newClientId, supports LAN HTTP. */ +function newDragToken(): string { + const sequence = ++dragSequence; + if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") { + try { return `${sequence}:${crypto.randomUUID()}`; } + catch { /* Some browsers expose randomUUID but reject it outside secure contexts. */ } + } + return `picker-${Date.now().toString(36)}-${sequence}`; +} + +export default function ModelPickerOrderEditor({ apiBase, active, identities, onAccepted, onBusyChange }: { + apiBase: string; active: boolean; identities: readonly PickerModelIdentity[]; + onAccepted: (receipt: Receipt) => void; onBusyChange: (busy: boolean) => void; +}) { + const t = useT(); + const [snapshot, setSnapshot] = useState(null); + const [draft, setDraft] = useState([]); + const [busy, setBusy] = useState(false); + const [blocked, setBlocked] = useState(null); + const [error, setError] = useState(false); + const [announcement, setAnnouncement] = useState(""); + const [dragging, setDragging] = useState(null); + const [over, setOver] = useState(null); + const drag = useRef<{ id: string; token: string } | null>(null); + const generation = useRef(0); + const flight = useRef(null); + const identitySignature = JSON.stringify(identities.map(({ provider, id, namespaced }) => [provider, id, namespaced])); + const latestIdentitySignature = useRef(identitySignature); + useLayoutEffect(() => { latestIdentitySignature.current = identitySignature; }, [identitySignature]); + const identityChanged = snapshot !== null && snapshot.identities !== identitySignature; + const disabled = !active || busy || !snapshot || blocked !== null || identityChanged; + const dirty = snapshot !== null && JSON.stringify(draft) !== JSON.stringify(snapshot.order); + const clearDrag = useCallback(() => { drag.current = null; setDragging(null); setOver(null); }, []); + + // Layout cleanup fences even A → B → A and unmount before a pending promise resumes. + useLayoutEffect(() => { + generation.current++; + setSnapshot(null); setDraft([]); setBlocked(null); setError(false); + return () => { + generation.current++; + flight.current?.controller.abort(); flight.current?.clear(); flight.current = null; + drag.current = null; onBusyChange(false); + }; + }, [apiBase, active, onBusyChange]); + useEffect(() => { clearDrag(); }, [disabled, snapshot, identitySignature, clearDrag]); + + const run = async (save: boolean) => { + if (!active || flight.current || (save && (disabled || !dirty))) return; + const owner = generation.current, bounded = createBoundedFetch(15_000); + flight.current = bounded; setBusy(true); onBusyChange(true); setError(false); clearDrag(); + const owns = () => generation.current === owner && flight.current === bounded; + const current = () => owns() && !bounded.signal.aborted + && latestIdentitySignature.current === identitySignature; + try { + const response = await fetch(`${apiBase}/api/subagent-models`, { signal: bounded.signal }); + if (!current()) return; + const settings = await readJsonOrThrow(response); + if (!current()) return; + if (!isPickerOrderSettings(settings)) throw new Error("Invalid picker settings"); + const signature = pickerSnapshotSignature(apiBase, owner, settings); + if (save && (!snapshot || signature !== snapshot.signature || identitySignature !== snapshot.identities)) { + setBlocked("models.pickerOrder.changed"); return; + } + const rows = customPickerRows(settings, identities); + if (!rows) { + setBlocked(settings.pickerOrder.some(id => !id.includes("/")) + ? "models.pickerOrder.nativeLocked" : settings.chosen === undefined + ? "models.pickerOrder.unknownChosen" : "models.pickerOrder.catalogRequired"); + return; + } + if (!save) { + setSnapshot({ ...rows, signature, identities: identitySignature }); setDraft(rows.order); + setBlocked(null); setAnnouncement(""); return; + } + const result = await fetch(`${apiBase}/api/subagent-models`, { + method: "PUT", headers: { "Content-Type": "application/json" }, signal: bounded.signal, + body: JSON.stringify({ pickerOrder: draft, pickerOrderMode: null }), + }); + if (!current()) return; + const receipt = await readJsonOrThrow(result); + if (!current()) return; + if (!isPickerOrderSaved(receipt) || !("ok" in receipt) || receipt.ok !== true) throw new Error("Invalid picker receipt"); + setDraft(receipt.pickerOrder); setBlocked("models.pickerOrder.savedReload"); + onAccepted({ pickerOrder: receipt.pickerOrder, pickerOrderMode: receipt.pickerOrderMode, + catalogRefresh: "catalogRefresh" in receipt ? receipt.catalogRefresh : undefined }); + } catch { + if (owns() && latestIdentitySignature.current === identitySignature) setError(true); + // Current-identity timeouts surface an error; stale identities retain the draft silently. + } finally { + bounded.clear(); + if (owns()) { flight.current = null; setBusy(false); onBusyChange(false); } + } + }; + const enter = useEffectEvent(() => { void run(false); }); + useEffect(() => { if (active) enter(); }, [apiBase, active]); + + const move = (id: string, next: string[]) => { + if (disabled) return; + setDraft(next); + setAnnouncement(t("models.pickerOrder.position", { model: id, position: next.indexOf(id) + 1, total: next.length })); + clearDrag(); + }; + const movable = (id: string) => !disabled && draft.includes(id) && !snapshot?.fixed.includes(id); + return
+

{t("models.pickerOrder.editorHint")}

+ {(blocked || identityChanged) &&

{t(blocked ?? "models.pickerOrder.changed")}

} + {error &&

{t("models.pickerOrder.requestFailed")}

} + {snapshot && draft.length === 0 &&

{t("models.pickerOrder.empty")}

} +
    + {draft.map((id, index) => { + const fixed = snapshot?.fixed.includes(id) === true; + return
  1. { + if (!drag.current || drag.current.id === id || !movable(drag.current.id) || !movable(id) + || !event.dataTransfer.types.includes(DRAG_TYPE)) return; + event.preventDefault(); event.dataTransfer.dropEffect = "move"; setOver(id); + }} + onDragLeave={() => setOver(null)} + onDrop={event => { + const source = drag.current; + if (source && source.id !== id && source.token === event.dataTransfer.getData(DRAG_TYPE) && movable(source.id) && movable(id)) { + event.preventDefault(); move(source.id, movePickerBefore(draft, source.id, id, snapshot?.fixed ?? [])); + } + clearDrag(); + }} onDragEnd={clearDrag}> + + {id} + {fixed && {t("models.pickerOrder.featured")}} + + + + +
  2. ; + })} +
+

{announcement}

+
+ + +
+
; +} diff --git a/gui/src/i18n/de.ts b/gui/src/i18n/de.ts index 79d1591728..d413e1277c 100644 --- a/gui/src/i18n/de.ts +++ b/gui/src/i18n/de.ts @@ -2625,4 +2625,19 @@ export const de: Record = { "usage.range.invalid": "Geben Sie gültige lokale Daten und Uhrzeiten ab 1970-01-01 UTC ein.", "usage.range.reversed": "Das Ende muss auf oder nach dem Beginn liegen.", "usage.range.applied": "Ausgewählter Zeitraum: {start} – {end} (beide Grenzen eingeschlossen).", + "models.pickerOrder.editorHint": "Routingsmodelle neu ordnen und den Entwurf speichern. Hervorgehobene Zeilen sind fest; native Modelle werden nicht angezeigt.", + "models.pickerOrder.nativeLocked": "Diese Reihenfolge enthält native Modelle. Vor der Bearbeitung eine Routing-Vorgabe oder Standard anwenden.", + "models.pickerOrder.unknownChosen": "Hervorgehobene Modelle sind unbekannt. Vor der Bearbeitung neu laden.", + "models.pickerOrder.changed": "Die Einstellungen haben sich geändert. Der Entwurf bleibt erhalten; erneutes Laden verwirft ihn und lädt die aktuellen Einstellungen.", + "models.pickerOrder.savedReload": "Reihenfolge gespeichert. Vor weiterer Bearbeitung aktuelle Einstellungen laden.", + "models.pickerOrder.requestFailed": "Anfrage fehlgeschlagen. Der Entwurf bleibt erhalten; erneut versuchen oder neu laden.", + "models.pickerOrder.empty": "Keine Routingmodelle verfügbar.", + "models.pickerOrder.dragModel": "{model} ziehen", + "models.pickerOrder.featured": "Hervorgehoben", + "models.pickerOrder.upModel": "{model} nach oben verschieben", + "models.pickerOrder.downModel": "{model} nach unten verschieben", + "models.pickerOrder.position": "{model}: Position {position} von {total}", + "models.pickerOrder.saveDraft": "Entwurf speichern", + "models.pickerOrder.reloadDraft": "Neu laden und Entwurf verwerfen", + "models.pickerOrder.catalogRequired": "Modellidentitäten fehlen oder sind mehrdeutig. Laden Sie die Modellseite neu, um den Katalog vor der Bearbeitung zu aktualisieren.", }; diff --git a/gui/src/i18n/en.ts b/gui/src/i18n/en.ts index cceef53d12..b842f4618c 100644 --- a/gui/src/i18n/en.ts +++ b/gui/src/i18n/en.ts @@ -2659,6 +2659,21 @@ export const en = { "usage.range.invalid": "Enter valid local dates and times, on or after 1970-01-01 UTC.", "usage.range.reversed": "The end must be at or after the start.", "usage.range.applied": "Selected interval: {start} – {end} (both inclusive).", + "models.pickerOrder.editorHint": "Reorder routed models, then save your draft. Featured rows are fixed; native models are not shown.", + "models.pickerOrder.nativeLocked": "This saved order includes native models. Apply a routed preset or Default before editing Custom.", + "models.pickerOrder.unknownChosen": "Featured choices are unknown. Reload before editing.", + "models.pickerOrder.changed": "Picker settings changed. Your draft is kept; reload to discard it and use current settings.", + "models.pickerOrder.savedReload": "Order saved. Reload current settings before editing again.", + "models.pickerOrder.requestFailed": "Request failed. Your draft is kept; retry or reload.", + "models.pickerOrder.empty": "No routed models are available.", + "models.pickerOrder.dragModel": "Drag {model}", + "models.pickerOrder.featured": "Featured", + "models.pickerOrder.upModel": "Move {model} up", + "models.pickerOrder.downModel": "Move {model} down", + "models.pickerOrder.position": "{model}: position {position} of {total}", + "models.pickerOrder.saveDraft": "Save draft", + "models.pickerOrder.reloadDraft": "Reload and discard draft", + "models.pickerOrder.catalogRequired": "Model identities are missing or ambiguous. Reload the Models page to refresh its catalog before editing Custom.", } as const; export type TKey = keyof typeof en; diff --git a/gui/src/i18n/fr.ts b/gui/src/i18n/fr.ts index 67b2586fe4..d07b7f7a16 100644 --- a/gui/src/i18n/fr.ts +++ b/gui/src/i18n/fr.ts @@ -2612,4 +2612,19 @@ export const fr: Record = { "usage.range.invalid": "Saisissez des dates et heures locales valides à partir du 1970-01-01 UTC.", "usage.range.reversed": "La fin doit être égale ou postérieure au début.", "usage.range.applied": "Période sélectionnée : {start} – {end} (bornes incluses).", + "models.pickerOrder.editorHint": "Réordonnez les modèles routés, puis enregistrez le brouillon. Les lignes mises en avant sont fixes ; les modèles natifs ne sont pas affichés.", + "models.pickerOrder.nativeLocked": "Cet ordre contient des modèles natifs. Appliquez un préréglage de routage ou Par défaut avant de le personnaliser.", + "models.pickerOrder.unknownChosen": "Les modèles mis en avant sont inconnus. Rechargez avant de modifier.", + "models.pickerOrder.changed": "Les paramètres ont changé. Le brouillon est conservé ; rechargez pour le supprimer et utiliser les paramètres actuels.", + "models.pickerOrder.savedReload": "Ordre enregistré. Rechargez les paramètres actuels avant de modifier à nouveau.", + "models.pickerOrder.requestFailed": "Échec de la requête. Le brouillon est conservé ; réessayez ou rechargez.", + "models.pickerOrder.empty": "Aucun modèle routé disponible.", + "models.pickerOrder.dragModel": "Faire glisser {model}", + "models.pickerOrder.featured": "Mis en avant", + "models.pickerOrder.upModel": "Monter {model}", + "models.pickerOrder.downModel": "Descendre {model}", + "models.pickerOrder.position": "{model} : position {position} sur {total}", + "models.pickerOrder.saveDraft": "Enregistrer le brouillon", + "models.pickerOrder.reloadDraft": "Recharger et supprimer le brouillon", + "models.pickerOrder.catalogRequired": "Les identités des modèles sont manquantes ou ambiguës. Rechargez la page Modèles pour actualiser le catalogue avant de personnaliser l’ordre.", }; diff --git a/gui/src/i18n/ja.ts b/gui/src/i18n/ja.ts index 92bb516827..1db94902c5 100644 --- a/gui/src/i18n/ja.ts +++ b/gui/src/i18n/ja.ts @@ -2646,4 +2646,19 @@ export const ja: Record = { "usage.range.invalid": "1970-01-01 UTC以降の有効な現地日時を入力してください。", "usage.range.reversed": "終了日時は開始日時と同じか、それ以降にしてください。", "usage.range.applied": "選択した期間:{start} – {end}(両端を含む)。", + "models.pickerOrder.editorHint": "ルーティングモデルを並べ替えて下書きを保存します。おすすめ行は固定され、ネイティブモデルは表示されません。", + "models.pickerOrder.nativeLocked": "保存済みの順序にネイティブモデルが含まれています。ルーティングのプリセットかデフォルトを適用してからカスタム順序を編集してください。", + "models.pickerOrder.unknownChosen": "おすすめモデルが不明です。再読み込みしてから編集してください。", + "models.pickerOrder.changed": "設定が変更されました。下書きは保持されます。再読み込みすると下書きを破棄し、現在の設定を使用します。", + "models.pickerOrder.savedReload": "順序を保存しました。再編集する前に現在の設定を読み込んでください。", + "models.pickerOrder.requestFailed": "リクエストに失敗しました。下書きは保持されます。再試行するか再読み込みしてください。", + "models.pickerOrder.empty": "利用可能なルーティングモデルはありません。", + "models.pickerOrder.dragModel": "{model} をドラッグ", + "models.pickerOrder.featured": "おすすめ", + "models.pickerOrder.upModel": "{model} を上へ移動", + "models.pickerOrder.downModel": "{model} を下へ移動", + "models.pickerOrder.position": "{model}: {total} 件中 {position} 番目", + "models.pickerOrder.saveDraft": "下書きを保存", + "models.pickerOrder.reloadDraft": "下書きを破棄して再読み込み", + "models.pickerOrder.catalogRequired": "モデルの識別情報が不足しているか曖昧です。モデルページを再読み込みしてカタログを更新してからカスタム順序を編集してください。", }; diff --git a/gui/src/i18n/ko.ts b/gui/src/i18n/ko.ts index 7f02d3792f..b31d6e4e1a 100644 --- a/gui/src/i18n/ko.ts +++ b/gui/src/i18n/ko.ts @@ -2647,4 +2647,19 @@ export const ko: Record = { "usage.range.invalid": "1970-01-01 UTC 이후의 유효한 현지 날짜와 시간을 입력하세요.", "usage.range.reversed": "종료 시각은 시작 시각과 같거나 이후여야 합니다.", "usage.range.applied": "선택한 기간: {start} – {end} (양 끝 시각 포함).", + "models.pickerOrder.editorHint": "라우팅 모델의 순서를 바꾼 뒤 초안을 저장하세요. 추천 모델은 고정되며 네이티브 모델은 표시하지 않습니다.", + "models.pickerOrder.nativeLocked": "저장된 순서에 네이티브 모델이 포함되어 있습니다. 라우팅 프리셋이나 기본값을 적용한 뒤 사용자 지정 순서를 편집하세요.", + "models.pickerOrder.unknownChosen": "추천 모델 정보를 확인할 수 없습니다. 다시 불러온 뒤 편집하세요.", + "models.pickerOrder.changed": "모델 선택 설정이 바뀌었습니다. 초안은 유지됩니다. 다시 불러오면 초안을 버리고 현재 설정을 사용합니다.", + "models.pickerOrder.savedReload": "순서가 저장되었습니다. 다시 편집하려면 현재 설정을 불러오세요.", + "models.pickerOrder.requestFailed": "요청에 실패했습니다. 초안은 유지됩니다. 재시도하거나 다시 불러오세요.", + "models.pickerOrder.empty": "사용 가능한 라우팅 모델이 없습니다.", + "models.pickerOrder.dragModel": "{model} 끌어서 이동", + "models.pickerOrder.featured": "추천 모델", + "models.pickerOrder.upModel": "{model} 위로 이동", + "models.pickerOrder.downModel": "{model} 아래로 이동", + "models.pickerOrder.position": "{model}: {total}개 중 {position}번째", + "models.pickerOrder.saveDraft": "초안 저장", + "models.pickerOrder.reloadDraft": "초안 버리고 다시 불러오기", + "models.pickerOrder.catalogRequired": "모델 식별 정보가 없거나 모호합니다. 모델 페이지를 새로고침해 목록을 갱신한 뒤 사용자 지정 순서를 편집하세요.", }; diff --git a/gui/src/i18n/ru.ts b/gui/src/i18n/ru.ts index 9548be7d64..a8370e7f5f 100644 --- a/gui/src/i18n/ru.ts +++ b/gui/src/i18n/ru.ts @@ -2648,4 +2648,19 @@ export const ru: Record = { "usage.range.invalid": "Введите допустимые местные дату и время не ранее 1970-01-01 UTC.", "usage.range.reversed": "Конец не может быть раньше начала.", "usage.range.applied": "Выбранный период: {start} – {end} (обе границы включены).", + "models.pickerOrder.editorHint": "Измените порядок маршрутизируемых моделей и сохраните черновик. Избранные строки закреплены; нативные модели не показаны.", + "models.pickerOrder.nativeLocked": "Сохранённый порядок содержит нативные модели. Перед редактированием примените пресет маршрутизации или порядок по умолчанию.", + "models.pickerOrder.unknownChosen": "Избранные модели неизвестны. Перезагрузите данные перед редактированием.", + "models.pickerOrder.changed": "Настройки изменились. Черновик сохранён; перезагрузка сбросит его и загрузит текущие настройки.", + "models.pickerOrder.savedReload": "Порядок сохранён. Перед следующим редактированием загрузите текущие настройки.", + "models.pickerOrder.requestFailed": "Ошибка запроса. Черновик сохранён; повторите запрос или перезагрузите данные.", + "models.pickerOrder.empty": "Нет доступных маршрутизируемых моделей.", + "models.pickerOrder.dragModel": "Перетащить {model}", + "models.pickerOrder.featured": "Избранная", + "models.pickerOrder.upModel": "Переместить {model} вверх", + "models.pickerOrder.downModel": "Переместить {model} вниз", + "models.pickerOrder.position": "{model}: позиция {position} из {total}", + "models.pickerOrder.saveDraft": "Сохранить черновик", + "models.pickerOrder.reloadDraft": "Перезагрузить и сбросить черновик", + "models.pickerOrder.catalogRequired": "Идентификаторы моделей отсутствуют или неоднозначны. Перезагрузите страницу моделей, чтобы обновить каталог перед редактированием порядка.", }; diff --git a/gui/src/i18n/tr.ts b/gui/src/i18n/tr.ts index 7b835eb03e..6a7c02c936 100644 --- a/gui/src/i18n/tr.ts +++ b/gui/src/i18n/tr.ts @@ -2648,4 +2648,19 @@ export const tr: Record = { "usage.range.invalid": "1970-01-01 UTC veya sonrasına ait geçerli yerel tarih ve saat girin.", "usage.range.reversed": "Bitiş, başlangıçla aynı veya daha sonra olmalıdır.", "usage.range.applied": "Seçilen aralık: {start} – {end} (iki sınır da dahil).", + "models.pickerOrder.editorHint": "Yönlendirilen modelleri sıralayıp taslağı kaydedin. Öne çıkan satırlar sabittir; yerel modeller gösterilmez.", + "models.pickerOrder.nativeLocked": "Kayıtlı sıra yerel modeller içeriyor. Özel sırayı düzenlemeden önce yönlendirme ön ayarını veya Varsayılan seçeneğini uygulayın.", + "models.pickerOrder.unknownChosen": "Öne çıkan modeller bilinmiyor. Düzenlemeden önce yeniden yükleyin.", + "models.pickerOrder.changed": "Seçici ayarları değişti. Taslağınız korunuyor; yeniden yüklemek taslağı siler ve güncel ayarları kullanır.", + "models.pickerOrder.savedReload": "Sıra kaydedildi. Yeniden düzenlemeden önce güncel ayarları yükleyin.", + "models.pickerOrder.requestFailed": "İstek başarısız. Taslağınız korunuyor; tekrar deneyin veya yeniden yükleyin.", + "models.pickerOrder.empty": "Kullanılabilir yönlendirilen model yok.", + "models.pickerOrder.dragModel": "{model} modelini sürükle", + "models.pickerOrder.featured": "Öne çıkan", + "models.pickerOrder.upModel": "{model} modelini yukarı taşı", + "models.pickerOrder.downModel": "{model} modelini aşağı taşı", + "models.pickerOrder.position": "{model}: {total} içinde {position}. sıra", + "models.pickerOrder.saveDraft": "Taslağı kaydet", + "models.pickerOrder.reloadDraft": "Yeniden yükle ve taslağı sil", + "models.pickerOrder.catalogRequired": "Model kimlikleri eksik veya belirsiz. Özel sırayı düzenlemeden önce kataloğu yenilemek için Modeller sayfasını yeniden yükleyin.", }; diff --git a/gui/src/i18n/zh-TW.ts b/gui/src/i18n/zh-TW.ts index cd0b7e17d3..d59fa6d6bc 100644 --- a/gui/src/i18n/zh-TW.ts +++ b/gui/src/i18n/zh-TW.ts @@ -2610,4 +2610,19 @@ export const zhTW: Record = { "usage.range.invalid": "請輸入不早於 1970-01-01 UTC 的有效本地日期和時間。", "usage.range.reversed": "結束時間必須等於或晚於開始時間。", "usage.range.applied": "所選範圍:{start} – {end}(包含兩端)。", + "models.pickerOrder.editorHint": "調整路由模型順序後儲存草稿。精選列固定,原生模型不在此顯示。", + "models.pickerOrder.nativeLocked": "已儲存的順序包含原生模型。請先套用路由預設或預設順序,再編輯自訂順序。", + "models.pickerOrder.unknownChosen": "精選模型資訊未知。請重新載入後再編輯。", + "models.pickerOrder.changed": "模型選擇設定已變更。草稿已保留;重新載入將捨棄草稿並使用目前設定。", + "models.pickerOrder.savedReload": "順序已儲存。再次編輯前請重新載入目前設定。", + "models.pickerOrder.requestFailed": "請求失敗。草稿已保留;請重試或重新載入。", + "models.pickerOrder.empty": "沒有可用的路由模型。", + "models.pickerOrder.dragModel": "拖曳 {model}", + "models.pickerOrder.featured": "精選", + "models.pickerOrder.upModel": "上移 {model}", + "models.pickerOrder.downModel": "下移 {model}", + "models.pickerOrder.position": "{model}:第 {position} 位,共 {total} 個", + "models.pickerOrder.saveDraft": "儲存草稿", + "models.pickerOrder.reloadDraft": "捨棄草稿並重新載入", + "models.pickerOrder.catalogRequired": "模型識別資訊缺失或不明確。請重新載入模型頁面以更新目錄,再編輯自訂順序。", }; diff --git a/gui/src/i18n/zh.ts b/gui/src/i18n/zh.ts index d9f93f20c7..d20318ce42 100644 --- a/gui/src/i18n/zh.ts +++ b/gui/src/i18n/zh.ts @@ -2646,4 +2646,19 @@ export const zh: Record = { "usage.range.invalid": "请输入不早于 1970-01-01 UTC 的有效本地日期和时间。", "usage.range.reversed": "结束时间必须等于或晚于开始时间。", "usage.range.applied": "所选范围:{start} – {end}(包含两端)。", + "models.pickerOrder.editorHint": "调整路由模型顺序后保存草稿。精选行固定,原生模型不在此显示。", + "models.pickerOrder.nativeLocked": "已保存的顺序包含原生模型。请先应用路由预设或默认顺序,再编辑自定义顺序。", + "models.pickerOrder.unknownChosen": "精选模型信息未知。请重新加载后再编辑。", + "models.pickerOrder.changed": "模型选择设置已更改。草稿已保留;重新加载将丢弃草稿并使用当前设置。", + "models.pickerOrder.savedReload": "顺序已保存。再次编辑前请重新加载当前设置。", + "models.pickerOrder.requestFailed": "请求失败。草稿已保留;请重试或重新加载。", + "models.pickerOrder.empty": "没有可用的路由模型。", + "models.pickerOrder.dragModel": "拖动 {model}", + "models.pickerOrder.featured": "精选", + "models.pickerOrder.upModel": "上移 {model}", + "models.pickerOrder.downModel": "下移 {model}", + "models.pickerOrder.position": "{model}:第 {position} 位,共 {total} 个", + "models.pickerOrder.saveDraft": "保存草稿", + "models.pickerOrder.reloadDraft": "丢弃草稿并重新加载", + "models.pickerOrder.catalogRequired": "模型标识信息缺失或不明确。请重新加载模型页面以刷新目录,再编辑自定义顺序。", }; diff --git a/gui/src/model-picker-order.ts b/gui/src/model-picker-order.ts index dfa5073b08..0de6190f02 100644 --- a/gui/src/model-picker-order.ts +++ b/gui/src/model-picker-order.ts @@ -11,7 +11,7 @@ export interface PickerOrderSaved { pickerOrder: string[]; pickerOrderMode: SavedModelPickerOrderMode | null; } -export interface PickerOrderSettings extends PickerOrderSaved { pickerAvailable: string[] } +export interface PickerOrderSettings extends PickerOrderSaved { pickerAvailable: string[]; chosen?: string[] } function stringList(value: unknown): value is string[] { return Array.isArray(value) && value.every(id => typeof id === "string" && id.trim().length > 0); @@ -25,7 +25,11 @@ export function isPickerOrderSaved(value: unknown): value is PickerOrderSaved { return stringList(row.pickerOrder) && savedMode(row.pickerOrderMode); } export function isPickerOrderSettings(value: unknown): value is PickerOrderSettings { - return isPickerOrderSaved(value) && stringList((value as PickerOrderSettings).pickerAvailable); + if (!isPickerOrderSaved(value)) return false; + const row = value as PickerOrderSettings; + // Roster writes accept every string, including blanks; picker fields remain nonempty-string lists. + return stringList(row.pickerAvailable) && (!("chosen" in row) + || (Array.isArray(row.chosen) && row.chosen.every(id => typeof id === "string"))); } export function isModelPickerUsage(value: unknown): value is ModelPickerUsage[] { return Array.isArray(value) && value.every(row => row !== null && typeof row === "object" @@ -104,3 +108,71 @@ export function modelPickerOrderMode( } return "custom"; } + + +/** Resolve exact canonical ids before legacy provider/raw spellings; never guess a bare native id. */ +export function normalizePickerIds(ids: readonly string[], available: readonly string[], identities: readonly PickerModelIdentity[]): string[] { + const candidates = new Set(available.filter(id => id.includes("/"))); + const resolve = (id: string): string | undefined => { + if (candidates.has(id)) return id; + const matches = new Set(identities.filter(row => candidates.has(row.namespaced) + && id === `${row.provider}/${row.id}`).map(row => row.namespaced)); + return matches.size === 1 ? [...matches][0] : undefined; + }; + return [...new Set(ids.map(id => resolve(id.trim())).filter((id): id is string => id !== undefined))]; +} + +export function pickerSnapshotSignature(apiBase: string, generation: number, settings: PickerOrderSettings): string { + return JSON.stringify([apiBase, generation, settings.pickerAvailable, settings.chosen ?? null, + settings.pickerOrder, settings.pickerOrderMode]); +} + +/** Every candidate needs one observed provider/raw identity, with no encoded/raw collisions. */ +export function pickerIdentityCoverage(available: readonly string[], identities: readonly PickerModelIdentity[]): boolean { + const candidates = new Set(available.filter(id => id.includes("/"))); + const rawBySlug = new Map>(), slugsByRaw = new Map>(); + for (const row of identities) { + if (!candidates.has(row.namespaced)) continue; + const raw = `${row.provider}/${row.id}`; + const raws = rawBySlug.get(row.namespaced) ?? new Set(); + const slugs = slugsByRaw.get(raw) ?? new Set(); + raws.add(raw); slugs.add(row.namespaced); + rawBySlug.set(row.namespaced, raws); slugsByRaw.set(raw, slugs); + } + return [...candidates].every(slug => { + const raws = rawBySlug.get(slug); + return raws?.size === 1 && slugsByRaw.get([...raws][0]!)?.size === 1; + }); +} + +export function customPickerRows(settings: PickerOrderSettings, identities: readonly PickerModelIdentity[]): { order: string[]; fixed: string[] } | null { + // Unknown featured state and complete/native orders cannot safely become routed-only drafts. + if (settings.chosen === undefined || settings.pickerOrder.some(id => !id.includes("/"))) return null; + const available = [...new Set(settings.pickerAvailable.filter(id => id.includes("/")))]; + if (!pickerIdentityCoverage(available, identities)) return null; + // Roster strings stay verbatim. Map uses the LAST occurrence; each row prefers its exact canonical rank. + const chosenRank = new Map(settings.chosen.map((id, index) => [id, index])); + const rawBySlug = new Map(identities.map(row => [row.namespaced, `${row.provider}/${row.id}`])); + const rankOf = (slug: string) => chosenRank.get(slug) ?? chosenRank.get(rawBySlug.get(slug)!); + const fixed = available.filter(slug => rankOf(slug) !== undefined).sort((a, b) => rankOf(a)! - rankOf(b)!); + const saved = normalizePickerIds(settings.pickerOrder, available, identities); + return { fixed, order: [...new Set([...fixed, ...saved, ...available])] }; +} + +/** Drop semantics: remove first, re-find the target, then insert before it. */ +export function movePickerBefore(order: readonly string[], source: string, target: string, fixed: readonly string[]): string[] { + const next = [...order]; + if (source === target || fixed.includes(source) || fixed.includes(target) + || !next.includes(source) || !next.includes(target)) return next; + next.splice(next.indexOf(source), 1); + next.splice(next.indexOf(target), 0, source); + return next; +} + +/** Keyboard semantics deliberately differ from dropping before the next row. */ +export function stepPickerOrder(order: readonly string[], source: string, direction: -1 | 1, fixed: readonly string[]): string[] { + const next = [...order], index = next.indexOf(source), target = index + direction; + if (index < 0 || target < 0 || target >= next.length || fixed.includes(source) || fixed.includes(next[target]!)) return next; + [next[index], next[target]] = [next[target]!, next[index]!]; + return next; +} diff --git a/gui/src/pages/Models.tsx b/gui/src/pages/Models.tsx index bc010c4abc..55d9c16106 100644 --- a/gui/src/pages/Models.tsx +++ b/gui/src/pages/Models.tsx @@ -1,10 +1,11 @@ import { CodexStaleBanner } from "../components/codex-stale-banner"; +import ModelPickerOrderEditor from "../components/ModelPickerOrderEditor"; import ModelDisplayNameDialog from "../components/ModelDisplayNameDialog"; import ModelPriceDialog from "../components/ModelPriceDialog"; import { fetchCodexAppServerState } from "../codex-app-server-state"; import type { AppServerStateOutcome } from "../codex-app-server-state"; import { useCodexRestart } from "../use-codex-restart"; -import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react"; import { Switch, Notice, EmptyState, Select, Tooltip } from "../ui"; import { IconChevron, IconBoxes, IconInfo, IconCheck, IconAlert, IconRefresh, IconPencil } from "../icons"; import { useT } from "../i18n/shared"; @@ -18,7 +19,7 @@ import { setClientResourceData } from "../client-resource"; import { createBoundedFetch, type BoundedFetch } from "../bounded-fetch"; import { isModelPickerUsage, isPickerOrderSaved, isPickerOrderSettings, modelPickerOrder, modelPickerOrderMode, - type ModelPickerOrderMode, type PickerOrderSettings, type ModelPickerUsage, + type ModelPickerOrderMode, type PickerOrderSettings, type PickerOrderSaved, type ModelPickerUsage, } from "../model-picker-order"; import { startVisibilityPoll } from "../visibility-poll"; import { useDataSurface } from "../data-surface"; @@ -253,6 +254,7 @@ export default function Models({ apiBase, restartEpoch = 0 }: { apiBase: string; const [pickerDraft, setPickerDraft] = useState(null); const [pickerBusy, setPickerBusy] = useState(false); const pickerFlight = useRef(null); + const pickerGeneration = useRef(0); const pickerResource = useDataSurface( pickerCacheKey, [apiBase], useCallback(async (signal: AbortSignal) => { @@ -269,16 +271,22 @@ export default function Models({ apiBase, restartEpoch = 0 }: { apiBase: string; const pickerMode = pickerDraft ?? modelPickerOrderMode( pickerSettings?.pickerAvailable ?? [], pickerSettings?.pickerOrder ?? [], pickerSettings?.pickerOrderMode, ); - useEffect(() => { + useLayoutEffect(() => { + pickerGeneration.current++; setPickerDraft(null); setPickerBusy(false); return () => { + pickerGeneration.current++; pickerFlight.current?.controller.abort(); pickerFlight.current?.clear(); pickerFlight.current = null; cancelAppServerRead(); }; }, [apiBase, catalogActive, cancelAppServerRead]); + useLayoutEffect(() => { + // Pin inferred Custom before any late GET can switch mode and unmount its draft. + if (catalogActive && pickerDraft === null && pickerMode === "custom") setPickerDraft("custom"); + }, [catalogActive, pickerDraft, pickerMode]); const [customCap, setCustomCap] = useState(""); const [showCustom, setShowCustom] = useState(false); const [providerCapCustomOpen, setProviderCapCustomOpen] = useState>({}); @@ -1825,49 +1833,61 @@ export default function Models({ apiBase, restartEpoch = 0 }: { apiBase: string; ? groups.filter(group => group.provider === selectedProvider) : groups; + const acceptPickerOrder = (data: PickerOrderSaved & { catalogRefresh?: unknown }, custom = false) => { + // A receipt proves only the saved fields. No old chosen/available snapshot is promoted. + const next: PickerOrderSettings = { pickerOrder: data.pickerOrder, pickerOrderMode: data.pickerOrderMode, pickerAvailable: [] }; + setClientResourceData(pickerCacheKey, next); + writeSessionListCache(pickerCacheKey, next); + if (custom) setPickerDraft("custom"); + pickerResource.refresh(); + const refresh = data.catalogRefresh; + const converged = refresh !== null && typeof refresh === "object" + && "status" in refresh && refresh.status === "committed" + && "degraded" in refresh && refresh.degraded === false; + publishFeedback(converged, t(converged ? "models.pickerOrder.saved" : "models.pickerOrder.pending")); + void reloadAppServerState(); + }; + const savePickerOrder = async () => { if (pickerFlight.current || !pickerSettings || pickerResource.state.showError || pickerMode === "custom") return; + const owner = pickerGeneration.current; const mode = pickerMode; const available = pickerSettings.pickerAvailable; const bounded = createBoundedFetch(15_000); pickerFlight.current = bounded; setPickerBusy(true); + const owns = () => pickerGeneration.current === owner && pickerFlight.current === bounded; + const current = () => owns() && !bounded.signal.aborted; try { let usage: ModelPickerUsage[] = []; if (mode === "most-used") { const response = await fetch(`${apiBase}/api/usage?range=all&surface=all`, { signal: bounded.signal }); + if (!current()) return; const payload = await readJsonOrThrow<{ models?: unknown }>(response, t("models.pickerOrder.usageFailed")); + if (!current()) return; if (!isModelPickerUsage(payload?.models)) throw new Error(t("models.pickerOrder.usageFailed")); usage = payload.models; } + if (!current()) return; const order = modelPickerOrder(mode, available, usage, models); const response = await fetch(`${apiBase}/api/subagent-models`, { method: "PUT", headers: { "Content-Type": "application/json" }, signal: bounded.signal, body: JSON.stringify({ pickerOrder: order, pickerOrderMode: mode === "default" ? null : mode }), }); + if (!current()) return; const data = await readJsonOrThrow(response, t("models.saveFailed")); if (!isPickerOrderSaved(data) || !("ok" in data) || data.ok !== true) throw new Error(t("models.saveFailed")); - if (bounded.signal.aborted || pickerFlight.current !== bounded) return; - const next = { ...pickerSettings, pickerOrder: data.pickerOrder, pickerOrderMode: data.pickerOrderMode }; - // This aborts an older GET and advances the shared resource generation. - setClientResourceData(pickerCacheKey, next); - writeSessionListCache(pickerCacheKey, next); + if (!current()) return; + acceptPickerOrder({ pickerOrder: data.pickerOrder, pickerOrderMode: data.pickerOrderMode, + catalogRefresh: "catalogRefresh" in data ? data.catalogRefresh : undefined }); setPickerDraft(null); - - const refresh = "catalogRefresh" in data ? data.catalogRefresh : undefined; - const converged = refresh !== null && typeof refresh === "object" - && "status" in refresh && refresh.status === "committed" - && "degraded" in refresh && refresh.degraded === false; - publishFeedback(converged, t(converged ? "models.pickerOrder.saved" : "models.pickerOrder.pending")); - // Durable save is already accepted. Observational failure must not undo it. - void reloadAppServerState(); } catch (error) { - if (pickerFlight.current === bounded) { + if (owns()) { publishFeedback(false, error instanceof Error ? error.message : t("models.networkError")); } } finally { bounded.clear(); - if (pickerFlight.current === bounded) { pickerFlight.current = null; setPickerBusy(false); } + if (owns()) { pickerFlight.current = null; setPickerBusy(false); } } }; @@ -2039,7 +2059,7 @@ export default function Models({ apiBase, restartEpoch = 0 }: { apiBase: string; { value: "alphabetical", label: t("models.pickerOrder.alphabetical") }, { value: "provider", label: t("models.pickerOrder.provider") }, { value: "most-used", label: t("models.pickerOrder.mostUsed") }, - ...(pickerMode === "custom" ? [{ value: "custom", label: t("models.pickerOrder.custom") }] : []), + { value: "custom", label: t("models.pickerOrder.custom") }, ]} onChange={value => setPickerDraft(value as ModelPickerOrderMode)} disabled={pickerBusy || !pickerSettings || pickerResource.state.showError} @@ -2058,6 +2078,9 @@ export default function Models({ apiBase, restartEpoch = 0 }: { apiBase: string; } {t("models.pickerOrder.hint")} + {pickerMode === "custom" && acceptPickerOrder(data, true)} />} + {(() => { const customCount = models.filter(m => m.custom).length; diff --git a/gui/src/styles-models-workspace.css b/gui/src/styles-models-workspace.css index 6195a7b24f..67872711e2 100644 --- a/gui/src/styles-models-workspace.css +++ b/gui/src/styles-models-workspace.css @@ -648,3 +648,10 @@ } } .models-integration-warning { overflow-wrap: anywhere; } + +.picker-order-editor { margin-block: 12px; } +.picker-order-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 8px; } +.picker-order-row { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; padding-block: 4px; } +.picker-order-name { flex: 1; min-width: 0; overflow-wrap: anywhere; } +.picker-order-actions { display: inline-flex; flex-shrink: 0; gap: 2px; } +.picker-order-row .cwi-target-grip:disabled { cursor: default; opacity: 0.5; } diff --git a/gui/tests/model-picker-order-editor.test.tsx b/gui/tests/model-picker-order-editor.test.tsx new file mode 100644 index 0000000000..7cfeb6b326 --- /dev/null +++ b/gui/tests/model-picker-order-editor.test.tsx @@ -0,0 +1,358 @@ +import { afterEach, beforeEach, expect, test } from "bun:test"; +import { Window } from "happy-dom"; +import { act } from "react"; +import type { Root } from "react-dom/client"; +import Models from "../src/pages/Models"; +import { clearClientResourceStoresForTests, setClientResourceData } from "../src/client-resource"; +import ModelPickerOrderEditor from "../src/components/ModelPickerOrderEditor"; +import { LanguageProvider } from "../src/i18n/provider"; +import type { PickerModelIdentity, PickerOrderSettings, PickerOrderSaved } from "../src/model-picker-order"; + +const globals = ["document", "window", "navigator", "localStorage", "sessionStorage", "fetch", "crypto", "IS_REACT_ACT_ENVIRONMENT"] as const; +const ids: PickerModelIdentity[] = ["f", "a", "b", "c"].map(id => ({ provider: "p", id, namespaced: `p/${id}` })); +const initial = (): PickerOrderSettings => ({ pickerAvailable: ["p/f", "p/a", "p/b", "p/c"], + chosen: ["native", "p/f"], pickerOrder: ["p/a", "p/b", "p/c", "p/f"], pickerOrderMode: null }); +const changedDraft = ["p/f", "p/b", "p/a", "p/c"]; +function deferred() { + let resolve!: (value: T) => void, reject!: (error: Error) => void; + const promise = new Promise((yes, no) => { resolve = yes; reject = no; }); + return { promise, resolve, reject }; +} +type Request = ReturnType> & { url: string; method: string; body: unknown; signal?: AbortSignal | null }; +let previous: Map; +let win: Window, host: HTMLElement, root: Root | null; +let requests: Request[], receipts: Array, busy: boolean[]; +const onAccepted = (value: PickerOrderSaved & { catalogRefresh?: unknown }) => { receipts.push(value); }; +const onBusyChange = (value: boolean) => { busy.push(value); }; + +beforeEach(() => { + clearClientResourceStoresForTests(); + previous = new Map(globals.map(key => [key, Object.getOwnPropertyDescriptor(globalThis, key)])); + win = new Window({ url: "http://localhost/#models" }); + win.localStorage.setItem("ocx-lang", "en"); + const values = { document: win.document, window: win, navigator: win.navigator, + localStorage: win.localStorage, sessionStorage: win.sessionStorage, IS_REACT_ACT_ENVIRONMENT: true }; + for (const [key, value] of Object.entries(values)) Object.defineProperty(globalThis, key, { configurable: true, value }); + requests = []; receipts = []; busy = []; root = null; + Object.defineProperty(globalThis, "fetch", { configurable: true, value: (input: RequestInfo | URL, init?: RequestInit) => { + // Intentionally ignores abort: late network/body completion must be fenced by the component. + const request = { ...deferred(), url: String(input), method: init?.method ?? "GET", + body: init?.body ? JSON.parse(String(init.body)) : undefined, signal: init?.signal }; + requests.push(request); return request.promise; + } }); + host = document.createElement("div"); document.body.append(host); +}); +afterEach(async () => { + if (root) await act(async () => { root!.unmount(); }); + clearClientResourceStoresForTests(); + win.close(); + for (const key of globals) { + const descriptor = previous.get(key); + if (descriptor) Object.defineProperty(globalThis, key, descriptor); + else Reflect.deleteProperty(globalThis, key); + } +}); +async function render(apiBase = "/a", identities = ids, active = true) { + const { createRoot } = await import("react-dom/client"); + await act(async () => { + root ??= createRoot(host); + root.render(); + }); +} +async function reply(index: number, data: unknown, status = 200) { + await act(async () => { requests[index]!.resolve(Response.json(data, { status })); }); +} +const order = (within: ParentNode = host) => [...within.querySelectorAll(".picker-order-name")].map(row => row.textContent); +function button(name: string, within: ParentNode = host): HTMLButtonElement { + const found = [...within.querySelectorAll("button")] + .find(node => node.getAttribute("aria-label") === name || node.textContent === name); + if (!found) throw new Error(`Missing button: ${name}`); + return found; +} +async function click(name: string) { await act(async () => { button(name).click(); }); } +function row(id: string, within: ParentNode = host): HTMLElement { + const found = [...within.querySelectorAll("li")].find(node => node.querySelector("code")?.textContent === id); + if (!found) throw new Error(`Missing row: ${id}`); + return found; +} +function transfer() { + const data = new Map(); + return { effectAllowed: "uninitialized", dropEffect: "none", get types() { return [...data.keys()]; }, + setData: (type: string, value: string) => { data.set(type, value); }, getData: (type: string) => data.get(type) ?? "" }; +} +async function dragEvent(target: Element, type: string, dataTransfer: ReturnType) { + await act(async () => { + const event = new win.Event(type, { bubbles: true, cancelable: true }); + Object.defineProperty(event, "dataTransfer", { value: dataTransfer }); target.dispatchEvent(event); + }); +} +async function drop(source: string, target: string) { + const data = transfer(); + await dragEvent(button(`Drag ${source}`), "dragstart", data); + await dragEvent(row(target), "dragover", data); + await dragEvent(row(target), "drop", data); +} +async function edit() { await render(); await reply(0, initial()); await click("Move p/a down"); } + +// No sleeps, retries or real transport: each deferred settlement is explicitly released in act. +test("entering Custom reads a fresh GET each activation and only renders pickerAvailable", async () => { + await render("/a", ids, false); expect(requests).toHaveLength(0); + await render(); expect(requests.map(r => [r.url, r.method])).toEqual([["/a/api/subagent-models", "GET"]]); + expect(order()).toEqual([]); expect(busy.at(-1)).toBe(true); + await reply(0, { ...initial(), available: ["native", "other/roster-only"] }); + expect(order()).toEqual(["p/f", "p/a", "p/b", "p/c"]); expect(busy.at(-1)).toBe(false); + await render("/a", ids, false); await render(); expect(requests).toHaveLength(2); + await reply(1, { ...initial(), pickerOrder: ["p/c", "p/b", "p/a"] }); + expect(order()).toEqual(["p/f", "p/c", "p/b", "p/a"]); +}); + +for (const [name, override] of [ + ["missing", {}], ["null", { chosen: null }], ["non-array", { chosen: "p/f" }], ["invalid item", { chosen: [1] }], +] as const) test(`Custom cannot edit with ${name} chosen`, async () => { + await render(); + const { chosen: _chosen, ...settings } = initial(); + await reply(0, { ...settings, ...override }); + expect(order()).toEqual([]); expect(host.querySelector('[role="alert"]')).not.toBeNull(); + expect(button("Save draft").disabled).toBe(true); + await click("Save draft"); expect(requests).toHaveLength(1); +}); +test("saved bare native order remains locked without sending a replacement", async () => { + await render(); await reply(0, { ...initial(), pickerOrder: ["native", "p/a"] }); + expect(host.textContent).toContain("This saved order includes native models."); + expect(button("Save draft").disabled).toBe(true); expect(receipts).toEqual([]); + expect(requests.map(r => r.method)).toEqual(["GET"]); +}); + +test("forward/backward drop and Up/Down controls submit the complete routed list only", async () => { + await render(); await reply(0, initial()); + expect(button("Move p/f down").disabled).toBe(true); expect(button("Move p/a up").disabled).toBe(true); + await drop("p/a", "p/c"); expect(order()).toEqual(["p/f", "p/b", "p/a", "p/c"]); + await drop("p/c", "p/b"); expect(order()).toEqual(["p/f", "p/c", "p/b", "p/a"]); + button("Move p/c down").focus(); await click("Move p/c down"); + expect(order()).toEqual(["p/f", "p/b", "p/c", "p/a"]); + expect(document.activeElement).toBe(button("Move p/c down")); + await click("Move p/a up"); expect(order()).toEqual(changedDraft); + expect(host.querySelector('[role="status"]')?.textContent).toBe("p/a: position 3 of 4"); + await click("Save draft"); expect(requests.map(r => r.method)).toEqual(["GET", "GET"]); + await reply(1, initial()); + expect(requests[2]?.method).toBe("PUT"); + expect(requests[2]?.body).toEqual({ pickerOrder: changedDraft, pickerOrderMode: null }); +}); + +test("external, self, fixed and expired drag tokens cannot reorder", async () => { + await render(); await reply(0, initial()); + const original = ["p/f", "p/a", "p/b", "p/c"], external = transfer(); + external.setData("application/x-ocx-picker-order", "external"); + await dragEvent(row("p/b"), "drop", external); expect(order()).toEqual(original); + await drop("p/a", "p/a"); await drop("p/a", "p/f"); expect(order()).toEqual(original); + const local = transfer(); await dragEvent(button("Drag p/a"), "dragstart", local); + await dragEvent(row("p/b"), "drop", external); expect(order()).toEqual(original); + await dragEvent(row("p/b"), "drop", local); expect(order()).toEqual(original); + await dragEvent(button("Drag p/a"), "dragstart", local); + await dragEvent(row("p/a"), "dragend", local); + await dragEvent(row("p/c"), "drop", local); expect(order()).toEqual(original); +}); + +test("preflight roster drift blocks PUT, preserves draft, and requires explicit reload", async () => { + await edit(); await click("Save draft"); + const updated = { ...initial(), chosen: ["p/b"] }; + await reply(1, updated); + expect(order()).toEqual(changedDraft); expect(button("Save draft").disabled).toBe(true); + expect(host.textContent).toContain("Picker settings changed."); + await click("Save draft"); expect(requests.map(r => r.method)).toEqual(["GET", "GET"]); + await click("Reload and discard draft"); expect(order()).toEqual(changedDraft); + await reply(2, updated); expect(order()).toEqual(["p/b", "p/a", "p/c", "p/f"]); + expect(button("Move p/a down").disabled).toBe(false); expect(receipts).toEqual([]); +}); + +for (const failure of ["rejected", "malformed JSON", "malformed receipt", "network"] as const) + test(`failed PUT (${failure}) retains draft for a fresh preflight retry`, async () => { + await edit(); await click("Save draft"); await reply(1, initial()); + if (failure === "network") await act(async () => { requests[2]!.reject(new Error("offline")); }); + else if (failure === "malformed JSON") await act(async () => { requests[2]!.resolve(new Response("{")); }); + else await reply(2, failure === "rejected" ? { error: "refused" } : { ok: true, pickerOrder: [] }, failure === "rejected" ? 409 : 200); + expect(order()).toEqual(changedDraft); expect(receipts).toEqual([]); + expect(host.textContent).toContain("Request failed. Your draft is kept;"); + expect(button("Save draft").disabled).toBe(false); + await click("Save draft"); expect(requests[3]?.method).toBe("GET"); + await reply(3, initial()); expect(requests[4]?.body).toEqual({ pickerOrder: changedDraft, pickerOrderMode: null }); + }); + +test("pending accepted receipt publishes saved fields and requires reload before editing again", async () => { + await edit(); await click("Save draft"); await reply(1, initial()); + const accepted = { pickerOrder: changedDraft, pickerOrderMode: null, catalogRefresh: { status: "pending", degraded: true } }; + await reply(2, { ok: true, ...accepted, chosen: ["stale/receipt-choice"], pickerAvailable: ["stale/candidate"] }); + expect(receipts).toEqual([accepted]); expect(order()).toEqual(changedDraft); + expect(host.textContent).toContain("Order saved. Reload current settings before editing again."); + expect(button("Save draft").disabled).toBe(true); expect(button("Move p/a down").disabled).toBe(true); + expect(busy.at(-1)).toBe(false); expect(requests).toHaveLength(3); + await click("Reload and discard draft"); + await reply(3, { ...initial(), pickerOrder: changedDraft }); + expect(button("Move p/a down").disabled).toBe(false); +}); + +const stages = ["initial GET", "preflight GET", "preflight body", "PUT", "receipt body"] as const; +type Stage = typeof stages[number]; +async function pauseAt(stage: Stage): Promise<() => Promise> { + await render(); + if (stage === "initial GET") return () => reply(0, initial()); + await reply(0, initial()); await click("Move p/a down"); await click("Save draft"); + if (stage === "preflight GET") return () => reply(1, initial()); + if (stage !== "preflight body") await reply(1, initial()); + const accepted = { ok: true, pickerOrder: changedDraft, pickerOrderMode: null, catalogRefresh: { status: "pending" } }; + if (stage === "PUT") return () => reply(2, accepted); + const body = deferred(); let reads = 0; + const response = new Response(); + Object.defineProperty(response, "text", { value: () => { reads++; return body.promise; } }); + await act(async () => { requests[stage === "preflight body" ? 1 : 2]!.resolve(response); }); + expect(reads).toBe(1); // The deferred body is actually reached before changing owner/identity. + return async () => { await act(async () => { body.resolve(JSON.stringify(stage === "preflight body" ? initial() : accepted)); }); }; +} + +for (const stage of stages) { + test(`late ${stage} after unmount cannot write, publish a receipt or reset busy`, async () => { + const settle = await pauseAt(stage), count = requests.length; + await act(async () => { root!.unmount(); root = null; }); + const settledBusy = [...busy]; + expect(requests[count - 1]!.signal?.aborted).toBe(true); + await settle(); + expect(requests).toHaveLength(count); expect(receipts).toEqual([]); + expect(busy).toEqual(settledBusy); expect(host.textContent).toBe(""); + }); + test(`late ${stage} from API A→B→A cannot affect the new A flight`, async () => { + const settle = await pauseAt(stage); + await render("/b"); await render("/a"); + const count = requests.length, current = count - 1, settledBusy = [...busy]; + expect(requests[current]?.url).toBe("/a/api/subagent-models"); expect(busy.at(-1)).toBe(true); + expect(requests[current - 1]!.signal?.aborted).toBe(true); + await settle(); + expect(requests).toHaveLength(count); expect(receipts).toEqual([]); expect(order()).toEqual([]); + expect(busy).toEqual(settledBusy); // Old finally must not clear the successor's busy state. + await reply(current, { ...initial(), pickerOrder: ["p/c", "p/a", "p/b"] }); + expect(order()).toEqual(["p/f", "p/c", "p/a", "p/b"]); + }); + test(`identity drift during ${stage} suppresses stale snapshot, PUT and receipt publication`, async () => { + const settle = await pauseAt(stage), count = requests.length; + await render("/a", ids.map(row => row.id === "a" ? { ...row, id: "raw/a" } : row)); + await settle(); + expect(requests).toHaveLength(count); expect(receipts).toEqual([]); expect(busy.at(-1)).toBe(false); + expect(order()).toEqual(stage === "initial GET" ? [] : changedDraft); + expect(button("Save draft").disabled).toBe(true); + if (stage !== "initial GET") expect(host.textContent).toContain("Picker settings changed."); + // Reload, not the stale operation, is allowed to accept current identities. + await click("Reload and discard draft"); await reply(count, initial()); + expect(button("Move p/a down").disabled).toBe(false); + }); +} + + +for (const chosen of [[""], [" "]]) test(`blank chosen ${JSON.stringify(chosen)} keeps routed editing available`, async () => { + await render(); await reply(0, { ...initial(), chosen }); + expect(order()).toEqual(["p/a", "p/b", "p/c", "p/f"]); + expect(host.querySelector('[role="alert"]')).toBeNull(); + expect(button("Move p/f up").disabled).toBe(false); + await click("Move p/a down"); expect(button("Save draft").disabled).toBe(false); +}); + +for (const availability of ["absent", "throws"] as const) + test(`LAN drag with randomUUID ${availability}: same-editor works; cross-editor and stale tokens fail`, async () => { + Object.defineProperty(globalThis, "crypto", { configurable: true, value: availability === "absent" ? {} + : { randomUUID: () => { throw new Error("insecure context"); } } }); + const { createRoot } = await import("react-dom/client"); + await act(async () => { + root = createRoot(host); + root.render({["left", "right"].map(name =>
+ +
)}
); + }); + await reply(requests.findIndex(r => r.url === "/left/api/subagent-models"), initial()); + await reply(requests.findIndex(r => r.url === "/right/api/subagent-models"), initial()); + const left = host.querySelector('[data-editor="left"]')!; + const right = host.querySelector('[data-editor="right"]')!; + const original = ["p/f", "p/a", "p/b", "p/c"], type = "application/x-ocx-picker-order"; + const leftDrag = transfer(), rightDrag = transfer(); + await dragEvent(button("Drag p/a", left), "dragstart", leftDrag); + await dragEvent(button("Drag p/a", right), "dragstart", rightDrag); + expect(leftDrag.getData(type)).not.toBe(""); + expect(leftDrag.getData(type)).not.toBe(rightDrag.getData(type)); + // Both editors have active local drags: rejection must compare identities, not just presence. + await dragEvent(row("p/c", right), "drop", leftDrag); expect(order(right)).toEqual(original); + await dragEvent(row("p/c", left), "drop", leftDrag); expect(order(left)).toEqual(changedDraft); + const fresh = transfer(); await dragEvent(button("Drag p/b", left), "dragstart", fresh); + expect(fresh.getData(type)).not.toBe(leftDrag.getData(type)); + await dragEvent(row("p/c", left), "drop", leftDrag); expect(order(left)).toEqual(changedDraft); + await dragEvent(row("p/c", left), "drop", fresh); expect(order(left)).toEqual(changedDraft); + const ended = transfer(); await dragEvent(button("Drag p/b", left), "dragstart", ended); + await dragEvent(row("p/b", left), "dragend", ended); + await dragEvent(row("p/c", left), "drop", ended); expect(order(left)).toEqual(changedDraft); + const retry = transfer(); await dragEvent(button("Drag p/a", right), "dragstart", retry); + await dragEvent(row("p/c", right), "drop", retry); expect(order(right)).toEqual(changedDraft); + expect(requests.map(r => r.method)).toEqual(["GET", "GET"]); expect(receipts).toEqual([]); + }); + + +test("fresh legacy featured settings cannot unlock a row missing from the model identity catalog", async () => { + const settings = { pickerAvailable: ["p/team-model", "p/a"], chosen: ["p/team/model"], pickerOrder: [], pickerOrderMode: null }; + const a = { provider: "p", id: "a", namespaced: "p/a" }; + await render("/a", [a]); await reply(0, settings); + expect(order()).toEqual([]); expect(button("Save draft").disabled).toBe(true); + expect(host.textContent).toContain("Reload the Models page to refresh its catalog"); + await click("Reload and discard draft"); await reply(1, settings); + expect(order()).toEqual([]); // Settings-only reload cannot repair a missing model catalog. + await render("/a", [a, { provider: "p", id: "team/model", namespaced: "p/team-model" }]); + await click("Reload and discard draft"); await reply(2, settings); + expect(order()).toEqual(["p/team-model", "p/a"]); + expect(button("Drag p/team-model").disabled).toBe(true); + expect(requests.map(r => r.method)).toEqual(["GET", "GET", "GET"]); +}); + +test("duplicate featured choices use last occurrence and padded roster strings do not lock rows", async () => { + await render(); await reply(0, { ...initial(), chosen: ["p/a", "p/b", "p/a", " p/c "] }); + expect(order()).toEqual(["p/b", "p/a", "p/c", "p/f"]); + expect(button("Drag p/b").disabled).toBe(true); expect(button("Drag p/a").disabled).toBe(true); + expect(button("Drag p/c").disabled).toBe(false); +}); + +test("Models pins cache-inferred Custom across late parent GET publication, then resets on API change", async () => { + const modelRows = ids.map(row => ({ ...row, disabled: false })); + const catalog = { models: modelRows, providers: [{ name: "p" }], selectedModels: {}, disabled: [], + contextCaps: {}, contextCapValue: 350_000 }; + const custom = { ...initial(), pickerOrder: ["p/c", "p/a", "p/f", "p/b"] }; + for (const base of ["/a", "/b"]) { + win.sessionStorage.setItem(`ocx.models.catalog.v1:${base}`, JSON.stringify(catalog)); + win.sessionStorage.setItem(`ocx.models.catalog.v1:${base}:picker-order`, JSON.stringify(base === "/a" ? custom + : { ...initial(), pickerOrder: [] })); + } + const deferredFetch = globalThis.fetch; + Object.defineProperty(globalThis, "fetch", { configurable: true, value: (input: RequestInfo | URL, init?: RequestInit) => { + const path = String(input); + if (path.endsWith("/api/subagent-models")) return deferredFetch(input, init); + const payload = path.endsWith("/api/models") ? modelRows + : path.endsWith("/api/providers") ? catalog.providers + : path.endsWith("/api/provider-context-caps") ? { caps: {} } + : path.endsWith("/api/selected-models") ? { selected: {} } + : path.endsWith("/api/aliases") ? { providers: {}, models: {}, defaults: { global: false, providers: {} } } + : undefined; + return Promise.resolve(payload === undefined ? new Response(null, { status: 404 }) : Response.json(payload)); + } }); + const { createRoot } = await import("react-dom/client"); + await act(async () => { root = createRoot(host); root.render(); }); + // Parent resource and editor have separate initial reads; resolve both without relying on effect order. + const initialReads = requests.map((request, index) => ({ request, index })); + expect(initialReads).toHaveLength(2); + for (const { index } of initialReads) await reply(index, custom); + expect(order()).toEqual(["p/f", "p/c", "p/a", "p/b"]); + await click("Move p/a down"); const editor = host.querySelector(".picker-order-editor"); + expect(order()).toEqual(["p/f", "p/c", "p/b", "p/a"]); expect(button("Save draft").disabled).toBe(false); + // Integration seam: publish the same parent resource state a late GET would install. + const late = deferred(); + const publication = late.promise.then(value => setClientResourceData("ocx.models.catalog.v1:/a:picker-order", value)); + await act(async () => { late.resolve({ ...initial(), pickerOrderMode: "provider" }); await publication; }); + expect(host.querySelector(".picker-order-editor")).toBe(editor); + expect(order()).toEqual(["p/f", "p/c", "p/b", "p/a"]); expect(button("Save draft").disabled).toBe(false); + expect(requests.every(r => r.method === "GET")).toBe(true); + await act(async () => { root!.render(); }); + expect(host.querySelector(".picker-order-editor")).toBeNull(); +}); diff --git a/gui/tests/model-picker-order.test.ts b/gui/tests/model-picker-order.test.ts index 29c72c0b16..50f79d0b15 100644 --- a/gui/tests/model-picker-order.test.ts +++ b/gui/tests/model-picker-order.test.ts @@ -1,7 +1,7 @@ import { expect, test } from "bun:test"; import { summarizeUsage } from "../../src/usage/summary"; import type { PersistedUsageEntry } from "../../src/usage/log"; -import { isModelPickerUsage, isPickerOrderSaved, isPickerOrderSettings, modelPickerOrder, modelPickerOrderMode } from "../src/model-picker-order"; +import { pickerIdentityCoverage, customPickerRows, normalizePickerIds, pickerSnapshotSignature, movePickerBefore, stepPickerOrder, isModelPickerUsage, isPickerOrderSaved, isPickerOrderSettings, modelPickerOrder, modelPickerOrderMode } from "../src/model-picker-order"; const models = ["zeta/beta", "alpha/zeta", "alpha/alpha"]; @@ -77,3 +77,110 @@ test("real mixed-resolved usage summary never credits an entire legacy bucket to expect(modelPickerOrder("most-used", ["p/c", "p/b", "p/a"], summary.models)) .toEqual(["p/a", "p/b", "p/c"]); }); + + +test("Custom normalizes exact canonical names before provider/raw aliases, without native guesses", () => { + const identities = [ + { provider: "p", id: "team/model", namespaced: "p/team-model" }, + { provider: "p", id: "collision", namespaced: "p/a" }, + { provider: "p", id: "collision", namespaced: "p/b" }, + ]; + expect(normalizePickerIds(["p/team/model", "p/collision", "native", "p/team-model"], + ["p/team-model", "p/a", "p/b"], identities)).toEqual(["p/team-model"]); + expect(normalizePickerIds(["p/team/model"], ["p/team/model", "p/team-model"], identities)).toEqual(["p/team/model"]); +}); + +test("featured rank wins, survivors retain saved order, newcomers follow GET candidate order", () => { + expect(customPickerRows({ pickerAvailable: ["p/new", "p/b", "p/a", "p/top", "p/b"], + chosen: ["native", "p/top", "p/a", "missing/model"], pickerOrder: ["gone/model", "p/b", "p/a"], pickerOrderMode: null, + }, ["new", "b", "a", "top"].map(id => ({ provider: "p", id, namespaced: `p/${id}` })))).toEqual({ fixed: ["p/top", "p/a"], order: ["p/top", "p/a", "p/b", "p/new"] }); + expect(customPickerRows({ pickerAvailable: [], chosen: [], pickerOrder: [], pickerOrderMode: null }, [])) + .toEqual({ fixed: [], order: [] }); +}); + +test("unknown chosen cannot edit; malformed supplied chosen rejects; native saved ids remain untouched", () => { + const settings = { pickerAvailable: ["p/a"], pickerOrder: ["native", "p/a"], pickerOrderMode: null }; + expect(isPickerOrderSettings(settings)).toBe(true); + expect(customPickerRows(settings, [])).toBeNull(); + expect(customPickerRows({ ...settings, chosen: [] }, [])).toBeNull(); + expect(settings.pickerOrder).toEqual(["native", "p/a"]); + expect(customPickerRows({ ...settings, pickerOrder: [] }, [])).toBeNull(); + for (const chosen of [null, undefined, "p/a", [2]]) expect(isPickerOrderSettings({ ...settings, chosen })).toBe(false); + expect(isPickerOrderSettings({ ...settings, chosen: [] })).toBe(true); +}); + +test("snapshot binds base, activation, candidate sequence, chosen, saved order and provenance", () => { + const settings = { pickerAvailable: ["p/b", "p/a"], chosen: [], pickerOrder: ["p/a"], pickerOrderMode: null }; + const expected = '["/a",7,["p/b","p/a"],[],["p/a"],null]'; + expect(pickerSnapshotSignature("/a", 7, settings)).toBe(expected); + expect(pickerSnapshotSignature("/b", 7, settings)).not.toBe(expected); + expect(pickerSnapshotSignature("/a", 9, settings)).not.toBe(expected); // A → B → A + for (const changed of [ + { ...settings, pickerAvailable: ["p/a", "p/b"] }, { ...settings, chosen: ["p/a"] }, + { ...settings, pickerOrder: [] }, { ...settings, pickerOrderMode: "provider" as const }, + { pickerAvailable: settings.pickerAvailable, pickerOrder: settings.pickerOrder, pickerOrderMode: null }, + ]) expect(pickerSnapshotSignature("/a", 7, changed)).not.toBe(expected); +}); + +test("drop-before re-finds target after removal, while keyboard Down swaps adjacent movable rows", () => { + const order = ["p/featured", "p/a", "p/b", "p/c"], fixed = ["p/featured"]; + expect(movePickerBefore(order, "p/a", "p/c", fixed)).toEqual(["p/featured", "p/b", "p/a", "p/c"]); + expect(movePickerBefore(order, "p/c", "p/a", fixed)).toEqual(["p/featured", "p/c", "p/a", "p/b"]); + expect(movePickerBefore(order, "p/a", "p/b", fixed)).toEqual(order); + expect(stepPickerOrder(order, "p/a", 1, fixed)).toEqual(["p/featured", "p/b", "p/a", "p/c"]); + expect(stepPickerOrder(order, "p/c", -1, fixed)).toEqual(["p/featured", "p/a", "p/c", "p/b"]); + for (const [source, target] of [["outside", "p/a"], ["p/a", "outside"], ["p/a", "p/a"], ["p/featured", "p/b"], ["p/b", "p/featured"]]) + expect(movePickerBefore(order, source!, target!, fixed)).toEqual(order); + expect(stepPickerOrder(order, "p/a", -1, fixed)).toEqual(order); + expect(stepPickerOrder(order, "p/c", 1, fixed)).toEqual(order); + expect(order).toEqual(["p/featured", "p/a", "p/b", "p/c"]); +}); + + +test("blank roster strings retain GET compatibility and preset provenance without becoming featured rows", () => { + for (const blank of ["", " "]) { + const settings = { pickerAvailable: models, chosen: [blank], pickerOrder: ["alpha/alpha", "alpha/zeta", "zeta/beta"], + pickerOrderMode: "provider" as const }; + expect(isPickerOrderSettings(settings)).toBe(true); + expect(normalizePickerIds(settings.chosen, models, [])).toEqual([]); + const identities = [{ provider: "alpha", id: "alpha", namespaced: "alpha/alpha" }, + { provider: "alpha", id: "zeta", namespaced: "alpha/zeta" }, { provider: "zeta", id: "beta", namespaced: "zeta/beta" }]; + expect(customPickerRows(settings, identities)).toEqual({ fixed: [], order: ["alpha/alpha", "alpha/zeta", "zeta/beta"] }); + expect(modelPickerOrderMode(models, settings.pickerOrder, settings.pickerOrderMode)).toBe("provider"); + expect(modelPickerOrder("alphabetical", settings.pickerAvailable)).toEqual(["alpha/alpha", "zeta/beta", "alpha/zeta"]); + expect(settings.chosen).toEqual([blank]); // Normalization must not rewrite the saved roster. + expect(isPickerOrderSettings({ ...settings, pickerOrder: [""] })).toBe(false); + expect(isPickerOrderSettings({ ...settings, pickerAvailable: [" "] })).toBe(false); + } + expect(normalizePickerIds(["", " ", "alpha/zeta"], models, [])).toEqual(["alpha/zeta"]); +}); + + +test("incomplete or ambiguous catalog identities block projection, even with canonical candidates", () => { + const settings = { pickerAvailable: ["p/team-model", "p/a"], chosen: ["p/team/model"], pickerOrder: [], pickerOrderMode: null }; + const team = { provider: "p", id: "team/model", namespaced: "p/team-model" }; + const a = { provider: "p", id: "a", namespaced: "p/a" }; + for (const identities of [[], [a], [team], [team, a, { ...team, namespaced: "p/a" }], + [team, a, { ...team, id: "team-model" }]]) { + expect(pickerIdentityCoverage(settings.pickerAvailable, identities)).toBe(false); + expect(customPickerRows(settings, identities)).toBeNull(); + } + expect(pickerIdentityCoverage(settings.pickerAvailable, [team, a, { ...team }])).toBe(true); + expect(customPickerRows(settings, [team, a])).toEqual({ fixed: ["p/team-model"], order: ["p/team-model", "p/a"] }); +}); + +test("featured ranks use last duplicate, exact canonical precedence, and untrimmed roster strings", () => { + const identities = [{ provider: "p", id: "team/model", namespaced: "p/team-model" }, + { provider: "p", id: "a", namespaced: "p/a" }, { provider: "p", id: "b", namespaced: "p/b" }]; + const settings = { pickerAvailable: ["p/team-model", "p/a", "p/b"], pickerOrder: [], pickerOrderMode: null }; + expect(customPickerRows({ ...settings, chosen: ["p/a", "p/b", "p/a"] }, identities)) + .toEqual({ fixed: ["p/b", "p/a"], order: ["p/b", "p/a", "p/team-model"] }); + expect(customPickerRows({ ...settings, chosen: ["p/team/model", "p/b", "p/team-model"] }, identities)) + .toEqual({ fixed: ["p/b", "p/team-model"], order: ["p/b", "p/team-model", "p/a"] }); + expect(customPickerRows({ ...settings, chosen: ["p/team-model", "p/b", "p/team/model"] }, identities)) + .toEqual({ fixed: ["p/team-model", "p/b"], order: ["p/team-model", "p/b", "p/a"] }); + const chosen = [" p/a ", "", " "]; + expect(customPickerRows({ ...settings, chosen, pickerOrder: [" p/a "] }, identities)) + .toEqual({ fixed: [], order: ["p/a", "p/team-model", "p/b"] }); + expect(chosen).toEqual([" p/a ", "", " "]); +}); From dd8fb50b5e15ace4204ec7aa4ffb0d02df293c94 Mon Sep 17 00:00:00 2001 From: t Date: Mon, 7 Sep 2026 21:46:20 +0900 Subject: [PATCH 145/412] fix(gui): reconcile picker lifecycle outside synchronous effects [skip ci] Keep cancellation and stale-response fencing while separating render state reconciliation from automatic transport startup. Preserve immediate user actions and cover unmount before automatic request issuance. Co-authored-by: leonclab <26379556+leonclab@users.noreply.github.com> --- gui/src/components/ModelPickerOrderEditor.tsx | 61 ++++++++++++------- gui/tests/model-picker-order-editor.test.tsx | 18 ++++++ 2 files changed, 58 insertions(+), 21 deletions(-) diff --git a/gui/src/components/ModelPickerOrderEditor.tsx b/gui/src/components/ModelPickerOrderEditor.tsx index 3c379f8cce..1ca60c96b1 100644 --- a/gui/src/components/ModelPickerOrderEditor.tsx +++ b/gui/src/components/ModelPickerOrderEditor.tsx @@ -35,34 +35,48 @@ export default function ModelPickerOrderEditor({ apiBase, active, identities, on const [announcement, setAnnouncement] = useState(""); const [dragging, setDragging] = useState(null); const [over, setOver] = useState(null); - const drag = useRef<{ id: string; token: string } | null>(null); - const generation = useRef(0); - const flight = useRef(null); + const lifetime = useRef({ + generation: 0, + flight: null as BoundedFetch | null, + drag: null as { id: string; token: string } | null, + }); + const [activation, setActivation] = useState({ apiBase, active, onBusyChange }); const identitySignature = JSON.stringify(identities.map(({ provider, id, namespaced }) => [provider, id, namespaced])); const latestIdentitySignature = useRef(identitySignature); useLayoutEffect(() => { latestIdentitySignature.current = identitySignature; }, [identitySignature]); const identityChanged = snapshot !== null && snapshot.identities !== identitySignature; const disabled = !active || busy || !snapshot || blocked !== null || identityChanged; const dirty = snapshot !== null && JSON.stringify(draft) !== JSON.stringify(snapshot.order); - const clearDrag = useCallback(() => { drag.current = null; setDragging(null); setOver(null); }, []); + const clearDrag = useCallback(() => { lifetime.current.drag = null; setDragging(null); setOver(null); }, []); - // Layout cleanup fences even A → B → A and unmount before a pending promise resumes. + // Reconcile before committing children, like the existing display-name dialog. + if (activation.apiBase !== apiBase || activation.active !== active || activation.onBusyChange !== onBusyChange) { + setActivation({ apiBase, active, onBusyChange }); + setSnapshot(null); setDraft([]); setBlocked(null); setError(false); setBusy(false); + } + const [dragContext, setDragContext] = useState({ disabled, snapshot, identitySignature }); + if (dragContext.disabled !== disabled || dragContext.snapshot !== snapshot || dragContext.identitySignature !== identitySignature) { + setDragContext({ disabled, snapshot, identitySignature }); + setDragging(null); setOver(null); + } + + // Capture the stable holder, but always abort its CURRENT flight during cleanup. useLayoutEffect(() => { - generation.current++; - setSnapshot(null); setDraft([]); setBlocked(null); setError(false); + const holder = lifetime.current; + holder.generation++; return () => { - generation.current++; - flight.current?.controller.abort(); flight.current?.clear(); flight.current = null; - drag.current = null; onBusyChange(false); + holder.generation++; + holder.flight?.controller.abort(); holder.flight?.clear(); holder.flight = null; + holder.drag = null; onBusyChange(false); }; }, [apiBase, active, onBusyChange]); - useEffect(() => { clearDrag(); }, [disabled, snapshot, identitySignature, clearDrag]); + useLayoutEffect(() => { lifetime.current.drag = null; }, [disabled, snapshot, identitySignature]); const run = async (save: boolean) => { - if (!active || flight.current || (save && (disabled || !dirty))) return; - const owner = generation.current, bounded = createBoundedFetch(15_000); - flight.current = bounded; setBusy(true); onBusyChange(true); setError(false); clearDrag(); - const owns = () => generation.current === owner && flight.current === bounded; + if (!active || lifetime.current.flight || (save && (disabled || !dirty))) return; + const owner = lifetime.current.generation, bounded = createBoundedFetch(15_000); + lifetime.current.flight = bounded; setBusy(true); onBusyChange(true); setError(false); clearDrag(); + const owns = () => lifetime.current.generation === owner && lifetime.current.flight === bounded; const current = () => owns() && !bounded.signal.aborted && latestIdentitySignature.current === identitySignature; try { @@ -102,11 +116,16 @@ export default function ModelPickerOrderEditor({ apiBase, active, identities, on // Current-identity timeouts surface an error; stale identities retain the draft silently. } finally { bounded.clear(); - if (owns()) { flight.current = null; setBusy(false); onBusyChange(false); } + if (owns()) { lifetime.current.flight = null; setBusy(false); onBusyChange(false); } } }; - const enter = useEffectEvent(() => { void run(false); }); - useEffect(() => { if (active) enter(); }, [apiBase, active]); + const enter = useEffectEvent(async () => { + const holder = lifetime.current, owner = holder.generation; + // Automatic startup is cancellable before issuing transport; event actions stay immediate. + await Promise.resolve(); + if (active && holder.generation === owner) void run(false); + }); + useEffect(() => { if (active) void enter(); }, [apiBase, active, onBusyChange]); const move = (id: string, next: string[]) => { if (disabled) return; @@ -125,13 +144,13 @@ export default function ModelPickerOrderEditor({ apiBase, active, identities, on const fixed = snapshot?.fixed.includes(id) === true; return
  • { - if (!drag.current || drag.current.id === id || !movable(drag.current.id) || !movable(id) + if (!lifetime.current.drag || lifetime.current.drag.id === id || !movable(lifetime.current.drag.id) || !movable(id) || !event.dataTransfer.types.includes(DRAG_TYPE)) return; event.preventDefault(); event.dataTransfer.dropEffect = "move"; setOver(id); }} onDragLeave={() => setOver(null)} onDrop={event => { - const source = drag.current; + const source = lifetime.current.drag; if (source && source.id !== id && source.token === event.dataTransfer.getData(DRAG_TYPE) && movable(source.id) && movable(id)) { event.preventDefault(); move(source.id, movePickerBefore(draft, source.id, id, snapshot?.fixed ?? [])); } @@ -141,7 +160,7 @@ export default function ModelPickerOrderEditor({ apiBase, active, identities, on aria-label={t("models.pickerOrder.dragModel", { model: id })} onDragStart={event => { if (!movable(id)) { event.preventDefault(); return; } - const token = newDragToken(); drag.current = { id, token }; setDragging(id); + const token = newDragToken(); lifetime.current.drag = { id, token }; setDragging(id); event.dataTransfer.effectAllowed = "move"; event.dataTransfer.setData(DRAG_TYPE, token); }}>
  • ?NIwe(U$)(Yx_CmRi56@(YM%XRvF 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 literal 227826 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˙ICx6sUxBH$yMO@i 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