@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
|
@@ -24,6 +24,7 @@ import { clientEncoderForDelivery, deliverClientEncodedResponse } from "../infer
|
|
|
24
24
|
import { noteKiroServedSuccess } from "../../providers/kiro-usage";
|
|
25
25
|
import { persistKiroAccountState } from "../../providers/kiro-account-state-disk";
|
|
26
26
|
import { isCanonicalOpenAiForwardProvider } from "../../providers/openai-tiers";
|
|
27
|
+
import { guardEmptyToolCatalogEvents, guardEmptyToolCatalogStream } from "../../lib/empty-tool-catalog";
|
|
27
28
|
|
|
28
29
|
/** One responsibility of the Responses request pipeline; state owners are explicit. */
|
|
29
30
|
export async function deliverAdapterResponse(
|
|
@@ -34,6 +35,7 @@ export async function deliverAdapterResponse(
|
|
|
34
35
|
| "route"
|
|
35
36
|
| "translatorBudget"
|
|
36
37
|
| "toolBridgeMaps"
|
|
38
|
+
| "clientToolCatalogRestriction"
|
|
37
39
|
| "rememberKiroDeliveredFinalAnswer"
|
|
38
40
|
| "responseStateOptions"
|
|
39
41
|
>,
|
|
@@ -75,6 +77,10 @@ export async function deliverAdapterResponse(
|
|
|
75
77
|
const { routedCompaction } = sidecarState;
|
|
76
78
|
const bodyInactivityMs = resolveStallTimeoutMs(config.stallTimeoutSec, { localUpstream });
|
|
77
79
|
const upstreamRequestsStream = parsed.stream || isCanonicalOpenAiForwardProvider(route.provider);
|
|
80
|
+
const clientToolCatalog = requestState.clientToolCatalogRestriction && route.provider.authMode !== "forward"
|
|
81
|
+
? requestState.clientToolCatalogRestriction : undefined;
|
|
82
|
+
const deliveryToolBridgeMaps = clientToolCatalog
|
|
83
|
+
? { ...toolBridgeMaps, ...clientToolCatalog } : toolBridgeMaps;
|
|
78
84
|
|
|
79
85
|
|
|
80
86
|
if (parsed.stream) {
|
|
@@ -113,17 +119,31 @@ export async function deliverAdapterResponse(
|
|
|
113
119
|
continuation: next => fetchTerminalGuardContinuation(next, undefined, !parsed.stream),
|
|
114
120
|
})
|
|
115
121
|
: initialEventStream;
|
|
122
|
+
// Optional advisor guard (registered per request by the sidecar planner; absent unless the
|
|
123
|
+
// user enabled the advisor): holds synthetic `advisor` tool calls, consults the configured
|
|
124
|
+
// expert model, and re-dispatches the worker. Sits inside the empty-completion guard so an
|
|
125
|
+
// advisor-only turn never reads as an empty completion, and outside the bridge so the
|
|
126
|
+
// synthetic call never reaches the client.
|
|
127
|
+
const advisorStream = parsed._advisorGuard
|
|
128
|
+
? parsed._advisorGuard({
|
|
129
|
+
parsed,
|
|
130
|
+
translatorBudget,
|
|
131
|
+
firstEvents: eventStream,
|
|
132
|
+
continuation: fetchTerminalGuardContinuation,
|
|
133
|
+
})
|
|
134
|
+
: eventStream;
|
|
116
135
|
// The empty-completion guard sits OUTSIDE the terminal guard: a completed
|
|
117
136
|
// turn with no text and no tool call is retried with the IDENTICAL request
|
|
118
137
|
// (fetchTerminalGuardContinuation(parsed) replays the cached byte-identical
|
|
119
138
|
// request — same body, same headers, same signal).
|
|
120
|
-
const
|
|
139
|
+
const completionGuardedEventStream = emptyCompletionGuardEnabled
|
|
121
140
|
? guardEmptyCompletionEventStream({
|
|
122
|
-
firstEvents:
|
|
141
|
+
firstEvents: advisorStream,
|
|
123
142
|
continuation: fetchGuardedEmptyCompletionRetry,
|
|
124
143
|
})
|
|
125
|
-
:
|
|
126
|
-
const
|
|
144
|
+
: advisorStream;
|
|
145
|
+
const guardedEventStream = guardEmptyToolCatalogStream(completionGuardedEventStream, clientToolCatalog, translatorBudget);
|
|
146
|
+
const { toolNsMap, declaredToolNames, toolParameterSchemas, freeformToolNames, bareCustomToolNames, toolSearchToolNames } = deliveryToolBridgeMaps;
|
|
127
147
|
// One completion owner for both deliveries: the bridge calls it from its terminal, the
|
|
128
148
|
// direct client encoder from the fold of the same events.
|
|
129
149
|
const onCompletedResponse = (response: Record<string, unknown>, providerState?: OcxProviderContinuationState) => {
|
|
@@ -145,7 +165,9 @@ export async function deliverAdapterResponse(
|
|
|
145
165
|
}
|
|
146
166
|
notifyResponseComplete(response);
|
|
147
167
|
};
|
|
148
|
-
|
|
168
|
+
// The Responses bridge owns code-mode helper compilation; the direct encoder only renames.
|
|
169
|
+
const clientEncoder = clientToolCatalog?.bareCustomToolNames.has("exec") ? undefined
|
|
170
|
+
: clientEncoderForDelivery(options, logCtx, !!routedCompaction, transportState.activeAdapter.name);
|
|
149
171
|
if (clientEncoder) {
|
|
150
172
|
return deliverClientEncodedResponse({
|
|
151
173
|
encoder: clientEncoder,
|
|
@@ -184,9 +206,10 @@ export async function deliverAdapterResponse(
|
|
|
184
206
|
declaredToolNames,
|
|
185
207
|
bareCustomToolNames,
|
|
186
208
|
enforceDeclaredToolNames: options.inboundWire !== "chat" && options.inboundWire !== "anthropic",
|
|
209
|
+
terminalRefusalAsFailed: options.inboundWire !== "chat" && options.inboundWire !== "anthropic",
|
|
187
210
|
toolParameterSchemas,
|
|
188
211
|
...(options.onFirstOutput ? { onFirstOutput: options.onFirstOutput } : {}),
|
|
189
|
-
...(routedCompaction ? { compaction: true } : {}),
|
|
212
|
+
...(routedCompaction ? { compaction: true, compactionRetention: parsed._compactionRetention } : {}),
|
|
190
213
|
// Same grok-surface split as the runTurn branch above.
|
|
191
214
|
...(logCtx.surface === "grok" ? { heartbeatStyle: "comment" as const } : {}),
|
|
192
215
|
onUsage: usage => {
|
|
@@ -240,6 +263,17 @@ export async function deliverAdapterResponse(
|
|
|
240
263
|
} else {
|
|
241
264
|
guardedEvents = initialEvents;
|
|
242
265
|
}
|
|
266
|
+
// Optional advisor guard — same semantics as the streaming branch above.
|
|
267
|
+
if (parsed._advisorGuard) {
|
|
268
|
+
const advisorEvents: AdapterEvent[] = [];
|
|
269
|
+
for await (const event of parsed._advisorGuard({
|
|
270
|
+
parsed,
|
|
271
|
+
translatorBudget,
|
|
272
|
+
firstEvents: (async function* () { yield* guardedEvents; })(),
|
|
273
|
+
continuation: fetchTerminalGuardContinuation,
|
|
274
|
+
})) advisorEvents.push(event);
|
|
275
|
+
guardedEvents = advisorEvents;
|
|
276
|
+
}
|
|
243
277
|
if (emptyCompletionGuardEnabled) {
|
|
244
278
|
events = [];
|
|
245
279
|
for await (const event of guardEmptyCompletionEventStream({
|
|
@@ -257,8 +291,9 @@ export async function deliverAdapterResponse(
|
|
|
257
291
|
} finally {
|
|
258
292
|
cleanupUpstreamAbort();
|
|
259
293
|
}
|
|
260
|
-
const { toolNsMap, declaredToolNames, toolParameterSchemas, freeformToolNames, bareCustomToolNames, toolSearchToolNames } =
|
|
294
|
+
const { toolNsMap, declaredToolNames, toolParameterSchemas, freeformToolNames, bareCustomToolNames, toolSearchToolNames } = deliveryToolBridgeMaps;
|
|
261
295
|
let providerState: OcxProviderContinuationState | undefined;
|
|
296
|
+
events = guardEmptyToolCatalogEvents(events, clientToolCatalog, translatorBudget);
|
|
262
297
|
const json = buildResponseJSON(events, parsed._responseModelId ?? parsed.modelId, {
|
|
263
298
|
translatorBudget,
|
|
264
299
|
replayCacheScope: parsed._reasoningReplayScope,
|
|
@@ -271,7 +306,7 @@ export async function deliverAdapterResponse(
|
|
|
271
306
|
toolParameterSchemas,
|
|
272
307
|
freeformToolNames,
|
|
273
308
|
toolSearchToolNames,
|
|
274
|
-
...(routedCompaction ? { compaction: true } : {}),
|
|
309
|
+
...(routedCompaction ? { compaction: true, compactionRetention: parsed._compactionRetention } : {}),
|
|
275
310
|
onProviderState: state => { providerState = state; },
|
|
276
311
|
onUsage: usage => {
|
|
277
312
|
transportState.bindKeyUsageFromBridge(usage);
|
|
@@ -54,7 +54,7 @@ import { describeUpstreamConnectFailure } from "./upstream-error";
|
|
|
54
54
|
import type { OpaqueBlobRecoveryGuard } from "./core-opaque-recovery";
|
|
55
55
|
import type { AttemptRecoveryKind } from "../../usage/log";
|
|
56
56
|
import type { OAuthAccessSnapshot } from "../../oauth";
|
|
57
|
-
import { OAuthAccountPausedError, OAuthLoginRequiredError, publicOAuthAuthenticationErrorMessage } from "../../oauth";
|
|
57
|
+
import { OAuthAccountPausedError, OAuthLoginRequiredError, OAuthTokenRefreshBusyError, publicOAuthAuthenticationErrorMessage } from "../../oauth";
|
|
58
58
|
import { getAccountSet, markAccountNeedsReauthIfGeneration } from "../../oauth/store";
|
|
59
59
|
import { tryKiroAlternateAfterTerminalRefresh } from "../../oauth/kiro-terminal-failover";
|
|
60
60
|
import { classifyKiroRefusal } from "../../adapters/kiro-refusal";
|
|
@@ -112,6 +112,7 @@ import { mapCodexAuthContextErrorToResponse } from "./codex-auth-error";
|
|
|
112
112
|
import { chargeWorkflowSends } from "../../lib/workflow-budget";
|
|
113
113
|
import { isAntigravityValidationRefusal } from "./antigravity-validation-refusal";
|
|
114
114
|
import { unboundPoolSpendRefusalResponse } from "../workflow-refusal";
|
|
115
|
+
import { AdmissionModelDeniedError, admissionModelDeniedResponse } from "../admission-model-scope";
|
|
115
116
|
|
|
116
117
|
/** One responsibility of the Responses request pipeline; state owners are explicit. */
|
|
117
118
|
export async function prepareAdapterExchange(
|
|
@@ -225,8 +226,13 @@ export async function prepareAdapterExchange(
|
|
|
225
226
|
|
|
226
227
|
|
|
227
228
|
let selfContainedJudgment: boolean | undefined;
|
|
229
|
+
// On the Antigravity direct lane the raw body carries only settings; judge the body the bridge
|
|
230
|
+
// would have sent, built only if an ambiguous reset actually asks.
|
|
231
|
+
const directRequest = options.directRequest;
|
|
228
232
|
const requestIsSelfContained = (): boolean =>
|
|
229
|
-
selfContainedJudgment ??= selfContainedResponsesBody(
|
|
233
|
+
selfContainedJudgment ??= selfContainedResponsesBody(directRequest
|
|
234
|
+
? { ...(parsed._rawBody as Record<string, unknown>), ...directRequest.bridgeConversation() }
|
|
235
|
+
: parsed._rawBody);
|
|
230
236
|
const claimPreHeaderResend = (): boolean => authorizeResendForRecovery(
|
|
231
237
|
"pre-header", "connection-reset",
|
|
232
238
|
ambiguousResendAllowanceFor(route.provider, requestIsSelfContained, claimAmbiguousResend),
|
|
@@ -541,6 +547,10 @@ export async function prepareAdapterExchange(
|
|
|
541
547
|
return storageRefusal;
|
|
542
548
|
}
|
|
543
549
|
const refusal = err instanceof UpstreamRetryEvidenceError ? err.cause : err;
|
|
550
|
+
if (refusal instanceof AdmissionModelDeniedError) {
|
|
551
|
+
releaseCodexAuthContextProbeLease(admissionState.authCtx);
|
|
552
|
+
return admissionModelDeniedResponse(refusal);
|
|
553
|
+
}
|
|
544
554
|
const codexRefusal = mapCodexAuthContextErrorToResponse(unwrapUpstreamRetryEvidenceError(err), {
|
|
545
555
|
now: Date.now(), accountSelector: route.codexAccountNamespace,
|
|
546
556
|
});
|
|
@@ -810,6 +820,13 @@ export async function prepareAdapterExchange(
|
|
|
810
820
|
releaseCodexAuthContextProbeLease(admissionState.authCtx);
|
|
811
821
|
return { failed: storageRefusal };
|
|
812
822
|
}
|
|
823
|
+
const scopeRefusal = unwrapUpstreamRetryEvidenceError(err);
|
|
824
|
+
if (!options.abortSignal?.aborted && scopeRefusal instanceof AdmissionModelDeniedError) {
|
|
825
|
+
cleanupUpstreamAbort();
|
|
826
|
+
upstream.abort();
|
|
827
|
+
releaseCodexAuthContextProbeLease(admissionState.authCtx);
|
|
828
|
+
return { failed: admissionModelDeniedResponse(scopeRefusal) };
|
|
829
|
+
}
|
|
813
830
|
const codexRefusal = !options.abortSignal?.aborted && mapCodexAuthContextErrorToResponse(unwrapUpstreamRetryEvidenceError(err), {
|
|
814
831
|
now: Date.now(), accountSelector: route.codexAccountNamespace,
|
|
815
832
|
});
|
|
@@ -915,6 +932,15 @@ export async function prepareAdapterExchange(
|
|
|
915
932
|
try {
|
|
916
933
|
refreshed = await refreshResolvedOAuthSelection(transportState.sentOAuthSnapshot);
|
|
917
934
|
} catch (err) {
|
|
935
|
+
const cancelled = options.abortSignal?.aborted || req.signal.aborted;
|
|
936
|
+
if (cancelled || err instanceof OAuthTokenRefreshBusyError) {
|
|
937
|
+
cleanupUpstreamAbort();
|
|
938
|
+
upstream.abort();
|
|
939
|
+
try { void upstreamResponse.body?.cancel().catch(() => {}); } catch { /* already closed */ }
|
|
940
|
+
releaseCodexAuthContextProbeLease(admissionState.authCtx);
|
|
941
|
+
return cancelled ? clientCancelledResponse()
|
|
942
|
+
: formatErrorResponse(503, "server_error", publicOAuthAuthenticationErrorMessage(err), { retryAfter: "1" });
|
|
943
|
+
}
|
|
918
944
|
const failed = transportState.sentOAuthSnapshot;
|
|
919
945
|
if (route.providerName === "google-antigravity" && !antigravityAuthRotationAttempted
|
|
920
946
|
&& err instanceof OAuthLoginRequiredError && failed
|
|
@@ -1320,9 +1346,17 @@ export async function prepareAdapterExchange(
|
|
|
1320
1346
|
resolveWireProtocolOverride(route.providerName, route.modelId, route.provider, inboundWire, route.staticPolicy),
|
|
1321
1347
|
config.cacheRetention,
|
|
1322
1348
|
);
|
|
1349
|
+
bindRouteReasoningReplayScope({
|
|
1350
|
+
parsed,
|
|
1351
|
+
providerName: route.providerName,
|
|
1352
|
+
provider: route.provider,
|
|
1353
|
+
adapterName: transportState.activeAdapter.name,
|
|
1354
|
+
oauthCredentialSnapshot: transportState.replayOAuthCredentialSnapshot,
|
|
1355
|
+
});
|
|
1323
1356
|
sealRequestAttemptIdentity(logCtx.activeAttempt, logCtx.provider, transportState.activeAdapter.name, logCtx.accountLogLabel);
|
|
1324
1357
|
recordAttemptCredentialSource(logCtx.activeAttempt, route.providerName, route.provider, transportState.activeAdapter.name);
|
|
1325
|
-
const result = await rebuildAndRefetch(upstreamResponse.status === 401 ? "oauth-401"
|
|
1358
|
+
const result = await rebuildAndRefetch(upstreamResponse.status === 401 ? "oauth-401"
|
|
1359
|
+
: upstreamResponse.status === 403 ? "oauth-account-403" : "anthropic-oauth-429");
|
|
1326
1360
|
if ("failed" in result) return result.failed;
|
|
1327
1361
|
upstreamResponse = result;
|
|
1328
1362
|
if (isNonReplayableResponse(upstreamResponse)) continue recovery;
|
|
@@ -1539,7 +1573,17 @@ export async function prepareAdapterExchange(
|
|
|
1539
1573
|
// The hop's permit is already settled by the dispatch boundary above; continuing
|
|
1540
1574
|
// only skips the remaining arms, it does not abandon a reservation.
|
|
1541
1575
|
if (isNonReplayableResponse(upstreamResponse)) continue recovery;
|
|
1542
|
-
} catch {
|
|
1576
|
+
} catch (err) {
|
|
1577
|
+
// A local admission denial is terminal for the whole request: rotating to another
|
|
1578
|
+
// account cannot re-scope the key, so the refusal answers in place of the 429.
|
|
1579
|
+
const scopeRefusal = unwrapUpstreamRetryEvidenceError(err);
|
|
1580
|
+
if (!options.abortSignal?.aborted && scopeRefusal instanceof AdmissionModelDeniedError) {
|
|
1581
|
+
hop.permit?.release();
|
|
1582
|
+
cleanupUpstreamAbort();
|
|
1583
|
+
upstream.abort();
|
|
1584
|
+
releaseCodexAuthContextProbeLease(admissionState.authCtx);
|
|
1585
|
+
return admissionModelDeniedResponse(scopeRefusal);
|
|
1586
|
+
}
|
|
1543
1587
|
// A throw before the send — snapshot fetch, credential application, adapter
|
|
1544
1588
|
// resolution — must hand the reservation back. Without this the ladder charges the
|
|
1545
1589
|
// request for a send it never made, and a later recovery in the same request is
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** Core-owned, config-scoped registration. An inactive install has no Advisor factory. */
|
|
2
|
+
import type { OcxConfig, OcxParsedRequest, OcxTool } from "../../types";
|
|
3
|
+
|
|
4
|
+
export interface AdvisorPlanInput {
|
|
5
|
+
config: OcxConfig;
|
|
6
|
+
workerIdentity: string;
|
|
7
|
+
workerModelId: string;
|
|
8
|
+
abortSignal?: AbortSignal;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface RegisteredAdvisorPlan {
|
|
12
|
+
tool: OcxTool;
|
|
13
|
+
preflightInject(parsed: OcxParsedRequest): Promise<boolean>;
|
|
14
|
+
attachGuard(parsed: OcxParsedRequest): void;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
type AdvisorPlanFactory = (input: AdvisorPlanInput) => Promise<RegisteredAdvisorPlan | null>;
|
|
18
|
+
const factories = new WeakMap<OcxConfig, AdvisorPlanFactory>();
|
|
19
|
+
|
|
20
|
+
export function setAdvisorPlanFactory(config: OcxConfig, factory: AdvisorPlanFactory | null): void {
|
|
21
|
+
if (factory) factories.set(config, factory);
|
|
22
|
+
else factories.delete(config);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function createRegisteredAdvisorPlan(input: AdvisorPlanInput): Promise<RegisteredAdvisorPlan | null> | null {
|
|
26
|
+
return factories.get(input.config)?.(input) ?? null;
|
|
27
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { jsonUtf8Bytes } from "../../lib/json-byte-size";
|
|
2
|
+
import {
|
|
3
|
+
TRANSLATOR_MAX_TURN_BYTES,
|
|
4
|
+
TranslatorBudgetExceededError,
|
|
5
|
+
type TranslatorBudget,
|
|
6
|
+
} from "../../lib/translator-budget";
|
|
7
|
+
import type { AdapterEvent, OcxMessage, OcxUsage } from "../../types";
|
|
8
|
+
import { mergeUsage } from "./terminal-guard";
|
|
9
|
+
|
|
10
|
+
export const MAX_ADVISOR_RETAINED_EVENTS = 4_096;
|
|
11
|
+
export const MAX_ADVISOR_RETAINED_CALLS = 1_024;
|
|
12
|
+
|
|
13
|
+
/** Independent ownership: never borrow the bridge's event or tool-call leases. */
|
|
14
|
+
export class AdvisorRetention {
|
|
15
|
+
private legBytes = 0;
|
|
16
|
+
private historyBytes = 0;
|
|
17
|
+
private copyBytes = 0;
|
|
18
|
+
private usageBytes = 0;
|
|
19
|
+
private events = 0;
|
|
20
|
+
private calls = 0;
|
|
21
|
+
|
|
22
|
+
constructor(private readonly shared?: TranslatorBudget) {}
|
|
23
|
+
|
|
24
|
+
private charge(bytes: number, kind: "retained_collectors" | "request_copies"): void {
|
|
25
|
+
if (bytes > TRANSLATOR_MAX_TURN_BYTES - this.legBytes - this.historyBytes - this.copyBytes - this.usageBytes) {
|
|
26
|
+
throw new TranslatorBudgetExceededError(kind, TRANSLATOR_MAX_TURN_BYTES);
|
|
27
|
+
}
|
|
28
|
+
this.shared?.chargeRetained(bytes, { kind });
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Usage can alias a terminal payload. Keep its own owner after the raw leg ends. */
|
|
32
|
+
usage(first: OcxUsage | undefined, second: OcxUsage | undefined): OcxUsage | undefined {
|
|
33
|
+
if (!second) return first;
|
|
34
|
+
// Two-input merge materializes a new object. Reserve before merging, including
|
|
35
|
+
// a conservative bound for concatenation if a provider supplied malformed scalars.
|
|
36
|
+
const bytes = first
|
|
37
|
+
? (jsonUtf8Bytes(first) + jsonUtf8Bytes(second)) * 2 + 256
|
|
38
|
+
: jsonUtf8Bytes(second) + 1;
|
|
39
|
+
this.charge(bytes, "request_copies");
|
|
40
|
+
this.copyBytes += bytes;
|
|
41
|
+
let retained = 0;
|
|
42
|
+
try {
|
|
43
|
+
const merged = mergeUsage(first, second);
|
|
44
|
+
const measured = jsonUtf8Bytes(merged, bytes) + 1;
|
|
45
|
+
if (measured > bytes) throw new TranslatorBudgetExceededError("request_copies", TRANSLATOR_MAX_TURN_BYTES);
|
|
46
|
+
retained = measured;
|
|
47
|
+
const previous = this.usageBytes;
|
|
48
|
+
this.usageBytes = retained;
|
|
49
|
+
this.shared?.releaseRetained(previous, { kind: "request_copies" });
|
|
50
|
+
return merged;
|
|
51
|
+
} finally {
|
|
52
|
+
this.copyBytes -= bytes;
|
|
53
|
+
this.shared?.releaseRetained(bytes - retained, { kind: "request_copies" });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* `counted: false` is only for non-empty text/thinking deltas: the leg's 16 KiB character
|
|
59
|
+
* caps already bound how many of those can be held, and an ordinary long answer streams
|
|
60
|
+
* thousands of them. They still consume bytes.
|
|
61
|
+
*/
|
|
62
|
+
retain(event: AdapterEvent, call = false, counted = true): void {
|
|
63
|
+
if ((counted && this.events >= MAX_ADVISOR_RETAINED_EVENTS) || (call && this.calls >= MAX_ADVISOR_RETAINED_CALLS)) {
|
|
64
|
+
throw new TranslatorBudgetExceededError("retained_collectors", TRANSLATOR_MAX_TURN_BYTES);
|
|
65
|
+
}
|
|
66
|
+
const bytes = jsonUtf8Bytes(event) + 1;
|
|
67
|
+
this.charge(bytes, "retained_collectors");
|
|
68
|
+
this.legBytes += bytes;
|
|
69
|
+
if (counted) this.events++;
|
|
70
|
+
if (call) this.calls++;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Hold a bounded materialization while its raw sources are still retained. */
|
|
74
|
+
copy<T>(bytes: number, build: () => T): T {
|
|
75
|
+
this.charge(bytes, "request_copies");
|
|
76
|
+
this.copyBytes += bytes;
|
|
77
|
+
try { return build(); }
|
|
78
|
+
finally {
|
|
79
|
+
this.copyBytes -= bytes;
|
|
80
|
+
this.shared?.releaseRetained(bytes, { kind: "request_copies" });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Reserve before constructing replay JSON; transfer the reservation to history. */
|
|
85
|
+
history<T extends OcxMessage | undefined>(bytes: number, build: () => T): T {
|
|
86
|
+
this.charge(bytes, "request_copies");
|
|
87
|
+
this.copyBytes += bytes;
|
|
88
|
+
let retained = 0;
|
|
89
|
+
try {
|
|
90
|
+
const message = build();
|
|
91
|
+
const measured = message ? jsonUtf8Bytes(message, bytes) + 1 : 0;
|
|
92
|
+
if (measured > bytes) throw new TranslatorBudgetExceededError("request_copies", TRANSLATOR_MAX_TURN_BYTES);
|
|
93
|
+
retained = measured;
|
|
94
|
+
this.historyBytes += retained;
|
|
95
|
+
return message;
|
|
96
|
+
} finally {
|
|
97
|
+
this.copyBytes -= bytes;
|
|
98
|
+
this.shared?.releaseRetained(bytes - retained, { kind: "request_copies" });
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Event envelopes dominate the replay content; allow new message/call framing too. */
|
|
103
|
+
replayReservation(): number { return this.legBytes + (this.calls + 1) * 256; }
|
|
104
|
+
|
|
105
|
+
releaseLeg(): void {
|
|
106
|
+
this.shared?.releaseRetained(this.legBytes, { kind: "retained_collectors" });
|
|
107
|
+
this.legBytes = this.events = this.calls = 0;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
release(): void {
|
|
111
|
+
this.releaseLeg();
|
|
112
|
+
this.shared?.releaseRetained(this.historyBytes, { kind: "request_copies" });
|
|
113
|
+
this.historyBytes = 0;
|
|
114
|
+
this.shared?.releaseRetained(this.usageBytes, { kind: "request_copies" });
|
|
115
|
+
this.usageBytes = 0;
|
|
116
|
+
}
|
|
117
|
+
}
|