@iislee/opencodex 2.11.0 → 2.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS_INSTALL.md +109 -0
- package/README.md +114 -19
- package/bin/ocx.mjs +164 -36
- package/bin/package-main.mjs +1 -1
- package/gui/dist/assets/index-BF38heuV.js +104 -0
- package/gui/dist/assets/index-DMiI18Kv.css +1 -0
- package/gui/dist/index.html +2 -2
- package/gui/dist/provider-icons/alibaba-color.svg +1 -1
- package/gui/dist/provider-icons/antigravity-color.svg +1 -1
- package/gui/dist/provider-icons/claude-color.svg +1 -1
- package/gui/dist/provider-icons/cline-color.svg +16 -0
- package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/commandcode-color.svg +1 -0
- package/gui/dist/provider-icons/copilot-color.svg +1 -1
- package/gui/dist/provider-icons/cursor-color.svg +1 -1
- package/gui/dist/provider-icons/deepseek-color.svg +1 -1
- package/gui/dist/provider-icons/firepass-color.svg +1 -1
- package/gui/dist/provider-icons/fireworks-color.svg +1 -1
- package/gui/dist/provider-icons/gemini-color.svg +1 -1
- package/gui/dist/provider-icons/github-copilot-color.svg +1 -1
- package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -1
- package/gui/dist/provider-icons/grok.svg +1 -1
- package/gui/dist/provider-icons/groq-color.svg +1 -1
- package/gui/dist/provider-icons/huggingface-color.svg +1 -1
- package/gui/dist/provider-icons/kimi-color.svg +1 -1
- package/gui/dist/provider-icons/kiro-color.svg +2 -2
- package/gui/dist/provider-icons/lm-studio-color.svg +1 -1
- package/gui/dist/provider-icons/mistral-color.svg +1 -1
- package/gui/dist/provider-icons/moonshot-color.svg +1 -1
- package/gui/dist/provider-icons/nvidia-color.svg +1 -1
- package/gui/dist/provider-icons/ollama-color.svg +1 -1
- package/gui/dist/provider-icons/openai.svg +1 -1
- package/gui/dist/provider-icons/opencode.svg +2 -1
- package/gui/dist/provider-icons/openrouter-color.svg +1 -1
- package/gui/dist/provider-icons/pi.svg +2 -2
- package/gui/dist/provider-icons/qianfan-color.svg +1 -1
- package/gui/dist/provider-icons/qwen-portal-color.svg +1 -1
- package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/vllm-color.svg +1 -1
- package/gui/dist/provider-icons/xiaomi-color.svg +1 -1
- package/package.json +19 -10
- package/src/adapters/anthropic-output-schema.ts +137 -0
- package/src/adapters/anthropic.ts +376 -52
- package/src/adapters/base.ts +54 -7
- package/src/adapters/client-fingerprint.ts +18 -12
- package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
- package/src/adapters/command-code.ts +601 -0
- package/src/adapters/cursor/checkpoint-store.ts +303 -0
- package/src/adapters/cursor/cursor-errors.ts +129 -6
- package/src/adapters/cursor/discovery.ts +61 -4
- package/src/adapters/cursor/effort-map.ts +27 -3
- package/src/adapters/cursor/framing.ts +39 -0
- package/src/adapters/cursor/h2-pool.ts +123 -0
- package/src/adapters/cursor/http1-bidi.ts +361 -0
- package/src/adapters/cursor/images.ts +704 -0
- package/src/adapters/cursor/live-models.ts +174 -58
- package/src/adapters/cursor/live-transport.ts +609 -170
- package/src/adapters/cursor/native-exec-common.ts +23 -2
- package/src/adapters/cursor/native-exec-fs.ts +10 -7
- package/src/adapters/cursor/native-exec-network.ts +1 -1
- package/src/adapters/cursor/native-exec-shell.ts +0 -1
- package/src/adapters/cursor/native-exec.ts +101 -14
- package/src/adapters/cursor/protobuf-events.ts +829 -11
- package/src/adapters/cursor/protobuf-request.ts +383 -65
- package/src/adapters/cursor/request-builder.ts +237 -31
- package/src/adapters/cursor/tool-definitions.ts +242 -12
- package/src/adapters/cursor/tool-result-normalize.ts +92 -0
- package/src/adapters/cursor/transport.ts +22 -0
- package/src/adapters/cursor/types.ts +28 -1
- package/src/adapters/cursor.ts +133 -7
- package/src/adapters/google-antigravity-replay.ts +558 -34
- package/src/adapters/google-antigravity-wire.ts +43 -10
- package/src/adapters/google-http.ts +38 -10
- package/src/adapters/google-tool-schema.ts +80 -15
- package/src/adapters/google-truncation.ts +11 -0
- package/src/adapters/google.ts +618 -74
- package/src/adapters/identity.ts +39 -6
- package/src/adapters/kiro-errors.ts +11 -0
- package/src/adapters/kiro-events.ts +19 -1
- package/src/adapters/kiro-thinking.ts +18 -2
- package/src/adapters/kiro-tools.ts +10 -1
- package/src/adapters/kiro.ts +92 -54
- package/src/adapters/mimo-free.ts +17 -0
- package/src/adapters/openai-chat-url.ts +11 -0
- package/src/adapters/openai-chat.ts +1311 -336
- package/src/adapters/openai-responses-url.ts +16 -0
- package/src/adapters/openai-responses.ts +830 -56
- package/src/adapters/registry.ts +175 -0
- package/src/adapters/responses-tool-schema.ts +67 -0
- package/src/adapters/tool-call-id.ts +119 -0
- package/src/adapters/tool-catalog-nudge.ts +104 -21
- package/src/adapters/xai-web-search.ts +185 -0
- package/src/bridge.ts +428 -61
- package/src/chat/inbound.ts +43 -19
- package/src/chat/outbound.ts +82 -26
- package/src/claude/agents-inject.ts +32 -9
- package/src/claude/context-windows.ts +21 -5
- package/src/claude/desktop-3p.ts +243 -9
- package/src/claude/gateway-cache.ts +41 -4
- package/src/claude/inbound.ts +72 -3
- package/src/claude/model-info.ts +38 -15
- package/src/claude/outbound.ts +70 -16
- package/src/cli/account-api.ts +35 -1
- package/src/cli/account-auth.ts +33 -6
- package/src/cli/account-catalog-refresh.ts +14 -0
- package/src/cli/account-extended.ts +389 -2
- package/src/cli/account-main.ts +317 -0
- package/src/cli/account.ts +30 -6
- package/src/cli/agent.ts +45 -1
- package/src/cli/claude-agent-startup-sync.ts +73 -0
- package/src/cli/claude-desktop.ts +29 -4
- package/src/cli/claude.ts +103 -34
- package/src/cli/codex-log-guard-doctor.ts +103 -0
- package/src/cli/codex-shim-autorestore.ts +2 -0
- package/src/cli/codex-shim-readiness.ts +76 -0
- package/src/cli/combo.ts +8 -0
- package/src/cli/config-command.ts +74 -10
- package/src/cli/dispatch.ts +593 -0
- package/src/cli/doctor.ts +315 -43
- package/src/cli/ensure-desired-integrations.ts +152 -0
- package/src/cli/export-command.ts +46 -20
- package/src/cli/help.ts +20 -271
- package/src/cli/index.ts +378 -519
- package/src/cli/init.ts +4 -17
- package/src/cli/integrations.ts +120 -2
- package/src/cli/lab.ts +607 -0
- package/src/cli/launcher-context.ts +77 -0
- package/src/cli/minimax.ts +497 -0
- package/src/cli/models-runtime.ts +35 -2
- package/src/cli/models.ts +100 -14
- package/src/cli/observe.ts +92 -3
- package/src/cli/opencode.ts +4 -2
- package/src/cli/provider-runtime.ts +18 -1
- package/src/cli/provider.ts +24 -3
- package/src/cli/ready.ts +301 -0
- package/src/cli/registry.ts +437 -0
- package/src/cli/root.ts +86 -0
- package/src/cli/route-policy.ts +92 -0
- package/src/cli/runtime-api.ts +6 -3
- package/src/cli/star-prompt.ts +71 -15
- package/src/cli/status.ts +10 -3
- package/src/cli/system-restart-client.ts +146 -0
- package/src/cli/tray-proxy.ts +153 -6
- package/src/cli/v2.ts +105 -10
- package/src/cli.ts +1 -1
- package/src/clients/config-export.ts +1358 -21
- package/src/codex/account-label.ts +14 -1
- package/src/codex/account-lifecycle.ts +130 -13
- package/src/codex/account-namespaces.ts +49 -3
- package/src/codex/account-priority.ts +83 -0
- package/src/codex/account-store.ts +29 -2
- package/src/codex/account-usability.ts +25 -2
- package/src/codex/admission.ts +256 -0
- package/src/codex/affinity-debug.ts +162 -0
- package/src/codex/app-server-processes.ts +493 -106
- package/src/codex/app-server-restart-service.ts +232 -0
- package/src/codex/auth-api.ts +849 -242
- package/src/codex/auth-collision.ts +5 -3
- package/src/codex/auth-context.ts +345 -32
- package/src/codex/autostart-health.ts +8 -1
- package/src/codex/catalog/account-models.ts +67 -0
- package/src/codex/catalog/aggregation.ts +68 -10
- package/src/codex/catalog/bundled.ts +331 -33
- package/src/codex/catalog/effort.ts +121 -30
- package/src/codex/catalog/filesystem-evidence.ts +302 -0
- package/src/codex/catalog/kinds.ts +2 -0
- package/src/codex/catalog/metadata.ts +529 -45
- package/src/codex/catalog/native-models.ts +72 -0
- package/src/codex/catalog/parsing.ts +224 -30
- package/src/codex/catalog/provider-fetch.ts +1460 -134
- package/src/codex/catalog/sync.ts +1449 -186
- package/src/codex/catalog-admission.ts +199 -0
- package/src/codex/catalog-refresh-status.ts +105 -0
- package/src/codex/catalog-write-serialization.ts +242 -0
- package/src/codex/catalog.ts +6 -3
- package/src/codex/codex-write-lock.ts +384 -0
- package/src/codex/convergence-types.ts +614 -0
- package/src/codex/convergence.ts +651 -0
- package/src/codex/coordinator-doctor.ts +332 -0
- package/src/codex/custom-model-catalog-migration.ts +176 -0
- package/src/codex/desired-state.ts +230 -0
- package/src/codex/features.ts +636 -39
- package/src/codex/generation.ts +202 -0
- package/src/codex/history-job.ts +407 -0
- package/src/codex/history-lock.ts +242 -0
- package/src/codex/history-migration-guardian.ts +26 -20
- package/src/codex/history-provider.ts +231 -28
- package/src/codex/history-transition.ts +105 -0
- package/src/codex/history-worker.ts +220 -0
- package/src/codex/inject-coordination.ts +290 -0
- package/src/codex/inject.ts +1073 -152
- package/src/codex/injected-marker.ts +37 -3
- package/src/codex/integration-record.ts +266 -0
- package/src/codex/internal/catalog-writer.ts +203 -0
- package/src/codex/internal/history-writer.ts +80 -0
- package/src/codex/journal.ts +66 -4
- package/src/codex/log-guard/inspect.ts +506 -0
- package/src/codex/log-guard/lock.ts +150 -0
- package/src/codex/log-guard/maintenance.ts +403 -0
- package/src/codex/log-guard/path-safety.ts +88 -0
- package/src/codex/log-guard/policy.ts +44 -0
- package/src/codex/log-guard/processes.ts +205 -0
- package/src/codex/log-guard/protection.ts +489 -0
- package/src/codex/log-guard/sqlite-errors.ts +9 -0
- package/src/codex/main-account-cache.ts +24 -0
- package/src/codex/main-account.ts +29 -1
- package/src/codex/management-convergence.ts +167 -0
- package/src/codex/model-cache.ts +56 -10
- package/src/codex/model-entitlements.ts +353 -0
- package/src/codex/native-main-admission.ts +47 -0
- package/src/codex/native-main-auth-temp.ts +187 -0
- package/src/codex/native-main-claim.ts +178 -0
- package/src/codex/native-main-lock-file.ts +162 -0
- package/src/codex/native-main-owner.ts +329 -0
- package/src/codex/native-profile-api.ts +247 -0
- package/src/codex/native-profile-manager.ts +1531 -0
- package/src/codex/native-profile-processes.ts +121 -0
- package/src/codex/native-profile-recovery.ts +99 -0
- package/src/codex/native-profile-stage-store.ts +387 -0
- package/src/codex/native-profile-startup.ts +492 -0
- package/src/codex/native-profile-store.ts +855 -0
- package/src/codex/native-profile-types.ts +120 -0
- package/src/codex/native-residue.ts +682 -0
- package/src/codex/paths.ts +80 -1
- package/src/codex/plan-from-token.ts +140 -0
- package/src/codex/plan.ts +40 -0
- package/src/codex/plugins-doctor.ts +1 -1
- package/src/codex/pool-rotation.ts +74 -4
- package/src/codex/project-config-warnings.ts +20 -6
- package/src/codex/prompt-journal.ts +352 -0
- package/src/codex/prompt-layers.ts +967 -0
- package/src/codex/prompt-lock.ts +143 -0
- package/src/codex/quota-rejection.ts +298 -0
- package/src/codex/quota.ts +175 -13
- package/src/codex/refresh.ts +11 -2
- package/src/codex/reset-credit-recovery.ts +1044 -0
- package/src/codex/routing.ts +505 -94
- package/src/codex/runtime.ts +159 -38
- package/src/codex/shim.ts +1009 -28
- package/src/codex/subagent-model-fallback.ts +350 -35
- package/src/codex/sync.ts +191 -2
- package/src/codex/transition-state.ts +612 -0
- package/src/codex/upstream-host-health.ts +368 -0
- package/src/codex/user-identity.ts +557 -0
- package/src/codex/warmup.ts +187 -81
- package/src/codex/write-coordination.ts +114 -0
- package/src/combos/failover.ts +20 -0
- package/src/combos/index.ts +4 -0
- package/src/combos/request.ts +32 -0
- package/src/combos/types.ts +81 -9
- package/src/config/provider-name.ts +24 -0
- package/src/config.ts +1762 -140
- package/src/generated/compatibility-version.json +3164 -0
- package/src/generated/{jawcode-model-metadata.ts → model-metadata.ts} +19 -17
- package/src/grok/inject.ts +16 -5
- package/src/grok/inspect.ts +45 -0
- package/src/grok/sync.ts +2 -2
- package/src/images/loop.ts +152 -29
- package/src/images/plan.ts +23 -13
- package/src/integrations/config-io.ts +269 -0
- package/src/integrations/journal.ts +315 -0
- package/src/integrations/merge.ts +135 -0
- package/src/integrations/mutation-flight.ts +71 -0
- package/src/integrations/native/ownership-preflight.ts +202 -0
- package/src/integrations/omp-yaml-source.ts +358 -0
- package/src/integrations/owned-refresh.ts +74 -0
- package/src/integrations/ownership.ts +111 -0
- package/src/integrations/registry.ts +159 -0
- package/src/integrations/serialize.ts +314 -0
- package/src/integrations/state.ts +361 -0
- package/src/integrations/store.ts +103 -0
- package/src/integrations/writer-lock.ts +98 -0
- package/src/integrations/writer.ts +691 -0
- package/src/lab/artifacts/sanitize.ts +586 -0
- package/src/lab/artifacts/secure-fs.ts +475 -0
- package/src/lab/artifacts/store.ts +310 -0
- package/src/lab/automation/budgets.ts +78 -0
- package/src/lab/automation/config-persistence.ts +256 -0
- package/src/lab/automation/constants.ts +39 -0
- package/src/lab/automation/cooldown.ts +103 -0
- package/src/lab/automation/dispatch.ts +211 -0
- package/src/lab/automation/index.ts +13 -0
- package/src/lab/automation/orchestrator.ts +499 -0
- package/src/lab/automation/persistence.ts +512 -0
- package/src/lab/automation/planner.ts +371 -0
- package/src/lab/automation/policy.ts +136 -0
- package/src/lab/automation/queue.ts +191 -0
- package/src/lab/automation/recovery.ts +24 -0
- package/src/lab/automation/route-context.ts +21 -0
- package/src/lab/automation/run-key.ts +44 -0
- package/src/lab/automation/runs-query.ts +34 -0
- package/src/lab/automation/types.ts +160 -0
- package/src/lab/conformance/assertion.ts +325 -0
- package/src/lab/conformance/digest.ts +22 -0
- package/src/lab/conformance/executor.ts +741 -0
- package/src/lab/conformance/fixture-provider.ts +27 -0
- package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
- package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
- package/src/lab/conformance/harness-budget.ts +47 -0
- package/src/lab/conformance/index.ts +5 -0
- package/src/lab/conformance/jcs.ts +64 -0
- package/src/lab/conformance/json-pointer.ts +39 -0
- package/src/lab/conformance/manifest.ts +180 -0
- package/src/lab/conformance/mcp-stub.ts +179 -0
- package/src/lab/conformance/negative-controls.ts +164 -0
- package/src/lab/conformance/observation.ts +355 -0
- package/src/lab/conformance/runner.ts +68 -0
- package/src/lab/conformance/sse-normalize.ts +59 -0
- package/src/lab/conformance/suite-manifest.ts +78 -0
- package/src/lab/conformance/types.ts +214 -0
- package/src/lab/constants.ts +126 -0
- package/src/lab/digest.ts +64 -0
- package/src/lab/events/errors.ts +9 -0
- package/src/lab/events/limits.ts +117 -0
- package/src/lab/events/types.ts +229 -0
- package/src/lab/events/validate.ts +781 -0
- package/src/lab/fabric/constants.ts +40 -0
- package/src/lab/fabric/executor.ts +492 -0
- package/src/lab/fabric/index.ts +80 -0
- package/src/lab/fabric/manifest.ts +222 -0
- package/src/lab/fabric/observe.ts +489 -0
- package/src/lab/fabric/patch.ts +79 -0
- package/src/lab/fabric/producer-child.ts +139 -0
- package/src/lab/fabric/producer-isolate.ts +276 -0
- package/src/lab/fabric/producer-protocol.ts +61 -0
- package/src/lab/fabric/scratch.ts +439 -0
- package/src/lab/fabric/subject.ts +106 -0
- package/src/lab/fabric/types.ts +134 -0
- package/src/lab/fabric/verifier.ts +98 -0
- package/src/lab/index.ts +54 -0
- package/src/lab/ledger/artifact-refs.ts +127 -0
- package/src/lab/ledger/invalidation.ts +136 -0
- package/src/lab/ledger/purge.ts +310 -0
- package/src/lab/ledger/store.ts +532 -0
- package/src/lab/live/credential-lease.ts +53 -0
- package/src/lab/live/destination.ts +155 -0
- package/src/lab/live/executor.ts +336 -0
- package/src/lab/live/inert-tools.ts +56 -0
- package/src/lab/live/manifest.ts +85 -0
- package/src/lab/live/mcp-loopback.ts +57 -0
- package/src/lab/live/runner.ts +19 -0
- package/src/lab/live/sandbox.ts +61 -0
- package/src/lab/live/suite-manifest.ts +41 -0
- package/src/lab/live/transport.ts +118 -0
- package/src/lab/live/types.ts +197 -0
- package/src/lab/observe/from-conformance.ts +301 -0
- package/src/lab/observe/from-live.ts +117 -0
- package/src/lab/paths.ts +153 -0
- package/src/lab/projection/rebuild.ts +495 -0
- package/src/lab/projection/schema.ts +135 -0
- package/src/lab/projection/verdicts.ts +474 -0
- package/src/lab/projection/verification.ts +412 -0
- package/src/lab/public/bundle.ts +217 -0
- package/src/lab/public/community-authority.ts +175 -0
- package/src/lab/public/community-files.ts +29 -0
- package/src/lab/public/community.ts +479 -0
- package/src/lab/public/file-safety.ts +155 -0
- package/src/lab/public/ids.ts +26 -0
- package/src/lab/public/index.ts +16 -0
- package/src/lab/public/mutation-lock.ts +424 -0
- package/src/lab/public/operator.ts +353 -0
- package/src/lab/public/origin-purge.ts +79 -0
- package/src/lab/public/origin.ts +203 -0
- package/src/lab/public/privacy.ts +143 -0
- package/src/lab/public/private-file.ts +261 -0
- package/src/lab/public/project.ts +124 -0
- package/src/lab/public/purge-test-fault.ts +21 -0
- package/src/lab/public/purge.ts +223 -0
- package/src/lab/public/registry.ts +44 -0
- package/src/lab/public/revocation.ts +252 -0
- package/src/lab/public/signature.ts +243 -0
- package/src/lab/public/storage.ts +105 -0
- package/src/lab/public/strict-json.ts +206 -0
- package/src/lab/public/time.ts +26 -0
- package/src/lab/public/types.ts +172 -0
- package/src/lab/public/validate.ts +391 -0
- package/src/lab/query/catalog.ts +101 -0
- package/src/lab/query/connection.ts +107 -0
- package/src/lab/query/constants.ts +4 -0
- package/src/lab/query/cursor.ts +132 -0
- package/src/lab/query/dto-map.ts +277 -0
- package/src/lab/query/errors.ts +22 -0
- package/src/lab/query/freshness.ts +53 -0
- package/src/lab/query/index.ts +45 -0
- package/src/lab/query/latest-observation.ts +59 -0
- package/src/lab/query/passive-production.ts +159 -0
- package/src/lab/query/queries.ts +444 -0
- package/src/lab/query/types.ts +266 -0
- package/src/lab/subject/behavior-fingerprint.ts +77 -0
- package/src/lab/subject/installation-salt.ts +112 -0
- package/src/lab/subject/protocol-subject.ts +80 -0
- package/src/lab/subject/route-subject.ts +74 -0
- package/src/lib/app-owned-memory-stores.ts +22 -0
- package/src/lib/bounded-body.ts +153 -9
- package/src/lib/bun-runtime.ts +125 -12
- package/src/lib/bun-stream-caps.ts +13 -9
- package/src/lib/codex-restart-contract.ts +120 -0
- package/src/lib/config-ownership.ts +6 -2
- package/src/lib/destination-policy.ts +65 -1
- package/src/lib/errors.ts +44 -2
- package/src/lib/fabric-task-execution-authority.ts +7 -0
- package/src/lib/fabric-task-host.ts +29 -0
- package/src/lib/lab-activation.ts +223 -0
- package/src/lib/lab-live-execution-authority.ts +13 -0
- package/src/lib/lab-live-host.ts +30 -0
- package/src/lib/lab-live-pinned-sender.ts +56 -0
- package/src/lib/lab-live-route-production.ts +130 -0
- package/src/lib/lab-passive-linker-registration.ts +26 -0
- package/src/lib/local-management-attestation.ts +51 -0
- package/src/lib/local-management-capability.ts +100 -0
- package/src/lib/local-provider-reload-contract.ts +100 -0
- package/src/lib/optional-shutdown-hooks.ts +57 -0
- package/src/lib/pinned-http.ts +145 -26
- package/src/lib/process-control.ts +4 -1
- package/src/lib/provider-outbound.ts +49 -9
- package/src/lib/redact.ts +419 -3
- package/src/lib/self-launch-argv.ts +15 -0
- package/src/lib/server-resource-ownership.ts +71 -0
- package/src/lib/shadow-call.ts +35 -4
- package/src/lib/sse-decoder.ts +41 -0
- package/src/lib/state-store-registrations.ts +10 -2
- package/src/lib/system-restart-contract.ts +73 -0
- package/src/lib/token-estimate.ts +19 -2
- package/src/lib/tool-argument-integers.ts +202 -0
- package/src/lib/translator-budget.ts +44 -0
- package/src/lib/upstream-http-version.ts +57 -0
- package/src/lib/upstream-reachability.ts +95 -0
- package/src/lib/upstream-retry.ts +156 -3
- package/src/lib/windows-atomic-replace.ts +155 -0
- package/src/lib/windows-elevation.ts +70 -2
- package/src/lib/windows-secret-acl.ts +409 -69
- package/src/lib/windows-service-wrappers.ts +72 -0
- package/src/lib/windows-text.ts +106 -0
- package/src/lib/windows-user-principal.ts +341 -0
- package/src/lib/winsw.ts +33 -5
- package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
- package/src/oauth/account-import/index.ts +15 -0
- package/src/oauth/account-import/parser.ts +83 -0
- package/src/oauth/account-import/registry.ts +18 -0
- package/src/oauth/account-import/service.ts +75 -0
- package/src/oauth/account-import/types.ts +91 -0
- package/src/oauth/anthropic.ts +12 -1
- package/src/oauth/callback-server.ts +8 -2
- package/src/oauth/chatgpt.ts +12 -1
- package/src/oauth/command-code.ts +239 -0
- package/src/oauth/cursor.ts +46 -5
- package/src/oauth/google-antigravity.ts +35 -3
- package/src/oauth/health.ts +20 -12
- package/src/oauth/index.ts +398 -66
- package/src/oauth/key-providers.ts +16 -0
- package/src/oauth/kimi.ts +16 -2
- package/src/oauth/kiro.ts +50 -6
- package/src/oauth/local-token-detect.ts +11 -2
- package/src/oauth/log.ts +3 -1
- package/src/oauth/login-cli.ts +88 -28
- package/src/oauth/nous.ts +798 -0
- package/src/oauth/store.ts +119 -21
- package/src/oauth/token-guardian.ts +9 -3
- package/src/pi/models.ts +2 -2
- package/src/providers/alibaba-region-migration.ts +1 -1
- package/src/providers/antigravity-models.ts +521 -31
- package/src/providers/base-url-choices.ts +10 -0
- package/src/providers/codex-capacity.ts +292 -0
- package/src/providers/command-code-efforts.ts +144 -0
- package/src/providers/context-cap.ts +22 -5
- package/src/providers/cursor-pool.ts +72 -0
- package/src/providers/derive.ts +253 -6
- package/src/providers/fastwire.ts +501 -0
- package/src/providers/free-directory.ts +10 -7
- package/src/providers/google-vertex-location.ts +14 -0
- package/src/providers/key-failover.ts +71 -3
- package/src/providers/label.ts +1 -1
- package/src/providers/model-discovery-limits.ts +16 -0
- package/src/providers/model-discovery.ts +115 -22
- package/src/providers/model-rename-migration.ts +255 -0
- package/src/providers/model-rename-startup.ts +28 -0
- package/src/providers/openai-sidecar.ts +72 -4
- package/src/providers/openai-tier-startup.ts +31 -2
- package/src/providers/openai-tiers.ts +119 -4
- package/src/providers/openai-virtual-models.ts +1 -0
- package/src/providers/opencode-zen-rate-limit.ts +102 -0
- package/src/providers/provider-id-rewrite.ts +29 -0
- package/src/providers/quota.ts +1319 -38
- package/src/providers/registry.ts +1429 -111
- package/src/providers/request-pacing.ts +310 -0
- package/src/providers/service-tier.ts +277 -0
- package/src/providers/slug-codec.ts +42 -6
- package/src/providers/static-model-discovery.ts +86 -0
- package/src/providers/xai-responses-opt-in.ts +15 -0
- package/src/providers/xai-transport.ts +11 -4
- package/src/reasoning-effort.ts +49 -1
- package/src/responses/compaction.ts +26 -1
- package/src/responses/custom-tool-compat.ts +266 -0
- package/src/responses/hosted-tool-policy.ts +9 -0
- package/src/responses/namespace-tool-compat.ts +355 -0
- package/src/responses/parser.ts +220 -38
- package/src/responses/provider-continuation.ts +98 -0
- package/src/responses/provider-opaque-metadata.ts +73 -0
- package/src/responses/reasoning-envelope.ts +9 -1
- package/src/responses/reasoning-replay-cache.ts +426 -0
- package/src/responses/schema.ts +7 -1
- package/src/responses/spill-store.ts +75 -10
- package/src/responses/state.ts +565 -27
- package/src/responses/thought-signature-replay.ts +347 -0
- package/src/responses/tool-search-compat.ts +301 -0
- package/src/responses/truncated-stop-reason.ts +60 -0
- package/src/router.ts +366 -30
- package/src/routing/analytics.ts +378 -0
- package/src/routing/capability.ts +244 -0
- package/src/routing/compatibility/assemble.ts +73 -0
- package/src/routing/compatibility/behavior.ts +278 -0
- package/src/routing/compatibility/catalog.ts +99 -0
- package/src/routing/compatibility/endpoint.ts +52 -0
- package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
- package/src/routing/compatibility/policy.ts +181 -0
- package/src/routing/compatibility/provider-slot.ts +56 -0
- package/src/routing/compatibility/reader.ts +110 -0
- package/src/routing/compatibility/subject.ts +191 -0
- package/src/routing/compatibility/types.ts +64 -0
- package/src/routing/compatibility/version.ts +104 -0
- package/src/routing/cost.ts +77 -0
- package/src/routing/evaluator.ts +495 -0
- package/src/routing/health.ts +412 -0
- package/src/routing/history/cursor.ts +43 -0
- package/src/routing/history/indexer.ts +605 -0
- package/src/routing/history/schema.ts +72 -0
- package/src/routing/profile-namespace.ts +15 -0
- package/src/routing/profile.ts +547 -0
- package/src/routing/quota.ts +145 -0
- package/src/routing/request-evidence.ts +45 -0
- package/src/routing/trace.ts +776 -0
- package/src/server/adapter-resolve.ts +2 -29
- package/src/server/auth-cors.ts +267 -46
- package/src/server/background-lifecycle.ts +182 -0
- package/src/server/chat-completions.ts +130 -56
- package/src/server/chat-native-sse.ts +331 -0
- package/src/server/chat-native.ts +426 -0
- package/src/server/claude-messages.ts +159 -43
- package/src/server/direct-local-http.ts +347 -0
- package/src/server/effort-policy.ts +18 -0
- package/src/server/github-copilot-responses-repair.ts +338 -0
- package/src/server/gui-static.ts +39 -10
- package/src/server/images.ts +94 -12
- package/src/server/index.ts +865 -181
- package/src/server/lifecycle.ts +284 -13
- package/src/server/live.ts +136 -17
- package/src/server/local-management-read-client.ts +90 -0
- package/src/server/local-provider-reload-client.ts +137 -0
- package/src/server/management/agent-settings-routes.ts +398 -103
- package/src/server/management/api-key-usage.ts +31 -5
- package/src/server/management/body.ts +6 -0
- package/src/server/management/combo-routes.ts +62 -24
- package/src/server/management/config-routes.ts +464 -51
- package/src/server/management/context.ts +80 -2
- package/src/server/management/integration-routes.ts +498 -0
- package/src/server/management/lab-automation-routes.ts +206 -0
- package/src/server/management/lab-routes.ts +563 -0
- package/src/server/management/logs-usage-routes.ts +101 -32
- package/src/server/management/model-routes.ts +189 -131
- package/src/server/management/model-rows.ts +163 -0
- package/src/server/management/native-integration-routes.ts +769 -0
- package/src/server/management/oauth-account-routes.ts +80 -4
- package/src/server/management/provider-capability-config.ts +48 -0
- package/src/server/management/provider-routes.ts +764 -157
- package/src/server/management/request-history-routes.ts +191 -0
- package/src/server/management/routing-analytics-routes.ts +74 -0
- package/src/server/management/routing-profile-routes.ts +380 -0
- package/src/server/management/shared.ts +27 -11
- package/src/server/management/sidebar-routes.ts +47 -31
- package/src/server/management/storage-log-guard-routes.ts +186 -0
- package/src/server/management/sync-response.ts +69 -0
- package/src/server/management/system-restart.ts +288 -32
- package/src/server/management/system-routes.ts +77 -0
- package/src/server/management/usage-summary-cache.ts +9 -1
- package/src/server/management/vision-sidecar-options.ts +167 -0
- package/src/server/management/web-search-sidecar-options.ts +120 -0
- package/src/server/management-api.ts +115 -14
- package/src/server/management-auth.ts +220 -5
- package/src/server/passive-route-linker.ts +66 -0
- package/src/server/ports.ts +41 -1
- package/src/server/proxy-liveness.ts +132 -5
- package/src/server/readiness.ts +99 -0
- package/src/server/relay-eager.ts +82 -42
- package/src/server/relay.ts +236 -76
- package/src/server/request-decompress.ts +113 -6
- package/src/server/request-log.ts +235 -22
- package/src/server/responses/agent-task-recovery-cache.ts +143 -0
- package/src/server/responses/agent-task-recovery.ts +465 -0
- package/src/server/responses/collaboration.ts +204 -35
- package/src/server/responses/compact.ts +442 -55
- package/src/server/responses/core.ts +2872 -331
- package/src/server/responses/empty-completion-guard.ts +276 -0
- package/src/server/responses/encrypted-payload.ts +62 -39
- package/src/server/responses/fetch-helpers.ts +79 -4
- package/src/server/responses/input-admission.ts +185 -0
- package/src/server/responses/pacing-overload.ts +13 -0
- package/src/server/responses/policy-fallback.ts +178 -0
- package/src/server/responses/responses-field-backfill.ts +251 -0
- package/src/server/responses/terminal-guard.ts +26 -5
- package/src/server/responses/upstream-error.ts +5 -0
- package/src/server/responses/ws-upstream.ts +308 -0
- package/src/server/responses-custom-tool-repair.ts +282 -0
- package/src/server/responses-item-id-repair.ts +54 -6
- package/src/server/responses-json-events.ts +90 -0
- package/src/server/responses-model-rewrite.ts +29 -0
- package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
- package/src/server/responses-snapshot-repair.ts +621 -0
- package/src/server/responses-terminal-repair.ts +342 -0
- package/src/server/responses-tool-search-repair.ts +267 -0
- package/src/server/responses-undeclared-tool-guard.ts +153 -0
- package/src/server/responses.ts +18 -2
- package/src/server/search.ts +78 -13
- package/src/server/sse-frame-buffer.ts +292 -0
- package/src/server/sse-payload-rewrite.ts +110 -22
- package/src/server/startup-action-control.ts +8 -1
- package/src/server/startup-health-cache.ts +19 -1
- package/src/server/system-env.ts +80 -9
- package/src/server/ws-bridge.ts +39 -38
- package/src/service-manager-probe.ts +892 -0
- package/src/service.ts +1111 -90
- package/src/sidecar/auth.ts +92 -0
- package/src/sidecar/candidates.ts +83 -0
- package/src/storage/cleanup.ts +2 -2
- package/src/storage/scanner.ts +1 -1
- package/src/storage/worker-lifecycle.ts +14 -14
- package/src/tray/windows-tray.ps1 +83 -9
- package/src/tray/windows.ts +43 -16
- package/src/types/accounts.ts +37 -0
- package/src/types/config.ts +845 -0
- package/src/types/provider.ts +545 -0
- package/src/types/request.ts +384 -0
- package/src/types/tools.ts +131 -0
- package/src/types/wire.ts +80 -0
- package/src/types.ts +104 -1236
- package/src/update/index.ts +32 -19
- package/src/update/job.ts +442 -67
- package/src/update/notify.ts +12 -6
- package/src/update/npm-cache-preflight.d.mts +47 -0
- package/src/update/npm-cache-preflight.mjs +201 -0
- package/src/update/transactional-install.d.mts +22 -0
- package/src/update/transactional-install.mjs +259 -0
- package/src/usage/cost.ts +0 -0
- package/src/usage/expected-prices.ts +268 -16
- package/src/usage/log.ts +606 -41
- package/src/usage/summary.ts +177 -9
- package/src/usage/user-cost-overlay-reconciler.ts +313 -0
- package/src/usage/user-cost-overlays.ts +314 -0
- package/src/vision/anthropic-describe.ts +10 -6
- package/src/vision/backends.ts +97 -0
- package/src/vision/describe.ts +9 -3
- package/src/vision/eligibility.ts +250 -0
- package/src/vision/index.ts +238 -24
- package/src/vision/reasoning.ts +55 -0
- package/src/vision/routed-describe.ts +175 -0
- package/src/vision/timeout-bounds.ts +9 -0
- package/src/web-search/anthropic-executor.ts +13 -7
- package/src/web-search/backends.ts +108 -0
- package/src/web-search/exa-executor.ts +88 -0
- package/src/web-search/executor.ts +11 -3
- package/src/web-search/gemini-executor.ts +141 -0
- package/src/web-search/index.ts +150 -15
- package/src/web-search/loop.ts +279 -50
- package/src/web-search/parse.ts +125 -30
- package/src/web-search/sources.ts +60 -0
- package/src/web-search/xai-executor.ts +219 -0
- package/gui/dist/assets/index-DTpMHS4F.js +0 -67
- package/gui/dist/assets/index-ZNVDE3C7.css +0 -1
- package/gui/dist/provider-icons/antigravity.svg +0 -1
- package/gui/dist/provider-icons/claude.svg +0 -1
- package/gui/dist/provider-icons/copilot.svg +0 -1
- package/gui/dist/provider-icons/cursor.svg +0 -2
- package/gui/dist/provider-icons/gemini.svg +0 -1
- package/gui/dist/provider-icons/grok-color.svg +0 -1
- package/gui/dist/provider-icons/kiro.svg +0 -14
- package/src/cli/internal-dispatch.ts +0 -20
package/src/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,29 @@ 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
307
|
* 429 key-failover hook: rotate the provider's active pool key and return a rebuilt adapter,
|
|
244
308
|
* or null when the pool is exhausted (same semantics as the normal routed path).
|
|
245
309
|
*/
|
|
246
310
|
on429?: (retryAfterHeader: string | null) => ProviderAdapter | null;
|
|
311
|
+
/** Opt-in same-target 429 policy (key-auth providers). When present, 429 replays on the SAME key before on429 rotation. */
|
|
312
|
+
retryOn429Policy?: Required<RateLimitRetryPolicy> | null;
|
|
313
|
+
/** Called only when the final bridged Responses stream reaches completed or incomplete. */
|
|
314
|
+
onCompletedResponse?: (response: Record<string, unknown>) => void;
|
|
247
315
|
}
|
|
248
316
|
|
|
249
317
|
/**
|
|
@@ -260,6 +328,12 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
260
328
|
// Mutable: 429 key-failover (deps.on429) can swap in a rebuilt adapter mid-loop.
|
|
261
329
|
let adapter = deps.adapter;
|
|
262
330
|
|
|
331
|
+
// Bridge stall budget (seconds of silence before upstream_stall_timeout); the retry backoff
|
|
332
|
+
// heartbeat interval is derived from it so the watchdog is always fed during deliberate waits.
|
|
333
|
+
const stallTimeoutMs = typeof deps.stallTimeoutSec === "number" && Number.isFinite(deps.stallTimeoutSec) && deps.stallTimeoutSec > 0
|
|
334
|
+
? Math.floor(deps.stallTimeoutSec * 1000)
|
|
335
|
+
: 300_000;
|
|
336
|
+
|
|
263
337
|
const messages: OcxMessage[] = [...parsed.context.messages];
|
|
264
338
|
const loopT0 = Date.now();
|
|
265
339
|
const allTools = parsed.context.tools ?? [];
|
|
@@ -292,11 +366,29 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
292
366
|
response: Response;
|
|
293
367
|
responseAdapter: ProviderAdapter;
|
|
294
368
|
}
|
|
295
|
-
type IterationSplit = ReturnType<typeof scanEventsForWebSearch
|
|
369
|
+
type IterationSplit = ReturnType<typeof scanEventsForWebSearch> & {
|
|
370
|
+
/**
|
|
371
|
+
* How many leading passthrough events were already delivered live this iteration. They are
|
|
372
|
+
* exactly the first N passthrough entries (live delivery stops before the first event that
|
|
373
|
+
* scanEventsForWebSearch could group or reorder), so the terminal replay skips them by count.
|
|
374
|
+
*/
|
|
375
|
+
streamedPassthroughCount: number;
|
|
376
|
+
};
|
|
377
|
+
|
|
378
|
+
// Same-target 429 budget is per REQUEST, not per model iteration: later search rounds inherit
|
|
379
|
+
// what earlier rounds left of `attempts`, so a bounded multi-round turn can never exceed the
|
|
380
|
+
// configured replay count in total (a per-round reset would multiply it by maxSearches).
|
|
381
|
+
const rateLimitRetryPolicy = deps.retryOn429Policy ?? null;
|
|
382
|
+
let rateLimitRetries = 0;
|
|
296
383
|
|
|
297
384
|
// Acquire one iteration's final response headers. The first call is drained eagerly so an initial
|
|
298
385
|
// connect/header/HTTP failure stays a non-2xx JSON response. Its successful BODY is deliberately
|
|
299
386
|
// left unread until the downstream Responses SSE bridge exists.
|
|
387
|
+
/**
|
|
388
|
+
* Fetch one web-search iteration's final response headers, applying the response-header
|
|
389
|
+
* deadline and the same-target 429 retry policy (with awaited body release and deadline
|
|
390
|
+
* restart) before the `on429` key rotation.
|
|
391
|
+
*/
|
|
300
392
|
const prepareIterationEvents = async function* (forceAnswer: boolean): AsyncGenerator<AdapterEvent, IterationResponse> {
|
|
301
393
|
// On the forced-answer pass the synthetic web_search tool is gone, so the model MUST answer
|
|
302
394
|
// from the results already in `messages`. A weak model can still produce a thin answer that
|
|
@@ -313,30 +405,55 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
313
405
|
// One cumulative header deadline spans every pool-key 429 rotation in this model iteration.
|
|
314
406
|
// clear() stops only its timer after final headers; the direct turn signal remains attached to
|
|
315
407
|
// the returned response body through AbortSignal.any().
|
|
316
|
-
|
|
408
|
+
let headerDeadline = clearableDeadline(connectTimeoutMs, signal);
|
|
317
409
|
try {
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
410
|
+
/**
|
|
411
|
+
* Build and fetch one web-search iteration on the given adapter, under the iteration
|
|
412
|
+
* header deadline. The caller owns same-target 429 replays and key rotation around it.
|
|
413
|
+
* The outbound request is cached per adapter so a same-target replay reuses the EXACT
|
|
414
|
+
* URL, serialized body, and headers (builder runs once per target sequence).
|
|
415
|
+
*/
|
|
416
|
+
let cachedRequest: AdapterRequest | undefined;
|
|
417
|
+
let cachedAdapter: ProviderAdapter | undefined;
|
|
418
|
+
/**
|
|
419
|
+
* Build and fetch one web-search iteration on the given adapter, under the iteration
|
|
420
|
+
* header deadline. The caller owns same-target 429 replays and key rotation around it.
|
|
421
|
+
*/
|
|
422
|
+
const fetchOnce = async (requestAdapter: ProviderAdapter, recovery?: AttemptRecoveryKind): Promise<IterationResponse> => {
|
|
423
|
+
let request: AdapterRequest;
|
|
424
|
+
if (cachedRequest !== undefined && cachedAdapter === requestAdapter) {
|
|
425
|
+
request = cachedRequest;
|
|
426
|
+
} else {
|
|
427
|
+
request = await requestAdapter.buildRequest(iterParsed, {
|
|
428
|
+
headers: selectedForwardHeaders,
|
|
429
|
+
abortSignal: headerDeadline.signal,
|
|
430
|
+
translatorBudget,
|
|
431
|
+
});
|
|
432
|
+
try {
|
|
433
|
+
deps.onRequestBuilt?.(request);
|
|
434
|
+
} catch {
|
|
435
|
+
// Diagnostics are best-effort and must never abort a web-search iteration.
|
|
436
|
+
}
|
|
437
|
+
cachedRequest = request;
|
|
438
|
+
cachedAdapter = requestAdapter;
|
|
328
439
|
}
|
|
329
440
|
let response: Response;
|
|
330
441
|
try {
|
|
331
|
-
|
|
332
|
-
|
|
442
|
+
if (requestAdapter.fetchResponse) {
|
|
443
|
+
deps.onAttemptSend?.(recovery);
|
|
444
|
+
response = await requestAdapter.fetchResponse(request, {
|
|
333
445
|
abortSignal: headerDeadline.signal,
|
|
334
446
|
timeoutMs: connectTimeoutMs,
|
|
335
447
|
returnRawErrors: true,
|
|
336
448
|
stream: true,
|
|
337
|
-
})
|
|
338
|
-
|
|
339
|
-
|
|
449
|
+
});
|
|
450
|
+
} else {
|
|
451
|
+
response = await fetchWithResetRetry(
|
|
452
|
+
(retryRecovery) => {
|
|
453
|
+
// Record every helper-driven send (the callback runs for the first attempt and
|
|
454
|
+
// each connection-reset replay); preserve the caller's recovery kind
|
|
455
|
+
// (rate-limit-429 / key-429) when the retry layer supplies none.
|
|
456
|
+
deps.onAttemptSend?.(retryRecovery ?? recovery);
|
|
340
457
|
const h = new Headers(request.headers);
|
|
341
458
|
if (!h.has("accept-encoding")) h.set("accept-encoding", "identity");
|
|
342
459
|
return fetch(request.url, {
|
|
@@ -347,7 +464,8 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
347
464
|
});
|
|
348
465
|
},
|
|
349
466
|
{ abortSignal: headerDeadline.signal, label: "web-search-loop" },
|
|
350
|
-
|
|
467
|
+
);
|
|
468
|
+
}
|
|
351
469
|
} finally {
|
|
352
470
|
request.releaseBodyObservation?.();
|
|
353
471
|
}
|
|
@@ -355,6 +473,39 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
355
473
|
};
|
|
356
474
|
|
|
357
475
|
let prepared = await fetchOnce(adapter);
|
|
476
|
+
// Same-target 429 wait-and-retry (opt-in `retryOn429`) BEFORE key rotation: a primary-key
|
|
477
|
+
// rate-limit blip replays on the SAME key; rotation only runs after attempts exhaust.
|
|
478
|
+
while (
|
|
479
|
+
prepared.response.status === 429
|
|
480
|
+
&& rateLimitRetryPolicy !== null
|
|
481
|
+
&& rateLimitRetries < rateLimitRetryPolicy.attempts
|
|
482
|
+
) {
|
|
483
|
+
rateLimitRetries += 1;
|
|
484
|
+
// Release unread body + heartbeat-fed wait via the shared same-target helper.
|
|
485
|
+
const retryAfterHeader = prepared.response.headers.get("retry-after");
|
|
486
|
+
// The old header deadline must not stay armed across the deliberate wait: clear it
|
|
487
|
+
// before sleeping so a stale expiry can never race the client-cancel path.
|
|
488
|
+
headerDeadline.clear();
|
|
489
|
+
try {
|
|
490
|
+
yield* prepareSameTarget429Wait({
|
|
491
|
+
body: prepared.response.body,
|
|
492
|
+
signal,
|
|
493
|
+
delayMs: rateLimitRetryDelayMs(rateLimitRetryPolicy, retryAfterHeader, Date.now()),
|
|
494
|
+
heartbeatIntervalMs: Math.min(10_000, Math.max(250, stallTimeoutMs / 2)),
|
|
495
|
+
});
|
|
496
|
+
} catch {
|
|
497
|
+
throw new LoopError(499, "client closed request during web-search");
|
|
498
|
+
}
|
|
499
|
+
// Client cancellation wins over any stale-deadline edge: re-check before telemetry/replay.
|
|
500
|
+
if (signal.aborted) throw new LoopError(499, "client closed request during web-search");
|
|
501
|
+
// The deliberate backoff must not consume the cumulative response-header deadline:
|
|
502
|
+
// start a fresh one so the replay gets a new connect budget (504 stays reserved for real
|
|
503
|
+
// upstream latency).
|
|
504
|
+
headerDeadline = clearableDeadline(connectTimeoutMs, signal);
|
|
505
|
+
// Stall-watchdog seam between bounded retry fetches.
|
|
506
|
+
yield { type: "heartbeat" };
|
|
507
|
+
prepared = await fetchOnce(adapter, "rate-limit-429");
|
|
508
|
+
}
|
|
358
509
|
// 429 key-failover parity with the normal routed path: rotate pool keys until one responds
|
|
359
510
|
// or the pool is exhausted (deps.on429 returns null — cooldown map guarantees termination).
|
|
360
511
|
while (prepared.response.status === 429 && deps.on429) {
|
|
@@ -366,7 +517,7 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
366
517
|
adapter = rotated;
|
|
367
518
|
// Stall-watchdog seam between bounded retry fetches (audit 011 B3).
|
|
368
519
|
yield { type: "heartbeat" };
|
|
369
|
-
prepared = await fetchOnce(adapter);
|
|
520
|
+
prepared = await fetchOnce(adapter, "key-429");
|
|
370
521
|
}
|
|
371
522
|
|
|
372
523
|
// Final headers have arrived. Clear only the deadline timer before ANY body read.
|
|
@@ -417,10 +568,23 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
417
568
|
return r.value;
|
|
418
569
|
};
|
|
419
570
|
|
|
571
|
+
// Event types that may leave the live window before the first tool-call boundary: pure
|
|
572
|
+
// text/thinking output the native (sidecar-less) path would deliver identically. Everything
|
|
573
|
+
// else — tool calls above all, and any type scanEventsForWebSearch could group or a future
|
|
574
|
+
// adapter could add — closes the window so live delivery can never reorder against the replay.
|
|
575
|
+
const LIVE_STREAMABLE = new Set<AdapterEvent["type"]>([
|
|
576
|
+
"text_delta", "thinking_delta", "reasoning_raw_delta",
|
|
577
|
+
"thinking_signature", "redacted_thinking", "kiro_redacted_reasoning",
|
|
578
|
+
]);
|
|
579
|
+
|
|
420
580
|
// Consume and validate one successful response body under a resettable raw-byte inactivity guard.
|
|
421
|
-
//
|
|
581
|
+
// By default only invisible heartbeat events escape while semantic output remains buffered for
|
|
582
|
+
// safe scanning; with `streamRoutedModelOutput` the leading text/thinking deltas stream live and
|
|
583
|
+
// the live window closes permanently at the first buffer-only event (see LIVE_STREAMABLE).
|
|
422
584
|
const consumeIterationEvents = async function* (prepared: IterationResponse): AsyncGenerator<AdapterEvent, IterationSplit> {
|
|
423
585
|
const events: AdapterEvent[] = [];
|
|
586
|
+
let liveWindowOpen = deps.streamRoutedModelOutput === true;
|
|
587
|
+
let streamedPassthroughCount = 0;
|
|
424
588
|
try {
|
|
425
589
|
const parse = prepared.responseAdapter.parseStream.bind(prepared.responseAdapter);
|
|
426
590
|
for await (const event of parseStreamWithProgress(prepared.response, parse, {
|
|
@@ -436,7 +600,16 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
436
600
|
// Tool events remain buffered below, so the decision to invoke the hosted sidecar is still
|
|
437
601
|
// atomic and no search call can escape before its stream has validated successfully.
|
|
438
602
|
else if (event.type === "text_delta" && event.phase === "commentary") yield event;
|
|
439
|
-
else
|
|
603
|
+
else if (liveWindowOpen && LIVE_STREAMABLE.has(event.type)) {
|
|
604
|
+
// Live events are ALSO buffered: the scanner still needs them for thinking extraction
|
|
605
|
+
// and the forced-answer output check; only the terminal replay skips them (by count).
|
|
606
|
+
yield event;
|
|
607
|
+
streamedPassthroughCount++;
|
|
608
|
+
events.push(event);
|
|
609
|
+
} else {
|
|
610
|
+
liveWindowOpen = false;
|
|
611
|
+
events.push(event);
|
|
612
|
+
}
|
|
440
613
|
}
|
|
441
614
|
} catch (error) {
|
|
442
615
|
if (isTranslatorBudgetExceededError(error)) throw error;
|
|
@@ -458,7 +631,7 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
458
631
|
}
|
|
459
632
|
throw new LoopError(502, terminal.message);
|
|
460
633
|
}
|
|
461
|
-
return scanEventsForWebSearch(events);
|
|
634
|
+
return { ...scanEventsForWebSearch(events), streamedPassthroughCount };
|
|
462
635
|
};
|
|
463
636
|
|
|
464
637
|
// Execute one model-requested web_search call. The call may batch several queries (native
|
|
@@ -501,9 +674,30 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
501
674
|
// signal.aborted both after the await and in the catch (a fulfilled {error} on an aborted
|
|
502
675
|
// signal would otherwise look like an ordinary degradable failure).
|
|
503
676
|
try {
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
677
|
+
if (backend === "anthropic" && anthropicSidecar) {
|
|
678
|
+
outcome = await runAnthropicWebSearch(query, anthropicSidecar.providerName, anthropicSidecar.provider, settings, signal);
|
|
679
|
+
} else if (backend === "xai") {
|
|
680
|
+
// L7: stored Grok OAuth to the pinned api.x.ai Responses endpoint; same
|
|
681
|
+
// never-throws contract and no Codex/OpenAI pool outcome recording (F5 parity).
|
|
682
|
+
// A missing xaiSidecar is an invariant violation — fail CLOSED with an error
|
|
683
|
+
// outcome rather than falling through to the forward-header OpenAI executor
|
|
684
|
+
// (review High: that fallthrough would be credential-sensitive).
|
|
685
|
+
outcome = deps.xaiSidecar
|
|
686
|
+
? await runXaiWebSearch(query, deps.xaiSidecar.providerName, deps.xaiSidecar.provider, settings, deps.xaiSearchOptions ?? {}, signal)
|
|
687
|
+
: { text: "", sources: [], error: "xai backend selected without a resolved Grok OAuth provider" };
|
|
688
|
+
} else if (backend === "gemini") {
|
|
689
|
+
// L8: Antigravity CCA grounding; same fail-closed invariant stance as xai.
|
|
690
|
+
outcome = deps.geminiSidecar
|
|
691
|
+
? await runGeminiWebSearch(query, deps.geminiSidecar.providerName, deps.geminiSidecar.provider, settings, signal)
|
|
692
|
+
: { text: "", sources: [], error: "gemini backend selected without a resolved Antigravity provider" };
|
|
693
|
+
} else if (backend === "exa") {
|
|
694
|
+
// L9: non-LLM lane; key comes from the loop deps, never the plan. Fail closed.
|
|
695
|
+
outcome = deps.exaApiKey
|
|
696
|
+
? await runExaWebSearch(query, deps.exaApiKey, settings, signal)
|
|
697
|
+
: { text: "", sources: [], error: "exa backend selected without an exaApiKey" };
|
|
698
|
+
} else {
|
|
699
|
+
outcome = await runWebSearch(query, hostedTool, forwardProvider!, selectedForwardHeaders, settings, signal, recordSidecarOutcome);
|
|
700
|
+
}
|
|
507
701
|
if (signal.aborted) throw new LoopError(499, "client closed request during web-search");
|
|
508
702
|
} catch (e) {
|
|
509
703
|
if (e instanceof LoopError) throw e;
|
|
@@ -529,7 +723,17 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
529
723
|
// Signed thinking must precede tool_use on replay (Anthropic extended thinking), and
|
|
530
724
|
// unsigned raw reasoning has to ride along for providers that require it back (#688).
|
|
531
725
|
...precedingThinking,
|
|
532
|
-
{
|
|
726
|
+
{
|
|
727
|
+
type: "toolCall" as const,
|
|
728
|
+
id: call.id,
|
|
729
|
+
name: WEB_SEARCH_TOOL_NAME,
|
|
730
|
+
arguments: callArgs,
|
|
731
|
+
// Re-attach the signature to the rebuilt call so a sidecar turn keeps Gemini
|
|
732
|
+
// reasoning continuity instead of relying on the same-process replay cache.
|
|
733
|
+
...(cloneProviderOpaqueToolCallMetadata(call.providerMetadata)
|
|
734
|
+
? { providerMetadata: cloneProviderOpaqueToolCallMetadata(call.providerMetadata) }
|
|
735
|
+
: {}),
|
|
736
|
+
},
|
|
533
737
|
],
|
|
534
738
|
timestamp: now,
|
|
535
739
|
});
|
|
@@ -576,11 +780,20 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
576
780
|
throw e;
|
|
577
781
|
}
|
|
578
782
|
|
|
579
|
-
const toolNsMap = new Map<string, { namespace: string; name: string }>();
|
|
783
|
+
const toolNsMap = new Map<string, { namespace: string; name: string; freeform?: true }>();
|
|
580
784
|
const freeform = new Set<string>();
|
|
581
785
|
const toolSearch = new Set<string>();
|
|
582
|
-
|
|
583
|
-
|
|
786
|
+
const requestedTools = parsed.context.tools ?? [];
|
|
787
|
+
const toolAllowed = toolChoiceToolPredicate(parsed.options.toolChoice, requestedTools);
|
|
788
|
+
for (const t of requestedTools) {
|
|
789
|
+
if (!toolAllowed(t)) continue;
|
|
790
|
+
if (t.namespace) {
|
|
791
|
+
toolNsMap.set(namespacedToolName(t.namespace, t.name), {
|
|
792
|
+
namespace: t.namespace,
|
|
793
|
+
name: t.name,
|
|
794
|
+
...(t.freeform ? { freeform: true } : {}),
|
|
795
|
+
});
|
|
796
|
+
}
|
|
584
797
|
if (t.freeform) freeform.add(t.name);
|
|
585
798
|
if (t.toolSearch) toolSearch.add(t.name);
|
|
586
799
|
}
|
|
@@ -607,6 +820,18 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
607
820
|
// calls reach Codex. forceAnswer also finalizes.
|
|
608
821
|
const shouldLoop = split.calls.length > 0 && !split.hasRealToolCall && !forceAnswer;
|
|
609
822
|
if (!shouldLoop) {
|
|
823
|
+
// #1001: a forced-answer pass that ends `done` must have produced
|
|
824
|
+
// usable output — never a malformed tool call, and never silence.
|
|
825
|
+
if (forceAnswer) {
|
|
826
|
+
// An unterminated call flushes AFTER the terminal event, so find
|
|
827
|
+
// the terminal rather than assuming it is last (#1001).
|
|
828
|
+
const terminalEvent = split.passthrough.find(event => event.type === "done");
|
|
829
|
+
if (terminalEvent?.type === "done"
|
|
830
|
+
&& (split.hasMalformedToolCall
|
|
831
|
+
|| (!split.hasRealToolCall && !hasVisibleAssistantText(split.passthrough)))) {
|
|
832
|
+
throw new LoopError(502, "forced-answer pass produced no usable assistant output");
|
|
833
|
+
}
|
|
834
|
+
}
|
|
610
835
|
if (executedSearchCount > 0) {
|
|
611
836
|
const failedCount = failedQueries.size;
|
|
612
837
|
console.warn(
|
|
@@ -615,7 +840,9 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
615
840
|
+ `, ${i + 1} iteration${i > 0 ? "s" : ""}, ${Date.now() - loopT0}ms`,
|
|
616
841
|
);
|
|
617
842
|
}
|
|
618
|
-
|
|
843
|
+
// Live-streamed leading events are exactly the first N passthrough entries — replay
|
|
844
|
+
// only the buffered tail so nothing reaches the client twice.
|
|
845
|
+
yield* replay(split.passthrough.slice(split.streamedPassthroughCount));
|
|
619
846
|
return;
|
|
620
847
|
}
|
|
621
848
|
// The thinking that led to the search belongs to the FIRST call's assistant replay turn.
|
|
@@ -644,7 +871,7 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
644
871
|
}
|
|
645
872
|
|
|
646
873
|
const sse = bridgeToResponsesSSE(
|
|
647
|
-
produce(), parsed.modelId, toolNsMap, freeform, toolSearch, () => {
|
|
874
|
+
produce(), parsed._responseModelId ?? parsed.modelId, toolNsMap, freeform, toolSearch, () => {
|
|
648
875
|
const elapsed = Date.now() - loopT0;
|
|
649
876
|
if (executedSearchCount > 0 || searchesExecuted > 0) {
|
|
650
877
|
console.warn(`[web-search-loop] cancelled — ${executedSearchCount} real searches, ${searchesExecuted - executedSearchCount} placeholders, ${elapsed}ms`);
|
|
@@ -653,11 +880,13 @@ export async function runWithWebSearch(deps: WebSearchLoopDeps): Promise<Respons
|
|
|
653
880
|
}, undefined,
|
|
654
881
|
{
|
|
655
882
|
translatorBudget,
|
|
883
|
+
replayCacheScope: parsed._reasoningReplayScope,
|
|
656
884
|
...(deps.forceEmptyResponseId ? { responseId: "" } : {}),
|
|
657
885
|
hideThinkingSummary: parsed.options.hideThinkingSummary,
|
|
658
886
|
...(deps.stallTimeoutSec !== undefined ? { stallTimeoutSec: deps.stallTimeoutSec } : {}),
|
|
659
887
|
...(deps.onFirstOutput ? { onFirstOutput: deps.onFirstOutput } : {}),
|
|
660
888
|
...(deps.onUsage ? { onUsage: deps.onUsage } : {}),
|
|
889
|
+
...(deps.onCompletedResponse ? { onCompletedResponse: deps.onCompletedResponse } : {}),
|
|
661
890
|
},
|
|
662
891
|
);
|
|
663
892
|
return new Response(sse, { headers: SSE_HEADERS });
|