@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
|
@@ -7,9 +7,9 @@ import { isBuiltinAnthropicInstanceRow } from "../providers/anthropic-instance";
|
|
|
7
7
|
* exists is Anthropic's — behind its own opt-in. So xAI, Cursor, Kimi, GitHub Copilot,
|
|
8
8
|
* Antigravity and Nous have no recovery path on a 429 even with several accounts logged in.
|
|
9
9
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
10
|
+
* Conversation ownership lives in generic-session-affinity.ts; this module owns account
|
|
11
|
+
* eligibility, quota-ranked preference and bounded refusal recovery. Probe leases remain
|
|
12
|
+
* provider-specific.
|
|
13
13
|
*
|
|
14
14
|
* NOT a home for Codex (`codex/routing.ts` owns quota scopes and probe leases) or Anthropic
|
|
15
15
|
* (`oauth/anthropic-routing.ts` owns affinity and a fail-closed local-cli credential rule).
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
hasHeadroomEvidence,
|
|
26
26
|
isAccountQuotaExhausted,
|
|
27
27
|
rankAccountsByHeadroom,
|
|
28
|
+
rankAccountsByResetFirst,
|
|
28
29
|
classifyModelFamilyForQuota,
|
|
29
30
|
type QuotaModelFamily,
|
|
30
31
|
} from "./account-quota-rank";
|
|
@@ -41,6 +42,7 @@ import type { KiroRefusalKind } from "../adapters/kiro-refusal";
|
|
|
41
42
|
import { kiroAccountEvidence } from "../providers/kiro-usage";
|
|
42
43
|
import { kiroEvidenceIdentity } from "../providers/kiro-account-state-disk";
|
|
43
44
|
import { kiroAccountSupportsModel } from "../providers/kiro-model-catalog";
|
|
45
|
+
import { antigravityAccountSupportsModel } from "../providers/antigravity-account-roster";
|
|
44
46
|
import { ACCOUNT_QUOTA_TTL_MS } from "../providers/quota-wire";
|
|
45
47
|
import { sweepExpiredOnWrite } from "../lib/state-store-sweeper";
|
|
46
48
|
import { subscribeOAuthAccountPauseChanges } from "../lib/account-selection-events";
|
|
@@ -248,11 +250,31 @@ export function eligibleFailoverAccounts(providerName: string, now = Date.now(),
|
|
|
248
250
|
return eligibleIdsIn(getAccountSet(providerName), providerName, now, family);
|
|
249
251
|
}
|
|
250
252
|
|
|
251
|
-
/**
|
|
253
|
+
/** Whether an account's own model listing includes `model`; undefined when unknown. */
|
|
254
|
+
function accountListsModel(providerName: string, accountId: string, model: string): boolean | undefined {
|
|
255
|
+
if (providerName === "kiro") return kiroAccountSupportsModel(accountId, model);
|
|
256
|
+
if (providerName === "google-antigravity") return antigravityAccountSupportsModel(providerName, accountId, model);
|
|
257
|
+
return undefined;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Model evidence only ranks accounts already eligible and below any configured cap.
|
|
262
|
+
*
|
|
263
|
+
* Kiro and Antigravity both gate models per account. For Antigravity (Claude 4.6 vs 5.5, Argon)
|
|
264
|
+
* an account whose discovered roster lists the model wins; an account whose roster omits it is
|
|
265
|
+
* skipped while any other remains; an account with no roster yet is unknown and stays usable.
|
|
266
|
+
*/
|
|
252
267
|
export function preferKiroModelSupport(
|
|
253
268
|
providerName: string, ids: string[], model?: string | null, config?: OcxConfig,
|
|
254
269
|
): string[] {
|
|
255
|
-
if (
|
|
270
|
+
if (!model) return ids;
|
|
271
|
+
if (providerName === "google-antigravity") {
|
|
272
|
+
const positive = ids.filter(id => accountListsModel(providerName, id, model) === true);
|
|
273
|
+
if (positive.length) return positive;
|
|
274
|
+
const notListedAgainst = ids.filter(id => accountListsModel(providerName, id, model) !== false);
|
|
275
|
+
return notListedAgainst.length ? notListedAgainst : ids;
|
|
276
|
+
}
|
|
277
|
+
if (providerName !== "kiro") return ids;
|
|
256
278
|
const cap = config?.providers?.kiro?.oauthAccountFailover?.maxConcurrentPerAccount;
|
|
257
279
|
const withRoom = typeof cap === "number" && Number.isInteger(cap) && cap >= 1 && cap <= 100
|
|
258
280
|
? ids.filter(id => accountInFlight("kiro", id) < cap) : ids;
|
|
@@ -330,7 +352,7 @@ export function rotateAntigravityAccountOnAuthRefusal(
|
|
|
330
352
|
}
|
|
331
353
|
|
|
332
354
|
/** Generic pool strategies the kernel can actually run. `quota` IS the pre-kernel path. */
|
|
333
|
-
type ActiveGenericStrategy = "round-robin" | "fill-first" | "least-loaded";
|
|
355
|
+
type ActiveGenericStrategy = "round-robin" | "fill-first" | "reset-first" | "least-loaded";
|
|
334
356
|
|
|
335
357
|
/** Matches the Codex and Anthropic pools; the DTO still reports `null` for "not stored". */
|
|
336
358
|
const DEFAULT_GENERIC_AUTO_SWITCH_THRESHOLD = 80;
|
|
@@ -344,10 +366,13 @@ const DEFAULT_GENERIC_AUTO_SWITCH_THRESHOLD = 80;
|
|
|
344
366
|
* branch instead of a four-way one.
|
|
345
367
|
*/
|
|
346
368
|
function activeGenericStrategy(config: OcxConfig, providerName: string): ActiveGenericStrategy | null {
|
|
369
|
+
// All pool strategies run behind the kernel flag; `quota` is the pre-kernel path.
|
|
370
|
+
// Letting `reset-first` bypass it would change 429 selection for pools that never
|
|
371
|
+
// opted into kernel-gated strategies.
|
|
347
372
|
if (config.pool?.kernel !== true) return null;
|
|
348
373
|
const raw = config.providers?.[providerName]?.oauthAccountFailover?.strategy;
|
|
349
374
|
if (providerName === "kiro" && raw === "least-loaded") return raw;
|
|
350
|
-
return raw === "round-robin" || raw === "fill-first" ? raw : null;
|
|
375
|
+
return raw === "round-robin" || raw === "fill-first" || raw === "reset-first" ? raw : null;
|
|
351
376
|
}
|
|
352
377
|
|
|
353
378
|
function genericStickyLimit(config: OcxConfig, providerName: string): number {
|
|
@@ -395,6 +420,7 @@ function pickFillFirstGenericAccount(
|
|
|
395
420
|
now: number,
|
|
396
421
|
requestedModelId?: string | null,
|
|
397
422
|
accountRows?: ReadonlyMap<string, ProviderAccount>,
|
|
423
|
+
preferBelowThreshold = false,
|
|
398
424
|
): string | null {
|
|
399
425
|
const stableAll = stableGenericRoster(providerName);
|
|
400
426
|
if (stableAll.length < 2) return null;
|
|
@@ -410,6 +436,11 @@ function pickFillFirstGenericAccount(
|
|
|
410
436
|
}
|
|
411
437
|
const start = activeId ? stableAll.indexOf(activeId) : -1;
|
|
412
438
|
const ring = start >= 0 ? [...stableAll.slice(start + 1), ...stableAll.slice(0, start)] : stableAll;
|
|
439
|
+
if (preferBelowThreshold) {
|
|
440
|
+
const below = ring.find(id => id !== activeId && eligible.has(id)
|
|
441
|
+
&& !isOverAutoSwitchThreshold(providerName, id, threshold, requestedModelId, accountRows?.get(id)));
|
|
442
|
+
if (below) return below;
|
|
443
|
+
}
|
|
413
444
|
for (const id of ring) {
|
|
414
445
|
if (id !== activeId && eligible.has(id)) return id;
|
|
415
446
|
}
|
|
@@ -553,6 +584,10 @@ export function rotateGenericOAuthAccountOnRefusal(
|
|
|
553
584
|
}
|
|
554
585
|
return null;
|
|
555
586
|
}
|
|
587
|
+
if (strategy === "reset-first") {
|
|
588
|
+
return rankAccountsByResetFirst(providerName, candidates, requestedModelId, now,
|
|
589
|
+
new Map(set.accounts.map(account => [account.id, account])))[0] ?? null;
|
|
590
|
+
}
|
|
556
591
|
// With no quota evidence this returns the ring untouched, so providers without
|
|
557
592
|
// per-account quota keep exactly the traversal they have today.
|
|
558
593
|
return rankAccountsByHeadroom(providerName, candidates, requestedModelId,
|
|
@@ -613,6 +648,7 @@ export function preferredInitialAccount(
|
|
|
613
648
|
providerName: string,
|
|
614
649
|
now = Date.now(),
|
|
615
650
|
requestedModelId?: string | null,
|
|
651
|
+
activeAccountOverride?: string,
|
|
616
652
|
): string | null {
|
|
617
653
|
// The PROACTIVE predicate, not the reactive one: this steers a request upstream has not
|
|
618
654
|
// refused, so `oauthAccountFailover.enabled: false` must still be able to refuse it.
|
|
@@ -621,7 +657,7 @@ export function preferredInitialAccount(
|
|
|
621
657
|
// active id separately would delay manual selection and account removal.
|
|
622
658
|
const selected = getAccountSet(providerName);
|
|
623
659
|
if (!selected) return null;
|
|
624
|
-
const active = selected.activeAccountId;
|
|
660
|
+
const active = activeAccountOverride ?? selected.activeAccountId;
|
|
625
661
|
const accountRows = new Map(selected.accounts.map(account => [account.id, account]));
|
|
626
662
|
const order = selected.accounts
|
|
627
663
|
.filter(account => account.paused !== true && account.needsReauth !== true)
|
|
@@ -631,10 +667,13 @@ export function preferredInitialAccount(
|
|
|
631
667
|
const modelEligible = preferKiroModelSupport(providerName,
|
|
632
668
|
eligibleFailoverAccounts(providerName, now, classifyModelFamilyForQuota(providerName, requestedModelId)),
|
|
633
669
|
requestedModelId, config);
|
|
634
|
-
const activeLacks = providerName === "kiro"
|
|
635
|
-
&&
|
|
670
|
+
const activeLacks = (providerName === "kiro" || providerName === "google-antigravity")
|
|
671
|
+
&& !!active && !!requestedModelId
|
|
672
|
+
&& accountListsModel(providerName, active, requestedModelId) === false;
|
|
636
673
|
const listingSibling = activeLacks
|
|
637
|
-
? modelEligible.find(id => id !== active &&
|
|
674
|
+
? modelEligible.find(id => id !== active && (providerName === "kiro"
|
|
675
|
+
? kiroModelListingHasRoom(config, id, requestedModelId!)
|
|
676
|
+
: accountListsModel(providerName, id, requestedModelId!) === true))
|
|
638
677
|
: undefined;
|
|
639
678
|
if (listingSibling) return listingSibling;
|
|
640
679
|
|
|
@@ -670,9 +709,20 @@ export function preferredInitialAccount(
|
|
|
670
709
|
return picked && picked !== active ? picked : null;
|
|
671
710
|
}
|
|
672
711
|
if (strategy === "fill-first") {
|
|
673
|
-
const picked = pickFillFirstGenericAccount(config, providerName, active, now, requestedModelId, accountRows);
|
|
712
|
+
const picked = pickFillFirstGenericAccount(config, providerName, active, now, requestedModelId, accountRows, activeAccountOverride !== undefined);
|
|
674
713
|
return picked && picked !== active ? picked : null;
|
|
675
714
|
}
|
|
715
|
+
if (strategy === "reset-first") {
|
|
716
|
+
// Same candidate set as round-robin: paused, reauth-needed and cooled accounts are out,
|
|
717
|
+
// and an account whose model listing omits the requested model loses to one that has it.
|
|
718
|
+
// Reset ordering needs quota evidence; without it the ordinary active-account path runs.
|
|
719
|
+
const family = classifyModelFamilyForQuota(providerName, requestedModelId);
|
|
720
|
+
const eligibleNow = preferKiroModelSupport(providerName,
|
|
721
|
+
eligibleFailoverAccounts(providerName, now, family), requestedModelId, config);
|
|
722
|
+
if (eligibleNow.length === 0 || !hasHeadroomEvidence(providerName, eligibleNow, requestedModelId, accountRows)) return null;
|
|
723
|
+
const best = rankAccountsByResetFirst(providerName, eligibleNow, requestedModelId, now, accountRows)[0] ?? null;
|
|
724
|
+
return best && best !== active ? best : null;
|
|
725
|
+
}
|
|
676
726
|
|
|
677
727
|
const activeRow = selected.accounts.find(account => account.id === active);
|
|
678
728
|
if (activeRow && activeRow.paused !== true && activeRow.needsReauth !== true
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/** Request-local conversation ownership for opt-in generic OAuth pools. No credentials are retained. */
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { getConfigDir } from "../config/paths";
|
|
4
|
+
import { subscribeAccountSelections } from "../lib/account-selection-events";
|
|
5
|
+
import type { OcxConfig } from "../types";
|
|
6
|
+
import { classifyModelFamilyForQuota } from "./account-quota-rank";
|
|
7
|
+
import { eligibleFailoverAccounts, isGenericFailoverProvider, preferKiroModelSupport, preferredInitialAccount } from "./generic-account-failover";
|
|
8
|
+
import type { OAuthAccessSnapshot } from "./index";
|
|
9
|
+
import { captureOAuthAccountSelection, credentialGeneration, getAccountCredentialWithStatus } from "./store";
|
|
10
|
+
import type { OAuthAccountSelection } from "./types";
|
|
11
|
+
|
|
12
|
+
const IDLE_TTL_MS = 24 * 60 * 60_000;
|
|
13
|
+
const MAX_ENTRIES = 2_000;
|
|
14
|
+
const bindings = new Map<string, { accountId: string; lastUsedAt: number; selection: OAuthAccountSelection }>();
|
|
15
|
+
const prefix = (provider: string) => `${JSON.stringify([getConfigDir(), provider])}\u0000`;
|
|
16
|
+
const key = (provider: string, session: string) => prefix(provider) + "session:" + createHash("sha256").update(session).digest("hex");
|
|
17
|
+
const cursorKey = (provider: string) => prefix(provider) + "fill-first";
|
|
18
|
+
|
|
19
|
+
/** A persisted operator/roster/policy change revokes old session choices before its writer returns. */
|
|
20
|
+
export function clearGenericSessionAffinity(provider?: string): void {
|
|
21
|
+
if (!provider) { bindings.clear(); return; }
|
|
22
|
+
const scope = prefix(provider);
|
|
23
|
+
for (const id of bindings.keys()) if (id.startsWith(scope)) bindings.delete(id);
|
|
24
|
+
}
|
|
25
|
+
subscribeAccountSelections(event => { if (event.kind === "oauth") clearGenericSessionAffinity(event.provider); });
|
|
26
|
+
|
|
27
|
+
/** Unlike new-session strategy selection, keeping the surviving account needs no 2+ quorum. */
|
|
28
|
+
export function genericSessionAffinityEnabled(config: OcxConfig, provider: string): boolean {
|
|
29
|
+
const row = config.providers[provider];
|
|
30
|
+
const enabled = !!row && row.disabled !== true && provider !== "anthropic2" && isGenericFailoverProvider(provider, row)
|
|
31
|
+
&& row.oauthAccountFailover?.sessionAffinity === "conversation"
|
|
32
|
+
&& (row.oauthAccountFailover.enabled ?? config.oauthAccountFailover?.enabled) === true;
|
|
33
|
+
if (!enabled) clearGenericSessionAffinity(provider);
|
|
34
|
+
return enabled;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function genericSessionAccountEligible(
|
|
38
|
+
config: OcxConfig, provider: string, accountId: string, model?: string | null, now = Date.now(), allowActiveFallback = false,
|
|
39
|
+
): boolean {
|
|
40
|
+
const eligible = eligibleFailoverAccounts(provider, now, classifyModelFamilyForQuota(provider, model));
|
|
41
|
+
// Existing conversation ownership is independent of transient per-account load.
|
|
42
|
+
if (preferKiroModelSupport(provider, eligible, model).includes(accountId)) return true;
|
|
43
|
+
// Cached automatic exclusions remain preferences when no alternative exists. Preserve the
|
|
44
|
+
// ordinary active/singleton attempt and its upstream refusal instead of inventing a conflict.
|
|
45
|
+
if (!allowActiveFallback || eligible.length > 0 || captureOAuthAccountSelection(provider)?.accountId !== accountId) return false;
|
|
46
|
+
const row = getAccountCredentialWithStatus(provider, accountId);
|
|
47
|
+
return !!row && !row.paused && !row.needsReauth;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Peek only. The admitted snapshot, never a speculative token lookup, establishes ownership. */
|
|
51
|
+
export function genericSessionAccount(
|
|
52
|
+
config: OcxConfig, provider: string, session: string | null, model?: string | null, now = Date.now(),
|
|
53
|
+
): string | null {
|
|
54
|
+
if (!genericSessionAffinityEnabled(config, provider) || !session) return null;
|
|
55
|
+
return readBinding(config, provider, key(provider, session), model, now);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function readBinding(config: OcxConfig, provider: string, id: string, model: string | null | undefined, now: number): string | null {
|
|
59
|
+
const bound = bindings.get(id);
|
|
60
|
+
if (!bound) return null;
|
|
61
|
+
const current = captureOAuthAccountSelection(provider);
|
|
62
|
+
if (!current || current.accountId !== bound.selection.accountId || current.revision !== bound.selection.revision
|
|
63
|
+
|| now - bound.lastUsedAt >= IDLE_TTL_MS || now < bound.lastUsedAt
|
|
64
|
+
|| !genericSessionAccountEligible(config, provider, bound.accountId, model, now)) {
|
|
65
|
+
bindings.delete(id);
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
return bound.accountId;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** New sessions use the configured strategy; an ineligible active account cannot defeat release. */
|
|
72
|
+
export function preferredGenericSessionAccount(
|
|
73
|
+
config: OcxConfig, provider: string, session: string | null, model?: string | null, now = Date.now(),
|
|
74
|
+
): string | null {
|
|
75
|
+
if (!genericSessionAffinityEnabled(config, provider)) return null;
|
|
76
|
+
const bound = genericSessionAccount(config, provider, session, model, now);
|
|
77
|
+
if (bound) return bound;
|
|
78
|
+
const cursor = readBinding(config, provider, cursorKey(provider), model, now);
|
|
79
|
+
const active = cursor ?? captureOAuthAccountSelection(provider)?.accountId;
|
|
80
|
+
const preferred = preferredInitialAccount(config, provider, now, model, active);
|
|
81
|
+
if (preferred) return preferred;
|
|
82
|
+
if (active && genericSessionAccountEligible(config, provider, active, model, now)) return active;
|
|
83
|
+
return preferKiroModelSupport(provider,
|
|
84
|
+
eligibleFailoverAccounts(provider, now, classifyModelFamilyForQuota(provider, model)), model, config)[0]
|
|
85
|
+
?? captureOAuthAccountSelection(provider)?.accountId ?? null;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Validate against the operator's persisted selection without moving it. ALL automatic choices
|
|
90
|
+
* in affinity mode use this receipt, including unkeyed requests and failovers, so concurrent
|
|
91
|
+
* conversations cannot invalidate each other's selection revision. Manual A→B→A still fences.
|
|
92
|
+
*/
|
|
93
|
+
export function admitGenericSessionAccount(
|
|
94
|
+
config: OcxConfig, provider: string, expected: OAuthAccountSelection,
|
|
95
|
+
snapshot: OAuthAccessSnapshot, model?: string | null, modeEnabled = genericSessionAffinityEnabled(config, provider),
|
|
96
|
+
): OAuthAccountSelection | null {
|
|
97
|
+
if (!modeEnabled || snapshot.provider !== provider) return null;
|
|
98
|
+
const current = captureOAuthAccountSelection(provider);
|
|
99
|
+
if (!current || current.accountId !== expected.accountId || current.revision !== expected.revision) return null;
|
|
100
|
+
const row = getAccountCredentialWithStatus(provider, snapshot.accountId);
|
|
101
|
+
if (!row || row.paused || row.needsReauth || credentialGeneration(row.credential) !== snapshot.generation
|
|
102
|
+
|| !genericSessionAccountEligible(config, provider, snapshot.accountId, model, Date.now(), true)) return null;
|
|
103
|
+
return current;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function bindGenericSessionAccount(
|
|
107
|
+
config: OcxConfig, provider: string, session: string | null, accountId: string, model?: string | null, now = Date.now(),
|
|
108
|
+
): void {
|
|
109
|
+
if (!genericSessionAffinityEnabled(config, provider)
|
|
110
|
+
|| !genericSessionAccountEligible(config, provider, accountId, model, now)) return;
|
|
111
|
+
for (const [id, entry] of bindings) {
|
|
112
|
+
if (now - entry.lastUsedAt >= IDLE_TTL_MS || now < entry.lastUsedAt) bindings.delete(id);
|
|
113
|
+
}
|
|
114
|
+
const selection = captureOAuthAccountSelection(provider);
|
|
115
|
+
if (!selection) return;
|
|
116
|
+
const keep = (id: string) => {
|
|
117
|
+
bindings.delete(id);
|
|
118
|
+
bindings.set(id, { accountId, lastUsedAt: now, selection });
|
|
119
|
+
};
|
|
120
|
+
const hit = session && genericSessionAccount(config, provider, session, model, now) === accountId;
|
|
121
|
+
if (!hit && config.pool?.kernel === true && config.providers[provider]?.oauthAccountFailover?.strategy === "fill-first")
|
|
122
|
+
keep(cursorKey(provider));
|
|
123
|
+
if (session) keep(key(provider, session));
|
|
124
|
+
while (bindings.size > MAX_ENTRIES) bindings.delete(bindings.keys().next().value!);
|
|
125
|
+
}
|