@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
package/src/web-search/loop.ts
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
import type { AdapterRequest, IncomingMeta, ProviderAdapter } from "../adapters/base";
|
|
2
|
-
import type { AdapterEvent, OcxMessage, OcxParsedRequest, OcxProviderConfig, OcxThinkingContent, OcxUsage } from "../types";
|
|
3
|
-
import { namespacedToolName } from "../types";
|
|
2
|
+
import type { AdapterEvent, OcxMessage, OcxParsedRequest, OcxProviderConfig, OcxProviderOpaqueToolCallMetadata, OcxThinkingContent, OcxUsage, RateLimitRetryPolicy } from "../types";
|
|
3
|
+
import { namespacedToolName, toolChoiceToolPredicate } from "../types";
|
|
4
|
+
import { cloneProviderOpaqueToolCallMetadata } from "../responses/provider-opaque-metadata";
|
|
5
|
+
import type { AttemptRecoveryKind } from "../usage/log";
|
|
4
6
|
import { bridgeToResponsesSSE } from "../bridge";
|
|
5
7
|
import { runWebSearch, type SidecarOutcome, type SidecarOutcomeRecorder, type SidecarSettings } from "./executor";
|
|
6
8
|
import { runAnthropicWebSearch } from "./anthropic-executor";
|
|
9
|
+
import { runXaiWebSearch, type XaiSearchOptions } from "./xai-executor";
|
|
10
|
+
import { runGeminiWebSearch } from "./gemini-executor";
|
|
11
|
+
import { runExaWebSearch } from "./exa-executor";
|
|
12
|
+
import type { WebSearchBackendId } from "./index";
|
|
7
13
|
import { clearableDeadline } from "../lib/abort";
|
|
8
14
|
import { redactSecretString } from "../lib/redact";
|
|
9
15
|
import { readBoundedResponseBody } from "../lib/bounded-body";
|
|
10
|
-
import { fetchWithResetRetry } from "../lib/upstream-retry";
|
|
16
|
+
import { fetchWithResetRetry, prepareSameTarget429Wait } from "../lib/upstream-retry";
|
|
17
|
+
import { rateLimitRetryDelayMs } from "../providers/key-failover";
|
|
11
18
|
import {
|
|
12
19
|
isTranslatorBudgetExceededError,
|
|
13
20
|
TRANSLATOR_MAX_TURN_BYTES,
|
|
@@ -30,6 +37,11 @@ interface WebSearchCall {
|
|
|
30
37
|
// empty array means the model called the tool with neither `query` nor `queries` (handled as an
|
|
31
38
|
// empty-query placeholder).
|
|
32
39
|
queries: string[];
|
|
40
|
+
/**
|
|
41
|
+
* Provider-opaque metadata from the originating part (issue #1735). Stored PER CALL so a
|
|
42
|
+
* signature can never migrate to a different call when the model batches several.
|
|
43
|
+
*/
|
|
44
|
+
providerMetadata?: OcxProviderOpaqueToolCallMetadata;
|
|
33
45
|
}
|
|
34
46
|
|
|
35
47
|
/**
|
|
@@ -61,40 +73,68 @@ export function scanEventsForWebSearch(events: AdapterEvent[]): {
|
|
|
61
73
|
calls: WebSearchCall[];
|
|
62
74
|
passthrough: AdapterEvent[];
|
|
63
75
|
hasRealToolCall: boolean;
|
|
76
|
+
hasMalformedToolCall: boolean;
|
|
64
77
|
} {
|
|
65
78
|
const calls: WebSearchCall[] = [];
|
|
66
79
|
const passthrough: AdapterEvent[] = [];
|
|
67
80
|
let hasRealToolCall = false;
|
|
68
|
-
let
|
|
81
|
+
let hasMalformedToolCall = false;
|
|
82
|
+
let pending: { name: string; id: string; argsBuf: string; closed: boolean; events: AdapterEvent[]; providerMetadata?: OcxProviderOpaqueToolCallMetadata } | null = null;
|
|
83
|
+
const isBlank = (value: string): boolean => value.trim().length === 0;
|
|
69
84
|
const flushPending = (): void => {
|
|
85
|
+
// A pending call that never saw tool_call_end is structurally malformed.
|
|
86
|
+
if (pending && !pending.closed) hasMalformedToolCall = true;
|
|
70
87
|
if (pending && pending.name !== WEB_SEARCH_TOOL_NAME) {
|
|
71
88
|
passthrough.push(...pending.events);
|
|
72
|
-
hasRealToolCall = true;
|
|
89
|
+
if (pending.closed && !isBlank(pending.id) && !isBlank(pending.name)) hasRealToolCall = true;
|
|
73
90
|
}
|
|
74
91
|
pending = null;
|
|
75
92
|
};
|
|
76
93
|
for (const e of events) {
|
|
77
94
|
if (e.type === "tool_call_start") {
|
|
78
95
|
flushPending();
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
96
|
+
if (isBlank(e.id) || isBlank(e.name)) hasMalformedToolCall = true;
|
|
97
|
+
pending = { name: e.name, id: e.id, argsBuf: "", closed: false, events: [e], providerMetadata: e.providerMetadata };
|
|
98
|
+
} else if (e.type === "tool_call_delta") {
|
|
99
|
+
// Orphan delta (no open call) is malformed.
|
|
100
|
+
if (!pending) hasMalformedToolCall = true;
|
|
101
|
+
else {
|
|
102
|
+
pending.argsBuf += e.arguments;
|
|
103
|
+
pending.events.push(e);
|
|
104
|
+
}
|
|
105
|
+
} else if (e.type === "tool_call_end") {
|
|
106
|
+
// Orphan end (no open call) is malformed.
|
|
107
|
+
if (!pending) {
|
|
108
|
+
hasMalformedToolCall = true;
|
|
87
109
|
} else {
|
|
88
|
-
|
|
89
|
-
|
|
110
|
+
pending.events.push(e);
|
|
111
|
+
pending.closed = true;
|
|
112
|
+
if (pending.name === WEB_SEARCH_TOOL_NAME) {
|
|
113
|
+
calls.push({ id: pending.id, queries: parseQueries(pending.argsBuf), providerMetadata: pending.providerMetadata });
|
|
114
|
+
} else {
|
|
115
|
+
passthrough.push(...pending.events);
|
|
116
|
+
if (!isBlank(pending.id) && !isBlank(pending.name)) hasRealToolCall = true;
|
|
117
|
+
}
|
|
118
|
+
pending = null;
|
|
90
119
|
}
|
|
91
|
-
pending = null;
|
|
92
120
|
} else {
|
|
93
121
|
passthrough.push(e);
|
|
94
122
|
}
|
|
95
123
|
}
|
|
96
124
|
flushPending();
|
|
97
|
-
return { calls, passthrough, hasRealToolCall };
|
|
125
|
+
return { calls, passthrough, hasRealToolCall, hasMalformedToolCall };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Visible final-answer text: a non-whitespace text_delta that is NOT commentary
|
|
130
|
+
* (#1001). Commentary streams early for progress and must not satisfy the
|
|
131
|
+
* forced-answer output check; thinking alone never counts either.
|
|
132
|
+
*/
|
|
133
|
+
export function hasVisibleAssistantText(events: AdapterEvent[]): boolean {
|
|
134
|
+
return events.some(event =>
|
|
135
|
+
event.type === "text_delta"
|
|
136
|
+
&& event.phase !== "commentary"
|
|
137
|
+
&& event.text.trim().length > 0);
|
|
98
138
|
}
|
|
99
139
|
|
|
100
140
|
async function* replay(events: AdapterEvent[]): AsyncGenerator<AdapterEvent> {
|
|
@@ -206,16 +246,32 @@ class LoopError extends Error {
|
|
|
206
246
|
}
|
|
207
247
|
}
|
|
208
248
|
|
|
249
|
+
/**
|
|
250
|
+
* Dependencies for one web-search loop iteration: parsed request, active adapter,
|
|
251
|
+
* incoming metadata, and the configured search executor.
|
|
252
|
+
*/
|
|
209
253
|
export interface WebSearchLoopDeps {
|
|
210
254
|
parsed: OcxParsedRequest;
|
|
211
255
|
adapter: ProviderAdapter;
|
|
212
256
|
incomingMeta: IncomingMeta;
|
|
213
|
-
/**
|
|
214
|
-
|
|
257
|
+
/**
|
|
258
|
+
* Which executor runs searches. Defaults to "openai" so existing callers keep the ChatGPT path
|
|
259
|
+
* (audit F4). The widened ids (xai/gemini/exa) cannot reach the loop yet: planWebSearch returns
|
|
260
|
+
* no plan for them (inert 060 arms), and the dispatch below only branches on "anthropic".
|
|
261
|
+
*/
|
|
262
|
+
backend?: WebSearchBackendId;
|
|
215
263
|
/** Required for the openai backend; unused (and typically undefined) for the anthropic backend. */
|
|
216
264
|
forwardProvider?: OcxProviderConfig;
|
|
217
265
|
/** Required for the anthropic backend: the stored-OAuth provider that runs web_search_20250305. */
|
|
218
266
|
anthropicSidecar?: { providerName: string; provider: OcxProviderConfig };
|
|
267
|
+
/** Required for the xai backend: the stored Grok OAuth provider (L7). */
|
|
268
|
+
xaiSidecar?: { providerName: string; provider: OcxProviderConfig };
|
|
269
|
+
/** Required for the gemini backend: the stored Antigravity CCA provider (L8). */
|
|
270
|
+
geminiSidecar?: { providerName: string; provider: OcxProviderConfig };
|
|
271
|
+
/** Required for the exa backend: the operator key, read from config at plan unpack (L9). */
|
|
272
|
+
exaApiKey?: string;
|
|
273
|
+
/** Opt-in x_search options for the xai backend. */
|
|
274
|
+
xaiSearchOptions?: XaiSearchOptions;
|
|
219
275
|
hostedTool: Record<string, unknown>;
|
|
220
276
|
selectedForwardHeaders: Headers;
|
|
221
277
|
settings: SidecarSettings;
|
|
@@ -233,17 +289,30 @@ export interface WebSearchLoopDeps {
|
|
|
233
289
|
* sidecar search, so a legitimately slow-but-progressing unit never trips the bridge watchdog.
|
|
234
290
|
*/
|
|
235
291
|
stallTimeoutSec?: number;
|
|
292
|
+
/**
|
|
293
|
+
* Opt-in: stream the routed model's leading text/thinking deltas live instead of holding the whole
|
|
294
|
+
* iteration back. The live window closes at the first buffer-only event (tool calls above all) so
|
|
295
|
+
* the web_search interception decision stays atomic; everything after replays in order at the end.
|
|
296
|
+
*/
|
|
297
|
+
streamRoutedModelOutput?: boolean;
|
|
236
298
|
/** One-shot TTFT callback: first non-empty model output observed (WP4). */
|
|
237
299
|
onFirstOutput?: () => void;
|
|
238
300
|
/** Raw adapter usage at the terminal event, pre wire-normalization (see bridgeToResponsesSSE onUsage). */
|
|
239
301
|
onUsage?: (usage: OcxUsage | undefined) => void;
|
|
240
302
|
/** Observe the exact adapter request selected for each routed-model iteration. */
|
|
241
303
|
onRequestBuilt?: (request: AdapterRequest) => void;
|
|
304
|
+
/** Called before each routed-model dispatch in the loop, for attempt telemetry. Same-target 429 replays pass the `rate-limit-429` recovery kind. */
|
|
305
|
+
onAttemptSend?: (recovery?: AttemptRecoveryKind) => void;
|
|
242
306
|
/**
|
|
243
|
-
* 429
|
|
244
|
-
* or null when the pool is exhausted
|
|
307
|
+
* 429 failover hook: rotate the provider's active credential and return a rebuilt adapter,
|
|
308
|
+
* or null when the pool is exhausted. Async hooks support OAuth refresh; existing synchronous
|
|
309
|
+
* key-pool hooks remain valid.
|
|
245
310
|
*/
|
|
246
|
-
on429?: (retryAfterHeader: string | null) => ProviderAdapter | null
|
|
311
|
+
on429?: (retryAfterHeader: string | null) => ProviderAdapter | null | Promise<ProviderAdapter | null>;
|
|
312
|
+
/** Opt-in same-target 429 policy (key-auth providers). When present, 429 replays on the SAME key before on429 rotation. */
|
|
313
|
+
retryOn429Policy?: Required<RateLimitRetryPolicy> | null;
|
|
314
|
+
/** Called only when the final bridged Responses stream reaches completed or incomplete. */
|
|
315
|
+
onCompletedResponse?: (response: Record<string, unknown>) => void;
|
|
247
316
|
}
|
|
248
317
|
|
|
249
318
|
/**
|
|
@@ -260,6 +329,12 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
260
329
|
// Mutable: 429 key-failover (deps.on429) can swap in a rebuilt adapter mid-loop.
|
|
261
330
|
let adapter = deps.adapter;
|
|
262
331
|
|
|
332
|
+
// Bridge stall budget (seconds of silence before upstream_stall_timeout); the retry backoff
|
|
333
|
+
// heartbeat interval is derived from it so the watchdog is always fed during deliberate waits.
|
|
334
|
+
const stallTimeoutMs = typeof deps.stallTimeoutSec === "number" && Number.isFinite(deps.stallTimeoutSec) && deps.stallTimeoutSec > 0
|
|
335
|
+
? Math.floor(deps.stallTimeoutSec * 1000)
|
|
336
|
+
: 300_000;
|
|
337
|
+
|
|
263
338
|
const messages: OcxMessage[] = [...parsed.context.messages];
|
|
264
339
|
const loopT0 = Date.now();
|
|
265
340
|
const allTools = parsed.context.tools ?? [];
|
|
@@ -292,11 +367,29 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
292
367
|
response: Response;
|
|
293
368
|
responseAdapter: ProviderAdapter;
|
|
294
369
|
}
|
|
295
|
-
type IterationSplit = ReturnType<typeof scanEventsForWebSearch
|
|
370
|
+
type IterationSplit = ReturnType<typeof scanEventsForWebSearch> & {
|
|
371
|
+
/**
|
|
372
|
+
* How many leading passthrough events were already delivered live this iteration. They are
|
|
373
|
+
* exactly the first N passthrough entries (live delivery stops before the first event that
|
|
374
|
+
* scanEventsForWebSearch could group or reorder), so the terminal replay skips them by count.
|
|
375
|
+
*/
|
|
376
|
+
streamedPassthroughCount: number;
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
// Same-target 429 budget is per REQUEST, not per model iteration: later search rounds inherit
|
|
380
|
+
// what earlier rounds left of `attempts`, so a bounded multi-round turn can never exceed the
|
|
381
|
+
// configured replay count in total (a per-round reset would multiply it by maxSearches).
|
|
382
|
+
const rateLimitRetryPolicy = deps.retryOn429Policy ?? null;
|
|
383
|
+
let rateLimitRetries = 0;
|
|
296
384
|
|
|
297
385
|
// Acquire one iteration's final response headers. The first call is drained eagerly so an initial
|
|
298
386
|
// connect/header/HTTP failure stays a non-2xx JSON response. Its successful BODY is deliberately
|
|
299
387
|
// left unread until the downstream Responses SSE bridge exists.
|
|
388
|
+
/**
|
|
389
|
+
* Fetch one web-search iteration's final response headers, applying the response-header
|
|
390
|
+
* deadline and the same-target 429 retry policy (with awaited body release and deadline
|
|
391
|
+
* restart) before the `on429` key rotation.
|
|
392
|
+
*/
|
|
300
393
|
const prepareIterationEvents = async function* (forceAnswer: boolean): AsyncGenerator<AdapterEvent, IterationResponse> {
|
|
301
394
|
// On the forced-answer pass the synthetic web_search tool is gone, so the model MUST answer
|
|
302
395
|
// from the results already in `messages`. A weak model can still produce a thin answer that
|
|
@@ -313,30 +406,55 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
313
406
|
// One cumulative header deadline spans every pool-key 429 rotation in this model iteration.
|
|
314
407
|
// clear() stops only its timer after final headers; the direct turn signal remains attached to
|
|
315
408
|
// the returned response body through AbortSignal.any().
|
|
316
|
-
|
|
409
|
+
let headerDeadline = clearableDeadline(connectTimeoutMs, signal);
|
|
317
410
|
try {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
411
|
+
/**
|
|
412
|
+
* Build and fetch one web-search iteration on the given adapter, under the iteration
|
|
413
|
+
* header deadline. The caller owns same-target 429 replays and key rotation around it.
|
|
414
|
+
* The outbound request is cached per adapter so a same-target replay reuses the EXACT
|
|
415
|
+
* URL, serialized body, and headers (builder runs once per target sequence).
|
|
416
|
+
*/
|
|
417
|
+
let cachedRequest: AdapterRequest | undefined;
|
|
418
|
+
let cachedAdapter: ProviderAdapter | undefined;
|
|
419
|
+
/**
|
|
420
|
+
* Build and fetch one web-search iteration on the given adapter, under the iteration
|
|
421
|
+
* header deadline. The caller owns same-target 429 replays and key rotation around it.
|
|
422
|
+
*/
|
|
423
|
+
const fetchOnce = async (requestAdapter: ProviderAdapter, recovery?: AttemptRecoveryKind): Promise<IterationResponse> => {
|
|
424
|
+
let request: AdapterRequest;
|
|
425
|
+
if (cachedRequest !== undefined && cachedAdapter === requestAdapter) {
|
|
426
|
+
request = cachedRequest;
|
|
427
|
+
} else {
|
|
428
|
+
request = await requestAdapter.buildRequest(iterParsed, {
|
|
429
|
+
headers: selectedForwardHeaders,
|
|
430
|
+
abortSignal: headerDeadline.signal,
|
|
431
|
+
translatorBudget,
|
|
432
|
+
});
|
|
433
|
+
try {
|
|
434
|
+
deps.onRequestBuilt?.(request);
|
|
435
|
+
} catch {
|
|
436
|
+
// Diagnostics are best-effort and must never abort a web-search iteration.
|
|
437
|
+
}
|
|
438
|
+
cachedRequest = request;
|
|
439
|
+
cachedAdapter = requestAdapter;
|
|
328
440
|
}
|
|
329
441
|
let response: Response;
|
|
330
442
|
try {
|
|
331
|
-
|
|
332
|
-
|
|
443
|
+
if (requestAdapter.fetchResponse) {
|
|
444
|
+
deps.onAttemptSend?.(recovery);
|
|
445
|
+
response = await requestAdapter.fetchResponse(request, {
|
|
333
446
|
abortSignal: headerDeadline.signal,
|
|
334
447
|
timeoutMs: connectTimeoutMs,
|
|
335
448
|
returnRawErrors: true,
|
|
336
449
|
stream: true,
|
|
337
|
-
})
|
|
338
|
-
|
|
339
|
-
|
|
450
|
+
});
|
|
451
|
+
} else {
|
|
452
|
+
response = await fetchWithResetRetry(
|
|
453
|
+
(retryRecovery) => {
|
|
454
|
+
// Record every helper-driven send (the callback runs for the first attempt and
|
|
455
|
+
// each connection-reset replay); preserve the caller's recovery kind
|
|
456
|
+
// (rate-limit-429 / key-429) when the retry layer supplies none.
|
|
457
|
+
deps.onAttemptSend?.(retryRecovery ?? recovery);
|
|
340
458
|
const h = new Headers(request.headers);
|
|
341
459
|
if (!h.has("accept-encoding")) h.set("accept-encoding", "identity");
|
|
342
460
|
return fetch(request.url, {
|
|
@@ -347,7 +465,8 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
347
465
|
});
|
|
348
466
|
},
|
|
349
467
|
{ abortSignal: headerDeadline.signal, label: "web-search-loop" },
|
|
350
|
-
|
|
468
|
+
);
|
|
469
|
+
}
|
|
351
470
|
} finally {
|
|
352
471
|
request.releaseBodyObservation?.();
|
|
353
472
|
}
|
|
@@ -355,10 +474,43 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
355
474
|
};
|
|
356
475
|
|
|
357
476
|
let prepared = await fetchOnce(adapter);
|
|
477
|
+
// Same-target 429 wait-and-retry (opt-in `retryOn429`) BEFORE key rotation: a primary-key
|
|
478
|
+
// rate-limit blip replays on the SAME key; rotation only runs after attempts exhaust.
|
|
479
|
+
while (
|
|
480
|
+
prepared.response.status === 429
|
|
481
|
+
&& rateLimitRetryPolicy !== null
|
|
482
|
+
&& rateLimitRetries < rateLimitRetryPolicy.attempts
|
|
483
|
+
) {
|
|
484
|
+
rateLimitRetries += 1;
|
|
485
|
+
// Release unread body + heartbeat-fed wait via the shared same-target helper.
|
|
486
|
+
const retryAfterHeader = prepared.response.headers.get("retry-after");
|
|
487
|
+
// The old header deadline must not stay armed across the deliberate wait: clear it
|
|
488
|
+
// before sleeping so a stale expiry can never race the client-cancel path.
|
|
489
|
+
headerDeadline.clear();
|
|
490
|
+
try {
|
|
491
|
+
yield* prepareSameTarget429Wait({
|
|
492
|
+
body: prepared.response.body,
|
|
493
|
+
signal,
|
|
494
|
+
delayMs: rateLimitRetryDelayMs(rateLimitRetryPolicy, retryAfterHeader, Date.now()),
|
|
495
|
+
heartbeatIntervalMs: Math.min(10_000, Math.max(250, stallTimeoutMs / 2)),
|
|
496
|
+
});
|
|
497
|
+
} catch {
|
|
498
|
+
throw new LoopError(499, "client closed request during web-search");
|
|
499
|
+
}
|
|
500
|
+
// Client cancellation wins over any stale-deadline edge: re-check before telemetry/replay.
|
|
501
|
+
if (signal.aborted) throw new LoopError(499, "client closed request during web-search");
|
|
502
|
+
// The deliberate backoff must not consume the cumulative response-header deadline:
|
|
503
|
+
// start a fresh one so the replay gets a new connect budget (504 stays reserved for real
|
|
504
|
+
// upstream latency).
|
|
505
|
+
headerDeadline = clearableDeadline(connectTimeoutMs, signal);
|
|
506
|
+
// Stall-watchdog seam between bounded retry fetches.
|
|
507
|
+
yield { type: "heartbeat" };
|
|
508
|
+
prepared = await fetchOnce(adapter, "rate-limit-429");
|
|
509
|
+
}
|
|
358
510
|
// 429 key-failover parity with the normal routed path: rotate pool keys until one responds
|
|
359
511
|
// or the pool is exhausted (deps.on429 returns null — cooldown map guarantees termination).
|
|
360
512
|
while (prepared.response.status === 429 && deps.on429) {
|
|
361
|
-
const rotated = deps.on429(prepared.response.headers.get("retry-after"));
|
|
513
|
+
const rotated = await deps.on429(prepared.response.headers.get("retry-after"));
|
|
362
514
|
if (!rotated) break;
|
|
363
515
|
// Never let a broken body's cancel promise outlive the cumulative header deadline. Observe
|
|
364
516
|
// it, but proceed immediately to the rotated fetch under the SAME deadline signal.
|
|
@@ -366,7 +518,7 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
366
518
|
adapter = rotated;
|
|
367
519
|
// Stall-watchdog seam between bounded retry fetches (audit 011 B3).
|
|
368
520
|
yield { type: "heartbeat" };
|
|
369
|
-
prepared = await fetchOnce(adapter);
|
|
521
|
+
prepared = await fetchOnce(adapter, "key-429");
|
|
370
522
|
}
|
|
371
523
|
|
|
372
524
|
// Final headers have arrived. Clear only the deadline timer before ANY body read.
|
|
@@ -417,10 +569,23 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
417
569
|
return r.value;
|
|
418
570
|
};
|
|
419
571
|
|
|
572
|
+
// Event types that may leave the live window before the first tool-call boundary: pure
|
|
573
|
+
// text/thinking output the native (sidecar-less) path would deliver identically. Everything
|
|
574
|
+
// else — tool calls above all, and any type scanEventsForWebSearch could group or a future
|
|
575
|
+
// adapter could add — closes the window so live delivery can never reorder against the replay.
|
|
576
|
+
const LIVE_STREAMABLE = new Set<AdapterEvent["type"]>([
|
|
577
|
+
"text_delta", "thinking_delta", "reasoning_raw_delta",
|
|
578
|
+
"thinking_signature", "redacted_thinking", "kiro_redacted_reasoning",
|
|
579
|
+
]);
|
|
580
|
+
|
|
420
581
|
// Consume and validate one successful response body under a resettable raw-byte inactivity guard.
|
|
421
|
-
//
|
|
582
|
+
// By default only invisible heartbeat events escape while semantic output remains buffered for
|
|
583
|
+
// safe scanning; with `streamRoutedModelOutput` the leading text/thinking deltas stream live and
|
|
584
|
+
// the live window closes permanently at the first buffer-only event (see LIVE_STREAMABLE).
|
|
422
585
|
const consumeIterationEvents = async function* (prepared: IterationResponse): AsyncGenerator<AdapterEvent, IterationSplit> {
|
|
423
586
|
const events: AdapterEvent[] = [];
|
|
587
|
+
let liveWindowOpen = deps.streamRoutedModelOutput === true;
|
|
588
|
+
let streamedPassthroughCount = 0;
|
|
424
589
|
try {
|
|
425
590
|
const parse = prepared.responseAdapter.parseStream.bind(prepared.responseAdapter);
|
|
426
591
|
for await (const event of parseStreamWithProgress(prepared.response, parse, {
|
|
@@ -436,7 +601,16 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
436
601
|
// Tool events remain buffered below, so the decision to invoke the hosted sidecar is still
|
|
437
602
|
// atomic and no search call can escape before its stream has validated successfully.
|
|
438
603
|
else if (event.type === "text_delta" && event.phase === "commentary") yield event;
|
|
439
|
-
else
|
|
604
|
+
else if (liveWindowOpen && LIVE_STREAMABLE.has(event.type)) {
|
|
605
|
+
// Live events are ALSO buffered: the scanner still needs them for thinking extraction
|
|
606
|
+
// and the forced-answer output check; only the terminal replay skips them (by count).
|
|
607
|
+
yield event;
|
|
608
|
+
streamedPassthroughCount++;
|
|
609
|
+
events.push(event);
|
|
610
|
+
} else {
|
|
611
|
+
liveWindowOpen = false;
|
|
612
|
+
events.push(event);
|
|
613
|
+
}
|
|
440
614
|
}
|
|
441
615
|
} catch (error) {
|
|
442
616
|
if (isTranslatorBudgetExceededError(error)) throw error;
|
|
@@ -458,7 +632,7 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
458
632
|
}
|
|
459
633
|
throw new LoopError(502, terminal.message);
|
|
460
634
|
}
|
|
461
|
-
return scanEventsForWebSearch(events);
|
|
635
|
+
return { ...scanEventsForWebSearch(events), streamedPassthroughCount };
|
|
462
636
|
};
|
|
463
637
|
|
|
464
638
|
// Execute one model-requested web_search call. The call may batch several queries (native
|
|
@@ -501,9 +675,30 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
501
675
|
// signal.aborted both after the await and in the catch (a fulfilled {error} on an aborted
|
|
502
676
|
// signal would otherwise look like an ordinary degradable failure).
|
|
503
677
|
try {
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
678
|
+
if (backend === "anthropic" && anthropicSidecar) {
|
|
679
|
+
outcome = await runAnthropicWebSearch(query, anthropicSidecar.providerName, anthropicSidecar.provider, settings, signal);
|
|
680
|
+
} else if (backend === "xai") {
|
|
681
|
+
// L7: stored Grok OAuth to the pinned api.x.ai Responses endpoint; same
|
|
682
|
+
// never-throws contract and no Codex/OpenAI pool outcome recording (F5 parity).
|
|
683
|
+
// A missing xaiSidecar is an invariant violation — fail CLOSED with an error
|
|
684
|
+
// outcome rather than falling through to the forward-header OpenAI executor
|
|
685
|
+
// (review High: that fallthrough would be credential-sensitive).
|
|
686
|
+
outcome = deps.xaiSidecar
|
|
687
|
+
? await runXaiWebSearch(query, deps.xaiSidecar.providerName, deps.xaiSidecar.provider, settings, deps.xaiSearchOptions ?? {}, signal)
|
|
688
|
+
: { text: "", sources: [], error: "xai backend selected without a resolved Grok OAuth provider" };
|
|
689
|
+
} else if (backend === "gemini") {
|
|
690
|
+
// L8: Antigravity CCA grounding; same fail-closed invariant stance as xai.
|
|
691
|
+
outcome = deps.geminiSidecar
|
|
692
|
+
? await runGeminiWebSearch(query, deps.geminiSidecar.providerName, deps.geminiSidecar.provider, settings, signal)
|
|
693
|
+
: { text: "", sources: [], error: "gemini backend selected without a resolved Antigravity provider" };
|
|
694
|
+
} else if (backend === "exa") {
|
|
695
|
+
// L9: non-LLM lane; key comes from the loop deps, never the plan. Fail closed.
|
|
696
|
+
outcome = deps.exaApiKey
|
|
697
|
+
? await runExaWebSearch(query, deps.exaApiKey, settings, signal)
|
|
698
|
+
: { text: "", sources: [], error: "exa backend selected without an exaApiKey" };
|
|
699
|
+
} else {
|
|
700
|
+
outcome = await runWebSearch(query, hostedTool, forwardProvider!, selectedForwardHeaders, settings, signal, recordSidecarOutcome);
|
|
701
|
+
}
|
|
507
702
|
if (signal.aborted) throw new LoopError(499, "client closed request during web-search");
|
|
508
703
|
} catch (e) {
|
|
509
704
|
if (e instanceof LoopError) throw e;
|
|
@@ -529,7 +724,17 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
529
724
|
// Signed thinking must precede tool_use on replay (Anthropic extended thinking), and
|
|
530
725
|
// unsigned raw reasoning has to ride along for providers that require it back (#688).
|
|
531
726
|
...precedingThinking,
|
|
532
|
-
{
|
|
727
|
+
{
|
|
728
|
+
type: "toolCall" as const,
|
|
729
|
+
id: call.id,
|
|
730
|
+
name: WEB_SEARCH_TOOL_NAME,
|
|
731
|
+
arguments: callArgs,
|
|
732
|
+
// Re-attach the signature to the rebuilt call so a sidecar turn keeps Gemini
|
|
733
|
+
// reasoning continuity instead of relying on the same-process replay cache.
|
|
734
|
+
...(cloneProviderOpaqueToolCallMetadata(call.providerMetadata)
|
|
735
|
+
? { providerMetadata: cloneProviderOpaqueToolCallMetadata(call.providerMetadata) }
|
|
736
|
+
: {}),
|
|
737
|
+
},
|
|
533
738
|
],
|
|
534
739
|
timestamp: now,
|
|
535
740
|
});
|
|
@@ -576,11 +781,20 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
576
781
|
throw e;
|
|
577
782
|
}
|
|
578
783
|
|
|
579
|
-
const toolNsMap = new Map<string, { namespace: string; name: string }>();
|
|
784
|
+
const toolNsMap = new Map<string, { namespace: string; name: string; freeform?: true }>();
|
|
580
785
|
const freeform = new Set<string>();
|
|
581
786
|
const toolSearch = new Set<string>();
|
|
582
|
-
|
|
583
|
-
|
|
787
|
+
const requestedTools = parsed.context.tools ?? [];
|
|
788
|
+
const toolAllowed = toolChoiceToolPredicate(parsed.options.toolChoice, requestedTools);
|
|
789
|
+
for (const t of requestedTools) {
|
|
790
|
+
if (!toolAllowed(t)) continue;
|
|
791
|
+
if (t.namespace) {
|
|
792
|
+
toolNsMap.set(namespacedToolName(t.namespace, t.name), {
|
|
793
|
+
namespace: t.namespace,
|
|
794
|
+
name: t.name,
|
|
795
|
+
...(t.freeform ? { freeform: true } : {}),
|
|
796
|
+
});
|
|
797
|
+
}
|
|
584
798
|
if (t.freeform) freeform.add(t.name);
|
|
585
799
|
if (t.toolSearch) toolSearch.add(t.name);
|
|
586
800
|
}
|
|
@@ -607,6 +821,18 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
607
821
|
// calls reach Codex. forceAnswer also finalizes.
|
|
608
822
|
const shouldLoop = split.calls.length > 0 && !split.hasRealToolCall && !forceAnswer;
|
|
609
823
|
if (!shouldLoop) {
|
|
824
|
+
// #1001: a forced-answer pass that ends `done` must have produced
|
|
825
|
+
// usable output — never a malformed tool call, and never silence.
|
|
826
|
+
if (forceAnswer) {
|
|
827
|
+
// An unterminated call flushes AFTER the terminal event, so find
|
|
828
|
+
// the terminal rather than assuming it is last (#1001).
|
|
829
|
+
const terminalEvent = split.passthrough.find(event => event.type === "done");
|
|
830
|
+
if (terminalEvent?.type === "done"
|
|
831
|
+
&& (split.hasMalformedToolCall
|
|
832
|
+
|| (!split.hasRealToolCall && !hasVisibleAssistantText(split.passthrough)))) {
|
|
833
|
+
throw new LoopError(502, "forced-answer pass produced no usable assistant output");
|
|
834
|
+
}
|
|
835
|
+
}
|
|
610
836
|
if (executedSearchCount > 0) {
|
|
611
837
|
const failedCount = failedQueries.size;
|
|
612
838
|
console.warn(
|
|
@@ -615,7 +841,9 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
615
841
|
+ `, ${i + 1} iteration${i > 0 ? "s" : ""}, ${Date.now() - loopT0}ms`,
|
|
616
842
|
);
|
|
617
843
|
}
|
|
618
|
-
|
|
844
|
+
// Live-streamed leading events are exactly the first N passthrough entries — replay
|
|
845
|
+
// only the buffered tail so nothing reaches the client twice.
|
|
846
|
+
yield* replay(split.passthrough.slice(split.streamedPassthroughCount));
|
|
619
847
|
return;
|
|
620
848
|
}
|
|
621
849
|
// The thinking that led to the search belongs to the FIRST call's assistant replay turn.
|
|
@@ -644,7 +872,7 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
644
872
|
}
|
|
645
873
|
|
|
646
874
|
const sse = bridgeToResponsesSSE(
|
|
647
|
-
produce(), parsed.modelId, toolNsMap, freeform, toolSearch, () => {
|
|
875
|
+
produce(), parsed._responseModelId ?? parsed.modelId, toolNsMap, freeform, toolSearch, () => {
|
|
648
876
|
const elapsed = Date.now() - loopT0;
|
|
649
877
|
if (executedSearchCount > 0 || searchesExecuted > 0) {
|
|
650
878
|
console.warn(`[web-search-loop] cancelled — ${executedSearchCount} real searches, ${searchesExecuted - executedSearchCount} placeholders, ${elapsed}ms`);
|
|
@@ -653,11 +881,13 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
653
881
|
}, undefined,
|
|
654
882
|
{
|
|
655
883
|
translatorBudget,
|
|
884
|
+
replayCacheScope: parsed._reasoningReplayScope,
|
|
656
885
|
...(deps.forceEmptyResponseId ? { responseId: "" } : {}),
|
|
657
886
|
hideThinkingSummary: parsed.options.hideThinkingSummary,
|
|
658
887
|
...(deps.stallTimeoutSec !== undefined ? { stallTimeoutSec: deps.stallTimeoutSec } : {}),
|
|
659
888
|
...(deps.onFirstOutput ? { onFirstOutput: deps.onFirstOutput } : {}),
|
|
660
889
|
...(deps.onUsage ? { onUsage: deps.onUsage } : {}),
|
|
890
|
+
...(deps.onCompletedResponse ? { onCompletedResponse: deps.onCompletedResponse } : {}),
|
|
661
891
|
},
|
|
662
892
|
);
|
|
663
893
|
return new Response(sse, { headers: SSE_HEADERS });
|