@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/responses/parser.ts
CHANGED
|
@@ -9,23 +9,43 @@ import type {
|
|
|
9
9
|
OcxThinkingContent,
|
|
10
10
|
OcxTool,
|
|
11
11
|
OcxToolCall,
|
|
12
|
+
OcxReasoningReplayScopeRef,
|
|
12
13
|
} from "../types";
|
|
13
|
-
import { namespacedToolName } from "../types";
|
|
14
|
+
import { createToolChoiceResolver, namespacedToolName } from "../types";
|
|
14
15
|
import { responsesRequestSchema } from "./schema";
|
|
15
|
-
import {
|
|
16
|
+
import { providerMetadataFromResponsesFunctionCall } from "./provider-opaque-metadata";
|
|
17
|
+
import { lookupReplayThoughtSignature } from "./thought-signature-replay";
|
|
18
|
+
import { compactionItemToText, isCompactionItemType } from "./compaction";
|
|
16
19
|
import { previousResponseReplayPrefixLength } from "./state";
|
|
17
20
|
import { decodeReasoningEnvelope } from "./reasoning-envelope";
|
|
18
21
|
import { extractHostedWebSearch, WEB_SEARCH_TOOL_NAME } from "../web-search/synthetic-tool";
|
|
19
22
|
import { extractHostedImageGeneration, IMAGE_GEN_TOOL_NAME } from "../images/synthetic-tool";
|
|
23
|
+
import { toolSearchDescription, toolSearchParameters } from "./tool-search-compat";
|
|
20
24
|
|
|
21
25
|
function isObj(v: unknown): v is Record<string, unknown> {
|
|
22
26
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
23
27
|
}
|
|
24
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Wrap a remembered proxy-side signature as provider metadata for a replayed tool call.
|
|
31
|
+
*
|
|
32
|
+
* The scope is REQUIRED for a hit. `parseRequest` runs before the route and account are
|
|
33
|
+
* chosen, so a caller that has not yet bound a replay scope gets nothing rather than a
|
|
34
|
+
* signature belonging to some other thread that happened to reuse the same `call_id`.
|
|
35
|
+
*/
|
|
36
|
+
function replayThoughtSignatureMetadata(
|
|
37
|
+
callId: string,
|
|
38
|
+
scope: OcxReasoningReplayScopeRef | undefined,
|
|
39
|
+
): { google: { thoughtSignature: string } } | undefined {
|
|
40
|
+
const signature = lookupReplayThoughtSignature(callId, scope);
|
|
41
|
+
return signature ? { google: { thoughtSignature: signature } } : undefined;
|
|
42
|
+
}
|
|
43
|
+
|
|
25
44
|
type InputBlock =
|
|
26
45
|
| { type: "input_text"; text: string }
|
|
27
46
|
| { type: "text"; text: string }
|
|
28
47
|
| { type: "input_image"; image_url?: string; file_id?: string; detail?: string }
|
|
48
|
+
| { type: "input_video"; video_url?: string }
|
|
29
49
|
| { type: "input_file"; file_id?: string; filename?: string; file_data?: string };
|
|
30
50
|
|
|
31
51
|
/** A usable reference string, or undefined. Empty strings and non-strings are not references. */
|
|
@@ -61,6 +81,9 @@ function inputContentParts(blocks: unknown): string | OcxContentPart[] {
|
|
|
61
81
|
}
|
|
62
82
|
// No usable reference: omit the block. A "[image: ?]" marker would claim an attachment
|
|
63
83
|
// the request never carried, which is worse than dropping malformed input.
|
|
84
|
+
} else if (block.type === "input_video") {
|
|
85
|
+
const videoUrl = nonEmptyString(block.video_url);
|
|
86
|
+
if (videoUrl) parts.push({ type: "video", videoUrl });
|
|
64
87
|
} else if (block.type === "input_file") {
|
|
65
88
|
const b = block as { file_id?: string; filename?: string; file_data?: string };
|
|
66
89
|
const fileId = nonEmptyString(b.file_id);
|
|
@@ -151,43 +174,53 @@ function buildTools(tools: unknown[] | undefined): OcxTool[] | undefined {
|
|
|
151
174
|
if (namespace) tool.namespace = namespace;
|
|
152
175
|
out.push(tool);
|
|
153
176
|
};
|
|
177
|
+
const pushCustom = (t: Record<string, unknown>, namespace?: string) => {
|
|
178
|
+
// Freeform custom tools are lowered to a single string `input` because chat models cannot
|
|
179
|
+
// emit Responses grammar payloads directly. Keep tool-specific input guidance scoped to the
|
|
180
|
+
// tool that owns it: leaking apply_patch syntax into `exec` or another freeform tool teaches
|
|
181
|
+
// routed models that the nested helper name is itself a callable top-level tool.
|
|
182
|
+
const inputDescription = t.name === "apply_patch"
|
|
183
|
+
? "Raw tool input. For apply_patch, begin exactly with `*** Begin Patch` (no trailing `***`), then use its standard patch envelope."
|
|
184
|
+
: "Raw freeform input for this tool.";
|
|
185
|
+
const tool: OcxTool = {
|
|
186
|
+
name: t.name as string,
|
|
187
|
+
description: (t.description as string) ?? "",
|
|
188
|
+
parameters: { type: "object", properties: { input: { type: "string", description: inputDescription } }, required: ["input"] },
|
|
189
|
+
freeform: true,
|
|
190
|
+
};
|
|
191
|
+
if (namespace) tool.namespace = namespace;
|
|
192
|
+
out.push(tool);
|
|
193
|
+
};
|
|
154
194
|
for (const t of tools) {
|
|
155
195
|
if (!isObj(t)) continue;
|
|
196
|
+
if (t.type === "function" && isObj(t.function) && typeof t.function.name === "string" && t.function.name.length > 0) {
|
|
197
|
+
pushFn(t.function as Record<string, unknown>);
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
156
200
|
if (t.type === "function" && typeof t.name === "string") {
|
|
157
201
|
pushFn(t);
|
|
158
202
|
} else if (t.type === "namespace" && Array.isArray(t.tools)) {
|
|
159
|
-
//
|
|
160
|
-
//
|
|
161
|
-
|
|
203
|
+
// Codex 0.147 groups its ordinary client tools under the reserved `functions` namespace,
|
|
204
|
+
// including freeform custom tools such as code-mode `exec`. Those children are still
|
|
205
|
+
// top-level Responses tools, so flatten them without a namespace. Other namespace groups
|
|
206
|
+
// are MCP-style and keep their namespace for round-trip routing.
|
|
207
|
+
const builtinFunctions = t.name === "functions";
|
|
208
|
+
const ns = typeof t.name === "string" && !builtinFunctions ? t.name : undefined;
|
|
162
209
|
for (const inner of t.tools as unknown[]) {
|
|
163
210
|
if (isObj(inner) && inner.type === "function" && typeof inner.name === "string") pushFn(inner, ns);
|
|
211
|
+
else if (isObj(inner) && inner.type === "custom" && typeof inner.name === "string") pushCustom(inner, ns);
|
|
164
212
|
}
|
|
165
213
|
}
|
|
166
214
|
else if (t.type === "custom" && typeof t.name === "string") {
|
|
167
|
-
|
|
168
|
-
// function with a single string `input` carrying the raw tool body; the bridge relays the model's
|
|
169
|
-
// call back as a custom_tool_call (Codex's freeform handler rejects a function_call → fatal abort).
|
|
170
|
-
out.push({
|
|
171
|
-
name: t.name,
|
|
172
|
-
description: (t.description as string) ?? "",
|
|
173
|
-
parameters: { type: "object", properties: { input: { type: "string", description: "Raw tool input. For apply_patch, begin exactly with `*** Begin Patch` (no trailing `***`), then use its standard patch envelope." } }, required: ["input"] },
|
|
174
|
-
freeform: true,
|
|
175
|
-
});
|
|
215
|
+
pushCustom(t);
|
|
176
216
|
}
|
|
177
217
|
else if (t.type === "tool_search") {
|
|
178
218
|
// Client-executed tool discovery — the gateway to deferred tools (subagents, extra MCP tools).
|
|
179
219
|
// Expose as a function so chat models can call it; the bridge relays it as a tool_search_call.
|
|
180
220
|
out.push({
|
|
181
221
|
name: "tool_search",
|
|
182
|
-
description: (t
|
|
183
|
-
parameters: (
|
|
184
|
-
type: "object",
|
|
185
|
-
properties: {
|
|
186
|
-
query: { type: "string", description: "Search query for tools to load." },
|
|
187
|
-
limit: { type: "number", description: "Maximum number of tools to return." },
|
|
188
|
-
},
|
|
189
|
-
required: ["query"],
|
|
190
|
-
}) as Record<string, unknown>,
|
|
222
|
+
description: toolSearchDescription(t),
|
|
223
|
+
parameters: normalizeParameters(toolSearchParameters(t)),
|
|
191
224
|
toolSearch: true,
|
|
192
225
|
});
|
|
193
226
|
}
|
|
@@ -263,9 +296,70 @@ function findToolById(messages: OcxMessage[], callId: string): { name: string; n
|
|
|
263
296
|
return { name: "" };
|
|
264
297
|
}
|
|
265
298
|
|
|
299
|
+
/**
|
|
300
|
+
* Attach pending reasoning to the assistant turn that owns the given call id.
|
|
301
|
+
* Reconstructed histories (resume/retry/synthetic) can order a `reasoning`
|
|
302
|
+
* item AFTER the `function_call` it belongs to; without this, the pending
|
|
303
|
+
* buffer is cleared at the tool output and the turn serializes without
|
|
304
|
+
* `reasoning_content`, which DeepSeek thinking mode rejects with HTTP 400
|
|
305
|
+
* (issue #950).
|
|
306
|
+
*/
|
|
307
|
+
function attachPendingReasoningToCallOwner(
|
|
308
|
+
messages: OcxMessage[],
|
|
309
|
+
callId: string,
|
|
310
|
+
pendingReasoning: Array<{ part: OcxThinkingContent; envelopeSigned: boolean }>,
|
|
311
|
+
): void {
|
|
312
|
+
if (pendingReasoning.length === 0 || !callId) return;
|
|
313
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
314
|
+
const m = messages[i];
|
|
315
|
+
if (m.role !== "assistant") continue;
|
|
316
|
+
for (const part of m.content) {
|
|
317
|
+
if (part.type === "toolCall" && part.id === callId) {
|
|
318
|
+
// Prepend so thinking still precedes tool_use for adapters that require
|
|
319
|
+
// that ordering (Anthropic-style replay).
|
|
320
|
+
m.content = [...pendingReasoning.map(entry => entry.part), ...m.content];
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
266
327
|
const REASONING_EFFORTS = new Set(["none", "minimal", "low", "medium", "high", "xhigh", "max"]);
|
|
267
328
|
|
|
268
|
-
|
|
329
|
+
/**
|
|
330
|
+
* Namespace a custom tool was declared under, by its bare name.
|
|
331
|
+
*
|
|
332
|
+
* A `custom_tool_call` echoed back by the client carries only the bare name — the bridge
|
|
333
|
+
* emits `{"type":"custom_tool_call","name":"exec"}` even when the tool was declared as
|
|
334
|
+
* `mcp__functions__exec`. Without this lookup the namespace is lost on the return trip,
|
|
335
|
+
* and the adapters replay history through `namespacedToolName(namespace, name)`, which
|
|
336
|
+
* then produces a bare `exec` the provider may not have. Ordinary `function_call` items
|
|
337
|
+
* do not need this: they carry `namespace` on the wire.
|
|
338
|
+
*/
|
|
339
|
+
function customToolNamespaces(tools: unknown): Map<string, string> {
|
|
340
|
+
const out = new Map<string, string>();
|
|
341
|
+
if (!Array.isArray(tools)) return out;
|
|
342
|
+
for (const spec of tools) {
|
|
343
|
+
if (!isObj(spec) || spec.type !== "namespace" || !Array.isArray(spec.tools)) continue;
|
|
344
|
+
const namespace = typeof spec.name === "string" ? spec.name : undefined;
|
|
345
|
+
// Codex 0.147 groups ordinary client tools under the reserved `functions` namespace and
|
|
346
|
+
// buildTools deliberately flattens those without a namespace. Mirror that here, or the
|
|
347
|
+
// reconstruction would invent a namespace the request never advertised.
|
|
348
|
+
if (!namespace || namespace === "functions") continue;
|
|
349
|
+
for (const inner of spec.tools) {
|
|
350
|
+
if (!isObj(inner) || inner.type !== "custom" || typeof inner.name !== "string") continue;
|
|
351
|
+
// Ambiguous bare names are already rejected upstream, so first declaration wins.
|
|
352
|
+
if (!out.has(inner.name)) out.set(inner.name, namespace);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
return out;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
export function parseRequest(
|
|
359
|
+
body: unknown,
|
|
360
|
+
parseOptions?: { replayCacheScope?: OcxReasoningReplayScopeRef },
|
|
361
|
+
): OcxParsedRequest {
|
|
362
|
+
const replayCacheScope = parseOptions?.replayCacheScope;
|
|
269
363
|
const replayedInputPrefixLength = previousResponseReplayPrefixLength(body);
|
|
270
364
|
const parsed = responsesRequestSchema.safeParse(body);
|
|
271
365
|
if (!parsed.success) {
|
|
@@ -274,6 +368,9 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
274
368
|
const data = parsed.data;
|
|
275
369
|
const now = Date.now();
|
|
276
370
|
const messages: OcxMessage[] = [];
|
|
371
|
+
// Built before the item loop: a custom_tool_call echoed back in `input` needs the
|
|
372
|
+
// namespace from the request's own tool catalog to survive the round trip.
|
|
373
|
+
const customToolNamespacesByName = customToolNamespaces(data.tools);
|
|
277
374
|
const systemPrompt: string[] = [];
|
|
278
375
|
// Responses reasoning siblings belong to the following assistant, including across call items.
|
|
279
376
|
// Keep them off the message list until that assistant arrives; turn boundaries clear the array.
|
|
@@ -296,17 +393,33 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
296
393
|
// synthetic `{type:"compaction"}` output item (src/responses/compaction.ts). Flagged for the server.
|
|
297
394
|
let compactionRequest = false;
|
|
298
395
|
let contextCompactionBoundary = false;
|
|
396
|
+
let continuationConversationMessageIndex: number | undefined;
|
|
299
397
|
|
|
300
398
|
if (typeof data.instructions === "string" && data.instructions.length > 0) {
|
|
301
399
|
systemPrompt.push(data.instructions);
|
|
302
400
|
}
|
|
303
401
|
|
|
304
402
|
if (typeof data.input === "string") {
|
|
403
|
+
if (data.previous_response_id) continuationConversationMessageIndex = messages.length;
|
|
305
404
|
messages.push({ role: "user", content: data.input, timestamp: now });
|
|
306
405
|
} else if (data.input) {
|
|
307
406
|
for (let inputIndex = 0; inputIndex < data.input.length; inputIndex++) {
|
|
308
407
|
const item = data.input[inputIndex];
|
|
309
408
|
const effectiveType = (item as { type?: string }).type ?? ("role" in item ? "message" : undefined);
|
|
409
|
+
const itemRole = (item as { role?: string }).role;
|
|
410
|
+
// Raw protocol items do not map one-to-one onto context messages. Capture the boundary while
|
|
411
|
+
// both representations are available so later metadata can stay before conversation in both.
|
|
412
|
+
if (
|
|
413
|
+
data.previous_response_id
|
|
414
|
+
&& inputIndex >= replayedInputPrefixLength
|
|
415
|
+
&& continuationConversationMessageIndex === undefined
|
|
416
|
+
&& (
|
|
417
|
+
effectiveType === "agent_message"
|
|
418
|
+
|| (effectiveType === "message" && (itemRole === "user" || itemRole === "assistant"))
|
|
419
|
+
)
|
|
420
|
+
) {
|
|
421
|
+
continuationConversationMessageIndex = messages.length;
|
|
422
|
+
}
|
|
310
423
|
|
|
311
424
|
if (effectiveType === "compaction_trigger") {
|
|
312
425
|
compactionRequest = true;
|
|
@@ -325,7 +438,7 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
325
438
|
continue;
|
|
326
439
|
}
|
|
327
440
|
|
|
328
|
-
if (effectiveType
|
|
441
|
+
if (isCompactionItemType(effectiveType)) {
|
|
329
442
|
// A stored summary from a previous compaction. Decode our ocx1 envelope into plain text so
|
|
330
443
|
// the routed model keeps the compacted context; real OpenAI-encrypted blobs degrade to a note.
|
|
331
444
|
// `context_compaction` (encrypted_content optional) is codex-rs's local-compaction marker;
|
|
@@ -416,6 +529,18 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
416
529
|
: null;
|
|
417
530
|
const thinkingText = envelope?.txt || text;
|
|
418
531
|
|
|
532
|
+
// Kiro reasoning round-trip: a krc-only item carries nothing renderable — it is provider
|
|
533
|
+
// state for the assistant turn that ALREADY closed, because Kiro emits its
|
|
534
|
+
// reasoningContentEvent at the END of a turn (after content AND tool calls, verified
|
|
535
|
+
// against kiro-cli 2.14.1/2.16.0). Folding it into the FOLLOWING turn like ordinary
|
|
536
|
+
// reasoning would attach turn N's blob to turn N+1, so attach it backwards instead. With
|
|
537
|
+
// no assistant turn to own it the blob is dropped rather than mis-paired.
|
|
538
|
+
if (envelope?.krc && thinkingText.length === 0) {
|
|
539
|
+
const previous = messages[messages.length - 1];
|
|
540
|
+
if (previous?.role === "assistant") previous.kiroRedactedReasoning = envelope.krc;
|
|
541
|
+
continue;
|
|
542
|
+
}
|
|
543
|
+
|
|
419
544
|
// Native/non-ocxr1 encrypted-only reasoning is opaque here. Do not create a detached
|
|
420
545
|
// assistant turn or invent replayable plaintext/signatures from the encrypted payload.
|
|
421
546
|
if (thinkingText.length > 0) {
|
|
@@ -442,7 +567,7 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
442
567
|
}
|
|
443
568
|
|
|
444
569
|
if (effectiveType === "function_call") {
|
|
445
|
-
const call = item as { id?: string; call_id: string; name: string; arguments?: string; namespace?: string };
|
|
570
|
+
const call = item as { id?: string; call_id: string; name: string; arguments?: string; namespace?: string; extra_content?: unknown };
|
|
446
571
|
// Tolerate empty/non-JSON arguments (e.g. a no-arg tool call serialized as "") instead of
|
|
447
572
|
// throwing — a single poisoned history item would otherwise 400 every subsequent turn.
|
|
448
573
|
let args: Record<string, unknown> = {};
|
|
@@ -463,16 +588,32 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
463
588
|
type: "toolCall", id: call.call_id, name: call.name, arguments: args,
|
|
464
589
|
...(call.namespace ? { namespace: call.namespace } : {}),
|
|
465
590
|
};
|
|
591
|
+
// Provider-opaque metadata (e.g. a Gemini thought signature) travels with the call so a
|
|
592
|
+
// history-replayed or previous_response_id turn rebuilds the same signed part instead of
|
|
593
|
+
// depending on the same-process replay cache (issue #1735). Real clients do not echo
|
|
594
|
+
// extra_content on replay, so fall back to the proxy-side store keyed by call_id.
|
|
595
|
+
const providerMetadata = providerMetadataFromResponsesFunctionCall(call)
|
|
596
|
+
?? (typeof call.call_id === "string"
|
|
597
|
+
? replayThoughtSignatureMetadata(call.call_id, replayCacheScope)
|
|
598
|
+
: undefined);
|
|
599
|
+
if (providerMetadata) toolCall.providerMetadata = providerMetadata;
|
|
466
600
|
assistantHolderWithReasoning().content.push(toolCall);
|
|
467
601
|
continue;
|
|
468
602
|
}
|
|
469
603
|
|
|
470
604
|
if (effectiveType === "custom_tool_call") {
|
|
471
605
|
const call = item as { id?: string; call_id: string; name: string; input: string };
|
|
606
|
+
const remembered = typeof call.call_id === "string" ? replayThoughtSignatureMetadata(call.call_id, replayCacheScope) : undefined;
|
|
607
|
+
// Reconstruct the namespace the request declared this tool under. The wire item
|
|
608
|
+
// carries only the bare name, so without this the round trip loses it and adapters
|
|
609
|
+
// replay the call as an unnamespaced tool the provider may not expose.
|
|
610
|
+
const customNamespace = customToolNamespacesByName.get(call.name);
|
|
472
611
|
const toolCall: OcxToolCall = {
|
|
473
612
|
type: "toolCall", id: call.call_id, name: call.name,
|
|
474
613
|
arguments: { input: call.input ?? "" },
|
|
475
614
|
customWireName: call.name,
|
|
615
|
+
...(customNamespace ? { namespace: customNamespace } : {}),
|
|
616
|
+
...(remembered ? { providerMetadata: remembered } : {}),
|
|
476
617
|
};
|
|
477
618
|
assistantHolderWithReasoning().content.push(toolCall);
|
|
478
619
|
continue;
|
|
@@ -485,9 +626,11 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
485
626
|
const callId = call.call_id ?? call.id;
|
|
486
627
|
if (callId) {
|
|
487
628
|
const command = Array.isArray(call.action?.command) ? call.action.command : [];
|
|
629
|
+
const remembered = replayThoughtSignatureMetadata(callId, replayCacheScope);
|
|
488
630
|
assistantHolderWithReasoning().content.push({
|
|
489
631
|
type: "toolCall", id: callId, name: "shell",
|
|
490
632
|
arguments: command.length > 0 ? { command } : {},
|
|
633
|
+
...(remembered ? { providerMetadata: remembered } : {}),
|
|
491
634
|
});
|
|
492
635
|
}
|
|
493
636
|
continue;
|
|
@@ -506,9 +649,11 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
506
649
|
// history stays complete (otherwise the model re-issues tool_search forever).
|
|
507
650
|
const call = item as { id?: string; call_id?: string; arguments?: unknown };
|
|
508
651
|
const callId = call.call_id ?? call.id ?? "";
|
|
652
|
+
const remembered = callId ? replayThoughtSignatureMetadata(callId, replayCacheScope) : undefined;
|
|
509
653
|
assistantHolderWithReasoning().content.push({
|
|
510
654
|
type: "toolCall", id: callId, name: "tool_search",
|
|
511
655
|
arguments: isObj(call.arguments) ? call.arguments : {},
|
|
656
|
+
...(remembered ? { providerMetadata: remembered } : {}),
|
|
512
657
|
});
|
|
513
658
|
continue;
|
|
514
659
|
}
|
|
@@ -545,8 +690,9 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
545
690
|
}
|
|
546
691
|
|
|
547
692
|
if (effectiveType === "function_call_output") {
|
|
548
|
-
pendingReasoning.length = 0;
|
|
549
693
|
const output = item as { call_id: string; output?: string | unknown[] };
|
|
694
|
+
attachPendingReasoningToCallOwner(messages, output.call_id, pendingReasoning);
|
|
695
|
+
pendingReasoning.length = 0;
|
|
550
696
|
const toolInfo = findToolById(messages, output.call_id);
|
|
551
697
|
messages.push({
|
|
552
698
|
role: "toolResult", toolCallId: output.call_id,
|
|
@@ -558,8 +704,9 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
558
704
|
}
|
|
559
705
|
|
|
560
706
|
if (effectiveType === "custom_tool_call_output") {
|
|
561
|
-
pendingReasoning.length = 0;
|
|
562
707
|
const output = item as { call_id: string; output: string | unknown[] };
|
|
708
|
+
attachPendingReasoningToCallOwner(messages, output.call_id, pendingReasoning);
|
|
709
|
+
pendingReasoning.length = 0;
|
|
563
710
|
const toolInfo = findToolById(messages, output.call_id);
|
|
564
711
|
messages.push({
|
|
565
712
|
role: "toolResult", toolCallId: output.call_id,
|
|
@@ -572,10 +719,22 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
572
719
|
}
|
|
573
720
|
}
|
|
574
721
|
}
|
|
722
|
+
if (data.previous_response_id && continuationConversationMessageIndex === undefined) {
|
|
723
|
+
continuationConversationMessageIndex = messages.length;
|
|
724
|
+
}
|
|
575
725
|
|
|
576
726
|
const declaredTools = buildTools(data.tools as unknown[] | undefined) ?? [];
|
|
577
727
|
const loadedTools = buildTools(loadedToolSpecs) ?? [];
|
|
578
728
|
const loadedToolNames = new Set(loadedTools.map(t => namespacedToolName(t.namespace, t.name)));
|
|
729
|
+
const wireOwners = new Map<string, OcxTool>();
|
|
730
|
+
for (const tool of [...declaredTools, ...loadedTools]) {
|
|
731
|
+
const wireName = namespacedToolName(tool.namespace, tool.name);
|
|
732
|
+
const previous = wireOwners.get(wireName);
|
|
733
|
+
if (previous && (previous.namespace !== tool.namespace || previous.name !== tool.name || previous.freeform !== tool.freeform || previous.toolSearch !== tool.toolSearch)) {
|
|
734
|
+
throw new Error(`ambiguous tool catalog: multiple logical tools map to wire name ${wireName}`);
|
|
735
|
+
}
|
|
736
|
+
wireOwners.set(wireName, tool);
|
|
737
|
+
}
|
|
579
738
|
const seenTools = new Set<string>();
|
|
580
739
|
const mergedTools = [...declaredTools, ...loadedTools]
|
|
581
740
|
.filter(t => {
|
|
@@ -601,6 +760,15 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
601
760
|
options.stopSequences = typeof data.stop === "string" ? [data.stop] : data.stop;
|
|
602
761
|
}
|
|
603
762
|
const tc = mapToolChoice(data.tool_choice);
|
|
763
|
+
if (tc && typeof tc === "object") {
|
|
764
|
+
const selectors = "allowedTools" in tc ? tc.allowedTools : [tc.name];
|
|
765
|
+
const resolver = createToolChoiceResolver(mergedTools);
|
|
766
|
+
for (const selector of selectors) {
|
|
767
|
+
if (resolver.candidateCount(selector) > 1) {
|
|
768
|
+
throw new Error(`ambiguous tool_choice name: ${selector}`);
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
}
|
|
604
772
|
if (tc !== undefined) options.toolChoice = tc;
|
|
605
773
|
if (data.parallel_tool_calls !== undefined) options.parallelToolCalls = data.parallel_tool_calls;
|
|
606
774
|
// Upstream codex-rs converts "ultra" to "max" at the inference boundary (core/src/client.rs
|
|
@@ -626,9 +794,12 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
626
794
|
...(data.tools as unknown[] ?? []),
|
|
627
795
|
...loadedToolSpecs,
|
|
628
796
|
]);
|
|
629
|
-
//
|
|
630
|
-
//
|
|
631
|
-
|
|
797
|
+
// Capture structured-output mode (Responses `text.format`): the format object rides
|
|
798
|
+
// options.textFormat for adapters whose wire has an equivalent (openai-chat response_format),
|
|
799
|
+
// while the `_structuredOutput` flag keeps the web-search sidecar rendering its tool_result
|
|
800
|
+
// as JSON rather than prose that could corrupt the model's schema-constrained answer.
|
|
801
|
+
const textFormat = parseTextFormat(data.text);
|
|
802
|
+
if (textFormat) options.textFormat = textFormat;
|
|
632
803
|
|
|
633
804
|
return {
|
|
634
805
|
modelId: data.model,
|
|
@@ -638,19 +809,35 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
638
809
|
options,
|
|
639
810
|
_rawBody: body,
|
|
640
811
|
...(replayedInputPrefixLength > 0 ? { _replayPrefixLen: replayedInputPrefixLength } : {}),
|
|
812
|
+
...(continuationConversationMessageIndex !== undefined
|
|
813
|
+
? { _continuationConversationMessageIndex: continuationConversationMessageIndex }
|
|
814
|
+
: {}),
|
|
641
815
|
...(webSearch ? { _webSearch: webSearch } : {}),
|
|
642
816
|
...(imageGen ? { _imageGeneration: imageGen } : {}),
|
|
643
|
-
...(
|
|
817
|
+
...(textFormat ? { _structuredOutput: true } : {}),
|
|
644
818
|
...(compactionRequest ? { _compactionRequest: true } : {}),
|
|
645
819
|
...(contextCompactionBoundary ? { _contextCompactionBoundary: true } : {}),
|
|
646
820
|
};
|
|
647
821
|
}
|
|
648
822
|
|
|
649
|
-
/**
|
|
650
|
-
|
|
651
|
-
|
|
823
|
+
/**
|
|
824
|
+
* The Responses `text.format` object when it requests structured output (json_schema or
|
|
825
|
+
* json_object), undefined otherwise. Acceptance is identical to the boolean detector this
|
|
826
|
+
* replaces; unknown or malformed formats are ignored, never rejected, so the native
|
|
827
|
+
* passthrough keeps forwarding whatever the caller sent via `_rawBody`.
|
|
828
|
+
*/
|
|
829
|
+
function parseTextFormat(text: unknown): OcxRequestOptions["textFormat"] {
|
|
830
|
+
if (!isObj(text)) return undefined;
|
|
652
831
|
const format = (text as { format?: unknown }).format;
|
|
653
|
-
if (!isObj(format)) return
|
|
654
|
-
const
|
|
655
|
-
|
|
832
|
+
if (!isObj(format)) return undefined;
|
|
833
|
+
const f = format as { type?: unknown; name?: unknown; description?: unknown; schema?: unknown; strict?: unknown };
|
|
834
|
+
if (f.type === "json_object") return { type: "json_object" };
|
|
835
|
+
if (f.type !== "json_schema") return undefined;
|
|
836
|
+
return {
|
|
837
|
+
type: "json_schema",
|
|
838
|
+
...(typeof f.name === "string" ? { name: f.name } : {}),
|
|
839
|
+
...(typeof f.description === "string" ? { description: f.description } : {}),
|
|
840
|
+
...(isObj(f.schema) ? { schema: f.schema as Record<string, unknown> } : {}),
|
|
841
|
+
...(typeof f.strict === "boolean" ? { strict: f.strict } : {}),
|
|
842
|
+
};
|
|
656
843
|
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
OcxProviderContinuationOwner,
|
|
3
|
+
OcxReasoningReplayIdentity,
|
|
4
|
+
} from "../types";
|
|
5
|
+
|
|
6
|
+
const bounded = (value: unknown, max: number): value is string =>
|
|
7
|
+
typeof value === "string" && value.length > 0 && value.length <= max;
|
|
8
|
+
|
|
9
|
+
const isPlainRecord = (value: unknown): value is Record<string, unknown> => {
|
|
10
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
11
|
+
const prototype = Object.getPrototypeOf(value);
|
|
12
|
+
return prototype === Object.prototype || prototype === null;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const defineOwn = (target: Record<string, unknown>, key: string, value: unknown): void => {
|
|
16
|
+
Object.defineProperty(target, key, {
|
|
17
|
+
value,
|
|
18
|
+
enumerable: true,
|
|
19
|
+
configurable: true,
|
|
20
|
+
writable: true,
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
/** Recursively merge provider-owned plain objects; arrays and scalar values replace prior state. */
|
|
25
|
+
export function mergeProviderContinuationPayload(
|
|
26
|
+
inherited: Readonly<Record<string, unknown>>,
|
|
27
|
+
emitted: Readonly<Record<string, unknown>>,
|
|
28
|
+
): Record<string, unknown> {
|
|
29
|
+
const merged: Record<string, unknown> = {};
|
|
30
|
+
for (const [key, value] of Object.entries(inherited)) defineOwn(merged, key, value);
|
|
31
|
+
for (const [key, value] of Object.entries(emitted)) {
|
|
32
|
+
const prior = Object.hasOwn(merged, key) ? merged[key] : undefined;
|
|
33
|
+
defineOwn(
|
|
34
|
+
merged,
|
|
35
|
+
key,
|
|
36
|
+
isPlainRecord(prior) && isPlainRecord(value)
|
|
37
|
+
? mergeProviderContinuationPayload(prior, value)
|
|
38
|
+
: value,
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
return merged;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Validate proxy-authored continuation ownership before trusting persisted state. */
|
|
45
|
+
export function isValidProviderContinuationOwner(
|
|
46
|
+
value: unknown,
|
|
47
|
+
): value is OcxProviderContinuationOwner {
|
|
48
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
49
|
+
const owner = value as Record<string, unknown>;
|
|
50
|
+
return owner.version === 1
|
|
51
|
+
&& bounded(owner.providerName, 256)
|
|
52
|
+
&& typeof owner.providerDestinationIdentity === "string"
|
|
53
|
+
&& /^destination:[0-9a-f]{64}$/.test(owner.providerDestinationIdentity)
|
|
54
|
+
&& bounded(owner.adapterName, 128)
|
|
55
|
+
&& bounded(owner.modelId, 512)
|
|
56
|
+
&& typeof owner.credentialIdentity === "string"
|
|
57
|
+
&& /^(key|oauth|codex):[0-9a-f]{64}$/.test(owner.credentialIdentity);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Reuse the exact process-local route identity already established for reasoning replay. */
|
|
61
|
+
export function providerContinuationOwnerFromReplayIdentity(
|
|
62
|
+
identity: Readonly<OcxReasoningReplayIdentity> | undefined,
|
|
63
|
+
): OcxProviderContinuationOwner | undefined {
|
|
64
|
+
if (!identity) return undefined;
|
|
65
|
+
const owner: OcxProviderContinuationOwner = {
|
|
66
|
+
version: 1,
|
|
67
|
+
providerName: identity.providerName,
|
|
68
|
+
providerDestinationIdentity: identity.providerDestinationIdentity,
|
|
69
|
+
adapterName: identity.adapterName,
|
|
70
|
+
modelId: identity.modelId,
|
|
71
|
+
credentialIdentity: identity.credentialIdentity,
|
|
72
|
+
};
|
|
73
|
+
return isValidProviderContinuationOwner(owner) ? owner : undefined;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export function sameProviderContinuationOwner(
|
|
77
|
+
left: OcxProviderContinuationOwner,
|
|
78
|
+
right: OcxProviderContinuationOwner,
|
|
79
|
+
): boolean {
|
|
80
|
+
return left.version === right.version
|
|
81
|
+
&& left.providerName === right.providerName
|
|
82
|
+
&& left.providerDestinationIdentity === right.providerDestinationIdentity
|
|
83
|
+
&& left.adapterName === right.adapterName
|
|
84
|
+
&& left.modelId === right.modelId
|
|
85
|
+
&& left.credentialIdentity === right.credentialIdentity;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Cursor hashes this non-secret namespace with the client thread id. */
|
|
89
|
+
export function providerContinuationRouteScope(owner: OcxProviderContinuationOwner): string {
|
|
90
|
+
return JSON.stringify([
|
|
91
|
+
"provider-continuation-v1",
|
|
92
|
+
owner.providerName,
|
|
93
|
+
owner.providerDestinationIdentity,
|
|
94
|
+
owner.adapterName,
|
|
95
|
+
owner.modelId,
|
|
96
|
+
owner.credentialIdentity,
|
|
97
|
+
]);
|
|
98
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider-opaque tool-call metadata across the Responses boundary (issue #1735).
|
|
3
|
+
*
|
|
4
|
+
* Gemini issues a `thoughtSignature` on the exact part that carries a function call, and the
|
|
5
|
+
* next request is only valid if that signature comes back on the part rebuilt from that same
|
|
6
|
+
* call. Every synthetic loop in this proxy (web search, images, continuation replay) tears a
|
|
7
|
+
* tool call down into id/name/arguments and builds a fresh one, which silently dropped the
|
|
8
|
+
* signature and left only the same-process replay cache to paper over it. History replay and
|
|
9
|
+
* `previous_response_id` had no cache to fall back on.
|
|
10
|
+
*
|
|
11
|
+
* This module is the single seam where that metadata crosses into and out of the Responses
|
|
12
|
+
* wire, so a loop that rebuilds a call only has to carry one field instead of knowing about
|
|
13
|
+
* any provider. Values are treated as opaque: never parsed, merged, re-encoded, or synthesized.
|
|
14
|
+
*/
|
|
15
|
+
import type { OcxProviderOpaqueToolCallMetadata } from "../types";
|
|
16
|
+
|
|
17
|
+
/** Wire shape: `extra_content.google.thought_signature` on a Responses function_call item. */
|
|
18
|
+
interface ResponsesExtraContent {
|
|
19
|
+
google?: { thought_signature?: unknown };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function isObj(value: unknown): value is Record<string, unknown> {
|
|
23
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Same ceiling the Antigravity replay cache already enforces on a stored signature. An opaque
|
|
28
|
+
* token this large is not a real signature, and accepting it would let a caller push unbounded
|
|
29
|
+
* state through history replay.
|
|
30
|
+
*/
|
|
31
|
+
const MAX_SIGNATURE_BYTES = 64 * 1024;
|
|
32
|
+
|
|
33
|
+
export function isCarryableSignature(value: unknown): value is string {
|
|
34
|
+
if (typeof value !== "string" || value.length === 0) return false;
|
|
35
|
+
// Cheap length pre-check: UTF-8 is at most 3 bytes per UTF-16 code unit for the BMP, so this
|
|
36
|
+
// skips the encode for the overwhelmingly common short case.
|
|
37
|
+
if (value.length <= MAX_SIGNATURE_BYTES / 3) return true;
|
|
38
|
+
return Buffer.byteLength(value, "utf8") <= MAX_SIGNATURE_BYTES;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Read provider metadata off an inbound Responses function_call item. */
|
|
42
|
+
export function providerMetadataFromResponsesFunctionCall(
|
|
43
|
+
item: { extra_content?: unknown } | undefined,
|
|
44
|
+
): OcxProviderOpaqueToolCallMetadata | undefined {
|
|
45
|
+
const extra = item?.extra_content;
|
|
46
|
+
if (!isObj(extra)) return undefined;
|
|
47
|
+
const google = (extra as ResponsesExtraContent).google;
|
|
48
|
+
if (!isObj(google)) return undefined;
|
|
49
|
+
const signature = google.thought_signature;
|
|
50
|
+
if (!isCarryableSignature(signature)) return undefined;
|
|
51
|
+
return { google: { thoughtSignature: signature } };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Serialize provider metadata onto an outbound Responses function_call item. */
|
|
55
|
+
export function responsesExtraContentFromProviderMetadata(
|
|
56
|
+
metadata: OcxProviderOpaqueToolCallMetadata | undefined,
|
|
57
|
+
): { extra_content: { google: { thought_signature: string } } } | undefined {
|
|
58
|
+
const signature = metadata?.google?.thoughtSignature;
|
|
59
|
+
if (!isCarryableSignature(signature)) return undefined;
|
|
60
|
+
return { extra_content: { google: { thought_signature: signature } } };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Copy metadata for a rebuilt tool call. A signature belongs to one specific part, so a loop
|
|
65
|
+
* that fans one model response into several calls must copy per call and never share or merge.
|
|
66
|
+
*/
|
|
67
|
+
export function cloneProviderOpaqueToolCallMetadata(
|
|
68
|
+
metadata: OcxProviderOpaqueToolCallMetadata | undefined,
|
|
69
|
+
): OcxProviderOpaqueToolCallMetadata | undefined {
|
|
70
|
+
const signature = metadata?.google?.thoughtSignature;
|
|
71
|
+
if (!isCarryableSignature(signature)) return undefined;
|
|
72
|
+
return { google: { thoughtSignature: signature } };
|
|
73
|
+
}
|
|
@@ -24,6 +24,12 @@ export interface ReasoningEnvelope {
|
|
|
24
24
|
* so replay needs it even though the visible summary was suppressed.
|
|
25
25
|
*/
|
|
26
26
|
txt?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Kiro `reasoningContentEvent.redactedContent`: a KMS-encrypted reasoning blob that is opaque to
|
|
29
|
+
* the proxy. Kiro's own CLI replays it on the matching `assistantResponseMessage` to preserve
|
|
30
|
+
* model reasoning across turns, so it round-trips here the same way a signature does.
|
|
31
|
+
*/
|
|
32
|
+
krc?: string;
|
|
27
33
|
}
|
|
28
34
|
|
|
29
35
|
export function encodeReasoningEnvelope(envelope: ReasoningEnvelope): string {
|
|
@@ -45,7 +51,9 @@ export function decodeReasoningEnvelope(encryptedContent: string): ReasoningEnve
|
|
|
45
51
|
}
|
|
46
52
|
const txt = (parsed as { txt?: unknown }).txt;
|
|
47
53
|
if (typeof txt === "string" && txt.length > 0) envelope.txt = txt;
|
|
48
|
-
|
|
54
|
+
const krc = (parsed as { krc?: unknown }).krc;
|
|
55
|
+
if (typeof krc === "string" && krc.length > 0) envelope.krc = krc;
|
|
56
|
+
return envelope.sig || envelope.red || envelope.txt || envelope.krc ? envelope : null;
|
|
49
57
|
} catch {
|
|
50
58
|
return null;
|
|
51
59
|
}
|