@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
|
@@ -23,13 +23,14 @@ import { normalizeLogConversationId } from "../request-log-conversation";
|
|
|
23
23
|
import { normalizeDeclaredToolName, type AdapterEvent, type OcxProviderContinuationState } from "../../types";
|
|
24
24
|
import { adapterFailureFromMessage, SEND_BUDGET_EXHAUSTED_CODE, SPEND_LEDGER_STORAGE_UNAVAILABLE_CODE, type OcxErrorPayload } from "../../lib/errors";
|
|
25
25
|
import { SendBudgetExhaustedError, markResponseNonReplayable } from "../../lib/upstream-retry";
|
|
26
|
+
import { hasKeyPoolFailover, rotateProviderTransportOn401, rotateProviderTransportOn429 } from "../../providers/key-failover";
|
|
26
27
|
import {
|
|
27
28
|
hasEligibleGenericOAuthFailoverTarget,
|
|
28
29
|
isGenericOAuthFailoverEnabled,
|
|
29
30
|
rotateGenericOAuthAccountOn429,
|
|
30
31
|
failoverAccountSnapshot,
|
|
31
32
|
} from "../../oauth/generic-account-failover";
|
|
32
|
-
import { OAuthAccountPausedError, publicOAuthAuthenticationErrorMessage, type OAuthAccessSnapshot } from "../../oauth/index";
|
|
33
|
+
import { OAuthAccountPausedError, OAuthTokenRefreshBusyError, publicOAuthAuthenticationErrorMessage, type OAuthAccessSnapshot } from "../../oauth/index";
|
|
33
34
|
import { tryAlternateAfterTerminalRefresh } from "../../oauth/kiro-terminal-failover";
|
|
34
35
|
import { resolveWireProtocolOverride } from "../adapter-resolve";
|
|
35
36
|
import { formatErrorResponse, bridgeToResponsesSSE, buildResponseJSON } from "../../bridge";
|
|
@@ -48,12 +49,14 @@ import { rememberResponseState } from "../../responses/state";
|
|
|
48
49
|
import { trackStreamLifetime } from "../lifecycle";
|
|
49
50
|
import { awaitThoughtSignatureDurability } from "../../responses/thought-signature-replay";
|
|
50
51
|
import { undeclaredToolCallMessage } from "../responses-undeclared-tool-guard";
|
|
52
|
+
import { emptyToolCatalogRefusal, guardEmptyToolCatalogEvents, guardEmptyToolCatalogStream } from "../../lib/empty-tool-catalog";
|
|
51
53
|
// LOCAL PATCH (runturn-websearch)
|
|
52
54
|
import { planWebSearch } from "../../web-search";
|
|
53
55
|
import { runTurnWebSearchInitialParsed, runTurnWebSearchLoop } from "../../web-search/run-turn-loop";
|
|
54
56
|
import { WEB_SEARCH_TOOL_NAME } from "../../web-search/synthetic-tool";
|
|
55
57
|
import { orderDevinMessagesOutput } from "../../claude/devin-output-order";
|
|
56
58
|
import { unboundPoolSpendRefusalMessage } from "../workflow-refusal";
|
|
59
|
+
import { claudeUsagePreflight } from "../../adapters/claude-cli/usage-admission";
|
|
57
60
|
|
|
58
61
|
// LOCAL PATCH (runturn-websearch): top-level fields route binding or the
|
|
59
62
|
// adapter itself may write during a turn. Iteration-local `turnParsed` objects
|
|
@@ -70,13 +73,16 @@ const RUNTURN_WS_ROUTE_STATE_KEYS = [
|
|
|
70
73
|
"_providerContinuationOwner",
|
|
71
74
|
"_providerContinuationCandidate",
|
|
72
75
|
"_stripReasoningEncryptedContent",
|
|
76
|
+
"_stripNativeCompactionEncryptedContent",
|
|
77
|
+
"_nativeReasoningRetention",
|
|
78
|
+
"_nativeReasoningRetainedAcrossRoute",
|
|
73
79
|
"_dropForeignReasoningItemIds",
|
|
74
80
|
"_reasoningReplayScope",
|
|
75
81
|
] as const;
|
|
76
82
|
|
|
77
83
|
/** One responsibility of the Responses request pipeline; state owners are explicit. */
|
|
78
84
|
export async function executeResponsesRunTurn(
|
|
79
|
-
requestContext: Pick<ResponsesRequestContext, "options" | "logCtx" | "config">,
|
|
85
|
+
requestContext: Pick<ResponsesRequestContext, "req" | "options" | "logCtx" | "config">,
|
|
80
86
|
admissionState: ResponsesAdmissionState,
|
|
81
87
|
requestState: Pick<
|
|
82
88
|
PreparedResponsesRequest,
|
|
@@ -86,6 +92,7 @@ export async function executeResponsesRunTurn(
|
|
|
86
92
|
| "translatorBudget"
|
|
87
93
|
| "inboundWire"
|
|
88
94
|
| "toolBridgeMaps"
|
|
95
|
+
| "clientToolCatalogRestriction"
|
|
89
96
|
| "rememberKiroDeliveredFinalAnswer"
|
|
90
97
|
| "responseStateOptions"
|
|
91
98
|
>,
|
|
@@ -126,7 +133,7 @@ export async function executeResponsesRunTurn(
|
|
|
126
133
|
>,
|
|
127
134
|
completionPolicy: Pick<ResponsesCompletionPolicy, "emptyCompletionGuardEnabled">,
|
|
128
135
|
): Promise<Response> {
|
|
129
|
-
const { options, logCtx, config } = requestContext;
|
|
136
|
+
const { req, options, logCtx, config } = requestContext;
|
|
130
137
|
const {
|
|
131
138
|
selectionIsCurrent,
|
|
132
139
|
adapterBindings,
|
|
@@ -168,6 +175,33 @@ export async function executeResponsesRunTurn(
|
|
|
168
175
|
const releaseSearchProbeLease = (): void => {
|
|
169
176
|
sidecarState.openAiSidecar?.releaseProbeLease?.();
|
|
170
177
|
};
|
|
178
|
+
// Publish the known subscription pause before headers or a CLI turn, preserving its reset
|
|
179
|
+
// across both Responses and translated Chat instead of presenting a retryable generic 502.
|
|
180
|
+
if (transportState.runTurnAdapter.name === "claude-cli") {
|
|
181
|
+
let usage: Awaited<ReturnType<typeof claudeUsagePreflight>>;
|
|
182
|
+
try {
|
|
183
|
+
usage = await claudeUsagePreflight(parsed.modelId);
|
|
184
|
+
} catch (error) {
|
|
185
|
+
// The outer cleanup does not own the sidecar's probe lease: hand it back before rethrowing.
|
|
186
|
+
releaseSearchProbeLease();
|
|
187
|
+
throw error;
|
|
188
|
+
}
|
|
189
|
+
if (usage.state === "exhausted") {
|
|
190
|
+
cancelResponseCompletion();
|
|
191
|
+
releaseSearchProbeLease();
|
|
192
|
+
const refusal = new Response(JSON.stringify({ error: {
|
|
193
|
+
type: "rate_limit_error", code: "claude_subscription_cooldown", param: null,
|
|
194
|
+
message: usage.message ?? "Claude subscription usage is exhausted.",
|
|
195
|
+
} }), {
|
|
196
|
+
status: 429,
|
|
197
|
+
headers: { "Content-Type": "application/json",
|
|
198
|
+
...(usage.resetAt ? { "Retry-After": String(Math.max(1, Math.ceil((usage.resetAt - Date.now()) / 1000))) } : {}),
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
markResponseNonReplayable(refusal);
|
|
202
|
+
return refusal;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
171
205
|
// When Codex declared hosted web_search and a sidecar plan resolves, drive
|
|
172
206
|
// the routed model through the same search interception the fetch-path loop
|
|
173
207
|
// runs — injected as a function tool, calls intercepted, results appended to
|
|
@@ -185,7 +219,9 @@ export async function executeResponsesRunTurn(
|
|
|
185
219
|
}
|
|
186
220
|
|
|
187
221
|
const runTurnAbort = new AbortController();
|
|
188
|
-
const
|
|
222
|
+
const cleanupRequestAbort = linkAbortSignal(runTurnAbort, req.signal);
|
|
223
|
+
const cleanupOptionAbort = linkAbortSignal(runTurnAbort, options.abortSignal);
|
|
224
|
+
const cleanupRunTurnAbort = (): void => { cleanupRequestAbort(); cleanupOptionAbort(); };
|
|
189
225
|
const devinProducers = new Set<AbortController>();
|
|
190
226
|
const orderMessagesOutput = (source: AsyncIterable<AdapterEvent>): AsyncIterable<AdapterEvent> =>
|
|
191
227
|
inboundWire === "anthropic" && transportState.runTurnAdapter.name === "devin" && !routedCompaction
|
|
@@ -196,12 +232,13 @@ export async function executeResponsesRunTurn(
|
|
|
196
232
|
const queue = createAdapterEventQueue({
|
|
197
233
|
onBacklogExceeded: () => runTurnAbort.abort(),
|
|
198
234
|
});
|
|
199
|
-
const refreshRunTurnSelection = async (): Promise<
|
|
200
|
-
if (selectionIsCurrent(adapterBindings.get(transportState.runTurnAdapter))) return;
|
|
235
|
+
const refreshRunTurnSelection = async (): Promise<boolean> => {
|
|
236
|
+
if (selectionIsCurrent(adapterBindings.get(transportState.runTurnAdapter))) return false;
|
|
201
237
|
await refreshRunTurnAdapter(parsed);
|
|
202
238
|
bindRouteReasoningReplayScope({ parsed, providerName: route.providerName, provider: route.provider,
|
|
203
239
|
adapterName: transportState.runTurnAdapter.name, oauthCredentialSnapshot: transportState.replayOAuthCredentialSnapshot });
|
|
204
240
|
sealRequestAttemptIdentity(logCtx.activeAttempt, logCtx.provider, transportState.runTurnAdapter.name, logCtx.accountLogLabel);
|
|
241
|
+
return true;
|
|
205
242
|
};
|
|
206
243
|
// Initial admission must settle before the streaming Response commits HTTP 200.
|
|
207
244
|
// Let the outer Responses facade preserve the local retryable-429 contract.
|
|
@@ -224,6 +261,11 @@ export async function executeResponsesRunTurn(
|
|
|
224
261
|
// in-flight; only the latest dispatch may merge adapter-written route
|
|
225
262
|
// state back onto `parsed`, or the superseded attempt would restore the
|
|
226
263
|
// failed account's cursor/continuation over the rotation's rebind.
|
|
264
|
+
type KeyBinding = Extract<NonNullable<ReturnType<typeof adapterBindings.get>>, { kind: "api-key" }>;
|
|
265
|
+
const failedKeyBindings = new WeakMap<Extract<AdapterEvent, { type: "error" }>, KeyBinding>();
|
|
266
|
+
const failedKeys = new Set<string>();
|
|
267
|
+
const keyAttemptLimit = route.provider.apiKeyPool?.length ?? 0;
|
|
268
|
+
let lastKeyFailure: Extract<AdapterEvent, { type: "error" }> | undefined;
|
|
227
269
|
let runTurnAttemptSeq = 0;
|
|
228
270
|
const runTurnAttempt = async (
|
|
229
271
|
targetQueue: AdapterEventQueue,
|
|
@@ -238,7 +280,9 @@ export async function executeResponsesRunTurn(
|
|
|
238
280
|
const attemptSeq = ++runTurnAttemptSeq;
|
|
239
281
|
if (attemptSeq === 1 && options.comboInitialSend) options.comboInitialSend.producerOwned = true;
|
|
240
282
|
let pacingSlot = preacquiredSlot;
|
|
283
|
+
let sentKeyBinding: KeyBinding | undefined;
|
|
241
284
|
const emit = (event: AdapterEvent) => {
|
|
285
|
+
if (event.type === "error" && sentKeyBinding) failedKeyBindings.set(event, sentKeyBinding);
|
|
242
286
|
options.onCompactionRecoveryAdapterEvent?.(event);
|
|
243
287
|
targetQueue.push(event);
|
|
244
288
|
};
|
|
@@ -248,7 +292,18 @@ export async function executeResponsesRunTurn(
|
|
|
248
292
|
if (!pacingSlotAcquired) {
|
|
249
293
|
pacingSlot = await waitForProviderRequestSlot(route.providerName, route.provider, route.modelId, runTurnAbort.signal);
|
|
250
294
|
}
|
|
251
|
-
await refreshRunTurnSelection();
|
|
295
|
+
const selectionChanged = await refreshRunTurnSelection();
|
|
296
|
+
const selectedBinding = adapterBindings.get(transportState.runTurnAdapter);
|
|
297
|
+
if (lastKeyFailure && selectedBinding?.kind === "api-key"
|
|
298
|
+
&& failedKeys.has(selectedBinding.provider.apiKey ?? "")) {
|
|
299
|
+
emit(lastKeyFailure);
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
if (selectionChanged) {
|
|
303
|
+
releaseProviderRequestSlot(pacingSlot);
|
|
304
|
+
pacingSlot = undefined;
|
|
305
|
+
pacingSlot = await waitForProviderRequestSlot(route.providerName, route.provider, route.modelId, runTurnAbort.signal);
|
|
306
|
+
}
|
|
252
307
|
// LOCAL PATCH (runturn-websearch): refreshRunTurnSelection binds route
|
|
253
308
|
// state onto `parsed`; mirror it onto the iteration-local copy the
|
|
254
309
|
// adapter actually receives.
|
|
@@ -293,13 +348,14 @@ export async function executeResponsesRunTurn(
|
|
|
293
348
|
// The only way the request budget reaches a transport the adapter owns. Without it
|
|
294
349
|
// a Cursor turn's inner ladder was three physical sends the cap read as one.
|
|
295
350
|
...(adapterDispatchBudget ? { sendBudget: adapterDispatchBudget } : {}),
|
|
296
|
-
onPhysicalSend: send =>
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
351
|
+
onPhysicalSend: send => {
|
|
352
|
+
// Capture once at this attempt's send, before later selection or recovery changes it.
|
|
353
|
+
const binding = adapterBindings.get(transportState.runTurnAdapter);
|
|
354
|
+
if (!sentKeyBinding && binding?.kind === "api-key") sentKeyBinding = binding;
|
|
355
|
+
noteAdapterPhysicalSend(logCtx.usageLogInputTokens,
|
|
356
|
+
{ ...send, ...(send.recovery ?? recovery ? { recovery: send.recovery ?? recovery } : {}) },
|
|
357
|
+
{ includeFirst: reportsOwnSends });
|
|
358
|
+
},
|
|
303
359
|
onRecoveryWithheld: noteAdapterRecoveryWithheld,
|
|
304
360
|
},
|
|
305
361
|
emit,
|
|
@@ -361,6 +417,7 @@ export async function executeResponsesRunTurn(
|
|
|
361
417
|
const runTurn = async (): Promise<void> => runTurnAttempt(queue, undefined, true, wsFirstParsed, initialPacingSlot);
|
|
362
418
|
const runTurnFailoverArmed = () =>
|
|
363
419
|
route.provider.authMode === "oauth"
|
|
420
|
+
|| (transportState.runTurnAdapter.name === "qoder" && hasKeyPoolFailover(route.provider))
|
|
364
421
|
|| !!(transportState.genericFailoverAccountId
|
|
365
422
|
&& isGenericOAuthFailoverEnabled(config, route.providerName));
|
|
366
423
|
const dispatchSearchIteration = (iterParsed: PreparedResponsesRequest["parsed"]): AsyncIterable<AdapterEvent> => {
|
|
@@ -420,7 +477,19 @@ export async function executeResponsesRunTurn(
|
|
|
420
477
|
// selected; the turn then moves to a surviving stored account, or, with none, the client
|
|
421
478
|
// gets the login instruction instead of an opaque upstream 401.
|
|
422
479
|
let oauth401ReplayAttempted = false;
|
|
423
|
-
let
|
|
480
|
+
let authRecoveryRefusal: Response | undefined;
|
|
481
|
+
const refuseLocalAuthRecovery = (error: Extract<AdapterEvent, { type: "error" }>, cause: unknown): boolean => {
|
|
482
|
+
const cancelled = runTurnAbort.signal.aborted;
|
|
483
|
+
if (!cancelled && !(cause instanceof OAuthTokenRefreshBusyError) && !(cause instanceof OAuthAccountPausedError)) return false;
|
|
484
|
+
const status = cancelled ? 499 : cause instanceof OAuthTokenRefreshBusyError ? 503 : 403;
|
|
485
|
+
const errorType = cancelled ? "client_cancelled" : status === 503 ? "server_error" : "permission_error";
|
|
486
|
+
const message = cancelled ? "Client cancelled request" : publicOAuthAuthenticationErrorMessage(cause);
|
|
487
|
+
// If a readiness heartbeat already committed SSE, the mapped event remains retryable
|
|
488
|
+
// capacity rather than retaining the rejected credential's authentication error/code.
|
|
489
|
+
Object.assign(error, { status, errorType, message, code: undefined, retryable: status === 503 });
|
|
490
|
+
authRecoveryRefusal = formatErrorResponse(status, errorType, message, status === 503 ? { retryAfter: "1" } : undefined);
|
|
491
|
+
return true;
|
|
492
|
+
};
|
|
424
493
|
const recoverRunTurnAdapterOnPreflight401 = async (
|
|
425
494
|
error: Extract<AdapterEvent, { type: "error" }>,
|
|
426
495
|
): Promise<boolean> => {
|
|
@@ -434,9 +503,7 @@ export async function executeResponsesRunTurn(
|
|
|
434
503
|
try {
|
|
435
504
|
admitted = await applyFailoverSnapshot(await refreshResolvedOAuthSelection(sent));
|
|
436
505
|
} catch (err) {
|
|
437
|
-
if (err
|
|
438
|
-
pausedAuthRecovery = true;
|
|
439
|
-
Object.assign(error, { status: 403, errorType: "permission_error", message: publicOAuthAuthenticationErrorMessage(err) });
|
|
506
|
+
if (refuseLocalAuthRecovery(error, err)) {
|
|
440
507
|
hop.permit?.release();
|
|
441
508
|
return false;
|
|
442
509
|
}
|
|
@@ -459,14 +526,58 @@ export async function executeResponsesRunTurn(
|
|
|
459
526
|
} catch (err) {
|
|
460
527
|
// Applying the alternate can still fail, e.g. when a newer manual selection points back
|
|
461
528
|
// at the flagged account; the client then needs the login instruction, not the raw 401.
|
|
462
|
-
|
|
529
|
+
if (!refuseLocalAuthRecovery(error, err)) {
|
|
530
|
+
Object.assign(error, { errorType: "authentication_error", message: publicOAuthAuthenticationErrorMessage(err) });
|
|
531
|
+
}
|
|
463
532
|
hop.permit?.release();
|
|
464
533
|
return false;
|
|
465
534
|
}
|
|
466
535
|
};
|
|
536
|
+
const recoverRunTurnKey = async (
|
|
537
|
+
error: Extract<AdapterEvent, { type: "error" }>,
|
|
538
|
+
): Promise<AttemptRecoveryKind | undefined> => {
|
|
539
|
+
const binding = failedKeyBindings.get(error);
|
|
540
|
+
if (error.apiKeyRecovery !== true || (error.status !== 401 && error.status !== 429)
|
|
541
|
+
|| !binding || runTurnAbort.signal.aborted || !hasKeyPoolFailover(route.provider)
|
|
542
|
+
|| failedKeys.size >= keyAttemptLimit) return undefined;
|
|
543
|
+
const failed = binding.provider;
|
|
544
|
+
if (!failed.apiKey || !failed._apiKeyAttempt || failedKeys.has(failed.apiKey)) return undefined;
|
|
545
|
+
const hop = reserveCredentialHop("auth-recovery", `${route.providerName}|${route.modelId}|runturn-key-${error.status}`);
|
|
546
|
+
if (!hop.allowed) return undefined;
|
|
547
|
+
failedKeys.add(failed.apiKey);
|
|
548
|
+
lastKeyFailure = error;
|
|
549
|
+
try {
|
|
550
|
+
const rotate = error.status === 401 ? rotateProviderTransportOn401 : rotateProviderTransportOn429;
|
|
551
|
+
const rotated = rotate(config, route.providerName, failed, {
|
|
552
|
+
attemptedKey: failed.apiKey, attemptedSelection: failed._apiKeyAttempt,
|
|
553
|
+
promptCacheKey: parsed.options.promptCacheKey,
|
|
554
|
+
});
|
|
555
|
+
if (!rotated || failedKeys.size >= keyAttemptLimit || failedKeys.has(rotated.apiKey ?? "") || runTurnAbort.signal.aborted) {
|
|
556
|
+
hop.permit?.release();
|
|
557
|
+
return undefined;
|
|
558
|
+
}
|
|
559
|
+
route.provider = rotated;
|
|
560
|
+
const adapter = await refreshRunTurnAdapter(parsed);
|
|
561
|
+
if (!adapter.runTurn || failedKeys.has(route.provider.apiKey ?? "") || runTurnAbort.signal.aborted) {
|
|
562
|
+
hop.permit?.release();
|
|
563
|
+
return undefined;
|
|
564
|
+
}
|
|
565
|
+
bindRouteReasoningReplayScope({ parsed, providerName: route.providerName, provider: route.provider,
|
|
566
|
+
adapterName: adapter.name, forwardHeaders: requestState.selectedForwardHeaders });
|
|
567
|
+
sealRequestAttemptIdentity(logCtx.activeAttempt, logCtx.provider, adapter.name, logCtx.accountLogLabel);
|
|
568
|
+
recordAttemptCredentialSource(logCtx.activeAttempt, route.providerName, route.provider, adapter.name);
|
|
569
|
+
sendBudgetState.pendingHopPermit = hop.permit;
|
|
570
|
+
return error.status === 401 ? "key-401" : "key-429";
|
|
571
|
+
} catch {
|
|
572
|
+
hop.permit?.release();
|
|
573
|
+
return undefined;
|
|
574
|
+
}
|
|
575
|
+
};
|
|
467
576
|
const recoverRunTurnAdapterOnPreflightError = async (
|
|
468
577
|
error: Extract<AdapterEvent, { type: "error" }>,
|
|
469
578
|
): Promise<AttemptRecoveryKind | undefined> => {
|
|
579
|
+
const keyRecovery = await recoverRunTurnKey(error);
|
|
580
|
+
if (keyRecovery) return keyRecovery;
|
|
470
581
|
if (await recoverRunTurnAdapterOnPreflight401(error)) return "oauth-401";
|
|
471
582
|
if (await rotateRunTurnAdapterOnPreflight429(error)) return "oauth-account-429";
|
|
472
583
|
return undefined;
|
|
@@ -641,14 +752,19 @@ export async function executeResponsesRunTurn(
|
|
|
641
752
|
return orderMessagesOutput(retryQueue.stream());
|
|
642
753
|
};
|
|
643
754
|
|
|
644
|
-
const
|
|
755
|
+
const clientToolCatalog = requestState.clientToolCatalogRestriction && route.provider.authMode !== "forward"
|
|
756
|
+
? requestState.clientToolCatalogRestriction : undefined;
|
|
757
|
+
const { toolNsMap, declaredToolNames, toolParameterSchemas, freeformToolNames, bareCustomToolNames, toolSearchToolNames } = clientToolCatalog
|
|
758
|
+
? { ...toolBridgeMaps, ...clientToolCatalog } : toolBridgeMaps;
|
|
645
759
|
const enforceDeclaredToolNames = inboundWire !== "chat" && inboundWire !== "anthropic";
|
|
646
760
|
const classifyUndeclaredFirstTool = (
|
|
647
761
|
event: AdapterEvent,
|
|
648
762
|
): Extract<AdapterEvent, { type: "error" }> | undefined => {
|
|
649
|
-
if (!enforceDeclaredToolNames || event.type !== "tool_call_start") return undefined;
|
|
650
763
|
// This tool is declared to the adapter by the private search loop.
|
|
651
|
-
if (wsPlan && event.name === WEB_SEARCH_TOOL_NAME) return undefined;
|
|
764
|
+
if (wsPlan && event.type === "tool_call_start" && event.name === WEB_SEARCH_TOOL_NAME) return undefined;
|
|
765
|
+
const emptyCatalogRefusal = emptyToolCatalogRefusal(event, clientToolCatalog);
|
|
766
|
+
if (emptyCatalogRefusal) return emptyCatalogRefusal;
|
|
767
|
+
if (!enforceDeclaredToolNames || event.type !== "tool_call_start") return undefined;
|
|
652
768
|
const effectiveName = normalizeDeclaredToolName(event.name, declaredToolNames, undefined, bareCustomToolNames);
|
|
653
769
|
if (declaredToolNames.has(effectiveName)) return undefined;
|
|
654
770
|
return {
|
|
@@ -683,20 +799,24 @@ export async function executeResponsesRunTurn(
|
|
|
683
799
|
const stallTimeoutSec = wsPlan?.stallTimeoutSec ?? config.stallTimeoutSec;
|
|
684
800
|
// A disabled watchdog (0) is not a zero preflight: it would commit SSE before Devin's first
|
|
685
801
|
// event and deliver a pre-output 429 in-stream. Fall back to the default finite bound.
|
|
686
|
-
|
|
802
|
+
// A key-pool preflight must not outlast the stall budget, or a silent CLI holds the SSE
|
|
803
|
+
// Response (heartbeats, stall watchdog) hostage; the OAuth preflight wait is unchanged.
|
|
804
|
+
const keyPoolPreflight = transportState.runTurnAdapter.name === "qoder"
|
|
805
|
+
&& route.provider.authMode !== "oauth" && hasKeyPoolFailover(route.provider);
|
|
806
|
+
const preflightDeadlineAt = grokDevinPreflight || keyPoolPreflight
|
|
687
807
|
? Date.now() + (resolveStallTimeoutSec(stallTimeoutSec) || DEFAULT_STALL_TIMEOUT_SEC) * 1_000
|
|
688
808
|
: undefined;
|
|
689
809
|
if (runTurnFailoverArmed()) {
|
|
690
810
|
// Preflight holds only heartbeats and the first meaningful event. A first-event 429 can be
|
|
691
811
|
// replayed transparently; after any output reaches the bridge, a later error stays terminal.
|
|
692
812
|
eventSource = await preflightRunTurnFailover(eventSource, wsFirstParsed, preflightDeadlineAt);
|
|
693
|
-
if (
|
|
813
|
+
if (authRecoveryRefusal) {
|
|
694
814
|
cancelResponseCompletion();
|
|
695
815
|
runTurnAbort.abort();
|
|
696
816
|
queue.close();
|
|
697
817
|
cleanupRunTurnAbort();
|
|
698
818
|
releaseSearchProbeLease();
|
|
699
|
-
return
|
|
819
|
+
return authRecoveryRefusal;
|
|
700
820
|
}
|
|
701
821
|
}
|
|
702
822
|
if (grokDevinPreflight) {
|
|
@@ -714,9 +834,13 @@ export async function executeResponsesRunTurn(
|
|
|
714
834
|
if (preflight.error || preflight.empty) {
|
|
715
835
|
runTurnAbort.abort();
|
|
716
836
|
queue.close();
|
|
717
|
-
const
|
|
718
|
-
|
|
719
|
-
|
|
837
|
+
const classified = adapterFailureFromEvent(preflight.error ?? {
|
|
838
|
+
type: "error", status: 502, message: "Adapter ended before producing a response",
|
|
839
|
+
});
|
|
840
|
+
const storageRefusal = preflight.error?.code === SPEND_LEDGER_STORAGE_UNAVAILABLE_CODE;
|
|
841
|
+
const failure = formatErrorResponse(storageRefusal ? 503 : classified.httpStatus,
|
|
842
|
+
storageRefusal ? SPEND_LEDGER_STORAGE_UNAVAILABLE_CODE : classified.error.type,
|
|
843
|
+
redactSecretString(classified.error.message), { code: classified.error.code, classified: true });
|
|
720
844
|
// A replay-unsafe heartbeat means the adapter already ran a local side effect, so the
|
|
721
845
|
// combo must not send this turn to another target: the failure stays with this child.
|
|
722
846
|
if (preflight.replayUnsafe) markResponseNonReplayable(failure);
|
|
@@ -762,7 +886,7 @@ export async function executeResponsesRunTurn(
|
|
|
762
886
|
console.warn(emptyCompletionNotice(route.providerName, route.modelId));
|
|
763
887
|
});
|
|
764
888
|
const sseStream = bridgeToResponsesSSE(
|
|
765
|
-
guardedSource, parsed._responseModelId ?? parsed.modelId, toolNsMap, freeformToolNames, toolSearchToolNames,
|
|
889
|
+
guardEmptyToolCatalogStream(guardedSource, clientToolCatalog, translatorBudget), parsed._responseModelId ?? parsed.modelId, toolNsMap, freeformToolNames, toolSearchToolNames,
|
|
766
890
|
() => {
|
|
767
891
|
cancelResponseCompletion();
|
|
768
892
|
runTurnAbort.abort();
|
|
@@ -778,9 +902,11 @@ export async function executeResponsesRunTurn(
|
|
|
778
902
|
declaredToolNames,
|
|
779
903
|
bareCustomToolNames,
|
|
780
904
|
enforceDeclaredToolNames,
|
|
905
|
+
// Same wire split: only a Responses client (Codex) needs the refusal as a failure.
|
|
906
|
+
terminalRefusalAsFailed: enforceDeclaredToolNames,
|
|
781
907
|
toolParameterSchemas,
|
|
782
908
|
...(options.onFirstOutput ? { onFirstOutput: options.onFirstOutput } : {}),
|
|
783
|
-
...(routedCompaction ? { compaction: true } : {}),
|
|
909
|
+
...(routedCompaction ? { compaction: true, compactionRetention: parsed._compactionRetention } : {}),
|
|
784
910
|
// grok-build's strict decoder dies on the typed response.heartbeat frame; its
|
|
785
911
|
// eventsource layer tolerates comment keep-alives. Codex needs the opposite.
|
|
786
912
|
...(logCtx.surface === "grok" ? { heartbeatStyle: "comment" as const } : {}),
|
|
@@ -835,13 +961,13 @@ export async function executeResponsesRunTurn(
|
|
|
835
961
|
for await (const event of await preflightRunTurnFailover(
|
|
836
962
|
(async function* () { yield* firstAttemptEvents; })(),
|
|
837
963
|
)) runTurnEvents.push(event);
|
|
838
|
-
if (
|
|
964
|
+
if (authRecoveryRefusal) {
|
|
839
965
|
cancelResponseCompletion();
|
|
840
966
|
runTurnAbort.abort();
|
|
841
967
|
queue.close();
|
|
842
968
|
cleanupRunTurnAbort();
|
|
843
969
|
releaseSearchProbeLease();
|
|
844
|
-
return
|
|
970
|
+
return authRecoveryRefusal;
|
|
845
971
|
}
|
|
846
972
|
}
|
|
847
973
|
if (grokDevinPreflight) {
|
|
@@ -899,6 +1025,7 @@ export async function executeResponsesRunTurn(
|
|
|
899
1025
|
}
|
|
900
1026
|
events = searched;
|
|
901
1027
|
}
|
|
1028
|
+
events = guardEmptyToolCatalogEvents(events, clientToolCatalog, translatorBudget);
|
|
902
1029
|
if (options.comboAttempt) {
|
|
903
1030
|
const firstMeaningfulIndex = events.findIndex(event => event.type !== "heartbeat");
|
|
904
1031
|
const firstMeaningful = firstMeaningfulIndex === -1 ? undefined : events[firstMeaningfulIndex];
|
|
@@ -912,12 +1039,13 @@ export async function executeResponsesRunTurn(
|
|
|
912
1039
|
? classifyUndeclaredFirstTool(firstMeaningful)
|
|
913
1040
|
: undefined;
|
|
914
1041
|
if (!firstMeaningful || firstMeaningful.type === "error" || classifiedError) {
|
|
915
|
-
const
|
|
916
|
-
? firstMeaningful
|
|
917
|
-
: "Adapter ended before producing a response");
|
|
1042
|
+
const classified = adapterFailureFromEvent(classifiedError ?? (firstMeaningful?.type === "error"
|
|
1043
|
+
? firstMeaningful
|
|
1044
|
+
: { type: "error", status: 502, message: "Adapter ended before producing a response" }));
|
|
918
1045
|
const storageRefusal = firstMeaningful?.type === "error" && firstMeaningful.code === SPEND_LEDGER_STORAGE_UNAVAILABLE_CODE;
|
|
919
|
-
const failure = formatErrorResponse(storageRefusal ? 503 :
|
|
920
|
-
storageRefusal ? SPEND_LEDGER_STORAGE_UNAVAILABLE_CODE :
|
|
1046
|
+
const failure = formatErrorResponse(storageRefusal ? 503 : classified.httpStatus,
|
|
1047
|
+
storageRefusal ? SPEND_LEDGER_STORAGE_UNAVAILABLE_CODE : classified.error.type,
|
|
1048
|
+
redactSecretString(classified.error.message), { code: classified.error.code, classified: true });
|
|
921
1049
|
if (replayUnsafe) markResponseNonReplayable(failure);
|
|
922
1050
|
return failure;
|
|
923
1051
|
}
|
|
@@ -935,7 +1063,7 @@ export async function executeResponsesRunTurn(
|
|
|
935
1063
|
freeformToolNames,
|
|
936
1064
|
bareCustomToolNames,
|
|
937
1065
|
toolSearchToolNames,
|
|
938
|
-
...(routedCompaction ? { compaction: true } : {}),
|
|
1066
|
+
...(routedCompaction ? { compaction: true, compactionRetention: parsed._compactionRetention } : {}),
|
|
939
1067
|
onProviderState: state => { providerState = state; },
|
|
940
1068
|
onUsage: usage => {
|
|
941
1069
|
transportState.bindKeyUsageFromBridge(usage);
|