@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
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chat Completions -> IR, directly (the Antigravity direct lane).
|
|
3
|
+
*
|
|
4
|
+
* The bridge decodes a Chat conversation twice: `chatCompletionsToResponsesBody`
|
|
5
|
+
* (`src/chat/inbound.ts`) projects it into Responses items, then `parseRequest`
|
|
6
|
+
* (`src/responses/parser.ts`) turns those items into the IR. This module walks the Chat messages
|
|
7
|
+
* once and builds the IR conversation itself: system text, messages, tool calls and results,
|
|
8
|
+
* prior reasoning and the tool catalog. It is the request-side twin of the direct client encoders
|
|
9
|
+
* (`src/protocols/encoders/`).
|
|
10
|
+
*
|
|
11
|
+
* Contract: for every Chat body the bridge accepts, `chatConversationToIr(body, model)` equals
|
|
12
|
+
* the `context` of `parseRequest(chatCompletionsToResponsesBody(body))`, and every body the bridge
|
|
13
|
+
* refuses is refused here with the same `ChatCompletionsRequestError` message in the same order.
|
|
14
|
+
* `tests/protocols/chat-ir-parity.test.ts` holds both sides over a fixture corpus. The rules
|
|
15
|
+
* mirrored here are the Chat translator's walk (leading-system hoist, held mid-batch
|
|
16
|
+
* instructions, tool-call naming, legacy function pairing) and the parser's assembly for the item
|
|
17
|
+
* kinds that walk produces (pending reasoning, the assistant placeholder, reasoning that arrives
|
|
18
|
+
* after its call, tool-result naming).
|
|
19
|
+
*
|
|
20
|
+
* Request settings (model, stream, reasoning, limits, tool choice, format) are not decoded here:
|
|
21
|
+
* they travel through the Responses core on `chatSettingsToResponsesBody`, so effort policy,
|
|
22
|
+
* tier and routing keep their single owner.
|
|
23
|
+
*/
|
|
24
|
+
import {
|
|
25
|
+
assistantReasoningText,
|
|
26
|
+
ChatCompletionsRequestError,
|
|
27
|
+
contentToText,
|
|
28
|
+
fileFromPart,
|
|
29
|
+
videoFromPart,
|
|
30
|
+
} from "../../chat/inbound";
|
|
31
|
+
import { chatImageUrlFromPart } from "../../chat/image-parts";
|
|
32
|
+
import { untranslatedChatInputMedia, untranslatedInputMediaMessage } from "../../responses/input-media";
|
|
33
|
+
import { inlineDocumentFromDataUrl } from "../../responses/inline-document";
|
|
34
|
+
import { functionCallArgumentsFromText } from "../../responses/parser";
|
|
35
|
+
import { normalizeVisualizationContext } from "../../responses/visualization-directives";
|
|
36
|
+
import { hasRoutedIdentity, nameRoutedIdentity } from "../../adapters/identity";
|
|
37
|
+
import { createToolChoiceResolver, namespacedToolName } from "../../types";
|
|
38
|
+
import type {
|
|
39
|
+
OcxAssistantMessage,
|
|
40
|
+
OcxContentPart,
|
|
41
|
+
OcxContext,
|
|
42
|
+
OcxMessage,
|
|
43
|
+
OcxParsedRequest,
|
|
44
|
+
OcxThinkingContent,
|
|
45
|
+
OcxTool,
|
|
46
|
+
OcxToolCall,
|
|
47
|
+
} from "../../types";
|
|
48
|
+
import type { PolicyRequestEvidence } from "../../routing/evaluator";
|
|
49
|
+
|
|
50
|
+
type Rec = Record<string, unknown>;
|
|
51
|
+
|
|
52
|
+
function isRec(value: unknown): value is Rec {
|
|
53
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** The parser's request-time naming of a proxy-authored identity sentence (#5217). */
|
|
57
|
+
function nameDestination(text: string, modelId: string): string {
|
|
58
|
+
return hasRoutedIdentity(text) ? nameRoutedIdentity(text, modelId) : text;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function imageDetail(part: Rec): string | undefined {
|
|
62
|
+
const detail = isRec(part.image_url) ? part.image_url.detail : part.detail;
|
|
63
|
+
return detail === "auto" || detail === "low" || detail === "high" ? detail : undefined;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** One file part as the IR carries inline bytes: a document, or the marker when undecodable. */
|
|
67
|
+
function filePart(part: Rec): OcxContentPart | null {
|
|
68
|
+
const file = fileFromPart(part);
|
|
69
|
+
if (!file) return null;
|
|
70
|
+
const fileData = file.file_data as string;
|
|
71
|
+
const filename = typeof file.filename === "string" ? file.filename : undefined;
|
|
72
|
+
return inlineDocumentFromDataUrl(fileData, filename)
|
|
73
|
+
?? { type: "text", text: filename ? `[file: ${filename}]` : "[file: inline data]" };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** User or tool content parts in source order; `media: false` keeps only text and images. */
|
|
77
|
+
function contentParts(content: unknown, media = true): OcxContentPart[] {
|
|
78
|
+
if (typeof content === "string") return content.length > 0 ? [{ type: "text", text: content }] : [];
|
|
79
|
+
if (!Array.isArray(content)) return [];
|
|
80
|
+
const parts: OcxContentPart[] = [];
|
|
81
|
+
for (const raw of content) {
|
|
82
|
+
if (typeof raw === "string") {
|
|
83
|
+
if (raw.length > 0) parts.push({ type: "text", text: raw });
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (!isRec(raw)) continue;
|
|
87
|
+
if ((raw.type === "text" || raw.type === "input_text" || raw.type === "output_text") && typeof raw.text === "string") {
|
|
88
|
+
parts.push({ type: "text", text: raw.text });
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const imageUrl = chatImageUrlFromPart(raw);
|
|
92
|
+
if (imageUrl) {
|
|
93
|
+
const detail = imageDetail(raw);
|
|
94
|
+
parts.push({ type: "image", imageUrl, ...(detail ? { detail } : {}) });
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
const video = videoFromPart(raw);
|
|
98
|
+
if (video) {
|
|
99
|
+
if (media) parts.push({ type: "video", videoUrl: video.url, ...(video.processing ? { processing: video.processing } : {}) });
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
if (!media) continue;
|
|
103
|
+
const file = filePart(raw);
|
|
104
|
+
if (file) parts.push(file);
|
|
105
|
+
}
|
|
106
|
+
return parts;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/** The parser collapses a lone text part to a plain string; images and documents stay structured. */
|
|
110
|
+
function collapsed(parts: OcxContentPart[]): string | OcxContentPart[] {
|
|
111
|
+
return parts.length === 1 && parts[0]!.type === "text" ? parts[0]!.text : parts;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function assistantTextParts(content: unknown): Array<{ type: "text"; text: string }> {
|
|
115
|
+
if (typeof content === "string") return content.length > 0 ? [{ type: "text", text: content }] : [];
|
|
116
|
+
if (!Array.isArray(content)) return [];
|
|
117
|
+
const parts: Array<{ type: "text"; text: string }> = [];
|
|
118
|
+
for (const raw of content) {
|
|
119
|
+
if (typeof raw === "string") {
|
|
120
|
+
if (raw.length > 0) parts.push({ type: "text", text: raw });
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if (isRec(raw) && (raw.type === "text" || raw.type === "output_text") && typeof raw.text === "string") {
|
|
124
|
+
parts.push({ type: "text", text: raw.text });
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return parts;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* The parser keeps an unsigned reasoning item's serialized form as its placeholder signature.
|
|
132
|
+
* The Chat translator's item is `{type, summary, content}` with one text in each, so the value is
|
|
133
|
+
* spelled out rather than produced by a Responses round trip.
|
|
134
|
+
*/
|
|
135
|
+
function unsignedReasoningSignature(text: string): string {
|
|
136
|
+
return JSON.stringify({
|
|
137
|
+
type: "reasoning",
|
|
138
|
+
summary: [{ type: "summary_text", text }],
|
|
139
|
+
content: [{ type: "reasoning_text", text }],
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* The parser's parameter normalization. The bridge's schema parse hands the parser a shallow
|
|
145
|
+
* copy of the caller's record, so this copies too: a sanitizer that edits the catalog in place
|
|
146
|
+
* must not reach the caller's body, which the lane may still need to re-decode.
|
|
147
|
+
* Shared with the direct Messages decoder (`messages-ir.ts`), whose tools pass the same schema.
|
|
148
|
+
*/
|
|
149
|
+
export function normalizedParameters(raw: unknown): Record<string, unknown> {
|
|
150
|
+
// The bridge's `z.record` copies own keys except `__proto__`, which JSON.parse can create.
|
|
151
|
+
const copy: Record<string, unknown> = {};
|
|
152
|
+
if (isRec(raw)) {
|
|
153
|
+
for (const key of Object.keys(raw)) {
|
|
154
|
+
if (key !== "__proto__") copy[key] = raw[key];
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (isRec(raw) && raw.type === "object") return copy;
|
|
158
|
+
return { ...copy, type: "object" };
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function functionTool(name: string, description: unknown, parameters: unknown, strict: unknown): OcxTool {
|
|
162
|
+
const tool: OcxTool = {
|
|
163
|
+
name,
|
|
164
|
+
description: typeof description === "string" ? description : "",
|
|
165
|
+
parameters: normalizedParameters(isRec(parameters) ? parameters : undefined),
|
|
166
|
+
};
|
|
167
|
+
if (typeof strict === "boolean") tool.strict = strict;
|
|
168
|
+
return tool;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/** `tools` then legacy `functions`, deduplicated by name as the parser's catalog merge does. */
|
|
172
|
+
function toolCatalog(raw: Rec): OcxTool[] {
|
|
173
|
+
const declared: OcxTool[] = [];
|
|
174
|
+
if (Array.isArray(raw.tools)) {
|
|
175
|
+
for (const entry of raw.tools) {
|
|
176
|
+
if (!isRec(entry) || entry.type !== "function") continue;
|
|
177
|
+
if (typeof entry.name === "string" && entry.name.length > 0) {
|
|
178
|
+
declared.push(functionTool(entry.name, entry.description, entry.parameters, entry.strict));
|
|
179
|
+
} else if (isRec(entry.function) && typeof entry.function.name === "string" && entry.function.name.length > 0) {
|
|
180
|
+
const fn = entry.function;
|
|
181
|
+
declared.push(functionTool(fn.name as string, fn.description, fn.parameters, fn.strict));
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (raw.functions !== undefined) {
|
|
186
|
+
if (!Array.isArray(raw.functions)) throw new ChatCompletionsRequestError("functions must be an array");
|
|
187
|
+
for (const entry of raw.functions) {
|
|
188
|
+
if (!isRec(entry) || typeof entry.name !== "string" || entry.name.length === 0) {
|
|
189
|
+
throw new ChatCompletionsRequestError("functions entries require a name");
|
|
190
|
+
}
|
|
191
|
+
declared.push(functionTool(entry.name, entry.description, entry.parameters, undefined));
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
const seen = new Set<string>();
|
|
195
|
+
return declared.filter(tool => {
|
|
196
|
+
const key = namespacedToolName(tool.namespace, tool.name);
|
|
197
|
+
if (seen.has(key)) return false;
|
|
198
|
+
seen.add(key);
|
|
199
|
+
return true;
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export interface ChatIrConversation {
|
|
204
|
+
/** The model the conversation was decoded for; identity naming and placeholders depend on it. */
|
|
205
|
+
modelId: string;
|
|
206
|
+
context: OcxContext;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Decode a Chat body's conversation straight into the IR context. Throws
|
|
211
|
+
* `ChatCompletionsRequestError` exactly where `chatCompletionsToResponsesBody` would.
|
|
212
|
+
*/
|
|
213
|
+
export function chatConversationToIr(raw: unknown, modelId: string): ChatIrConversation {
|
|
214
|
+
if (!isRec(raw) || !Array.isArray(raw.messages) || raw.messages.length === 0) {
|
|
215
|
+
throw new ChatCompletionsRequestError("messages must be a non-empty array");
|
|
216
|
+
}
|
|
217
|
+
const unsupportedMedia = untranslatedChatInputMedia(raw);
|
|
218
|
+
if (unsupportedMedia) throw new ChatCompletionsRequestError(untranslatedInputMediaMessage(unsupportedMedia));
|
|
219
|
+
|
|
220
|
+
const now = Date.now();
|
|
221
|
+
const systemParts: string[] = [];
|
|
222
|
+
const messages: OcxMessage[] = [];
|
|
223
|
+
let emitted = false;
|
|
224
|
+
const pending: OcxThinkingContent[] = [];
|
|
225
|
+
const knownNameByCallId = new Map<string, string>();
|
|
226
|
+
const legacyAwaiting: Array<{ callId: string; name: string }> = [];
|
|
227
|
+
let legacyCallSequence = 0;
|
|
228
|
+
const awaitingToolResult = new Set<string>();
|
|
229
|
+
const heldInstructions: string[] = [];
|
|
230
|
+
|
|
231
|
+
const pushDeveloper = (text: string): void => {
|
|
232
|
+
emitted = true;
|
|
233
|
+
pending.length = 0;
|
|
234
|
+
messages.push({ role: "developer", content: nameDestination(text, modelId), timestamp: now });
|
|
235
|
+
};
|
|
236
|
+
const releaseHeldInstructions = (): void => {
|
|
237
|
+
if (heldInstructions.length === 0) return;
|
|
238
|
+
pushDeveloper(heldInstructions.join("\n\n"));
|
|
239
|
+
heldInstructions.length = 0;
|
|
240
|
+
};
|
|
241
|
+
const beginConversationTurn = (): void => {
|
|
242
|
+
releaseHeldInstructions();
|
|
243
|
+
awaitingToolResult.clear();
|
|
244
|
+
legacyAwaiting.length = 0;
|
|
245
|
+
};
|
|
246
|
+
const assistantHolder = (): OcxAssistantMessage => {
|
|
247
|
+
const last = messages[messages.length - 1];
|
|
248
|
+
let holder: OcxAssistantMessage;
|
|
249
|
+
if (last && last.role === "assistant") holder = last;
|
|
250
|
+
else {
|
|
251
|
+
holder = { role: "assistant", content: [], model: modelId, timestamp: now };
|
|
252
|
+
messages.push(holder);
|
|
253
|
+
}
|
|
254
|
+
if (pending.length > 0) {
|
|
255
|
+
holder.content.push(...pending);
|
|
256
|
+
pending.length = 0;
|
|
257
|
+
}
|
|
258
|
+
return holder;
|
|
259
|
+
};
|
|
260
|
+
const pushToolCall = (callId: string, name: string, args: string): void => {
|
|
261
|
+
emitted = true;
|
|
262
|
+
const call: OcxToolCall = { type: "toolCall", id: callId, name, arguments: functionCallArgumentsFromText(callId, args) };
|
|
263
|
+
assistantHolder().content.push(call);
|
|
264
|
+
awaitingToolResult.add(callId);
|
|
265
|
+
};
|
|
266
|
+
const toolOwner = (callId: string): { name: string; namespace?: string } => {
|
|
267
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
268
|
+
const message = messages[i]!;
|
|
269
|
+
if (message.role !== "assistant") continue;
|
|
270
|
+
for (const part of message.content) {
|
|
271
|
+
if (part.type === "toolCall" && part.id === callId) return { name: part.name, namespace: part.namespace };
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
return { name: "" };
|
|
275
|
+
};
|
|
276
|
+
const pushToolResult = (callId: string, content: string | OcxContentPart[]): void => {
|
|
277
|
+
emitted = true;
|
|
278
|
+
// Reasoning replayed after the call it belongs to joins that call's assistant turn (#950).
|
|
279
|
+
if (pending.length > 0) {
|
|
280
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
281
|
+
const message = messages[i]!;
|
|
282
|
+
if (message.role !== "assistant") continue;
|
|
283
|
+
if (message.content.some(part => part.type === "toolCall" && part.id === callId)) {
|
|
284
|
+
message.content = [...pending, ...message.content];
|
|
285
|
+
break;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
pending.length = 0;
|
|
290
|
+
const owner = toolOwner(callId);
|
|
291
|
+
messages.push({
|
|
292
|
+
role: "toolResult", toolCallId: callId, toolName: owner.name, toolNamespace: owner.namespace,
|
|
293
|
+
content, isError: false, timestamp: now,
|
|
294
|
+
});
|
|
295
|
+
awaitingToolResult.delete(callId);
|
|
296
|
+
if (awaitingToolResult.size === 0) releaseHeldInstructions();
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
for (const msg of raw.messages) {
|
|
300
|
+
if (!isRec(msg)) continue;
|
|
301
|
+
const role = typeof msg.role === "string" ? msg.role : "";
|
|
302
|
+
switch (role) {
|
|
303
|
+
case "system":
|
|
304
|
+
case "developer": {
|
|
305
|
+
if (!emitted) {
|
|
306
|
+
const text = contentToText(msg.content).trim();
|
|
307
|
+
if (text) systemParts.push(text);
|
|
308
|
+
break;
|
|
309
|
+
}
|
|
310
|
+
const text = contentToText(msg.content).trim();
|
|
311
|
+
if (!text) break;
|
|
312
|
+
if (awaitingToolResult.size > 0) heldInstructions.push(text);
|
|
313
|
+
else pushDeveloper(text);
|
|
314
|
+
break;
|
|
315
|
+
}
|
|
316
|
+
case "user": {
|
|
317
|
+
beginConversationTurn();
|
|
318
|
+
const parts = contentParts(msg.content);
|
|
319
|
+
if (parts.length > 0) {
|
|
320
|
+
emitted = true;
|
|
321
|
+
pending.length = 0;
|
|
322
|
+
messages.push({ role: "user", content: collapsed(parts), timestamp: now });
|
|
323
|
+
}
|
|
324
|
+
break;
|
|
325
|
+
}
|
|
326
|
+
case "assistant": {
|
|
327
|
+
beginConversationTurn();
|
|
328
|
+
const reasoningText = assistantReasoningText(msg);
|
|
329
|
+
if (reasoningText !== undefined) {
|
|
330
|
+
emitted = true;
|
|
331
|
+
const part: OcxThinkingContent = {
|
|
332
|
+
type: "thinking",
|
|
333
|
+
thinking: reasoningText,
|
|
334
|
+
signature: unsignedReasoningSignature(reasoningText),
|
|
335
|
+
};
|
|
336
|
+
// Consecutive unsigned reasoning folds into one block, as the parser does.
|
|
337
|
+
const previous = pending[pending.length - 1];
|
|
338
|
+
if (previous && !previous.redacted) {
|
|
339
|
+
pending[pending.length - 1] = { ...part, thinking: `${previous.thinking}\n${part.thinking}` };
|
|
340
|
+
} else {
|
|
341
|
+
pending.push(part);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
const text = assistantTextParts(msg.content);
|
|
345
|
+
if (text.length > 0) {
|
|
346
|
+
emitted = true;
|
|
347
|
+
messages.push({
|
|
348
|
+
role: "assistant",
|
|
349
|
+
content: pending.length > 0 ? [...pending, ...text] : text,
|
|
350
|
+
model: modelId,
|
|
351
|
+
timestamp: now,
|
|
352
|
+
});
|
|
353
|
+
pending.length = 0;
|
|
354
|
+
}
|
|
355
|
+
if (msg.tool_calls !== undefined && Array.isArray(msg.tool_calls)) {
|
|
356
|
+
for (const entry of msg.tool_calls) {
|
|
357
|
+
if (!isRec(entry)) continue;
|
|
358
|
+
const fn = isRec(entry.function) ? entry.function : null;
|
|
359
|
+
let name = typeof fn?.name === "string" ? fn.name : typeof entry.name === "string" ? entry.name : "";
|
|
360
|
+
const args = typeof fn?.arguments === "string"
|
|
361
|
+
? fn.arguments
|
|
362
|
+
: typeof entry.arguments === "string"
|
|
363
|
+
? entry.arguments
|
|
364
|
+
: JSON.stringify(fn?.arguments ?? entry.arguments ?? {});
|
|
365
|
+
const callId = typeof entry.id === "string" && entry.id.length > 0
|
|
366
|
+
? entry.id
|
|
367
|
+
: typeof entry.call_id === "string" && entry.call_id.length > 0
|
|
368
|
+
? entry.call_id
|
|
369
|
+
: `call_${crypto.randomUUID().replace(/-/g, "").slice(0, 24)}`;
|
|
370
|
+
if (!name) name = knownNameByCallId.get(callId) ?? "";
|
|
371
|
+
if (!name) throw new ChatCompletionsRequestError("tool_calls entries require function.name");
|
|
372
|
+
knownNameByCallId.set(callId, name);
|
|
373
|
+
pushToolCall(callId, name, args);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
if (msg.function_call !== undefined && msg.function_call !== null) {
|
|
377
|
+
const value = msg.function_call;
|
|
378
|
+
if (!isRec(value) || typeof value.name !== "string" || value.name.length === 0) {
|
|
379
|
+
throw new ChatCompletionsRequestError("assistant function_call requires a name");
|
|
380
|
+
}
|
|
381
|
+
const args = typeof value.arguments === "string" ? value.arguments : JSON.stringify(value.arguments ?? {});
|
|
382
|
+
const callId = `call_legacy_${String(++legacyCallSequence).padStart(4, "0")}`;
|
|
383
|
+
knownNameByCallId.set(callId, value.name);
|
|
384
|
+
pushToolCall(callId, value.name, args);
|
|
385
|
+
legacyAwaiting.push({ callId, name: value.name });
|
|
386
|
+
}
|
|
387
|
+
break;
|
|
388
|
+
}
|
|
389
|
+
case "function": {
|
|
390
|
+
if (Array.isArray(msg.content) && msg.content.some(part => isRec(part) && chatImageUrlFromPart(part))) {
|
|
391
|
+
throw new ChatCompletionsRequestError(
|
|
392
|
+
"Legacy function-result image translation is not implemented. Use tool_calls and role:tool with tool_call_id.",
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
const name = typeof msg.name === "string" ? msg.name : "";
|
|
396
|
+
if (!name) throw new ChatCompletionsRequestError("function messages require a name");
|
|
397
|
+
const pendingIndex = legacyAwaiting.findIndex(call => call.name === name);
|
|
398
|
+
if (pendingIndex < 0) throw new ChatCompletionsRequestError(`function result has no pending call named ${name}`);
|
|
399
|
+
const [call] = legacyAwaiting.splice(pendingIndex, 1);
|
|
400
|
+
pushToolResult(call!.callId, contentToText(msg.content));
|
|
401
|
+
break;
|
|
402
|
+
}
|
|
403
|
+
case "tool": {
|
|
404
|
+
const callId = typeof msg.tool_call_id === "string" ? msg.tool_call_id
|
|
405
|
+
: typeof msg.tool_use_id === "string" ? msg.tool_use_id
|
|
406
|
+
: "";
|
|
407
|
+
if (!callId) throw new ChatCompletionsRequestError("tool messages require tool_call_id");
|
|
408
|
+
const parts = contentParts(msg.content, false);
|
|
409
|
+
pushToolResult(callId, parts.some(part => part.type === "image") ? parts : contentToText(msg.content));
|
|
410
|
+
break;
|
|
411
|
+
}
|
|
412
|
+
default:
|
|
413
|
+
break;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
releaseHeldInstructions();
|
|
417
|
+
|
|
418
|
+
if (!emitted && systemParts.length === 0) {
|
|
419
|
+
throw new ChatCompletionsRequestError("messages must include at least one user/assistant/tool turn");
|
|
420
|
+
}
|
|
421
|
+
const tools = toolCatalog(raw);
|
|
422
|
+
const context: OcxContext = {
|
|
423
|
+
...(systemParts.length > 0 ? { systemPrompt: [nameDestination(systemParts.join("\n\n"), modelId)] } : {}),
|
|
424
|
+
messages,
|
|
425
|
+
...(tools.length > 0 ? { tools } : {}),
|
|
426
|
+
};
|
|
427
|
+
return { modelId, context: normalizeVisualizationContext(context) };
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Put a directly decoded conversation onto the request the core parsed from the settings-only
|
|
432
|
+
* body. The conversation is re-decoded if the core settled a different model id than the one the
|
|
433
|
+
* ingress decoded for, because identity naming and assistant placeholders carry it. The tool
|
|
434
|
+
* choice is checked against the decoded catalog, which the settings-only parse could not see.
|
|
435
|
+
*/
|
|
436
|
+
export function withDirectChatConversation(
|
|
437
|
+
base: OcxParsedRequest,
|
|
438
|
+
chatBody: unknown,
|
|
439
|
+
decoded: ChatIrConversation,
|
|
440
|
+
): OcxParsedRequest {
|
|
441
|
+
const conversation = decoded.modelId === base.modelId ? decoded : chatConversationToIr(chatBody, base.modelId);
|
|
442
|
+
const choice = base.options.toolChoice;
|
|
443
|
+
if (choice && typeof choice === "object") {
|
|
444
|
+
const selectors = "allowedTools" in choice ? choice.allowedTools : [choice.name];
|
|
445
|
+
const resolver = createToolChoiceResolver(conversation.context.tools ?? []);
|
|
446
|
+
for (const selector of selectors) {
|
|
447
|
+
if (resolver.candidateCount(selector) > 1) throw new Error(`ambiguous tool_choice name: ${selector}`);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
return { ...base, context: conversation.context };
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/**
|
|
454
|
+
* The policy-routing evidence the core would have read from the bridge body
|
|
455
|
+
* (`evidenceFromBody`): a non-empty tool catalog, and an image in a user message. An image in a
|
|
456
|
+
* tool result sits under `output` on the bridge body, which that scan does not read, so it is
|
|
457
|
+
* not evidence here either.
|
|
458
|
+
*/
|
|
459
|
+
export function chatIrRouteEvidence(conversation: ChatIrConversation): PolicyRequestEvidence {
|
|
460
|
+
const tools = (conversation.context.tools?.length ?? 0) > 0;
|
|
461
|
+
const image = conversation.context.messages.some(message => message.role === "user"
|
|
462
|
+
&& Array.isArray(message.content) && message.content.some(part => part.type === "image"));
|
|
463
|
+
return {
|
|
464
|
+
...(tools ? { toolsRequired: true } : {}),
|
|
465
|
+
...(image ? { imageInputRequired: true } : {}),
|
|
466
|
+
};
|
|
467
|
+
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* (`src/chat/inbound.ts`), including its validation and the fields it drops, which
|
|
7
7
|
* `src/protocols/features.ts` declares.
|
|
8
8
|
*/
|
|
9
|
-
import { chatCompletionsToResponsesBody } from "../../chat/inbound";
|
|
9
|
+
import { chatCompletionsToResponsesBody, chatSettingsToResponsesBody } from "../../chat/inbound";
|
|
10
10
|
import { featuresFromChatBody } from "../features";
|
|
11
11
|
|
|
12
12
|
/** Project a Chat Completions body onto the internal Responses bridge body. */
|
|
@@ -14,4 +14,13 @@ export function chatToResponsesBody(body: unknown): Record<string, unknown> {
|
|
|
14
14
|
return chatCompletionsToResponsesBody(body);
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
/**
|
|
18
|
+
* The request settings alone, as a Responses body with an empty conversation: what the
|
|
19
|
+
* Antigravity direct lane hands the Responses core while the conversation is decoded by
|
|
20
|
+
* `chatConversationToIr` (`chat-ir.ts`).
|
|
21
|
+
*/
|
|
22
|
+
export function chatSettingsBody(body: unknown): Record<string, unknown> {
|
|
23
|
+
return chatSettingsToResponsesBody(body);
|
|
24
|
+
}
|
|
25
|
+
|
|
17
26
|
export const chatFeatures = featuresFromChatBody;
|