@iislee/opencodex 2.11.0 → 2.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS_INSTALL.md +109 -0
- package/README.md +117 -22
- package/bin/ocx.mjs +245 -88
- package/bin/package-main.mjs +1 -1
- package/gui/dist/assets/index-Be1sDpWw.css +1 -0
- package/gui/dist/assets/index-D4OKgUV4.js +114 -0
- package/gui/dist/index.html +2 -2
- package/gui/dist/provider-icons/alibaba-color.svg +1 -1
- package/gui/dist/provider-icons/antigravity-color.svg +1 -1
- package/gui/dist/provider-icons/claude-color.svg +1 -1
- package/gui/dist/provider-icons/cline-color.svg +16 -0
- package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/commandcode-color.svg +1 -0
- package/gui/dist/provider-icons/copilot-color.svg +1 -1
- package/gui/dist/provider-icons/cursor-color.svg +1 -1
- package/gui/dist/provider-icons/deepseek-color.svg +1 -1
- package/gui/dist/provider-icons/firepass-color.svg +1 -1
- package/gui/dist/provider-icons/fireworks-color.svg +1 -1
- package/gui/dist/provider-icons/gemini-color.svg +1 -1
- package/gui/dist/provider-icons/github-copilot-color.svg +1 -1
- package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -1
- package/gui/dist/provider-icons/grok.svg +1 -1
- package/gui/dist/provider-icons/groq-color.svg +1 -1
- package/gui/dist/provider-icons/huggingface-color.svg +1 -1
- package/gui/dist/provider-icons/kimi-color.svg +1 -1
- package/gui/dist/provider-icons/kiro-color.svg +2 -2
- package/gui/dist/provider-icons/lm-studio-color.svg +1 -1
- package/gui/dist/provider-icons/mistral-color.svg +1 -1
- package/gui/dist/provider-icons/moonshot-color.svg +1 -1
- package/gui/dist/provider-icons/nvidia-color.svg +1 -1
- package/gui/dist/provider-icons/ollama-color.svg +1 -1
- package/gui/dist/provider-icons/openai.svg +1 -1
- package/gui/dist/provider-icons/opencode.svg +2 -1
- package/gui/dist/provider-icons/openrouter-color.svg +1 -1
- package/gui/dist/provider-icons/pi.svg +2 -2
- package/gui/dist/provider-icons/qianfan-color.svg +1 -1
- package/gui/dist/provider-icons/qwen-portal-color.svg +1 -1
- package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/vllm-color.svg +1 -1
- package/gui/dist/provider-icons/xiaomi-color.svg +1 -1
- package/package.json +21 -10
- package/src/adapters/anthropic-output-schema.ts +137 -0
- package/src/adapters/anthropic.ts +475 -62
- package/src/adapters/base.ts +82 -7
- package/src/adapters/client-fingerprint.ts +18 -12
- package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
- package/src/adapters/command-code.ts +637 -0
- package/src/adapters/cursor/call-id.ts +44 -0
- package/src/adapters/cursor/catalog.ts +541 -0
- package/src/adapters/cursor/checkpoint-store.ts +308 -0
- package/src/adapters/cursor/cursor-errors.ts +144 -6
- package/src/adapters/cursor/discovery.ts +122 -14
- package/src/adapters/cursor/effort-map.ts +106 -4
- package/src/adapters/cursor/envelope-echo.ts +290 -0
- package/src/adapters/cursor/framing.ts +39 -0
- package/src/adapters/cursor/h2-pool.ts +123 -0
- package/src/adapters/cursor/http1-bidi.ts +361 -0
- package/src/adapters/cursor/images.ts +704 -0
- package/src/adapters/cursor/live-models.ts +180 -59
- package/src/adapters/cursor/live-transport.ts +623 -170
- package/src/adapters/cursor/message-mapper.ts +4 -1
- package/src/adapters/cursor/native-exec-common.ts +23 -2
- package/src/adapters/cursor/native-exec-desktop.ts +23 -0
- package/src/adapters/cursor/native-exec-fs.ts +10 -7
- package/src/adapters/cursor/native-exec-network.ts +1 -1
- package/src/adapters/cursor/native-exec-shell.ts +5 -3
- package/src/adapters/cursor/native-exec.ts +121 -14
- package/src/adapters/cursor/protobuf-events.ts +829 -11
- package/src/adapters/cursor/protobuf-request.ts +447 -75
- package/src/adapters/cursor/request-builder.ts +271 -35
- package/src/adapters/cursor/tool-definitions.ts +252 -12
- package/src/adapters/cursor/tool-result-normalize.ts +115 -0
- package/src/adapters/cursor/transport.ts +22 -0
- package/src/adapters/cursor/types.ts +48 -1
- package/src/adapters/cursor.ts +336 -39
- package/src/adapters/exec-tool-result-normalize.ts +99 -0
- package/src/adapters/google-antigravity-replay.ts +713 -41
- package/src/adapters/google-antigravity-wire.ts +48 -10
- package/src/adapters/google-errors.ts +44 -12
- package/src/adapters/google-http.ts +38 -10
- package/src/adapters/google-tool-schema.ts +80 -15
- package/src/adapters/google-truncation.ts +11 -0
- package/src/adapters/google.ts +742 -86
- package/src/adapters/identity.ts +39 -6
- package/src/adapters/image.ts +1 -1
- package/src/adapters/kiro-constants.ts +27 -0
- package/src/adapters/kiro-errors.ts +11 -0
- package/src/adapters/kiro-events.ts +19 -1
- package/src/adapters/kiro-thinking.ts +18 -2
- package/src/adapters/kiro-tools.ts +65 -17
- package/src/adapters/kiro.ts +270 -73
- package/src/adapters/mimo-free.ts +17 -0
- package/src/adapters/openai-chat-url.ts +11 -0
- package/src/adapters/openai-chat.ts +1377 -344
- package/src/adapters/openai-responses-url.ts +16 -0
- package/src/adapters/openai-responses.ts +1164 -64
- package/src/adapters/registry.ts +175 -0
- package/src/adapters/responses-tool-schema.ts +67 -0
- package/src/adapters/run-turn-queue.ts +36 -1
- package/src/adapters/tool-call-id.ts +119 -0
- package/src/adapters/tool-catalog-nudge.ts +105 -21
- package/src/adapters/xai-tool-schema.ts +436 -0
- package/src/adapters/xai-web-search.ts +186 -0
- package/src/bridge.ts +512 -92
- package/src/chat/inbound.ts +57 -20
- package/src/chat/outbound.ts +97 -33
- package/src/claude/agents-inject.ts +40 -10
- package/src/claude/context-windows.ts +37 -14
- package/src/claude/desktop-3p.ts +243 -9
- package/src/claude/gateway-cache.ts +41 -4
- package/src/claude/inbound.ts +72 -3
- package/src/claude/model-info.ts +38 -15
- package/src/claude/outbound.ts +88 -21
- package/src/cli/access.ts +46 -3
- package/src/cli/account-api.ts +150 -19
- package/src/cli/account-auth.ts +33 -6
- package/src/cli/account-catalog-refresh.ts +14 -0
- package/src/cli/account-extended.ts +648 -28
- package/src/cli/account-main.ts +317 -0
- package/src/cli/account.ts +97 -19
- package/src/cli/agent.ts +53 -2
- package/src/cli/alias.ts +66 -0
- package/src/cli/capabilities-command.ts +94 -0
- package/src/cli/capabilities.ts +496 -0
- package/src/cli/claude-agent-startup-sync.ts +73 -0
- package/src/cli/claude-desktop.ts +60 -15
- package/src/cli/claude.ts +129 -35
- package/src/cli/codex-log-guard-doctor.ts +103 -0
- package/src/cli/codex-shim-autorestore.ts +2 -0
- package/src/cli/codex-shim-readiness.ts +76 -0
- package/src/cli/combo.ts +8 -0
- package/src/cli/config-command.ts +74 -10
- package/src/cli/dispatch.ts +821 -0
- package/src/cli/doctor.ts +440 -56
- package/src/cli/ensure-desired-integrations.ts +152 -0
- package/src/cli/export-command.ts +46 -20
- package/src/cli/help.ts +34 -274
- package/src/cli/index.ts +417 -528
- package/src/cli/init.ts +5 -17
- package/src/cli/inspect.ts +230 -0
- package/src/cli/integrations.ts +120 -2
- package/src/cli/lab.ts +607 -0
- package/src/cli/launcher-context.ts +77 -0
- package/src/cli/minimax.ts +497 -0
- package/src/cli/models-runtime.ts +130 -2
- package/src/cli/models.ts +118 -16
- package/src/cli/observe.ts +123 -11
- package/src/cli/opencode.ts +4 -2
- package/src/cli/provider-runtime.ts +34 -3
- package/src/cli/provider.ts +25 -3
- package/src/cli/ready.ts +301 -0
- package/src/cli/registry.ts +476 -0
- package/src/cli/root.ts +86 -0
- package/src/cli/route-policy.ts +92 -0
- package/src/cli/runtime-api.ts +57 -10
- package/src/cli/star-prompt.ts +71 -15
- package/src/cli/status.ts +51 -4
- package/src/cli/storage.ts +234 -0
- package/src/cli/system-command.ts +16 -0
- package/src/cli/system-restart-client.ts +146 -0
- package/src/cli/tray-proxy.ts +153 -6
- package/src/cli/usage-report.ts +184 -0
- package/src/cli/v2.ts +137 -18
- package/src/cli/version-skew.ts +46 -0
- package/src/cli.ts +1 -1
- package/src/clients/config-export.ts +1442 -23
- package/src/clients/effective-status.ts +30 -2
- package/src/clients/probes/cline.ts +81 -0
- package/src/codex/account-label.ts +35 -1
- package/src/codex/account-lifecycle.ts +130 -13
- package/src/codex/account-namespaces.ts +49 -3
- package/src/codex/account-pause.ts +2 -1
- package/src/codex/account-priority.ts +84 -0
- package/src/codex/account-store.ts +29 -2
- package/src/codex/account-usability.ts +25 -2
- package/src/codex/admission.ts +256 -0
- package/src/codex/affinity-debug.ts +162 -0
- package/src/codex/app-server-processes.ts +570 -107
- package/src/codex/app-server-restart-service.ts +232 -0
- package/src/codex/auth-api.ts +893 -246
- package/src/codex/auth-collision.ts +5 -3
- package/src/codex/auth-context.ts +348 -32
- package/src/codex/autostart-health.ts +24 -1
- package/src/codex/catalog/account-models.ts +67 -0
- package/src/codex/catalog/aggregation.ts +86 -10
- package/src/codex/catalog/bundled.ts +331 -33
- package/src/codex/catalog/effort.ts +138 -32
- package/src/codex/catalog/filesystem-evidence.ts +302 -0
- package/src/codex/catalog/kinds.ts +2 -0
- package/src/codex/catalog/metadata.ts +555 -45
- package/src/codex/catalog/native-models.ts +75 -0
- package/src/codex/catalog/parsing.ts +269 -30
- package/src/codex/catalog/provider-fetch.ts +1626 -144
- package/src/codex/catalog/sync.ts +1576 -187
- package/src/codex/catalog-admission.ts +199 -0
- package/src/codex/catalog-refresh-status.ts +105 -0
- package/src/codex/catalog-write-serialization.ts +242 -0
- package/src/codex/catalog.ts +6 -3
- package/src/codex/codex-write-lock.ts +386 -0
- package/src/codex/convergence-types.ts +614 -0
- package/src/codex/convergence.ts +676 -0
- package/src/codex/coordinator-doctor.ts +332 -0
- package/src/codex/custom-model-catalog-migration.ts +176 -0
- package/src/codex/desired-state.ts +230 -0
- package/src/codex/desktop-app-restart.ts +355 -0
- package/src/codex/features.ts +636 -39
- package/src/codex/generation.ts +202 -0
- package/src/codex/history-job.ts +436 -0
- package/src/codex/history-lock.ts +242 -0
- package/src/codex/history-manifest.ts +112 -0
- package/src/codex/history-migration-guardian.ts +30 -24
- package/src/codex/history-provider.ts +1016 -235
- package/src/codex/history-transition.ts +105 -0
- package/src/codex/history-worker.ts +223 -0
- package/src/codex/inject-coordination.ts +373 -0
- package/src/codex/inject.ts +1114 -152
- package/src/codex/injected-marker.ts +37 -3
- package/src/codex/integration-record.ts +266 -0
- package/src/codex/internal/catalog-writer.ts +203 -0
- package/src/codex/internal/history-writer.ts +81 -0
- package/src/codex/journal.ts +66 -4
- package/src/codex/log-guard/inspect.ts +524 -0
- package/src/codex/log-guard/lock.ts +150 -0
- package/src/codex/log-guard/maintenance.ts +403 -0
- package/src/codex/log-guard/path-safety.ts +88 -0
- package/src/codex/log-guard/policy.ts +44 -0
- package/src/codex/log-guard/processes.ts +205 -0
- package/src/codex/log-guard/protection.ts +489 -0
- package/src/codex/log-guard/sqlite-errors.ts +9 -0
- package/src/codex/main-account-cache.ts +24 -0
- package/src/codex/main-account.ts +29 -1
- package/src/codex/management-convergence.ts +167 -0
- package/src/codex/model-cache.ts +56 -10
- package/src/codex/model-entitlements.ts +360 -0
- package/src/codex/native-main-admission.ts +47 -0
- package/src/codex/native-main-auth-temp.ts +187 -0
- package/src/codex/native-main-claim.ts +178 -0
- package/src/codex/native-main-lock-file.ts +162 -0
- package/src/codex/native-main-owner.ts +329 -0
- package/src/codex/native-profile-api.ts +247 -0
- package/src/codex/native-profile-manager.ts +1531 -0
- package/src/codex/native-profile-processes.ts +121 -0
- package/src/codex/native-profile-recovery.ts +99 -0
- package/src/codex/native-profile-stage-store.ts +387 -0
- package/src/codex/native-profile-startup.ts +622 -0
- package/src/codex/native-profile-store.ts +855 -0
- package/src/codex/native-profile-types.ts +120 -0
- package/src/codex/native-residue.ts +675 -0
- package/src/codex/paths.ts +80 -1
- package/src/codex/plan-from-token.ts +140 -0
- package/src/codex/plan.ts +40 -0
- package/src/codex/plugins-doctor.ts +1 -1
- package/src/codex/pool-rotation.ts +74 -4
- package/src/codex/project-config-warnings.ts +20 -6
- package/src/codex/prompt-journal.ts +352 -0
- package/src/codex/prompt-layers.ts +1313 -0
- package/src/codex/prompt-lock.ts +143 -0
- package/src/codex/prompt-text-probe.ts +238 -0
- package/src/codex/quota-rejection.ts +298 -0
- package/src/codex/quota.ts +264 -21
- package/src/codex/refresh.ts +11 -2
- package/src/codex/reset-credit-recovery.ts +1044 -0
- package/src/codex/routing.ts +514 -94
- package/src/codex/runtime.ts +159 -38
- package/src/codex/shim.ts +1065 -31
- package/src/codex/subagent-model-fallback.ts +437 -43
- package/src/codex/sync.ts +191 -2
- package/src/codex/transition-state.ts +720 -0
- package/src/codex/upstream-host-health.ts +368 -0
- package/src/codex/user-identity.ts +557 -0
- package/src/codex/warmup.ts +187 -81
- package/src/codex/write-coordination.ts +114 -0
- package/src/combos/failover.ts +47 -0
- package/src/combos/index.ts +4 -0
- package/src/combos/request.ts +32 -0
- package/src/combos/types.ts +91 -9
- package/src/compatibility/index.ts +26 -0
- package/src/compatibility/manifest.ts +253 -0
- package/src/compatibility/openai-responses.ts +121 -0
- package/src/config/atomic-write.ts +219 -0
- package/src/config/paths.ts +40 -0
- package/src/config/process-state.ts +309 -0
- package/src/config/provider-name.ts +24 -0
- package/src/config/provider-validation.ts +177 -0
- package/src/config/rebase-provenance.ts +68 -0
- package/src/config.ts +1713 -709
- package/src/generated/compatibility-version.json +3324 -0
- package/src/generated/{jawcode-model-metadata.ts → model-metadata.ts} +19 -17
- package/src/grok/inject.ts +16 -5
- package/src/grok/inspect.ts +45 -0
- package/src/grok/sync.ts +2 -2
- package/src/images/loop.ts +157 -33
- package/src/images/plan.ts +24 -13
- package/src/integrations/config-io.ts +269 -0
- package/src/integrations/journal.ts +315 -0
- package/src/integrations/merge.ts +135 -0
- package/src/integrations/mutation-flight.ts +71 -0
- package/src/integrations/native/ownership-preflight.ts +202 -0
- package/src/integrations/omp-yaml-source.ts +358 -0
- package/src/integrations/owned-refresh.ts +74 -0
- package/src/integrations/ownership-policy.ts +160 -0
- package/src/integrations/ownership.ts +155 -0
- package/src/integrations/registry.ts +166 -0
- package/src/integrations/serialize.ts +314 -0
- package/src/integrations/state.ts +433 -0
- package/src/integrations/store.ts +103 -0
- package/src/integrations/writer-lock.ts +98 -0
- package/src/integrations/writer.ts +715 -0
- package/src/lab/artifacts/sanitize.ts +586 -0
- package/src/lab/artifacts/secure-fs.ts +475 -0
- package/src/lab/artifacts/store.ts +310 -0
- package/src/lab/automation/budgets.ts +78 -0
- package/src/lab/automation/config-persistence.ts +256 -0
- package/src/lab/automation/constants.ts +39 -0
- package/src/lab/automation/cooldown.ts +103 -0
- package/src/lab/automation/dispatch.ts +211 -0
- package/src/lab/automation/index.ts +13 -0
- package/src/lab/automation/orchestrator.ts +499 -0
- package/src/lab/automation/persistence.ts +512 -0
- package/src/lab/automation/planner.ts +371 -0
- package/src/lab/automation/policy.ts +136 -0
- package/src/lab/automation/queue.ts +191 -0
- package/src/lab/automation/recovery.ts +24 -0
- package/src/lab/automation/route-context.ts +21 -0
- package/src/lab/automation/run-key.ts +44 -0
- package/src/lab/automation/runs-query.ts +34 -0
- package/src/lab/automation/types.ts +160 -0
- package/src/lab/conformance/assertion.ts +325 -0
- package/src/lab/conformance/digest.ts +22 -0
- package/src/lab/conformance/executor.ts +741 -0
- package/src/lab/conformance/fixture-provider.ts +27 -0
- package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
- package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
- package/src/lab/conformance/harness-budget.ts +47 -0
- package/src/lab/conformance/index.ts +5 -0
- package/src/lab/conformance/jcs.ts +64 -0
- package/src/lab/conformance/json-pointer.ts +39 -0
- package/src/lab/conformance/manifest.ts +180 -0
- package/src/lab/conformance/mcp-stub.ts +179 -0
- package/src/lab/conformance/negative-controls.ts +164 -0
- package/src/lab/conformance/observation.ts +355 -0
- package/src/lab/conformance/runner.ts +68 -0
- package/src/lab/conformance/sse-normalize.ts +59 -0
- package/src/lab/conformance/suite-manifest.ts +78 -0
- package/src/lab/conformance/types.ts +214 -0
- package/src/lab/constants.ts +126 -0
- package/src/lab/digest.ts +64 -0
- package/src/lab/events/errors.ts +9 -0
- package/src/lab/events/limits.ts +117 -0
- package/src/lab/events/types.ts +229 -0
- package/src/lab/events/validate.ts +781 -0
- package/src/lab/fabric/constants.ts +40 -0
- package/src/lab/fabric/executor.ts +492 -0
- package/src/lab/fabric/index.ts +80 -0
- package/src/lab/fabric/manifest.ts +222 -0
- package/src/lab/fabric/observe.ts +489 -0
- package/src/lab/fabric/patch.ts +79 -0
- package/src/lab/fabric/producer-child.ts +139 -0
- package/src/lab/fabric/producer-isolate.ts +276 -0
- package/src/lab/fabric/producer-protocol.ts +61 -0
- package/src/lab/fabric/scratch.ts +439 -0
- package/src/lab/fabric/subject.ts +106 -0
- package/src/lab/fabric/types.ts +134 -0
- package/src/lab/fabric/verifier.ts +98 -0
- package/src/lab/index.ts +54 -0
- package/src/lab/ledger/artifact-refs.ts +127 -0
- package/src/lab/ledger/invalidation.ts +136 -0
- package/src/lab/ledger/purge.ts +310 -0
- package/src/lab/ledger/store.ts +532 -0
- package/src/lab/live/credential-lease.ts +53 -0
- package/src/lab/live/destination.ts +155 -0
- package/src/lab/live/executor.ts +336 -0
- package/src/lab/live/inert-tools.ts +56 -0
- package/src/lab/live/manifest.ts +85 -0
- package/src/lab/live/mcp-loopback.ts +57 -0
- package/src/lab/live/runner.ts +19 -0
- package/src/lab/live/sandbox.ts +61 -0
- package/src/lab/live/suite-manifest.ts +41 -0
- package/src/lab/live/transport.ts +118 -0
- package/src/lab/live/types.ts +197 -0
- package/src/lab/observe/from-conformance.ts +301 -0
- package/src/lab/observe/from-live.ts +117 -0
- package/src/lab/paths.ts +153 -0
- package/src/lab/projection/rebuild.ts +495 -0
- package/src/lab/projection/schema.ts +135 -0
- package/src/lab/projection/verdicts.ts +474 -0
- package/src/lab/projection/verification.ts +412 -0
- package/src/lab/public/bundle.ts +217 -0
- package/src/lab/public/community-authority.ts +175 -0
- package/src/lab/public/community-files.ts +29 -0
- package/src/lab/public/community.ts +479 -0
- package/src/lab/public/file-safety.ts +155 -0
- package/src/lab/public/ids.ts +26 -0
- package/src/lab/public/index.ts +16 -0
- package/src/lab/public/mutation-lock.ts +424 -0
- package/src/lab/public/operator.ts +353 -0
- package/src/lab/public/origin-purge.ts +79 -0
- package/src/lab/public/origin.ts +203 -0
- package/src/lab/public/privacy.ts +143 -0
- package/src/lab/public/private-file.ts +261 -0
- package/src/lab/public/project.ts +124 -0
- package/src/lab/public/purge-test-fault.ts +21 -0
- package/src/lab/public/purge.ts +223 -0
- package/src/lab/public/registry.ts +44 -0
- package/src/lab/public/revocation.ts +252 -0
- package/src/lab/public/signature.ts +243 -0
- package/src/lab/public/storage.ts +105 -0
- package/src/lab/public/strict-json.ts +206 -0
- package/src/lab/public/time.ts +26 -0
- package/src/lab/public/types.ts +172 -0
- package/src/lab/public/validate.ts +391 -0
- package/src/lab/query/catalog.ts +101 -0
- package/src/lab/query/connection.ts +107 -0
- package/src/lab/query/constants.ts +4 -0
- package/src/lab/query/cursor.ts +132 -0
- package/src/lab/query/dto-map.ts +277 -0
- package/src/lab/query/errors.ts +22 -0
- package/src/lab/query/freshness.ts +53 -0
- package/src/lab/query/index.ts +45 -0
- package/src/lab/query/latest-observation.ts +59 -0
- package/src/lab/query/passive-production.ts +159 -0
- package/src/lab/query/queries.ts +444 -0
- package/src/lab/query/types.ts +266 -0
- package/src/lab/subject/behavior-fingerprint.ts +77 -0
- package/src/lab/subject/installation-salt.ts +112 -0
- package/src/lab/subject/protocol-subject.ts +80 -0
- package/src/lab/subject/route-subject.ts +74 -0
- package/src/lib/admin-secrets.ts +24 -0
- package/src/lib/app-owned-memory-stores.ts +22 -0
- package/src/lib/bounded-body.ts +167 -11
- package/src/lib/bun-runtime.ts +125 -12
- package/src/lib/bun-stream-caps.ts +13 -9
- package/src/lib/codex-restart-contract.ts +120 -0
- package/src/lib/config-ownership.ts +26 -2
- package/src/lib/destination-policy.ts +65 -1
- package/src/lib/errors.ts +80 -5
- package/src/lib/fabric-task-execution-authority.ts +7 -0
- package/src/lib/fabric-task-host.ts +29 -0
- package/src/lib/lab-activation.ts +223 -0
- package/src/lib/lab-live-execution-authority.ts +13 -0
- package/src/lib/lab-live-host.ts +30 -0
- package/src/lib/lab-live-pinned-sender.ts +56 -0
- package/src/lib/lab-live-route-production.ts +130 -0
- package/src/lib/lab-passive-linker-registration.ts +26 -0
- package/src/lib/local-management-attestation.ts +51 -0
- package/src/lib/local-management-capability.ts +100 -0
- package/src/lib/local-provider-reload-contract.ts +100 -0
- package/src/lib/optional-shutdown-hooks.ts +57 -0
- package/src/lib/package-tree-integrity.ts +101 -0
- package/src/lib/pinned-http.ts +145 -26
- package/src/lib/process-control.ts +6 -2
- package/src/lib/provider-outbound.ts +49 -9
- package/src/lib/redact.ts +419 -3
- package/src/lib/self-launch-argv.ts +15 -0
- package/src/lib/server-resource-ownership.ts +71 -0
- package/src/lib/service-secrets.ts +15 -0
- package/src/lib/shadow-call.ts +35 -4
- package/src/lib/sse-decoder.ts +41 -0
- package/src/lib/state-store-registrations.ts +10 -2
- package/src/lib/system-restart-contract.ts +73 -0
- package/src/lib/token-estimate.ts +19 -2
- package/src/lib/tool-argument-integers.ts +253 -0
- package/src/lib/translator-budget.ts +44 -0
- package/src/lib/upstream-http-version.ts +57 -0
- package/src/lib/upstream-reachability.ts +95 -0
- package/src/lib/upstream-retry.ts +156 -3
- package/src/lib/windows-atomic-replace.ts +155 -0
- package/src/lib/windows-elevation.ts +70 -2
- package/src/lib/windows-secret-acl.ts +409 -69
- package/src/lib/windows-service-wrappers.ts +72 -0
- package/src/lib/windows-text.ts +106 -0
- package/src/lib/windows-user-principal.ts +341 -0
- package/src/lib/winsw.ts +33 -5
- package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
- package/src/oauth/account-import/index.ts +15 -0
- package/src/oauth/account-import/parser.ts +83 -0
- package/src/oauth/account-import/registry.ts +18 -0
- package/src/oauth/account-import/service.ts +75 -0
- package/src/oauth/account-import/types.ts +91 -0
- package/src/oauth/anthropic.ts +12 -1
- package/src/oauth/callback-server.ts +30 -4
- package/src/oauth/chatgpt.ts +12 -1
- package/src/oauth/cline.ts +203 -0
- package/src/oauth/command-code.ts +239 -0
- package/src/oauth/cursor.ts +46 -5
- package/src/oauth/generic-account-failover.ts +231 -0
- package/src/oauth/google-antigravity.ts +35 -3
- package/src/oauth/health.ts +20 -12
- package/src/oauth/index.ts +462 -71
- package/src/oauth/key-providers.ts +25 -0
- package/src/oauth/kimi.ts +25 -3
- package/src/oauth/kiro.ts +95 -6
- package/src/oauth/local-token-detect.ts +13 -2
- package/src/oauth/log.ts +3 -1
- package/src/oauth/login-cli.ts +88 -28
- package/src/oauth/nous.ts +798 -0
- package/src/oauth/open-browser-choice.ts +26 -0
- package/src/oauth/store.ts +133 -26
- package/src/oauth/token-guardian.ts +9 -3
- package/src/oauth/types.ts +15 -0
- package/src/pi/models.ts +2 -2
- package/src/providers/alibaba-region-migration.ts +1 -1
- package/src/providers/antigravity-models.ts +521 -31
- package/src/providers/auto-compact-budget.ts +65 -0
- package/src/providers/base-url-choices.ts +10 -0
- package/src/providers/codex-capacity.ts +292 -0
- package/src/providers/command-code-efforts.ts +176 -0
- package/src/providers/context-cap.ts +26 -8
- package/src/providers/cursor-pool.ts +72 -0
- package/src/providers/default-aliases.ts +65 -0
- package/src/providers/derive.ts +281 -6
- package/src/providers/fastwire.ts +507 -0
- package/src/providers/free-directory.ts +10 -7
- package/src/providers/google-vertex-location.ts +14 -0
- package/src/providers/key-failover.ts +71 -3
- package/src/providers/label.ts +35 -2
- package/src/providers/model-discovery-limits.ts +16 -0
- package/src/providers/model-discovery.ts +115 -22
- package/src/providers/model-presets.ts +119 -0
- package/src/providers/model-rename-migration.ts +255 -0
- package/src/providers/model-rename-startup.ts +28 -0
- package/src/providers/new-model-policy.ts +146 -0
- package/src/providers/openai-sidecar.ts +72 -4
- package/src/providers/openai-tier-startup.ts +31 -2
- package/src/providers/openai-tiers.ts +119 -4
- package/src/providers/openai-virtual-models.ts +1 -0
- package/src/providers/opencode-zen-rate-limit.ts +102 -0
- package/src/providers/provider-id-rewrite.ts +30 -0
- package/src/providers/quota.ts +1379 -40
- package/src/providers/registry.ts +1545 -112
- package/src/providers/request-pacing.ts +310 -0
- package/src/providers/service-tier.ts +277 -0
- package/src/providers/slug-codec.ts +94 -6
- package/src/providers/static-model-discovery.ts +86 -0
- package/src/providers/xai-responses-opt-in.ts +15 -0
- package/src/providers/xai-transport.ts +32 -4
- package/src/reasoning-effort.ts +68 -3
- package/src/responses/apply-patch-envelope.ts +63 -0
- package/src/responses/code-mode-helper-compat.ts +50 -0
- package/src/responses/compaction.ts +26 -1
- package/src/responses/custom-tool-compat.ts +384 -0
- package/src/responses/hosted-tool-policy.ts +9 -0
- package/src/responses/namespace-tool-compat.ts +435 -0
- package/src/responses/parser.ts +225 -38
- package/src/responses/provider-continuation.ts +98 -0
- package/src/responses/provider-opaque-metadata.ts +73 -0
- package/src/responses/reasoning-envelope.ts +9 -1
- package/src/responses/reasoning-replay-cache.ts +504 -0
- package/src/responses/schema.ts +12 -2
- package/src/responses/spill-store.ts +75 -10
- package/src/responses/state.ts +659 -31
- package/src/responses/thought-signature-replay.ts +364 -0
- package/src/responses/tool-search-compat.ts +301 -0
- package/src/responses/truncated-stop-reason.ts +60 -0
- package/src/responses/turn-termination.ts +107 -0
- package/src/router.ts +405 -31
- package/src/routing/analytics.ts +379 -0
- package/src/routing/capability.ts +244 -0
- package/src/routing/compatibility/assemble.ts +73 -0
- package/src/routing/compatibility/behavior.ts +278 -0
- package/src/routing/compatibility/catalog.ts +99 -0
- package/src/routing/compatibility/endpoint.ts +52 -0
- package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
- package/src/routing/compatibility/policy.ts +181 -0
- package/src/routing/compatibility/provider-slot.ts +56 -0
- package/src/routing/compatibility/reader.ts +110 -0
- package/src/routing/compatibility/subject.ts +191 -0
- package/src/routing/compatibility/types.ts +64 -0
- package/src/routing/compatibility/version.ts +104 -0
- package/src/routing/cost.ts +77 -0
- package/src/routing/evaluator.ts +495 -0
- package/src/routing/health.ts +412 -0
- package/src/routing/history/cursor.ts +43 -0
- package/src/routing/history/indexer.ts +605 -0
- package/src/routing/history/schema.ts +72 -0
- package/src/routing/profile-namespace.ts +15 -0
- package/src/routing/profile.ts +547 -0
- package/src/routing/quota.ts +155 -0
- package/src/routing/request-evidence.ts +45 -0
- package/src/routing/trace.ts +776 -0
- package/src/server/adapter-resolve.ts +2 -29
- package/src/server/auth-cors.ts +289 -48
- package/src/server/background-lifecycle.ts +182 -0
- package/src/server/chat-completions.ts +154 -72
- package/src/server/chat-native-sse.ts +331 -0
- package/src/server/chat-native.ts +445 -0
- package/src/server/claude-messages.ts +160 -44
- package/src/server/direct-local-http.ts +347 -0
- package/src/server/effort-policy.ts +18 -0
- package/src/server/github-copilot-responses-repair.ts +338 -0
- package/src/server/gui-static.ts +39 -10
- package/src/server/images.ts +94 -12
- package/src/server/index.ts +1021 -190
- package/src/server/lifecycle.ts +336 -14
- package/src/server/live.ts +136 -17
- package/src/server/local-management-read-client.ts +90 -0
- package/src/server/local-provider-reload-client.ts +137 -0
- package/src/server/management/agent-settings-routes.ts +433 -116
- package/src/server/management/api-key-usage.ts +31 -5
- package/src/server/management/body.ts +6 -0
- package/src/server/management/codex-prompt-routes.ts +570 -0
- package/src/server/management/combo-routes.ts +64 -25
- package/src/server/management/config-routes.ts +511 -51
- package/src/server/management/context.ts +89 -2
- package/src/server/management/integration-routes.ts +498 -0
- package/src/server/management/lab-automation-routes.ts +206 -0
- package/src/server/management/lab-routes.ts +563 -0
- package/src/server/management/logs-usage-routes.ts +127 -52
- package/src/server/management/model-routes.ts +461 -133
- package/src/server/management/model-rows.ts +167 -0
- package/src/server/management/native-integration-routes.ts +770 -0
- package/src/server/management/oauth-account-routes.ts +90 -8
- package/src/server/management/provider-capability-config.ts +48 -0
- package/src/server/management/provider-routes.ts +836 -159
- package/src/server/management/request-history-routes.ts +191 -0
- package/src/server/management/route-registry.ts +332 -0
- package/src/server/management/routing-analytics-routes.ts +74 -0
- package/src/server/management/routing-profile-routes.ts +380 -0
- package/src/server/management/shared.ts +27 -11
- package/src/server/management/sidebar-routes.ts +47 -31
- package/src/server/management/storage-log-guard-routes.ts +186 -0
- package/src/server/management/sync-response.ts +69 -0
- package/src/server/management/system-restart.ts +289 -33
- package/src/server/management/system-routes.ts +77 -0
- package/src/server/management/usage-summary-cache.ts +9 -1
- package/src/server/management/vision-sidecar-options.ts +167 -0
- package/src/server/management/web-search-sidecar-options.ts +120 -0
- package/src/server/management-api.ts +126 -23
- package/src/server/management-auth.ts +220 -5
- package/src/server/passive-route-linker.ts +66 -0
- package/src/server/port-reclaim.ts +1 -1
- package/src/server/ports.ts +41 -1
- package/src/server/proxy-liveness.ts +161 -10
- package/src/server/readiness.ts +99 -0
- package/src/server/relay-eager.ts +221 -54
- package/src/server/relay.ts +479 -87
- package/src/server/request-decompress.ts +113 -6
- package/src/server/request-log-conversation.ts +51 -0
- package/src/server/request-log.ts +298 -31
- package/src/server/responses/agent-task-recovery-cache.ts +143 -0
- package/src/server/responses/agent-task-recovery.ts +465 -0
- package/src/server/responses/codex-auth-error.ts +55 -0
- package/src/server/responses/collaboration.ts +239 -36
- package/src/server/responses/combo-stream-preflight.ts +178 -0
- package/src/server/responses/compact.ts +444 -72
- package/src/server/responses/core.ts +3579 -436
- package/src/server/responses/empty-completion-guard.ts +333 -0
- package/src/server/responses/encrypted-payload.ts +62 -39
- package/src/server/responses/fetch-helpers.ts +89 -99
- package/src/server/responses/input-admission.ts +187 -0
- package/src/server/responses/pacing-overload.ts +13 -0
- package/src/server/responses/passthrough-error.ts +33 -9
- package/src/server/responses/policy-fallback.ts +178 -0
- package/src/server/responses/responses-field-backfill.ts +343 -0
- package/src/server/responses/terminal-guard.ts +26 -5
- package/src/server/responses/upstream-error.ts +5 -0
- package/src/server/responses/ws-upstream.ts +381 -0
- package/src/server/responses-custom-tool-repair.ts +363 -0
- package/src/server/responses-item-id-repair.ts +54 -6
- package/src/server/responses-json-events.ts +90 -0
- package/src/server/responses-model-rewrite.ts +29 -0
- package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
- package/src/server/responses-snapshot-repair.ts +621 -0
- package/src/server/responses-terminal-repair.ts +363 -0
- package/src/server/responses-tool-search-repair.ts +267 -0
- package/src/server/responses-undeclared-tool-guard.ts +376 -0
- package/src/server/responses.ts +18 -2
- package/src/server/search.ts +78 -13
- package/src/server/sse-frame-buffer.ts +319 -0
- package/src/server/sse-payload-rewrite.ts +110 -22
- package/src/server/startup-action-control.ts +8 -1
- package/src/server/startup-health-cache.ts +19 -1
- package/src/server/system-env.ts +80 -9
- package/src/server/ws-bridge.ts +53 -40
- package/src/service-manager-probe.ts +892 -0
- package/src/service.ts +1153 -94
- package/src/sidecar/auth.ts +92 -0
- package/src/sidecar/candidates.ts +83 -0
- package/src/storage/cleanup.ts +2 -2
- package/src/storage/policy-job.ts +14 -4
- package/src/storage/policy.ts +88 -23
- package/src/storage/scanner.ts +1 -1
- package/src/storage/worker-lifecycle.ts +14 -14
- package/src/tray/windows-tray.ps1 +83 -9
- package/src/tray/windows.ts +43 -16
- package/src/types/accounts.ts +37 -0
- package/src/types/config.ts +911 -0
- package/src/types/provider.ts +614 -0
- package/src/types/request.ts +397 -0
- package/src/types/tools.ts +236 -0
- package/src/types/wire.ts +80 -0
- package/src/types.ts +107 -1237
- package/src/update/index.ts +37 -23
- package/src/update/job.ts +445 -68
- package/src/update/notify.ts +12 -6
- package/src/update/npm-cache-preflight.d.mts +47 -0
- package/src/update/npm-cache-preflight.mjs +201 -0
- package/src/update/transactional-install.d.mts +22 -0
- package/src/update/transactional-install.mjs +266 -0
- package/src/usage/cost.ts +0 -0
- package/src/usage/expected-prices.ts +287 -16
- package/src/usage/log.ts +666 -50
- package/src/usage/summary.ts +388 -17
- package/src/usage/user-cost-overlay-reconciler.ts +313 -0
- package/src/usage/user-cost-overlays.ts +314 -0
- package/src/vision/anthropic-describe.ts +10 -6
- package/src/vision/backends.ts +97 -0
- package/src/vision/describe.ts +27 -16
- package/src/vision/eligibility.ts +250 -0
- package/src/vision/index.ts +238 -24
- package/src/vision/reasoning.ts +55 -0
- package/src/vision/routed-describe.ts +175 -0
- package/src/vision/timeout-bounds.ts +9 -0
- package/src/web-search/anthropic-executor.ts +13 -7
- package/src/web-search/backends.ts +108 -0
- package/src/web-search/exa-executor.ts +119 -0
- package/src/web-search/executor.ts +21 -6
- package/src/web-search/gemini-executor.ts +141 -0
- package/src/web-search/index.ts +150 -15
- package/src/web-search/loop.ts +284 -54
- package/src/web-search/parse.ts +125 -30
- package/src/web-search/sources.ts +60 -0
- package/src/web-search/xai-executor.ts +219 -0
- package/gui/dist/assets/index-DTpMHS4F.js +0 -67
- package/gui/dist/assets/index-ZNVDE3C7.css +0 -1
- package/gui/dist/provider-icons/antigravity.svg +0 -1
- package/gui/dist/provider-icons/claude.svg +0 -1
- package/gui/dist/provider-icons/copilot.svg +0 -1
- package/gui/dist/provider-icons/cursor.svg +0 -2
- package/gui/dist/provider-icons/gemini.svg +0 -1
- package/gui/dist/provider-icons/grok-color.svg +0 -1
- package/gui/dist/provider-icons/kiro.svg +0 -14
- package/src/cli/internal-dispatch.ts +0 -20
package/src/router.ts
CHANGED
|
@@ -1,19 +1,77 @@
|
|
|
1
1
|
import type { CodexAccountMode, OcxConfig, OcxProviderConfig } from "./types";
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import {
|
|
3
|
+
getCombo,
|
|
4
|
+
isComboTargetInCooldown,
|
|
5
|
+
preservesPhysicalComboProvider,
|
|
6
|
+
targetKey,
|
|
7
|
+
tryPickComboModel,
|
|
8
|
+
type ComboPick,
|
|
9
|
+
} from "./combos";
|
|
10
|
+
import type { NormalizedComboConfig } from "./combos/types";
|
|
11
|
+
import { hasOwnProvider } from "./config/provider-name";
|
|
12
|
+
import { resolveEnvValue } from "./config";
|
|
4
13
|
import { assertProviderDestinationAllowed } from "./lib/destination-policy";
|
|
5
14
|
import { redactSecretString, redactUrlForLog } from "./lib/redact";
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
15
|
+
import {
|
|
16
|
+
PROVIDER_REGISTRY,
|
|
17
|
+
mergeRegistryStaticHeaders,
|
|
18
|
+
providerCodexAccountMode,
|
|
19
|
+
registryModelServiceTierCapabilityApplies,
|
|
20
|
+
} from "./providers/registry";
|
|
21
|
+
import { applyDirectReasoningEffortContracts, hasLegacyClinePassReasoningEfforts } from "./providers/derive";
|
|
22
|
+
import { cloneFastWire } from "./providers/fastwire";
|
|
23
|
+
import {
|
|
24
|
+
providerMatchesRegistryTransportWithStaticGuards,
|
|
25
|
+
providerSupportsLiveModelDiscovery,
|
|
26
|
+
} from "./providers/static-model-discovery";
|
|
27
|
+
import {
|
|
28
|
+
isCanonicalOpenAiForwardProvider,
|
|
29
|
+
LEGACY_CHATGPT_PROVIDER_ID,
|
|
30
|
+
LEGACY_OPENAI_MULTI_PROVIDER_ID,
|
|
31
|
+
OPENAI_API_PROVIDER_ID,
|
|
32
|
+
OPENAI_CODEX_PROVIDER_ID,
|
|
33
|
+
} from "./providers/openai-tiers";
|
|
34
|
+
import { decodeRoutedModelIdOrThrow, encodeRoutedModelId } from "./providers/slug-codec";
|
|
35
|
+
import { resolveModelAlias } from "./providers/default-aliases";
|
|
9
36
|
import { getStaleCached } from "./codex/model-cache";
|
|
37
|
+
import { codexAccountNamespaceEntries } from "./codex/account-namespaces";
|
|
38
|
+
import {
|
|
39
|
+
buildRouteDecisionTrace,
|
|
40
|
+
type RouteDecisionKind,
|
|
41
|
+
type RouteDecisionTraceV1,
|
|
42
|
+
type TraceCandidateInput,
|
|
43
|
+
} from "./routing/trace";
|
|
44
|
+
import { getRoutingProfile, resolvePolicyProfileId } from "./routing/profile";
|
|
45
|
+
import { evaluatePolicyProfile, type PolicyRequestEvidence } from "./routing/evaluator";
|
|
46
|
+
import { assemblePolicyCandidateEvidence } from "./routing/compatibility/assemble";
|
|
47
|
+
|
|
48
|
+
export class NoEligiblePolicyCandidateError extends Error {
|
|
49
|
+
/** Evaluation trace (with per-candidate exclusions) when nothing qualified. */
|
|
50
|
+
readonly trace?: RouteDecisionTraceV1;
|
|
51
|
+
|
|
52
|
+
constructor(readonly profileId: string, trace?: RouteDecisionTraceV1) {
|
|
53
|
+
super(`No eligible candidates for policy profile: ${profileId}`);
|
|
54
|
+
this.name = "NoEligiblePolicyCandidateError";
|
|
55
|
+
this.trace = trace;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
10
58
|
|
|
11
59
|
export interface RouteResult {
|
|
12
60
|
providerName: string;
|
|
13
61
|
provider: OcxProviderConfig;
|
|
14
62
|
modelId: string;
|
|
63
|
+
/** Which deterministic routing path produced this route (RI-01). */
|
|
64
|
+
routeKind: RouteDecisionKind;
|
|
65
|
+
/** Stable wire reason code for the selected route (RI-01). */
|
|
66
|
+
routeReason: string;
|
|
15
67
|
codexAccountMode?: CodexAccountMode;
|
|
68
|
+
/** Exact account selected by an account-qualified native model. */
|
|
69
|
+
codexAccountId?: string;
|
|
70
|
+
/** Public namespace used by the account-qualified selector. */
|
|
71
|
+
codexAccountNamespace?: string;
|
|
16
72
|
combo?: ComboPick;
|
|
73
|
+
/** Bounded route-decision trace (RI-01); never contains secrets. */
|
|
74
|
+
routeDecision?: RouteDecisionTraceV1;
|
|
17
75
|
}
|
|
18
76
|
|
|
19
77
|
const MODEL_PROVIDER_PATTERNS: Array<{ providerNames: string[]; prefixes: string[] }> = [
|
|
@@ -37,10 +95,15 @@ const MODEL_PROVIDER_PATTERNS: Array<{ providerNames: string[]; prefixes: string
|
|
|
37
95
|
* last-known-good live /models cache (may be empty on a cold start; decode then passes
|
|
38
96
|
* unknown ids through unchanged for an honest upstream error).
|
|
39
97
|
*/
|
|
40
|
-
export function knownModelIdsForProvider(
|
|
98
|
+
export function knownModelIdsForProvider(
|
|
99
|
+
provName: string,
|
|
100
|
+
prov: OcxProviderConfig,
|
|
101
|
+
config?: Pick<OcxConfig, "customModels">,
|
|
102
|
+
): string[] {
|
|
41
103
|
const ids = new Set<string>();
|
|
42
104
|
for (const id of prov.models ?? []) ids.add(id);
|
|
43
|
-
|
|
105
|
+
if (prov.defaultModel) ids.add(prov.defaultModel);
|
|
106
|
+
const registry = providerMatchesRegistryTransportWithStaticGuards(provName, prov)
|
|
44
107
|
? PROVIDER_REGISTRY.find(entry => entry.id === provName)
|
|
45
108
|
: undefined;
|
|
46
109
|
for (const id of registry?.models ?? []) ids.add(id);
|
|
@@ -53,10 +116,15 @@ export function knownModelIdsForProvider(provName: string, prov: OcxProviderConf
|
|
|
53
116
|
registry?.modelDefaultReasoningEfforts,
|
|
54
117
|
registry?.modelReasoningEffortMap,
|
|
55
118
|
registry?.modelMaxOutputTokens,
|
|
119
|
+
registry?.modelSupportsServiceTier,
|
|
120
|
+
registry?.modelSupportsVerbosity,
|
|
56
121
|
]) {
|
|
57
122
|
for (const id of Object.keys(map ?? {})) ids.add(id);
|
|
58
123
|
}
|
|
59
124
|
for (const cached of getStaleCached(provName) ?? []) ids.add(cached.id);
|
|
125
|
+
for (const model of config?.customModels ?? []) {
|
|
126
|
+
if (model.provider === provName && model.modelId) ids.add(model.modelId);
|
|
127
|
+
}
|
|
60
128
|
return [...ids];
|
|
61
129
|
}
|
|
62
130
|
|
|
@@ -201,22 +269,28 @@ function usableResolvedApiKey(apiKey: string | undefined): string | undefined {
|
|
|
201
269
|
return typeof resolved === "string" && resolved.trim().length > 0 ? resolved : undefined;
|
|
202
270
|
}
|
|
203
271
|
|
|
204
|
-
function routedProviderConfig(providerName: string, provider: OcxProviderConfig): OcxProviderConfig {
|
|
272
|
+
export function routedProviderConfig(providerName: string, provider: OcxProviderConfig): OcxProviderConfig {
|
|
205
273
|
const registryEntry = PROVIDER_REGISTRY.find(entry => entry.id === providerName);
|
|
206
|
-
if (!registryEntry || !
|
|
274
|
+
if (!registryEntry || !providerMatchesRegistryTransportWithStaticGuards(providerName, provider)) {
|
|
207
275
|
assertProviderDestinationAllowed(providerName, provider);
|
|
208
276
|
return { ...provider, apiKey: usableResolvedApiKey(provider.apiKey) };
|
|
209
277
|
}
|
|
210
278
|
const resolvedApiKey = usableResolvedApiKey(provider.apiKey);
|
|
279
|
+
const staticModelCatalog = !providerSupportsLiveModelDiscovery(providerName, provider);
|
|
280
|
+
const repairLegacyMimoFreeAuth = providerName === "mimo-free"
|
|
281
|
+
&& staticModelCatalog
|
|
282
|
+
&& (provider.authMode === undefined || provider.authMode === "local");
|
|
211
283
|
const explicitKeyOverride = registryEntry.authKind === "oauth"
|
|
212
284
|
&& registryEntry.allowKeyAuthOverride === true
|
|
213
285
|
&& provider.authMode === "key"
|
|
214
286
|
&& resolvedApiKey !== undefined;
|
|
215
287
|
const canonicalAuthMode = explicitKeyOverride
|
|
216
288
|
? "key"
|
|
217
|
-
:
|
|
218
|
-
?
|
|
219
|
-
|
|
289
|
+
: repairLegacyMimoFreeAuth
|
|
290
|
+
? "key"
|
|
291
|
+
: registryEntry.authKind === "forward" || registryEntry.authKind === "oauth"
|
|
292
|
+
? registryEntry.authKind
|
|
293
|
+
: provider.authMode === "forward" ? undefined : provider.authMode;
|
|
220
294
|
const reasoningEffortMap = mergeRecord(registryEntry.reasoningEffortMap, provider.reasoningEffortMap);
|
|
221
295
|
const modelReasoningEffortMap = mergeNestedRecord(registryEntry.modelReasoningEffortMap, provider.modelReasoningEffortMap);
|
|
222
296
|
const modelReasoningEfforts = mergeStringArrayRecord(registryEntry.modelReasoningEfforts, provider.modelReasoningEfforts);
|
|
@@ -225,10 +299,25 @@ function routedProviderConfig(providerName: string, provider: OcxProviderConfig)
|
|
|
225
299
|
? mergePositiveNumberCaps(registryEntry.modelContextWindows, provider.modelContextWindows)
|
|
226
300
|
: mergeRecordFill(registryEntry.modelContextWindows, provider.modelContextWindows);
|
|
227
301
|
const modelInputModalities = mergeRecordFill(registryEntry.modelInputModalities, provider.modelInputModalities);
|
|
302
|
+
// Registry static headers are documented as applying to every upstream request, so they are
|
|
303
|
+
// filled at resolve time rather than only at seed time: a config written before a header
|
|
304
|
+
// existed, or one carrying any header of its own, would otherwise never receive it. User
|
|
305
|
+
// headers win, matched case-insensitively so an override replaces rather than duplicates.
|
|
306
|
+
const headers = mergeRegistryStaticHeaders(registryEntry.staticHeaders, provider.headers);
|
|
228
307
|
const modelMaxInputTokens = providerName === OPENAI_API_PROVIDER_ID
|
|
229
308
|
? mergePositiveNumberCaps(registryEntry.modelMaxInputTokens, provider.modelMaxInputTokens)
|
|
230
309
|
: mergeRecordFill(registryEntry.modelMaxInputTokens, provider.modelMaxInputTokens);
|
|
231
310
|
const modelMaxOutputTokens = mergeRecordFill(registryEntry.modelMaxOutputTokens, provider.modelMaxOutputTokens);
|
|
311
|
+
const modelSupportsServiceTier = mergeRecordFill(
|
|
312
|
+
registryModelServiceTierCapabilityApplies(registryEntry, provider)
|
|
313
|
+
? registryEntry.modelSupportsServiceTier
|
|
314
|
+
: undefined,
|
|
315
|
+
provider.modelSupportsServiceTier,
|
|
316
|
+
);
|
|
317
|
+
const modelSupportsVerbosity = mergeRecordFill(
|
|
318
|
+
registryEntry.modelSupportsVerbosity,
|
|
319
|
+
provider.modelSupportsVerbosity,
|
|
320
|
+
);
|
|
232
321
|
const noVisionModels = mergeStringArray(registryEntry.noVisionModels, provider.noVisionModels);
|
|
233
322
|
const noReasoningModels = mergeStringArray(registryEntry.noReasoningModels, provider.noReasoningModels);
|
|
234
323
|
const noTemperatureModels = mergeStringArray(registryEntry.noTemperatureModels, provider.noTemperatureModels);
|
|
@@ -236,6 +325,7 @@ function routedProviderConfig(providerName: string, provider: OcxProviderConfig)
|
|
|
236
325
|
const noPenaltyModels = mergeStringArray(registryEntry.noPenaltyModels, provider.noPenaltyModels);
|
|
237
326
|
const autoToolChoiceOnlyModels = mergeStringArray(registryEntry.autoToolChoiceOnlyModels, provider.autoToolChoiceOnlyModels);
|
|
238
327
|
const preserveReasoningContentModels = mergeStringArray(registryEntry.preserveReasoningContentModels, provider.preserveReasoningContentModels);
|
|
328
|
+
const requiresReasoningPlaceholderModels = mergeStringArray(registryEntry.requiresReasoningPlaceholderModels, provider.requiresReasoningPlaceholderModels);
|
|
239
329
|
const reasoningSplitModels = mergeStringArray(registryEntry.reasoningSplitModels, provider.reasoningSplitModels);
|
|
240
330
|
const thinkingToggleModels = mergeStringArray(registryEntry.thinkingToggleModels, provider.thinkingToggleModels);
|
|
241
331
|
const thinkingBudgetModels = mergeStringArray(registryEntry.thinkingBudgetModels, provider.thinkingBudgetModels);
|
|
@@ -252,15 +342,63 @@ function routedProviderConfig(providerName: string, provider: OcxProviderConfig)
|
|
|
252
342
|
if (userBaseUrlIsResolved) warnIfBaseUrlDiscarded(providerName, userBaseUrl, baseUrl);
|
|
253
343
|
assertProviderDestinationAllowed(providerName, { baseUrl, allowPrivateNetwork: provider.allowPrivateNetwork });
|
|
254
344
|
|
|
255
|
-
|
|
345
|
+
const resolved: OcxProviderConfig = {
|
|
256
346
|
...provider,
|
|
257
347
|
adapter: registryEntry.adapter,
|
|
258
348
|
baseUrl,
|
|
259
349
|
...(provider.responsesPath === undefined && registryEntry.responsesPath !== undefined
|
|
260
350
|
? { responsesPath: registryEntry.responsesPath }
|
|
261
351
|
: {}),
|
|
352
|
+
...(provider.requiresAdjacentResponsesToolResults === undefined
|
|
353
|
+
&& registryEntry.requiresAdjacentResponsesToolResults !== undefined
|
|
354
|
+
? { requiresAdjacentResponsesToolResults: registryEntry.requiresAdjacentResponsesToolResults }
|
|
355
|
+
: {}),
|
|
356
|
+
...(provider.fastWire === undefined && registryEntry.fastWire !== undefined
|
|
357
|
+
? {
|
|
358
|
+
fastWire: cloneFastWire(registryEntry.fastWire),
|
|
359
|
+
}
|
|
360
|
+
: {}),
|
|
361
|
+
...(provider.supportsServiceTier === undefined && registryEntry.supportsServiceTier !== undefined
|
|
362
|
+
? { supportsServiceTier: registryEntry.supportsServiceTier }
|
|
363
|
+
: {}),
|
|
364
|
+
// Registry-only web-search capability: without this backfill a saved provider row reaches
|
|
365
|
+
// the Responses adapter with the flag `undefined`, so the capability gate added in #2262
|
|
366
|
+
// reads "unclassified" and forwards Codex's OpenAI-only `web_search` config fields. xAI
|
|
367
|
+
// rejects the whole request before inference ("Argument not supported:
|
|
368
|
+
// external_web_access"), which killed every routed Grok turn on the Responses lane.
|
|
369
|
+
// enrichProviderFromRegistry() already fills this, but the request path resolves through
|
|
370
|
+
// routedProviderConfig() and never called it.
|
|
371
|
+
...(provider.supportsOpenAiWebSearchToolFields === undefined
|
|
372
|
+
&& registryEntry.supportsOpenAiWebSearchToolFields !== undefined
|
|
373
|
+
? { supportsOpenAiWebSearchToolFields: registryEntry.supportsOpenAiWebSearchToolFields }
|
|
374
|
+
: {}),
|
|
375
|
+
...(provider.supportsResponsesCustomTools === undefined && registryEntry.supportsResponsesCustomTools !== undefined
|
|
376
|
+
? { supportsResponsesCustomTools: registryEntry.supportsResponsesCustomTools }
|
|
377
|
+
: {}),
|
|
378
|
+
...(provider.preserveResponsesReasoningContent === undefined && registryEntry.preserveResponsesReasoningContent !== undefined
|
|
379
|
+
? { preserveResponsesReasoningContent: registryEntry.preserveResponsesReasoningContent }
|
|
380
|
+
: {}),
|
|
381
|
+
// Registry-only client-facing repair policy (#938): fill only when the
|
|
382
|
+
// saved provider has no explicit policy; clone so runtime never aliases
|
|
383
|
+
// the registry constant.
|
|
384
|
+
...(provider.responsesItemIdRepair === undefined && registryEntry.responsesItemIdRepair
|
|
385
|
+
? {
|
|
386
|
+
responsesItemIdRepair: {
|
|
387
|
+
...(registryEntry.responsesItemIdRepair.message ? { message: [...registryEntry.responsesItemIdRepair.message] } : {}),
|
|
388
|
+
...(registryEntry.responsesItemIdRepair.reasoning ? { reasoning: [...registryEntry.responsesItemIdRepair.reasoning] } : {}),
|
|
389
|
+
...(registryEntry.responsesItemIdRepair.repairMissingTerminalIds !== undefined
|
|
390
|
+
? { repairMissingTerminalIds: registryEntry.responsesItemIdRepair.repairMissingTerminalIds }
|
|
391
|
+
: {}),
|
|
392
|
+
...(registryEntry.responsesItemIdRepair.repairInvalidIds !== undefined
|
|
393
|
+
? { repairInvalidIds: registryEntry.responsesItemIdRepair.repairInvalidIds }
|
|
394
|
+
: {}),
|
|
395
|
+
},
|
|
396
|
+
}
|
|
397
|
+
: {}),
|
|
262
398
|
authMode: canonicalAuthMode,
|
|
263
399
|
apiKey: resolvedApiKey,
|
|
400
|
+
...(staticModelCatalog ? { liveModels: false } : {}),
|
|
401
|
+
...(headers ? { headers } : {}),
|
|
264
402
|
// Backfill the Google wire mode + Vertex project/location from the registry when the user
|
|
265
403
|
// config omits them, so a minimal `google-vertex`/`google-antigravity` entry still routes
|
|
266
404
|
// through the correct branch (CCA/Vertex) instead of falling back to AI Studio.
|
|
@@ -268,7 +406,10 @@ function routedProviderConfig(providerName: string, provider: OcxProviderConfig)
|
|
|
268
406
|
...(provider.project === undefined && registryEntry.project !== undefined ? { project: registryEntry.project } : {}),
|
|
269
407
|
...(provider.location === undefined && registryEntry.location !== undefined ? { location: registryEntry.location } : {}),
|
|
270
408
|
...(provider.contextWindow === undefined && registryEntry.contextWindow !== undefined ? { contextWindow: registryEntry.contextWindow } : {}),
|
|
271
|
-
...(provider.reasoningEfforts === undefined
|
|
409
|
+
...((provider.reasoningEfforts === undefined || hasLegacyClinePassReasoningEfforts(providerName, provider))
|
|
410
|
+
&& registryEntry.reasoningEfforts !== undefined
|
|
411
|
+
? { reasoningEfforts: [...registryEntry.reasoningEfforts] }
|
|
412
|
+
: {}),
|
|
272
413
|
...(provider.escapeBuiltinToolNames === undefined && registryEntry.escapeBuiltinToolNames !== undefined ? { escapeBuiltinToolNames: registryEntry.escapeBuiltinToolNames } : {}),
|
|
273
414
|
...(provider.keyOptional === undefined && registryEntry.keyOptional !== undefined ? { keyOptional: registryEntry.keyOptional } : {}),
|
|
274
415
|
...(provider.modelSuffixBracketStrip === undefined && registryEntry.modelSuffixBracketStrip !== undefined ? { modelSuffixBracketStrip: registryEntry.modelSuffixBracketStrip } : {}),
|
|
@@ -276,6 +417,13 @@ function routedProviderConfig(providerName: string, provider: OcxProviderConfig)
|
|
|
276
417
|
// opt-in, while an explicit user `false` keeps overriding registry `true`.
|
|
277
418
|
...(provider.parallelToolCalls === undefined && registryEntry.parallelToolCalls !== undefined ? { parallelToolCalls: registryEntry.parallelToolCalls } : {}),
|
|
278
419
|
...(provider.promptCacheKey === undefined && registryEntry.promptCacheKey !== undefined ? { promptCacheKey: registryEntry.promptCacheKey } : {}),
|
|
420
|
+
...(provider.chatServiceTier === undefined && registryEntry.chatServiceTier !== undefined ? { chatServiceTier: registryEntry.chatServiceTier } : {}),
|
|
421
|
+
...(provider.openaiChatEofTolerance === undefined && registryEntry.openaiChatEofTolerance !== undefined
|
|
422
|
+
? { openaiChatEofTolerance: registryEntry.openaiChatEofTolerance }
|
|
423
|
+
: {}),
|
|
424
|
+
...(provider.reasoningWireFormat === undefined && registryEntry.reasoningWireFormat !== undefined
|
|
425
|
+
? { reasoningWireFormat: registryEntry.reasoningWireFormat }
|
|
426
|
+
: {}),
|
|
279
427
|
...(provider.defaultMaxOutputTokens === undefined && registryEntry.defaultMaxOutputTokens !== undefined
|
|
280
428
|
? { defaultMaxOutputTokens: registryEntry.defaultMaxOutputTokens }
|
|
281
429
|
: {}),
|
|
@@ -283,6 +431,8 @@ function routedProviderConfig(providerName: string, provider: OcxProviderConfig)
|
|
|
283
431
|
...(modelInputModalities ? { modelInputModalities } : {}),
|
|
284
432
|
...(modelMaxInputTokens ? { modelMaxInputTokens } : {}),
|
|
285
433
|
...(modelMaxOutputTokens ? { modelMaxOutputTokens } : {}),
|
|
434
|
+
...(modelSupportsServiceTier ? { modelSupportsServiceTier } : {}),
|
|
435
|
+
...(modelSupportsVerbosity ? { modelSupportsVerbosity } : {}),
|
|
286
436
|
...(modelReasoningEfforts ? { modelReasoningEfforts } : {}),
|
|
287
437
|
...(modelDefaultReasoningEfforts ? { modelDefaultReasoningEfforts } : {}),
|
|
288
438
|
...(reasoningEffortMap ? { reasoningEffortMap } : {}),
|
|
@@ -294,10 +444,13 @@ function routedProviderConfig(providerName: string, provider: OcxProviderConfig)
|
|
|
294
444
|
...(noPenaltyModels ? { noPenaltyModels } : {}),
|
|
295
445
|
...(autoToolChoiceOnlyModels ? { autoToolChoiceOnlyModels } : {}),
|
|
296
446
|
...(preserveReasoningContentModels ? { preserveReasoningContentModels } : {}),
|
|
447
|
+
...(requiresReasoningPlaceholderModels ? { requiresReasoningPlaceholderModels } : {}),
|
|
297
448
|
...(reasoningSplitModels ? { reasoningSplitModels } : {}),
|
|
298
449
|
...(thinkingToggleModels ? { thinkingToggleModels } : {}),
|
|
299
450
|
...(thinkingBudgetModels ? { thinkingBudgetModels } : {}),
|
|
300
451
|
};
|
|
452
|
+
applyDirectReasoningEffortContracts(registryEntry, resolved, provider);
|
|
453
|
+
return resolved;
|
|
301
454
|
}
|
|
302
455
|
|
|
303
456
|
function activeProviderEntries(config: OcxConfig): [string, OcxProviderConfig][] {
|
|
@@ -315,6 +468,34 @@ export class NoEnabledOpenAiProviderError extends Error {
|
|
|
315
468
|
}
|
|
316
469
|
}
|
|
317
470
|
|
|
471
|
+
/**
|
|
472
|
+
* One immutable selection trace for a combo request: built once from the
|
|
473
|
+
* initial pick, before any child dispatch. Fallback execution stays in the
|
|
474
|
+
* usage entry's `attempts[]`; the trace never changes after selection.
|
|
475
|
+
*/
|
|
476
|
+
export function comboRouteDecisionTrace(
|
|
477
|
+
config: OcxConfig,
|
|
478
|
+
comboId: string,
|
|
479
|
+
pick: ComboPick,
|
|
480
|
+
requestedModel: string,
|
|
481
|
+
): RouteDecisionTraceV1 {
|
|
482
|
+
const combo = getCombo(config, comboId);
|
|
483
|
+
return buildRouteDecisionTrace({
|
|
484
|
+
requestedModel,
|
|
485
|
+
routeKind: "combo",
|
|
486
|
+
selected: {
|
|
487
|
+
provider: pick.target.provider,
|
|
488
|
+
model: pick.target.model,
|
|
489
|
+
reason: "combo-pick",
|
|
490
|
+
candidateIndex: pick.targetIndex,
|
|
491
|
+
...(combo
|
|
492
|
+
? { tieBreak: combo.strategy === "round-robin" ? "round-robin" : "failover" }
|
|
493
|
+
: {}),
|
|
494
|
+
},
|
|
495
|
+
candidates: combo ? comboRouteCandidates(config, pick, combo) : undefined,
|
|
496
|
+
});
|
|
497
|
+
}
|
|
498
|
+
|
|
318
499
|
// Codex uses a small number of control-plane model ids that are not part of the public GPT/o
|
|
319
500
|
// naming families. Keep this exact: a broad `codex-*` rule could capture a third-party model.
|
|
320
501
|
const CODEX_INTERNAL_OPENAI_MODELS = new Set(["codex-auto-review"]);
|
|
@@ -324,25 +505,140 @@ function isBareOpenAiFamilyModel(modelId: string): boolean {
|
|
|
324
505
|
&& (/^(?:gpt-|o1-|o3-|o4-)/.test(modelId) || CODEX_INTERNAL_OPENAI_MODELS.has(modelId));
|
|
325
506
|
}
|
|
326
507
|
|
|
327
|
-
function routeResult(
|
|
508
|
+
function routeResult(
|
|
509
|
+
providerName: string,
|
|
510
|
+
provider: OcxProviderConfig,
|
|
511
|
+
modelId: string,
|
|
512
|
+
routeKind: RouteDecisionKind,
|
|
513
|
+
routeReason: string,
|
|
514
|
+
): RouteResult {
|
|
328
515
|
const codexAccountMode = providerCodexAccountMode(providerName, provider);
|
|
329
516
|
return {
|
|
330
517
|
providerName,
|
|
331
518
|
provider: routedProviderConfig(providerName, provider),
|
|
332
519
|
modelId,
|
|
520
|
+
routeKind,
|
|
521
|
+
routeReason,
|
|
333
522
|
...(codexAccountMode ? { codexAccountMode } : {}),
|
|
334
523
|
};
|
|
335
524
|
}
|
|
336
525
|
|
|
337
|
-
|
|
526
|
+
/**
|
|
527
|
+
* Candidate evidence for a combo route: every configured target with its
|
|
528
|
+
* selection-time eligibility and exclusion reasons. Purely observational; the
|
|
529
|
+
* pick already happened and this never re-selects.
|
|
530
|
+
*/
|
|
531
|
+
function comboRouteCandidates(
|
|
532
|
+
config: OcxConfig,
|
|
533
|
+
pick: NonNullable<RouteResult["combo"]>,
|
|
534
|
+
combo: NormalizedComboConfig,
|
|
535
|
+
): TraceCandidateInput[] {
|
|
536
|
+
const now = Date.now();
|
|
537
|
+
return combo.targets.map((target, index) => {
|
|
538
|
+
const key = targetKey(target);
|
|
539
|
+
const provider = config.providers[target.provider];
|
|
540
|
+
const configured = provider !== undefined;
|
|
541
|
+
const enabled = configured && provider.disabled !== true;
|
|
542
|
+
const inCooldown = isComboTargetInCooldown(pick.comboId, target, now);
|
|
543
|
+
const isSelected = index === pick.targetIndex;
|
|
544
|
+
// The pick's `attempted` list includes the winner itself; only non-selected
|
|
545
|
+
// targets can be "already-attempted" (fallback picks exclude earlier tries).
|
|
546
|
+
const alreadyAttempted = !isSelected && pick.attempted.includes(key);
|
|
547
|
+
const exclusions: TraceCandidateInput["exclusions"] = [];
|
|
548
|
+
if (!configured) exclusions.push({ code: "unconfigured" });
|
|
549
|
+
if (configured && !enabled) exclusions.push({ code: "disabled" });
|
|
550
|
+
if (inCooldown) exclusions.push({ code: "cooldown" });
|
|
551
|
+
if (isSelected && inCooldown) exclusions.push({ code: "selected-despite-cooldown" });
|
|
552
|
+
if (!isSelected && alreadyAttempted && exclusions.length === 0) {
|
|
553
|
+
exclusions.push({ code: "already-attempted" });
|
|
554
|
+
}
|
|
555
|
+
if (!isSelected && exclusions.length === 0) exclusions.push({ code: "not-selected" });
|
|
556
|
+
return {
|
|
557
|
+
provider: target.provider,
|
|
558
|
+
model: target.model,
|
|
559
|
+
eligible: enabled && !inCooldown && !alreadyAttempted,
|
|
560
|
+
exclusions,
|
|
561
|
+
};
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
function routeModelInternal(
|
|
566
|
+
config: OcxConfig,
|
|
567
|
+
modelId: string,
|
|
568
|
+
bypassCombos: boolean,
|
|
569
|
+
policyEvidence?: PolicyRequestEvidence,
|
|
570
|
+
): RouteResult {
|
|
571
|
+
const slash = modelId.indexOf("/");
|
|
572
|
+
// Policy namespace is system-reserved: an explicit `policy/<id>` or a
|
|
573
|
+
// configured profile alias executes the policy evaluator and routes the
|
|
574
|
+
// selected candidate. Only explicit requests reach this branch; concrete
|
|
575
|
+
// recursive targets skip policy resolution entirely (bypassCombos) so an
|
|
576
|
+
// alias matching a selected candidate can never recurse, and a
|
|
577
|
+
// `policy/<id>` without a configured profile falls through to normal
|
|
578
|
+
// provider/default resolution instead of failing.
|
|
579
|
+
const policyId = !bypassCombos ? resolvePolicyProfileId(config, modelId) : null;
|
|
580
|
+
const profile = policyId ? getRoutingProfile(config, policyId) : undefined;
|
|
581
|
+
if (profile && policyId) {
|
|
582
|
+
// One clock read per decision keeps candidate evidence, exclusions, and
|
|
583
|
+
// scores mutually consistent and reproducible.
|
|
584
|
+
const now = Date.now();
|
|
585
|
+
const candidateEvidence = assemblePolicyCandidateEvidence(config, profile, now, {
|
|
586
|
+
routedProviderConfig,
|
|
587
|
+
});
|
|
588
|
+
const evaluation = evaluatePolicyProfile(config, policyId, policyEvidence ?? {}, candidateEvidence, now);
|
|
589
|
+
if (evaluation.selectedIndex === null) {
|
|
590
|
+
throw new NoEligiblePolicyCandidateError(policyId, evaluation.trace);
|
|
591
|
+
}
|
|
592
|
+
const selected = evaluation.candidates[evaluation.selectedIndex]!;
|
|
593
|
+
const concrete = `${selected.provider}/${selected.model}`;
|
|
594
|
+
const routed = routeModelInternal(config, concrete, true);
|
|
595
|
+
return {
|
|
596
|
+
...routed,
|
|
597
|
+
routeKind: "policy" as const,
|
|
598
|
+
routeReason: "policy-selected",
|
|
599
|
+
routeDecision: evaluation.trace,
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
if (slash > 0) {
|
|
603
|
+
const namespace = modelId.slice(0, slash);
|
|
604
|
+
const binding = codexAccountNamespaceEntries(config)
|
|
605
|
+
.find(([candidate]) => candidate === namespace);
|
|
606
|
+
if (binding) {
|
|
607
|
+
const nativeModelId = modelId.slice(slash + 1);
|
|
608
|
+
if (!isBareOpenAiFamilyModel(nativeModelId)) {
|
|
609
|
+
throw new Error(`Codex account namespace ${namespace} only supports native OpenAI model ids`);
|
|
610
|
+
}
|
|
611
|
+
const provider = config.providers[OPENAI_CODEX_PROVIDER_ID];
|
|
612
|
+
if (!provider || provider.disabled === true) {
|
|
613
|
+
throw new NoEnabledOpenAiProviderError(nativeModelId);
|
|
614
|
+
}
|
|
615
|
+
// Registry routing backfills an omitted authMode on the built-in OpenAI row to forward.
|
|
616
|
+
// Mirror only that default here; explicit non-forward modes still fail closed.
|
|
617
|
+
const providerForCanonicalCheck = provider.authMode === undefined
|
|
618
|
+
? { ...provider, authMode: "forward" as const }
|
|
619
|
+
: provider;
|
|
620
|
+
if (!isCanonicalOpenAiForwardProvider(providerForCanonicalCheck)) {
|
|
621
|
+
throw new NoEnabledOpenAiProviderError(nativeModelId);
|
|
622
|
+
}
|
|
623
|
+
return {
|
|
624
|
+
...routeResult(OPENAI_CODEX_PROVIDER_ID, provider, nativeModelId, "explicit-account", "account-namespace"),
|
|
625
|
+
// Exact account injection uses the pool credential machinery even when the canonical
|
|
626
|
+
// provider is globally Direct. The fixed id bypasses pool selection entirely.
|
|
627
|
+
codexAccountMode: "pool",
|
|
628
|
+
codexAccountId: binding[1],
|
|
629
|
+
codexAccountNamespace: namespace,
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
338
634
|
if (!bypassCombos && !preservesPhysicalComboProvider(config)) {
|
|
339
635
|
const combo = tryPickComboModel(config, modelId);
|
|
340
636
|
if (combo) {
|
|
341
637
|
const concrete = `${combo.target.provider}/${combo.target.model}`;
|
|
342
638
|
// The selected target is already a concrete provider/model reference. Resolve it without
|
|
343
639
|
// consulting combo aliases again, otherwise an alias that shadows the target can recurse.
|
|
344
|
-
const routed = routeModelInternal(config, concrete, true);
|
|
345
|
-
return { ...routed, combo };
|
|
640
|
+
const routed = routeModelInternal(config, concrete, true, undefined);
|
|
641
|
+
return { ...routed, combo, routeKind: "combo" as const, routeReason: "combo-pick" };
|
|
346
642
|
}
|
|
347
643
|
}
|
|
348
644
|
|
|
@@ -350,36 +646,58 @@ function routeModelInternal(config: OcxConfig, modelId: string, bypassCombos: bo
|
|
|
350
646
|
// Only triggers when the prefix matches a CONFIGURED provider, so genuine
|
|
351
647
|
// slash-containing model ids (e.g. "anthropic/claude-...") fall through when
|
|
352
648
|
// no such provider exists.
|
|
353
|
-
const slash = modelId.indexOf("/");
|
|
354
649
|
if (slash > 0) {
|
|
355
|
-
const
|
|
650
|
+
const requestedProvider = modelId.slice(0, slash);
|
|
651
|
+
const provName = hasOwnProvider(config.providers, requestedProvider)
|
|
652
|
+
? requestedProvider
|
|
653
|
+
: Object.entries(config.providers).find(([, provider]) =>
|
|
654
|
+
typeof provider.alias === "string" && provider.alias.toLowerCase() === requestedProvider.toLowerCase())?.[0];
|
|
655
|
+
if (!provName) {
|
|
656
|
+
// A genuine slash-containing native model id still falls through unchanged.
|
|
657
|
+
} else {
|
|
356
658
|
if (provName === LEGACY_CHATGPT_PROVIDER_ID || provName === LEGACY_OPENAI_MULTI_PROVIDER_ID) {
|
|
357
659
|
throw new Error(`No provider configured for model: ${modelId}`);
|
|
358
660
|
}
|
|
359
661
|
if (hasOwnProvider(config.providers, provName)) {
|
|
360
662
|
const prov = config.providers[provName];
|
|
361
663
|
if (prov.disabled === true) throw new Error(`Provider is disabled: ${provName}`);
|
|
362
|
-
const known = knownModelIdsForProvider(provName, prov);
|
|
664
|
+
const known = knownModelIdsForProvider(provName, prov, config);
|
|
363
665
|
// Self-namespaced native id — the vendor segment equals the provider id, so the FULL ref is
|
|
364
666
|
// itself a known model (e.g. orcarouter/auto). Route it whole instead of stripping to the
|
|
365
667
|
// remainder, which would send a bare `auto` the upstream cannot resolve.
|
|
366
|
-
if (known.includes(modelId))
|
|
668
|
+
if (known.includes(modelId)) {
|
|
669
|
+
return routeResult(provName, prov, modelId, "explicit-provider", "explicit-provider-namespace");
|
|
670
|
+
}
|
|
367
671
|
// Codex-facing alias ids (`provider/vendor-model`) decode back to the native
|
|
368
672
|
// slash id via an exact known-id lookup; raw full-slash selectors keep working.
|
|
369
|
-
|
|
673
|
+
const requestedModel = modelId.slice(slash + 1);
|
|
674
|
+
const decoded = decodeRoutedModelIdOrThrow(requestedModel, known);
|
|
675
|
+
const nativeModel = known.includes(decoded)
|
|
676
|
+
? decoded
|
|
677
|
+
: resolveModelAlias(config, prov, known, requestedModel) ?? decoded;
|
|
678
|
+
return routeResult(
|
|
679
|
+
provName,
|
|
680
|
+
prov,
|
|
681
|
+
nativeModel,
|
|
682
|
+
"explicit-provider",
|
|
683
|
+
"explicit-provider-namespace",
|
|
684
|
+
);
|
|
685
|
+
}
|
|
370
686
|
}
|
|
371
687
|
}
|
|
372
688
|
|
|
373
689
|
if (isBareOpenAiFamilyModel(modelId)) {
|
|
374
690
|
const provider = config.providers[OPENAI_CODEX_PROVIDER_ID];
|
|
375
|
-
if (provider && provider.disabled !== true)
|
|
691
|
+
if (provider && provider.disabled !== true) {
|
|
692
|
+
return routeResult(OPENAI_CODEX_PROVIDER_ID, provider, modelId, "native", "native-family");
|
|
693
|
+
}
|
|
376
694
|
throw new NoEnabledOpenAiProviderError(modelId);
|
|
377
695
|
}
|
|
378
696
|
|
|
379
697
|
for (const [provName, prov] of activeProviderEntries(config)) {
|
|
380
698
|
if (prov.defaultModel === modelId
|
|
381
699
|
|| (typeof prov.defaultModel === "string" && encodeRoutedModelId(prov.defaultModel) === modelId)) {
|
|
382
|
-
return routeResult(provName, prov, prov.defaultModel as string);
|
|
700
|
+
return routeResult(provName, prov, prov.defaultModel as string, "explicit-provider", "configured-default-model");
|
|
383
701
|
}
|
|
384
702
|
}
|
|
385
703
|
|
|
@@ -389,36 +707,92 @@ function routeModelInternal(config: OcxConfig, modelId: string, bypassCombos: bo
|
|
|
389
707
|
for (const [provName, prov] of activeProviderEntries(config)) {
|
|
390
708
|
if (prov.models && Array.isArray(prov.models)) {
|
|
391
709
|
const hit = (prov.models as string[]).find(id => id === modelId || encodeRoutedModelId(id) === modelId);
|
|
392
|
-
if (hit !== undefined)
|
|
710
|
+
if (hit !== undefined) {
|
|
711
|
+
return routeResult(provName, prov, hit, "explicit-provider", "configured-model-list");
|
|
712
|
+
}
|
|
393
713
|
}
|
|
394
714
|
}
|
|
395
715
|
|
|
716
|
+
const aliasMatches: Array<{ provider: string; model: string; qualified: string }> = [];
|
|
717
|
+
for (const [provName, prov] of activeProviderEntries(config)) {
|
|
718
|
+
const known = knownModelIdsForProvider(provName, prov, config);
|
|
719
|
+
const native = resolveModelAlias(config, prov, known, modelId);
|
|
720
|
+
if (native) aliasMatches.push({
|
|
721
|
+
provider: provName,
|
|
722
|
+
model: native,
|
|
723
|
+
qualified: `${prov.alias || provName}/${modelId}`,
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
if (aliasMatches.length > 1) {
|
|
727
|
+
throw new Error(`model alias '${modelId}' is ambiguous: ${aliasMatches.map(match => match.qualified).sort().join(", ")}`);
|
|
728
|
+
}
|
|
729
|
+
if (aliasMatches[0]) {
|
|
730
|
+
const match = aliasMatches[0];
|
|
731
|
+
return routeResult(match.provider, config.providers[match.provider], match.model, "explicit-provider", "model-alias");
|
|
732
|
+
}
|
|
733
|
+
|
|
396
734
|
if (config.defaultProvider === LEGACY_CHATGPT_PROVIDER_ID) {
|
|
397
735
|
throw new Error(`No provider configured for model: ${modelId}`);
|
|
398
736
|
}
|
|
399
737
|
if (hasOwnProvider(config.providers, config.defaultProvider)) {
|
|
400
738
|
const defaultProv = config.providers[config.defaultProvider];
|
|
401
739
|
if (defaultProv.disabled === true) throw new Error(`Default provider is disabled: ${config.defaultProvider}`);
|
|
402
|
-
return routeResult(config.defaultProvider, defaultProv, modelId);
|
|
740
|
+
return routeResult(config.defaultProvider, defaultProv, modelId, "default-provider", "default-provider");
|
|
403
741
|
}
|
|
404
742
|
|
|
405
743
|
throw new Error(`No provider configured for model: ${modelId}`);
|
|
406
744
|
}
|
|
407
745
|
|
|
408
|
-
export function routeModel(
|
|
409
|
-
|
|
746
|
+
export function routeModel(
|
|
747
|
+
config: OcxConfig,
|
|
748
|
+
modelId: string,
|
|
749
|
+
policyEvidence?: PolicyRequestEvidence,
|
|
750
|
+
): RouteResult {
|
|
751
|
+
const route = routeModelInternal(config, modelId, false, policyEvidence);
|
|
752
|
+
// Policy routes carry a full evaluation trace already; never rebuild it.
|
|
753
|
+
if (route.routeDecision) return route;
|
|
754
|
+
const accountRef = route.codexAccountNamespace;
|
|
755
|
+
const combo = route.combo ? getCombo(config, route.combo.comboId) : undefined;
|
|
756
|
+
route.routeDecision = buildRouteDecisionTrace({
|
|
757
|
+
requestedModel: modelId,
|
|
758
|
+
routeKind: route.routeKind,
|
|
759
|
+
selected: {
|
|
760
|
+
provider: route.providerName,
|
|
761
|
+
model: route.modelId,
|
|
762
|
+
...(accountRef ? { accountRef } : {}),
|
|
763
|
+
reason: route.routeReason,
|
|
764
|
+
...(route.combo ? { candidateIndex: route.combo.targetIndex } : {}),
|
|
765
|
+
...(combo
|
|
766
|
+
? { tieBreak: combo.strategy === "round-robin" ? "round-robin" : "failover" }
|
|
767
|
+
: {}),
|
|
768
|
+
},
|
|
769
|
+
candidates: route.routeKind === "combo" && route.combo && combo
|
|
770
|
+
? comboRouteCandidates(config, route.combo, combo)
|
|
771
|
+
: undefined,
|
|
772
|
+
});
|
|
773
|
+
return route;
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
/** Resolve a combo-selected provider/model target without consulting public combo aliases again. */
|
|
777
|
+
export function routeConcreteModel(config: OcxConfig, modelId: string): RouteResult {
|
|
778
|
+
return routeModelInternal(config, modelId, true, undefined);
|
|
410
779
|
}
|
|
411
780
|
|
|
412
781
|
function routeByKnownModelPattern(config: OcxConfig, modelId: string): RouteResult | undefined {
|
|
413
782
|
for (const { providerNames, prefixes } of MODEL_PROVIDER_PATTERNS) {
|
|
414
783
|
if (prefixes.some(prefix => modelId.startsWith(prefix))) {
|
|
415
784
|
const matchingProvider = Object.entries(config.providers).find(
|
|
416
|
-
([name]) => providerNames.some(providerName => name === providerName || name.startsWith(`${providerName}-`))
|
|
785
|
+
([name, prov]) => prov.disabled !== true && providerNames.some(providerName => name === providerName || name.startsWith(`${providerName}-`))
|
|
417
786
|
);
|
|
418
787
|
if (matchingProvider) {
|
|
419
788
|
const [provName, prov] = matchingProvider;
|
|
420
|
-
return routeResult(provName, prov, modelId);
|
|
789
|
+
return routeResult(provName, prov, modelId, "explicit-provider", "model-pattern");
|
|
421
790
|
}
|
|
791
|
+
// Deliberately no "first provider with an Anthropic adapter" fallback here. Picking by
|
|
792
|
+
// object insertion order, without checking `models`, `selectedModels`, `disabledModels` or
|
|
793
|
+
// discovery state, silently moves a request onto a provider the operator never chose, with
|
|
794
|
+
// its own privacy and billing consequences (#1697). A classifier turn that needs a specific
|
|
795
|
+
// target gets it from operator-declared `claudeCode.classifierModel` / `classifierFallbacks`.
|
|
422
796
|
}
|
|
423
797
|
}
|
|
424
798
|
return undefined;
|