@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
|
@@ -2,6 +2,7 @@ import type { Server } from "bun";
|
|
|
2
2
|
import { bridgeToResponsesSSE, buildResponseJSON, formatErrorResponse, type ResponsesTerminalStatus } from "../../bridge";
|
|
3
3
|
import {
|
|
4
4
|
getConfigPath,
|
|
5
|
+
loadConfig,
|
|
5
6
|
multiAgentGuidanceEnabled,
|
|
6
7
|
resolveEnvValue,
|
|
7
8
|
} from "../../config";
|
|
@@ -10,6 +11,7 @@ import { buildCompactV1Output, COMPACT_PROMPT, decodeCompactionSummary, extractC
|
|
|
10
11
|
import { FORWARD_HEADERS, sanitizeReasoningInputContent } from "../../adapters/openai-responses";
|
|
11
12
|
import { expandPreviousResponseInput, previousResponseProviderState, rememberResponseState } from "../../responses/state";
|
|
12
13
|
import { routeModel } from "../../router";
|
|
14
|
+
import type { RawEntry } from "../../codex/catalog/parsing";
|
|
13
15
|
import {
|
|
14
16
|
advanceComboAfterFailure,
|
|
15
17
|
comboDefaultEffort,
|
|
@@ -26,7 +28,7 @@ import {
|
|
|
26
28
|
} from "../../combos";
|
|
27
29
|
import { isInjectionDebugEnabled } from "../../lib/debug-settings";
|
|
28
30
|
import { injectionDebugLog } from "../../lib/injection-debug-log";
|
|
29
|
-
import { modelInList, namespacedToolName } from "../../types";
|
|
31
|
+
import { modelInList, namespacedToolName, toolChoiceToolPredicate } from "../../types";
|
|
30
32
|
import type { AdapterEvent, OcxConfig, OcxParsedRequest, OcxProviderConfig, OcxProviderContinuationState, OcxUsage } from "../../types";
|
|
31
33
|
import {
|
|
32
34
|
forceRefreshOAuthAccessSnapshot,
|
|
@@ -96,23 +98,37 @@ import {
|
|
|
96
98
|
sanitizePassthroughHeaders,
|
|
97
99
|
} from "../relay";
|
|
98
100
|
import { hasResponsesItemIdRepair, relaySseWithResponsesItemIdRepair } from "../responses-item-id-repair";
|
|
99
|
-
import type { EffectiveSubagentRoster, SpawnAgentSurface } from "../../codex/catalog";
|
|
101
|
+
import type { EffectiveSubagentModel, EffectiveSubagentRoster, SpawnAgentSurface } from "../../codex/catalog";
|
|
100
102
|
import type { TranslatorBudget } from "../../lib/translator-budget";
|
|
101
103
|
|
|
102
104
|
|
|
103
105
|
export function buildToolBridgeMaps(parsed: OcxParsedRequest, budget?: TranslatorBudget): {
|
|
104
|
-
toolNsMap: Map<string, { namespace: string; name: string }>;
|
|
106
|
+
toolNsMap: Map<string, { namespace: string; name: string; freeform?: true }>;
|
|
107
|
+
declaredToolNames: Set<string>;
|
|
108
|
+
/** Declared parameter schema per request-visible tool name (#1611 integer repair). */
|
|
109
|
+
toolParameterSchemas: Map<string, Record<string, unknown>>;
|
|
105
110
|
freeformToolNames: Set<string>;
|
|
106
111
|
toolSearchToolNames: Set<string>;
|
|
107
112
|
} {
|
|
108
|
-
const toolNsMap = new Map<string, { namespace: string; name: string }>();
|
|
113
|
+
const toolNsMap = new Map<string, { namespace: string; name: string; freeform?: true }>();
|
|
114
|
+
const declaredToolNames = new Set<string>();
|
|
115
|
+
const toolParameterSchemas = new Map<string, Record<string, unknown>>();
|
|
109
116
|
const freeformToolNames = new Set<string>();
|
|
110
117
|
const toolSearchToolNames = new Set<string>();
|
|
111
|
-
|
|
118
|
+
const requestedTools = parsed.context.tools ?? [];
|
|
119
|
+
const toolAllowed = toolChoiceToolPredicate(parsed.options.toolChoice, requestedTools);
|
|
120
|
+
const authorizedTools = requestedTools.filter(toolAllowed);
|
|
121
|
+
for (const t of authorizedTools) {
|
|
122
|
+
// Upstream output is untrusted: only restore calls for tools the caller authorized.
|
|
123
|
+
const wireName = namespacedToolName(t.namespace, t.name);
|
|
124
|
+
budget?.chargeRetained(new TextEncoder().encode(wireName).byteLength, { kind: "retained_collectors" });
|
|
125
|
+
declaredToolNames.add(wireName);
|
|
126
|
+
// Retained by reference (the schema is already resident in parsed.context.tools),
|
|
127
|
+
// so this adds a map entry rather than a copy of every tool's parameters.
|
|
128
|
+
if (t.parameters && typeof t.parameters === "object") toolParameterSchemas.set(wireName, t.parameters);
|
|
112
129
|
if (t.namespace) {
|
|
113
|
-
const wireName = namespacedToolName(t.namespace, t.name);
|
|
114
130
|
budget?.chargeRetained(new TextEncoder().encode(JSON.stringify([wireName, t.namespace, t.name])).byteLength, { kind: "retained_collectors" });
|
|
115
|
-
toolNsMap.set(wireName, { namespace: t.namespace, name: t.name });
|
|
131
|
+
toolNsMap.set(wireName, { namespace: t.namespace, name: t.name, ...(t.freeform ? { freeform: true } : {}) });
|
|
116
132
|
}
|
|
117
133
|
if (t.freeform) {
|
|
118
134
|
budget?.chargeRetained(new TextEncoder().encode(t.name).byteLength, { kind: "retained_collectors" });
|
|
@@ -123,7 +139,30 @@ export function buildToolBridgeMaps(parsed: OcxParsedRequest, budget?: Translato
|
|
|
123
139
|
toolSearchToolNames.add(t.name);
|
|
124
140
|
}
|
|
125
141
|
}
|
|
126
|
-
|
|
142
|
+
// Some routed providers echo a bare tool_choice selector instead of the flattened catalog
|
|
143
|
+
// name. Accept only selectors the client actually sent and only when the full request catalog
|
|
144
|
+
// contains one tool with that logical name.
|
|
145
|
+
const choice = parsed.options.toolChoice;
|
|
146
|
+
const bareChoiceNames = new Set(
|
|
147
|
+
choice && typeof choice === "object"
|
|
148
|
+
? ("allowedTools" in choice ? choice.allowedTools : [choice.name])
|
|
149
|
+
: [],
|
|
150
|
+
);
|
|
151
|
+
const bareNameCounts = new Map<string, number>();
|
|
152
|
+
for (const t of requestedTools) {
|
|
153
|
+
bareNameCounts.set(t.name, (bareNameCounts.get(t.name) ?? 0) + 1);
|
|
154
|
+
}
|
|
155
|
+
for (const t of authorizedTools) {
|
|
156
|
+
if (!t.namespace || !bareChoiceNames.has(t.name) || bareNameCounts.get(t.name) !== 1 || declaredToolNames.has(t.name)) continue;
|
|
157
|
+
budget?.chargeRetained(new TextEncoder().encode(t.name).byteLength, { kind: "retained_collectors" });
|
|
158
|
+
declaredToolNames.add(t.name);
|
|
159
|
+
budget?.chargeRetained(new TextEncoder().encode(JSON.stringify([t.name, t.namespace, t.name])).byteLength, { kind: "retained_collectors" });
|
|
160
|
+
toolNsMap.set(t.name, { namespace: t.namespace, name: t.name, ...(t.freeform ? { freeform: true } : {}) });
|
|
161
|
+
if (t.parameters && typeof t.parameters === "object") {
|
|
162
|
+
toolParameterSchemas.set(t.name, t.parameters);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return { toolNsMap, declaredToolNames, toolParameterSchemas, freeformToolNames, toolSearchToolNames };
|
|
127
166
|
}
|
|
128
167
|
|
|
129
168
|
|
|
@@ -169,6 +208,7 @@ export function collabSurface(parsed: OcxParsedRequest): "v1" | "v2" | null {
|
|
|
169
208
|
|
|
170
209
|
export interface MultiAgentGuidanceOptions {
|
|
171
210
|
multiAgentGuidanceEnabled?: boolean;
|
|
211
|
+
codexAccountNamespace?: string;
|
|
172
212
|
injectionModel?: string;
|
|
173
213
|
injectionEffort?: string;
|
|
174
214
|
subagentModels?: string[];
|
|
@@ -183,7 +223,8 @@ export interface MultiAgentGuidanceDeps {
|
|
|
183
223
|
configuredModels: readonly string[],
|
|
184
224
|
surface: SpawnAgentSurface,
|
|
185
225
|
) => EffectiveSubagentRoster | Promise<EffectiveSubagentRoster>;
|
|
186
|
-
collectCatalogState?: () => { state: "fresh" | "stale" | "not_running" | "unknown" }
|
|
226
|
+
collectCatalogState?: () => { state: "fresh" | "stale" | "not_running" | "unknown" }
|
|
227
|
+
| Promise<{ state: "fresh" | "stale" | "not_running" | "unknown" }>;
|
|
187
228
|
}
|
|
188
229
|
|
|
189
230
|
async function defaultCollectCatalogState(): Promise<{ state: "fresh" | "stale" | "not_running" | "unknown" }> {
|
|
@@ -193,8 +234,8 @@ async function defaultCollectCatalogState(): Promise<{ state: "fresh" | "stale"
|
|
|
193
234
|
if (override === "fresh" || override === "stale" || override === "not_running" || override === "unknown") {
|
|
194
235
|
return { state: override };
|
|
195
236
|
}
|
|
196
|
-
const {
|
|
197
|
-
return
|
|
237
|
+
const { collectCodexAppServerCatalogStateForRequest } = await import("../../codex/app-server-processes");
|
|
238
|
+
return collectCodexAppServerCatalogStateForRequest();
|
|
198
239
|
}
|
|
199
240
|
|
|
200
241
|
|
|
@@ -204,7 +245,49 @@ export async function resolveEffectiveSubagentRoster(
|
|
|
204
245
|
surface: SpawnAgentSurface,
|
|
205
246
|
): Promise<EffectiveSubagentRoster> {
|
|
206
247
|
const { effectiveSubagentRoster } = await import("../../codex/catalog");
|
|
207
|
-
return effectiveSubagentRoster(configuredModels, surface);
|
|
248
|
+
return effectiveSubagentRoster(configuredModels, surface, await freshSubagentCatalogEntries());
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* The persisted Codex catalog, with native context metadata re-derived from the CURRENT config.
|
|
253
|
+
*
|
|
254
|
+
* The subagent roster reads the catalog FILE, which is only as fresh as the last sync. A row
|
|
255
|
+
* written before the operator widened the native window keeps its old `context_window`, so a
|
|
256
|
+
* child was planning and compacting against a narrower budget than its parent — measured at
|
|
257
|
+
* 272,000 x 95% = 258,400 while the request path resolved 922,000 (#2574).
|
|
258
|
+
*
|
|
259
|
+
* Re-applying the override is cheap and idempotent: it is the same function the writer uses,
|
|
260
|
+
* so a fresh catalog is unchanged and a stale one is repaired in memory rather than silently
|
|
261
|
+
* believed. It does not rewrite the file — the row on disk stays whatever the last sync wrote,
|
|
262
|
+
* and `ocx sync` remains what refreshes it.
|
|
263
|
+
*/
|
|
264
|
+
async function freshSubagentCatalogEntries(): Promise<RawEntry[]> {
|
|
265
|
+
const { readCatalog, readCodexCatalogPath, nativeContextLimits } = await import("../../codex/catalog");
|
|
266
|
+
const { applyNativeOpenAiContextOverride } = await import("../../codex/catalog/parsing");
|
|
267
|
+
const entries = readCatalog(readCodexCatalogPath())?.models ?? [];
|
|
268
|
+
if (entries.length === 0) return [];
|
|
269
|
+
let limits: ReturnType<typeof nativeContextLimits>;
|
|
270
|
+
try {
|
|
271
|
+
limits = nativeContextLimits(loadConfig());
|
|
272
|
+
} catch {
|
|
273
|
+
// An unreadable config must not cost the caller its roster; serve the file as written.
|
|
274
|
+
return entries;
|
|
275
|
+
}
|
|
276
|
+
return entries.map(entry => {
|
|
277
|
+
const clone = { ...entry };
|
|
278
|
+
applyNativeOpenAiContextOverride(clone, limits);
|
|
279
|
+
return clone;
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/** Reuse one parsed catalog snapshot across every roster projection for this request. */
|
|
284
|
+
async function createRequestScopedSubagentRosterResolver(): Promise<NonNullable<
|
|
285
|
+
MultiAgentGuidanceDeps["resolveEffectiveSubagentRoster"]
|
|
286
|
+
>> {
|
|
287
|
+
const { effectiveSubagentRoster } = await import("../../codex/catalog");
|
|
288
|
+
const catalogEntries = await freshSubagentCatalogEntries();
|
|
289
|
+
return (configuredModels, surface) =>
|
|
290
|
+
effectiveSubagentRoster(configuredModels, surface, catalogEntries);
|
|
208
291
|
}
|
|
209
292
|
|
|
210
293
|
|
|
@@ -218,10 +301,14 @@ export async function multiAgentGuidanceText(
|
|
|
218
301
|
const {
|
|
219
302
|
injectionModel,
|
|
220
303
|
injectionEffort,
|
|
304
|
+
codexAccountNamespace,
|
|
221
305
|
subagentModels,
|
|
222
306
|
subagentModelFallback,
|
|
223
307
|
injectionPrompt,
|
|
224
308
|
} = options;
|
|
309
|
+
const activeAccountNamespace = codexAccountNamespace?.length
|
|
310
|
+
? codexAccountNamespace
|
|
311
|
+
: undefined;
|
|
225
312
|
const surface = collabSurface(parsed);
|
|
226
313
|
if (surface === null) return null;
|
|
227
314
|
|
|
@@ -231,9 +318,24 @@ export async function multiAgentGuidanceText(
|
|
|
231
318
|
// Codex cannot actually spawn makes spawn_agent reject the override, so
|
|
232
319
|
// suppress positive model claims while the state is stale or unknown.
|
|
233
320
|
const catalogState = await (deps.collectCatalogState ?? defaultCollectCatalogState)();
|
|
321
|
+
// #1354 / #1395: `collectCodexAppServerCatalogState()` folds every app-server
|
|
322
|
+
// owned by the current user into ONE global observation, and the inbound
|
|
323
|
+
// request carries no sender PID or catalog fingerprint. So a stale process A
|
|
324
|
+
// makes the global state `stale` even when this request came from a fresh
|
|
325
|
+
// process B, and `unknown` can be reached by a process-enumeration failure
|
|
326
|
+
// that says nothing about any particular server.
|
|
327
|
+
//
|
|
328
|
+
// Emitting "do not set model or reasoning_effort overrides" off that global
|
|
329
|
+
// observation prohibits options the active `spawn_agent` tool legitimately
|
|
330
|
+
// advertises, for a request we cannot attribute to the stale process. The
|
|
331
|
+
// safe behaviour is to withhold OpenCodex's own disk-derived claims —
|
|
332
|
+
// preferred model, roster, fallback, custom guidance — and stay silent about
|
|
333
|
+
// overrides, leaving the active tool schema authoritative.
|
|
334
|
+
//
|
|
335
|
+
// `fresh` and `not_running` are unchanged: there we can positively describe
|
|
336
|
+
// the catalog, so the guidance below still applies.
|
|
234
337
|
if (catalogState.state === "stale" || catalogState.state === "unknown") {
|
|
235
|
-
return
|
|
236
|
-
+ "model or reasoning_effort overrides until Codex restarts.</multi_agent_mode>";
|
|
338
|
+
return null;
|
|
237
339
|
}
|
|
238
340
|
// codex-rs supplies the Proactive text on v2; the proxy only adds model-designation
|
|
239
341
|
// guidance, and only when there is something concrete to designate: a configured
|
|
@@ -242,15 +344,51 @@ export async function multiAgentGuidanceText(
|
|
|
242
344
|
...(subagentModels ?? []),
|
|
243
345
|
...(injectionModel ? [injectionModel] : []),
|
|
244
346
|
];
|
|
245
|
-
const resolveRoster = deps.resolveEffectiveSubagentRoster
|
|
347
|
+
const resolveRoster = deps.resolveEffectiveSubagentRoster
|
|
348
|
+
?? await createRequestScopedSubagentRosterResolver();
|
|
246
349
|
const effective = await resolveRoster(configuredForGuidance, "v2");
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
350
|
+
// Resolve the roster and preferred roles independently so a bare native can project onto its
|
|
351
|
+
// generated account rows without making an unrelated provider/gpt-* row look equivalent.
|
|
352
|
+
// The intersection keeps both projections inside Codex's one global five-model window.
|
|
353
|
+
const candidateModels = new Set(effective.candidates.map(candidate => candidate.model));
|
|
354
|
+
const withinCandidateWindow = (candidate: EffectiveSubagentModel): boolean =>
|
|
355
|
+
candidateModels.has(candidate.model);
|
|
356
|
+
const configuredSubagents = subagentModels ?? [];
|
|
357
|
+
const subagentEffective = configuredSubagents.length > 0
|
|
358
|
+
? injectionModel
|
|
359
|
+
? await resolveRoster(configuredSubagents, "v2")
|
|
360
|
+
: effective
|
|
361
|
+
: undefined;
|
|
362
|
+
const preferredEffective = injectionModel
|
|
363
|
+
? configuredSubagents.length > 0
|
|
364
|
+
? await resolveRoster([injectionModel], "v2")
|
|
365
|
+
: effective
|
|
366
|
+
: undefined;
|
|
367
|
+
const explicitlyConfigured = (candidate: EffectiveSubagentModel): boolean =>
|
|
368
|
+
configuredSubagents.some(model =>
|
|
369
|
+
model.includes("/") && slugsEquivalent(model, candidate.model)
|
|
370
|
+
);
|
|
371
|
+
const allowedForCurrentRoute = (candidate: EffectiveSubagentModel): boolean =>
|
|
372
|
+
explicitlyConfigured(candidate)
|
|
373
|
+
|| !candidate.model.includes("/")
|
|
374
|
+
|| (activeAccountNamespace !== undefined
|
|
375
|
+
&& candidate.model.startsWith(`${activeAccountNamespace}/`));
|
|
376
|
+
const rosterModels = (subagentEffective?.advertised ?? [])
|
|
377
|
+
.filter(withinCandidateWindow)
|
|
378
|
+
.filter(allowedForCurrentRoute);
|
|
250
379
|
const roster = subagentRosterText(rosterModels);
|
|
251
|
-
const
|
|
252
|
-
|
|
380
|
+
const preferredCandidates = (preferredEffective?.advertised ?? []).filter(withinCandidateWindow);
|
|
381
|
+
const soleBarePreferred = preferredCandidates.length === 1
|
|
382
|
+
&& !preferredCandidates[0]!.model.includes("/")
|
|
383
|
+
? preferredCandidates[0]
|
|
253
384
|
: undefined;
|
|
385
|
+
const preferred = injectionModel?.includes("/")
|
|
386
|
+
? preferredCandidates[0]
|
|
387
|
+
: activeAccountNamespace
|
|
388
|
+
? preferredCandidates.find(candidate =>
|
|
389
|
+
candidate.model.startsWith(`${activeAccountNamespace}/`)
|
|
390
|
+
) ?? soleBarePreferred
|
|
391
|
+
: soleBarePreferred;
|
|
254
392
|
|
|
255
393
|
if (isInjectionDebugEnabled() && effective.excluded.length > 0) {
|
|
256
394
|
injectionDebugLog(`[opencodex] multi-agent guidance excluded: ${effective.excluded
|
|
@@ -260,7 +398,11 @@ export async function multiAgentGuidanceText(
|
|
|
260
398
|
const fallbackGuidance = subagentFallbackGuidanceText({ subagentModelFallback } as OcxConfig);
|
|
261
399
|
if (!injectionModel && roster === "" && fallbackGuidance === "") return null;
|
|
262
400
|
if (injectionPrompt) {
|
|
263
|
-
|
|
401
|
+
// Bare ids must resolve to a unique/current-route candidate. Preserve the legacy raw
|
|
402
|
+
// fallback only for explicit routed/account-qualified ids.
|
|
403
|
+
const promptModel = preferred?.model
|
|
404
|
+
?? (injectionModel?.includes("/") ? injectionModel : undefined);
|
|
405
|
+
return `<multi_agent_mode>${applyInjectionPlaceholders(injectionPrompt, promptModel, injectionEffort, roster, fallbackGuidance)}</multi_agent_mode>`;
|
|
264
406
|
}
|
|
265
407
|
if (!preferred && roster === "" && fallbackGuidance === "") return null;
|
|
266
408
|
let text = "When the active spawn_agent tool supports optional \"model\" or \"reasoning_effort\" overrides, "
|
|
@@ -323,32 +465,93 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
|
|
323
465
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
324
466
|
}
|
|
325
467
|
|
|
326
|
-
function
|
|
327
|
-
if (!isRecord(item) || item.type !== "message" || item.role !== "developer") return
|
|
328
|
-
if (!Array.isArray(item.content) || item.content.length !== 1) return
|
|
468
|
+
function generatedDeveloperText(item: unknown): string | undefined {
|
|
469
|
+
if (!isRecord(item) || item.type !== "message" || item.role !== "developer") return undefined;
|
|
470
|
+
if (!Array.isArray(item.content) || item.content.length !== 1) return undefined;
|
|
329
471
|
const [part] = item.content;
|
|
330
|
-
return isRecord(part) && part.type === "input_text" && part.text ===
|
|
472
|
+
return isRecord(part) && part.type === "input_text" && typeof part.text === "string"
|
|
473
|
+
? part.text
|
|
474
|
+
: undefined;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
function isGeneratedDeveloperItem(item: unknown, text: string): boolean {
|
|
478
|
+
return generatedDeveloperText(item) === text;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
function isDeveloperPrefixItem(item: unknown): boolean {
|
|
482
|
+
if (!isRecord(item)) return false;
|
|
483
|
+
if (item.type === "additional_tools") return item.role === "developer";
|
|
484
|
+
const type = item.type ?? (typeof item.role === "string" ? "message" : undefined);
|
|
485
|
+
return type === "message" && (item.role === "system" || item.role === "developer");
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
function leadingDeveloperPrefixLength(items: readonly unknown[]): number {
|
|
489
|
+
let index = 0;
|
|
490
|
+
while (index < items.length && isDeveloperPrefixItem(items[index])) index += 1;
|
|
491
|
+
return index;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
function isConversationalItem(item: unknown): boolean {
|
|
495
|
+
if (!isRecord(item)) return false;
|
|
496
|
+
if (item.type === "agent_message") return true;
|
|
497
|
+
const type = item.type ?? (typeof item.role === "string" ? "message" : undefined);
|
|
498
|
+
return type === "message" && (item.role === "user" || item.role === "assistant");
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
function statefulRawInsertionIndex(items: readonly unknown[], replayPrefixLen: number): number {
|
|
502
|
+
for (let index = replayPrefixLen; index < items.length; index += 1) {
|
|
503
|
+
if (isConversationalItem(items[index])) return index;
|
|
504
|
+
}
|
|
505
|
+
const last = items[items.length - 1];
|
|
506
|
+
return isRecord(last) && last.type === "compaction_trigger"
|
|
507
|
+
? items.length - 1
|
|
508
|
+
: items.length;
|
|
331
509
|
}
|
|
332
510
|
|
|
333
511
|
export function injectDeveloperMessage(parsed: OcxParsedRequest, text: string): void {
|
|
334
512
|
const raw = parsed._rawBody as { input?: unknown } | undefined;
|
|
513
|
+
const rawInput = raw && Array.isArray(raw.input) ? raw.input : undefined;
|
|
514
|
+
const replayPrefixLen = rawInput
|
|
515
|
+
? Math.min(parsed._replayPrefixLen ?? 0, rawInput.length)
|
|
516
|
+
: 0;
|
|
335
517
|
const devItem = { type: "message", role: "developer", content: [{ type: "input_text", text }] };
|
|
336
|
-
if (
|
|
337
|
-
const
|
|
338
|
-
|
|
518
|
+
if (rawInput) {
|
|
519
|
+
const replayPrefix = rawInput.slice(0, replayPrefixLen);
|
|
520
|
+
const taggedGuidance = text.startsWith("<multi_agent_mode>") && text.endsWith("</multi_agent_mode>");
|
|
521
|
+
const lastTaggedGuidance = taggedGuidance
|
|
522
|
+
? replayPrefix.map(generatedDeveloperText)
|
|
523
|
+
.filter(item => item?.startsWith("<multi_agent_mode>") && item.endsWith("</multi_agent_mode>"))
|
|
524
|
+
.at(-1)
|
|
525
|
+
: undefined;
|
|
526
|
+
if (taggedGuidance ? lastTaggedGuidance === text : replayPrefix.some(item => isGeneratedDeveloperItem(item, text))) {
|
|
339
527
|
return;
|
|
340
528
|
}
|
|
341
529
|
}
|
|
342
530
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
531
|
+
const statefulContinuation = parsed.previousResponseId !== undefined;
|
|
532
|
+
const message = { role: "developer" as const, content: text, timestamp: Date.now() };
|
|
533
|
+
const statefulRawIndex = statefulContinuation && rawInput
|
|
534
|
+
? statefulRawInsertionIndex(rawInput, replayPrefixLen)
|
|
535
|
+
: undefined;
|
|
536
|
+
|
|
537
|
+
// A previous_response_id delta can begin with tool/protocol items. Keep those first, then place
|
|
538
|
+
// changed guidance before the current conversation. Stateless requests keep guidance in the prefix.
|
|
539
|
+
if (statefulContinuation) {
|
|
540
|
+
const index = Math.min(
|
|
541
|
+
parsed._continuationConversationMessageIndex ?? parsed.context.messages.length,
|
|
542
|
+
parsed.context.messages.length,
|
|
543
|
+
);
|
|
544
|
+
parsed.context.messages.splice(index, 0, message);
|
|
545
|
+
} else {
|
|
546
|
+
const prefixLen = parsed.context.messages.findIndex(item => item.role !== "developer");
|
|
547
|
+
parsed.context.messages.splice(prefixLen < 0 ? parsed.context.messages.length : prefixLen, 0, message);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
if (rawInput) {
|
|
551
|
+
if (statefulContinuation) {
|
|
552
|
+
rawInput.splice(statefulRawIndex!, 0, devItem);
|
|
350
553
|
} else {
|
|
351
|
-
|
|
554
|
+
rawInput.splice(leadingDeveloperPrefixLength(rawInput), 0, devItem);
|
|
352
555
|
}
|
|
353
556
|
}
|
|
354
557
|
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import type { ResponsesTerminalStatus } from "../../bridge";
|
|
2
|
+
import type { RequestLogContext } from "../request-log";
|
|
3
|
+
import { createSseInspector } from "../relay";
|
|
4
|
+
import { MAX_CLIENT_SSE_FRAME_BYTES } from "../sse-frame-buffer";
|
|
5
|
+
|
|
6
|
+
const COMBO_STREAM_PREFLIGHT_MAX_BYTES = MAX_CLIENT_SSE_FRAME_BYTES;
|
|
7
|
+
// Keep retained object count proportional to the same byte budget used by the
|
|
8
|
+
// shared SSE framer. Tiny or empty upstream reads must not bypass the byte cap.
|
|
9
|
+
const COMBO_STREAM_PREFLIGHT_MAX_CHUNKS = Math.max(
|
|
10
|
+
1,
|
|
11
|
+
Math.ceil(COMBO_STREAM_PREFLIGHT_MAX_BYTES / 1024),
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
const PRE_OUTPUT_CONTROL_EVENTS = new Set([
|
|
15
|
+
"response.created",
|
|
16
|
+
"response.in_progress",
|
|
17
|
+
"response.queued",
|
|
18
|
+
"response.heartbeat",
|
|
19
|
+
]);
|
|
20
|
+
|
|
21
|
+
const TERMINAL_EVENTS = new Set([
|
|
22
|
+
"response.completed",
|
|
23
|
+
"response.failed",
|
|
24
|
+
"response.incomplete",
|
|
25
|
+
]);
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Decide when replaying the request on another combo target would risk duplicating
|
|
29
|
+
* client-visible output or a tool-side effect. Unknown event types commit the child
|
|
30
|
+
* conservatively; only the small Responses lifecycle preamble remains replayable.
|
|
31
|
+
*/
|
|
32
|
+
export function comboStreamPayloadCommitsOutput(payload: unknown): boolean {
|
|
33
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) return true;
|
|
34
|
+
const type = (payload as { type?: unknown }).type;
|
|
35
|
+
if (typeof type !== "string") return true;
|
|
36
|
+
return !PRE_OUTPUT_CONTROL_EVENTS.has(type) && !TERMINAL_EVENTS.has(type);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function replayBufferedResponse(
|
|
40
|
+
response: Response,
|
|
41
|
+
reader: ReadableStreamDefaultReader<Uint8Array>,
|
|
42
|
+
buffered: Uint8Array[],
|
|
43
|
+
): Response {
|
|
44
|
+
let index = 0;
|
|
45
|
+
const body = new ReadableStream<Uint8Array>({
|
|
46
|
+
async pull(controller) {
|
|
47
|
+
if (index < buffered.length) {
|
|
48
|
+
controller.enqueue(buffered[index++]!);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
const next = await reader.read();
|
|
53
|
+
if (next.done) controller.close();
|
|
54
|
+
else controller.enqueue(next.value);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
try { controller.error(error); } catch { /* consumer already closed */ }
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
cancel(reason) {
|
|
60
|
+
reader.cancel(reason).catch(() => undefined);
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
return new Response(body, {
|
|
64
|
+
status: response.status,
|
|
65
|
+
statusText: response.statusText,
|
|
66
|
+
headers: response.headers,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function failedTerminalResponse(
|
|
71
|
+
response: Response,
|
|
72
|
+
terminalPayload: Record<string, unknown>,
|
|
73
|
+
logCtx: RequestLogContext,
|
|
74
|
+
): Response {
|
|
75
|
+
const nested = terminalPayload.response;
|
|
76
|
+
const terminalResponse = nested && typeof nested === "object" && !Array.isArray(nested)
|
|
77
|
+
? nested as Record<string, unknown>
|
|
78
|
+
: {};
|
|
79
|
+
const nestedError = terminalResponse.error;
|
|
80
|
+
const error = nestedError && typeof nestedError === "object" && !Array.isArray(nestedError)
|
|
81
|
+
? nestedError as Record<string, unknown>
|
|
82
|
+
: {
|
|
83
|
+
type: "upstream_error",
|
|
84
|
+
code: "upstream_server_error",
|
|
85
|
+
message: logCtx.upstreamError ?? "Provider stream failed before producing output",
|
|
86
|
+
};
|
|
87
|
+
const headers = new Headers(response.headers);
|
|
88
|
+
headers.set("content-type", "application/json");
|
|
89
|
+
headers.delete("content-length");
|
|
90
|
+
headers.delete("content-encoding");
|
|
91
|
+
const usage = terminalResponse.usage;
|
|
92
|
+
return new Response(JSON.stringify({
|
|
93
|
+
error,
|
|
94
|
+
// The combo classifier needs only the error and optional usage. Do not carry
|
|
95
|
+
// response ids, provider metadata, or future terminal fields into the client
|
|
96
|
+
// error envelope merely because they shared the terminal snapshot.
|
|
97
|
+
response: {
|
|
98
|
+
error,
|
|
99
|
+
...(usage && typeof usage === "object" && !Array.isArray(usage) ? { usage } : {}),
|
|
100
|
+
},
|
|
101
|
+
}), {
|
|
102
|
+
status: logCtx.terminalHttpStatus ?? 502,
|
|
103
|
+
headers,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export type ComboStreamPreflightResult =
|
|
108
|
+
| { kind: "accepted"; response: Response }
|
|
109
|
+
| { kind: "failed"; response: Response };
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Buffer a combo child's downstream SSE only until the request becomes unsafe to
|
|
113
|
+
* replay or reaches a terminal. This owns exactly one body reader. The aggregate
|
|
114
|
+
* buffer is capped by bytes and retained chunks; hitting either cap commits the
|
|
115
|
+
* current target instead of growing memory or guessing that replay is safe.
|
|
116
|
+
*/
|
|
117
|
+
export async function preflightComboStreamResponse(
|
|
118
|
+
response: Response,
|
|
119
|
+
logCtx: RequestLogContext,
|
|
120
|
+
): Promise<ComboStreamPreflightResult> {
|
|
121
|
+
const contentType = response.headers.get("content-type")?.toLowerCase() ?? "";
|
|
122
|
+
if (!response.ok || !response.body || !contentType.includes("text/event-stream")) {
|
|
123
|
+
return { kind: "accepted", response };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const reader = response.body.getReader();
|
|
127
|
+
const buffered: Uint8Array[] = [];
|
|
128
|
+
let bufferedBytes = 0;
|
|
129
|
+
let outputCommitted = false;
|
|
130
|
+
let terminalStatus: ResponsesTerminalStatus | undefined;
|
|
131
|
+
let failedPayload: Record<string, unknown> | undefined;
|
|
132
|
+
const inspector = createSseInspector({
|
|
133
|
+
logCtx,
|
|
134
|
+
onParsedPayload: payload => {
|
|
135
|
+
if (comboStreamPayloadCommitsOutput(payload)) outputCommitted = true;
|
|
136
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload)) return;
|
|
137
|
+
if ((payload as { type?: unknown }).type === "response.failed") {
|
|
138
|
+
failedPayload = payload as Record<string, unknown>;
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
onTerminal: status => { terminalStatus = status; },
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
try {
|
|
145
|
+
for (;;) {
|
|
146
|
+
const next = await reader.read();
|
|
147
|
+
if (next.done) {
|
|
148
|
+
inspector.finish();
|
|
149
|
+
} else {
|
|
150
|
+
if (bufferedBytes + next.value.byteLength > COMBO_STREAM_PREFLIGHT_MAX_BYTES) {
|
|
151
|
+
// Keep the cap about memory the preflight allocates. The upstream chunk already exists;
|
|
152
|
+
// copying it before committing would transiently exceed the boundary for no
|
|
153
|
+
// replay benefit. Preserve it unsliced behind the already-bounded prefix.
|
|
154
|
+
return {
|
|
155
|
+
kind: "accepted",
|
|
156
|
+
response: replayBufferedResponse(response, reader, [...buffered, next.value]),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
const retained = next.value.slice();
|
|
160
|
+
buffered.push(retained);
|
|
161
|
+
bufferedBytes += retained.byteLength;
|
|
162
|
+
inspector.feed(retained);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (terminalStatus === "failed" && !outputCommitted && failedPayload) {
|
|
166
|
+
await reader.cancel("retrying zero-output combo stream failure").catch(() => undefined);
|
|
167
|
+
return { kind: "failed", response: failedTerminalResponse(response, failedPayload, logCtx) };
|
|
168
|
+
}
|
|
169
|
+
if (next.done || terminalStatus !== undefined || outputCommitted
|
|
170
|
+
|| bufferedBytes >= COMBO_STREAM_PREFLIGHT_MAX_BYTES
|
|
171
|
+
|| buffered.length >= COMBO_STREAM_PREFLIGHT_MAX_CHUNKS) {
|
|
172
|
+
return { kind: "accepted", response: replayBufferedResponse(response, reader, buffered) };
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
} finally {
|
|
176
|
+
inspector.dispose();
|
|
177
|
+
}
|
|
178
|
+
}
|