@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
|
@@ -2,6 +2,7 @@ import type { OcxUsage } from "../../types";
|
|
|
2
2
|
import type { AgentServerMessage, McpArgs, ToolCall } from "./gen/agent_pb";
|
|
3
3
|
import { decodeCursorArgsMap } from "./arg-codec";
|
|
4
4
|
import { normalizeArgKeys } from "./arg-normalize";
|
|
5
|
+
import { canonicalCursorFreeformArgs } from "./freeform-args";
|
|
5
6
|
import {
|
|
6
7
|
CODEX_APPLY_PATCH_TOOL,
|
|
7
8
|
CURSOR_MULTI_EDIT_TOOL,
|
|
@@ -334,9 +335,20 @@ function toolSchemaForWireName(state: CursorProtobufEventState, toolName: string
|
|
|
334
335
|
return resolveShellBridgeAliasKey(toolName, alias => state.toolSchemas!.get(alias));
|
|
335
336
|
}
|
|
336
337
|
|
|
337
|
-
function
|
|
338
|
-
|
|
338
|
+
function isFreeformCall(state: CursorProtobufEventState, responsesName: string | undefined): boolean {
|
|
339
|
+
return responsesName !== undefined && state.freeformToolNames?.has(responsesName) === true;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function decodeMcpArgsNormalized(
|
|
343
|
+
args: McpArgs | undefined,
|
|
344
|
+
state: CursorProtobufEventState,
|
|
345
|
+
openResponsesName?: string,
|
|
346
|
+
): string {
|
|
339
347
|
const toolName = mcpWireNameFromArgs(args);
|
|
348
|
+
const responsesName = toolName
|
|
349
|
+
? responsesToolNameFromCursorWire(toolName, state.cursorToolNameMap)
|
|
350
|
+
: openResponsesName;
|
|
351
|
+
const decoded = decodeCursorArgsMap(args?.args, { preserveStrings: isFreeformCall(state, responsesName) });
|
|
340
352
|
const schema = toolSchemaForWireName(state, toolName);
|
|
341
353
|
if (schema) return JSON.stringify(normalizeArgKeys(decoded, schema));
|
|
342
354
|
return JSON.stringify(decoded);
|
|
@@ -381,8 +393,13 @@ function normalizeJsonText(text: string, toolName: string | undefined, state: Cu
|
|
|
381
393
|
* preserved verbatim so the bridge can reject malformed or truncated JSON instead of silently
|
|
382
394
|
* converting it to `{}`. A genuinely empty buffer remains the no-argument case.
|
|
383
395
|
*/
|
|
384
|
-
function resolveCompletedArgs(
|
|
385
|
-
|
|
396
|
+
function resolveCompletedArgs(
|
|
397
|
+
buffered: string,
|
|
398
|
+
args: McpArgs | undefined,
|
|
399
|
+
state: CursorProtobufEventState,
|
|
400
|
+
openResponsesName?: string,
|
|
401
|
+
): string {
|
|
402
|
+
if (hasMcpArgBytes(args)) return decodeMcpArgsNormalized(args, state, openResponsesName);
|
|
386
403
|
const name = mcpWireNameFromArgs(args);
|
|
387
404
|
if (isCompleteJson(buffered)) return normalizeJsonText(buffered, name, state);
|
|
388
405
|
return buffered;
|
|
@@ -1092,7 +1109,7 @@ export function mapSyntheticMcpExecToToolEvents(
|
|
|
1092
1109
|
const out: CursorServerMessage[] = [...recordToolCall(options.state, callId, cursorWireName)];
|
|
1093
1110
|
if (out.some(event => event.type === "error")) return out;
|
|
1094
1111
|
const open = options.state.openToolCalls.get(callId);
|
|
1095
|
-
const finalArgs = resolveCompletedArgs(open?.args ?? "", args, options.state);
|
|
1112
|
+
const finalArgs = resolveCompletedArgs(open?.args ?? "", args, options.state, open?.name);
|
|
1096
1113
|
out.push(...commitToolCall(options.state, callId, finalArgs));
|
|
1097
1114
|
return out;
|
|
1098
1115
|
}
|
|
@@ -1167,23 +1184,16 @@ function discardBufferedTextToolCalls(state: CursorProtobufEventState): void {
|
|
|
1167
1184
|
* recorded in `openToolCalls`. Because each completion emits a whole non-interleaved unit, the bridge
|
|
1168
1185
|
* (which tracks a single current tool call) serializes parallel Cursor calls correctly.
|
|
1169
1186
|
*/
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
return !!parsed
|
|
1174
|
-
&& typeof parsed === "object"
|
|
1175
|
-
&& !Array.isArray(parsed)
|
|
1176
|
-
&& typeof (parsed as Record<string, unknown>).input === "string";
|
|
1177
|
-
} catch {
|
|
1178
|
-
return false;
|
|
1179
|
-
}
|
|
1187
|
+
/** True when the args already carry a body this call can commit, canonical or repairable (#7049). */
|
|
1188
|
+
function cursorFreeformArgsCommittable(args: string, toolName: string): boolean {
|
|
1189
|
+
return canonicalCursorFreeformArgs(args, toolName).ok;
|
|
1180
1190
|
}
|
|
1181
1191
|
|
|
1182
|
-
function dropInvalidFreeformCall(state: CursorProtobufEventState, callId: string, toolName: string): CursorServerMessage[] {
|
|
1192
|
+
function dropInvalidFreeformCall(state: CursorProtobufEventState, callId: string, toolName: string, reason: string): CursorServerMessage[] {
|
|
1183
1193
|
state.openToolCalls.delete(callId);
|
|
1184
1194
|
state.translatorBudget?.closeCall(callId);
|
|
1185
1195
|
state.completedToolCalls.add(callId);
|
|
1186
|
-
return [{ type: "error", message: `${toolName} call had invalid freeform arguments; expected {input:string}` }];
|
|
1196
|
+
return [{ type: "error", message: `${toolName} call had invalid freeform arguments; expected {input:string} (${reason})` }];
|
|
1187
1197
|
}
|
|
1188
1198
|
|
|
1189
1199
|
function dropShellBridgeCall(state: CursorProtobufEventState, callId: string, toolName: string): CursorServerMessage[] {
|
|
@@ -1202,11 +1212,14 @@ function dropStructuredEditCall(state: CursorProtobufEventState, callId: string,
|
|
|
1202
1212
|
return [{ type: "text", text: `\n${toolName} call was not converted to apply_patch: ${reason}` }];
|
|
1203
1213
|
}
|
|
1204
1214
|
|
|
1205
|
-
function commitToolCall(state: CursorProtobufEventState, callId: string,
|
|
1215
|
+
function commitToolCall(state: CursorProtobufEventState, callId: string, committedArgs: string): CursorServerMessage[] {
|
|
1206
1216
|
const open = state.openToolCalls.get(callId);
|
|
1207
1217
|
if (!open) return [];
|
|
1208
|
-
|
|
1209
|
-
|
|
1218
|
+
let finalArgs = committedArgs;
|
|
1219
|
+
if (isFreeformCall(state, open.name)) {
|
|
1220
|
+
const freeform = canonicalCursorFreeformArgs(finalArgs, open.name);
|
|
1221
|
+
if (!freeform.ok) return dropInvalidFreeformCall(state, callId, open.name, freeform.reason);
|
|
1222
|
+
finalArgs = freeform.args;
|
|
1210
1223
|
}
|
|
1211
1224
|
const schema = toolSchemaForWireName(state, open.name);
|
|
1212
1225
|
if (!cursorShellBridgeArgsValid(finalArgs, open.name, schema)) {
|
|
@@ -1386,7 +1399,7 @@ export function mapCursorProtobufServerMessage(
|
|
|
1386
1399
|
&& (
|
|
1387
1400
|
(name !== undefined && openBeforeStart.args.length === 0)
|
|
1388
1401
|
|| (state.freeformToolNames?.has(openBeforeStart.name) === true
|
|
1389
|
-
&& !
|
|
1402
|
+
&& !cursorFreeformArgsCommittable(openBeforeStart.args, openBeforeStart.name)
|
|
1390
1403
|
)
|
|
1391
1404
|
)
|
|
1392
1405
|
) {
|
|
@@ -1410,13 +1423,13 @@ export function mapCursorProtobufServerMessage(
|
|
|
1410
1423
|
if (
|
|
1411
1424
|
!openBeforeStart && open && !hasMcpArgBytes(args)
|
|
1412
1425
|
&& state.freeformToolNames?.has(open.name) === true
|
|
1413
|
-
&& !
|
|
1426
|
+
&& !cursorFreeformArgsCommittable(open.args, open.name)
|
|
1414
1427
|
) {
|
|
1415
1428
|
open.awaitingNativeArgs = true;
|
|
1416
1429
|
return [];
|
|
1417
1430
|
}
|
|
1418
1431
|
if (open) {
|
|
1419
|
-
const finalArgs = resolveCompletedArgs(open.args, args, state);
|
|
1432
|
+
const finalArgs = resolveCompletedArgs(open.args, args, state, open.name);
|
|
1420
1433
|
out.push(...commitToolCall(state, update.value.callId, finalArgs));
|
|
1421
1434
|
}
|
|
1422
1435
|
return out;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { IncomingMeta, ProviderAdapter } from "./base";
|
|
2
|
+
import { createAnthropicAdapter } from "./anthropic";
|
|
3
|
+
import type { AdapterFactoryContext } from "./registry";
|
|
4
|
+
import type { OcxParsedRequest, OcxProviderConfig } from "../types";
|
|
5
|
+
import { resolveDshAccountMessagesUrl } from "../providers/dsh-account-destination";
|
|
6
|
+
|
|
7
|
+
export { DSH_ACCOUNT_DEFAULT_MESSAGES_URL, resolveDshAccountMessagesUrl } from "../providers/dsh-account-destination";
|
|
8
|
+
|
|
9
|
+
export const DSH_ACCOUNT_RESERVED_HEADERS = new Set([
|
|
10
|
+
"x-dsh-auth-token",
|
|
11
|
+
"anthropic-version",
|
|
12
|
+
"authorization",
|
|
13
|
+
"x-api-key",
|
|
14
|
+
"host",
|
|
15
|
+
]);
|
|
16
|
+
|
|
17
|
+
export function createDshAccountAdapter(
|
|
18
|
+
provider: OcxProviderConfig,
|
|
19
|
+
_context?: AdapterFactoryContext,
|
|
20
|
+
): ProviderAdapter {
|
|
21
|
+
// Use key authMode internally so that createAnthropicAdapter doesn't inject Claude Code headers/prompt.
|
|
22
|
+
const baseAdapter = createAnthropicAdapter({
|
|
23
|
+
...provider,
|
|
24
|
+
authMode: "key",
|
|
25
|
+
}, "none");
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
...baseAdapter,
|
|
29
|
+
name: "dsh-account",
|
|
30
|
+
|
|
31
|
+
formatErrorBody(status: number, headers: Headers, payloadText: string): string {
|
|
32
|
+
if (status === 401) {
|
|
33
|
+
return "DeepSeek Harness account authentication failed (401 / ACCOUNT_TOKEN_INVALID). Please sign in to DeepSeek Harness Desktop and re-import.";
|
|
34
|
+
}
|
|
35
|
+
return baseAdapter.formatErrorBody?.(status, headers, payloadText) ?? payloadText;
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
async buildRequest(parsed: OcxParsedRequest, incoming: IncomingMeta) {
|
|
39
|
+
const token = provider.apiKey?.trim();
|
|
40
|
+
if (!token) {
|
|
41
|
+
throw new Error("DeepSeek Harness account token missing — import your account in Providers > DeepSeek Account (DSH)");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Fail-closed if custom provider configuration attempts to set any reserved header
|
|
45
|
+
if (provider.headers) {
|
|
46
|
+
for (const key of Object.keys(provider.headers)) {
|
|
47
|
+
if (DSH_ACCOUNT_RESERVED_HEADERS.has(key.toLowerCase())) {
|
|
48
|
+
throw new Error(`Reserved header "${key}" cannot be overridden in dsh-account provider configuration`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const req = await baseAdapter.buildRequest(parsed, incoming);
|
|
54
|
+
const url = resolveDshAccountMessagesUrl(provider.baseUrl);
|
|
55
|
+
|
|
56
|
+
const headers: Record<string, string> = { ...req.headers };
|
|
57
|
+
|
|
58
|
+
// Apply custom provider headers strictly before authoritative authentication headers
|
|
59
|
+
if (provider.headers) {
|
|
60
|
+
for (const [key, value] of Object.entries(provider.headers)) {
|
|
61
|
+
if (!DSH_ACCOUNT_RESERVED_HEADERS.has(key.toLowerCase()) && typeof value === "string") {
|
|
62
|
+
headers[key] = value;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Authoritative cleanup: strip any API key or Claude headers
|
|
68
|
+
for (const key of Object.keys(headers)) {
|
|
69
|
+
const lower = key.toLowerCase();
|
|
70
|
+
if (
|
|
71
|
+
lower === "authorization"
|
|
72
|
+
|| lower === "x-api-key"
|
|
73
|
+
|| lower === "x-dsh-auth-token"
|
|
74
|
+
|| lower === "anthropic-version"
|
|
75
|
+
|| lower === "anthropic-beta"
|
|
76
|
+
|| lower === "x-claude-code-session-id"
|
|
77
|
+
|| lower === "x-client-request-id"
|
|
78
|
+
) {
|
|
79
|
+
delete headers[key];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Set authoritative DeepSeek Harness Account headers strictly at the end
|
|
84
|
+
headers["x-dsh-auth-token"] = token;
|
|
85
|
+
headers["anthropic-version"] = "2023-06-01";
|
|
86
|
+
if (!headers["Content-Type"]) headers["Content-Type"] = "application/json";
|
|
87
|
+
if (!headers["Accept"]) headers["Accept"] = parsed.stream ? "text/event-stream" : "application/json";
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
...req,
|
|
91
|
+
url,
|
|
92
|
+
headers,
|
|
93
|
+
redirect: "manual",
|
|
94
|
+
};
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import type { OcxContentPart, OcxParsedRequest } from "../types";
|
|
3
|
-
import { antigravityUserAgent } from "./client-fingerprint";
|
|
3
|
+
import { antigravityCliUserAgent, antigravityUserAgent } from "./client-fingerprint";
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Antigravity request User-Agent. Mirrors the real Antigravity IDE UA
|
|
@@ -11,6 +11,27 @@ import { antigravityUserAgent } from "./client-fingerprint";
|
|
|
11
11
|
*/
|
|
12
12
|
export const ANTIGRAVITY_REQUEST_UA = antigravityUserAgent();
|
|
13
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Antigravity CLI User-Agent. CCA serves Gemini 4 Argon only to the CLI client family, and it
|
|
16
|
+
* 404s other agent models (`gemini-3.7-flash-tiered`, `gemini-3.1-pro-low`) under it, so the
|
|
17
|
+
* choice is per wire model: see `antigravityUserAgentForWireModel`.
|
|
18
|
+
*/
|
|
19
|
+
export const ANTIGRAVITY_CLI_REQUEST_UA = antigravityCliUserAgent();
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Model discovery (`:fetchAvailableModels`) uses the CLI UA so Argon's wire ids are listed;
|
|
23
|
+
* under the IDE UA they are absent.
|
|
24
|
+
*/
|
|
25
|
+
export const ANTIGRAVITY_DISCOVERY_UA = ANTIGRAVITY_CLI_REQUEST_UA;
|
|
26
|
+
|
|
27
|
+
/** Wire ids CCA serves only to the CLI client family (verified 2026-10-14). */
|
|
28
|
+
const ANTIGRAVITY_CLI_ONLY_WIRE_MODEL = /^gemini-4-argon(?:-(?:low|medium|high))?$/;
|
|
29
|
+
|
|
30
|
+
/** The User-Agent an Antigravity inference request for `wireModelId` must carry. */
|
|
31
|
+
export function antigravityUserAgentForWireModel(wireModelId: string): string {
|
|
32
|
+
return ANTIGRAVITY_CLI_ONLY_WIRE_MODEL.test(wireModelId) ? ANTIGRAVITY_CLI_REQUEST_UA : ANTIGRAVITY_REQUEST_UA;
|
|
33
|
+
}
|
|
34
|
+
|
|
14
35
|
/**
|
|
15
36
|
* Whether a stored `OcxToolCall.thoughtSignature` is a REAL upstream Gemini signature versus a
|
|
16
37
|
* foreign id that must not be forwarded to Gemini/Antigravity.
|
package/src/adapters/google.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { openCodeZenGeminiEndpoint } from "../types/opencode-zen";
|
|
1
2
|
import type { AdapterFetchContext, AdapterRequest, ProviderAdapter } from "./base";
|
|
2
3
|
import { debugDroppedFrame, debugProviderDiagnosticLazy } from "../lib/debug";
|
|
3
4
|
import { createToolCallIdAllocator } from "./tool-call-id";
|
|
5
|
+
import { openCodeGoGeminiEndpoint } from "../types/opencode-go";
|
|
4
6
|
import { createImageBudget, materializeInlineImage, MAX_ENCODED_BYTES_PER_IMAGE, artifactHttpUrl } from "../images/artifacts";
|
|
5
7
|
import type {
|
|
6
8
|
AdapterEvent,
|
|
@@ -17,11 +19,11 @@ import type {
|
|
|
17
19
|
import { isAllowedToolChoice, namespacedToolName, resolveToolChoiceWireName, toolChoiceToolPredicate } from "../types";
|
|
18
20
|
import type { OcxTool } from "../types";
|
|
19
21
|
import { contentPartsToText, parseDataUrl } from "./image";
|
|
20
|
-
import { getVertexAccessToken } from "../lib/gcp-adc";
|
|
22
|
+
import { GCP_CREDENTIAL_MARKER_PREFIX, gcpCredentialMarkerAccount, getVertexAccessToken } from "../lib/gcp-adc";
|
|
21
23
|
import { fetchAntigravityWithRetry, fetchVertexWithRetry } from "./google-http";
|
|
22
24
|
import { safeAntigravityHttpErrorMessage, safeVertexHttpErrorMessage } from "./google-errors";
|
|
23
25
|
import { isVertexTruncatedTurn, vertexTruncationErrorEvent } from "./google-truncation";
|
|
24
|
-
import {
|
|
26
|
+
import { antigravitySessionAnchor, antigravityUserAgentForWireModel, antigravitySessionId, isLikelyRealThoughtSignature, sanitizeAntigravityClaudeSignatures } from "./google-antigravity-wire";
|
|
25
27
|
import { summarizeGoogleWireShape } from "./google-wire-shape";
|
|
26
28
|
import { compileGoogleWireBody } from "./google-wire-compiler";
|
|
27
29
|
import type { GoogleToolSchemaLossReport, GoogleToolSchemaProfile } from "./google-tool-schema";
|
|
@@ -174,7 +176,15 @@ function resolveDirectGeminiWireModelId(modelId: string, applyRenames: boolean):
|
|
|
174
176
|
|
|
175
177
|
/** Vertex API key: provider.apiKey if it looks real (not a sentinel), else GOOGLE_CLOUD_API_KEY env. */
|
|
176
178
|
function resolveVertexApiKey(optKey?: string): string | undefined {
|
|
177
|
-
|
|
179
|
+
// A `gcp-sa:` marker is the keychain-backed credential reference (see gcp-adc): it is not
|
|
180
|
+
// API-key material, so it must not be sent as x-goog-api-key — the ADC branch below handles it.
|
|
181
|
+
// AND the marker means the operator named one credential explicitly: the GOOGLE_CLOUD_API_KEY
|
|
182
|
+
// env fallback must NOT fire (it would silently route this provider's inference through the
|
|
183
|
+
// ambient env key instead of the configured service account).
|
|
184
|
+
if (optKey && optKey.startsWith(GCP_CREDENTIAL_MARKER_PREFIX)) return undefined;
|
|
185
|
+
const realKey = optKey && !optKey.startsWith("<") && optKey !== "N/A"
|
|
186
|
+
? optKey
|
|
187
|
+
: undefined;
|
|
178
188
|
return realKey || process.env.GOOGLE_CLOUD_API_KEY;
|
|
179
189
|
}
|
|
180
190
|
|
|
@@ -864,6 +874,7 @@ function invalidGoogleShapeEvent(
|
|
|
864
874
|
};
|
|
865
875
|
}
|
|
866
876
|
|
|
877
|
+
/** Build Gemini transport and response parsing for AI Studio, Vertex, Cloud Code Assist or Go. */
|
|
867
878
|
export function createGoogleAdapter(provider: OcxProviderConfig): ProviderAdapter {
|
|
868
879
|
const toolSchemaPolicy = provider.googleToolSchemaPolicy ?? "compatible";
|
|
869
880
|
const toolSchemaProfile = {
|
|
@@ -945,6 +956,7 @@ export function createGoogleAdapter(provider: OcxProviderConfig): ProviderAdapte
|
|
|
945
956
|
}
|
|
946
957
|
: {}),
|
|
947
958
|
|
|
959
|
+
/** Compile an admitted request into the selected Gemini endpoint, body and authentication. */
|
|
948
960
|
async buildRequest(parsed: OcxParsedRequest) {
|
|
949
961
|
// Structured-output admission runs FIRST, before messagesToGeminiFormat writes
|
|
950
962
|
// lastInjectedCallIds/lastReasoningReplayScope: a refused request must not leave
|
|
@@ -983,7 +995,7 @@ export function createGoogleAdapter(provider: OcxProviderConfig): ProviderAdapte
|
|
|
983
995
|
mapReasoningEffort(provider, parsed.modelId, parsed.options.reasoning),
|
|
984
996
|
provider.baseUrl,
|
|
985
997
|
).wireModelId
|
|
986
|
-
: provider.googleMode === "vertex"
|
|
998
|
+
: provider.googleMode === "vertex" || openCodeZenGeminiEndpoint(provider, parsed.modelId) !== undefined
|
|
987
999
|
? parsed.modelId
|
|
988
1000
|
: resolveDirectGeminiWireModelId(parsed.modelId, provider.directGeminiWireRenames !== false);
|
|
989
1001
|
returnsThoughtSummaries = provider.googleMode === "cloud-code-assist"
|
|
@@ -1155,7 +1167,7 @@ export function createGoogleAdapter(provider: OcxProviderConfig): ProviderAdapte
|
|
|
1155
1167
|
requestId: `agent-${crypto.randomUUID()}`,
|
|
1156
1168
|
request,
|
|
1157
1169
|
};
|
|
1158
|
-
headers["User-Agent"] =
|
|
1170
|
+
headers["User-Agent"] = antigravityUserAgentForWireModel(wireModelId);
|
|
1159
1171
|
headers["Authorization"] = `Bearer ${token}`;
|
|
1160
1172
|
return { url, method: "POST", headers, body: JSON.stringify(envelope) };
|
|
1161
1173
|
}
|
|
@@ -1197,16 +1209,31 @@ export function createGoogleAdapter(provider: OcxProviderConfig): ProviderAdapte
|
|
|
1197
1209
|
if (locationError) throw new Error(locationError);
|
|
1198
1210
|
const host = location === "global" ? "aiplatform.googleapis.com" : `${location}-aiplatform.googleapis.com`;
|
|
1199
1211
|
const url = `https://${host}/v1/projects/${project}/locations/${location}/publishers/google/models/${parsed.modelId}:${method}${streamParam}`;
|
|
1200
|
-
|
|
1212
|
+
// The marker account travels per-request as an argument (never process-global state): a
|
|
1213
|
+
// module-level "active marker" written at routing time would race across concurrent
|
|
1214
|
+
// requests for different providers and could resolve one call with another's credential.
|
|
1215
|
+
const markerAccount = gcpCredentialMarkerAccount(provider.apiKey);
|
|
1216
|
+
const token = await getVertexAccessToken({ markerAccount });
|
|
1201
1217
|
headers["Authorization"] = `Bearer ${token}`;
|
|
1202
1218
|
return { url, method: "POST", headers, body: JSON.stringify(compiled.body) };
|
|
1203
1219
|
}
|
|
1204
1220
|
|
|
1205
|
-
//
|
|
1206
|
-
const
|
|
1221
|
+
// Go and Zen use separate guarded Gemini endpoints; AI Studio retains /v1beta.
|
|
1222
|
+
const goEndpoint = openCodeGoGeminiEndpoint(provider, routedModelId);
|
|
1223
|
+
const zenEndpoint = openCodeZenGeminiEndpoint(provider, routedModelId);
|
|
1224
|
+
const endpoint = goEndpoint ?? zenEndpoint ?? `${provider.baseUrl}/v1beta/models/${routedModelId}`;
|
|
1225
|
+
const url = `${endpoint}:${method}${streamParam}`;
|
|
1207
1226
|
const apiKey = provider.apiKey?.trim();
|
|
1208
|
-
if (!apiKey) throw new Error("google (AI Studio) requires a non-empty API key
|
|
1209
|
-
|
|
1227
|
+
if (!apiKey) throw new Error(`${goEndpoint ? "OpenCode Go" : zenEndpoint ? "OpenCode Zen" : "google (AI Studio)"} requires a non-empty API key`);
|
|
1228
|
+
if (goEndpoint) {
|
|
1229
|
+
// Console inference documents Bearer auth. Send only the selected Go key.
|
|
1230
|
+
for (const name of Object.keys(headers)) {
|
|
1231
|
+
if (["authorization", "x-goog-api-key", "x-api-key"].includes(name.toLowerCase())) delete headers[name];
|
|
1232
|
+
}
|
|
1233
|
+
headers["Authorization"] = `Bearer ${apiKey}`;
|
|
1234
|
+
} else {
|
|
1235
|
+
headers["x-goog-api-key"] = apiKey;
|
|
1236
|
+
}
|
|
1210
1237
|
|
|
1211
1238
|
const compiled = compileGoogleWireBody(body, toolSchemaProfile, toolSchemaPolicy);
|
|
1212
1239
|
reportToolSchemaLoss(compiled.toolSchemaLossReport);
|
|
@@ -7,6 +7,7 @@ import { EMPTY_TOOL_OUTPUT_ANNOTATION, isWhitespaceOnlyTextPartArray } from "../
|
|
|
7
7
|
import { identifyRoutedModel } from "../identity";
|
|
8
8
|
import { buildNonOpenAIToolCatalogNudgeForTools, shouldInjectNonOpenAIToolCatalogNudge } from "../tool-catalog-nudge";
|
|
9
9
|
import { peekReasoningForCall } from "../../responses/reasoning-replay-cache";
|
|
10
|
+
import { chatReasoningReplayPolicy } from "./reasoning-replay";
|
|
10
11
|
import type { ClaudeThinkingProjection } from "../../lib/claude-request-projection";
|
|
11
12
|
import { inlineDocumentDataUrl } from "../../responses/inline-document";
|
|
12
13
|
import type { OcxAssistantMessage, OcxContentPart, OcxParsedRequest, OcxProviderConfig, OcxTextContent, OcxThinkingContent, OcxToolCall } from "../../types";
|
|
@@ -75,7 +76,7 @@ export function openAIChatSerializesThinking(
|
|
|
75
76
|
modelId: string,
|
|
76
77
|
): ClaudeThinkingProjection {
|
|
77
78
|
return {
|
|
78
|
-
text:
|
|
79
|
+
text: chatReasoningReplayPolicy(provider, modelId).preserve,
|
|
79
80
|
// The wire has no `signature` field — base64 replay tokens are Anthropic-wire-only.
|
|
80
81
|
signature: false,
|
|
81
82
|
// A `redacted_thinking` block is opaque provider data with no Chat representation: the
|
|
@@ -267,7 +268,7 @@ export function messagesToChatFormat(parsed: OcxParsedRequest, provider: OcxProv
|
|
|
267
268
|
// recorded under every call id — join unique texts only.
|
|
268
269
|
if (cached.length > 0) {
|
|
269
270
|
reasoningContent = [...new Set(cached)].join("\n");
|
|
270
|
-
} else if (
|
|
271
|
+
} else if (chatReasoningReplayPolicy(provider, parsed.modelId).placeholder) {
|
|
271
272
|
// Fallback (extends #950 and #1193; fixes #5421): the replay cache is
|
|
272
273
|
// bounded (64 entries / 256 KiB / 1 h TTL) and always misses on
|
|
273
274
|
// long sessions, and some thinking/tool rounds carry no recorded
|
|
@@ -354,7 +355,7 @@ export function messagesToChatFormat(parsed: OcxParsedRequest, provider: OcxProv
|
|
|
354
355
|
const orphanReasoning =
|
|
355
356
|
cachedReasoning
|
|
356
357
|
|| (wireSerializesThinking
|
|
357
|
-
&&
|
|
358
|
+
&& chatReasoningReplayPolicy(provider, parsed.modelId).placeholder
|
|
358
359
|
? " "
|
|
359
360
|
: undefined);
|
|
360
361
|
const orphanReasoningFields: Record<string, unknown> = !orphanReasoning
|
|
@@ -14,6 +14,8 @@ import { modelRecordValue } from "../../reasoning-effort";
|
|
|
14
14
|
import { modelInList, type OcxProviderConfig } from "../../types";
|
|
15
15
|
import { chatParallelToolCallsWireValue } from "./parallel-tool-calls";
|
|
16
16
|
import { applyExplicitChatReasoningWirePolicy } from "./reasoning-wire";
|
|
17
|
+
import { replayNativeChatReasoning } from "./reasoning-replay";
|
|
18
|
+
import type { OcxReasoningReplayScopeRef } from "../../types";
|
|
17
19
|
|
|
18
20
|
const CHAT_PASSTHROUGH_FIELDS = [
|
|
19
21
|
"audio",
|
|
@@ -55,17 +57,19 @@ export function buildOpenAIChatPassthroughRequest(
|
|
|
55
57
|
fastPolicy: ResolvedFastPolicy = fastPolicyForModel(provider, modelId, undefined, "chat"),
|
|
56
58
|
fastMode?: boolean,
|
|
57
59
|
providerName?: string,
|
|
60
|
+
replayScope?: OcxReasoningReplayScopeRef,
|
|
58
61
|
): AdapterRequest {
|
|
59
62
|
const { url, headers, hasCredential } = openAIChatTransport(provider);
|
|
60
63
|
|
|
61
64
|
const body: Record<string, unknown> = {
|
|
62
65
|
model: provider.modelSuffixBracketStrip ? stripBracketedModelSuffix(modelId) : modelId,
|
|
63
|
-
// The caller's messages
|
|
66
|
+
// The caller's messages retain their wire shape. An operator who
|
|
64
67
|
// recorded that this destination rejects the `developer` role gets that role converted in
|
|
65
68
|
// place. Verbatim was not neutral there — it sent the role anyway and the turn failed
|
|
66
69
|
// upstream with a 400 before the model saw it. An unrecorded destination is still verbatim,
|
|
67
70
|
// and the conversion changes the role of those messages and nothing else, so the position
|
|
68
|
-
// of every message and every other field survive unchanged.
|
|
71
|
+
// of every message and every other field survive unchanged. Missing thinking history is
|
|
72
|
+
// repaired below using the same preserve policy as the translated Chat builder.
|
|
69
73
|
messages: applyExplicitChatDeveloperRole(
|
|
70
74
|
frameAgentRouterMessages(provider.baseUrl, rawBody.messages),
|
|
71
75
|
provider,
|
|
@@ -75,6 +79,8 @@ export function buildOpenAIChatPassthroughRequest(
|
|
|
75
79
|
for (const field of CHAT_PASSTHROUGH_FIELDS) {
|
|
76
80
|
if (rawBody[field] !== undefined) body[field] = rawBody[field];
|
|
77
81
|
}
|
|
82
|
+
body.messages = replayNativeChatReasoning(body.messages, provider, modelId, replayScope,
|
|
83
|
+
Array.isArray(rawBody.tools) && rawBody.tools.length > 0);
|
|
78
84
|
if (protectGlmSummaryBudget(body, provider.baseUrl, body.reasoning_effort)) body.reasoning_effort = "low";
|
|
79
85
|
const rawEfforts = modelRecordValue(provider.modelReasoningEfforts, modelId) ?? provider.reasoningEfforts;
|
|
80
86
|
const reasoningDisabled = modelInList(provider.noReasoningModels, modelId) || rawEfforts?.length === 0;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { modelInList, type OcxProviderConfig, type OcxReasoningReplayScopeRef } from "../../types";
|
|
2
|
+
import { peekReasoningForCall } from "../../responses/reasoning-replay-cache";
|
|
3
|
+
|
|
4
|
+
type Rec = Record<string, unknown>;
|
|
5
|
+
export const isChatRecord = (value: unknown): value is Rec =>
|
|
6
|
+
value !== null && typeof value === "object" && !Array.isArray(value);
|
|
7
|
+
|
|
8
|
+
const isDeepSeekThinkingModel = (modelId: string): boolean =>
|
|
9
|
+
/(?:^|\/)deepseek-(?:v\d+(?:\.\d+)*-(?:flash|pro)|flash|pro)(?:$|[-_:])/i.test(modelId);
|
|
10
|
+
|
|
11
|
+
/** DeepSeek thinking tool replay is a model contract, independent of the gateway's name. */
|
|
12
|
+
export function chatReasoningReplayPolicy(provider: OcxProviderConfig, modelId: string): {
|
|
13
|
+
preserve: boolean; placeholder: boolean;
|
|
14
|
+
} {
|
|
15
|
+
// Match whole model-family tokens, including dotted versions, namespace and deployment suffixes.
|
|
16
|
+
// Legacy chat/reasoner and distilled R1 models do not share the thinking tool-call contract.
|
|
17
|
+
const preserve = provider.preserveReasoningContentModels === undefined
|
|
18
|
+
? isDeepSeekThinkingModel(modelId)
|
|
19
|
+
: modelInList(provider.preserveReasoningContentModels, modelId);
|
|
20
|
+
return {
|
|
21
|
+
preserve,
|
|
22
|
+
placeholder: preserve && (provider.requiresReasoningPlaceholderModels === undefined
|
|
23
|
+
? true
|
|
24
|
+
: modelInList(provider.requiresReasoningPlaceholderModels, modelId)),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Repair missing native history without mutating caller bodies used by retries/combo siblings. */
|
|
29
|
+
export function replayNativeChatReasoning(
|
|
30
|
+
messages: unknown,
|
|
31
|
+
provider: OcxProviderConfig,
|
|
32
|
+
modelId: string,
|
|
33
|
+
scope?: OcxReasoningReplayScopeRef,
|
|
34
|
+
hasTools = false,
|
|
35
|
+
): unknown {
|
|
36
|
+
const policy = chatReasoningReplayPolicy(provider, modelId);
|
|
37
|
+
if (!policy.preserve || !Array.isArray(messages)
|
|
38
|
+
|| modelInList(provider.reasoningDetailsModels, modelId)) return messages;
|
|
39
|
+
return messages.map(message => {
|
|
40
|
+
if (!isChatRecord(message) || message.role !== "assistant"
|
|
41
|
+
|| (typeof message.reasoning_content === "string" && message.reasoning_content.length > 0)) return message;
|
|
42
|
+
const calls = Array.isArray(message.tool_calls) ? message.tool_calls : [];
|
|
43
|
+
// DeepSeek's tools contract covers all prior assistant turns, even plain answers.
|
|
44
|
+
// Those turns have no call id for original replay; only the configured fallback applies.
|
|
45
|
+
if (calls.length === 0 && !(hasTools && isDeepSeekThinkingModel(modelId))) return message;
|
|
46
|
+
const cached = calls.filter(isChatRecord)
|
|
47
|
+
.map(tool => typeof tool.id === "string" ? peekReasoningForCall(tool.id, scope) : undefined)
|
|
48
|
+
.filter((text): text is string => typeof text === "string" && text.length > 0);
|
|
49
|
+
const reasoning = cached.length > 0 ? [...new Set(cached)].join("\n") : policy.placeholder ? " " : undefined;
|
|
50
|
+
return reasoning === undefined ? message : { ...message, reasoning_content: reasoning };
|
|
51
|
+
});
|
|
52
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { diagnoseInvalidToolCalls, isRecord, type InvalidToolCallDiagnostic } from "./tool-call-validation";
|
|
2
2
|
import { TranslatorBudgetExceededError, type TranslatorBudget } from "../../lib/translator-budget";
|
|
3
|
-
import type { AdapterEvent, OcxUsage } from "../../types";
|
|
3
|
+
import type { AdapterEvent, OcxProviderConfig, OcxUsage } from "../../types";
|
|
4
|
+
import { createInlineThinkContentSplitter } from "../inline-think-tags";
|
|
4
5
|
|
|
5
6
|
export function stopReasonFor(finishReason: unknown): "max_tokens" | "content_filter" | undefined {
|
|
6
7
|
return finishReason === "length"
|
|
@@ -18,6 +19,63 @@ export function reasoningTextFrom(record: Record<string, unknown>): string | und
|
|
|
18
19
|
: undefined;
|
|
19
20
|
}
|
|
20
21
|
|
|
22
|
+
type ChatContentEvent = Extract<AdapterEvent, { type: "text_delta" | "reasoning_raw_delta" | "error" }>;
|
|
23
|
+
|
|
24
|
+
/** Mistral can mix typed blocks and strings in one response. Other destinations keep their parser. */
|
|
25
|
+
export function chatContentEvents(content: unknown, baseUrl: string, usage?: OcxUsage, buffered = false): ChatContentEvent[] {
|
|
26
|
+
if (typeof content === "string") return content.length > 0 || buffered ? [{ type: "text_delta", text: content }] : [];
|
|
27
|
+
if (!Array.isArray(content)) return [];
|
|
28
|
+
let host: string;
|
|
29
|
+
try { host = new URL(baseUrl).hostname; } catch { return []; }
|
|
30
|
+
if (host !== "api.mistral.ai") return [];
|
|
31
|
+
const invalid = (): ChatContentEvent[] => [{
|
|
32
|
+
type: "error", status: 502, errorType: "upstream_error",
|
|
33
|
+
message: "unsupported Mistral content block", ...(usage ? { usage } : {}),
|
|
34
|
+
}];
|
|
35
|
+
const events: ChatContentEvent[] = [];
|
|
36
|
+
for (const block of content) {
|
|
37
|
+
if (!isRecord(block)) return invalid();
|
|
38
|
+
if (block.type === "text" && typeof block.text === "string") {
|
|
39
|
+
if (block.text.length > 0 || buffered) events.push({ type: "text_delta", text: block.text });
|
|
40
|
+
} else if (block.type === "thinking" && Array.isArray(block.thinking)) {
|
|
41
|
+
for (const inner of block.thinking) {
|
|
42
|
+
if (!isRecord(inner) || inner.type !== "text" || typeof inner.text !== "string") return invalid();
|
|
43
|
+
if (inner.text.length > 0) events.push({ type: "reasoning_raw_delta", text: inner.text });
|
|
44
|
+
}
|
|
45
|
+
} else return invalid();
|
|
46
|
+
}
|
|
47
|
+
return events;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Keep adjacent text together; typed reasoning flushes and resets inline-tag parsing. */
|
|
51
|
+
export function createChatContentSplitter(provider: OcxProviderConfig, modelId: string | undefined, budget: TranslatorBudget) {
|
|
52
|
+
let splitter = createInlineThinkContentSplitter(provider.inlineThinkTagModels, modelId, budget);
|
|
53
|
+
return {
|
|
54
|
+
feed(event: ChatContentEvent): AdapterEvent[] {
|
|
55
|
+
if (event.type === "error") return [event];
|
|
56
|
+
if (event.type === "text_delta") return splitter.feed(event.text);
|
|
57
|
+
const pending = splitter.flush();
|
|
58
|
+
splitter.dispose();
|
|
59
|
+
splitter = createInlineThinkContentSplitter(provider.inlineThinkTagModels, modelId, budget);
|
|
60
|
+
return [...pending, event];
|
|
61
|
+
},
|
|
62
|
+
flush: () => splitter.flush(),
|
|
63
|
+
dispose: () => splitter.dispose(),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Split a buffered answer with the same typed-reasoning boundaries as a stream. */
|
|
68
|
+
export function splitChatContentEvents(content: unknown, provider: OcxProviderConfig, modelId: string | undefined, budget: TranslatorBudget, usage?: OcxUsage): AdapterEvent[] {
|
|
69
|
+
const events = chatContentEvents(content, provider.baseUrl, usage, true);
|
|
70
|
+
if (events.some(event => event.type === "error")) return events;
|
|
71
|
+
const splitter = createChatContentSplitter(provider, modelId, budget);
|
|
72
|
+
try {
|
|
73
|
+
return [...events.flatMap(event => splitter.feed(event)), ...splitter.flush()];
|
|
74
|
+
} finally {
|
|
75
|
+
splitter.dispose();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
21
79
|
export interface ReasoningDetailSegment {
|
|
22
80
|
key: string;
|
|
23
81
|
text: string;
|
|
@@ -5,7 +5,6 @@ import { applyExplicitChatReasoningWirePolicy } from "./openai-chat/reasoning-wi
|
|
|
5
5
|
import type { AdapterRequest, IncomingMeta, ProviderAdapter } from "./base";
|
|
6
6
|
import type { AdapterEvent, OcxParsedRequest, OcxProviderConfig, OcxUsage } from "../types";
|
|
7
7
|
import { modelInList } from "../types";
|
|
8
|
-
import { createInlineThinkContentSplitter, splitInlineThinkContent } from "./inline-think-tags";
|
|
9
8
|
import { mapReasoningEffort } from "../reasoning-effort";
|
|
10
9
|
import { debugProviderDiagnostic } from "../lib/debug";
|
|
11
10
|
import { sseFieldValue } from "../lib/sse-decoder";
|
|
@@ -28,6 +27,7 @@ import {
|
|
|
28
27
|
type InvalidToolCallDiagnostic,
|
|
29
28
|
} from "./openai-chat/tool-call-validation";
|
|
30
29
|
import {
|
|
30
|
+
chatContentEvents, createChatContentSplitter, splitChatContentEvents,
|
|
31
31
|
createReasoningDetailSnapshotTracker,
|
|
32
32
|
invalidChoicesEvent,
|
|
33
33
|
invalidToolCallsEvent,
|
|
@@ -368,7 +368,7 @@ export function createOpenAIChatAdapter(provider: OcxProviderConfig): ProviderAd
|
|
|
368
368
|
const reasoningDetailsOptIn = modelInList(provider.reasoningDetailsModels, lastRequestedModelId ?? "");
|
|
369
369
|
// A gateway with no server-side reasoning parser leaves thinking inline in `content` as
|
|
370
370
|
// <think> blocks, which would otherwise render as the answer. Passthrough unless opted in.
|
|
371
|
-
const inlineThink =
|
|
371
|
+
const inlineThink = createChatContentSplitter(provider, lastRequestedModelId, budget);
|
|
372
372
|
const emitContent = function* (events: AdapterEvent[]): Generator<AdapterEvent> {
|
|
373
373
|
for (const event of events) {
|
|
374
374
|
// Any other event keeps its place behind held text instead of overtaking it.
|
|
@@ -444,8 +444,9 @@ export function createOpenAIChatAdapter(provider: OcxProviderConfig): ProviderAd
|
|
|
444
444
|
const reasoningText = reasoningTextFrom(delta);
|
|
445
445
|
if (reasoningText !== undefined) yield* toolCallContent.hold({ type: "reasoning_raw_delta", text: reasoningText });
|
|
446
446
|
}
|
|
447
|
-
|
|
448
|
-
yield*
|
|
447
|
+
for (const event of chatContentEvents(delta.content, provider.baseUrl, pendingUsage)) {
|
|
448
|
+
if (event.type === "error") return yield* terminateWithError(event);
|
|
449
|
+
yield* emitContent(inlineThink.feed(event));
|
|
449
450
|
}
|
|
450
451
|
|
|
451
452
|
const rawToolCalls = delta.tool_calls;
|
|
@@ -767,7 +768,9 @@ export function createOpenAIChatAdapter(provider: OcxProviderConfig): ProviderAd
|
|
|
767
768
|
}
|
|
768
769
|
if (reasoningText !== undefined) events.push({ type: "reasoning_raw_delta", text: reasoningText });
|
|
769
770
|
const contentStart = events.length;
|
|
770
|
-
|
|
771
|
+
const contentEvents = splitChatContentEvents(msg.content, provider, lastRequestedModelId, budget, usage);
|
|
772
|
+
if (contentEvents.some(event => event.type === "error")) return contentEvents;
|
|
773
|
+
events.push(...contentEvents);
|
|
771
774
|
const contentEnd = events.length;
|
|
772
775
|
const answerText = events.slice(contentStart).map(event => (event.type === "text_delta" ? event.text : "")).join("");
|
|
773
776
|
// Each call holds the delta event it emitted, so the batch repair sets its arguments later.
|