@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/responses/parser.ts
CHANGED
|
@@ -9,19 +9,38 @@ import type {
|
|
|
9
9
|
OcxThinkingContent,
|
|
10
10
|
OcxTool,
|
|
11
11
|
OcxToolCall,
|
|
12
|
+
OcxReasoningReplayScopeRef,
|
|
12
13
|
} from "../types";
|
|
13
|
-
import { namespacedToolName } from "../types";
|
|
14
|
+
import { namespacedToolName, toolChoiceCandidates } 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 }
|
|
@@ -151,43 +170,53 @@ function buildTools(tools: unknown[] | undefined): OcxTool[] | undefined {
|
|
|
151
170
|
if (namespace) tool.namespace = namespace;
|
|
152
171
|
out.push(tool);
|
|
153
172
|
};
|
|
173
|
+
const pushCustom = (t: Record<string, unknown>, namespace?: string) => {
|
|
174
|
+
// Freeform custom tools are lowered to a single string `input` because chat models cannot
|
|
175
|
+
// emit Responses grammar payloads directly. Keep tool-specific input guidance scoped to the
|
|
176
|
+
// tool that owns it: leaking apply_patch syntax into `exec` or another freeform tool teaches
|
|
177
|
+
// routed models that the nested helper name is itself a callable top-level tool.
|
|
178
|
+
const inputDescription = t.name === "apply_patch"
|
|
179
|
+
? "Raw tool input. For apply_patch, begin exactly with `*** Begin Patch` (no trailing `***`), then use its standard patch envelope."
|
|
180
|
+
: "Raw freeform input for this tool.";
|
|
181
|
+
const tool: OcxTool = {
|
|
182
|
+
name: t.name as string,
|
|
183
|
+
description: (t.description as string) ?? "",
|
|
184
|
+
parameters: { type: "object", properties: { input: { type: "string", description: inputDescription } }, required: ["input"] },
|
|
185
|
+
freeform: true,
|
|
186
|
+
};
|
|
187
|
+
if (namespace) tool.namespace = namespace;
|
|
188
|
+
out.push(tool);
|
|
189
|
+
};
|
|
154
190
|
for (const t of tools) {
|
|
155
191
|
if (!isObj(t)) continue;
|
|
192
|
+
if (t.type === "function" && isObj(t.function) && typeof t.function.name === "string" && t.function.name.length > 0) {
|
|
193
|
+
pushFn(t.function as Record<string, unknown>);
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
156
196
|
if (t.type === "function" && typeof t.name === "string") {
|
|
157
197
|
pushFn(t);
|
|
158
198
|
} else if (t.type === "namespace" && Array.isArray(t.tools)) {
|
|
159
|
-
//
|
|
160
|
-
//
|
|
161
|
-
|
|
199
|
+
// Codex 0.147 groups its ordinary client tools under the reserved `functions` namespace,
|
|
200
|
+
// including freeform custom tools such as code-mode `exec`. Those children are still
|
|
201
|
+
// top-level Responses tools, so flatten them without a namespace. Other namespace groups
|
|
202
|
+
// are MCP-style and keep their namespace for round-trip routing.
|
|
203
|
+
const builtinFunctions = t.name === "functions";
|
|
204
|
+
const ns = typeof t.name === "string" && !builtinFunctions ? t.name : undefined;
|
|
162
205
|
for (const inner of t.tools as unknown[]) {
|
|
163
206
|
if (isObj(inner) && inner.type === "function" && typeof inner.name === "string") pushFn(inner, ns);
|
|
207
|
+
else if (isObj(inner) && inner.type === "custom" && typeof inner.name === "string") pushCustom(inner, ns);
|
|
164
208
|
}
|
|
165
209
|
}
|
|
166
210
|
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
|
-
});
|
|
211
|
+
pushCustom(t);
|
|
176
212
|
}
|
|
177
213
|
else if (t.type === "tool_search") {
|
|
178
214
|
// Client-executed tool discovery — the gateway to deferred tools (subagents, extra MCP tools).
|
|
179
215
|
// Expose as a function so chat models can call it; the bridge relays it as a tool_search_call.
|
|
180
216
|
out.push({
|
|
181
217
|
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>,
|
|
218
|
+
description: toolSearchDescription(t),
|
|
219
|
+
parameters: normalizeParameters(toolSearchParameters(t)),
|
|
191
220
|
toolSearch: true,
|
|
192
221
|
});
|
|
193
222
|
}
|
|
@@ -263,9 +292,70 @@ function findToolById(messages: OcxMessage[], callId: string): { name: string; n
|
|
|
263
292
|
return { name: "" };
|
|
264
293
|
}
|
|
265
294
|
|
|
295
|
+
/**
|
|
296
|
+
* Attach pending reasoning to the assistant turn that owns the given call id.
|
|
297
|
+
* Reconstructed histories (resume/retry/synthetic) can order a `reasoning`
|
|
298
|
+
* item AFTER the `function_call` it belongs to; without this, the pending
|
|
299
|
+
* buffer is cleared at the tool output and the turn serializes without
|
|
300
|
+
* `reasoning_content`, which DeepSeek thinking mode rejects with HTTP 400
|
|
301
|
+
* (issue #950).
|
|
302
|
+
*/
|
|
303
|
+
function attachPendingReasoningToCallOwner(
|
|
304
|
+
messages: OcxMessage[],
|
|
305
|
+
callId: string,
|
|
306
|
+
pendingReasoning: Array<{ part: OcxThinkingContent; envelopeSigned: boolean }>,
|
|
307
|
+
): void {
|
|
308
|
+
if (pendingReasoning.length === 0 || !callId) return;
|
|
309
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
310
|
+
const m = messages[i];
|
|
311
|
+
if (m.role !== "assistant") continue;
|
|
312
|
+
for (const part of m.content) {
|
|
313
|
+
if (part.type === "toolCall" && part.id === callId) {
|
|
314
|
+
// Prepend so thinking still precedes tool_use for adapters that require
|
|
315
|
+
// that ordering (Anthropic-style replay).
|
|
316
|
+
m.content = [...pendingReasoning.map(entry => entry.part), ...m.content];
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
266
323
|
const REASONING_EFFORTS = new Set(["none", "minimal", "low", "medium", "high", "xhigh", "max"]);
|
|
267
324
|
|
|
268
|
-
|
|
325
|
+
/**
|
|
326
|
+
* Namespace a custom tool was declared under, by its bare name.
|
|
327
|
+
*
|
|
328
|
+
* A `custom_tool_call` echoed back by the client carries only the bare name — the bridge
|
|
329
|
+
* emits `{"type":"custom_tool_call","name":"exec"}` even when the tool was declared as
|
|
330
|
+
* `mcp__functions__exec`. Without this lookup the namespace is lost on the return trip,
|
|
331
|
+
* and the adapters replay history through `namespacedToolName(namespace, name)`, which
|
|
332
|
+
* then produces a bare `exec` the provider may not have. Ordinary `function_call` items
|
|
333
|
+
* do not need this: they carry `namespace` on the wire.
|
|
334
|
+
*/
|
|
335
|
+
function customToolNamespaces(tools: unknown): Map<string, string> {
|
|
336
|
+
const out = new Map<string, string>();
|
|
337
|
+
if (!Array.isArray(tools)) return out;
|
|
338
|
+
for (const spec of tools) {
|
|
339
|
+
if (!isObj(spec) || spec.type !== "namespace" || !Array.isArray(spec.tools)) continue;
|
|
340
|
+
const namespace = typeof spec.name === "string" ? spec.name : undefined;
|
|
341
|
+
// Codex 0.147 groups ordinary client tools under the reserved `functions` namespace and
|
|
342
|
+
// buildTools deliberately flattens those without a namespace. Mirror that here, or the
|
|
343
|
+
// reconstruction would invent a namespace the request never advertised.
|
|
344
|
+
if (!namespace || namespace === "functions") continue;
|
|
345
|
+
for (const inner of spec.tools) {
|
|
346
|
+
if (!isObj(inner) || inner.type !== "custom" || typeof inner.name !== "string") continue;
|
|
347
|
+
// Ambiguous bare names are already rejected upstream, so first declaration wins.
|
|
348
|
+
if (!out.has(inner.name)) out.set(inner.name, namespace);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
return out;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
export function parseRequest(
|
|
355
|
+
body: unknown,
|
|
356
|
+
parseOptions?: { replayCacheScope?: OcxReasoningReplayScopeRef },
|
|
357
|
+
): OcxParsedRequest {
|
|
358
|
+
const replayCacheScope = parseOptions?.replayCacheScope;
|
|
269
359
|
const replayedInputPrefixLength = previousResponseReplayPrefixLength(body);
|
|
270
360
|
const parsed = responsesRequestSchema.safeParse(body);
|
|
271
361
|
if (!parsed.success) {
|
|
@@ -274,6 +364,9 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
274
364
|
const data = parsed.data;
|
|
275
365
|
const now = Date.now();
|
|
276
366
|
const messages: OcxMessage[] = [];
|
|
367
|
+
// Built before the item loop: a custom_tool_call echoed back in `input` needs the
|
|
368
|
+
// namespace from the request's own tool catalog to survive the round trip.
|
|
369
|
+
const customToolNamespacesByName = customToolNamespaces(data.tools);
|
|
277
370
|
const systemPrompt: string[] = [];
|
|
278
371
|
// Responses reasoning siblings belong to the following assistant, including across call items.
|
|
279
372
|
// Keep them off the message list until that assistant arrives; turn boundaries clear the array.
|
|
@@ -296,17 +389,33 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
296
389
|
// synthetic `{type:"compaction"}` output item (src/responses/compaction.ts). Flagged for the server.
|
|
297
390
|
let compactionRequest = false;
|
|
298
391
|
let contextCompactionBoundary = false;
|
|
392
|
+
let continuationConversationMessageIndex: number | undefined;
|
|
299
393
|
|
|
300
394
|
if (typeof data.instructions === "string" && data.instructions.length > 0) {
|
|
301
395
|
systemPrompt.push(data.instructions);
|
|
302
396
|
}
|
|
303
397
|
|
|
304
398
|
if (typeof data.input === "string") {
|
|
399
|
+
if (data.previous_response_id) continuationConversationMessageIndex = messages.length;
|
|
305
400
|
messages.push({ role: "user", content: data.input, timestamp: now });
|
|
306
401
|
} else if (data.input) {
|
|
307
402
|
for (let inputIndex = 0; inputIndex < data.input.length; inputIndex++) {
|
|
308
403
|
const item = data.input[inputIndex];
|
|
309
404
|
const effectiveType = (item as { type?: string }).type ?? ("role" in item ? "message" : undefined);
|
|
405
|
+
const itemRole = (item as { role?: string }).role;
|
|
406
|
+
// Raw protocol items do not map one-to-one onto context messages. Capture the boundary while
|
|
407
|
+
// both representations are available so later metadata can stay before conversation in both.
|
|
408
|
+
if (
|
|
409
|
+
data.previous_response_id
|
|
410
|
+
&& inputIndex >= replayedInputPrefixLength
|
|
411
|
+
&& continuationConversationMessageIndex === undefined
|
|
412
|
+
&& (
|
|
413
|
+
effectiveType === "agent_message"
|
|
414
|
+
|| (effectiveType === "message" && (itemRole === "user" || itemRole === "assistant"))
|
|
415
|
+
)
|
|
416
|
+
) {
|
|
417
|
+
continuationConversationMessageIndex = messages.length;
|
|
418
|
+
}
|
|
310
419
|
|
|
311
420
|
if (effectiveType === "compaction_trigger") {
|
|
312
421
|
compactionRequest = true;
|
|
@@ -325,7 +434,7 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
325
434
|
continue;
|
|
326
435
|
}
|
|
327
436
|
|
|
328
|
-
if (effectiveType
|
|
437
|
+
if (isCompactionItemType(effectiveType)) {
|
|
329
438
|
// A stored summary from a previous compaction. Decode our ocx1 envelope into plain text so
|
|
330
439
|
// the routed model keeps the compacted context; real OpenAI-encrypted blobs degrade to a note.
|
|
331
440
|
// `context_compaction` (encrypted_content optional) is codex-rs's local-compaction marker;
|
|
@@ -416,6 +525,18 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
416
525
|
: null;
|
|
417
526
|
const thinkingText = envelope?.txt || text;
|
|
418
527
|
|
|
528
|
+
// Kiro reasoning round-trip: a krc-only item carries nothing renderable — it is provider
|
|
529
|
+
// state for the assistant turn that ALREADY closed, because Kiro emits its
|
|
530
|
+
// reasoningContentEvent at the END of a turn (after content AND tool calls, verified
|
|
531
|
+
// against kiro-cli 2.14.1/2.16.0). Folding it into the FOLLOWING turn like ordinary
|
|
532
|
+
// reasoning would attach turn N's blob to turn N+1, so attach it backwards instead. With
|
|
533
|
+
// no assistant turn to own it the blob is dropped rather than mis-paired.
|
|
534
|
+
if (envelope?.krc && thinkingText.length === 0) {
|
|
535
|
+
const previous = messages[messages.length - 1];
|
|
536
|
+
if (previous?.role === "assistant") previous.kiroRedactedReasoning = envelope.krc;
|
|
537
|
+
continue;
|
|
538
|
+
}
|
|
539
|
+
|
|
419
540
|
// Native/non-ocxr1 encrypted-only reasoning is opaque here. Do not create a detached
|
|
420
541
|
// assistant turn or invent replayable plaintext/signatures from the encrypted payload.
|
|
421
542
|
if (thinkingText.length > 0) {
|
|
@@ -442,7 +563,7 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
442
563
|
}
|
|
443
564
|
|
|
444
565
|
if (effectiveType === "function_call") {
|
|
445
|
-
const call = item as { id?: string; call_id: string; name: string; arguments?: string; namespace?: string };
|
|
566
|
+
const call = item as { id?: string; call_id: string; name: string; arguments?: string; namespace?: string; extra_content?: unknown };
|
|
446
567
|
// Tolerate empty/non-JSON arguments (e.g. a no-arg tool call serialized as "") instead of
|
|
447
568
|
// throwing — a single poisoned history item would otherwise 400 every subsequent turn.
|
|
448
569
|
let args: Record<string, unknown> = {};
|
|
@@ -463,16 +584,32 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
463
584
|
type: "toolCall", id: call.call_id, name: call.name, arguments: args,
|
|
464
585
|
...(call.namespace ? { namespace: call.namespace } : {}),
|
|
465
586
|
};
|
|
587
|
+
// Provider-opaque metadata (e.g. a Gemini thought signature) travels with the call so a
|
|
588
|
+
// history-replayed or previous_response_id turn rebuilds the same signed part instead of
|
|
589
|
+
// depending on the same-process replay cache (issue #1735). Real clients do not echo
|
|
590
|
+
// extra_content on replay, so fall back to the proxy-side store keyed by call_id.
|
|
591
|
+
const providerMetadata = providerMetadataFromResponsesFunctionCall(call)
|
|
592
|
+
?? (typeof call.call_id === "string"
|
|
593
|
+
? replayThoughtSignatureMetadata(call.call_id, replayCacheScope)
|
|
594
|
+
: undefined);
|
|
595
|
+
if (providerMetadata) toolCall.providerMetadata = providerMetadata;
|
|
466
596
|
assistantHolderWithReasoning().content.push(toolCall);
|
|
467
597
|
continue;
|
|
468
598
|
}
|
|
469
599
|
|
|
470
600
|
if (effectiveType === "custom_tool_call") {
|
|
471
601
|
const call = item as { id?: string; call_id: string; name: string; input: string };
|
|
602
|
+
const remembered = typeof call.call_id === "string" ? replayThoughtSignatureMetadata(call.call_id, replayCacheScope) : undefined;
|
|
603
|
+
// Reconstruct the namespace the request declared this tool under. The wire item
|
|
604
|
+
// carries only the bare name, so without this the round trip loses it and adapters
|
|
605
|
+
// replay the call as an unnamespaced tool the provider may not expose.
|
|
606
|
+
const customNamespace = customToolNamespacesByName.get(call.name);
|
|
472
607
|
const toolCall: OcxToolCall = {
|
|
473
608
|
type: "toolCall", id: call.call_id, name: call.name,
|
|
474
609
|
arguments: { input: call.input ?? "" },
|
|
475
610
|
customWireName: call.name,
|
|
611
|
+
...(customNamespace ? { namespace: customNamespace } : {}),
|
|
612
|
+
...(remembered ? { providerMetadata: remembered } : {}),
|
|
476
613
|
};
|
|
477
614
|
assistantHolderWithReasoning().content.push(toolCall);
|
|
478
615
|
continue;
|
|
@@ -485,9 +622,11 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
485
622
|
const callId = call.call_id ?? call.id;
|
|
486
623
|
if (callId) {
|
|
487
624
|
const command = Array.isArray(call.action?.command) ? call.action.command : [];
|
|
625
|
+
const remembered = replayThoughtSignatureMetadata(callId, replayCacheScope);
|
|
488
626
|
assistantHolderWithReasoning().content.push({
|
|
489
627
|
type: "toolCall", id: callId, name: "shell",
|
|
490
628
|
arguments: command.length > 0 ? { command } : {},
|
|
629
|
+
...(remembered ? { providerMetadata: remembered } : {}),
|
|
491
630
|
});
|
|
492
631
|
}
|
|
493
632
|
continue;
|
|
@@ -506,9 +645,11 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
506
645
|
// history stays complete (otherwise the model re-issues tool_search forever).
|
|
507
646
|
const call = item as { id?: string; call_id?: string; arguments?: unknown };
|
|
508
647
|
const callId = call.call_id ?? call.id ?? "";
|
|
648
|
+
const remembered = callId ? replayThoughtSignatureMetadata(callId, replayCacheScope) : undefined;
|
|
509
649
|
assistantHolderWithReasoning().content.push({
|
|
510
650
|
type: "toolCall", id: callId, name: "tool_search",
|
|
511
651
|
arguments: isObj(call.arguments) ? call.arguments : {},
|
|
652
|
+
...(remembered ? { providerMetadata: remembered } : {}),
|
|
512
653
|
});
|
|
513
654
|
continue;
|
|
514
655
|
}
|
|
@@ -545,8 +686,9 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
545
686
|
}
|
|
546
687
|
|
|
547
688
|
if (effectiveType === "function_call_output") {
|
|
548
|
-
pendingReasoning.length = 0;
|
|
549
689
|
const output = item as { call_id: string; output?: string | unknown[] };
|
|
690
|
+
attachPendingReasoningToCallOwner(messages, output.call_id, pendingReasoning);
|
|
691
|
+
pendingReasoning.length = 0;
|
|
550
692
|
const toolInfo = findToolById(messages, output.call_id);
|
|
551
693
|
messages.push({
|
|
552
694
|
role: "toolResult", toolCallId: output.call_id,
|
|
@@ -558,8 +700,9 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
558
700
|
}
|
|
559
701
|
|
|
560
702
|
if (effectiveType === "custom_tool_call_output") {
|
|
561
|
-
pendingReasoning.length = 0;
|
|
562
703
|
const output = item as { call_id: string; output: string | unknown[] };
|
|
704
|
+
attachPendingReasoningToCallOwner(messages, output.call_id, pendingReasoning);
|
|
705
|
+
pendingReasoning.length = 0;
|
|
563
706
|
const toolInfo = findToolById(messages, output.call_id);
|
|
564
707
|
messages.push({
|
|
565
708
|
role: "toolResult", toolCallId: output.call_id,
|
|
@@ -572,10 +715,22 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
572
715
|
}
|
|
573
716
|
}
|
|
574
717
|
}
|
|
718
|
+
if (data.previous_response_id && continuationConversationMessageIndex === undefined) {
|
|
719
|
+
continuationConversationMessageIndex = messages.length;
|
|
720
|
+
}
|
|
575
721
|
|
|
576
722
|
const declaredTools = buildTools(data.tools as unknown[] | undefined) ?? [];
|
|
577
723
|
const loadedTools = buildTools(loadedToolSpecs) ?? [];
|
|
578
724
|
const loadedToolNames = new Set(loadedTools.map(t => namespacedToolName(t.namespace, t.name)));
|
|
725
|
+
const wireOwners = new Map<string, OcxTool>();
|
|
726
|
+
for (const tool of [...declaredTools, ...loadedTools]) {
|
|
727
|
+
const wireName = namespacedToolName(tool.namespace, tool.name);
|
|
728
|
+
const previous = wireOwners.get(wireName);
|
|
729
|
+
if (previous && (previous.namespace !== tool.namespace || previous.name !== tool.name || previous.freeform !== tool.freeform || previous.toolSearch !== tool.toolSearch)) {
|
|
730
|
+
throw new Error(`ambiguous tool catalog: multiple logical tools map to wire name ${wireName}`);
|
|
731
|
+
}
|
|
732
|
+
wireOwners.set(wireName, tool);
|
|
733
|
+
}
|
|
579
734
|
const seenTools = new Set<string>();
|
|
580
735
|
const mergedTools = [...declaredTools, ...loadedTools]
|
|
581
736
|
.filter(t => {
|
|
@@ -601,6 +756,14 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
601
756
|
options.stopSequences = typeof data.stop === "string" ? [data.stop] : data.stop;
|
|
602
757
|
}
|
|
603
758
|
const tc = mapToolChoice(data.tool_choice);
|
|
759
|
+
if (tc && typeof tc === "object") {
|
|
760
|
+
const selectors = "allowedTools" in tc ? tc.allowedTools : [tc.name];
|
|
761
|
+
for (const selector of selectors) {
|
|
762
|
+
if (toolChoiceCandidates(mergedTools, selector).length > 1) {
|
|
763
|
+
throw new Error(`ambiguous tool_choice name: ${selector}`);
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
}
|
|
604
767
|
if (tc !== undefined) options.toolChoice = tc;
|
|
605
768
|
if (data.parallel_tool_calls !== undefined) options.parallelToolCalls = data.parallel_tool_calls;
|
|
606
769
|
// Upstream codex-rs converts "ultra" to "max" at the inference boundary (core/src/client.rs
|
|
@@ -626,9 +789,12 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
626
789
|
...(data.tools as unknown[] ?? []),
|
|
627
790
|
...loadedToolSpecs,
|
|
628
791
|
]);
|
|
629
|
-
//
|
|
630
|
-
//
|
|
631
|
-
|
|
792
|
+
// Capture structured-output mode (Responses `text.format`): the format object rides
|
|
793
|
+
// options.textFormat for adapters whose wire has an equivalent (openai-chat response_format),
|
|
794
|
+
// while the `_structuredOutput` flag keeps the web-search sidecar rendering its tool_result
|
|
795
|
+
// as JSON rather than prose that could corrupt the model's schema-constrained answer.
|
|
796
|
+
const textFormat = parseTextFormat(data.text);
|
|
797
|
+
if (textFormat) options.textFormat = textFormat;
|
|
632
798
|
|
|
633
799
|
return {
|
|
634
800
|
modelId: data.model,
|
|
@@ -638,19 +804,35 @@ export function parseRequest(body: unknown): OcxParsedRequest {
|
|
|
638
804
|
options,
|
|
639
805
|
_rawBody: body,
|
|
640
806
|
...(replayedInputPrefixLength > 0 ? { _replayPrefixLen: replayedInputPrefixLength } : {}),
|
|
807
|
+
...(continuationConversationMessageIndex !== undefined
|
|
808
|
+
? { _continuationConversationMessageIndex: continuationConversationMessageIndex }
|
|
809
|
+
: {}),
|
|
641
810
|
...(webSearch ? { _webSearch: webSearch } : {}),
|
|
642
811
|
...(imageGen ? { _imageGeneration: imageGen } : {}),
|
|
643
|
-
...(
|
|
812
|
+
...(textFormat ? { _structuredOutput: true } : {}),
|
|
644
813
|
...(compactionRequest ? { _compactionRequest: true } : {}),
|
|
645
814
|
...(contextCompactionBoundary ? { _contextCompactionBoundary: true } : {}),
|
|
646
815
|
};
|
|
647
816
|
}
|
|
648
817
|
|
|
649
|
-
/**
|
|
650
|
-
|
|
651
|
-
|
|
818
|
+
/**
|
|
819
|
+
* The Responses `text.format` object when it requests structured output (json_schema or
|
|
820
|
+
* json_object), undefined otherwise. Acceptance is identical to the boolean detector this
|
|
821
|
+
* replaces; unknown or malformed formats are ignored, never rejected, so the native
|
|
822
|
+
* passthrough keeps forwarding whatever the caller sent via `_rawBody`.
|
|
823
|
+
*/
|
|
824
|
+
function parseTextFormat(text: unknown): OcxRequestOptions["textFormat"] {
|
|
825
|
+
if (!isObj(text)) return undefined;
|
|
652
826
|
const format = (text as { format?: unknown }).format;
|
|
653
|
-
if (!isObj(format)) return
|
|
654
|
-
const
|
|
655
|
-
|
|
827
|
+
if (!isObj(format)) return undefined;
|
|
828
|
+
const f = format as { type?: unknown; name?: unknown; description?: unknown; schema?: unknown; strict?: unknown };
|
|
829
|
+
if (f.type === "json_object") return { type: "json_object" };
|
|
830
|
+
if (f.type !== "json_schema") return undefined;
|
|
831
|
+
return {
|
|
832
|
+
type: "json_schema",
|
|
833
|
+
...(typeof f.name === "string" ? { name: f.name } : {}),
|
|
834
|
+
...(typeof f.description === "string" ? { description: f.description } : {}),
|
|
835
|
+
...(isObj(f.schema) ? { schema: f.schema as Record<string, unknown> } : {}),
|
|
836
|
+
...(typeof f.strict === "boolean" ? { strict: f.strict } : {}),
|
|
837
|
+
};
|
|
656
838
|
}
|
|
@@ -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
|
}
|