@yansigit/opencodex 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/LICENSE +21 -0
- package/README.md +303 -0
- package/assets/architecture.png +0 -0
- package/assets/banner.png +0 -0
- package/assets/claude-code-models.gif +0 -0
- package/assets/codex-app-picker.png +0 -0
- package/bin/ocx.mjs +587 -0
- package/bin/package-main.mjs +9 -0
- package/gui/dist/assets/index-BNJ7r4Gd.js +102 -0
- package/gui/dist/assets/index-CGoDO3uO.css +1 -0
- package/gui/dist/favicon.png +0 -0
- package/gui/dist/icons.svg +24 -0
- package/gui/dist/index.html +25 -0
- package/gui/dist/logo.png +0 -0
- package/gui/dist/provider-icons/alibaba-color.svg +1 -0
- package/gui/dist/provider-icons/antigravity-color.svg +1 -0
- package/gui/dist/provider-icons/claude-color.svg +1 -0
- package/gui/dist/provider-icons/cline-color.svg +16 -0
- package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -0
- package/gui/dist/provider-icons/commandcode-color.svg +1 -0
- package/gui/dist/provider-icons/copilot-color.svg +1 -0
- package/gui/dist/provider-icons/cursor-color.svg +2 -0
- package/gui/dist/provider-icons/deepseek-color.svg +1 -0
- package/gui/dist/provider-icons/discord.svg +1 -0
- package/gui/dist/provider-icons/firepass-color.svg +1 -0
- package/gui/dist/provider-icons/fireworks-color.svg +1 -0
- package/gui/dist/provider-icons/gemini-color.svg +1 -0
- package/gui/dist/provider-icons/github-copilot-color.svg +1 -0
- package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -0
- package/gui/dist/provider-icons/grok.svg +1 -0
- package/gui/dist/provider-icons/groq-color.svg +1 -0
- package/gui/dist/provider-icons/huggingface-color.svg +1 -0
- package/gui/dist/provider-icons/kimi-color.svg +1 -0
- package/gui/dist/provider-icons/kiro-color.svg +15 -0
- package/gui/dist/provider-icons/lm-studio-color.svg +1 -0
- package/gui/dist/provider-icons/mistral-color.svg +1 -0
- package/gui/dist/provider-icons/moonshot-color.svg +1 -0
- package/gui/dist/provider-icons/nvidia-color.svg +1 -0
- package/gui/dist/provider-icons/ollama-color.svg +1 -0
- package/gui/dist/provider-icons/openai.svg +1 -0
- package/gui/dist/provider-icons/opencode.svg +2 -0
- package/gui/dist/provider-icons/openrouter-color.svg +1 -0
- package/gui/dist/provider-icons/pi.svg +21 -0
- package/gui/dist/provider-icons/qianfan-color.svg +1 -0
- package/gui/dist/provider-icons/qwen-portal-color.svg +1 -0
- package/gui/dist/provider-icons/telegram.svg +1 -0
- package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -0
- package/gui/dist/provider-icons/vllm-color.svg +1 -0
- package/gui/dist/provider-icons/xiaomi-color.svg +1 -0
- package/package.json +108 -0
- package/src/AGENTS.md +28 -0
- package/src/adapters/anthropic-image-guard.ts +251 -0
- package/src/adapters/anthropic-image-normalize.ts +518 -0
- package/src/adapters/anthropic-output-schema.ts +137 -0
- package/src/adapters/anthropic.ts +1327 -0
- package/src/adapters/azure.ts +36 -0
- package/src/adapters/base.ts +121 -0
- package/src/adapters/client-fingerprint.ts +65 -0
- package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
- package/src/adapters/command-code.ts +601 -0
- package/src/adapters/cursor/arg-codec.ts +38 -0
- package/src/adapters/cursor/arg-normalize.ts +104 -0
- package/src/adapters/cursor/checkpoint-store.ts +303 -0
- package/src/adapters/cursor/cursor-errors.ts +288 -0
- package/src/adapters/cursor/discovery.ts +333 -0
- package/src/adapters/cursor/effort-map.ts +151 -0
- package/src/adapters/cursor/exec-policy.ts +88 -0
- package/src/adapters/cursor/framing.ts +250 -0
- package/src/adapters/cursor/gen/agent_pb.ts +15274 -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/kv-store.ts +52 -0
- package/src/adapters/cursor/live-models.ts +269 -0
- package/src/adapters/cursor/live-smoke-gate.ts +41 -0
- package/src/adapters/cursor/live-transport.ts +1653 -0
- package/src/adapters/cursor/mcp-config.ts +42 -0
- package/src/adapters/cursor/mcp-manager.ts +333 -0
- package/src/adapters/cursor/message-mapper.ts +49 -0
- package/src/adapters/cursor/native-exec-common.ts +76 -0
- package/src/adapters/cursor/native-exec-desktop.ts +184 -0
- package/src/adapters/cursor/native-exec-fs.ts +332 -0
- package/src/adapters/cursor/native-exec-mcp.ts +153 -0
- package/src/adapters/cursor/native-exec-network.ts +43 -0
- package/src/adapters/cursor/native-exec-shell.ts +547 -0
- package/src/adapters/cursor/native-exec-tools.ts +118 -0
- package/src/adapters/cursor/native-exec.ts +663 -0
- package/src/adapters/cursor/protobuf-events.ts +1381 -0
- package/src/adapters/cursor/protobuf-request.ts +1032 -0
- package/src/adapters/cursor/request-builder.ts +461 -0
- package/src/adapters/cursor/thread-continuity.ts +67 -0
- package/src/adapters/cursor/tool-definitions.ts +735 -0
- package/src/adapters/cursor/tool-result-normalize.ts +92 -0
- package/src/adapters/cursor/transport-retry.ts +132 -0
- package/src/adapters/cursor/transport.ts +79 -0
- package/src/adapters/cursor/types.ts +79 -0
- package/src/adapters/cursor.ts +322 -0
- package/src/adapters/google-antigravity-hosts.ts +48 -0
- package/src/adapters/google-antigravity-replay.ts +827 -0
- package/src/adapters/google-antigravity-tools.ts +105 -0
- package/src/adapters/google-antigravity-wire.ts +141 -0
- package/src/adapters/google-errors.ts +92 -0
- package/src/adapters/google-http.ts +460 -0
- package/src/adapters/google-tool-schema.ts +238 -0
- package/src/adapters/google-truncation.ts +24 -0
- package/src/adapters/google-wire-compiler.ts +232 -0
- package/src/adapters/google.ts +1377 -0
- package/src/adapters/identity.ts +77 -0
- package/src/adapters/image.ts +23 -0
- package/src/adapters/kiro-constants.ts +16 -0
- package/src/adapters/kiro-errors.ts +208 -0
- package/src/adapters/kiro-events.ts +197 -0
- package/src/adapters/kiro-images.ts +129 -0
- package/src/adapters/kiro-retry.ts +312 -0
- package/src/adapters/kiro-thinking.ts +112 -0
- package/src/adapters/kiro-tool-fallback.ts +36 -0
- package/src/adapters/kiro-tools.ts +224 -0
- package/src/adapters/kiro-truncation.ts +33 -0
- package/src/adapters/kiro-wire.ts +129 -0
- package/src/adapters/kiro.ts +1936 -0
- package/src/adapters/mimo-free.ts +280 -0
- package/src/adapters/openai-chat-url.ts +11 -0
- package/src/adapters/openai-chat.ts +1980 -0
- package/src/adapters/openai-responses-url.ts +16 -0
- package/src/adapters/openai-responses.ts +1911 -0
- package/src/adapters/registry.ts +175 -0
- package/src/adapters/responses-tool-schema.ts +67 -0
- package/src/adapters/run-turn-queue.ts +114 -0
- package/src/adapters/tool-call-id.ts +119 -0
- package/src/adapters/tool-catalog-nudge.ts +154 -0
- package/src/adapters/upstream-http-error.ts +48 -0
- package/src/adapters/xai-web-search.ts +185 -0
- package/src/bridge.ts +1986 -0
- package/src/chat/inbound.ts +319 -0
- package/src/chat/outbound.ts +821 -0
- package/src/claude/agents-inject.ts +266 -0
- package/src/claude/alias.ts +149 -0
- package/src/claude/auth-detect.ts +229 -0
- package/src/claude/auth-mode-migration.ts +32 -0
- package/src/claude/auth-mode.ts +62 -0
- package/src/claude/context-windows.ts +205 -0
- package/src/claude/desktop-3p-guard.ts +35 -0
- package/src/claude/desktop-3p-paths.ts +84 -0
- package/src/claude/desktop-3p.ts +615 -0
- package/src/claude/desktop-health.ts +26 -0
- package/src/claude/desktop-profile.ts +263 -0
- package/src/claude/gateway-cache.ts +107 -0
- package/src/claude/inbound-debug.ts +163 -0
- package/src/claude/inbound.ts +578 -0
- package/src/claude/model-info.ts +174 -0
- package/src/claude/outbound.ts +926 -0
- package/src/cli/access.ts +108 -0
- package/src/cli/account-api.ts +302 -0
- package/src/cli/account-auth.ts +250 -0
- package/src/cli/account-catalog-refresh.ts +14 -0
- package/src/cli/account-extended.ts +737 -0
- package/src/cli/account-main.ts +317 -0
- package/src/cli/account.ts +299 -0
- package/src/cli/agent-driven.ts +70 -0
- package/src/cli/agent.ts +290 -0
- package/src/cli/catalog-prewarm.ts +27 -0
- package/src/cli/claude-agent-startup-sync.ts +73 -0
- package/src/cli/claude-desktop.ts +213 -0
- package/src/cli/claude.ts +355 -0
- package/src/cli/codex-log-guard-doctor.ts +103 -0
- package/src/cli/codex-shim-autorestore.ts +47 -0
- package/src/cli/codex-shim-readiness.ts +76 -0
- package/src/cli/combo.ts +127 -0
- package/src/cli/config-command.ts +209 -0
- package/src/cli/debug.ts +228 -0
- package/src/cli/dispatch.ts +585 -0
- package/src/cli/doctor.ts +1202 -0
- package/src/cli/ensure-desired-integrations.ts +152 -0
- package/src/cli/export-command.ts +213 -0
- package/src/cli/help.ts +101 -0
- package/src/cli/index.ts +973 -0
- package/src/cli/init.ts +211 -0
- package/src/cli/integrations.ts +260 -0
- package/src/cli/interactive-confirm.ts +133 -0
- 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 +245 -0
- package/src/cli/models.ts +422 -0
- package/src/cli/observe.ts +206 -0
- package/src/cli/opencode.ts +588 -0
- package/src/cli/provider-replit.ts +232 -0
- package/src/cli/provider-runtime.ts +179 -0
- package/src/cli/provider.ts +492 -0
- package/src/cli/ready.ts +301 -0
- package/src/cli/registry.ts +422 -0
- package/src/cli/replit-gateway-key-input.ts +138 -0
- package/src/cli/root.ts +86 -0
- package/src/cli/route-policy.ts +92 -0
- package/src/cli/runtime-api.ts +328 -0
- package/src/cli/star-prompt.ts +211 -0
- package/src/cli/status-oauth.ts +78 -0
- package/src/cli/status.ts +328 -0
- package/src/cli/system-command.ts +112 -0
- package/src/cli/system-restart-client.ts +146 -0
- package/src/cli/tray-proxy.ts +199 -0
- package/src/cli/v2.ts +268 -0
- package/src/cli.ts +10 -0
- package/src/clients/config-export.ts +1704 -0
- package/src/codex/account-id.ts +34 -0
- package/src/codex/account-label.ts +47 -0
- package/src/codex/account-lifecycle.ts +172 -0
- package/src/codex/account-namespace-match.ts +63 -0
- package/src/codex/account-namespaces.ts +195 -0
- package/src/codex/account-pause.ts +20 -0
- package/src/codex/account-priority.ts +83 -0
- package/src/codex/account-runtime-state.ts +31 -0
- package/src/codex/account-store.ts +544 -0
- package/src/codex/account-usability.ts +43 -0
- package/src/codex/admission.ts +256 -0
- package/src/codex/affinity-debug.ts +162 -0
- package/src/codex/agent-roles-sync.ts +225 -0
- package/src/codex/agent-roles.ts +238 -0
- package/src/codex/app-server-processes.ts +1143 -0
- package/src/codex/app-server-restart-service.ts +232 -0
- package/src/codex/auth-api.ts +2147 -0
- package/src/codex/auth-collision.ts +109 -0
- package/src/codex/auth-context.ts +665 -0
- package/src/codex/autostart-health.ts +156 -0
- package/src/codex/catalog/account-models.ts +67 -0
- package/src/codex/catalog/aggregation.ts +436 -0
- package/src/codex/catalog/bundled.ts +549 -0
- package/src/codex/catalog/effort.ts +446 -0
- package/src/codex/catalog/filesystem-evidence.ts +302 -0
- package/src/codex/catalog/kinds.ts +2 -0
- package/src/codex/catalog/metadata.ts +664 -0
- package/src/codex/catalog/native-models.ts +72 -0
- package/src/codex/catalog/parsing.ts +650 -0
- package/src/codex/catalog/provider-fetch.ts +2064 -0
- package/src/codex/catalog/sync.ts +1883 -0
- 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 +14 -0
- 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/data/upstream-models.json +830 -0
- package/src/codex/desired-state.ts +230 -0
- package/src/codex/exec-invocation.ts +22 -0
- package/src/codex/features.ts +1566 -0
- 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 +108 -0
- package/src/codex/history-provider.ts +979 -0
- package/src/codex/history-transition.ts +105 -0
- package/src/codex/history-worker.ts +220 -0
- package/src/codex/home.ts +206 -0
- package/src/codex/inject-coordination.ts +290 -0
- package/src/codex/inject.ts +1733 -0
- package/src/codex/injected-marker.ts +106 -0
- 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 +225 -0
- 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 +56 -0
- package/src/codex/main-account.ts +68 -0
- package/src/codex/management-convergence.ts +167 -0
- package/src/codex/model-cache.ts +273 -0
- 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 +144 -0
- package/src/codex/plan-from-token.ts +140 -0
- package/src/codex/plan.ts +40 -0
- package/src/codex/plugins-doctor.ts +242 -0
- package/src/codex/pool-rotation.ts +295 -0
- package/src/codex/project-config-warnings.ts +425 -0
- 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 +573 -0
- package/src/codex/refresh.ts +62 -0
- package/src/codex/reset-credit-recovery.ts +1044 -0
- package/src/codex/routing.ts +1888 -0
- package/src/codex/runtime.ts +659 -0
- package/src/codex/shim.ts +2170 -0
- package/src/codex/subagent-defaults.ts +550 -0
- package/src/codex/subagent-model-fallback.ts +784 -0
- package/src/codex/sync.ts +319 -0
- 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 +298 -0
- package/src/codex/websocket-registry.ts +100 -0
- package/src/codex/write-coordination.ts +114 -0
- package/src/combos/failover.ts +160 -0
- package/src/combos/index.ts +45 -0
- package/src/combos/request.ts +94 -0
- package/src/combos/resolve.ts +232 -0
- package/src/combos/types.ts +398 -0
- package/src/config/provider-name.ts +24 -0
- package/src/config.ts +4041 -0
- package/src/fork/register.ts +3 -0
- package/src/generated/compatibility-version.json +3116 -0
- package/src/generated/model-metadata.ts +106 -0
- package/src/github/star-state.ts +203 -0
- package/src/grok/inject.ts +530 -0
- package/src/grok/inspect.ts +45 -0
- package/src/grok/status.ts +121 -0
- package/src/grok/sync.ts +66 -0
- package/src/images/artifacts.ts +516 -0
- package/src/images/fulfill-video.ts +163 -0
- package/src/images/fulfill.ts +149 -0
- package/src/images/index.ts +4 -0
- package/src/images/loop.ts +955 -0
- package/src/images/plan.ts +143 -0
- package/src/images/synthetic-tool.ts +133 -0
- package/src/images/types.ts +41 -0
- package/src/images/xai-client.ts +141 -0
- package/src/images/xai-video-client.ts +163 -0
- package/src/index.ts +22 -0
- 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/abort.ts +146 -0
- package/src/lib/admin-secrets.ts +25 -0
- package/src/lib/admission.ts +83 -0
- package/src/lib/app-owned-memory-stores.ts +195 -0
- package/src/lib/app-owned-memory.ts +265 -0
- package/src/lib/bounded-body.ts +346 -0
- package/src/lib/bun-binary-validator.d.mts +3 -0
- package/src/lib/bun-binary-validator.mjs +18 -0
- package/src/lib/bun-runtime.ts +184 -0
- package/src/lib/bun-stream-caps.ts +130 -0
- package/src/lib/codex-restart-contract.ts +120 -0
- package/src/lib/config-ownership.ts +364 -0
- package/src/lib/crash-guard.ts +344 -0
- package/src/lib/debug-log-buffer.ts +83 -0
- package/src/lib/debug-settings.ts +108 -0
- package/src/lib/debug.ts +31 -0
- package/src/lib/destination-policy.ts +380 -0
- package/src/lib/errors.ts +406 -0
- package/src/lib/eventstream-decoder.ts +253 -0
- package/src/lib/fabric-task-execution-authority.ts +7 -0
- package/src/lib/fabric-task-host.ts +29 -0
- package/src/lib/gcp-adc.ts +341 -0
- package/src/lib/injection-debug-log.ts +58 -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/open-url.ts +25 -0
- package/src/lib/optional-shutdown-hooks.ts +57 -0
- package/src/lib/pinned-http.ts +270 -0
- package/src/lib/privacy.ts +20 -0
- package/src/lib/process-control.ts +168 -0
- package/src/lib/provider-outbound.ts +210 -0
- package/src/lib/provider-url.ts +14 -0
- package/src/lib/proxy-env.ts +18 -0
- package/src/lib/redact.ts +521 -0
- package/src/lib/retry-after.ts +55 -0
- package/src/lib/self-launch-argv.ts +15 -0
- package/src/lib/server-resource-ownership.ts +71 -0
- package/src/lib/service-secrets.ts +25 -0
- package/src/lib/shadow-call.ts +61 -0
- package/src/lib/sidecar-tracker.ts +52 -0
- package/src/lib/sse-decoder.ts +364 -0
- package/src/lib/state-store-registrations.ts +119 -0
- package/src/lib/state-store-sweeper.ts +184 -0
- package/src/lib/system-restart-contract.ts +73 -0
- package/src/lib/test-home-guard.ts +90 -0
- package/src/lib/token-estimate.ts +86 -0
- package/src/lib/tool-argument-integers.ts +202 -0
- package/src/lib/translator-budget.ts +400 -0
- package/src/lib/upstream-http-version.ts +57 -0
- package/src/lib/upstream-reachability.ts +95 -0
- package/src/lib/upstream-retry.ts +392 -0
- package/src/lib/win-exec.ts +115 -0
- package/src/lib/win-paths.ts +68 -0
- package/src/lib/windows-atomic-replace.ts +156 -0
- package/src/lib/windows-elevation.ts +773 -0
- package/src/lib/windows-secret-acl.ts +854 -0
- 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 +403 -0
- 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-routing.ts +594 -0
- package/src/oauth/anthropic.ts +188 -0
- package/src/oauth/antigravity-routing.ts +151 -0
- package/src/oauth/callback-server.ts +300 -0
- package/src/oauth/chatgpt.ts +161 -0
- package/src/oauth/command-code.ts +239 -0
- package/src/oauth/cursor.ts +252 -0
- package/src/oauth/github-copilot.ts +428 -0
- package/src/oauth/google-antigravity.ts +262 -0
- package/src/oauth/health.ts +407 -0
- package/src/oauth/index.ts +1504 -0
- package/src/oauth/key-providers.ts +124 -0
- package/src/oauth/kimi.ts +227 -0
- package/src/oauth/kiro-credentials.ts +726 -0
- package/src/oauth/kiro.ts +621 -0
- package/src/oauth/local-token-detect.ts +130 -0
- package/src/oauth/log.ts +50 -0
- package/src/oauth/login-cli.ts +223 -0
- package/src/oauth/nous.ts +798 -0
- package/src/oauth/pkce.ts +15 -0
- package/src/oauth/store.ts +728 -0
- package/src/oauth/token-guardian.ts +309 -0
- package/src/oauth/types.ts +62 -0
- package/src/oauth/xai.ts +241 -0
- package/src/providers/alibaba-region-backup.ts +75 -0
- package/src/providers/alibaba-region-migration.ts +156 -0
- package/src/providers/alibaba-region-startup.ts +36 -0
- package/src/providers/antigravity-models.ts +695 -0
- package/src/providers/antigravity-quota.ts +216 -0
- package/src/providers/api-keys.ts +140 -0
- package/src/providers/base-url-choices.ts +74 -0
- package/src/providers/codex-capacity.ts +292 -0
- package/src/providers/command-code-efforts.ts +144 -0
- package/src/providers/context-cap.ts +82 -0
- package/src/providers/cursor-pool.ts +72 -0
- package/src/providers/derive.ts +586 -0
- package/src/providers/fastwire.ts +501 -0
- package/src/providers/free-directory.ts +187 -0
- package/src/providers/github-copilot-transport.ts +56 -0
- package/src/providers/google-vertex-location.ts +14 -0
- package/src/providers/key-failover.ts +271 -0
- package/src/providers/kiro-models.ts +67 -0
- package/src/providers/label.ts +19 -0
- package/src/providers/model-discovery-limits.ts +16 -0
- package/src/providers/model-discovery.ts +449 -0
- package/src/providers/model-rename-migration.ts +255 -0
- package/src/providers/model-rename-startup.ts +28 -0
- package/src/providers/openai-sidecar.ts +243 -0
- package/src/providers/openai-tier-startup.ts +56 -0
- package/src/providers/openai-tiers.ts +423 -0
- package/src/providers/openai-virtual-models.ts +83 -0
- package/src/providers/opencode-zen-rate-limit.ts +102 -0
- package/src/providers/openrouter-routing.ts +102 -0
- package/src/providers/provider-id-rewrite.ts +185 -0
- package/src/providers/quota.ts +2345 -0
- package/src/providers/registry.ts +2918 -0
- package/src/providers/replit/constants.ts +27 -0
- package/src/providers/replit/derive.ts +85 -0
- package/src/providers/replit/headers.ts +28 -0
- package/src/providers/replit/origin.ts +55 -0
- package/src/providers/replit/pair-install-response.ts +72 -0
- package/src/providers/replit/probe.ts +199 -0
- package/src/providers/replit/setup.ts +350 -0
- package/src/providers/request-pacing.ts +310 -0
- package/src/providers/service-tier.ts +277 -0
- package/src/providers/slug-codec.ts +103 -0
- 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 +148 -0
- package/src/reasoning-effort.ts +183 -0
- package/src/responses/compaction.ts +142 -0
- 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 +838 -0
- package/src/responses/provider-continuation.ts +98 -0
- package/src/responses/provider-opaque-metadata.ts +73 -0
- package/src/responses/reasoning-envelope.ts +60 -0
- package/src/responses/reasoning-replay-cache.ts +426 -0
- package/src/responses/schema.ts +165 -0
- package/src/responses/spill-store.ts +459 -0
- package/src/responses/state.ts +1433 -0
- package/src/responses/thought-signature-replay.ts +347 -0
- package/src/responses/tool-groups.ts +19 -0
- package/src/responses/tool-search-compat.ts +301 -0
- package/src/responses/truncated-stop-reason.ts +60 -0
- package/src/router.ts +761 -0
- 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 +53 -0
- package/src/server/auth-cors.ts +751 -0
- package/src/server/background-lifecycle.ts +182 -0
- package/src/server/chat-completions.ts +442 -0
- package/src/server/chat-native-sse.ts +331 -0
- package/src/server/chat-native.ts +426 -0
- package/src/server/claude-messages.ts +1030 -0
- package/src/server/direct-local-http.ts +347 -0
- package/src/server/effort-policy.ts +190 -0
- package/src/server/github-copilot-responses-repair.ts +338 -0
- package/src/server/gui-static.ts +152 -0
- package/src/server/image-retry.ts +42 -0
- package/src/server/images.ts +568 -0
- package/src/server/index.ts +1813 -0
- package/src/server/lifecycle.ts +498 -0
- package/src/server/live.ts +717 -0
- 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 +1433 -0
- package/src/server/management/api-access.ts +141 -0
- package/src/server/management/api-key-usage.ts +193 -0
- package/src/server/management/body.ts +41 -0
- package/src/server/management/combo-routes.ts +263 -0
- package/src/server/management/config-routes.ts +835 -0
- package/src/server/management/context.ts +113 -0
- 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 +586 -0
- package/src/server/management/model-routes.ts +560 -0
- 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 +637 -0
- package/src/server/management/provider-capability-config.ts +48 -0
- package/src/server/management/provider-routes.ts +1033 -0
- package/src/server/management/replit-provider-routes.ts +86 -0
- 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 +385 -0
- package/src/server/management/shared.ts +286 -0
- package/src/server/management/sidebar-routes.ts +106 -0
- 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 +435 -0
- package/src/server/management/system-routes.ts +194 -0
- package/src/server/management/usage-summary-cache.ts +94 -0
- 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 +314 -0
- package/src/server/management-auth.ts +482 -0
- package/src/server/memory-watchdog.ts +156 -0
- package/src/server/passive-route-linker.ts +66 -0
- package/src/server/port-reclaim.ts +307 -0
- package/src/server/ports.ts +156 -0
- package/src/server/proxy-liveness.ts +328 -0
- package/src/server/readiness.ts +99 -0
- package/src/server/relay-eager.ts +353 -0
- package/src/server/relay.ts +1209 -0
- package/src/server/request-decompress.ts +239 -0
- package/src/server/request-log-conversation.ts +168 -0
- package/src/server/request-log.ts +1259 -0
- 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 +551 -0
- package/src/server/responses/compact.ts +771 -0
- package/src/server/responses/core.ts +5389 -0
- package/src/server/responses/empty-completion-guard.ts +276 -0
- package/src/server/responses/encrypted-payload.ts +331 -0
- package/src/server/responses/fetch-helpers.ts +232 -0
- package/src/server/responses/input-admission.ts +185 -0
- package/src/server/responses/pacing-overload.ts +13 -0
- package/src/server/responses/passthrough-error.ts +78 -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 +251 -0
- package/src/server/responses/upstream-error.ts +53 -0
- package/src/server/responses/ws-upstream.ts +308 -0
- package/src/server/responses-custom-tool-repair.ts +282 -0
- package/src/server/responses-image-gen-repair.ts +132 -0
- package/src/server/responses-item-id-repair.ts +272 -0
- 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 +25 -0
- package/src/server/search.ts +201 -0
- package/src/server/sse-frame-buffer.ts +292 -0
- package/src/server/sse-payload-rewrite.ts +263 -0
- package/src/server/startup-action-control.ts +315 -0
- package/src/server/startup-health-cache.ts +131 -0
- package/src/server/system-env.ts +484 -0
- package/src/server/windows-tcp-drop.ts +184 -0
- package/src/server/windows-tray-control.ts +41 -0
- package/src/server/ws-bridge.ts +472 -0
- package/src/service-manager-probe.ts +892 -0
- package/src/service.ts +3575 -0
- package/src/sidecar/auth.ts +92 -0
- package/src/sidecar/candidates.ts +83 -0
- package/src/stall-timeout.ts +20 -0
- package/src/storage/cleanup-job.ts +57 -0
- package/src/storage/cleanup.ts +3085 -0
- package/src/storage/policy-job.ts +457 -0
- package/src/storage/policy-scheduler.ts +40 -0
- package/src/storage/policy-worker.ts +59 -0
- package/src/storage/policy.ts +527 -0
- package/src/storage/restore-job.ts +299 -0
- package/src/storage/restore-worker.ts +58 -0
- package/src/storage/scanner.ts +238 -0
- package/src/storage/storage-mutation-coordinator.ts +139 -0
- package/src/storage/worker-lifecycle.ts +215 -0
- package/src/tray/assets/opencodex-tray-offline.ico +0 -0
- package/src/tray/assets/opencodex-tray-online.ico +0 -0
- package/src/tray/assets/opencodex-tray-warning.ico +0 -0
- package/src/tray/assets/opencodex-tray.png +0 -0
- package/src/tray/windows-tray.ps1 +364 -0
- package/src/tray/windows.ts +757 -0
- package/src/types/accounts.ts +37 -0
- package/src/types/config.ts +876 -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 +106 -0
- package/src/update/badge.ts +72 -0
- package/src/update/index.ts +415 -0
- package/src/update/job.ts +1887 -0
- package/src/update/notify.ts +263 -0
- package/src/update/npm-cache-preflight.d.mts +47 -0
- package/src/update/npm-cache-preflight.mjs +201 -0
- package/src/update/npm-invocation.d.mts +23 -0
- package/src/update/npm-invocation.mjs +94 -0
- package/src/update/transactional-install.d.mts +22 -0
- package/src/update/transactional-install.mjs +259 -0
- package/src/update/tray-update-plan.d.mts +18 -0
- package/src/update/tray-update-plan.mjs +38 -0
- package/src/usage/cost.ts +625 -0
- package/src/usage/debug.ts +97 -0
- package/src/usage/expected-prices.ts +416 -0
- package/src/usage/log.ts +1223 -0
- package/src/usage/summary.ts +753 -0
- package/src/usage/totals.ts +14 -0
- 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 +189 -0
- package/src/vision/backends.ts +97 -0
- package/src/vision/describe.ts +131 -0
- package/src/vision/eligibility.ts +250 -0
- package/src/vision/index.ts +681 -0
- 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 +195 -0
- package/src/web-search/backends.ts +108 -0
- package/src/web-search/exa-executor.ts +88 -0
- package/src/web-search/executor.ts +113 -0
- package/src/web-search/format-result.ts +89 -0
- package/src/web-search/gemini-executor.ts +141 -0
- package/src/web-search/index.ts +331 -0
- package/src/web-search/loop.ts +896 -0
- package/src/web-search/parse.ts +315 -0
- package/src/web-search/progress-stream.ts +342 -0
- package/src/web-search/sources.ts +60 -0
- package/src/web-search/synthetic-tool.ts +47 -0
- package/src/web-search/xai-executor.ts +219 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
// Schema-aware repair for tool arguments whose serialized representation disagrees
|
|
2
|
+
// with the declared schema in a way that has exactly one faithful reading.
|
|
3
|
+
//
|
|
4
|
+
// Case 1 — integer fields arriving as integral floats (issue #1611).
|
|
5
|
+
//
|
|
6
|
+
// Grok serializes integer tool-call arguments through a float representation, so
|
|
7
|
+
// `yield_time_ms: 120000` leaves the provider as `120000.0`. Codex declares those
|
|
8
|
+
// fields as Rust integer types, so it rejects the call BEFORE running the tool:
|
|
9
|
+
//
|
|
10
|
+
// failed to parse function arguments: invalid type: floating point `120000.0`, expected u64
|
|
11
|
+
//
|
|
12
|
+
// That is a hard failure, not a degradation — the model gets no result and retries
|
|
13
|
+
// the same float. Nothing on the routed path reconciled argument values against the
|
|
14
|
+
// declared schema, so the `.0` passed straight through.
|
|
15
|
+
//
|
|
16
|
+
// The boundary this file draws is INTENT, not convenience:
|
|
17
|
+
// - an integral float in an integer-typed field is a representation artifact, and
|
|
18
|
+
// `120000.0` has exactly one integer reading, so it is repaired;
|
|
19
|
+
// - `1.5` in an integer field is a genuine disagreement with the schema and is left
|
|
20
|
+
// alone so it still fails, rather than being truncated into a plausible lie.
|
|
21
|
+
//
|
|
22
|
+
// Case 2 — string fields arriving as bare integers (issue #1938).
|
|
23
|
+
//
|
|
24
|
+
// Cursor-served models emit `{"cell_id": 4}` where the schema declares
|
|
25
|
+
// `{"type": "string"}`. Codex rejects the call before the tool runs (invalid type:
|
|
26
|
+
// integer `4`, expected a string), and the model never self-corrects, so every such
|
|
27
|
+
// call is a hard failure loop. A safely-integral JSON number in a string-declared
|
|
28
|
+
// field has exactly one faithful string reading (`4` -> `"4"`), so it is repaired
|
|
29
|
+
// under the same intent boundary:
|
|
30
|
+
// - only when the field declares `string` and no numeric type (a
|
|
31
|
+
// `["integer","string"]` union accepts the number as-is and is left alone);
|
|
32
|
+
// - a non-integral number (`4.5`) in a string field is a genuine disagreement and
|
|
33
|
+
// is left alone so it still fails;
|
|
34
|
+
// - beyond 2^53-1 the parsed value may differ from the serialized text, so the
|
|
35
|
+
// original bytes stay.
|
|
36
|
+
//
|
|
37
|
+
// Anything without a declared `integer`/`string` type is never touched.
|
|
38
|
+
|
|
39
|
+
/** JSON Schema subset we need; provider tool schemas are untrusted input. */
|
|
40
|
+
type SchemaNode = Record<string, unknown>;
|
|
41
|
+
|
|
42
|
+
function asSchema(value: unknown): SchemaNode | undefined {
|
|
43
|
+
return value && typeof value === "object" && !Array.isArray(value)
|
|
44
|
+
? value as SchemaNode
|
|
45
|
+
: undefined;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** True when the node declares `integer`, including `["integer","null"]` unions. */
|
|
49
|
+
function declaresInteger(schema: SchemaNode): boolean {
|
|
50
|
+
const type = schema.type;
|
|
51
|
+
if (type === "integer") return true;
|
|
52
|
+
return Array.isArray(type) && type.includes("integer");
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** True when the node declares `string`, including `["string","null"]` unions. */
|
|
56
|
+
function declaresString(schema: SchemaNode): boolean {
|
|
57
|
+
const type = schema.type;
|
|
58
|
+
if (type === "string") return true;
|
|
59
|
+
return Array.isArray(type) && type.includes("string");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** True when the node accepts a JSON number (`integer` or `number`), so a numeric
|
|
63
|
+
* value is already schema-valid and must not be rewritten into a string. */
|
|
64
|
+
function declaresNumeric(schema: SchemaNode): boolean {
|
|
65
|
+
const type = schema.type;
|
|
66
|
+
if (type === "integer" || type === "number") return true;
|
|
67
|
+
return Array.isArray(type) && (type.includes("integer") || type.includes("number"));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Resolve a local `$ref` (`#/$defs/Foo`, `#/definitions/Foo`).
|
|
72
|
+
*
|
|
73
|
+
* Only same-document refs are followed: a remote ref is not fetchable here, and a
|
|
74
|
+
* schema we cannot resolve must leave its values untouched rather than guessed at.
|
|
75
|
+
*/
|
|
76
|
+
function resolveRef(schema: SchemaNode, root: SchemaNode, seen: Set<string>): SchemaNode | undefined {
|
|
77
|
+
const ref = schema.$ref;
|
|
78
|
+
if (typeof ref !== "string" || !ref.startsWith("#/")) return schema;
|
|
79
|
+
if (seen.has(ref)) return undefined; // cyclic $ref: stop rather than recurse forever
|
|
80
|
+
seen.add(ref);
|
|
81
|
+
let node: unknown = root;
|
|
82
|
+
for (const rawSegment of ref.slice(2).split("/")) {
|
|
83
|
+
const segment = rawSegment.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
84
|
+
const current = asSchema(node);
|
|
85
|
+
if (!current) return undefined;
|
|
86
|
+
node = current[segment];
|
|
87
|
+
}
|
|
88
|
+
const resolved = asSchema(node);
|
|
89
|
+
return resolved ? resolveRef(resolved, root, seen) : undefined;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Composition keywords whose branches may carry the integer declaration. */
|
|
93
|
+
const COMPOSITION_KEYS = ["anyOf", "oneOf", "allOf"] as const;
|
|
94
|
+
|
|
95
|
+
function compositionBranches(schema: SchemaNode): SchemaNode[] {
|
|
96
|
+
const branches: SchemaNode[] = [];
|
|
97
|
+
for (const key of COMPOSITION_KEYS) {
|
|
98
|
+
const value = schema[key];
|
|
99
|
+
if (!Array.isArray(value)) continue;
|
|
100
|
+
for (const branch of value) {
|
|
101
|
+
const node = asSchema(branch);
|
|
102
|
+
if (node) branches.push(node);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return branches;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* A JS number can only represent integers exactly up to 2^53-1. Beyond that a
|
|
110
|
+
* rewrite would emit a silently different value, so the original text stays.
|
|
111
|
+
*/
|
|
112
|
+
function safelyIntegral(value: number): boolean {
|
|
113
|
+
return Number.isInteger(value) && Math.abs(value) <= Number.MAX_SAFE_INTEGER;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
interface CoerceResult {
|
|
117
|
+
value: unknown;
|
|
118
|
+
changed: boolean;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function coerceValue(value: unknown, schema: SchemaNode | undefined, root: SchemaNode, depth: number): CoerceResult {
|
|
122
|
+
// A hostile or deeply nested schema must not blow the stack.
|
|
123
|
+
if (depth > 64) return { value, changed: false };
|
|
124
|
+
const resolved = schema ? resolveRef(schema, root, new Set()) : undefined;
|
|
125
|
+
|
|
126
|
+
if (typeof value === "number") {
|
|
127
|
+
if (!resolved) return { value, changed: false };
|
|
128
|
+
const branches = compositionBranches(resolved);
|
|
129
|
+
const integerDeclared = declaresInteger(resolved) || branches.some(declaresInteger);
|
|
130
|
+
if (!integerDeclared && safelyIntegral(value)) {
|
|
131
|
+
// Issue #1938: a bare integer in a string-only field has exactly one faithful
|
|
132
|
+
// string reading. A field that also accepts a numeric type keeps the number.
|
|
133
|
+
const stringDeclared = declaresString(resolved) || branches.some(declaresString);
|
|
134
|
+
const numericDeclared = declaresNumeric(resolved) || branches.some(declaresNumeric);
|
|
135
|
+
if (stringDeclared && !numericDeclared) {
|
|
136
|
+
return { value: String(value), changed: true };
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
// Not an integer field, already an integer, non-integral, or unrepresentable:
|
|
140
|
+
// in every one of those cases the received value is the right thing to keep.
|
|
141
|
+
if (!integerDeclared || !safelyIntegral(value)) return { value, changed: false };
|
|
142
|
+
// `120000.0` and `120000` are the same JS number; the difference is only in the
|
|
143
|
+
// serialized text, which is repaired by re-stringifying the parsed value.
|
|
144
|
+
return { value, changed: true };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (Array.isArray(value)) {
|
|
148
|
+
const itemSchema = resolved ? asSchema(resolved.items) : undefined;
|
|
149
|
+
let changed = false;
|
|
150
|
+
const next = value.map(entry => {
|
|
151
|
+
const result = coerceValue(entry, itemSchema, root, depth + 1);
|
|
152
|
+
if (result.changed) changed = true;
|
|
153
|
+
return result.value;
|
|
154
|
+
});
|
|
155
|
+
return changed ? { value: next, changed } : { value, changed: false };
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const object = asSchema(value);
|
|
159
|
+
if (!object) return { value, changed: false };
|
|
160
|
+
|
|
161
|
+
const properties = resolved ? asSchema(resolved.properties) : undefined;
|
|
162
|
+
const additional = resolved ? asSchema(resolved.additionalProperties) : undefined;
|
|
163
|
+
let changed = false;
|
|
164
|
+
const next: Record<string, unknown> = {};
|
|
165
|
+
for (const [key, entry] of Object.entries(object)) {
|
|
166
|
+
const childSchema = asSchema(properties?.[key]) ?? additional;
|
|
167
|
+
const result = coerceValue(entry, childSchema, root, depth + 1);
|
|
168
|
+
if (result.changed) changed = true;
|
|
169
|
+
next[key] = result.value;
|
|
170
|
+
}
|
|
171
|
+
return changed ? { value: next, changed } : { value, changed: false };
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Repair integral floats in a tool-call arguments STRING against the tool's declared
|
|
176
|
+
* parameter schema.
|
|
177
|
+
*
|
|
178
|
+
* Returns the original string unchanged when there is no schema, the payload does not
|
|
179
|
+
* parse, or nothing needed repair — so an unaffected call keeps its exact bytes and
|
|
180
|
+
* this stays a no-op for every provider that already emits real integers.
|
|
181
|
+
*/
|
|
182
|
+
export function coerceIntegerToolArguments(
|
|
183
|
+
args: string,
|
|
184
|
+
parameters: Record<string, unknown> | undefined,
|
|
185
|
+
): string {
|
|
186
|
+
if (!parameters || !args) return args;
|
|
187
|
+
// Cheap reject: a payload with no digit cannot need either repair (integral-float
|
|
188
|
+
// -> integer, or bare-integer -> string).
|
|
189
|
+
if (!/\d/.test(args)) return args;
|
|
190
|
+
let parsed: unknown;
|
|
191
|
+
try {
|
|
192
|
+
parsed = JSON.parse(args);
|
|
193
|
+
} catch {
|
|
194
|
+
// Malformed or still-streaming arguments are not this function's problem; the
|
|
195
|
+
// existing paths already handle them.
|
|
196
|
+
return args;
|
|
197
|
+
}
|
|
198
|
+
const root = parameters as SchemaNode;
|
|
199
|
+
const result = coerceValue(parsed, root, root, 0);
|
|
200
|
+
if (!result.changed) return args;
|
|
201
|
+
return JSON.stringify(result.value);
|
|
202
|
+
}
|
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
export const TRANSLATOR_MAX_CALL_ARGUMENT_BYTES = 2 * 1024 * 1024;
|
|
2
|
+
export const TRANSLATOR_MAX_TURN_BYTES = 32 * 1024 * 1024;
|
|
3
|
+
export const TRANSLATOR_MAX_SSE_EVENT_BYTES = 32 * 1024 * 1024;
|
|
4
|
+
export const CURSOR_MAX_CONNECT_FRAME_BYTES = 32 * 1024 * 1024;
|
|
5
|
+
export const CURSOR_MAX_EFFECTIVE_CONNECT_PAYLOAD_BYTES = 16 * 1024 * 1024;
|
|
6
|
+
export const CURSOR_TRANSPORT_MAX_BUFFERED_BYTES = 32 * 1024 * 1024;
|
|
7
|
+
export const CURSOR_TRANSPORT_RESUME_BYTES = 16 * 1024 * 1024;
|
|
8
|
+
export const CURSOR_MAX_PENDING_FRAMES = 1024;
|
|
9
|
+
export const CURSOR_PENDING_FRAMES_RESUME = 512;
|
|
10
|
+
export const MAX_PENDING_IMAGE_FULFILLMENTS = 64;
|
|
11
|
+
export const MAX_PENDING_OAUTH_MUTATIONS = 128;
|
|
12
|
+
|
|
13
|
+
export type TranslatorBufferKind =
|
|
14
|
+
| "tool_args"
|
|
15
|
+
| "retained_collectors"
|
|
16
|
+
| "live_transient"
|
|
17
|
+
| "reasoning"
|
|
18
|
+
| "item_ids"
|
|
19
|
+
| "tool_search_sources"
|
|
20
|
+
| "cursor_transport"
|
|
21
|
+
| "cursor_kv"
|
|
22
|
+
| "request_copies";
|
|
23
|
+
|
|
24
|
+
export type ExternallyCappedKind = "passthrough_serialization" | "mcp_payload";
|
|
25
|
+
|
|
26
|
+
export class TranslatorBudgetExceededError extends Error {
|
|
27
|
+
readonly code = "translation_buffer_limit";
|
|
28
|
+
|
|
29
|
+
constructor(readonly kind: TranslatorBufferKind, readonly limitBytes: number) {
|
|
30
|
+
super(`translator ${kind} buffer exceeded ${limitBytes} bytes`);
|
|
31
|
+
this.name = "TranslatorBudgetExceededError";
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function isTranslatorBudgetExceededError(error: unknown): error is TranslatorBudgetExceededError {
|
|
36
|
+
return error instanceof TranslatorBudgetExceededError
|
|
37
|
+
|| (error instanceof Error && (error as { code?: unknown }).code === "translation_buffer_limit");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface TranslatorBudgetSnapshot {
|
|
41
|
+
currentBytes: number;
|
|
42
|
+
highWaterBytes: number;
|
|
43
|
+
activeCalls: number;
|
|
44
|
+
overflows: number;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface TranslatorBudgetOptions {
|
|
48
|
+
maxCallArgumentBytes?: number;
|
|
49
|
+
maxTurnBytes?: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface TranslatorTransientReservation {
|
|
53
|
+
commitRetained(): void;
|
|
54
|
+
release(): void;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface TranslatorBudget {
|
|
58
|
+
openCall(id: string): void;
|
|
59
|
+
closeCall(id: string): void;
|
|
60
|
+
reserveTransient(
|
|
61
|
+
bytes: number,
|
|
62
|
+
scope: { kind: TranslatorBufferKind; callId?: string },
|
|
63
|
+
): TranslatorTransientReservation;
|
|
64
|
+
chargeRetained(delta: number, scope: { kind: TranslatorBufferKind; callId?: string }): void;
|
|
65
|
+
releaseRetained(bytes: number, scope: { kind: TranslatorBufferKind; callId?: string }): void;
|
|
66
|
+
observeAcceptedRequestCopy(bytes: number): () => void;
|
|
67
|
+
observeExternallyCapped(kind: ExternallyCappedKind, bytes: number): () => void;
|
|
68
|
+
snapshot(): TranslatorBudgetSnapshot;
|
|
69
|
+
dispose(): void;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const retainedEventOwnership = new WeakMap<object, { budget: TranslatorBudget; bytes: number }>();
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Charge one event appended to an incrementally materialized adapter-event batch.
|
|
76
|
+
* The newest event owns the closing array bracket; moving that byte from the old
|
|
77
|
+
* tail keeps in-order release accounting equal to the still-retained JSON array.
|
|
78
|
+
*/
|
|
79
|
+
export function retainTranslatedEvent<T extends object>(
|
|
80
|
+
event: T,
|
|
81
|
+
budget: TranslatorBudget,
|
|
82
|
+
previousTail?: object,
|
|
83
|
+
): void {
|
|
84
|
+
if (retainedEventOwnership.has(event)) {
|
|
85
|
+
throw new Error("translated event is already retained");
|
|
86
|
+
}
|
|
87
|
+
if (previousTail === event) {
|
|
88
|
+
throw new Error("incremental translated event tail must be a distinct object");
|
|
89
|
+
}
|
|
90
|
+
const previousOwnership = previousTail === undefined
|
|
91
|
+
? undefined
|
|
92
|
+
: retainedEventOwnership.get(previousTail);
|
|
93
|
+
if (
|
|
94
|
+
previousTail !== undefined
|
|
95
|
+
&& (!previousOwnership || previousOwnership.budget !== budget || previousOwnership.bytes < 2)
|
|
96
|
+
) {
|
|
97
|
+
throw new Error("incremental translated event tail is not retained by this budget");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const serializedBytes = Buffer.byteLength(JSON.stringify(event));
|
|
101
|
+
budget.chargeRetained(serializedBytes + (previousTail === undefined ? 2 : 1), {
|
|
102
|
+
kind: "retained_collectors",
|
|
103
|
+
});
|
|
104
|
+
if (previousOwnership) previousOwnership.bytes -= 1;
|
|
105
|
+
retainedEventOwnership.set(event, { budget, bytes: serializedBytes + 2 });
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Charge a materialized adapter-event batch and attach its lease to the events themselves.
|
|
110
|
+
* A copied event array (for example terminal-guard collection) preserves the event objects, so
|
|
111
|
+
* the response builder can consume each source lease immediately after its replacement lands.
|
|
112
|
+
*/
|
|
113
|
+
export function retainTranslatedEventBatch<T extends object>(events: T[], budget: TranslatorBudget): void {
|
|
114
|
+
if (events.length === 0) return;
|
|
115
|
+
const serialized = events.map(event => JSON.stringify(event));
|
|
116
|
+
const totalBytes = Buffer.byteLength(`[${serialized.join(",")}]`);
|
|
117
|
+
budget.chargeRetained(totalBytes, { kind: "retained_collectors" });
|
|
118
|
+
for (let index = 0; index < events.length; index++) {
|
|
119
|
+
const delimiterBytes = index === events.length - 1 ? 2 : 1;
|
|
120
|
+
retainedEventOwnership.set(events[index]!, {
|
|
121
|
+
budget,
|
|
122
|
+
bytes: Buffer.byteLength(serialized[index]!) + delimiterBytes,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Transfer one charged adapter event to the response builder's newly materialized owner. */
|
|
128
|
+
export function releaseTranslatedEvent(event: object, budget: TranslatorBudget): void {
|
|
129
|
+
const ownership = retainedEventOwnership.get(event);
|
|
130
|
+
if (!ownership || ownership.budget !== budget) return;
|
|
131
|
+
retainedEventOwnership.delete(event);
|
|
132
|
+
budget.releaseRetained(ownership.bytes, { kind: "retained_collectors" });
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const liveBudgets = new Set<Budget>();
|
|
136
|
+
let aggregateCurrentBytes = 0;
|
|
137
|
+
let aggregateActiveCalls = 0;
|
|
138
|
+
let aggregateHighWaterBytes = 0;
|
|
139
|
+
let aggregateOverflows = 0;
|
|
140
|
+
|
|
141
|
+
function normalizeBytes(bytes: number): number {
|
|
142
|
+
return Number.isFinite(bytes) && bytes > 0 ? Math.floor(bytes) : 0;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function observeAggregate(): void {
|
|
146
|
+
aggregateHighWaterBytes = Math.max(aggregateHighWaterBytes, aggregateCurrentBytes);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
class Budget implements TranslatorBudget {
|
|
150
|
+
private readonly calls = new Map<string, { logicalBytes: number; physicalBytes: number }>();
|
|
151
|
+
private readonly charged = new Map<TranslatorBufferKind, number>();
|
|
152
|
+
private hardChargedBytes = 0;
|
|
153
|
+
private observedBytes = 0;
|
|
154
|
+
private currentBytes = 0;
|
|
155
|
+
private highWaterBytes = 0;
|
|
156
|
+
private overflowCount = 0;
|
|
157
|
+
private disposed = false;
|
|
158
|
+
|
|
159
|
+
constructor(
|
|
160
|
+
private readonly maxCallArgumentBytes: number,
|
|
161
|
+
private readonly maxTurnBytes: number,
|
|
162
|
+
) {}
|
|
163
|
+
|
|
164
|
+
private chargedBytes(): number {
|
|
165
|
+
return this.hardChargedBytes;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
observedCurrentBytes(): number {
|
|
169
|
+
return this.currentBytes;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
private changed(): void {
|
|
173
|
+
const nextBytes = this.hardChargedBytes + this.observedBytes;
|
|
174
|
+
aggregateCurrentBytes += nextBytes - this.currentBytes;
|
|
175
|
+
this.currentBytes = nextBytes;
|
|
176
|
+
this.highWaterBytes = Math.max(this.highWaterBytes, nextBytes);
|
|
177
|
+
observeAggregate();
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
private reject(kind: TranslatorBufferKind, limitBytes: number): never {
|
|
181
|
+
this.overflowCount += 1;
|
|
182
|
+
aggregateOverflows += 1;
|
|
183
|
+
throw new TranslatorBudgetExceededError(kind, limitBytes);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
private admit(kind: TranslatorBufferKind, bytes: number): number {
|
|
187
|
+
const admitted = normalizeBytes(bytes);
|
|
188
|
+
if (this.chargedBytes() + admitted > this.maxTurnBytes) this.reject(kind, this.maxTurnBytes);
|
|
189
|
+
return admitted;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
openCall(id: string): void {
|
|
193
|
+
if (!this.calls.has(id)) {
|
|
194
|
+
this.calls.set(id, { logicalBytes: 0, physicalBytes: 0 });
|
|
195
|
+
aggregateActiveCalls += 1;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
closeCall(id: string): void {
|
|
200
|
+
const call = this.calls.get(id);
|
|
201
|
+
if (!call) return;
|
|
202
|
+
this.hardChargedBytes = Math.max(0, this.hardChargedBytes - call.physicalBytes);
|
|
203
|
+
this.calls.delete(id);
|
|
204
|
+
aggregateActiveCalls = Math.max(0, aggregateActiveCalls - 1);
|
|
205
|
+
this.changed();
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
reserveTransient(
|
|
209
|
+
bytes: number,
|
|
210
|
+
scope: { kind: TranslatorBufferKind; callId?: string },
|
|
211
|
+
): TranslatorTransientReservation {
|
|
212
|
+
const admitted = normalizeBytes(bytes);
|
|
213
|
+
if (scope.callId && admitted > this.maxCallArgumentBytes) {
|
|
214
|
+
this.reject("tool_args", this.maxCallArgumentBytes);
|
|
215
|
+
}
|
|
216
|
+
this.admit(scope.kind, admitted);
|
|
217
|
+
this.charged.set(scope.kind, (this.charged.get(scope.kind) ?? 0) + admitted);
|
|
218
|
+
this.hardChargedBytes += admitted;
|
|
219
|
+
this.changed();
|
|
220
|
+
let state: "reserved" | "committed" | "released" = "reserved";
|
|
221
|
+
return {
|
|
222
|
+
commitRetained: () => {
|
|
223
|
+
if (state !== "reserved") return;
|
|
224
|
+
state = "committed";
|
|
225
|
+
if (!scope.callId) return;
|
|
226
|
+
const call = this.calls.get(scope.callId) ?? { logicalBytes: 0, physicalBytes: 0 };
|
|
227
|
+
this.charged.set(scope.kind, Math.max(0, (this.charged.get(scope.kind) ?? 0) - admitted));
|
|
228
|
+
call.logicalBytes = admitted;
|
|
229
|
+
call.physicalBytes += admitted;
|
|
230
|
+
this.calls.set(scope.callId, call);
|
|
231
|
+
this.changed();
|
|
232
|
+
},
|
|
233
|
+
release: () => {
|
|
234
|
+
if (state !== "reserved") return;
|
|
235
|
+
state = "released";
|
|
236
|
+
this.charged.set(scope.kind, Math.max(0, (this.charged.get(scope.kind) ?? 0) - admitted));
|
|
237
|
+
this.hardChargedBytes = Math.max(0, this.hardChargedBytes - admitted);
|
|
238
|
+
this.changed();
|
|
239
|
+
},
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
chargeRetained(delta: number, scope: { kind: TranslatorBufferKind; callId?: string }): void {
|
|
244
|
+
const admitted = normalizeBytes(delta);
|
|
245
|
+
if (scope.callId) {
|
|
246
|
+
const call = this.calls.get(scope.callId) ?? { logicalBytes: 0, physicalBytes: 0 };
|
|
247
|
+
if (call.logicalBytes + admitted > this.maxCallArgumentBytes) {
|
|
248
|
+
this.reject("tool_args", this.maxCallArgumentBytes);
|
|
249
|
+
}
|
|
250
|
+
this.admit(scope.kind, admitted);
|
|
251
|
+
call.logicalBytes += admitted;
|
|
252
|
+
call.physicalBytes += admitted;
|
|
253
|
+
this.calls.set(scope.callId, call);
|
|
254
|
+
} else {
|
|
255
|
+
this.admit(scope.kind, admitted);
|
|
256
|
+
this.charged.set(scope.kind, (this.charged.get(scope.kind) ?? 0) + admitted);
|
|
257
|
+
}
|
|
258
|
+
this.hardChargedBytes += admitted;
|
|
259
|
+
this.changed();
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
releaseRetained(bytes: number, scope: { kind: TranslatorBufferKind; callId?: string }): void {
|
|
263
|
+
const released = normalizeBytes(bytes);
|
|
264
|
+
if (scope.callId) {
|
|
265
|
+
const call = this.calls.get(scope.callId);
|
|
266
|
+
if (call) {
|
|
267
|
+
const actual = Math.min(released, call.physicalBytes);
|
|
268
|
+
call.physicalBytes -= actual;
|
|
269
|
+
this.hardChargedBytes = Math.max(0, this.hardChargedBytes - actual);
|
|
270
|
+
}
|
|
271
|
+
} else {
|
|
272
|
+
const current = this.charged.get(scope.kind) ?? 0;
|
|
273
|
+
const actual = Math.min(released, current);
|
|
274
|
+
this.charged.set(scope.kind, current - actual);
|
|
275
|
+
this.hardChargedBytes = Math.max(0, this.hardChargedBytes - actual);
|
|
276
|
+
}
|
|
277
|
+
this.changed();
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
private observe(bytes: number): () => void {
|
|
281
|
+
const observed = normalizeBytes(bytes);
|
|
282
|
+
this.observedBytes += observed;
|
|
283
|
+
this.changed();
|
|
284
|
+
let released = false;
|
|
285
|
+
return () => {
|
|
286
|
+
if (released) return;
|
|
287
|
+
released = true;
|
|
288
|
+
this.observedBytes = Math.max(0, this.observedBytes - observed);
|
|
289
|
+
this.changed();
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
observeAcceptedRequestCopy(bytes: number): () => void {
|
|
294
|
+
return this.observe(bytes);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
observeExternallyCapped(_kind: ExternallyCappedKind, bytes: number): () => void {
|
|
298
|
+
return this.observe(bytes);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
snapshot(): TranslatorBudgetSnapshot {
|
|
302
|
+
return {
|
|
303
|
+
currentBytes: this.observedCurrentBytes(),
|
|
304
|
+
highWaterBytes: this.highWaterBytes,
|
|
305
|
+
activeCalls: this.calls.size,
|
|
306
|
+
overflows: this.overflowCount,
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
dispose(): void {
|
|
311
|
+
if (this.disposed) return;
|
|
312
|
+
this.disposed = true;
|
|
313
|
+
aggregateActiveCalls = Math.max(0, aggregateActiveCalls - this.calls.size);
|
|
314
|
+
aggregateCurrentBytes = Math.max(0, aggregateCurrentBytes - this.currentBytes);
|
|
315
|
+
this.calls.clear();
|
|
316
|
+
this.charged.clear();
|
|
317
|
+
this.hardChargedBytes = 0;
|
|
318
|
+
this.observedBytes = 0;
|
|
319
|
+
this.currentBytes = 0;
|
|
320
|
+
liveBudgets.delete(this);
|
|
321
|
+
observeAggregate();
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
export function createTranslatorBudget(options: TranslatorBudgetOptions = {}): TranslatorBudget {
|
|
326
|
+
const budget = new Budget(
|
|
327
|
+
options.maxCallArgumentBytes ?? TRANSLATOR_MAX_CALL_ARGUMENT_BYTES,
|
|
328
|
+
options.maxTurnBytes ?? TRANSLATOR_MAX_TURN_BYTES,
|
|
329
|
+
);
|
|
330
|
+
liveBudgets.add(budget);
|
|
331
|
+
observeAggregate();
|
|
332
|
+
return budget;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
export function translatorObservedBufferSnapshot(): {
|
|
336
|
+
currentBytes: number;
|
|
337
|
+
highWaterBytes: number;
|
|
338
|
+
active: number;
|
|
339
|
+
} {
|
|
340
|
+
return {
|
|
341
|
+
currentBytes: aggregateCurrentBytes,
|
|
342
|
+
highWaterBytes: aggregateHighWaterBytes,
|
|
343
|
+
active: aggregateActiveCalls,
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/** Internal diagnostics used by focused tests; never registered with app-owned memory. */
|
|
348
|
+
export function translatorObservedOverflowCount(): number {
|
|
349
|
+
return aggregateOverflows;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/** Test-only: proves owned default budgets are disposed on every stream-death path. */
|
|
353
|
+
export function translatorLiveBudgetCountForTests(): number {
|
|
354
|
+
return liveBudgets.size;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/** Test-only: proves no charge survives against a disposed budget (cancel race). */
|
|
358
|
+
export function translatorAggregateCurrentBytesForTests(): number {
|
|
359
|
+
return aggregateCurrentBytes;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/** Clears process-wide translator diagnostics and disposes leaked test budgets. */
|
|
363
|
+
export function resetTranslatorAggregateForTests(): void {
|
|
364
|
+
for (const budget of liveBudgets) budget.dispose();
|
|
365
|
+
aggregateCurrentBytes = 0;
|
|
366
|
+
aggregateActiveCalls = 0;
|
|
367
|
+
aggregateHighWaterBytes = 0;
|
|
368
|
+
aggregateOverflows = 0;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
export function finalizeTranslatorBudgetResponse(response: Response, budget: TranslatorBudget): Response {
|
|
372
|
+
if (!response.body) {
|
|
373
|
+
budget.dispose();
|
|
374
|
+
return response;
|
|
375
|
+
}
|
|
376
|
+
const reader = response.body.getReader();
|
|
377
|
+
let finalized = false;
|
|
378
|
+
const finalize = () => {
|
|
379
|
+
if (finalized) return;
|
|
380
|
+
finalized = true;
|
|
381
|
+
budget.dispose();
|
|
382
|
+
};
|
|
383
|
+
return new Response(new ReadableStream<Uint8Array>({
|
|
384
|
+
async pull(controller) {
|
|
385
|
+
try {
|
|
386
|
+
const result = await reader.read();
|
|
387
|
+
if (result.done) {
|
|
388
|
+
finalize();
|
|
389
|
+
controller.close();
|
|
390
|
+
} else controller.enqueue(result.value);
|
|
391
|
+
} catch (error) {
|
|
392
|
+
finalize();
|
|
393
|
+
controller.error(error);
|
|
394
|
+
}
|
|
395
|
+
},
|
|
396
|
+
async cancel(reason) {
|
|
397
|
+
try { await reader.cancel(reason); } finally { finalize(); }
|
|
398
|
+
},
|
|
399
|
+
}), { status: response.status, statusText: response.statusText, headers: response.headers });
|
|
400
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { OcxProviderConfig, UpstreamHttpVersion } from "../types";
|
|
2
|
+
|
|
3
|
+
/** True when a provider explicitly selected the HTTP/1.1 compatibility path. */
|
|
4
|
+
export function isPinnedHttp1(version: UpstreamHttpVersion | undefined): boolean {
|
|
5
|
+
return version === "http1.1" || version === "h1";
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Bun's fetch accepts a non-standard `protocol` init to pin the HTTP version
|
|
10
|
+
* (BunFetchRequestInit.protocol). The DOM lib types do not include it, so the
|
|
11
|
+
* value is represented through a RequestInit cast at this shared boundary.
|
|
12
|
+
*/
|
|
13
|
+
const UPSTREAM_HTTP_VERSION_PROTOCOL: Record<Exclude<UpstreamHttpVersion, "auto">, string> = {
|
|
14
|
+
"http1.1": "http1.1",
|
|
15
|
+
h1: "h1",
|
|
16
|
+
http2: "http2",
|
|
17
|
+
h2: "h2",
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/** Raised before I/O when a fixed Bun HTTP-version pin cannot apply to the target URL. */
|
|
21
|
+
export class UpstreamHttpVersionTargetError extends Error {
|
|
22
|
+
readonly code = "upstream_http_version_target";
|
|
23
|
+
|
|
24
|
+
constructor(readonly observedProtocol: string) {
|
|
25
|
+
super(`upstream HTTP version pin requires an HTTPS target (received ${observedProtocol})`);
|
|
26
|
+
this.name = "UpstreamHttpVersionTargetError";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** Attach Bun's `protocol` pin for one explicit version value. */
|
|
31
|
+
export function withUpstreamHttpVersionValue(
|
|
32
|
+
input: Parameters<typeof globalThis.fetch>[0],
|
|
33
|
+
init: RequestInit | undefined,
|
|
34
|
+
version: UpstreamHttpVersion | undefined,
|
|
35
|
+
): RequestInit | undefined {
|
|
36
|
+
if (!version || version === "auto") return init;
|
|
37
|
+
// Bun's protocol pin requires an https: target. An explicit fixed-version request must fail
|
|
38
|
+
// locally when the pin cannot be honored instead of silently negotiating another transport.
|
|
39
|
+
const target = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
40
|
+
let targetUrl: URL;
|
|
41
|
+
try {
|
|
42
|
+
targetUrl = new URL(target);
|
|
43
|
+
} catch {
|
|
44
|
+
throw new UpstreamHttpVersionTargetError("unparseable");
|
|
45
|
+
}
|
|
46
|
+
if (targetUrl.protocol !== "https:") throw new UpstreamHttpVersionTargetError(targetUrl.protocol);
|
|
47
|
+
return { ...(init ?? {}), protocol: UPSTREAM_HTTP_VERSION_PROTOCOL[version] } as RequestInit;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Attach Bun's `protocol` pin when the provider opted into a fixed HTTP version. */
|
|
51
|
+
export function withUpstreamHttpVersion(
|
|
52
|
+
input: Parameters<typeof globalThis.fetch>[0],
|
|
53
|
+
init: RequestInit | undefined,
|
|
54
|
+
provider: Pick<OcxProviderConfig, "upstreamHttpVersion">,
|
|
55
|
+
): RequestInit | undefined {
|
|
56
|
+
return withUpstreamHttpVersionValue(input, init, provider.upstreamHttpVersion);
|
|
57
|
+
}
|