@iislee/opencodex 2.11.0 → 2.31.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/AGENTS_INSTALL.md +109 -0
- package/README.md +114 -19
- package/bin/ocx.mjs +164 -36
- package/bin/package-main.mjs +1 -1
- package/gui/dist/assets/index-BF38heuV.js +104 -0
- package/gui/dist/assets/index-DMiI18Kv.css +1 -0
- package/gui/dist/index.html +2 -2
- package/gui/dist/provider-icons/alibaba-color.svg +1 -1
- package/gui/dist/provider-icons/antigravity-color.svg +1 -1
- package/gui/dist/provider-icons/claude-color.svg +1 -1
- package/gui/dist/provider-icons/cline-color.svg +16 -0
- package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/commandcode-color.svg +1 -0
- package/gui/dist/provider-icons/copilot-color.svg +1 -1
- package/gui/dist/provider-icons/cursor-color.svg +1 -1
- package/gui/dist/provider-icons/deepseek-color.svg +1 -1
- package/gui/dist/provider-icons/firepass-color.svg +1 -1
- package/gui/dist/provider-icons/fireworks-color.svg +1 -1
- package/gui/dist/provider-icons/gemini-color.svg +1 -1
- package/gui/dist/provider-icons/github-copilot-color.svg +1 -1
- package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -1
- package/gui/dist/provider-icons/grok.svg +1 -1
- package/gui/dist/provider-icons/groq-color.svg +1 -1
- package/gui/dist/provider-icons/huggingface-color.svg +1 -1
- package/gui/dist/provider-icons/kimi-color.svg +1 -1
- package/gui/dist/provider-icons/kiro-color.svg +2 -2
- package/gui/dist/provider-icons/lm-studio-color.svg +1 -1
- package/gui/dist/provider-icons/mistral-color.svg +1 -1
- package/gui/dist/provider-icons/moonshot-color.svg +1 -1
- package/gui/dist/provider-icons/nvidia-color.svg +1 -1
- package/gui/dist/provider-icons/ollama-color.svg +1 -1
- package/gui/dist/provider-icons/openai.svg +1 -1
- package/gui/dist/provider-icons/opencode.svg +2 -1
- package/gui/dist/provider-icons/openrouter-color.svg +1 -1
- package/gui/dist/provider-icons/pi.svg +2 -2
- package/gui/dist/provider-icons/qianfan-color.svg +1 -1
- package/gui/dist/provider-icons/qwen-portal-color.svg +1 -1
- package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/vllm-color.svg +1 -1
- package/gui/dist/provider-icons/xiaomi-color.svg +1 -1
- package/package.json +19 -10
- package/src/adapters/anthropic-output-schema.ts +137 -0
- package/src/adapters/anthropic.ts +376 -52
- package/src/adapters/base.ts +54 -7
- package/src/adapters/client-fingerprint.ts +18 -12
- package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
- package/src/adapters/command-code.ts +601 -0
- package/src/adapters/cursor/checkpoint-store.ts +303 -0
- package/src/adapters/cursor/cursor-errors.ts +129 -6
- package/src/adapters/cursor/discovery.ts +61 -4
- package/src/adapters/cursor/effort-map.ts +27 -3
- package/src/adapters/cursor/framing.ts +39 -0
- package/src/adapters/cursor/h2-pool.ts +123 -0
- package/src/adapters/cursor/http1-bidi.ts +361 -0
- package/src/adapters/cursor/images.ts +704 -0
- package/src/adapters/cursor/live-models.ts +174 -58
- package/src/adapters/cursor/live-transport.ts +609 -170
- package/src/adapters/cursor/native-exec-common.ts +23 -2
- package/src/adapters/cursor/native-exec-fs.ts +10 -7
- package/src/adapters/cursor/native-exec-network.ts +1 -1
- package/src/adapters/cursor/native-exec-shell.ts +0 -1
- package/src/adapters/cursor/native-exec.ts +101 -14
- package/src/adapters/cursor/protobuf-events.ts +829 -11
- package/src/adapters/cursor/protobuf-request.ts +383 -65
- package/src/adapters/cursor/request-builder.ts +237 -31
- package/src/adapters/cursor/tool-definitions.ts +242 -12
- package/src/adapters/cursor/tool-result-normalize.ts +92 -0
- package/src/adapters/cursor/transport.ts +22 -0
- package/src/adapters/cursor/types.ts +28 -1
- package/src/adapters/cursor.ts +133 -7
- package/src/adapters/google-antigravity-replay.ts +558 -34
- package/src/adapters/google-antigravity-wire.ts +43 -10
- package/src/adapters/google-http.ts +38 -10
- package/src/adapters/google-tool-schema.ts +80 -15
- package/src/adapters/google-truncation.ts +11 -0
- package/src/adapters/google.ts +618 -74
- package/src/adapters/identity.ts +39 -6
- package/src/adapters/kiro-errors.ts +11 -0
- package/src/adapters/kiro-events.ts +19 -1
- package/src/adapters/kiro-thinking.ts +18 -2
- package/src/adapters/kiro-tools.ts +10 -1
- package/src/adapters/kiro.ts +92 -54
- package/src/adapters/mimo-free.ts +17 -0
- package/src/adapters/openai-chat-url.ts +11 -0
- package/src/adapters/openai-chat.ts +1311 -336
- package/src/adapters/openai-responses-url.ts +16 -0
- package/src/adapters/openai-responses.ts +830 -56
- package/src/adapters/registry.ts +175 -0
- package/src/adapters/responses-tool-schema.ts +67 -0
- package/src/adapters/tool-call-id.ts +119 -0
- package/src/adapters/tool-catalog-nudge.ts +104 -21
- package/src/adapters/xai-web-search.ts +185 -0
- package/src/bridge.ts +428 -61
- package/src/chat/inbound.ts +43 -19
- package/src/chat/outbound.ts +82 -26
- package/src/claude/agents-inject.ts +32 -9
- package/src/claude/context-windows.ts +21 -5
- package/src/claude/desktop-3p.ts +243 -9
- package/src/claude/gateway-cache.ts +41 -4
- package/src/claude/inbound.ts +72 -3
- package/src/claude/model-info.ts +38 -15
- package/src/claude/outbound.ts +70 -16
- package/src/cli/account-api.ts +35 -1
- package/src/cli/account-auth.ts +33 -6
- package/src/cli/account-catalog-refresh.ts +14 -0
- package/src/cli/account-extended.ts +389 -2
- package/src/cli/account-main.ts +317 -0
- package/src/cli/account.ts +30 -6
- package/src/cli/agent.ts +45 -1
- package/src/cli/claude-agent-startup-sync.ts +73 -0
- package/src/cli/claude-desktop.ts +29 -4
- package/src/cli/claude.ts +103 -34
- package/src/cli/codex-log-guard-doctor.ts +103 -0
- package/src/cli/codex-shim-autorestore.ts +2 -0
- package/src/cli/codex-shim-readiness.ts +76 -0
- package/src/cli/combo.ts +8 -0
- package/src/cli/config-command.ts +74 -10
- package/src/cli/dispatch.ts +593 -0
- package/src/cli/doctor.ts +315 -43
- package/src/cli/ensure-desired-integrations.ts +152 -0
- package/src/cli/export-command.ts +46 -20
- package/src/cli/help.ts +20 -271
- package/src/cli/index.ts +378 -519
- package/src/cli/init.ts +4 -17
- package/src/cli/integrations.ts +120 -2
- package/src/cli/lab.ts +607 -0
- package/src/cli/launcher-context.ts +77 -0
- package/src/cli/minimax.ts +497 -0
- package/src/cli/models-runtime.ts +35 -2
- package/src/cli/models.ts +100 -14
- package/src/cli/observe.ts +92 -3
- package/src/cli/opencode.ts +4 -2
- package/src/cli/provider-runtime.ts +18 -1
- package/src/cli/provider.ts +24 -3
- package/src/cli/ready.ts +301 -0
- package/src/cli/registry.ts +437 -0
- package/src/cli/root.ts +86 -0
- package/src/cli/route-policy.ts +92 -0
- package/src/cli/runtime-api.ts +6 -3
- package/src/cli/star-prompt.ts +71 -15
- package/src/cli/status.ts +10 -3
- package/src/cli/system-restart-client.ts +146 -0
- package/src/cli/tray-proxy.ts +153 -6
- package/src/cli/v2.ts +105 -10
- package/src/cli.ts +1 -1
- package/src/clients/config-export.ts +1358 -21
- package/src/codex/account-label.ts +14 -1
- package/src/codex/account-lifecycle.ts +130 -13
- package/src/codex/account-namespaces.ts +49 -3
- package/src/codex/account-priority.ts +83 -0
- package/src/codex/account-store.ts +29 -2
- package/src/codex/account-usability.ts +25 -2
- package/src/codex/admission.ts +256 -0
- package/src/codex/affinity-debug.ts +162 -0
- package/src/codex/app-server-processes.ts +493 -106
- package/src/codex/app-server-restart-service.ts +232 -0
- package/src/codex/auth-api.ts +849 -242
- package/src/codex/auth-collision.ts +5 -3
- package/src/codex/auth-context.ts +345 -32
- package/src/codex/autostart-health.ts +8 -1
- package/src/codex/catalog/account-models.ts +67 -0
- package/src/codex/catalog/aggregation.ts +68 -10
- package/src/codex/catalog/bundled.ts +331 -33
- package/src/codex/catalog/effort.ts +121 -30
- package/src/codex/catalog/filesystem-evidence.ts +302 -0
- package/src/codex/catalog/kinds.ts +2 -0
- package/src/codex/catalog/metadata.ts +529 -45
- package/src/codex/catalog/native-models.ts +72 -0
- package/src/codex/catalog/parsing.ts +224 -30
- package/src/codex/catalog/provider-fetch.ts +1460 -134
- package/src/codex/catalog/sync.ts +1449 -186
- package/src/codex/catalog-admission.ts +199 -0
- package/src/codex/catalog-refresh-status.ts +105 -0
- package/src/codex/catalog-write-serialization.ts +242 -0
- package/src/codex/catalog.ts +6 -3
- package/src/codex/codex-write-lock.ts +384 -0
- package/src/codex/convergence-types.ts +614 -0
- package/src/codex/convergence.ts +651 -0
- package/src/codex/coordinator-doctor.ts +332 -0
- package/src/codex/custom-model-catalog-migration.ts +176 -0
- package/src/codex/desired-state.ts +230 -0
- package/src/codex/features.ts +636 -39
- package/src/codex/generation.ts +202 -0
- package/src/codex/history-job.ts +407 -0
- package/src/codex/history-lock.ts +242 -0
- package/src/codex/history-migration-guardian.ts +26 -20
- package/src/codex/history-provider.ts +231 -28
- package/src/codex/history-transition.ts +105 -0
- package/src/codex/history-worker.ts +220 -0
- package/src/codex/inject-coordination.ts +290 -0
- package/src/codex/inject.ts +1073 -152
- package/src/codex/injected-marker.ts +37 -3
- package/src/codex/integration-record.ts +266 -0
- package/src/codex/internal/catalog-writer.ts +203 -0
- package/src/codex/internal/history-writer.ts +80 -0
- package/src/codex/journal.ts +66 -4
- package/src/codex/log-guard/inspect.ts +506 -0
- package/src/codex/log-guard/lock.ts +150 -0
- package/src/codex/log-guard/maintenance.ts +403 -0
- package/src/codex/log-guard/path-safety.ts +88 -0
- package/src/codex/log-guard/policy.ts +44 -0
- package/src/codex/log-guard/processes.ts +205 -0
- package/src/codex/log-guard/protection.ts +489 -0
- package/src/codex/log-guard/sqlite-errors.ts +9 -0
- package/src/codex/main-account-cache.ts +24 -0
- package/src/codex/main-account.ts +29 -1
- package/src/codex/management-convergence.ts +167 -0
- package/src/codex/model-cache.ts +56 -10
- package/src/codex/model-entitlements.ts +353 -0
- package/src/codex/native-main-admission.ts +47 -0
- package/src/codex/native-main-auth-temp.ts +187 -0
- package/src/codex/native-main-claim.ts +178 -0
- package/src/codex/native-main-lock-file.ts +162 -0
- package/src/codex/native-main-owner.ts +329 -0
- package/src/codex/native-profile-api.ts +247 -0
- package/src/codex/native-profile-manager.ts +1531 -0
- package/src/codex/native-profile-processes.ts +121 -0
- package/src/codex/native-profile-recovery.ts +99 -0
- package/src/codex/native-profile-stage-store.ts +387 -0
- package/src/codex/native-profile-startup.ts +492 -0
- package/src/codex/native-profile-store.ts +855 -0
- package/src/codex/native-profile-types.ts +120 -0
- package/src/codex/native-residue.ts +682 -0
- package/src/codex/paths.ts +80 -1
- package/src/codex/plan-from-token.ts +140 -0
- package/src/codex/plan.ts +40 -0
- package/src/codex/plugins-doctor.ts +1 -1
- package/src/codex/pool-rotation.ts +74 -4
- package/src/codex/project-config-warnings.ts +20 -6
- package/src/codex/prompt-journal.ts +352 -0
- package/src/codex/prompt-layers.ts +967 -0
- package/src/codex/prompt-lock.ts +143 -0
- package/src/codex/quota-rejection.ts +298 -0
- package/src/codex/quota.ts +175 -13
- package/src/codex/refresh.ts +11 -2
- package/src/codex/reset-credit-recovery.ts +1044 -0
- package/src/codex/routing.ts +505 -94
- package/src/codex/runtime.ts +159 -38
- package/src/codex/shim.ts +1009 -28
- package/src/codex/subagent-model-fallback.ts +350 -35
- package/src/codex/sync.ts +191 -2
- package/src/codex/transition-state.ts +612 -0
- package/src/codex/upstream-host-health.ts +368 -0
- package/src/codex/user-identity.ts +557 -0
- package/src/codex/warmup.ts +187 -81
- package/src/codex/write-coordination.ts +114 -0
- package/src/combos/failover.ts +20 -0
- package/src/combos/index.ts +4 -0
- package/src/combos/request.ts +32 -0
- package/src/combos/types.ts +81 -9
- package/src/config/provider-name.ts +24 -0
- package/src/config.ts +1762 -140
- package/src/generated/compatibility-version.json +3164 -0
- package/src/generated/{jawcode-model-metadata.ts → model-metadata.ts} +19 -17
- package/src/grok/inject.ts +16 -5
- package/src/grok/inspect.ts +45 -0
- package/src/grok/sync.ts +2 -2
- package/src/images/loop.ts +152 -29
- package/src/images/plan.ts +23 -13
- package/src/integrations/config-io.ts +269 -0
- package/src/integrations/journal.ts +315 -0
- package/src/integrations/merge.ts +135 -0
- package/src/integrations/mutation-flight.ts +71 -0
- package/src/integrations/native/ownership-preflight.ts +202 -0
- package/src/integrations/omp-yaml-source.ts +358 -0
- package/src/integrations/owned-refresh.ts +74 -0
- package/src/integrations/ownership.ts +111 -0
- package/src/integrations/registry.ts +159 -0
- package/src/integrations/serialize.ts +314 -0
- package/src/integrations/state.ts +361 -0
- package/src/integrations/store.ts +103 -0
- package/src/integrations/writer-lock.ts +98 -0
- package/src/integrations/writer.ts +691 -0
- package/src/lab/artifacts/sanitize.ts +586 -0
- package/src/lab/artifacts/secure-fs.ts +475 -0
- package/src/lab/artifacts/store.ts +310 -0
- package/src/lab/automation/budgets.ts +78 -0
- package/src/lab/automation/config-persistence.ts +256 -0
- package/src/lab/automation/constants.ts +39 -0
- package/src/lab/automation/cooldown.ts +103 -0
- package/src/lab/automation/dispatch.ts +211 -0
- package/src/lab/automation/index.ts +13 -0
- package/src/lab/automation/orchestrator.ts +499 -0
- package/src/lab/automation/persistence.ts +512 -0
- package/src/lab/automation/planner.ts +371 -0
- package/src/lab/automation/policy.ts +136 -0
- package/src/lab/automation/queue.ts +191 -0
- package/src/lab/automation/recovery.ts +24 -0
- package/src/lab/automation/route-context.ts +21 -0
- package/src/lab/automation/run-key.ts +44 -0
- package/src/lab/automation/runs-query.ts +34 -0
- package/src/lab/automation/types.ts +160 -0
- package/src/lab/conformance/assertion.ts +325 -0
- package/src/lab/conformance/digest.ts +22 -0
- package/src/lab/conformance/executor.ts +741 -0
- package/src/lab/conformance/fixture-provider.ts +27 -0
- package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
- package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
- package/src/lab/conformance/harness-budget.ts +47 -0
- package/src/lab/conformance/index.ts +5 -0
- package/src/lab/conformance/jcs.ts +64 -0
- package/src/lab/conformance/json-pointer.ts +39 -0
- package/src/lab/conformance/manifest.ts +180 -0
- package/src/lab/conformance/mcp-stub.ts +179 -0
- package/src/lab/conformance/negative-controls.ts +164 -0
- package/src/lab/conformance/observation.ts +355 -0
- package/src/lab/conformance/runner.ts +68 -0
- package/src/lab/conformance/sse-normalize.ts +59 -0
- package/src/lab/conformance/suite-manifest.ts +78 -0
- package/src/lab/conformance/types.ts +214 -0
- package/src/lab/constants.ts +126 -0
- package/src/lab/digest.ts +64 -0
- package/src/lab/events/errors.ts +9 -0
- package/src/lab/events/limits.ts +117 -0
- package/src/lab/events/types.ts +229 -0
- package/src/lab/events/validate.ts +781 -0
- package/src/lab/fabric/constants.ts +40 -0
- package/src/lab/fabric/executor.ts +492 -0
- package/src/lab/fabric/index.ts +80 -0
- package/src/lab/fabric/manifest.ts +222 -0
- package/src/lab/fabric/observe.ts +489 -0
- package/src/lab/fabric/patch.ts +79 -0
- package/src/lab/fabric/producer-child.ts +139 -0
- package/src/lab/fabric/producer-isolate.ts +276 -0
- package/src/lab/fabric/producer-protocol.ts +61 -0
- package/src/lab/fabric/scratch.ts +439 -0
- package/src/lab/fabric/subject.ts +106 -0
- package/src/lab/fabric/types.ts +134 -0
- package/src/lab/fabric/verifier.ts +98 -0
- package/src/lab/index.ts +54 -0
- package/src/lab/ledger/artifact-refs.ts +127 -0
- package/src/lab/ledger/invalidation.ts +136 -0
- package/src/lab/ledger/purge.ts +310 -0
- package/src/lab/ledger/store.ts +532 -0
- package/src/lab/live/credential-lease.ts +53 -0
- package/src/lab/live/destination.ts +155 -0
- package/src/lab/live/executor.ts +336 -0
- package/src/lab/live/inert-tools.ts +56 -0
- package/src/lab/live/manifest.ts +85 -0
- package/src/lab/live/mcp-loopback.ts +57 -0
- package/src/lab/live/runner.ts +19 -0
- package/src/lab/live/sandbox.ts +61 -0
- package/src/lab/live/suite-manifest.ts +41 -0
- package/src/lab/live/transport.ts +118 -0
- package/src/lab/live/types.ts +197 -0
- package/src/lab/observe/from-conformance.ts +301 -0
- package/src/lab/observe/from-live.ts +117 -0
- package/src/lab/paths.ts +153 -0
- package/src/lab/projection/rebuild.ts +495 -0
- package/src/lab/projection/schema.ts +135 -0
- package/src/lab/projection/verdicts.ts +474 -0
- package/src/lab/projection/verification.ts +412 -0
- package/src/lab/public/bundle.ts +217 -0
- package/src/lab/public/community-authority.ts +175 -0
- package/src/lab/public/community-files.ts +29 -0
- package/src/lab/public/community.ts +479 -0
- package/src/lab/public/file-safety.ts +155 -0
- package/src/lab/public/ids.ts +26 -0
- package/src/lab/public/index.ts +16 -0
- package/src/lab/public/mutation-lock.ts +424 -0
- package/src/lab/public/operator.ts +353 -0
- package/src/lab/public/origin-purge.ts +79 -0
- package/src/lab/public/origin.ts +203 -0
- package/src/lab/public/privacy.ts +143 -0
- package/src/lab/public/private-file.ts +261 -0
- package/src/lab/public/project.ts +124 -0
- package/src/lab/public/purge-test-fault.ts +21 -0
- package/src/lab/public/purge.ts +223 -0
- package/src/lab/public/registry.ts +44 -0
- package/src/lab/public/revocation.ts +252 -0
- package/src/lab/public/signature.ts +243 -0
- package/src/lab/public/storage.ts +105 -0
- package/src/lab/public/strict-json.ts +206 -0
- package/src/lab/public/time.ts +26 -0
- package/src/lab/public/types.ts +172 -0
- package/src/lab/public/validate.ts +391 -0
- package/src/lab/query/catalog.ts +101 -0
- package/src/lab/query/connection.ts +107 -0
- package/src/lab/query/constants.ts +4 -0
- package/src/lab/query/cursor.ts +132 -0
- package/src/lab/query/dto-map.ts +277 -0
- package/src/lab/query/errors.ts +22 -0
- package/src/lab/query/freshness.ts +53 -0
- package/src/lab/query/index.ts +45 -0
- package/src/lab/query/latest-observation.ts +59 -0
- package/src/lab/query/passive-production.ts +159 -0
- package/src/lab/query/queries.ts +444 -0
- package/src/lab/query/types.ts +266 -0
- package/src/lab/subject/behavior-fingerprint.ts +77 -0
- package/src/lab/subject/installation-salt.ts +112 -0
- package/src/lab/subject/protocol-subject.ts +80 -0
- package/src/lab/subject/route-subject.ts +74 -0
- package/src/lib/app-owned-memory-stores.ts +22 -0
- package/src/lib/bounded-body.ts +153 -9
- package/src/lib/bun-runtime.ts +125 -12
- package/src/lib/bun-stream-caps.ts +13 -9
- package/src/lib/codex-restart-contract.ts +120 -0
- package/src/lib/config-ownership.ts +6 -2
- package/src/lib/destination-policy.ts +65 -1
- package/src/lib/errors.ts +44 -2
- package/src/lib/fabric-task-execution-authority.ts +7 -0
- package/src/lib/fabric-task-host.ts +29 -0
- package/src/lib/lab-activation.ts +223 -0
- package/src/lib/lab-live-execution-authority.ts +13 -0
- package/src/lib/lab-live-host.ts +30 -0
- package/src/lib/lab-live-pinned-sender.ts +56 -0
- package/src/lib/lab-live-route-production.ts +130 -0
- package/src/lib/lab-passive-linker-registration.ts +26 -0
- package/src/lib/local-management-attestation.ts +51 -0
- package/src/lib/local-management-capability.ts +100 -0
- package/src/lib/local-provider-reload-contract.ts +100 -0
- package/src/lib/optional-shutdown-hooks.ts +57 -0
- package/src/lib/pinned-http.ts +145 -26
- package/src/lib/process-control.ts +4 -1
- package/src/lib/provider-outbound.ts +49 -9
- package/src/lib/redact.ts +419 -3
- package/src/lib/self-launch-argv.ts +15 -0
- package/src/lib/server-resource-ownership.ts +71 -0
- package/src/lib/shadow-call.ts +35 -4
- package/src/lib/sse-decoder.ts +41 -0
- package/src/lib/state-store-registrations.ts +10 -2
- package/src/lib/system-restart-contract.ts +73 -0
- package/src/lib/token-estimate.ts +19 -2
- package/src/lib/tool-argument-integers.ts +202 -0
- package/src/lib/translator-budget.ts +44 -0
- package/src/lib/upstream-http-version.ts +57 -0
- package/src/lib/upstream-reachability.ts +95 -0
- package/src/lib/upstream-retry.ts +156 -3
- package/src/lib/windows-atomic-replace.ts +155 -0
- package/src/lib/windows-elevation.ts +70 -2
- package/src/lib/windows-secret-acl.ts +409 -69
- package/src/lib/windows-service-wrappers.ts +72 -0
- package/src/lib/windows-text.ts +106 -0
- package/src/lib/windows-user-principal.ts +341 -0
- package/src/lib/winsw.ts +33 -5
- package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
- package/src/oauth/account-import/index.ts +15 -0
- package/src/oauth/account-import/parser.ts +83 -0
- package/src/oauth/account-import/registry.ts +18 -0
- package/src/oauth/account-import/service.ts +75 -0
- package/src/oauth/account-import/types.ts +91 -0
- package/src/oauth/anthropic.ts +12 -1
- package/src/oauth/callback-server.ts +8 -2
- package/src/oauth/chatgpt.ts +12 -1
- package/src/oauth/command-code.ts +239 -0
- package/src/oauth/cursor.ts +46 -5
- package/src/oauth/google-antigravity.ts +35 -3
- package/src/oauth/health.ts +20 -12
- package/src/oauth/index.ts +398 -66
- package/src/oauth/key-providers.ts +16 -0
- package/src/oauth/kimi.ts +16 -2
- package/src/oauth/kiro.ts +50 -6
- package/src/oauth/local-token-detect.ts +11 -2
- package/src/oauth/log.ts +3 -1
- package/src/oauth/login-cli.ts +88 -28
- package/src/oauth/nous.ts +798 -0
- package/src/oauth/store.ts +119 -21
- package/src/oauth/token-guardian.ts +9 -3
- package/src/pi/models.ts +2 -2
- package/src/providers/alibaba-region-migration.ts +1 -1
- package/src/providers/antigravity-models.ts +521 -31
- package/src/providers/base-url-choices.ts +10 -0
- package/src/providers/codex-capacity.ts +292 -0
- package/src/providers/command-code-efforts.ts +144 -0
- package/src/providers/context-cap.ts +22 -5
- package/src/providers/cursor-pool.ts +72 -0
- package/src/providers/derive.ts +253 -6
- package/src/providers/fastwire.ts +501 -0
- package/src/providers/free-directory.ts +10 -7
- package/src/providers/google-vertex-location.ts +14 -0
- package/src/providers/key-failover.ts +71 -3
- package/src/providers/label.ts +1 -1
- package/src/providers/model-discovery-limits.ts +16 -0
- package/src/providers/model-discovery.ts +115 -22
- package/src/providers/model-rename-migration.ts +255 -0
- package/src/providers/model-rename-startup.ts +28 -0
- package/src/providers/openai-sidecar.ts +72 -4
- package/src/providers/openai-tier-startup.ts +31 -2
- package/src/providers/openai-tiers.ts +119 -4
- package/src/providers/openai-virtual-models.ts +1 -0
- package/src/providers/opencode-zen-rate-limit.ts +102 -0
- package/src/providers/provider-id-rewrite.ts +29 -0
- package/src/providers/quota.ts +1319 -38
- package/src/providers/registry.ts +1429 -111
- package/src/providers/request-pacing.ts +310 -0
- package/src/providers/service-tier.ts +277 -0
- package/src/providers/slug-codec.ts +42 -6
- package/src/providers/static-model-discovery.ts +86 -0
- package/src/providers/xai-responses-opt-in.ts +15 -0
- package/src/providers/xai-transport.ts +11 -4
- package/src/reasoning-effort.ts +49 -1
- package/src/responses/compaction.ts +26 -1
- package/src/responses/custom-tool-compat.ts +266 -0
- package/src/responses/hosted-tool-policy.ts +9 -0
- package/src/responses/namespace-tool-compat.ts +355 -0
- package/src/responses/parser.ts +220 -38
- package/src/responses/provider-continuation.ts +98 -0
- package/src/responses/provider-opaque-metadata.ts +73 -0
- package/src/responses/reasoning-envelope.ts +9 -1
- package/src/responses/reasoning-replay-cache.ts +426 -0
- package/src/responses/schema.ts +7 -1
- package/src/responses/spill-store.ts +75 -10
- package/src/responses/state.ts +565 -27
- package/src/responses/thought-signature-replay.ts +347 -0
- package/src/responses/tool-search-compat.ts +301 -0
- package/src/responses/truncated-stop-reason.ts +60 -0
- package/src/router.ts +366 -30
- package/src/routing/analytics.ts +378 -0
- package/src/routing/capability.ts +244 -0
- package/src/routing/compatibility/assemble.ts +73 -0
- package/src/routing/compatibility/behavior.ts +278 -0
- package/src/routing/compatibility/catalog.ts +99 -0
- package/src/routing/compatibility/endpoint.ts +52 -0
- package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
- package/src/routing/compatibility/policy.ts +181 -0
- package/src/routing/compatibility/provider-slot.ts +56 -0
- package/src/routing/compatibility/reader.ts +110 -0
- package/src/routing/compatibility/subject.ts +191 -0
- package/src/routing/compatibility/types.ts +64 -0
- package/src/routing/compatibility/version.ts +104 -0
- package/src/routing/cost.ts +77 -0
- package/src/routing/evaluator.ts +495 -0
- package/src/routing/health.ts +412 -0
- package/src/routing/history/cursor.ts +43 -0
- package/src/routing/history/indexer.ts +605 -0
- package/src/routing/history/schema.ts +72 -0
- package/src/routing/profile-namespace.ts +15 -0
- package/src/routing/profile.ts +547 -0
- package/src/routing/quota.ts +145 -0
- package/src/routing/request-evidence.ts +45 -0
- package/src/routing/trace.ts +776 -0
- package/src/server/adapter-resolve.ts +2 -29
- package/src/server/auth-cors.ts +267 -46
- package/src/server/background-lifecycle.ts +182 -0
- package/src/server/chat-completions.ts +130 -56
- package/src/server/chat-native-sse.ts +331 -0
- package/src/server/chat-native.ts +426 -0
- package/src/server/claude-messages.ts +159 -43
- package/src/server/direct-local-http.ts +347 -0
- package/src/server/effort-policy.ts +18 -0
- package/src/server/github-copilot-responses-repair.ts +338 -0
- package/src/server/gui-static.ts +39 -10
- package/src/server/images.ts +94 -12
- package/src/server/index.ts +865 -181
- package/src/server/lifecycle.ts +284 -13
- package/src/server/live.ts +136 -17
- package/src/server/local-management-read-client.ts +90 -0
- package/src/server/local-provider-reload-client.ts +137 -0
- package/src/server/management/agent-settings-routes.ts +398 -103
- package/src/server/management/api-key-usage.ts +31 -5
- package/src/server/management/body.ts +6 -0
- package/src/server/management/combo-routes.ts +62 -24
- package/src/server/management/config-routes.ts +464 -51
- package/src/server/management/context.ts +80 -2
- package/src/server/management/integration-routes.ts +498 -0
- package/src/server/management/lab-automation-routes.ts +206 -0
- package/src/server/management/lab-routes.ts +563 -0
- package/src/server/management/logs-usage-routes.ts +101 -32
- package/src/server/management/model-routes.ts +189 -131
- package/src/server/management/model-rows.ts +163 -0
- package/src/server/management/native-integration-routes.ts +769 -0
- package/src/server/management/oauth-account-routes.ts +80 -4
- package/src/server/management/provider-capability-config.ts +48 -0
- package/src/server/management/provider-routes.ts +764 -157
- package/src/server/management/request-history-routes.ts +191 -0
- package/src/server/management/routing-analytics-routes.ts +74 -0
- package/src/server/management/routing-profile-routes.ts +380 -0
- package/src/server/management/shared.ts +27 -11
- package/src/server/management/sidebar-routes.ts +47 -31
- package/src/server/management/storage-log-guard-routes.ts +186 -0
- package/src/server/management/sync-response.ts +69 -0
- package/src/server/management/system-restart.ts +288 -32
- package/src/server/management/system-routes.ts +77 -0
- package/src/server/management/usage-summary-cache.ts +9 -1
- package/src/server/management/vision-sidecar-options.ts +167 -0
- package/src/server/management/web-search-sidecar-options.ts +120 -0
- package/src/server/management-api.ts +115 -14
- package/src/server/management-auth.ts +220 -5
- package/src/server/passive-route-linker.ts +66 -0
- package/src/server/ports.ts +41 -1
- package/src/server/proxy-liveness.ts +132 -5
- package/src/server/readiness.ts +99 -0
- package/src/server/relay-eager.ts +82 -42
- package/src/server/relay.ts +236 -76
- package/src/server/request-decompress.ts +113 -6
- package/src/server/request-log.ts +235 -22
- package/src/server/responses/agent-task-recovery-cache.ts +143 -0
- package/src/server/responses/agent-task-recovery.ts +465 -0
- package/src/server/responses/collaboration.ts +204 -35
- package/src/server/responses/compact.ts +442 -55
- package/src/server/responses/core.ts +2872 -331
- package/src/server/responses/empty-completion-guard.ts +276 -0
- package/src/server/responses/encrypted-payload.ts +62 -39
- package/src/server/responses/fetch-helpers.ts +79 -4
- package/src/server/responses/input-admission.ts +185 -0
- package/src/server/responses/pacing-overload.ts +13 -0
- package/src/server/responses/policy-fallback.ts +178 -0
- package/src/server/responses/responses-field-backfill.ts +251 -0
- package/src/server/responses/terminal-guard.ts +26 -5
- package/src/server/responses/upstream-error.ts +5 -0
- package/src/server/responses/ws-upstream.ts +308 -0
- package/src/server/responses-custom-tool-repair.ts +282 -0
- package/src/server/responses-item-id-repair.ts +54 -6
- package/src/server/responses-json-events.ts +90 -0
- package/src/server/responses-model-rewrite.ts +29 -0
- package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
- package/src/server/responses-snapshot-repair.ts +621 -0
- package/src/server/responses-terminal-repair.ts +342 -0
- package/src/server/responses-tool-search-repair.ts +267 -0
- package/src/server/responses-undeclared-tool-guard.ts +153 -0
- package/src/server/responses.ts +18 -2
- package/src/server/search.ts +78 -13
- package/src/server/sse-frame-buffer.ts +292 -0
- package/src/server/sse-payload-rewrite.ts +110 -22
- package/src/server/startup-action-control.ts +8 -1
- package/src/server/startup-health-cache.ts +19 -1
- package/src/server/system-env.ts +80 -9
- package/src/server/ws-bridge.ts +39 -38
- package/src/service-manager-probe.ts +892 -0
- package/src/service.ts +1111 -90
- package/src/sidecar/auth.ts +92 -0
- package/src/sidecar/candidates.ts +83 -0
- package/src/storage/cleanup.ts +2 -2
- package/src/storage/scanner.ts +1 -1
- package/src/storage/worker-lifecycle.ts +14 -14
- package/src/tray/windows-tray.ps1 +83 -9
- package/src/tray/windows.ts +43 -16
- package/src/types/accounts.ts +37 -0
- package/src/types/config.ts +845 -0
- package/src/types/provider.ts +545 -0
- package/src/types/request.ts +384 -0
- package/src/types/tools.ts +131 -0
- package/src/types/wire.ts +80 -0
- package/src/types.ts +104 -1236
- package/src/update/index.ts +32 -19
- package/src/update/job.ts +442 -67
- package/src/update/notify.ts +12 -6
- package/src/update/npm-cache-preflight.d.mts +47 -0
- package/src/update/npm-cache-preflight.mjs +201 -0
- package/src/update/transactional-install.d.mts +22 -0
- package/src/update/transactional-install.mjs +259 -0
- package/src/usage/cost.ts +0 -0
- package/src/usage/expected-prices.ts +268 -16
- package/src/usage/log.ts +606 -41
- package/src/usage/summary.ts +177 -9
- package/src/usage/user-cost-overlay-reconciler.ts +313 -0
- package/src/usage/user-cost-overlays.ts +314 -0
- package/src/vision/anthropic-describe.ts +10 -6
- package/src/vision/backends.ts +97 -0
- package/src/vision/describe.ts +9 -3
- package/src/vision/eligibility.ts +250 -0
- package/src/vision/index.ts +238 -24
- package/src/vision/reasoning.ts +55 -0
- package/src/vision/routed-describe.ts +175 -0
- package/src/vision/timeout-bounds.ts +9 -0
- package/src/web-search/anthropic-executor.ts +13 -7
- package/src/web-search/backends.ts +108 -0
- package/src/web-search/exa-executor.ts +88 -0
- package/src/web-search/executor.ts +11 -3
- package/src/web-search/gemini-executor.ts +141 -0
- package/src/web-search/index.ts +150 -15
- package/src/web-search/loop.ts +279 -50
- package/src/web-search/parse.ts +125 -30
- package/src/web-search/sources.ts +60 -0
- package/src/web-search/xai-executor.ts +219 -0
- package/gui/dist/assets/index-DTpMHS4F.js +0 -67
- package/gui/dist/assets/index-ZNVDE3C7.css +0 -1
- package/gui/dist/provider-icons/antigravity.svg +0 -1
- package/gui/dist/provider-icons/claude.svg +0 -1
- package/gui/dist/provider-icons/copilot.svg +0 -1
- package/gui/dist/provider-icons/cursor.svg +0 -2
- package/gui/dist/provider-icons/gemini.svg +0 -1
- package/gui/dist/provider-icons/grok-color.svg +0 -1
- package/gui/dist/provider-icons/kiro.svg +0 -14
- package/src/cli/internal-dispatch.ts +0 -20
package/src/server/live.ts
CHANGED
|
@@ -19,24 +19,34 @@
|
|
|
19
19
|
* - `GET /v1/live/{callId}` — Frameless
|
|
20
20
|
* - `GET /v1/realtime/calls/{callId}` — path-form join
|
|
21
21
|
* - `GET /v1/realtime?call_id=` — Realtime v1/v2 join
|
|
22
|
+
*
|
|
23
|
+
* Inbound standalone session WebSocket (no call-create; codex-rs `thread/realtime/start`
|
|
24
|
+
* with the standalone WebSocket transport — the desktop voice path since 0.147.x):
|
|
25
|
+
* - `GET /v1/realtime?intent=quicksilver&model=` — Realtime v1 standalone
|
|
26
|
+
* - `GET /v1/realtime?model=` — RealtimeV2 standalone (no intent)
|
|
27
|
+
* - `GET /v1/live?model=` — Frameless standalone
|
|
22
28
|
*/
|
|
23
29
|
import { appendFileSync } from "node:fs";
|
|
24
30
|
import { formatErrorResponse } from "../bridge";
|
|
25
31
|
import {
|
|
26
32
|
CodexAccountCooldownError,
|
|
33
|
+
codexMainProfileDrainingResponse,
|
|
27
34
|
cooldownErrorResponse,
|
|
28
35
|
CodexAuthContextError,
|
|
36
|
+
CodexMainProfileDrainingError,
|
|
29
37
|
CodexPoolAuthenticationError,
|
|
30
38
|
CodexThreadAffinityExpiredError,
|
|
31
39
|
} from "../codex/auth-context";
|
|
32
40
|
import { formatCodexProviderForLog } from "../codex/routing";
|
|
33
|
-
import { signalWithTimeout } from "../lib/abort";
|
|
41
|
+
import { cancelBodyOnAbort, signalWithTimeout } from "../lib/abort";
|
|
34
42
|
import { sidecarEnter } from "../lib/sidecar-tracker";
|
|
35
43
|
import type { OcxConfig } from "../types";
|
|
36
44
|
import { resolveFirstUsableOpenAiSidecar, selectOpenAiImagesProvider } from "../providers/openai-sidecar";
|
|
37
45
|
import { ForwardAdmissionCredentialError, validateForwardAdmissionCredential } from "./auth-cors";
|
|
38
46
|
import type { RequestLogContext } from "./request-log";
|
|
39
47
|
import { codexLogAccountId } from "./responses";
|
|
48
|
+
import type { AdmissionLease } from "../lib/admission";
|
|
49
|
+
import { codexAccountSelectionForTurn } from "./lifecycle";
|
|
40
50
|
|
|
41
51
|
/** Voice call create can wait on SDP negotiation; bound a hung upstream. */
|
|
42
52
|
const LIVE_UPSTREAM_TIMEOUT_MS = 120_000;
|
|
@@ -137,10 +147,59 @@ function clientProtocolHeaders(reqHeaders: Headers): Record<string, string> {
|
|
|
137
147
|
|
|
138
148
|
const LIVE_CALL_ID_RE = /^[A-Za-z0-9_-]{1,128}$/;
|
|
139
149
|
|
|
150
|
+
/**
|
|
151
|
+
* Credential-shaped query keys never forwarded upstream on a standalone realtime
|
|
152
|
+
* relay. Auth on the upstream socket is proxy-owned (headers resolved by
|
|
153
|
+
* `resolveLiveRelay`); a caller that puts `access_token=`/`api_key=`/... in the
|
|
154
|
+
* URL must not get it relayed to the configured upstream. Compared case-folded on
|
|
155
|
+
* both the raw and percent-decoded key. Everything else — `intent`, `model`,
|
|
156
|
+
* duplicates, protocol extensions — passes through verbatim, matching codex-rs
|
|
157
|
+
* client behavior of constructing those fields itself.
|
|
158
|
+
*/
|
|
159
|
+
const STANDALONE_QUERY_DENYLIST = new Set([
|
|
160
|
+
"access_token",
|
|
161
|
+
"api_key",
|
|
162
|
+
"apikey",
|
|
163
|
+
"token",
|
|
164
|
+
"key",
|
|
165
|
+
"authorization",
|
|
166
|
+
"auth",
|
|
167
|
+
"signature",
|
|
168
|
+
"sig",
|
|
169
|
+
]);
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Filter a raw query string (no leading `?`) for standalone upstream relay: drop
|
|
173
|
+
* denylisted credential-shaped pairs, preserve the rest byte-for-byte (including
|
|
174
|
+
* ordering, duplicates, noncanonical encodings, and bare keys).
|
|
175
|
+
*/
|
|
176
|
+
export function sanitizeStandaloneRealtimeQuery(rawQuery: string): string {
|
|
177
|
+
if (!rawQuery) return "";
|
|
178
|
+
const kept: string[] = [];
|
|
179
|
+
for (const pair of rawQuery.split("&")) {
|
|
180
|
+
const eq = pair.indexOf("=");
|
|
181
|
+
const rawKey = eq === -1 ? pair : pair.slice(0, eq);
|
|
182
|
+
let decodedKey = rawKey;
|
|
183
|
+
try {
|
|
184
|
+
decodedKey = decodeURIComponent(rawKey);
|
|
185
|
+
} catch {
|
|
186
|
+
// Leave undecodable keys as-is; the raw comparison still applies.
|
|
187
|
+
}
|
|
188
|
+
if (STANDALONE_QUERY_DENYLIST.has(rawKey.toLowerCase()) || STANDALONE_QUERY_DENYLIST.has(decodedKey.toLowerCase())) {
|
|
189
|
+
console.warn(`[live] standalone realtime relay dropping credential-shaped query param: ${decodedKey}`);
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
kept.push(pair);
|
|
193
|
+
}
|
|
194
|
+
return kept.join("&");
|
|
195
|
+
}
|
|
196
|
+
|
|
140
197
|
export type LiveSidebandTarget =
|
|
141
198
|
| { style: "frameless-path"; callId: string }
|
|
142
199
|
| { style: "realtime-calls-path"; callId: string }
|
|
143
|
-
| { style: "realtime-query"; callId: string }
|
|
200
|
+
| { style: "realtime-query"; callId: string }
|
|
201
|
+
| { style: "realtime-standalone"; query: string }
|
|
202
|
+
| { style: "frameless-standalone"; query: string };
|
|
144
203
|
|
|
145
204
|
export type LiveRelayTarget = {
|
|
146
205
|
headers: Record<string, string>;
|
|
@@ -164,7 +223,7 @@ export function keyedLiveUrl(baseUrl: string): string {
|
|
|
164
223
|
}
|
|
165
224
|
|
|
166
225
|
export function forwardLiveUrl(baseUrl: string, usesBackendShape: boolean): string {
|
|
167
|
-
const root = baseUrl.replace(
|
|
226
|
+
const root = baseUrl.replace(/\/+$/, "");
|
|
168
227
|
if (usesBackendShape) return withAvasQuery(`${root}/realtime/calls`);
|
|
169
228
|
// Frameless API shape posts to /live without the AVAS query (codex RealtimeCallClient).
|
|
170
229
|
return `${root}/live`;
|
|
@@ -176,13 +235,17 @@ function httpsToWss(httpUrl: string): string {
|
|
|
176
235
|
return httpUrl;
|
|
177
236
|
}
|
|
178
237
|
|
|
179
|
-
export function parseLiveSidebandTarget(pathname: string, searchParams: URLSearchParams): LiveSidebandTarget | null {
|
|
238
|
+
export function parseLiveSidebandTarget(pathname: string, searchParams: URLSearchParams, rawQuery = ""): LiveSidebandTarget | null {
|
|
180
239
|
const liveMatch = pathname.match(/^\/v1\/live\/([^/]+)\/?$/);
|
|
181
240
|
if (liveMatch) {
|
|
182
241
|
const callId = decodeURIComponent(liveMatch[1]!);
|
|
183
242
|
if (!LIVE_CALL_ID_RE.test(callId)) return null;
|
|
184
243
|
return { style: "frameless-path", callId };
|
|
185
244
|
}
|
|
245
|
+
// Standalone Frameless session (no call-create): `GET /v1/live?model=`.
|
|
246
|
+
if (pathname === "/v1/live" || pathname === "/v1/live/") {
|
|
247
|
+
return { style: "frameless-standalone", query: sanitizeStandaloneRealtimeQuery(rawQuery) };
|
|
248
|
+
}
|
|
186
249
|
const callsMatch = pathname.match(/^\/v1\/realtime\/calls\/([^/]+)\/?$/);
|
|
187
250
|
if (callsMatch) {
|
|
188
251
|
const callId = decodeURIComponent(callsMatch[1]!);
|
|
@@ -190,9 +253,17 @@ export function parseLiveSidebandTarget(pathname: string, searchParams: URLSearc
|
|
|
190
253
|
return { style: "realtime-calls-path", callId };
|
|
191
254
|
}
|
|
192
255
|
if (pathname === "/v1/realtime" || pathname === "/v1/realtime/") {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
256
|
+
// A present-but-invalid `call_id` is a malformed join, not a standalone
|
|
257
|
+
// session — keep rejecting it instead of silently changing the request's
|
|
258
|
+
// meaning.
|
|
259
|
+
if (searchParams.has("call_id")) {
|
|
260
|
+
const callId = searchParams.get("call_id")?.trim() ?? "";
|
|
261
|
+
if (!LIVE_CALL_ID_RE.test(callId)) return null;
|
|
262
|
+
return { style: "realtime-query", callId };
|
|
263
|
+
}
|
|
264
|
+
// Standalone Realtime session (codex-rs thread/realtime/start, WebSocket
|
|
265
|
+
// transport): v1 sends `intent=quicksilver&model=`, v2 sends `model=` only.
|
|
266
|
+
return { style: "realtime-standalone", query: sanitizeStandaloneRealtimeQuery(rawQuery) };
|
|
196
267
|
}
|
|
197
268
|
return null;
|
|
198
269
|
}
|
|
@@ -203,8 +274,12 @@ export function parseLiveSidebandTarget(pathname: string, searchParams: URLSearc
|
|
|
203
274
|
*/
|
|
204
275
|
function isLoopbackHost(hostname: string): boolean {
|
|
205
276
|
const lower = hostname.toLowerCase();
|
|
277
|
+
const ipv4 = lower.split(".");
|
|
278
|
+
const ipv4Loopback = ipv4.length === 4
|
|
279
|
+
&& ipv4[0] === "127"
|
|
280
|
+
&& ipv4.every(part => /^\d{1,3}$/.test(part) && Number(part) <= 255);
|
|
206
281
|
return lower === "localhost" || lower.endsWith(".localhost")
|
|
207
|
-
||
|
|
282
|
+
|| ipv4Loopback
|
|
208
283
|
|| lower === "::1" || lower === "[::1]";
|
|
209
284
|
}
|
|
210
285
|
|
|
@@ -278,6 +353,12 @@ export function buildLiveSidebandUpstreamWsUrl(
|
|
|
278
353
|
if (target.style === "frameless-path") {
|
|
279
354
|
return httpsToWss(`${sidebandRoot}/live/${target.callId}`);
|
|
280
355
|
}
|
|
356
|
+
if (target.style === "frameless-standalone") {
|
|
357
|
+
return httpsToWss(`${sidebandRoot}/live${target.query ? `?${target.query}` : ""}`);
|
|
358
|
+
}
|
|
359
|
+
if (target.style === "realtime-standalone") {
|
|
360
|
+
return httpsToWss(`${sidebandRoot}/realtime${target.query ? `?${target.query}` : ""}`);
|
|
361
|
+
}
|
|
281
362
|
if (target.style === "realtime-calls-path") {
|
|
282
363
|
return httpsToWss(`${sidebandRoot}/realtime/calls/${target.callId}`);
|
|
283
364
|
}
|
|
@@ -356,8 +437,18 @@ export async function readBodyCapped(
|
|
|
356
437
|
}
|
|
357
438
|
chunks.push(value);
|
|
358
439
|
}
|
|
440
|
+
} catch (err) {
|
|
441
|
+
// A read that throws leaves the stream neither drained nor cancelled, and releasing the
|
|
442
|
+
// lock alone hands back an unsettled body. Cancel first, then rethrow so the caller's
|
|
443
|
+
// existing classification (client abort / timeout / connect error) is unchanged. The
|
|
444
|
+
// cancel itself can reject with the stream's stored error — that is expected and must not
|
|
445
|
+
// mask the original failure, so it is swallowed here.
|
|
446
|
+
await reader.cancel(err).catch(() => {});
|
|
447
|
+
throw err;
|
|
359
448
|
} finally {
|
|
360
449
|
try {
|
|
450
|
+
// Always release: `reader.cancel()` does NOT drop the lock, and holding it would leave
|
|
451
|
+
// the stream permanently locked for any later consumer (audit R-WP5-2).
|
|
361
452
|
reader.releaseLock();
|
|
362
453
|
} catch {
|
|
363
454
|
// already released / cancelled
|
|
@@ -409,6 +500,7 @@ export async function resolveLiveRelay(
|
|
|
409
500
|
req: Request,
|
|
410
501
|
config: OcxConfig,
|
|
411
502
|
logCtx: RequestLogContext,
|
|
503
|
+
turnAdmissionLease?: AdmissionLease,
|
|
412
504
|
): Promise<LiveRelayTarget | Response> {
|
|
413
505
|
try {
|
|
414
506
|
validateForwardAdmissionCredential(req.headers, config);
|
|
@@ -433,7 +525,9 @@ export async function resolveLiveRelay(
|
|
|
433
525
|
let forwardAuthError: Response | undefined;
|
|
434
526
|
if (candidates.forwardCandidates.length > 0) {
|
|
435
527
|
try {
|
|
436
|
-
forward = await resolveFirstUsableOpenAiSidecar(candidates.forwardCandidates, req.headers, config
|
|
528
|
+
forward = await resolveFirstUsableOpenAiSidecar(candidates.forwardCandidates, req.headers, config, {
|
|
529
|
+
beginCodexAccountSelection: codexAccountSelectionForTurn(turnAdmissionLease),
|
|
530
|
+
});
|
|
437
531
|
if (forward) {
|
|
438
532
|
logCtx.provider = formatCodexProviderForLog(
|
|
439
533
|
forward.providerName,
|
|
@@ -444,6 +538,8 @@ export async function resolveLiveRelay(
|
|
|
444
538
|
} catch (err) {
|
|
445
539
|
if (err instanceof CodexAccountCooldownError) {
|
|
446
540
|
forwardAuthError = cooldownErrorResponse(err);
|
|
541
|
+
} else if (err instanceof CodexMainProfileDrainingError) {
|
|
542
|
+
forwardAuthError = codexMainProfileDrainingResponse();
|
|
447
543
|
} else if (err instanceof CodexThreadAffinityExpiredError) {
|
|
448
544
|
forwardAuthError = formatErrorResponse(
|
|
449
545
|
409,
|
|
@@ -506,13 +602,14 @@ export async function handleLive(
|
|
|
506
602
|
req: Request,
|
|
507
603
|
config: OcxConfig,
|
|
508
604
|
logCtx: RequestLogContext,
|
|
605
|
+
turnAdmissionLease?: AdmissionLease,
|
|
509
606
|
): Promise<Response> {
|
|
510
607
|
const inboundContentType = req.headers.get("content-type") ?? "application/octet-stream";
|
|
511
608
|
const inboundBodyOrError = await readRequestBodyCapped(req, LIVE_REQUEST_MAX_BYTES);
|
|
512
609
|
if (inboundBodyOrError instanceof Response) return inboundBodyOrError;
|
|
513
610
|
const inboundBody = inboundBodyOrError;
|
|
514
611
|
|
|
515
|
-
const relay = await resolveLiveRelay(req, config, logCtx);
|
|
612
|
+
const relay = await resolveLiveRelay(req, config, logCtx, turnAdmissionLease);
|
|
516
613
|
if (relay instanceof Response) return relay;
|
|
517
614
|
|
|
518
615
|
const headers: Record<string, string> = { ...relay.headers };
|
|
@@ -532,7 +629,12 @@ export async function handleLive(
|
|
|
532
629
|
outboundContentType = rewritten.contentType;
|
|
533
630
|
}
|
|
534
631
|
} else {
|
|
535
|
-
|
|
632
|
+
// Frameless API-shape call-create posts to `{base}/live` without the AVAS
|
|
633
|
+
// query (openai/codex RealtimeCallClient, realtime_call.rs); only the
|
|
634
|
+
// realtime/calls inbound shape keeps the legacy keyed AVAS endpoint.
|
|
635
|
+
url = new URL(req.url).pathname === "/v1/live"
|
|
636
|
+
? forwardLiveUrl(relay.providerBaseUrl, /* usesBackendShape */ false)
|
|
637
|
+
: keyedLiveUrl(relay.providerBaseUrl);
|
|
536
638
|
}
|
|
537
639
|
|
|
538
640
|
headers["content-type"] = outboundContentType;
|
|
@@ -545,15 +647,31 @@ export async function handleLive(
|
|
|
545
647
|
headers,
|
|
546
648
|
body: outboundBody,
|
|
547
649
|
signal: linkedSignal.signal,
|
|
650
|
+
// Credential-bearing: do not follow a cross-origin 3xx. Bun strips `Authorization`
|
|
651
|
+
// across origins but forwards nonstandard headers such as `chatgpt-account-id`,
|
|
652
|
+
// `session_id`, and `x-codex-turn-metadata` to the redirect target.
|
|
653
|
+
redirect: "manual",
|
|
548
654
|
});
|
|
549
655
|
// Record every completed upstream response before body size handling so account health /
|
|
550
656
|
// cooldown still updates when we reject an oversized payload.
|
|
551
657
|
relay.recordOutcome?.(upstreamResponse.status);
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
658
|
+
// Settle the body on abort before the reader attaches. Without this, a client cancel or the
|
|
659
|
+
// linked timeout landing between fetch resolution and `readBodyCapped`'s `getReader()`
|
|
660
|
+
// leaves Bun's internal read rejection orphaned off the awaited path, where no caller
|
|
661
|
+
// try/catch can intercept it (src/lib/abort.ts). The guard covers the window BEFORE the
|
|
662
|
+
// reader exists; once a reader holds the lock only the reader can cancel, which is why
|
|
663
|
+
// readBodyCapped also cancels on a failed read. Found while investigating #1419.
|
|
664
|
+
const detachBodyGuard = cancelBodyOnAbort(upstreamResponse.body, linkedSignal.signal);
|
|
665
|
+
let payload: ArrayBuffer | Response;
|
|
666
|
+
try {
|
|
667
|
+
payload = await readBodyCapped(
|
|
668
|
+
upstreamResponse.body,
|
|
669
|
+
LIVE_RESPONSE_MAX_BYTES,
|
|
670
|
+
total => `live response too large (${total} bytes)`,
|
|
671
|
+
);
|
|
672
|
+
} finally {
|
|
673
|
+
detachBodyGuard();
|
|
674
|
+
}
|
|
557
675
|
if (payload instanceof Response) return payload;
|
|
558
676
|
const relayHeaders: Record<string, string> = {};
|
|
559
677
|
for (const name of LIVE_RELAY_HEADERS) {
|
|
@@ -587,8 +705,9 @@ export async function resolveLiveSidebandUpgrade(
|
|
|
587
705
|
config: OcxConfig,
|
|
588
706
|
logCtx: RequestLogContext,
|
|
589
707
|
target: LiveSidebandTarget,
|
|
708
|
+
turnAdmissionLease?: AdmissionLease,
|
|
590
709
|
): Promise<{ headers: Record<string, string>; upstreamWsUrl: string; recordOutcome?: LiveRelayTarget["recordOutcome"] } | Response> {
|
|
591
|
-
const relay = await resolveLiveRelay(req, config, logCtx);
|
|
710
|
+
const relay = await resolveLiveRelay(req, config, logCtx, turnAdmissionLease);
|
|
592
711
|
if (relay instanceof Response) return relay;
|
|
593
712
|
return {
|
|
594
713
|
headers: relay.headers,
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { readRuntimePort, type RuntimePortState } from "../config";
|
|
2
|
+
import { createLocalAttestationChallenge } from "../lib/local-management-attestation";
|
|
3
|
+
import {
|
|
4
|
+
LOCAL_MANAGEMENT_CAPABILITY_HEADER,
|
|
5
|
+
LOCAL_MANAGEMENT_CAPABILITY_EXPIRES_AT_HEADER,
|
|
6
|
+
LOCAL_MANAGEMENT_CAPABILITY_TTL_MS,
|
|
7
|
+
LOCAL_MANAGEMENT_EXPECTED_PID_HEADER,
|
|
8
|
+
LOCAL_MANAGEMENT_NONCE_HEADER,
|
|
9
|
+
createLocalManagementReadCapability,
|
|
10
|
+
type LocalManagementReadPath,
|
|
11
|
+
} from "../lib/local-management-capability";
|
|
12
|
+
import { directLocalHttpFetch } from "./direct-local-http";
|
|
13
|
+
import { probeHostname, type LiveProxy } from "./proxy-liveness";
|
|
14
|
+
|
|
15
|
+
export type LocalManagementReadResult =
|
|
16
|
+
| { kind: "response"; response: Response; targetPid: number }
|
|
17
|
+
| { kind: "unavailable"; reason: "unattested-target" | "runtime-mismatch" | "capability-unavailable" | "transport" };
|
|
18
|
+
|
|
19
|
+
export interface LocalManagementReadDeps {
|
|
20
|
+
fetchImpl?: typeof fetch;
|
|
21
|
+
readRuntime?: (pid: number) => RuntimePortState | null;
|
|
22
|
+
createNonce?: () => string;
|
|
23
|
+
now?: () => number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface LocalManagementReadRequestDeps extends LocalManagementReadDeps {
|
|
27
|
+
timeoutMs?: number;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Read one exact local management endpoint without sending a reusable admin credential.
|
|
32
|
+
*
|
|
33
|
+
* The runtime record is the protected source of the per-process key. The server proves
|
|
34
|
+
* it owns that key by accepting a single-use capability bound to this GET, path, PID,
|
|
35
|
+
* port, and short expiry.
|
|
36
|
+
*/
|
|
37
|
+
export async function fetchBoundLocalManagementRead(
|
|
38
|
+
target: LiveProxy,
|
|
39
|
+
path: LocalManagementReadPath,
|
|
40
|
+
deps: LocalManagementReadRequestDeps = {},
|
|
41
|
+
): Promise<LocalManagementReadResult> {
|
|
42
|
+
if (
|
|
43
|
+
target.source !== "runtime"
|
|
44
|
+
|| target.pid === null
|
|
45
|
+
|| !Number.isSafeInteger(target.pid)
|
|
46
|
+
|| target.pid <= 0
|
|
47
|
+
) {
|
|
48
|
+
return { kind: "unavailable", reason: "unattested-target" };
|
|
49
|
+
}
|
|
50
|
+
const readRuntime = deps.readRuntime ?? readRuntimePort;
|
|
51
|
+
const runtime = readRuntime(target.pid);
|
|
52
|
+
if (
|
|
53
|
+
!runtime?.attestationSecret
|
|
54
|
+
|| runtime.pid !== target.pid
|
|
55
|
+
|| runtime.port !== target.port
|
|
56
|
+
) {
|
|
57
|
+
return { kind: "unavailable", reason: "runtime-mismatch" };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const nonce = (deps.createNonce ?? createLocalAttestationChallenge)();
|
|
61
|
+
const expiresAt = (deps.now ?? Date.now)() + LOCAL_MANAGEMENT_CAPABILITY_TTL_MS;
|
|
62
|
+
const capability = createLocalManagementReadCapability(
|
|
63
|
+
runtime.attestationSecret,
|
|
64
|
+
nonce,
|
|
65
|
+
"GET",
|
|
66
|
+
path,
|
|
67
|
+
target.pid,
|
|
68
|
+
target.port,
|
|
69
|
+
expiresAt,
|
|
70
|
+
);
|
|
71
|
+
if (!capability) return { kind: "unavailable", reason: "capability-unavailable" };
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
const response = await (deps.fetchImpl ?? directLocalHttpFetch)(
|
|
75
|
+
`http://${probeHostname(target.hostname)}:${target.port}${path}`,
|
|
76
|
+
{
|
|
77
|
+
headers: {
|
|
78
|
+
[LOCAL_MANAGEMENT_EXPECTED_PID_HEADER]: String(target.pid),
|
|
79
|
+
[LOCAL_MANAGEMENT_NONCE_HEADER]: nonce,
|
|
80
|
+
[LOCAL_MANAGEMENT_CAPABILITY_EXPIRES_AT_HEADER]: String(expiresAt),
|
|
81
|
+
[LOCAL_MANAGEMENT_CAPABILITY_HEADER]: capability,
|
|
82
|
+
},
|
|
83
|
+
signal: AbortSignal.timeout(deps.timeoutMs ?? 4_000),
|
|
84
|
+
},
|
|
85
|
+
);
|
|
86
|
+
return { kind: "response", response, targetPid: target.pid };
|
|
87
|
+
} catch {
|
|
88
|
+
return { kind: "unavailable", reason: "transport" };
|
|
89
|
+
}
|
|
90
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { readRuntimePort, type RuntimePortState } from "../config";
|
|
2
|
+
import {
|
|
3
|
+
LOCAL_ATTESTATION_CHALLENGE_HEADER,
|
|
4
|
+
LOCAL_ATTESTATION_PROOF_HEADER,
|
|
5
|
+
createLocalAttestationChallenge,
|
|
6
|
+
verifyLocalAttestationProof,
|
|
7
|
+
} from "../lib/local-management-attestation";
|
|
8
|
+
import {
|
|
9
|
+
LOCAL_PROVIDER_RELOAD_CAPABILITY_HEADER,
|
|
10
|
+
LOCAL_PROVIDER_RELOAD_CAPABILITY_TTL_MS,
|
|
11
|
+
LOCAL_PROVIDER_RELOAD_CAPABILITY_VERSION,
|
|
12
|
+
LOCAL_PROVIDER_RELOAD_EXPECTED_PID_HEADER,
|
|
13
|
+
LOCAL_PROVIDER_RELOAD_EXPIRES_AT_HEADER,
|
|
14
|
+
LOCAL_PROVIDER_RELOAD_METHOD,
|
|
15
|
+
LOCAL_PROVIDER_RELOAD_NAME_HEADER,
|
|
16
|
+
LOCAL_PROVIDER_RELOAD_NONCE_HEADER,
|
|
17
|
+
LOCAL_PROVIDER_RELOAD_PATH,
|
|
18
|
+
createLocalProviderReloadCapability,
|
|
19
|
+
isLocalProviderReloadName,
|
|
20
|
+
} from "../lib/local-provider-reload-contract";
|
|
21
|
+
import { directLocalHttpFetch } from "./direct-local-http";
|
|
22
|
+
import { isOpencodexHealthz, probeHostname, type HealthzIdentity, type LiveProxy } from "./proxy-liveness";
|
|
23
|
+
|
|
24
|
+
export type LocalProviderReloadResult =
|
|
25
|
+
| { kind: "reloaded" }
|
|
26
|
+
| { kind: "unavailable"; reason: "invalid-name" | "unattested-target" | "runtime-mismatch" | "attestation" | "capability" | "transport" | "rejected" };
|
|
27
|
+
|
|
28
|
+
export interface LocalProviderReloadDeps {
|
|
29
|
+
fetchImpl?: typeof fetch;
|
|
30
|
+
readRuntime?: (pid: number) => RuntimePortState | null;
|
|
31
|
+
createNonce?: () => string;
|
|
32
|
+
now?: () => number;
|
|
33
|
+
timeoutMs?: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const LOCAL_PROVIDER_RELOAD_TIMEOUT_MS = 10_000;
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Ask the exact runtime proxy to reload one already-persisted provider.
|
|
40
|
+
*
|
|
41
|
+
* No provider object, API key, OAuth token, custom header, or reusable management
|
|
42
|
+
* credential crosses the socket. The request is bodyless and its one-shot capability
|
|
43
|
+
* binds the provider name to the attested process, method, path, PID, port, and expiry.
|
|
44
|
+
*/
|
|
45
|
+
export async function requestBoundLocalProviderReload(
|
|
46
|
+
target: LiveProxy,
|
|
47
|
+
name: string,
|
|
48
|
+
deps: LocalProviderReloadDeps = {},
|
|
49
|
+
): Promise<LocalProviderReloadResult> {
|
|
50
|
+
if (!isLocalProviderReloadName(name)) return { kind: "unavailable", reason: "invalid-name" };
|
|
51
|
+
if (target.source !== "runtime" || target.pid === null || target.pid <= 0) {
|
|
52
|
+
return { kind: "unavailable", reason: "unattested-target" };
|
|
53
|
+
}
|
|
54
|
+
const readRuntime = deps.readRuntime ?? readRuntimePort;
|
|
55
|
+
const runtime = readRuntime(target.pid);
|
|
56
|
+
if (
|
|
57
|
+
!runtime?.attestationSecret
|
|
58
|
+
|| runtime.pid !== target.pid
|
|
59
|
+
|| runtime.port !== target.port
|
|
60
|
+
) {
|
|
61
|
+
return { kind: "unavailable", reason: "runtime-mismatch" };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const fetchImpl = deps.fetchImpl ?? directLocalHttpFetch;
|
|
65
|
+
const timeoutMs = deps.timeoutMs ?? LOCAL_PROVIDER_RELOAD_TIMEOUT_MS;
|
|
66
|
+
const nonce = (deps.createNonce ?? createLocalAttestationChallenge)();
|
|
67
|
+
const baseUrl = `http://${probeHostname(target.hostname)}:${target.port}`;
|
|
68
|
+
let proofResponse: Response;
|
|
69
|
+
try {
|
|
70
|
+
proofResponse = await fetchImpl(`${baseUrl}/healthz`, {
|
|
71
|
+
headers: { [LOCAL_ATTESTATION_CHALLENGE_HEADER]: nonce },
|
|
72
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
73
|
+
});
|
|
74
|
+
} catch {
|
|
75
|
+
return { kind: "unavailable", reason: "transport" };
|
|
76
|
+
}
|
|
77
|
+
const body = await proofResponse.json().catch(() => null) as HealthzIdentity | null;
|
|
78
|
+
if (
|
|
79
|
+
!proofResponse.ok
|
|
80
|
+
|| !isOpencodexHealthz(body)
|
|
81
|
+
|| body?.pid !== target.pid
|
|
82
|
+
|| body?.port !== target.port
|
|
83
|
+
|| body?.providerReloadCapability !== LOCAL_PROVIDER_RELOAD_CAPABILITY_VERSION
|
|
84
|
+
|| !verifyLocalAttestationProof(
|
|
85
|
+
runtime.attestationSecret,
|
|
86
|
+
nonce,
|
|
87
|
+
target.pid,
|
|
88
|
+
target.port,
|
|
89
|
+
proofResponse.headers.get(LOCAL_ATTESTATION_PROOF_HEADER),
|
|
90
|
+
)
|
|
91
|
+
) {
|
|
92
|
+
return { kind: "unavailable", reason: "attestation" };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const currentRuntime = readRuntime(target.pid);
|
|
96
|
+
if (
|
|
97
|
+
!currentRuntime?.attestationSecret
|
|
98
|
+
|| currentRuntime.pid !== runtime.pid
|
|
99
|
+
|| currentRuntime.port !== runtime.port
|
|
100
|
+
|| currentRuntime.hostname !== runtime.hostname
|
|
101
|
+
|| currentRuntime.attestationSecret !== runtime.attestationSecret
|
|
102
|
+
) {
|
|
103
|
+
return { kind: "unavailable", reason: "runtime-mismatch" };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const expiresAt = (deps.now ?? Date.now)() + LOCAL_PROVIDER_RELOAD_CAPABILITY_TTL_MS;
|
|
107
|
+
const capability = createLocalProviderReloadCapability(
|
|
108
|
+
runtime.attestationSecret,
|
|
109
|
+
nonce,
|
|
110
|
+
LOCAL_PROVIDER_RELOAD_METHOD,
|
|
111
|
+
LOCAL_PROVIDER_RELOAD_PATH,
|
|
112
|
+
name,
|
|
113
|
+
target.pid,
|
|
114
|
+
target.port,
|
|
115
|
+
expiresAt,
|
|
116
|
+
);
|
|
117
|
+
if (!capability) return { kind: "unavailable", reason: "capability" };
|
|
118
|
+
|
|
119
|
+
try {
|
|
120
|
+
const response = await fetchImpl(`${baseUrl}${LOCAL_PROVIDER_RELOAD_PATH}`, {
|
|
121
|
+
method: LOCAL_PROVIDER_RELOAD_METHOD,
|
|
122
|
+
headers: {
|
|
123
|
+
[LOCAL_PROVIDER_RELOAD_EXPECTED_PID_HEADER]: String(target.pid),
|
|
124
|
+
[LOCAL_PROVIDER_RELOAD_NONCE_HEADER]: nonce,
|
|
125
|
+
[LOCAL_PROVIDER_RELOAD_EXPIRES_AT_HEADER]: String(expiresAt),
|
|
126
|
+
[LOCAL_PROVIDER_RELOAD_NAME_HEADER]: name,
|
|
127
|
+
[LOCAL_PROVIDER_RELOAD_CAPABILITY_HEADER]: capability,
|
|
128
|
+
},
|
|
129
|
+
signal: AbortSignal.timeout(timeoutMs),
|
|
130
|
+
});
|
|
131
|
+
return response.ok
|
|
132
|
+
? { kind: "reloaded" }
|
|
133
|
+
: { kind: "unavailable", reason: "rejected" };
|
|
134
|
+
} catch {
|
|
135
|
+
return { kind: "unavailable", reason: "transport" };
|
|
136
|
+
}
|
|
137
|
+
}
|