@bitkyc08/opencodex 2.84.0 → 2.87.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -4
- package/bin/ocx.mjs +61 -3
- package/gui/dist/assets/App-ZfYbLHkB.js +58 -0
- package/gui/dist/assets/App-wT3mXqFz.css +1 -0
- package/gui/dist/assets/{Tray-C9TGtwad.js → Tray-DCd-A1az.js} +1 -1
- package/gui/dist/assets/index-CfYDMj34.js +94 -0
- package/gui/dist/assets/index-DPeB9HpV.css +1 -0
- package/gui/dist/assets/quota-summary-ChvmKGOk.js +1 -0
- package/gui/dist/index.html +2 -2
- package/package.json +1 -2
- package/src/adapters/anthropic/beta-allowlist.ts +91 -11
- package/src/adapters/anthropic/beta-body-pairs.ts +93 -0
- package/src/adapters/anthropic/client-identity.ts +1 -1
- package/src/adapters/anthropic/passthrough.ts +16 -3
- package/src/adapters/anthropic-progress.ts +84 -0
- package/src/adapters/anthropic.ts +108 -21
- package/src/adapters/azure.ts +19 -1
- package/src/adapters/base.ts +2 -0
- package/src/adapters/claude-cli/adapter.ts +111 -23
- package/src/adapters/claude-cli/profiles.ts +2 -1
- package/src/adapters/claude-cli/stable-replay.ts +108 -0
- package/src/adapters/claude-cli/usage-admission.ts +230 -0
- package/src/adapters/client-fingerprint.ts +24 -0
- package/src/adapters/coding-agent/protocol.ts +1 -1
- package/src/adapters/coding-agent/turn.ts +40 -11
- package/src/adapters/cursor/arg-codec.ts +17 -5
- package/src/adapters/cursor/catalog.ts +8 -0
- package/src/adapters/cursor/effort-map.ts +3 -0
- package/src/adapters/cursor/freeform-args.ts +75 -0
- package/src/adapters/cursor/protobuf-events.ts +36 -23
- package/src/adapters/dsh-account.ts +97 -0
- package/src/adapters/google-antigravity-wire.ts +22 -1
- package/src/adapters/google.ts +37 -10
- package/src/adapters/openai-chat/messages.ts +4 -3
- package/src/adapters/openai-chat/passthrough.ts +8 -2
- package/src/adapters/openai-chat/reasoning-replay.ts +52 -0
- package/src/adapters/openai-chat/response-events.ts +59 -1
- package/src/adapters/openai-chat.ts +8 -5
- package/src/adapters/openai-responses/compaction-search-history.ts +14 -7
- package/src/adapters/openai-responses/passthrough.ts +57 -125
- package/src/adapters/openai-responses/request-strips.ts +25 -3
- package/src/adapters/openai-responses/transport.ts +81 -0
- package/src/adapters/qoder/adapter.ts +44 -3
- package/src/adapters/registry.ts +5 -0
- package/src/adapters/zed.ts +26 -1
- package/src/advisor/activity.ts +55 -0
- package/src/advisor/budget.ts +62 -0
- package/src/advisor/consult.ts +223 -0
- package/src/advisor/context.ts +238 -0
- package/src/advisor/disclosure.ts +20 -0
- package/src/advisor/evidence-tool.ts +21 -0
- package/src/advisor/evidence.ts +117 -0
- package/src/advisor/runtime.ts +353 -0
- package/src/advisor/settings.ts +144 -0
- package/src/advisor/state.ts +369 -0
- package/src/advisor/synthetic-tool.ts +33 -0
- package/src/bridge/errors.ts +24 -1
- package/src/bridge/internal.ts +3 -1
- package/src/bridge/response-json.ts +18 -3
- package/src/bridge/sse.ts +58 -8
- package/src/bridge/terminal-refusal.ts +59 -0
- package/src/chat/inbound.ts +30 -6
- package/src/chat/outbound.ts +5 -0
- package/src/claude/desktop-3p-library.ts +72 -7
- package/src/claude/desktop-3p.ts +75 -19
- package/src/claude/desktop-first-party.ts +1 -1
- package/src/claude/desktop-picker-platform.ts +4 -0
- package/src/claude/desktop-picker-profile.ts +11 -4
- package/src/claude/desktop-picker.ts +15 -8
- package/src/claude/desktop-profile.ts +10 -1
- package/src/claude/desktop-remote-store-io.ts +5 -3
- package/src/claude/desktop-system-proxy.ts +50 -4
- package/src/claude/inbound-content-options.ts +11 -0
- package/src/claude/inbound.ts +154 -50
- package/src/claude/intercept/local-ca.ts +8 -1
- package/src/claude/intercept/picker-ca-startup.ts +2 -1
- package/src/claude/intercept/picker-runtime.ts +6 -5
- package/src/claude/intercept/picker-trust-windows.ts +338 -0
- package/src/claude/intercept/picker-trust.ts +19 -0
- package/src/claude/intercept/port-policy.ts +30 -0
- package/src/claude/intercept/runtime.ts +97 -94
- package/src/claude/model-default-settings.ts +154 -0
- package/src/claude/model-info.ts +7 -7
- package/src/claude/outbound.ts +51 -19
- package/src/cli/account-api.ts +1 -0
- package/src/cli/account-policy-dto.ts +6 -0
- package/src/cli/account-policy.ts +34 -5
- package/src/cli/account-preservation.ts +44 -0
- package/src/cli/account.ts +8 -2
- package/src/cli/advisor.ts +165 -0
- package/src/cli/auxiliary-listener-preflight.ts +37 -0
- package/src/cli/capabilities-accounts.ts +20 -1
- package/src/cli/capabilities-agents-routing.ts +23 -2
- package/src/cli/capabilities-base.ts +39 -11
- package/src/cli/capabilities-observe-system.ts +63 -3
- package/src/cli/capabilities-provider-models.ts +11 -0
- package/src/cli/chatgpt-command.ts +35 -14
- package/src/cli/claude.ts +46 -6
- package/src/cli/codex-cli-update.ts +151 -41
- package/src/cli/codex-provider.ts +44 -0
- package/src/cli/combo-input.ts +10 -1
- package/src/cli/combo-result.ts +1 -1
- package/src/cli/combo.ts +2 -1
- package/src/cli/cross-home-owner.ts +17 -14
- package/src/cli/dispatch.ts +30 -5
- package/src/cli/doctor.ts +15 -1
- package/src/cli/ensure-desktop-cold-start.ts +382 -0
- package/src/cli/export-command.ts +1 -1
- package/src/cli/help.ts +4 -2
- package/src/cli/index.ts +14 -5
- package/src/cli/integration-plan-dto.ts +3 -0
- package/src/cli/log-history.ts +172 -0
- package/src/cli/models-runtime-subcommands.ts +1 -0
- package/src/cli/models-runtime.ts +72 -8
- package/src/cli/observe-stream.ts +2 -0
- package/src/cli/observe.ts +16 -4
- package/src/cli/provider.ts +27 -5
- package/src/cli/registry.ts +41 -9
- package/src/cli/restart-scope.ts +3 -1
- package/src/cli/runtime-api.ts +5 -3
- package/src/cli/system-command.ts +40 -8
- package/src/cli/uninstall-client-state.ts +32 -0
- package/src/cli/usage-compare.ts +309 -0
- package/src/cli/usage-model-search.ts +4 -4
- package/src/cli/usage-report.ts +2 -2
- package/src/cli/v2.ts +1 -1
- package/src/client/machine-listener.ts +1 -3
- package/src/client/runtime.ts +1 -0
- package/src/clients/client-path.ts +51 -0
- package/src/clients/config-export/contracts.ts +3 -1
- package/src/clients/config-export/model-metadata.ts +3 -2
- package/src/clients/config-export/qoder.ts +93 -0
- package/src/clients/config-export.ts +35 -48
- package/src/clients/gentle-shell-path.ts +87 -0
- package/src/codex/account-auto-switch.ts +2 -0
- package/src/codex/account-identity.ts +29 -0
- package/src/codex/account-label.ts +1 -1
- package/src/codex/account-lifecycle.ts +21 -5
- package/src/codex/account-preservation.ts +28 -0
- package/src/codex/account-use-remaining.ts +23 -0
- package/src/codex/app-server-processes.ts +97 -7
- package/src/codex/app-server-restart-service.ts +55 -4
- package/src/codex/auth-api/account-list.ts +4 -0
- package/src/codex/auth-api/account-pause-group.ts +6 -50
- package/src/codex/auth-api/account-preservation.ts +57 -0
- package/src/codex/auth-api/pool-mode-gate.ts +5 -2
- package/src/codex/auth-api/routes.ts +8 -0
- package/src/codex/auth-api/use-remaining-route.ts +36 -0
- package/src/codex/auth-api.ts +0 -1
- package/src/codex/auth-context.ts +81 -7
- package/src/codex/autostart-health.ts +4 -0
- package/src/codex/catalog/auto-review.ts +20 -3
- package/src/codex/catalog/build-entries.ts +19 -2
- package/src/codex/catalog/combo-member.ts +14 -5
- package/src/codex/catalog/configured-tiers.ts +50 -0
- package/src/codex/catalog/effort.ts +4 -1
- package/src/codex/catalog/gather-capture.ts +2 -0
- package/src/codex/catalog/metadata.ts +11 -9
- package/src/codex/catalog/model-hints.ts +42 -19
- package/src/codex/catalog/model-visibility.ts +3 -1
- package/src/codex/catalog/native-ultrafast.ts +106 -0
- package/src/codex/catalog/parsing.ts +35 -86
- package/src/codex/catalog/provider-models.ts +40 -34
- package/src/codex/catalog/retained-sync.ts +2 -0
- package/src/codex/catalog/routed-gather.ts +33 -16
- package/src/codex/catalog/vendor-context.ts +82 -0
- package/src/codex/cli-install-provenance.ts +105 -17
- package/src/codex/cli-update-plan.ts +545 -0
- package/src/codex/config-write-lock.ts +63 -4
- package/src/codex/convergence.ts +2 -0
- package/src/codex/desktop-app/picker-freshness.ts +96 -0
- package/src/codex/desktop-app/types.ts +2 -0
- package/src/codex/desktop-app/windows.ts +29 -16
- package/src/codex/desktop-app-restart.ts +25 -2
- package/src/codex/desktop-compatibility/certificate-service.ts +99 -0
- package/src/codex/desktop-compatibility/certificate-store.ts +193 -0
- package/src/codex/desktop-compatibility/connection-store.ts +87 -0
- package/src/codex/desktop-compatibility/installed-build.ts +73 -0
- package/src/codex/desktop-compatibility/json-body.ts +29 -0
- package/src/codex/desktop-compatibility/native-identity.ts +62 -0
- package/src/codex/desktop-compatibility/relay-listener.ts +93 -0
- package/src/codex/desktop-compatibility/routing-binding.ts +10 -0
- package/src/codex/desktop-compatibility/routing-preflight.ts +69 -0
- package/src/codex/desktop-compatibility/runtime-ownership.ts +28 -0
- package/src/codex/desktop-compatibility/runtime.ts +182 -0
- package/src/codex/desktop-compatibility/service.ts +30 -0
- package/src/codex/desktop-compatibility/startup-settings.ts +50 -0
- package/src/codex/desktop-compatibility/usage-activation.ts +86 -0
- package/src/codex/desktop-compatibility/usage-controlled-fetch.ts +59 -0
- package/src/codex/desktop-compatibility/usage-controller.ts +107 -0
- package/src/codex/desktop-compatibility/usage-policy.ts +59 -0
- package/src/codex/desktop-compatibility/usage-refresh.ts +33 -0
- package/src/codex/desktop-compatibility/usage-sse-controller.ts +86 -0
- package/src/codex/desktop-compatibility/windows-activation-source.ts +44 -0
- package/src/codex/desktop-compatibility/windows-certificate-trust.ts +81 -0
- package/src/codex/desktop-compatibility/windows-key-protection.ts +165 -0
- package/src/codex/desktop-compatibility/windows-package-command.ts +86 -0
- package/src/codex/desktop-compatibility/windows-package-launch.ts +28 -0
- package/src/codex/features.ts +85 -45
- package/src/codex/history-provider.ts +1 -1
- package/src/codex/inject/config-write-section.ts +4 -1
- package/src/codex/inject/history-failure.ts +27 -0
- package/src/codex/inject/remove.ts +18 -6
- package/src/codex/inject/restore.ts +24 -2
- package/src/codex/inject/routing-classify.ts +4 -3
- package/src/codex/inject.ts +18 -27
- package/src/codex/journal.ts +16 -1
- package/src/codex/main-account-hard-lock.ts +30 -1
- package/src/codex/main-account.ts +99 -15
- package/src/codex/native-main-refresh-mode.ts +217 -0
- package/src/codex/native-profile-startup.ts +1 -1
- package/src/codex/ocx-compaction-history.ts +12 -10
- package/src/codex/paths.ts +86 -1
- package/src/codex/provider-routing.ts +174 -0
- package/src/codex/refresh.ts +2 -2
- package/src/codex/routing/health-store.ts +2 -2
- package/src/codex/routing/pool-recovery.ts +79 -0
- package/src/codex/routing/selection.ts +4 -3
- package/src/codex/routing/thread-affinity.ts +1 -1
- package/src/codex/shim-diagnostics.ts +6 -0
- package/src/codex/shim-overlay.ts +7 -2
- package/src/codex/signed-in-identity.ts +43 -0
- package/src/codex/subagent-model-fallback.ts +1 -1
- package/src/codex/sync.ts +6 -1
- package/src/codex/user-identity.ts +16 -5
- package/src/codex/windows-local-appdata.ts +84 -0
- package/src/combos/failover.ts +6 -1
- package/src/combos/index.ts +1 -0
- package/src/combos/resolve.ts +46 -10
- package/src/combos/types.ts +15 -0
- package/src/config/diagnostics.ts +35 -7
- package/src/config/live-reconcile.ts +51 -2
- package/src/config/load-degrade.ts +23 -1
- package/src/config/opencode-wire-upgrade.ts +54 -0
- package/src/config/opencode-zen-upgrade.ts +52 -0
- package/src/config/owner-registry.ts +22 -17
- package/src/config/paths.ts +10 -3
- package/src/config/provider-validation.ts +45 -2
- package/src/config/schema/config-schema.ts +39 -0
- package/src/config/schema/desktop-compatibility.ts +9 -0
- package/src/config/schema/leaf-validators.ts +39 -9
- package/src/config/schema/main-account-hard-lock-fallback.ts +26 -0
- package/src/config/schema/native-reasoning-retention.ts +26 -0
- package/src/config.ts +2 -0
- package/src/generated/compatibility-version.json +962 -350
- package/src/generated/model-metadata.ts +1 -1
- package/src/grok/sync.ts +1 -1
- package/src/images/loop.ts +46 -8
- package/src/integrations/catalog-refresh.ts +1 -1
- package/src/integrations/config-io.ts +20 -2
- package/src/integrations/journal.ts +15 -1
- package/src/integrations/mutation-plan.ts +2 -0
- package/src/integrations/registry.ts +15 -0
- package/src/integrations/store.ts +3 -0
- package/src/integrations/writer.ts +10 -1
- package/src/lib/advisor-activation.ts +16 -0
- package/src/lib/background-work.ts +65 -0
- package/src/lib/bounded-file-read.ts +58 -0
- package/src/lib/bun-path-runtime.d.mts +10 -1
- package/src/lib/bun-path-runtime.mjs +62 -3
- package/src/lib/codex-restart-contract.ts +15 -0
- package/src/lib/desktop-proxy-route.ts +30 -0
- package/src/lib/desktop-upstream-tunnel.ts +72 -0
- package/src/lib/empty-tool-catalog.ts +62 -0
- package/src/lib/errors.ts +26 -3
- package/src/lib/gcp-adc.ts +96 -9
- package/src/lib/gcp-credential-input.ts +12 -0
- package/src/lib/lab-live-route-production.ts +5 -0
- package/src/lib/local-internal-call-capability.ts +55 -0
- package/src/lib/opaque-proxy-tunnel.ts +217 -0
- package/src/lib/package-tree-integrity.ts +2 -2
- package/src/lib/redact.ts +2 -2
- package/src/lib/socks5-fetch.ts +48 -71
- package/src/lib/socks5-handshake.ts +112 -0
- package/src/lib/translator-budget.ts +7 -1
- package/src/oauth/account-quota-rank.ts +69 -2
- package/src/oauth/anthropic-account-refusal.ts +20 -2
- package/src/oauth/anthropic-oauth-definitions.ts +3 -1
- package/src/oauth/anthropic-routing.ts +1 -21
- package/src/oauth/anthropic.ts +38 -7
- package/src/oauth/callback-server.ts +27 -1
- package/src/oauth/chatgpt-device.ts +1 -1
- package/src/oauth/chatgpt-shared.ts +83 -0
- package/src/oauth/chatgpt.ts +8 -72
- package/src/oauth/dsh.ts +203 -0
- package/src/oauth/generic-account-failover.ts +62 -12
- package/src/oauth/generic-session-affinity.ts +125 -0
- package/src/oauth/index.ts +188 -111
- package/src/oauth/kiro-device-login.ts +2 -1
- package/src/oauth/kiro.ts +7 -1
- package/src/oauth/local-token-detect.ts +21 -1
- package/src/oauth/login-cli-errors.ts +44 -0
- package/src/oauth/login-cli.ts +69 -7
- package/src/oauth/login-flow-state.ts +371 -23
- package/src/oauth/meta-muse-errors.ts +41 -0
- package/src/oauth/meta-muse-keychain.ts +52 -0
- package/src/oauth/meta-muse.ts +51 -84
- package/src/oauth/model-discovery-auth.ts +3 -0
- package/src/oauth/pool-settings-capability.ts +4 -2
- package/src/oauth/refresh-flight-retirement.ts +48 -0
- package/src/oauth/session-affinity-key.ts +23 -0
- package/src/oauth/store-anthropic-instance.ts +9 -2
- package/src/oauth/store.ts +12 -5
- package/src/protocols/codecs/chat-ir.ts +467 -0
- package/src/protocols/codecs/chat.ts +10 -1
- package/src/protocols/codecs/messages-ir.ts +500 -0
- package/src/protocols/encoders/adapter-events.ts +5 -4
- package/src/protocols/encoders/messages.ts +9 -6
- package/src/protocols/features.ts +10 -2
- package/src/protocols/path.ts +11 -1
- package/src/protocols/plan-snapshot.ts +39 -16
- package/src/protocols/plan.ts +9 -1
- package/src/protocols/provider-summary.ts +2 -1
- package/src/protocols/settings.ts +8 -0
- package/src/providers/antigravity-account-roster.ts +102 -0
- package/src/providers/antigravity-models.ts +85 -7
- package/src/providers/api-key-cooldowns.ts +49 -0
- package/src/providers/api-key-resolve.ts +11 -6
- package/src/providers/api-key-response-ownership.ts +57 -0
- package/src/providers/api-key-selection.ts +31 -6
- package/src/providers/api-keys.ts +214 -3
- package/src/providers/claude-cli-usage.ts +96 -0
- package/src/providers/dsh-account-destination.ts +31 -0
- package/src/providers/dsh-account-models.ts +41 -0
- package/src/providers/gcp-credential-cleanup.ts +59 -0
- package/src/providers/key-failover.ts +54 -50
- package/src/providers/key-store.ts +7 -2
- package/src/providers/model-rename-fields.ts +5 -0
- package/src/providers/model-rename-migration.ts +7 -5
- package/src/providers/openai-tiers-destination.ts +11 -2
- package/src/providers/openai-tiers.ts +5 -12
- package/src/providers/opencode-go-transport.ts +3 -1
- package/src/providers/quota/account-cache.ts +6 -5
- package/src/providers/quota/account-row.ts +34 -0
- package/src/providers/quota/antigravity.ts +28 -7
- package/src/providers/quota/dsh-account.ts +70 -0
- package/src/providers/quota/vendor-probes-oauth.ts +1 -93
- package/src/providers/quota-types.ts +2 -0
- package/src/providers/quota.ts +14 -20
- package/src/providers/registry/entries-core.ts +44 -14
- package/src/providers/registry/entries-extended.ts +19 -0
- package/src/providers/registry/types.ts +1 -1
- package/src/providers/request-pacing.ts +77 -19
- package/src/providers/routed-config.ts +339 -0
- package/src/providers/service-tier.ts +2 -1
- package/src/quota/window-mapping.ts +5 -2
- package/src/responses/anthropic-progress.ts +34 -0
- package/src/responses/assistant-replay.ts +35 -0
- package/src/responses/compaction-history-framing.ts +65 -0
- package/src/responses/compaction.ts +6 -1
- package/src/responses/incomplete-reason.ts +31 -0
- package/src/responses/parser.ts +78 -22
- package/src/responses/reasoning-envelope.ts +4 -0
- package/src/responses/reasoning-replay-cache.ts +24 -2
- package/src/responses/reasoning-retention.ts +173 -0
- package/src/responses/retained-compaction.ts +46 -0
- package/src/responses/schema.ts +23 -0
- package/src/responses/state.ts +32 -29
- package/src/router.ts +8 -321
- package/src/routing/health.ts +37 -22
- package/src/routing/history/build-file.ts +92 -0
- package/src/routing/history/indexer.ts +254 -221
- package/src/routing/history/ingest.ts +242 -0
- package/src/routing/history/rebuild-job.ts +111 -0
- package/src/routing/history/rebuild-protocol.ts +15 -0
- package/src/routing/history/rebuild-worker.ts +34 -0
- package/src/routing/profile.ts +1 -1
- package/src/server/admission-model-scope.ts +21 -1
- package/src/server/antigravity-direct-eligibility.ts +208 -0
- package/src/server/auth-cors.ts +15 -0
- package/src/server/chat-completions.ts +82 -10
- package/src/server/chat-native-reasoning.ts +123 -0
- package/src/server/chat-native-sse.ts +110 -7
- package/src/server/chat-native.ts +76 -17
- package/src/server/claude-messages.ts +164 -433
- package/src/server/effort-policy.ts +1 -1
- package/src/server/images.ts +15 -2
- package/src/server/index/desktop-compatibility-startup.ts +56 -0
- package/src/server/index/model-alias-id.ts +36 -0
- package/src/server/index/optional-listeners.ts +2 -0
- package/src/server/index/serve-options.ts +11 -3
- package/src/server/index/startup-warnings.ts +11 -0
- package/src/server/index/websocket-handler.ts +9 -0
- package/src/server/index.ts +14 -11
- package/src/server/inference/advisor-diagnostics.ts +31 -0
- package/src/server/inference/client-encoder-delivery.ts +6 -5
- package/src/server/login-shell-path.ts +146 -0
- package/src/server/management/advisor-routes.ts +202 -0
- package/src/server/management/agent-settings-routes.ts +22 -4
- package/src/server/management/claude-desktop-picker-routes.ts +1 -1
- package/src/server/management/combo-routes.ts +176 -50
- package/src/server/management/companion-routes.ts +4 -0
- package/src/server/management/config-routes.ts +77 -6
- package/src/server/management/context.ts +4 -0
- package/src/server/management/cursor-integration-routes.ts +1 -1
- package/src/server/management/desktop-compatibility-routes.ts +46 -0
- package/src/server/management/desktop-compatibility-runtime-routes.ts +46 -0
- package/src/server/management/desktop-compatibility-settings-routes.ts +27 -0
- package/src/server/management/model-routes.ts +13 -8
- package/src/server/management/model-rows.ts +14 -0
- package/src/server/management/native-integration-routes.ts +2 -7
- package/src/server/management/native-reasoning-retention-routes.ts +41 -0
- package/src/server/management/oauth-account-routes.ts +87 -14
- package/src/server/management/protocol-settings-patch.ts +1 -0
- package/src/server/management/provider-gcp-credential-routes.ts +29 -0
- package/src/server/management/provider-key-pacing-routes.ts +31 -0
- package/src/server/management/provider-overwrite-carry.ts +7 -0
- package/src/server/management/provider-routes.ts +25 -30
- package/src/server/management/route-registry.ts +21 -1
- package/src/server/management/sibling-guard.ts +1 -0
- package/src/server/management-api.ts +9 -1
- package/src/server/messages-antigravity-direct.ts +195 -0
- package/src/server/messages-native-tool-guard.ts +185 -0
- package/src/server/messages-native.ts +106 -22
- package/src/server/messages-shared.ts +431 -0
- package/src/server/relay.ts +1 -1
- package/src/server/request-log-terminal-status.ts +1 -1
- package/src/server/request-log.ts +13 -1
- package/src/server/responses/account-change-state.ts +8 -2
- package/src/server/responses/adapter-continuation.ts +48 -19
- package/src/server/responses/adapter-delivery.ts +43 -8
- package/src/server/responses/adapter-dispatch.ts +48 -4
- package/src/server/responses/advisor-plan-slot.ts +27 -0
- package/src/server/responses/advisor-retention.ts +117 -0
- package/src/server/responses/advisor-slot.ts +368 -0
- package/src/server/responses/code-mode-collab-surface.ts +116 -8
- package/src/server/responses/codex-ws-wire.ts +15 -8
- package/src/server/responses/compact.ts +303 -125
- package/src/server/responses/compaction-recovery.ts +18 -10
- package/src/server/responses/compaction-retention.ts +61 -0
- package/src/server/responses/context-overflow.ts +11 -6
- package/src/server/responses/core-auth.ts +6 -0
- package/src/server/responses/core-codex-account.ts +11 -1
- package/src/server/responses/core-combo-failure.ts +12 -1
- package/src/server/responses/core-combo.ts +141 -36
- package/src/server/responses/core-errors.ts +3 -3
- package/src/server/responses/core-lifetime.ts +7 -2
- package/src/server/responses/core-normalize.ts +11 -0
- package/src/server/responses/core-opaque-recovery.ts +35 -0
- package/src/server/responses/core-options.ts +51 -0
- package/src/server/responses/core-pipeline.ts +141 -0
- package/src/server/responses/core-replay.ts +25 -6
- package/src/server/responses/core.ts +3 -116
- package/src/server/responses/fetch-helpers.ts +73 -19
- package/src/server/responses/main-hard-lock-routing.ts +109 -0
- package/src/server/responses/native-response-control.ts +4 -2
- package/src/server/responses/passthrough-delivery.ts +19 -11
- package/src/server/responses/passthrough-dispatch.ts +29 -16
- package/src/server/responses/request-prepare.ts +144 -17
- package/src/server/responses/request-sidecar-auth.ts +2 -2
- package/src/server/responses/request-transport.ts +120 -27
- package/src/server/responses/response-effects.ts +1 -0
- package/src/server/responses/run-turn-execution.ts +166 -38
- package/src/server/responses/sidecar-execution.ts +98 -5
- package/src/server/responses/terminal-guard.ts +4 -17
- package/src/server/responses-undeclared-tool-guard.ts +30 -9
- package/src/server/startup-action-control.ts +16 -2
- package/src/server/startup-health-cache.ts +1 -0
- package/src/service/auth-preflight.ts +71 -0
- package/src/service/cli.ts +4 -2
- package/src/service/definition.ts +97 -0
- package/src/service/desktop-startup.ts +14 -0
- package/src/service/guards.ts +1 -61
- package/src/service/health-sentinel-linux.ts +112 -0
- package/src/service/health-sentinel-main.ts +99 -61
- package/src/service/health-sentinel-probe.ts +24 -7
- package/src/service/health.ts +5 -89
- package/src/service/launchd.ts +27 -7
- package/src/service/logging.ts +135 -0
- package/src/service/repair.ts +2 -1
- package/src/service/state.ts +7 -8
- package/src/service/systemd.ts +1 -1
- package/src/service/windows-guarded-manager.ts +2 -1
- package/src/service/windows-ops.ts +1 -1
- package/src/service/windows-scheduler.ts +2 -7
- package/src/service/windows-taskxml.ts +2 -2
- package/src/service/windows-wscript.ts +14 -0
- package/src/service.ts +4 -2
- package/src/sidecar/auth.ts +2 -0
- package/src/tray/windows-tray.ps1 +43 -24
- package/src/types/config.ts +124 -6
- package/src/types/opencode-go.ts +61 -0
- package/src/types/opencode-zen.ts +29 -0
- package/src/types/provider.ts +39 -6
- package/src/types/request.ts +38 -2
- package/src/types/tools.ts +2 -0
- package/src/types/wire.ts +29 -37
- package/src/types.ts +1 -0
- package/src/update/async-check.ts +1 -1
- package/src/update/badge.ts +2 -2
- package/src/update/index.ts +88 -15
- package/src/update/job-supervised-restart.ts +107 -0
- package/src/update/job.ts +32 -32
- package/src/update/notify.ts +1 -1
- package/src/update/npm-invocation.mjs +12 -2
- package/src/update/refresh-scheduler.ts +2 -2
- package/src/update/supervised-recovery.d.mts +27 -0
- package/src/update/supervised-recovery.mjs +157 -0
- package/src/usage/cache-diagnostic.ts +2 -0
- package/src/usage/cost.ts +48 -12
- package/src/usage/expected-prices.ts +15 -0
- package/src/usage/ledger-retention.ts +2 -1
- package/src/usage/ledger-scanner.ts +6 -5
- package/src/usage/log.ts +17 -8
- package/src/usage/summary.ts +22 -9
- package/src/usage/user-cost-overlays.ts +14 -19
- package/src/usage/user-cost-validation.ts +38 -0
- package/src/vision/eligibility.ts +13 -0
- package/src/web-search/gemini-executor.ts +2 -2
- package/src/web-search/loop.ts +55 -5
- package/src/web-search/progress-stream.ts +4 -1
- package/src/web-search/run-turn-loop.ts +9 -1
- package/assets/sponsors/packycode.png +0 -0
- package/gui/dist/assets/App-CSJvmjNs.css +0 -1
- package/gui/dist/assets/App-CZtqiGcw.js +0 -56
- package/gui/dist/assets/index-BB6uK6tU.css +0 -1
- package/gui/dist/assets/index-CTm4l-HQ.js +0 -94
- package/gui/dist/assets/quota-summary-BbEeRfPY.js +0 -1
|
@@ -27,10 +27,10 @@ import {
|
|
|
27
27
|
anthropicRoutingFor,
|
|
28
28
|
AnthropicAccountCooldownError,
|
|
29
29
|
formatAnthropicProviderForLog,
|
|
30
|
-
anthropicSessionKeyFromParts,
|
|
31
30
|
} from "../../oauth/anthropic-routing";
|
|
32
31
|
import {
|
|
33
32
|
OAuthAccountPausedError,
|
|
33
|
+
OAuthTokenRefreshBusyError,
|
|
34
34
|
getValidAccessSnapshotForAccount,
|
|
35
35
|
forceRefreshOAuthAccessSnapshot,
|
|
36
36
|
getValidAccessTokenSnapshot,
|
|
@@ -49,6 +49,9 @@ import {
|
|
|
49
49
|
refusalAwareInitialKiroAccount,
|
|
50
50
|
noteGenericPoolSelection,
|
|
51
51
|
} from "../../oauth/generic-account-failover";
|
|
52
|
+
import { admitGenericSessionAccount, bindGenericSessionAccount, genericSessionAccount, genericSessionAccountEligible, genericSessionAffinityEnabled, preferredGenericSessionAccount } from "../../oauth/generic-session-affinity";
|
|
53
|
+
import { oauthSessionKeyFromParts } from "../../oauth/session-affinity-key";
|
|
54
|
+
import { resolveContextPrincipal } from "../auth-cors";
|
|
52
55
|
import { tryKiroAlternateAfterTerminalRefresh } from "../../oauth/kiro-terminal-failover";
|
|
53
56
|
import { classifyModelFamilyForQuota } from "../../oauth/account-quota-rank";
|
|
54
57
|
import { expandInferenceOAuthSendBudget } from "../inference/context";
|
|
@@ -56,6 +59,11 @@ import { stampOAuthAccountLabel, usesApiKeyAccount } from "../../providers/label
|
|
|
56
59
|
import { resolveProviderTransport } from "../../providers/xai-transport";
|
|
57
60
|
import { captureRouteStaticPolicy } from "../../router";
|
|
58
61
|
import { CopilotAutoHttpError, resolveCopilotAuto } from "../../providers/github-copilot-auto";
|
|
62
|
+
import {
|
|
63
|
+
AdmissionModelDeniedError,
|
|
64
|
+
admissionModelDeniedResponse,
|
|
65
|
+
assertRouteAllowedByScope,
|
|
66
|
+
} from "../admission-model-scope";
|
|
59
67
|
import { renameRoutedIdentityInContext } from "../../adapters/identity";
|
|
60
68
|
import { resolveCopilotApiBaseUrl } from "../../oauth/github-copilot";
|
|
61
69
|
import {
|
|
@@ -73,6 +81,7 @@ import { bindRouteReasoningReplayScope } from "./core-replay";
|
|
|
73
81
|
import { sessionIdHeaderFromRequest, normalizeLogConversationId } from "../request-log-conversation";
|
|
74
82
|
import { redactSecretString } from "../../lib/redact";
|
|
75
83
|
import { selectProactiveApiKeyTransport } from "../../providers/key-failover";
|
|
84
|
+
import { distributedKeyPhysicalFetch } from "../../providers/api-key-response-ownership";
|
|
76
85
|
import { isCanonicalOpenAiForwardProvider } from "../../providers/openai-tiers";
|
|
77
86
|
import { providerConsumesCallerAuthorization } from "../../providers/caller-authorization";
|
|
78
87
|
import { releaseCodexAuthContextProbeLease, stripCodexRuntimeProviderFields } from "../../codex/auth-context";
|
|
@@ -109,10 +118,13 @@ export async function prepareResponsesTransport(
|
|
|
109
118
|
| "inboundWire"
|
|
110
119
|
| "selectedForwardHeaders"
|
|
111
120
|
| "translatorBudget"
|
|
121
|
+
| "inboundSelector"
|
|
122
|
+
| "admissionScope"
|
|
112
123
|
>,
|
|
113
124
|
) {
|
|
114
125
|
const { config, logCtx, options, req } = requestContext;
|
|
115
126
|
const { route, parsed, inboundWire, translatorBudget } = requestState;
|
|
127
|
+
const genericAffinityMode = genericSessionAffinityEnabled(config, route.providerName);
|
|
116
128
|
const anthropicInstance = route.provider.authMode === "oauth"
|
|
117
129
|
? configuredAnthropicInstance(config, route.providerName) : undefined;
|
|
118
130
|
// Refuse custom/orphan B OAuth before any generic resolver can observe its auth row.
|
|
@@ -169,6 +181,7 @@ export async function prepareResponsesTransport(
|
|
|
169
181
|
|| route.providerName === "orcarouter-oauth"
|
|
170
182
|
// runTurn transport: the replay runs on the first-event preflight in run-turn-execution.
|
|
171
183
|
|| route.providerName === "devin"
|
|
184
|
+
|| route.providerName === "dsh-account"
|
|
172
185
|
) && route.provider.authMode === "oauth";
|
|
173
186
|
let sentOAuthSnapshot: OAuthAccessSnapshot | undefined;
|
|
174
187
|
// One inference-401 replay belongs to this request, even when Auto changes exchange wire.
|
|
@@ -210,6 +223,8 @@ export async function prepareResponsesTransport(
|
|
|
210
223
|
for (let attempt = 0; attempt < maxSelectionAttempts; attempt++) {
|
|
211
224
|
requireAnthropicAdmission();
|
|
212
225
|
if (candidate.provider !== route.providerName) return null;
|
|
226
|
+
if (genericAffinityMode && route.provider.googleMode === "cloud-code-assist" && !candidate.projectId)
|
|
227
|
+
throw new OAuthLoginRequiredError(route.providerName);
|
|
213
228
|
if (anthropicInstance) anthropicRouteDecision = currentAnthropicRouteDecision();
|
|
214
229
|
if (!oauthSelection) return null;
|
|
215
230
|
const proactiveEnabled = anthropicInstance !== undefined
|
|
@@ -227,7 +242,9 @@ export async function prepareResponsesTransport(
|
|
|
227
242
|
if (candidate.provider !== route.providerName) return null;
|
|
228
243
|
if (anthropicInstance) anthropicRouteDecision = currentAnthropicRouteDecision();
|
|
229
244
|
if (anthropicRouteDecision && !routeCandidates(anthropicRouting!.getEligibleAnthropicAccounts(Date.now(), route.modelId), anthropicRouteDecision).includes(candidate.accountId)) return null;
|
|
230
|
-
const committed =
|
|
245
|
+
const committed = genericAffinityMode
|
|
246
|
+
? admitGenericSessionAccount(config, route.providerName, oauthSelection, candidate, route.modelId, genericAffinityMode)
|
|
247
|
+
: await commitOAuthAccountSelection(route.providerName, candidate.accountId, {
|
|
231
248
|
expectedSelection: oauthSelection,
|
|
232
249
|
expectedCredentialGeneration: candidate.generation,
|
|
233
250
|
requireUsableAccount: true,
|
|
@@ -241,14 +258,18 @@ export async function prepareResponsesTransport(
|
|
|
241
258
|
)) return null;
|
|
242
259
|
oauthSelection = committed;
|
|
243
260
|
servingOAuthSnapshot = candidate;
|
|
261
|
+
bindGenericSessionAccount(config, route.providerName, genericSessionKey, candidate.accountId, route.modelId);
|
|
244
262
|
if (anthropicInstance) replayOAuthCredentialSnapshot = { accountId: candidate.accountId, generation: candidate.generation };
|
|
245
263
|
forgetGenericFailoverRoster(route.providerName);
|
|
246
264
|
return candidate;
|
|
247
265
|
}
|
|
248
266
|
// A newer manual choice wins over this request's old proposal, including A→B→A.
|
|
249
267
|
// Resolve that choice, not the rejected candidate, before trying admission again.
|
|
268
|
+
const previousSelection = oauthSelection;
|
|
250
269
|
oauthSelection = captureOAuthAccountSelection(route.providerName);
|
|
251
270
|
if (!oauthSelection) return null;
|
|
271
|
+
const selectionChanged = oauthSelection.accountId !== previousSelection.accountId
|
|
272
|
+
|| oauthSelection.revision !== previousSelection.revision;
|
|
252
273
|
// A revision also changes on per-account policy edits. Re-evaluate the selector
|
|
253
274
|
// after credential waits even without a model route, rather than reusing stale active.
|
|
254
275
|
const revisedAnthropic = anthropicInstance !== undefined
|
|
@@ -256,9 +277,15 @@ export async function prepareResponsesTransport(
|
|
|
256
277
|
const revisedAnthropicId = revisedAnthropic?.accountId;
|
|
257
278
|
if (anthropicInstance !== undefined && !revisedAnthropicId) return null;
|
|
258
279
|
if (revisedAnthropic) anthropicReason = revisedAnthropic.reason;
|
|
280
|
+
const genericAccountId = genericAffinityMode && !selectionChanged
|
|
281
|
+
? (genericSessionAccountEligible(config, route.providerName, candidate.accountId, route.modelId, Date.now(), true)
|
|
282
|
+
? candidate.accountId : (preferredGenericSessionAccount(config, route.providerName, genericSessionKey, route.modelId)
|
|
283
|
+
?? oauthSelection.accountId))
|
|
284
|
+
: oauthSelection.accountId;
|
|
285
|
+
if (!genericAccountId && !anthropicInstance) return null;
|
|
259
286
|
candidate = anthropicInstance !== undefined
|
|
260
287
|
? await anthropicRouting!.getAnthropicPoolAccessSnapshot(revisedAnthropicId ?? oauthSelection.accountId)
|
|
261
|
-
: await getValidAccessSnapshotForAccount(route.providerName,
|
|
288
|
+
: await getValidAccessSnapshotForAccount(route.providerName, genericAccountId!, { requireUsableAccount: true });
|
|
262
289
|
if (route.provider.googleMode === "cloud-code-assist" && !candidate.projectId) return null;
|
|
263
290
|
}
|
|
264
291
|
return null;
|
|
@@ -268,7 +295,10 @@ export async function prepareResponsesTransport(
|
|
|
268
295
|
// Keyed on the account, not the selection revision: a selection that moved away and back
|
|
269
296
|
// (A -> B -> A) before the 401 landed still serves the rejected credential, and skipping
|
|
270
297
|
// the refresh would replay it and spend the one recovery attempt.
|
|
271
|
-
const candidate = current?.accountId === sent.accountId
|
|
298
|
+
const candidate = (current?.accountId === sent.accountId
|
|
299
|
+
|| (genericAffinityMode && current?.revision === oauthSelection?.revision
|
|
300
|
+
&& current?.accountId === oauthSelection?.accountId && servingOAuthSnapshot?.accountId === sent.accountId))
|
|
301
|
+
? await forceRefreshOAuthAccessSnapshot(sent) : sent;
|
|
272
302
|
const admitted = await commitResolvedOAuthSelection(candidate);
|
|
273
303
|
if (!admitted) throw new Error("OAuth selection changed during credential recovery");
|
|
274
304
|
if (kiroLoadEnabled && options.accountLoad?.lease?.accountId !== admitted.accountId) {
|
|
@@ -297,6 +327,7 @@ export async function prepareResponsesTransport(
|
|
|
297
327
|
const copilotRequestedModel = route.modelId;
|
|
298
328
|
/** Project only bounded Copilot refusal metadata; upstream bodies and session tokens never reach the client. */
|
|
299
329
|
const copilotRefusalResponse = (error: unknown): Response | undefined => {
|
|
330
|
+
if (error instanceof AdmissionModelDeniedError) return admissionModelDeniedResponse(error);
|
|
300
331
|
if (!(error instanceof CopilotAutoHttpError) || ![401, 403, 429].includes(error.status)) return;
|
|
301
332
|
const response = formatErrorResponse(error.status, error.status === 429 ? "rate_limit_error" : "authentication_error",
|
|
302
333
|
error.message);
|
|
@@ -357,6 +388,13 @@ export async function prepareResponsesTransport(
|
|
|
357
388
|
replayOAuthCredentialSnapshot = { accountId: refreshed.accountId, generation: refreshed.generation };
|
|
358
389
|
selected = await negotiate();
|
|
359
390
|
}
|
|
391
|
+
assertRouteAllowedByScope(
|
|
392
|
+
// The scope captured at admission: a key edited or removed while negotiation was in
|
|
393
|
+
// flight must not widen this request. The refusal names the caller's own selector.
|
|
394
|
+
requestState.admissionScope,
|
|
395
|
+
requestState.inboundSelector,
|
|
396
|
+
{ providerName: route.providerName, modelId: selected.modelId },
|
|
397
|
+
);
|
|
360
398
|
copilotSessionExpiresAt = selected.expiresAt ?? Infinity;
|
|
361
399
|
route.provider = selected.provider;
|
|
362
400
|
route.modelId = selected.modelId;
|
|
@@ -504,6 +542,8 @@ export async function prepareResponsesTransport(
|
|
|
504
542
|
return selected?.accountId === binding.selection.accountId && selected?.revision === binding.selection.revision
|
|
505
543
|
&& !!row && !row.paused && !row.needsReauth && row.credential.expires > Date.now()
|
|
506
544
|
&& (anthropicInstance === undefined || !anthropicRouting!.getAnthropicAccountHealthSnapshot(binding.snapshot.accountId) && !anthropicRatePolicy!.anthropicRatePauseUntil(binding.snapshot.accountId) && !anthropicQuota!.anthropicFamilyRejected(binding.snapshot.accountId, route.modelId))
|
|
545
|
+
&& (!genericAffinityMode
|
|
546
|
+
|| genericSessionAccountEligible(config, route.providerName, binding.snapshot.accountId, route.modelId, Date.now(), true))
|
|
507
547
|
&& credentialGeneration(row.credential) === binding.snapshot.generation;
|
|
508
548
|
};
|
|
509
549
|
/** Bind the negotiated wire adapter and its built requests to the serving credential's authority. */
|
|
@@ -577,12 +617,23 @@ export async function prepareResponsesTransport(
|
|
|
577
617
|
const accountId = await anthropicRouting!.resolveAnthropicDispatchAccountId(config, anthropicSessionKey, anthropicRouteDecision, route.modelId);
|
|
578
618
|
candidate = await anthropicRouting!.getAnthropicPoolAccessSnapshot(accountId);
|
|
579
619
|
}
|
|
620
|
+
if (genericAffinityMode
|
|
621
|
+
&& (!candidate || !genericSessionAccountEligible(config, route.providerName, candidate.accountId, route.modelId, Date.now(), true))) {
|
|
622
|
+
const accountId = preferredGenericSessionAccount(config, route.providerName, genericSessionKey, route.modelId)
|
|
623
|
+
?? captureOAuthAccountSelection(route.providerName)?.accountId;
|
|
624
|
+
candidate = accountId ? await getValidAccessSnapshotForAccount(route.providerName, accountId, { requireUsableAccount: true }) : undefined;
|
|
625
|
+
}
|
|
580
626
|
if (!candidate || !await applyFailoverSnapshot(candidate, requestParsed, true)) {
|
|
581
627
|
if (anthropicInstance !== undefined) await anthropicRouting!.resolveAnthropicDispatchAccountId(config, anthropicSessionKey, anthropicRouteDecision, route.modelId);
|
|
582
628
|
throw new Error("OAuth account selection changed before dispatch");
|
|
583
629
|
}
|
|
584
630
|
} else {
|
|
585
|
-
|
|
631
|
+
let current = resolveCurrentProviderApiKeyTransport(config, route.providerName, route.provider);
|
|
632
|
+
if (!current && (route.provider._apiKeyAttempt?.distributed || (route.provider.requestPacing?.enabled
|
|
633
|
+
&& (route.provider.requestPacing.keys || route.provider.requestPacing.keySelection === "round-robin")))) {
|
|
634
|
+
const fresh = resolveCurrentProviderApiKeyTransport(config, route.providerName, { ...route.provider, _apiKeyAttempt: undefined });
|
|
635
|
+
if (fresh) current = selectProactiveApiKeyTransport(config, route.providerName, fresh) ?? fresh;
|
|
636
|
+
}
|
|
586
637
|
if (!current) throw new Error("API key selection is unavailable before dispatch");
|
|
587
638
|
route.provider = current;
|
|
588
639
|
await resolveCopilotSelection(requestParsed, true);
|
|
@@ -610,7 +661,10 @@ export async function prepareResponsesTransport(
|
|
|
610
661
|
? (options.sendBudget as import("../../lib/request-execution-budget").RequestExecutionBudget).beginSpendProducer?.() : undefined;
|
|
611
662
|
try {
|
|
612
663
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
613
|
-
|
|
664
|
+
incoming.abortSignal?.throwIfAborted();
|
|
665
|
+
const selectionRefreshed = !selectionIsCurrent(adapterBindings.get(selectedAdapter));
|
|
666
|
+
if (attempt === 0 && selectionRefreshed) releaseProviderRequestSlot(incoming.pacingSlot);
|
|
667
|
+
if (selectionRefreshed) selectedAdapter = await refreshRunTurnAdapter(requestParsed);
|
|
614
668
|
const binding = adapterBindings.get(selectedAdapter);
|
|
615
669
|
const run = rawRunTurns.get(selectedAdapter);
|
|
616
670
|
if (!run) throw new Error("Selected provider no longer supports this turn transport");
|
|
@@ -620,24 +674,39 @@ export async function prepareResponsesTransport(
|
|
|
620
674
|
// Both main and image-loop callers already acquired the initial pacing slot.
|
|
621
675
|
// Subsequent physical messages retain this adapter/credential and are paced normally.
|
|
622
676
|
try {
|
|
623
|
-
|
|
624
|
-
|
|
677
|
+
// A pre-acquired lease belongs to the original selection, never its replacement.
|
|
678
|
+
attemptSlot = attempt === 0 && !selectionRefreshed && incoming.pacingSlot
|
|
679
|
+
? incoming.pacingSlot
|
|
625
680
|
: await waitForProviderRequestSlot(route.providerName, route.provider, route.modelId, incoming.abortSignal);
|
|
681
|
+
incoming.abortSignal?.throwIfAborted();
|
|
682
|
+
// Every admission can queue, including a replacement's. Never enter an
|
|
683
|
+
// adapter on a lease whose credential changed while it waited.
|
|
684
|
+
if (!selectionIsCurrent(binding)) {
|
|
685
|
+
refused = true;
|
|
686
|
+
throw new Error("Account selection changed before turn admission");
|
|
687
|
+
}
|
|
688
|
+
const beforePhysicalSend = (): void => {
|
|
689
|
+
incoming.abortSignal?.throwIfAborted();
|
|
690
|
+
if (sent) {
|
|
691
|
+
if (binding?.kind === "api-key" && binding.provider._apiKeyAttempt?.distributed
|
|
692
|
+
&& !selectionIsCurrent(binding)) throw new Error("API key became unavailable during the turn");
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
695
|
+
if (!selectionIsCurrent(binding)) {
|
|
696
|
+
refused = true;
|
|
697
|
+
throw new Error("Account selection changed before the first turn dispatch");
|
|
698
|
+
}
|
|
699
|
+
incoming.beforePhysicalSend?.();
|
|
700
|
+
commitKeyAttemptSend();
|
|
701
|
+
sent = true;
|
|
702
|
+
};
|
|
626
703
|
const fetch = providerFetch(route.provider, options.codexWsRuntimeIdentity, {
|
|
627
704
|
providerName: route.providerName, modelId: route.modelId, pacingSlotAcquired: true,
|
|
628
705
|
pacingSlot: attemptSlot,
|
|
629
706
|
turnScopedPacing: true,
|
|
630
|
-
beforeDispatch:
|
|
631
|
-
if (sent) return;
|
|
632
|
-
if (!selectionIsCurrent(binding)) {
|
|
633
|
-
refused = true;
|
|
634
|
-
throw new Error("Account selection changed before the first turn dispatch");
|
|
635
|
-
}
|
|
636
|
-
commitKeyAttemptSend();
|
|
637
|
-
sent = true;
|
|
638
|
-
},
|
|
707
|
+
beforeDispatch: beforePhysicalSend,
|
|
639
708
|
});
|
|
640
|
-
await run(requestParsed, { ...incoming, providerFetch: fetch }, event => { if (!refused) emit(event); });
|
|
709
|
+
await run(requestParsed, { ...incoming, pacingSlot: attemptSlot, providerFetch: fetch, beforePhysicalSend }, event => { if (!refused) emit(event); });
|
|
641
710
|
} catch (error) {
|
|
642
711
|
if (!refused) throw error;
|
|
643
712
|
} finally {
|
|
@@ -646,7 +715,7 @@ export async function prepareResponsesTransport(
|
|
|
646
715
|
if (!refused) return;
|
|
647
716
|
// The adapter may map the guard's exception to an error event. Neither that
|
|
648
717
|
// event nor a refused send may escape before retrying the newly selected account.
|
|
649
|
-
selectedAdapter = await refreshRunTurnAdapter(requestParsed);
|
|
718
|
+
if (attempt < 2) selectedAdapter = await refreshRunTurnAdapter(requestParsed);
|
|
650
719
|
}
|
|
651
720
|
throw new Error("Account selection changed repeatedly before turn dispatch");
|
|
652
721
|
} finally { producer?.close(); }
|
|
@@ -654,10 +723,16 @@ export async function prepareResponsesTransport(
|
|
|
654
723
|
/** Fence the physical send, with bounded credential/session rebuilds and safe negotiated refusals. */
|
|
655
724
|
const oauthDispatch = (wireRequest: AdapterRequest, requestParsed = parsed, owner: "adapter" | "passthrough" = "adapter"): ProviderFetchOptions["dispatchOverride"] => {
|
|
656
725
|
if (route.provider.authMode === "forward") return undefined;
|
|
657
|
-
return /** Dispatch with the current binding and session, rebuilding at most three times before returning a safe refusal. */ async (input, init, execute) => {
|
|
726
|
+
return /** Dispatch with the current binding and session, rebuilding at most three times before returning a safe refusal. */ async (input, init, execute, reacquirePacing) => {
|
|
658
727
|
let destination = input;
|
|
659
728
|
let dispatchInit = init;
|
|
729
|
+
let pacingChanged = false;
|
|
660
730
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
731
|
+
if (pacingChanged) {
|
|
732
|
+
if (!reacquirePacing) throw new Error("Refreshed dispatch requires pacing readmission");
|
|
733
|
+
await reacquirePacing(route.provider, route.modelId);
|
|
734
|
+
pacingChanged = false;
|
|
735
|
+
}
|
|
661
736
|
if (selectionIsCurrent(requestBindings.get(wireRequest)) && copilotSessionExpiresAt > Date.now() + 1000) {
|
|
662
737
|
const fetchImpl = (route.provider as OcxProviderConfig & { fetch?: typeof globalThis.fetch }).fetch ?? execute;
|
|
663
738
|
const binding = requestBindings.get(wireRequest);
|
|
@@ -698,7 +773,7 @@ export async function prepareResponsesTransport(
|
|
|
698
773
|
}
|
|
699
774
|
commitKeyAttemptSend();
|
|
700
775
|
response = await sendWithConnectionPolicy(
|
|
701
|
-
anthropicBillingPhysicalFetch(fetchImpl, route.providerName, route.provider),
|
|
776
|
+
distributedKeyPhysicalFetch(anthropicBillingPhysicalFetch(fetchImpl, route.providerName, route.provider), route.providerName, route.provider, target),
|
|
702
777
|
destination,
|
|
703
778
|
{ ...dispatchInit, redirect: "manual" },
|
|
704
779
|
{ providerName: route.providerName, provider: route.provider },
|
|
@@ -725,6 +800,7 @@ export async function prepareResponsesTransport(
|
|
|
725
800
|
let nextAdapter: ProviderAdapter;
|
|
726
801
|
try { nextAdapter = await refreshDispatchAdapter(requestParsed); }
|
|
727
802
|
catch (error) {
|
|
803
|
+
if (error instanceof AdmissionModelDeniedError) throw error;
|
|
728
804
|
const refusal = copilotRefusalResponse(error);
|
|
729
805
|
if (refusal) return refusal;
|
|
730
806
|
throw error;
|
|
@@ -759,13 +835,15 @@ export async function prepareResponsesTransport(
|
|
|
759
835
|
sameTargetToken = transportToken;
|
|
760
836
|
destination = rebuilt.url;
|
|
761
837
|
dispatchInit = { ...dispatchInit, method: rebuilt.method, headers, body: rebuilt.body };
|
|
762
|
-
|
|
838
|
+
pacingChanged = route.provider.requestPacing?.enabled === true
|
|
839
|
+
&& (!!route.provider.requestPacing.keys || route.provider.requestPacing.keySelection === "round-robin");
|
|
840
|
+
// A refreshed key must reacquire admission before the next synchronous send guard.
|
|
763
841
|
}
|
|
764
842
|
throw new Error("OAuth account selection changed repeatedly before dispatch");
|
|
765
843
|
};
|
|
766
844
|
};
|
|
767
|
-
const
|
|
768
|
-
?
|
|
845
|
+
const oauthSessionKey = route.provider.authMode === "oauth"
|
|
846
|
+
? oauthSessionKeyFromParts({
|
|
769
847
|
sessionIdHeader: sessionIdHeaderFromRequest(req.headers),
|
|
770
848
|
threadIdHeader: req.headers.get("thread-id"),
|
|
771
849
|
promptCacheKey: typeof parsed.options.promptCacheKey === "string" ? parsed.options.promptCacheKey : null,
|
|
@@ -773,6 +851,9 @@ export async function prepareResponsesTransport(
|
|
|
773
851
|
promptCacheKeyIsSharedCohort: options.promptCacheKeyIsSharedCohort === true,
|
|
774
852
|
})
|
|
775
853
|
: null;
|
|
854
|
+
const anthropicSessionKey = anthropicInstance ? oauthSessionKey : null;
|
|
855
|
+
const genericSessionKey = genericAffinityMode && oauthSessionKey
|
|
856
|
+
? JSON.stringify([resolveContextPrincipal(req, config, options.admission) ?? "loopback", oauthSessionKey]) : null;
|
|
776
857
|
if (route.provider.authMode === "oauth") {
|
|
777
858
|
try {
|
|
778
859
|
if (anthropicInstance !== undefined && anthropicRouting!.isAnthropicAccountPoolEnabled(config)) {
|
|
@@ -805,10 +886,17 @@ export async function prepareResponsesTransport(
|
|
|
805
886
|
// without quota evidence keeps the resolution it has today.
|
|
806
887
|
const refusalAwareId = route.providerName === "kiro" && oauthSelection?.accountId
|
|
807
888
|
? refusalAwareInitialKiroAccount(config, oauthSelection.accountId, Date.now(), route.modelId) : null;
|
|
808
|
-
const
|
|
889
|
+
const affinityAccountId = genericSessionAccount(config, route.providerName, genericSessionKey, route.modelId);
|
|
890
|
+
const proposedAccountId = affinityAccountId
|
|
891
|
+
?? preferredGenericSessionAccount(config, route.providerName, genericSessionKey, route.modelId)
|
|
892
|
+
?? refusalAwareId ?? (isGenericFailoverProvider(route.providerName, route.provider)
|
|
809
893
|
? preferredInitialAccount(config, route.providerName, Date.now(), route.modelId)
|
|
810
894
|
: null);
|
|
811
|
-
|
|
895
|
+
// An unchanged active choice must retain the ordinary resolver's terminal-refresh
|
|
896
|
+
// recovery (not the speculative-preference fallback that resolves the same dead grant).
|
|
897
|
+
const preferredAccountId = genericAffinityMode && proposedAccountId === oauthSelection?.accountId
|
|
898
|
+
? null : proposedAccountId;
|
|
899
|
+
let safetyAlternateId: string | null = !affinityAccountId && preferredAccountId === refusalAwareId ? refusalAwareId : null;
|
|
812
900
|
// Resolved account-scoped, NOT through failoverAccountSnapshot: that helper marks a
|
|
813
901
|
// rotation site, and rotation sites must apply their credential through
|
|
814
902
|
// applyFailoverSnapshot's pairing rules. This is initial resolution — the code below
|
|
@@ -910,7 +998,8 @@ export async function prepareResponsesTransport(
|
|
|
910
998
|
// Advance the pool cursor only now that this account is actually admitted. The
|
|
911
999
|
// helper returns immediately unless the kernel is on AND the strategy is
|
|
912
1000
|
// round-robin, so quota and fill-first pools reach it without being touched.
|
|
913
|
-
|
|
1001
|
+
if (!affinityAccountId || affinityAccountId !== resolved.accountId)
|
|
1002
|
+
noteGenericPoolSelection(config, route.providerName, resolved.accountId, route.modelId);
|
|
914
1003
|
}
|
|
915
1004
|
// Anthropic is excluded from isGenericFailoverProvider -- its own pool owns affinity and
|
|
916
1005
|
// a fail-closed local-cli credential rule -- so without this stamp its identity is
|
|
@@ -948,6 +1037,10 @@ export async function prepareResponsesTransport(
|
|
|
948
1037
|
`${redactSecretString(err.message)}. Remove or reconfigure provider '${safeProviderName}' in the OpenCodex configuration.`,
|
|
949
1038
|
);
|
|
950
1039
|
}
|
|
1040
|
+
if (err instanceof OAuthTokenRefreshBusyError) {
|
|
1041
|
+
return options.abortSignal?.aborted || req.signal.aborted ? clientCancelledResponse()
|
|
1042
|
+
: formatErrorResponse(503, "server_error", err.message, { retryAfter: "1" });
|
|
1043
|
+
}
|
|
951
1044
|
if (err instanceof OAuthAccountPausedError) {
|
|
952
1045
|
return formatErrorResponse(403, "permission_error", publicOAuthAuthenticationErrorMessage(err));
|
|
953
1046
|
}
|
|
@@ -89,6 +89,7 @@ export function createResponsesEffects(
|
|
|
89
89
|
if (routedCompaction) {
|
|
90
90
|
delete parsed.context.tools;
|
|
91
91
|
delete parsed._webSearch;
|
|
92
|
+
delete parsed._anthropicServerTools;
|
|
92
93
|
delete parsed.options.toolChoice;
|
|
93
94
|
delete parsed.options.parallelToolCalls;
|
|
94
95
|
// The compaction turn is a plain prose summary; a surviving structured-output format
|