@iislee/opencodex 2.11.0 → 2.35.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 +117 -22
- package/bin/ocx.mjs +245 -88
- package/bin/package-main.mjs +1 -1
- package/gui/dist/assets/index-Be1sDpWw.css +1 -0
- package/gui/dist/assets/index-D4OKgUV4.js +114 -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 +21 -10
- package/src/adapters/anthropic-output-schema.ts +137 -0
- package/src/adapters/anthropic.ts +475 -62
- package/src/adapters/base.ts +82 -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 +637 -0
- package/src/adapters/cursor/call-id.ts +44 -0
- package/src/adapters/cursor/catalog.ts +541 -0
- package/src/adapters/cursor/checkpoint-store.ts +308 -0
- package/src/adapters/cursor/cursor-errors.ts +144 -6
- package/src/adapters/cursor/discovery.ts +122 -14
- package/src/adapters/cursor/effort-map.ts +106 -4
- package/src/adapters/cursor/envelope-echo.ts +290 -0
- 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 +180 -59
- package/src/adapters/cursor/live-transport.ts +623 -170
- package/src/adapters/cursor/message-mapper.ts +4 -1
- package/src/adapters/cursor/native-exec-common.ts +23 -2
- package/src/adapters/cursor/native-exec-desktop.ts +23 -0
- 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 +5 -3
- package/src/adapters/cursor/native-exec.ts +121 -14
- package/src/adapters/cursor/protobuf-events.ts +829 -11
- package/src/adapters/cursor/protobuf-request.ts +447 -75
- package/src/adapters/cursor/request-builder.ts +271 -35
- package/src/adapters/cursor/tool-definitions.ts +252 -12
- package/src/adapters/cursor/tool-result-normalize.ts +115 -0
- package/src/adapters/cursor/transport.ts +22 -0
- package/src/adapters/cursor/types.ts +48 -1
- package/src/adapters/cursor.ts +336 -39
- package/src/adapters/exec-tool-result-normalize.ts +99 -0
- package/src/adapters/google-antigravity-replay.ts +713 -41
- package/src/adapters/google-antigravity-wire.ts +48 -10
- package/src/adapters/google-errors.ts +44 -12
- 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 +742 -86
- package/src/adapters/identity.ts +39 -6
- package/src/adapters/image.ts +1 -1
- package/src/adapters/kiro-constants.ts +27 -0
- 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 +65 -17
- package/src/adapters/kiro.ts +270 -73
- package/src/adapters/mimo-free.ts +17 -0
- package/src/adapters/openai-chat-url.ts +11 -0
- package/src/adapters/openai-chat.ts +1377 -344
- package/src/adapters/openai-responses-url.ts +16 -0
- package/src/adapters/openai-responses.ts +1164 -64
- package/src/adapters/registry.ts +175 -0
- package/src/adapters/responses-tool-schema.ts +67 -0
- package/src/adapters/run-turn-queue.ts +36 -1
- package/src/adapters/tool-call-id.ts +119 -0
- package/src/adapters/tool-catalog-nudge.ts +105 -21
- package/src/adapters/xai-tool-schema.ts +436 -0
- package/src/adapters/xai-web-search.ts +186 -0
- package/src/bridge.ts +512 -92
- package/src/chat/inbound.ts +57 -20
- package/src/chat/outbound.ts +97 -33
- package/src/claude/agents-inject.ts +40 -10
- package/src/claude/context-windows.ts +37 -14
- 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 +88 -21
- package/src/cli/access.ts +46 -3
- package/src/cli/account-api.ts +150 -19
- package/src/cli/account-auth.ts +33 -6
- package/src/cli/account-catalog-refresh.ts +14 -0
- package/src/cli/account-extended.ts +648 -28
- package/src/cli/account-main.ts +317 -0
- package/src/cli/account.ts +97 -19
- package/src/cli/agent.ts +53 -2
- package/src/cli/alias.ts +66 -0
- package/src/cli/capabilities-command.ts +94 -0
- package/src/cli/capabilities.ts +496 -0
- package/src/cli/claude-agent-startup-sync.ts +73 -0
- package/src/cli/claude-desktop.ts +60 -15
- package/src/cli/claude.ts +129 -35
- 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 +821 -0
- package/src/cli/doctor.ts +440 -56
- package/src/cli/ensure-desired-integrations.ts +152 -0
- package/src/cli/export-command.ts +46 -20
- package/src/cli/help.ts +34 -274
- package/src/cli/index.ts +417 -528
- package/src/cli/init.ts +5 -17
- package/src/cli/inspect.ts +230 -0
- 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 +130 -2
- package/src/cli/models.ts +118 -16
- package/src/cli/observe.ts +123 -11
- package/src/cli/opencode.ts +4 -2
- package/src/cli/provider-runtime.ts +34 -3
- package/src/cli/provider.ts +25 -3
- package/src/cli/ready.ts +301 -0
- package/src/cli/registry.ts +476 -0
- package/src/cli/root.ts +86 -0
- package/src/cli/route-policy.ts +92 -0
- package/src/cli/runtime-api.ts +57 -10
- package/src/cli/star-prompt.ts +71 -15
- package/src/cli/status.ts +51 -4
- package/src/cli/storage.ts +234 -0
- package/src/cli/system-command.ts +16 -0
- package/src/cli/system-restart-client.ts +146 -0
- package/src/cli/tray-proxy.ts +153 -6
- package/src/cli/usage-report.ts +184 -0
- package/src/cli/v2.ts +137 -18
- package/src/cli/version-skew.ts +46 -0
- package/src/cli.ts +1 -1
- package/src/clients/config-export.ts +1442 -23
- package/src/clients/effective-status.ts +30 -2
- package/src/clients/probes/cline.ts +81 -0
- package/src/codex/account-label.ts +35 -1
- package/src/codex/account-lifecycle.ts +130 -13
- package/src/codex/account-namespaces.ts +49 -3
- package/src/codex/account-pause.ts +2 -1
- package/src/codex/account-priority.ts +84 -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 +570 -107
- package/src/codex/app-server-restart-service.ts +232 -0
- package/src/codex/auth-api.ts +893 -246
- package/src/codex/auth-collision.ts +5 -3
- package/src/codex/auth-context.ts +348 -32
- package/src/codex/autostart-health.ts +24 -1
- package/src/codex/catalog/account-models.ts +67 -0
- package/src/codex/catalog/aggregation.ts +86 -10
- package/src/codex/catalog/bundled.ts +331 -33
- package/src/codex/catalog/effort.ts +138 -32
- package/src/codex/catalog/filesystem-evidence.ts +302 -0
- package/src/codex/catalog/kinds.ts +2 -0
- package/src/codex/catalog/metadata.ts +555 -45
- package/src/codex/catalog/native-models.ts +75 -0
- package/src/codex/catalog/parsing.ts +269 -30
- package/src/codex/catalog/provider-fetch.ts +1626 -144
- package/src/codex/catalog/sync.ts +1576 -187
- 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 +386 -0
- package/src/codex/convergence-types.ts +614 -0
- package/src/codex/convergence.ts +676 -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/desktop-app-restart.ts +355 -0
- package/src/codex/features.ts +636 -39
- package/src/codex/generation.ts +202 -0
- package/src/codex/history-job.ts +436 -0
- package/src/codex/history-lock.ts +242 -0
- package/src/codex/history-manifest.ts +112 -0
- package/src/codex/history-migration-guardian.ts +30 -24
- package/src/codex/history-provider.ts +1016 -235
- package/src/codex/history-transition.ts +105 -0
- package/src/codex/history-worker.ts +223 -0
- package/src/codex/inject-coordination.ts +373 -0
- package/src/codex/inject.ts +1114 -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 +81 -0
- package/src/codex/journal.ts +66 -4
- package/src/codex/log-guard/inspect.ts +524 -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 +360 -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 +622 -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 +675 -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 +1313 -0
- package/src/codex/prompt-lock.ts +143 -0
- package/src/codex/prompt-text-probe.ts +238 -0
- package/src/codex/quota-rejection.ts +298 -0
- package/src/codex/quota.ts +264 -21
- package/src/codex/refresh.ts +11 -2
- package/src/codex/reset-credit-recovery.ts +1044 -0
- package/src/codex/routing.ts +514 -94
- package/src/codex/runtime.ts +159 -38
- package/src/codex/shim.ts +1065 -31
- package/src/codex/subagent-model-fallback.ts +437 -43
- package/src/codex/sync.ts +191 -2
- package/src/codex/transition-state.ts +720 -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 +47 -0
- package/src/combos/index.ts +4 -0
- package/src/combos/request.ts +32 -0
- package/src/combos/types.ts +91 -9
- package/src/compatibility/index.ts +26 -0
- package/src/compatibility/manifest.ts +253 -0
- package/src/compatibility/openai-responses.ts +121 -0
- package/src/config/atomic-write.ts +219 -0
- package/src/config/paths.ts +40 -0
- package/src/config/process-state.ts +309 -0
- package/src/config/provider-name.ts +24 -0
- package/src/config/provider-validation.ts +177 -0
- package/src/config/rebase-provenance.ts +68 -0
- package/src/config.ts +1713 -709
- package/src/generated/compatibility-version.json +3324 -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 +157 -33
- package/src/images/plan.ts +24 -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-policy.ts +160 -0
- package/src/integrations/ownership.ts +155 -0
- package/src/integrations/registry.ts +166 -0
- package/src/integrations/serialize.ts +314 -0
- package/src/integrations/state.ts +433 -0
- package/src/integrations/store.ts +103 -0
- package/src/integrations/writer-lock.ts +98 -0
- package/src/integrations/writer.ts +715 -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/admin-secrets.ts +24 -0
- package/src/lib/app-owned-memory-stores.ts +22 -0
- package/src/lib/bounded-body.ts +167 -11
- 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 +26 -2
- package/src/lib/destination-policy.ts +65 -1
- package/src/lib/errors.ts +80 -5
- 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/package-tree-integrity.ts +101 -0
- package/src/lib/pinned-http.ts +145 -26
- package/src/lib/process-control.ts +6 -2
- 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/service-secrets.ts +15 -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 +253 -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 +30 -4
- package/src/oauth/chatgpt.ts +12 -1
- package/src/oauth/cline.ts +203 -0
- package/src/oauth/command-code.ts +239 -0
- package/src/oauth/cursor.ts +46 -5
- package/src/oauth/generic-account-failover.ts +231 -0
- package/src/oauth/google-antigravity.ts +35 -3
- package/src/oauth/health.ts +20 -12
- package/src/oauth/index.ts +462 -71
- package/src/oauth/key-providers.ts +25 -0
- package/src/oauth/kimi.ts +25 -3
- package/src/oauth/kiro.ts +95 -6
- package/src/oauth/local-token-detect.ts +13 -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/open-browser-choice.ts +26 -0
- package/src/oauth/store.ts +133 -26
- package/src/oauth/token-guardian.ts +9 -3
- package/src/oauth/types.ts +15 -0
- 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/auto-compact-budget.ts +65 -0
- package/src/providers/base-url-choices.ts +10 -0
- package/src/providers/codex-capacity.ts +292 -0
- package/src/providers/command-code-efforts.ts +176 -0
- package/src/providers/context-cap.ts +26 -8
- package/src/providers/cursor-pool.ts +72 -0
- package/src/providers/default-aliases.ts +65 -0
- package/src/providers/derive.ts +281 -6
- package/src/providers/fastwire.ts +507 -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 +35 -2
- package/src/providers/model-discovery-limits.ts +16 -0
- package/src/providers/model-discovery.ts +115 -22
- package/src/providers/model-presets.ts +119 -0
- package/src/providers/model-rename-migration.ts +255 -0
- package/src/providers/model-rename-startup.ts +28 -0
- package/src/providers/new-model-policy.ts +146 -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 +30 -0
- package/src/providers/quota.ts +1379 -40
- package/src/providers/registry.ts +1545 -112
- package/src/providers/request-pacing.ts +310 -0
- package/src/providers/service-tier.ts +277 -0
- package/src/providers/slug-codec.ts +94 -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 +32 -4
- package/src/reasoning-effort.ts +68 -3
- package/src/responses/apply-patch-envelope.ts +63 -0
- package/src/responses/code-mode-helper-compat.ts +50 -0
- package/src/responses/compaction.ts +26 -1
- package/src/responses/custom-tool-compat.ts +384 -0
- package/src/responses/hosted-tool-policy.ts +9 -0
- package/src/responses/namespace-tool-compat.ts +435 -0
- package/src/responses/parser.ts +225 -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 +504 -0
- package/src/responses/schema.ts +12 -2
- package/src/responses/spill-store.ts +75 -10
- package/src/responses/state.ts +659 -31
- package/src/responses/thought-signature-replay.ts +364 -0
- package/src/responses/tool-search-compat.ts +301 -0
- package/src/responses/truncated-stop-reason.ts +60 -0
- package/src/responses/turn-termination.ts +107 -0
- package/src/router.ts +405 -31
- package/src/routing/analytics.ts +379 -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 +155 -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 +289 -48
- package/src/server/background-lifecycle.ts +182 -0
- package/src/server/chat-completions.ts +154 -72
- package/src/server/chat-native-sse.ts +331 -0
- package/src/server/chat-native.ts +445 -0
- package/src/server/claude-messages.ts +160 -44
- 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 +1021 -190
- package/src/server/lifecycle.ts +336 -14
- 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 +433 -116
- package/src/server/management/api-key-usage.ts +31 -5
- package/src/server/management/body.ts +6 -0
- package/src/server/management/codex-prompt-routes.ts +570 -0
- package/src/server/management/combo-routes.ts +64 -25
- package/src/server/management/config-routes.ts +511 -51
- package/src/server/management/context.ts +89 -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 +127 -52
- package/src/server/management/model-routes.ts +461 -133
- package/src/server/management/model-rows.ts +167 -0
- package/src/server/management/native-integration-routes.ts +770 -0
- package/src/server/management/oauth-account-routes.ts +90 -8
- package/src/server/management/provider-capability-config.ts +48 -0
- package/src/server/management/provider-routes.ts +836 -159
- package/src/server/management/request-history-routes.ts +191 -0
- package/src/server/management/route-registry.ts +332 -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 +289 -33
- 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 +126 -23
- package/src/server/management-auth.ts +220 -5
- package/src/server/passive-route-linker.ts +66 -0
- package/src/server/port-reclaim.ts +1 -1
- package/src/server/ports.ts +41 -1
- package/src/server/proxy-liveness.ts +161 -10
- package/src/server/readiness.ts +99 -0
- package/src/server/relay-eager.ts +221 -54
- package/src/server/relay.ts +479 -87
- package/src/server/request-decompress.ts +113 -6
- package/src/server/request-log-conversation.ts +51 -0
- package/src/server/request-log.ts +298 -31
- 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/codex-auth-error.ts +55 -0
- package/src/server/responses/collaboration.ts +239 -36
- package/src/server/responses/combo-stream-preflight.ts +178 -0
- package/src/server/responses/compact.ts +444 -72
- package/src/server/responses/core.ts +3579 -436
- package/src/server/responses/empty-completion-guard.ts +333 -0
- package/src/server/responses/encrypted-payload.ts +62 -39
- package/src/server/responses/fetch-helpers.ts +89 -99
- package/src/server/responses/input-admission.ts +187 -0
- package/src/server/responses/pacing-overload.ts +13 -0
- package/src/server/responses/passthrough-error.ts +33 -9
- package/src/server/responses/policy-fallback.ts +178 -0
- package/src/server/responses/responses-field-backfill.ts +343 -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 +381 -0
- package/src/server/responses-custom-tool-repair.ts +363 -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 +363 -0
- package/src/server/responses-tool-search-repair.ts +267 -0
- package/src/server/responses-undeclared-tool-guard.ts +376 -0
- package/src/server/responses.ts +18 -2
- package/src/server/search.ts +78 -13
- package/src/server/sse-frame-buffer.ts +319 -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 +53 -40
- package/src/service-manager-probe.ts +892 -0
- package/src/service.ts +1153 -94
- package/src/sidecar/auth.ts +92 -0
- package/src/sidecar/candidates.ts +83 -0
- package/src/storage/cleanup.ts +2 -2
- package/src/storage/policy-job.ts +14 -4
- package/src/storage/policy.ts +88 -23
- 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 +911 -0
- package/src/types/provider.ts +614 -0
- package/src/types/request.ts +397 -0
- package/src/types/tools.ts +236 -0
- package/src/types/wire.ts +80 -0
- package/src/types.ts +107 -1237
- package/src/update/index.ts +37 -23
- package/src/update/job.ts +445 -68
- 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 +266 -0
- package/src/usage/cost.ts +0 -0
- package/src/usage/expected-prices.ts +287 -16
- package/src/usage/log.ts +666 -50
- package/src/usage/summary.ts +388 -17
- 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 +27 -16
- 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 +119 -0
- package/src/web-search/executor.ts +21 -6
- package/src/web-search/gemini-executor.ts +141 -0
- package/src/web-search/index.ts +150 -15
- package/src/web-search/loop.ts +284 -54
- 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
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
// Upstream WebSocket transport for the ChatGPT Codex backend.
|
|
2
|
+
//
|
|
3
|
+
// Why this exists: the Codex backend serves the responses_websockets path from
|
|
4
|
+
// a measurably faster queue than the plain SSE POST path. Measured 2026-08-12
|
|
5
|
+
// KST (same account, same payload, strictly sequential): gpt-5.6-luna TTFT p50
|
|
6
|
+
// ~1.0s over WS vs ~3.9s over SSE. Codex CLI itself defaults to the WS
|
|
7
|
+
// transport; opencodex previously always POSTed SSE, which is where its extra
|
|
8
|
+
// 2-3s of TTFT came from.
|
|
9
|
+
//
|
|
10
|
+
// The wrapper only swaps the transport. It dials wss:// with the same headers,
|
|
11
|
+
// sends the JSON body as a single `response.create` frame, and re-encodes the
|
|
12
|
+
// returned event frames as an SSE byte stream, so every downstream consumer
|
|
13
|
+
// (passthrough relay, adapter parsers, usage sniffing) is unchanged.
|
|
14
|
+
|
|
15
|
+
import { MAX_CLIENT_SSE_FRAME_BYTES } from "../sse-frame-buffer";
|
|
16
|
+
import { compareBunVersions } from "../../lib/bun-stream-caps";
|
|
17
|
+
|
|
18
|
+
const CODEX_RESPONSES_HTTP_URL = "https://chatgpt.com/backend-api/codex/responses";
|
|
19
|
+
const CODEX_RESPONSES_WS_URL = "wss://chatgpt.com/backend-api/codex/responses";
|
|
20
|
+
const WS_BETA = "responses_websockets=2026-02-06";
|
|
21
|
+
// If the 101 never arrives (network black hole), give SSE a chance well before
|
|
22
|
+
// the caller's connect timeout (default 200s) would fire.
|
|
23
|
+
const UPGRADE_DEADLINE_MS = 10_000;
|
|
24
|
+
// Keep the push-based WS transport inside the same memory envelope as the
|
|
25
|
+
// bounded SSE relays that consume this response. Unlike fetch response bodies,
|
|
26
|
+
// a WebSocket cannot be paused when a ReadableStream applies backpressure, so
|
|
27
|
+
// an upstream that outruns the consumer must be disconnected.
|
|
28
|
+
export const MAX_CODEX_WS_FRAME_BYTES = MAX_CLIENT_SSE_FRAME_BYTES;
|
|
29
|
+
export const MAX_CODEX_WS_QUEUE_BYTES = 8 * 1024 * 1024;
|
|
30
|
+
export const MIN_BOUNDED_CODEX_WS_BUN_VERSION = "1.4.0";
|
|
31
|
+
// The backend drops any inbound message of 16 MiB or more: it closes the socket
|
|
32
|
+
// (1009) without a Responses terminal event, which reaches clients as a bare
|
|
33
|
+
// 502 upstream_server_error. Measured against the live endpoint 2026-08-23:
|
|
34
|
+
// 16,777,000 B completed, 16,777,300 B closed in ~1s, every time. The same
|
|
35
|
+
// request body succeeds over HTTP SSE, so the ceiling belongs to this transport
|
|
36
|
+
// alone (see #2426). A full-replay thread reaches it with ~11 pasted
|
|
37
|
+
// screenshots, and then never recovers, because each retry resends the frame.
|
|
38
|
+
export const MAX_CODEX_WS_CREATE_FRAME_BYTES = 16 * 1024 * 1024;
|
|
39
|
+
// Bun frames the payload it is handed, so the send-side budget is the JSON text
|
|
40
|
+
// itself, and nothing is appended between the check and the send. The margin is
|
|
41
|
+
// a conservative cushion, not a computed requirement: it covers RFC 6455 frame
|
|
42
|
+
// overhead in case the backend counts it (14 bytes at this payload size — an
|
|
43
|
+
// 8-byte extended length plus a 4-byte client mask, leaving ~65.5 KiB spare),
|
|
44
|
+
// and it leaves room for a future caller that appends to the frame.
|
|
45
|
+
const CODEX_WS_CREATE_FRAME_MARGIN_BYTES = 64 * 1024;
|
|
46
|
+
export const CODEX_WS_CREATE_FRAME_LIMIT_BYTES =
|
|
47
|
+
MAX_CODEX_WS_CREATE_FRAME_BYTES - CODEX_WS_CREATE_FRAME_MARGIN_BYTES;
|
|
48
|
+
/** Close code the backend uses for an oversized message (RFC 6455 "message too big"). */
|
|
49
|
+
const WS_CLOSE_MESSAGE_TOO_BIG = 1009;
|
|
50
|
+
|
|
51
|
+
export type BunRuntimeIdentity = {
|
|
52
|
+
version: string;
|
|
53
|
+
versionWithSha: string;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export type BunRuntimeGateInput = string | BunRuntimeIdentity;
|
|
57
|
+
|
|
58
|
+
const codexWsUpstreamResponses = new WeakSet<Response>();
|
|
59
|
+
|
|
60
|
+
/** True only for a successful Codex WebSocket upgrade, never an HTTP fallback. */
|
|
61
|
+
export function isCodexWsUpstreamResponse(response: Response): boolean {
|
|
62
|
+
return codexWsUpstreamResponses.has(response);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function currentBunRuntimeIdentity(): BunRuntimeIdentity {
|
|
66
|
+
return {
|
|
67
|
+
version: Bun.version,
|
|
68
|
+
versionWithSha: Bun.version_with_sha,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function boundedRelayVersion(input: BunRuntimeGateInput): string | null {
|
|
73
|
+
if (typeof input === "string") return input.trim() || null;
|
|
74
|
+
const numericVersion = input.version.trim();
|
|
75
|
+
const numericMatch = /^(\d+\.\d+\.\d+)$/.exec(numericVersion);
|
|
76
|
+
const detailedMatch = /^v?(\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)\s+\([0-9a-fA-F]+\)$/.exec(
|
|
77
|
+
input.versionWithSha.trim(),
|
|
78
|
+
);
|
|
79
|
+
if (!numericMatch || !detailedMatch) return null;
|
|
80
|
+
const detailedNumeric = /^(\d+\.\d+\.\d+)/.exec(detailedMatch[1])?.[1];
|
|
81
|
+
return detailedNumeric === numericMatch[1] ? detailedMatch[1] : null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Bun 1.3.14 does not propagate a stalled HTTP response socket back to a JS
|
|
86
|
+
* ReadableStream producer on Windows. A real raw-TCP slow-client probe drained
|
|
87
|
+
* the entire upstream despite the eager relay queue; Bun 1.4.0-canary.1 stopped
|
|
88
|
+
* below one MiB. Prereleases still fail closed; release builds before 1.4.0
|
|
89
|
+
* fall back to HTTP SSE.
|
|
90
|
+
*/
|
|
91
|
+
export function bunSupportsBoundedCodexWsRelay(
|
|
92
|
+
runtime: BunRuntimeGateInput = currentBunRuntimeIdentity(),
|
|
93
|
+
): boolean {
|
|
94
|
+
const version = boundedRelayVersion(runtime);
|
|
95
|
+
if (!version) return false;
|
|
96
|
+
if (/^\d+\.\d+\.\d+-/.test(version.trim())) return false;
|
|
97
|
+
const comparison = compareBunVersions(version, MIN_BOUNDED_CODEX_WS_BUN_VERSION);
|
|
98
|
+
return comparison !== null && comparison >= 0;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function shouldUseCodexWsUpstream(
|
|
102
|
+
url: string,
|
|
103
|
+
init?: RequestInit,
|
|
104
|
+
runtime: BunRuntimeGateInput = currentBunRuntimeIdentity(),
|
|
105
|
+
): boolean {
|
|
106
|
+
if (!bunSupportsBoundedCodexWsRelay(runtime)) return false;
|
|
107
|
+
if (url !== CODEX_RESPONSES_HTTP_URL) return false;
|
|
108
|
+
if ((init?.method ?? "GET").toUpperCase() !== "POST") return false;
|
|
109
|
+
const body = init?.body;
|
|
110
|
+
if (typeof body !== "string") return false;
|
|
111
|
+
// Only root-level stream:true selects WS: JSON-mode calls keep the HTTP path
|
|
112
|
+
// because the WS path only speaks the event protocol, and a nested
|
|
113
|
+
// {"metadata":{"stream":true}} must not flip the transport. Parsing (not
|
|
114
|
+
// substring matching) also keeps whitespace-formatted bodies routable.
|
|
115
|
+
try {
|
|
116
|
+
const parsed = JSON.parse(body) as unknown;
|
|
117
|
+
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)
|
|
118
|
+
&& (parsed as Record<string, unknown>).stream === true;
|
|
119
|
+
} catch {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const CLOSED_BEFORE_TERMINAL = "codex websocket closed before a Responses terminal event";
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* The close code is the only thing that separates "the backend refused this
|
|
128
|
+
* payload" from "the network dropped", and both used to reach the caller as the
|
|
129
|
+
* same bare 502. Naming the oversized case here puts that distinction in the
|
|
130
|
+
* message the client receives.
|
|
131
|
+
*
|
|
132
|
+
* It does NOT reach the request log as a typed code. The eager relay turns any
|
|
133
|
+
* stream error into a generic `upstream_reset` synthetic terminal
|
|
134
|
+
* (`relay.ts`, `relay-eager.ts`) without feeding that frame back through the
|
|
135
|
+
* inspector, so `/api/logs` keeps neither this message nor a specific code —
|
|
136
|
+
* only `streamAborted`. Machine-readable typing would mean changing the error
|
|
137
|
+
* taxonomy, which is deliberately out of scope for this transport fix.
|
|
138
|
+
*/
|
|
139
|
+
function closedBeforeTerminalMessage(event: unknown): string {
|
|
140
|
+
const detail = event as { code?: unknown; reason?: unknown } | null | undefined;
|
|
141
|
+
const code = typeof detail?.code === "number" ? detail.code : null;
|
|
142
|
+
const reason = typeof detail?.reason === "string" ? detail.reason.trim() : "";
|
|
143
|
+
if (code === null) return CLOSED_BEFORE_TERMINAL;
|
|
144
|
+
const suffix = reason ? ` ${code} ${reason}` : ` ${code}`;
|
|
145
|
+
if (code === WS_CLOSE_MESSAGE_TOO_BIG) {
|
|
146
|
+
return `codex websocket rejected the request frame as too large (close${suffix});`
|
|
147
|
+
+ ` requests at or above ${MAX_CODEX_WS_CREATE_FRAME_BYTES} bytes must use the HTTP SSE transport`;
|
|
148
|
+
}
|
|
149
|
+
return `${CLOSED_BEFORE_TERMINAL} (close${suffix})`;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* True when the `response.create` frame is at or above the backend's inbound
|
|
154
|
+
* message ceiling, so this turn must take the HTTP SSE path instead.
|
|
155
|
+
*
|
|
156
|
+
* Sizing a 16 MiB string should not cost a 16 MiB copy. UTF-8 never encodes
|
|
157
|
+
* below one byte per UTF-16 code unit and never above three, so both tails are
|
|
158
|
+
* settled from the string length alone; only the narrow band between them pays
|
|
159
|
+
* for a real byte count, and `Buffer.byteLength` measures without allocating.
|
|
160
|
+
*/
|
|
161
|
+
export function codexWsCreateFrameExceedsLimit(
|
|
162
|
+
frameText: string,
|
|
163
|
+
limitBytes: number = CODEX_WS_CREATE_FRAME_LIMIT_BYTES,
|
|
164
|
+
): boolean {
|
|
165
|
+
if (frameText.length >= limitBytes) return true;
|
|
166
|
+
if (frameText.length * 3 < limitBytes) return false;
|
|
167
|
+
return Buffer.byteLength(frameText, "utf8") >= limitBytes;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export function codexWsUpstreamFetch(
|
|
171
|
+
url: string,
|
|
172
|
+
init: RequestInit,
|
|
173
|
+
sseFallback: typeof globalThis.fetch,
|
|
174
|
+
runtime: BunRuntimeGateInput = currentBunRuntimeIdentity(),
|
|
175
|
+
): Promise<Response> {
|
|
176
|
+
if (!bunSupportsBoundedCodexWsRelay(runtime)) {
|
|
177
|
+
return sseFallback(url, init);
|
|
178
|
+
}
|
|
179
|
+
const signal = init.signal ?? undefined;
|
|
180
|
+
if (signal?.aborted) {
|
|
181
|
+
return Promise.reject(signal.reason ?? new DOMException("The operation was aborted.", "AbortError"));
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
let frameText: string;
|
|
185
|
+
try {
|
|
186
|
+
const body = JSON.parse(init.body as string) as Record<string, unknown>;
|
|
187
|
+
// The WS create frame is implicitly streaming; the backend rejects the
|
|
188
|
+
// HTTP-only `stream` flag inside a frame.
|
|
189
|
+
delete body.stream;
|
|
190
|
+
frameText = JSON.stringify({ ...body, type: "response.create" });
|
|
191
|
+
} catch {
|
|
192
|
+
return sseFallback(url, init);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Decide before dialing. Once the socket is open the caller already holds a
|
|
196
|
+
// streaming Response, so the oversized close can only be surfaced as a stream
|
|
197
|
+
// error — and a resend at that point could double-generate. Measuring the
|
|
198
|
+
// frame we are about to send keeps the whole failure mode unreachable.
|
|
199
|
+
if (codexWsCreateFrameExceedsLimit(frameText)) {
|
|
200
|
+
return sseFallback(url, init);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const headers: Record<string, string> = {};
|
|
204
|
+
new Headers(init.headers ?? {}).forEach((value, key) => {
|
|
205
|
+
// HTTP-body framing headers do not apply to a WS handshake.
|
|
206
|
+
if (key === "content-type" || key === "content-length" || key === "accept" || key === "accept-encoding") return;
|
|
207
|
+
headers[key] = value;
|
|
208
|
+
});
|
|
209
|
+
headers["openai-beta"] = headers["openai-beta"]
|
|
210
|
+
? headers["openai-beta"].includes("responses_websockets")
|
|
211
|
+
? headers["openai-beta"]
|
|
212
|
+
: `${headers["openai-beta"]}, ${WS_BETA}`
|
|
213
|
+
: WS_BETA;
|
|
214
|
+
// A genuine caller `originator` is already in these headers via the forward
|
|
215
|
+
// set. Never fabricate one here: pool/forward traffic must not impersonate
|
|
216
|
+
// Codex CLI, per the metadata-integrity contract. (The backend's fast lane
|
|
217
|
+
// keys on WS + originator, so callers without the tag simply keep their own
|
|
218
|
+
// provenance and scheduling.)
|
|
219
|
+
|
|
220
|
+
return new Promise<Response>((resolve, reject) => {
|
|
221
|
+
let ws: WebSocket;
|
|
222
|
+
try {
|
|
223
|
+
// Bun accepts per-handshake headers; the DOM lib types only list protocol arrays.
|
|
224
|
+
ws = new WebSocket(CODEX_RESPONSES_WS_URL, { headers } as unknown as string[]);
|
|
225
|
+
} catch {
|
|
226
|
+
resolve(sseFallback(url, init));
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
let opened = false;
|
|
231
|
+
let settledPreOpen = false;
|
|
232
|
+
let terminal = false;
|
|
233
|
+
let controller: ReadableStreamDefaultController<Uint8Array> | null = null;
|
|
234
|
+
const encoder = new TextEncoder();
|
|
235
|
+
|
|
236
|
+
const failStream = (message: string) => {
|
|
237
|
+
if (terminal) return;
|
|
238
|
+
terminal = true;
|
|
239
|
+
try { controller?.error(new Error(message)); } catch { /* stream already done */ }
|
|
240
|
+
try { ws.close(); } catch { /* already closing */ }
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
const upgradeTimer = setTimeout(() => {
|
|
244
|
+
if (opened || settledPreOpen) return;
|
|
245
|
+
settledPreOpen = true;
|
|
246
|
+
try { ws.close(); } catch { /* already closing */ }
|
|
247
|
+
resolve(sseFallback(url, init));
|
|
248
|
+
}, UPGRADE_DEADLINE_MS);
|
|
249
|
+
|
|
250
|
+
const onAbort = () => {
|
|
251
|
+
if (!opened) {
|
|
252
|
+
if (settledPreOpen) return;
|
|
253
|
+
// Settle BEFORE close(): the close handler treats a pre-open close as
|
|
254
|
+
// an upgrade rejection and would dial the SSE fallback for a request
|
|
255
|
+
// the caller just cancelled.
|
|
256
|
+
settledPreOpen = true;
|
|
257
|
+
clearTimeout(upgradeTimer);
|
|
258
|
+
try { ws.close(); } catch { /* already closing */ }
|
|
259
|
+
reject(signal?.reason ?? new DOMException("The operation was aborted.", "AbortError"));
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
if (controller && !terminal) {
|
|
263
|
+
terminal = true;
|
|
264
|
+
// Mirror an aborted fetch: the body read rejects with the abort reason.
|
|
265
|
+
try { controller.error(signal?.reason ?? new DOMException("The operation was aborted.", "AbortError")); } catch { /* stream already done */ }
|
|
266
|
+
}
|
|
267
|
+
// Error the body before close(): test doubles and some runtimes dispatch
|
|
268
|
+
// close synchronously, and the caller's abort reason must stay authoritative.
|
|
269
|
+
try { ws.close(); } catch { /* already closing */ }
|
|
270
|
+
};
|
|
271
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
272
|
+
|
|
273
|
+
ws.addEventListener("open", () => {
|
|
274
|
+
if (settledPreOpen) return;
|
|
275
|
+
clearTimeout(upgradeTimer);
|
|
276
|
+
try {
|
|
277
|
+
ws.send(frameText);
|
|
278
|
+
} catch {
|
|
279
|
+
// send() throwing means the frame never left, so no upstream turn
|
|
280
|
+
// started and the SSE resend cannot double-generate. Falling back
|
|
281
|
+
// (instead of erroring a synthetic 200 body) keeps the pre-stream
|
|
282
|
+
// HTTP error/refresh/failover machinery in charge.
|
|
283
|
+
settledPreOpen = true;
|
|
284
|
+
try { ws.close(); } catch { /* already closing */ }
|
|
285
|
+
resolve(sseFallback(url, init));
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
opened = true;
|
|
289
|
+
const stream = new ReadableStream<Uint8Array>({
|
|
290
|
+
start(c) { controller = c; },
|
|
291
|
+
cancel() { try { ws.close(); } catch { /* already closing */ } },
|
|
292
|
+
}, new ByteLengthQueuingStrategy({ highWaterMark: MAX_CODEX_WS_QUEUE_BYTES }));
|
|
293
|
+
const response = new Response(stream, {
|
|
294
|
+
status: 200,
|
|
295
|
+
// The 101 response headers (x-codex-*-reset-at quota hints) are not
|
|
296
|
+
// exposed by Bun's WebSocket; the periodic quota poller covers those.
|
|
297
|
+
headers: { "content-type": "text/event-stream; charset=utf-8" },
|
|
298
|
+
});
|
|
299
|
+
codexWsUpstreamResponses.add(response);
|
|
300
|
+
resolve(response);
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
ws.addEventListener("message", (event) => {
|
|
304
|
+
if (!controller || terminal) return;
|
|
305
|
+
const text = typeof event.data === "string" ? event.data : "";
|
|
306
|
+
if (!text) return;
|
|
307
|
+
// UTF-8 byte length is always at least the JS string length. Reject this
|
|
308
|
+
// cheap lower bound before parsing so an obviously oversized frame does
|
|
309
|
+
// not create another large object graph.
|
|
310
|
+
if (text.length > MAX_CODEX_WS_FRAME_BYTES) {
|
|
311
|
+
failStream("codex websocket frame exceeds the response size limit");
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
const encodedText = encoder.encode(text);
|
|
315
|
+
if (encodedText.byteLength > MAX_CODEX_WS_FRAME_BYTES) {
|
|
316
|
+
failStream("codex websocket frame exceeds the response size limit");
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
let type: unknown;
|
|
320
|
+
try { type = (JSON.parse(text) as { type?: unknown }).type; } catch { return; }
|
|
321
|
+
if (typeof type !== "string") return;
|
|
322
|
+
// Relay only the event surface the SSE path produces today. WS-only
|
|
323
|
+
// frames (codex.rate_limits, responsesapi.websocket_timing) are dropped
|
|
324
|
+
// so downstream clients see exactly the stream shape they always got.
|
|
325
|
+
if (!type.startsWith("response.") && type !== "error") return;
|
|
326
|
+
const prefix = encoder.encode(`event: ${type}\ndata: `);
|
|
327
|
+
const suffix = encoder.encode("\n\n");
|
|
328
|
+
const frameBytes = prefix.byteLength + encodedText.byteLength + suffix.byteLength;
|
|
329
|
+
if (frameBytes > MAX_CLIENT_SSE_FRAME_BYTES) {
|
|
330
|
+
failStream("codex websocket frame exceeds the response size limit");
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
const availableBytes = controller.desiredSize ?? 0;
|
|
334
|
+
if (frameBytes > availableBytes) {
|
|
335
|
+
failStream("codex websocket response exceeded the buffered queue limit");
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
const sseFrame = new Uint8Array(frameBytes);
|
|
339
|
+
sseFrame.set(prefix);
|
|
340
|
+
sseFrame.set(encodedText, prefix.byteLength);
|
|
341
|
+
sseFrame.set(suffix, prefix.byteLength + encodedText.byteLength);
|
|
342
|
+
try {
|
|
343
|
+
controller.enqueue(sseFrame);
|
|
344
|
+
} catch {
|
|
345
|
+
failStream("codex websocket response stream closed while enqueueing");
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
if (type === "response.completed" || type === "response.failed" || type === "response.incomplete" || type === "error") {
|
|
349
|
+
terminal = true;
|
|
350
|
+
try { controller.close(); } catch { /* already closed */ }
|
|
351
|
+
try { ws.close(); } catch { /* already closing */ }
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
ws.addEventListener("close", (event: unknown) => {
|
|
356
|
+
signal?.removeEventListener("abort", onAbort);
|
|
357
|
+
if (!opened) {
|
|
358
|
+
if (settledPreOpen) return;
|
|
359
|
+
settledPreOpen = true;
|
|
360
|
+
clearTimeout(upgradeTimer);
|
|
361
|
+
// Upgrade rejected (401/403/429/5xx). Retry over plain SSE so the real
|
|
362
|
+
// HTTP status reaches the existing refresh/rotation handlers. No turn
|
|
363
|
+
// started upstream, so the resend cannot double-generate.
|
|
364
|
+
resolve(sseFallback(url, init));
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
if (controller && !terminal) {
|
|
368
|
+
terminal = true;
|
|
369
|
+
// Connection dropped before a Responses terminal event. A clean EOF
|
|
370
|
+
// here would reach clients with no response.completed/failed at all —
|
|
371
|
+
// relaySseWithFailedTail() only synthesizes a failed terminal when the
|
|
372
|
+
// body read THROWS. Error the stream like a reset TCP socket.
|
|
373
|
+
try { controller.error(new Error(closedBeforeTerminalMessage(event))); } catch { /* stream already done */ }
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
ws.addEventListener("error", () => {
|
|
378
|
+
/* Bun always follows error with close; the close handler settles. */
|
|
379
|
+
});
|
|
380
|
+
});
|
|
381
|
+
}
|