@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
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
// Registry model renames do not reach a saved provider config on their own.
|
|
2
|
+
//
|
|
3
|
+
// `reconcileOAuthProviders` refuses to touch a row whose `authMode` is not
|
|
4
|
+
// `oauth` (src/oauth/index.ts), and `enrichProviderFromRegistry` is fill-only by
|
|
5
|
+
// design: it backfills a MISSING field and never rewrites a present one, so a
|
|
6
|
+
// user's hand-edited model list survives an upgrade. Both postures are correct.
|
|
7
|
+
// Their gap is the case where the registry did not ADD a model but RENAMED one:
|
|
8
|
+
// the saved row keeps a retired id forever, the supported id never appears, and
|
|
9
|
+
// the capability metadata stays keyed to an id the vendor is taking offline
|
|
10
|
+
// (issue #1610 — `qwen3.8-max-preview` persisted through the `qwen3.8-max`
|
|
11
|
+
// rename in six separate fields, including a reasoning ladder that had since
|
|
12
|
+
// diverged from the registry's).
|
|
13
|
+
//
|
|
14
|
+
// This migration is deliberately NOT general reconciliation. It rewrites exactly
|
|
15
|
+
// one thing: an id this file declares retired, on a provider that still carries
|
|
16
|
+
// the registry's transport, and only when the registry currently seeds the
|
|
17
|
+
// replacement. Everything else in the row is left alone.
|
|
18
|
+
|
|
19
|
+
import { PROVIDER_REGISTRY } from "./registry";
|
|
20
|
+
import type { OcxConfig, OcxProviderConfig } from "../types";
|
|
21
|
+
|
|
22
|
+
export interface ModelRename {
|
|
23
|
+
/** Registry provider id whose saved rows may carry the retired model id. */
|
|
24
|
+
provider: string;
|
|
25
|
+
from: string;
|
|
26
|
+
to: string;
|
|
27
|
+
/** Why the vendor retired it, for the startup warning and future readers. */
|
|
28
|
+
reason: string;
|
|
29
|
+
/**
|
|
30
|
+
* Drop the retired key from `modelReasoningEffortMap` instead of renaming it.
|
|
31
|
+
*
|
|
32
|
+
* Renaming preserves the VALUE, which is right for records whose values describe the
|
|
33
|
+
* model — a context window or an effort ladder survives a rename — and wrong for the
|
|
34
|
+
* one record whose values are themselves wire ids. An effort map saved as
|
|
35
|
+
* `high -> gemini-3.6-flash-high` would keep naming a dead wire id under the new key,
|
|
36
|
+
* and the adapter maps effort BEFORE resolving CCA routing, so that value arrives as
|
|
37
|
+
* an unrecognised effort and silently degrades to the default tier.
|
|
38
|
+
*
|
|
39
|
+
* Only that one record is dropped. Emptying the others would be worse than the bug:
|
|
40
|
+
* catalog enrichment treats an existing `{}` as "already populated" and will not
|
|
41
|
+
* restore the registry's records, so the migrated user would keep routing correctly
|
|
42
|
+
* but lose the reasoning picker entirely.
|
|
43
|
+
*/
|
|
44
|
+
dropReasoningEffortMap?: boolean;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Renames already applied to `PROVIDER_REGISTRY`. An entry stays here after the
|
|
49
|
+
* registry moves on: it is what repairs configs saved before that move. Removing
|
|
50
|
+
* one strands every config that has not started since the rename shipped.
|
|
51
|
+
*/
|
|
52
|
+
export const MODEL_RENAMES: readonly ModelRename[] = [
|
|
53
|
+
{
|
|
54
|
+
provider: "alibaba-token-plan",
|
|
55
|
+
from: "qwen3.8-max-preview",
|
|
56
|
+
to: "qwen3.8-max",
|
|
57
|
+
reason: "Alibaba shipped Qwen3.8-Max as stable and documents the preview endpoint as liable to be taken offline once preview concludes",
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
provider: "alibaba-token-plan-intl",
|
|
61
|
+
from: "qwen3.8-max-preview",
|
|
62
|
+
to: "qwen3.8-max",
|
|
63
|
+
reason: "Alibaba shipped Qwen3.8-Max as stable and documents the preview endpoint as liable to be taken offline once preview concludes",
|
|
64
|
+
},
|
|
65
|
+
// Antigravity Flash generations. Google takes the previous Flash model off Cloud Code
|
|
66
|
+
// Assist almost immediately when the next ships, so a saved 3.6 (or older 3.5) id is a
|
|
67
|
+
// dead selection rather than a merely outdated one. Routing already redirects these ids
|
|
68
|
+
// at request time; this migration repairs the saved config so the picker, the allowlist
|
|
69
|
+
// and the capability maps stop naming a model the backend no longer serves.
|
|
70
|
+
...(["gemini-3.6-flash", "gemini-3.6-flash-low", "gemini-3.6-flash-medium", "gemini-3.6-flash-high",
|
|
71
|
+
"gemini-3.5-flash-extra-low", "gemini-3.5-flash-low", "gemini-3.5-flash-mid", "gemini-3.5-flash-high",
|
|
72
|
+
"gemini-3-flash-agent"] as const).map(from => ({
|
|
73
|
+
provider: "google-antigravity",
|
|
74
|
+
from,
|
|
75
|
+
to: "gemini-3.7-flash",
|
|
76
|
+
reason: "Google retires the previous Antigravity Flash generation from Cloud Code Assist when its successor ships, so the saved id no longer resolves to a live model",
|
|
77
|
+
// The retired Flash tiers were wire ids, so any saved per-model record keyed by one
|
|
78
|
+
// may also hold one as a value. 3.7 expresses tiers as thinkingLevel names instead.
|
|
79
|
+
dropReasoningEffortMap: true,
|
|
80
|
+
})),
|
|
81
|
+
];
|
|
82
|
+
|
|
83
|
+
/** Provider fields that key metadata by model id. */
|
|
84
|
+
const MODEL_KEYED_RECORDS = [
|
|
85
|
+
"modelContextWindows",
|
|
86
|
+
"modelMaxOutputTokens",
|
|
87
|
+
"modelInputModalities",
|
|
88
|
+
"modelReasoningEfforts",
|
|
89
|
+
"modelDefaultReasoningEfforts",
|
|
90
|
+
"modelReasoningEffortMap",
|
|
91
|
+
] as const;
|
|
92
|
+
|
|
93
|
+
/** Provider fields that are flat lists of model ids. */
|
|
94
|
+
const MODEL_ID_LISTS = [
|
|
95
|
+
"models",
|
|
96
|
+
// A retired id left here is worse than a stale label: `filterCatalogModels` treats
|
|
97
|
+
// `selectedModels` as an exact-match allowlist, so a user who allowlisted only the
|
|
98
|
+
// retired model gets NO replacement row at all — the model silently vanishes from
|
|
99
|
+
// their catalog instead of being renamed. OAuth reconciliation does not cover this
|
|
100
|
+
// field, so the rename has to.
|
|
101
|
+
"selectedModels",
|
|
102
|
+
"noVisionModels",
|
|
103
|
+
"noReasoningModels",
|
|
104
|
+
"noTemperatureModels",
|
|
105
|
+
"noTopPModels",
|
|
106
|
+
"noPenaltyModels",
|
|
107
|
+
"autoToolChoiceOnlyModels",
|
|
108
|
+
"preserveReasoningContentModels",
|
|
109
|
+
"thinkingBudgetModels",
|
|
110
|
+
"directReasoningEffortModels",
|
|
111
|
+
] as const;
|
|
112
|
+
|
|
113
|
+
function renameInList(value: unknown, from: string, to: string): string[] | null {
|
|
114
|
+
if (!Array.isArray(value) || !value.includes(from)) return null;
|
|
115
|
+
const seen = new Set<string>();
|
|
116
|
+
const next: string[] = [];
|
|
117
|
+
// Rename in place to preserve ordering, and collapse a duplicate if the target
|
|
118
|
+
// id was already present alongside the retired one.
|
|
119
|
+
for (const entry of value) {
|
|
120
|
+
if (typeof entry !== "string") continue;
|
|
121
|
+
const mapped = entry === from ? to : entry;
|
|
122
|
+
if (seen.has(mapped)) continue;
|
|
123
|
+
seen.add(mapped);
|
|
124
|
+
next.push(mapped);
|
|
125
|
+
}
|
|
126
|
+
return next;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function renameInRecord(value: unknown, from: string, to: string): Record<string, unknown> | null {
|
|
130
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
131
|
+
const record = value as Record<string, unknown>;
|
|
132
|
+
if (!(from in record)) return null;
|
|
133
|
+
const next: Record<string, unknown> = {};
|
|
134
|
+
for (const [key, entry] of Object.entries(record)) {
|
|
135
|
+
const mapped = key === from ? to : key;
|
|
136
|
+
if (mapped in next) continue;
|
|
137
|
+
// An explicit entry already saved under the new id is the newer intent.
|
|
138
|
+
next[mapped] = key === from && to in record ? record[to] : entry;
|
|
139
|
+
}
|
|
140
|
+
return next;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** Drop the retired key entirely, leaving any entry already saved under the new id. */
|
|
144
|
+
function dropFromRecord(value: unknown, from: string): Record<string, unknown> | null {
|
|
145
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
146
|
+
const record = value as Record<string, unknown>;
|
|
147
|
+
if (!(from in record)) return null;
|
|
148
|
+
const next: Record<string, unknown> = {};
|
|
149
|
+
for (const [key, entry] of Object.entries(record)) {
|
|
150
|
+
if (key === from) continue;
|
|
151
|
+
next[key] = entry;
|
|
152
|
+
}
|
|
153
|
+
return next;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* `provider/model` rows in the top-level `disabledModels` list.
|
|
158
|
+
*
|
|
159
|
+
* The retired row is DROPPED rather than renamed: carrying its disabled state to
|
|
160
|
+
* the new id would hide the supported model behind a toggle the user set for a
|
|
161
|
+
* different model. An existing row for the new id is left untouched.
|
|
162
|
+
*/
|
|
163
|
+
function renameDisabledModels(config: OcxConfig, rename: ModelRename): boolean {
|
|
164
|
+
const list = config.disabledModels;
|
|
165
|
+
if (!Array.isArray(list)) return false;
|
|
166
|
+
const retired = `${rename.provider}/${rename.from}`;
|
|
167
|
+
if (!list.includes(retired)) return false;
|
|
168
|
+
config.disabledModels = list.filter(entry => entry !== retired);
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Only migrate a row that still points at the registry's own endpoint. A user who
|
|
174
|
+
* repointed `baseUrl` at a different vendor owns their model ids.
|
|
175
|
+
*/
|
|
176
|
+
function providerStillMatchesRegistry(name: string, prov: OcxProviderConfig): boolean {
|
|
177
|
+
const entry = PROVIDER_REGISTRY.find(row => row.id === name);
|
|
178
|
+
if (!entry) return false;
|
|
179
|
+
if (!prov.baseUrl || !entry.baseUrl) return true;
|
|
180
|
+
const choices = entry.baseUrlChoices?.map(choice => choice.baseUrl) ?? [];
|
|
181
|
+
const known = [entry.baseUrl, ...choices]
|
|
182
|
+
.filter((url): url is string => typeof url === "string")
|
|
183
|
+
.map(url => url.replace(/\/+$/, ""));
|
|
184
|
+
return known.includes(prov.baseUrl.replace(/\/+$/, ""));
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/** Guard against a stale rename: only apply when the registry actually seeds `to`. */
|
|
188
|
+
function registrySeedsTarget(rename: ModelRename): boolean {
|
|
189
|
+
const entry = PROVIDER_REGISTRY.find(row => row.id === rename.provider);
|
|
190
|
+
return !!entry?.models?.includes(rename.to);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export interface ModelRenameProjection {
|
|
194
|
+
config: OcxConfig;
|
|
195
|
+
changed: boolean;
|
|
196
|
+
warnings: string[];
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Pure projection: apply every applicable rename and report what changed. The
|
|
201
|
+
* caller decides whether to persist.
|
|
202
|
+
*/
|
|
203
|
+
export function projectModelRenames(
|
|
204
|
+
config: OcxConfig,
|
|
205
|
+
renames: readonly ModelRename[] = MODEL_RENAMES,
|
|
206
|
+
): ModelRenameProjection {
|
|
207
|
+
const warnings: string[] = [];
|
|
208
|
+
let changed = false;
|
|
209
|
+
|
|
210
|
+
for (const rename of renames) {
|
|
211
|
+
const prov = config.providers?.[rename.provider];
|
|
212
|
+
if (!prov) continue;
|
|
213
|
+
if (!registrySeedsTarget(rename)) {
|
|
214
|
+
warnings.push(
|
|
215
|
+
`registry no longer seeds "${rename.to}" for "${rename.provider}"; skipping the `
|
|
216
|
+
+ `"${rename.from}" rename rather than writing an id the registry does not know.`,
|
|
217
|
+
);
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
if (!providerStillMatchesRegistry(rename.provider, prov)) continue;
|
|
221
|
+
|
|
222
|
+
// Provider config is a closed interface, so index through one unknown-cast
|
|
223
|
+
// view rather than casting at each assignment.
|
|
224
|
+
const row = prov as unknown as Record<string, unknown>;
|
|
225
|
+
let touched = false;
|
|
226
|
+
for (const field of MODEL_ID_LISTS) {
|
|
227
|
+
const next = renameInList(row[field], rename.from, rename.to);
|
|
228
|
+
if (!next) continue;
|
|
229
|
+
row[field] = next;
|
|
230
|
+
touched = true;
|
|
231
|
+
}
|
|
232
|
+
for (const field of MODEL_KEYED_RECORDS) {
|
|
233
|
+
const next = rename.dropReasoningEffortMap && field === "modelReasoningEffortMap"
|
|
234
|
+
? dropFromRecord(row[field], rename.from)
|
|
235
|
+
: renameInRecord(row[field], rename.from, rename.to);
|
|
236
|
+
if (!next) continue;
|
|
237
|
+
row[field] = next;
|
|
238
|
+
touched = true;
|
|
239
|
+
}
|
|
240
|
+
if (prov.defaultModel === rename.from) {
|
|
241
|
+
prov.defaultModel = rename.to;
|
|
242
|
+
touched = true;
|
|
243
|
+
}
|
|
244
|
+
if (renameDisabledModels(config, rename)) touched = true;
|
|
245
|
+
|
|
246
|
+
if (touched) {
|
|
247
|
+
changed = true;
|
|
248
|
+
warnings.push(
|
|
249
|
+
`renamed "${rename.provider}/${rename.from}" to "${rename.to}" in the saved config: ${rename.reason}.`,
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
return { config, changed, warnings };
|
|
255
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { saveConfig } from "../config";
|
|
2
|
+
import { projectModelRenames } from "./model-rename-migration";
|
|
3
|
+
import type { OcxConfig } from "../types";
|
|
4
|
+
|
|
5
|
+
export interface ModelRenameStartupDeps {
|
|
6
|
+
project: typeof projectModelRenames;
|
|
7
|
+
save: (config: OcxConfig) => void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Apply registry model renames to the saved config at startup (issue #1610).
|
|
12
|
+
*
|
|
13
|
+
* No backup is taken, unlike the OpenAI tier and Alibaba region migrations: those
|
|
14
|
+
* rewrite credentials and provider identity, where a bad projection is not
|
|
15
|
+
* recoverable from the config alone. This one only rewrites model ids that the
|
|
16
|
+
* registry itself no longer seeds, and the pre-migration value is a string this
|
|
17
|
+
* file still names, so the change is reversible by hand.
|
|
18
|
+
*/
|
|
19
|
+
export function runModelRenameStartupMigration(
|
|
20
|
+
config: OcxConfig,
|
|
21
|
+
deps: ModelRenameStartupDeps = { project: projectModelRenames, save: saveConfig },
|
|
22
|
+
): OcxConfig {
|
|
23
|
+
const projection = deps.project(config);
|
|
24
|
+
for (const warning of projection.warnings) console.warn(`[model-rename-migration] ${warning}`);
|
|
25
|
+
if (!projection.changed) return projection.config;
|
|
26
|
+
deps.save(projection.config);
|
|
27
|
+
return projection.config;
|
|
28
|
+
}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import type { OcxConfig } from "../types";
|
|
2
|
+
import { routedSlug } from "./slug-codec";
|
|
3
|
+
|
|
4
|
+
export const MODEL_REMOVAL_GRACE_FETCHES = 3;
|
|
5
|
+
export const MAX_KNOWN_MODELS_PER_PROVIDER = 2_000;
|
|
6
|
+
export const MAX_RECENT_ARRIVALS_PER_PROVIDER = 50;
|
|
7
|
+
|
|
8
|
+
export type KnownModelBaseline = NonNullable<NonNullable<OcxConfig["modelDiscovery"]>["knownModels"]>[string];
|
|
9
|
+
export type NewModelPolicy = "on" | "off";
|
|
10
|
+
|
|
11
|
+
export interface NewModelPolicyResult {
|
|
12
|
+
newIds: string[];
|
|
13
|
+
nextBaseline: KnownModelBaseline;
|
|
14
|
+
slugsToDisable: string[];
|
|
15
|
+
arrivals: Array<{ id: string; at: string }>;
|
|
16
|
+
overflow: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Whether a transition actually changes persisted state.
|
|
21
|
+
*
|
|
22
|
+
* `updatedAt` moves on every successful fetch, so comparing whole baselines would report a
|
|
23
|
+
* change every time and rewrite config.json on every catalog convergence — a write amplification
|
|
24
|
+
* that also churns the config generation other writers revalidate against. Only the fields that
|
|
25
|
+
* carry meaning are compared.
|
|
26
|
+
*/
|
|
27
|
+
function baselineDiffers(prior: KnownModelBaseline | undefined, next: KnownModelBaseline): boolean {
|
|
28
|
+
if (!prior) return true;
|
|
29
|
+
const sameList = (a: readonly string[], b: readonly string[]) =>
|
|
30
|
+
a.length === b.length && a.every((value, index) => value === b[index]);
|
|
31
|
+
if (!sameList(prior.ids, next.ids) || !sameList(prior.removed, next.removed)) return true;
|
|
32
|
+
const priorMissing = prior.missing ?? {};
|
|
33
|
+
const nextMissing = next.missing ?? {};
|
|
34
|
+
const keys = new Set([...Object.keys(priorMissing), ...Object.keys(nextMissing)]);
|
|
35
|
+
for (const key of keys) if (priorMissing[key] !== nextMissing[key]) return true;
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Pure successful-discovery transition. An absent baseline bootstraps without hiding anything. */
|
|
40
|
+
export function applyNewModelPolicy(options: {
|
|
41
|
+
provider: string;
|
|
42
|
+
discoveredIds: Iterable<string>;
|
|
43
|
+
baseline?: KnownModelBaseline;
|
|
44
|
+
policy: NewModelPolicy;
|
|
45
|
+
hasSelectedModels?: boolean;
|
|
46
|
+
now: string;
|
|
47
|
+
}): NewModelPolicyResult {
|
|
48
|
+
const discovered = [...new Set(options.discoveredIds)].sort();
|
|
49
|
+
const prior = options.baseline;
|
|
50
|
+
if (!prior) {
|
|
51
|
+
return {
|
|
52
|
+
newIds: [],
|
|
53
|
+
nextBaseline: { ids: discovered, removed: [], updatedAt: options.now },
|
|
54
|
+
slugsToDisable: [], arrivals: [],
|
|
55
|
+
overflow: discovered.length > MAX_KNOWN_MODELS_PER_PROVIDER,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const active = new Set(prior.ids);
|
|
59
|
+
const removed = new Set(prior.removed);
|
|
60
|
+
const seen = new Set(discovered);
|
|
61
|
+
const newIds = discovered.filter(id => !active.has(id) && !removed.has(id));
|
|
62
|
+
const missing: Record<string, number> = {};
|
|
63
|
+
for (const id of active) {
|
|
64
|
+
if (seen.has(id)) continue;
|
|
65
|
+
const count = (prior.missing?.[id] ?? 0) + 1;
|
|
66
|
+
if (count >= MODEL_REMOVAL_GRACE_FETCHES) {
|
|
67
|
+
active.delete(id);
|
|
68
|
+
removed.add(id);
|
|
69
|
+
} else missing[id] = count;
|
|
70
|
+
}
|
|
71
|
+
for (const id of discovered) active.add(id);
|
|
72
|
+
const unionSize = active.size + removed.size;
|
|
73
|
+
const overflow = unionSize > MAX_KNOWN_MODELS_PER_PROVIDER;
|
|
74
|
+
const arrivals = newIds.map(id => ({ id, at: options.now }));
|
|
75
|
+
return {
|
|
76
|
+
newIds,
|
|
77
|
+
nextBaseline: {
|
|
78
|
+
ids: [...active].sort(), removed: [...removed].sort(), updatedAt: options.now,
|
|
79
|
+
...(Object.keys(missing).length ? { missing } : {}),
|
|
80
|
+
},
|
|
81
|
+
// A non-empty preset/custom allowlist already excludes arrivals. This explicit no-op is
|
|
82
|
+
// deliberate: preset mode owns which matching flagships arrive on.
|
|
83
|
+
slugsToDisable: !overflow && options.policy === "off" && !options.hasSelectedModels
|
|
84
|
+
? newIds.map(id => routedSlug(options.provider, id)) : [],
|
|
85
|
+
arrivals,
|
|
86
|
+
overflow,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function effectiveNewModelPolicy(config: OcxConfig, provider: string): NewModelPolicy {
|
|
91
|
+
const local = config.providers[provider]?.newModelPolicy;
|
|
92
|
+
if (local === "on" || local === "off") return local;
|
|
93
|
+
return config.modelDiscovery?.newModelPolicy ?? "on";
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Apply authoritative provider rows to a mutable convergence copy; degraded providers are omitted. */
|
|
97
|
+
export function reconcileSuccessfulModelDiscoveries(options: {
|
|
98
|
+
config: OcxConfig;
|
|
99
|
+
models: Iterable<{ provider: string; id: string; custom?: boolean }>;
|
|
100
|
+
authoritativeProviders: Iterable<string>;
|
|
101
|
+
now: string;
|
|
102
|
+
}): boolean {
|
|
103
|
+
const byProvider = new Map<string, string[]>();
|
|
104
|
+
for (const model of options.models) {
|
|
105
|
+
if (model.custom) continue;
|
|
106
|
+
const ids = byProvider.get(model.provider) ?? [];
|
|
107
|
+
ids.push(model.id); byProvider.set(model.provider, ids);
|
|
108
|
+
}
|
|
109
|
+
let changed = false;
|
|
110
|
+
for (const provider of options.authoritativeProviders) {
|
|
111
|
+
const configured = options.config.providers[provider];
|
|
112
|
+
if (!configured || configured.liveModels === false) continue;
|
|
113
|
+
const discoveredIds = byProvider.get(provider) ?? [];
|
|
114
|
+
const discovery = options.config.modelDiscovery ??= {};
|
|
115
|
+
const known = discovery.knownModels ??= {};
|
|
116
|
+
const result = applyNewModelPolicy({
|
|
117
|
+
provider, discoveredIds, baseline: known[provider],
|
|
118
|
+
policy: effectiveNewModelPolicy(options.config, provider),
|
|
119
|
+
hasSelectedModels: (configured.selectedModels?.length ?? 0) > 0,
|
|
120
|
+
now: options.now,
|
|
121
|
+
});
|
|
122
|
+
if (result.overflow) continue;
|
|
123
|
+
const priorBaseline = known[provider];
|
|
124
|
+
const baselineChanged = baselineDiffers(priorBaseline, result.nextBaseline);
|
|
125
|
+
known[provider] = result.nextBaseline;
|
|
126
|
+
// Keep the previous timestamp when nothing else moved, so a steady-state roster does not
|
|
127
|
+
// make the baseline look dirty on the next comparison either.
|
|
128
|
+
if (!baselineChanged && priorBaseline) known[provider] = priorBaseline;
|
|
129
|
+
if (result.slugsToDisable.length) {
|
|
130
|
+
const disabled = options.config.disabledModels ??= [];
|
|
131
|
+
for (const slug of result.slugsToDisable) {
|
|
132
|
+
if (disabled.includes(slug)) continue;
|
|
133
|
+
disabled.push(slug);
|
|
134
|
+
changed = true;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (result.arrivals.length) {
|
|
138
|
+
const recent = discovery.recentArrivals ??= {};
|
|
139
|
+
recent[provider] = [...(recent[provider] ?? []), ...result.arrivals]
|
|
140
|
+
.slice(-MAX_RECENT_ARRIVALS_PER_PROVIDER);
|
|
141
|
+
changed = true;
|
|
142
|
+
}
|
|
143
|
+
if (baselineChanged) changed = true;
|
|
144
|
+
}
|
|
145
|
+
return changed;
|
|
146
|
+
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { resolveEnvValue } from "../config";
|
|
2
2
|
import {
|
|
3
|
+
CodexPoolAuthenticationError,
|
|
3
4
|
headersForCodexAuthContext,
|
|
4
5
|
hasCallerCodexBearer,
|
|
5
6
|
isCodexAuthContextUsable,
|
|
6
7
|
resolveCodexAuthContext,
|
|
8
|
+
type CodexAccountSelectionAdmission,
|
|
7
9
|
type CodexAuthContext,
|
|
8
10
|
} from "../codex/auth-context";
|
|
9
11
|
import { recordCodexUpstreamOutcome, type CodexUpstreamOutcome } from "../codex/routing";
|
|
@@ -11,6 +13,7 @@ import { extractAccountId } from "../oauth/chatgpt";
|
|
|
11
13
|
import { ForwardAdmissionCredentialError, validateForwardAdmissionCredential } from "../server/auth-cors";
|
|
12
14
|
import type { CodexAccountMode, OcxConfig, OcxProviderConfig } from "../types";
|
|
13
15
|
import {
|
|
16
|
+
CODEX_FORWARD_BASE_URL,
|
|
14
17
|
isCanonicalOpenAiForwardProvider,
|
|
15
18
|
OPENAI_API_PROVIDER_ID,
|
|
16
19
|
OPENAI_CODEX_PROVIDER_ID,
|
|
@@ -29,6 +32,17 @@ export interface ResolvedOpenAiForwardSidecar extends OpenAiForwardSidecarCandid
|
|
|
29
32
|
recordOutcome?: (outcome: CodexUpstreamOutcome) => void;
|
|
30
33
|
}
|
|
31
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Server-resolved exact account selection for a ChatGPT sidecar call.
|
|
37
|
+
* `accountId` must come from a validated account-qualified route; request headers
|
|
38
|
+
* are never trusted as account ids. `modelId` is the sidecar's actual upstream
|
|
39
|
+
* model so cooldown admission and outcome recording use the correct quota scope.
|
|
40
|
+
*/
|
|
41
|
+
export interface ExactOpenAiSidecarAccount {
|
|
42
|
+
accountId: string;
|
|
43
|
+
modelId: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
32
46
|
export interface OpenAiImagesProviderSelection {
|
|
33
47
|
forwardCandidates: OpenAiForwardSidecarCandidate[];
|
|
34
48
|
keyed?: {
|
|
@@ -41,11 +55,24 @@ export interface OpenAiImagesProviderSelection {
|
|
|
41
55
|
|
|
42
56
|
export function listOpenAiForwardSidecarCandidates(config: OcxConfig): OpenAiForwardSidecarCandidate[] {
|
|
43
57
|
const provider = config.providers[OPENAI_CODEX_PROVIDER_ID];
|
|
44
|
-
if (!provider || provider.disabled === true
|
|
58
|
+
if (!provider || provider.disabled === true) return [];
|
|
59
|
+
// The built-in registry defaults an omitted authMode to forward. Normalize only that
|
|
60
|
+
// missing field before the strict adapter/destination check; explicit key mode and
|
|
61
|
+
// noncanonical destinations remain ineligible for ChatGPT credential injection.
|
|
62
|
+
const canonicalProvider = provider.authMode === undefined
|
|
63
|
+
? { ...provider, authMode: "forward" as const }
|
|
64
|
+
: provider;
|
|
65
|
+
if (!isCanonicalOpenAiForwardProvider(canonicalProvider)) return [];
|
|
66
|
+
// The predicate accepts harmless trailing-slash variants. Pin the provider returned
|
|
67
|
+
// to credential-bearing sidecars so every consumer builds one exact ChatGPT path
|
|
68
|
+
// instead of independently concatenating the operator's equivalent spelling.
|
|
69
|
+
const pinnedProvider = canonicalProvider.baseUrl === CODEX_FORWARD_BASE_URL
|
|
70
|
+
? canonicalProvider
|
|
71
|
+
: { ...canonicalProvider, baseUrl: CODEX_FORWARD_BASE_URL };
|
|
45
72
|
return [{
|
|
46
73
|
providerName: OPENAI_CODEX_PROVIDER_ID,
|
|
47
|
-
provider,
|
|
48
|
-
accountMode: providerCodexAccountMode(OPENAI_CODEX_PROVIDER_ID,
|
|
74
|
+
provider: pinnedProvider,
|
|
75
|
+
accountMode: providerCodexAccountMode(OPENAI_CODEX_PROVIDER_ID, pinnedProvider) ?? "pool",
|
|
49
76
|
}];
|
|
50
77
|
}
|
|
51
78
|
|
|
@@ -70,7 +97,12 @@ export async function resolveFirstUsableOpenAiSidecar(
|
|
|
70
97
|
candidates: readonly OpenAiForwardSidecarCandidate[],
|
|
71
98
|
incomingHeaders: Headers,
|
|
72
99
|
config: OcxConfig,
|
|
100
|
+
options: {
|
|
101
|
+
exactAccount?: ExactOpenAiSidecarAccount;
|
|
102
|
+
beginCodexAccountSelection?: () => CodexAccountSelectionAdmission | undefined;
|
|
103
|
+
} = {},
|
|
73
104
|
): Promise<ResolvedOpenAiForwardSidecar | undefined> {
|
|
105
|
+
const { exactAccount } = options;
|
|
74
106
|
let callerBearerMayBeForwarded = true;
|
|
75
107
|
try {
|
|
76
108
|
validateForwardAdmissionCredential(incomingHeaders, config);
|
|
@@ -79,6 +111,39 @@ export async function resolveFirstUsableOpenAiSidecar(
|
|
|
79
111
|
callerBearerMayBeForwarded = false;
|
|
80
112
|
}
|
|
81
113
|
for (const candidate of candidates) {
|
|
114
|
+
if (exactAccount) {
|
|
115
|
+
// An account-qualified model is an explicit user choice. Resolve the stored
|
|
116
|
+
// credential directly even when the provider is globally Direct, and never
|
|
117
|
+
// consult Pool active state, affinity, probes, or alternates.
|
|
118
|
+
const authContext = await resolveCodexAuthContext(incomingHeaders, config, "pool", {
|
|
119
|
+
accountId: exactAccount.accountId,
|
|
120
|
+
modelId: exactAccount.modelId,
|
|
121
|
+
beginCodexAccountSelection: options.beginCodexAccountSelection,
|
|
122
|
+
});
|
|
123
|
+
if ((authContext.kind !== "pool" && authContext.kind !== "main-pool")
|
|
124
|
+
|| !isCodexAuthContextUsable(authContext, config)) {
|
|
125
|
+
// Exact selection is fail-closed. A generation/runtime-state race must not fall through
|
|
126
|
+
// to the caller-bearer error or let a later candidate select another account.
|
|
127
|
+
throw new CodexPoolAuthenticationError("Selected Codex account is unavailable");
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
...candidate,
|
|
131
|
+
authContext,
|
|
132
|
+
headers: headersForCodexAuthContext(incomingHeaders, authContext),
|
|
133
|
+
recordOutcome: (outcome: CodexUpstreamOutcome) => recordCodexUpstreamOutcome(
|
|
134
|
+
config,
|
|
135
|
+
authContext.accountId,
|
|
136
|
+
outcome,
|
|
137
|
+
{
|
|
138
|
+
modelId: exactAccount.modelId,
|
|
139
|
+
fixedAccount: true,
|
|
140
|
+
probeLeaseId: authContext.probeLeaseId,
|
|
141
|
+
probeQuotaScope: authContext.probeQuotaScope,
|
|
142
|
+
writerGeneration: authContext.writerGeneration,
|
|
143
|
+
},
|
|
144
|
+
),
|
|
145
|
+
};
|
|
146
|
+
}
|
|
82
147
|
if (candidate.accountMode === "direct") {
|
|
83
148
|
if (!callerBearerMayBeForwarded || !hasCallerCodexBearer(incomingHeaders)) continue;
|
|
84
149
|
const headers = directSidecarHeaders(incomingHeaders);
|
|
@@ -89,7 +154,9 @@ export async function resolveFirstUsableOpenAiSidecar(
|
|
|
89
154
|
headers,
|
|
90
155
|
};
|
|
91
156
|
}
|
|
92
|
-
const authContext = await resolveCodexAuthContext(incomingHeaders, config, candidate.accountMode
|
|
157
|
+
const authContext = await resolveCodexAuthContext(incomingHeaders, config, candidate.accountMode, {
|
|
158
|
+
beginCodexAccountSelection: options.beginCodexAccountSelection,
|
|
159
|
+
});
|
|
93
160
|
if (!isCodexAuthContextUsable(authContext, config)) continue;
|
|
94
161
|
return {
|
|
95
162
|
...candidate,
|
|
@@ -102,6 +169,7 @@ export async function resolveFirstUsableOpenAiSidecar(
|
|
|
102
169
|
authContext.accountId,
|
|
103
170
|
outcome,
|
|
104
171
|
{
|
|
172
|
+
threadId: authContext.affinityKey,
|
|
105
173
|
probeLeaseId: authContext.probeLeaseId,
|
|
106
174
|
writerGeneration: authContext.writerGeneration,
|
|
107
175
|
},
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
backupConfigBeforeOpenAiTierMigration,
|
|
3
|
+
OpenAiTierBackupCollisionError,
|
|
4
|
+
OpenAiTierRollbackPreserveError,
|
|
5
|
+
preserveOpenAiTierRollbackSnapshot,
|
|
6
|
+
saveConfig,
|
|
7
|
+
} from "../config";
|
|
2
8
|
import type { OcxConfig } from "../types";
|
|
3
9
|
import { projectOpenAiTierMigration } from "./openai-tiers";
|
|
4
10
|
|
|
@@ -6,6 +12,23 @@ export interface OpenAiTierStartupDeps {
|
|
|
6
12
|
project: typeof projectOpenAiTierMigration;
|
|
7
13
|
backup: () => void;
|
|
8
14
|
save: (config: OcxConfig) => void;
|
|
15
|
+
preserveRollback?: (error: OpenAiTierBackupCollisionError) => void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function defaultPreserveRollback(error: OpenAiTierBackupCollisionError): void {
|
|
19
|
+
if (!error.configPath) throw error;
|
|
20
|
+
try {
|
|
21
|
+
const preserved = preserveOpenAiTierRollbackSnapshot(error.configPath);
|
|
22
|
+
console.warn(`[openai-provider-migration] Preserved rollback snapshot at ${preserved}`);
|
|
23
|
+
} catch (cause) {
|
|
24
|
+
if (
|
|
25
|
+
cause instanceof OpenAiTierRollbackPreserveError
|
|
26
|
+
&& (cause.code === "missing" || cause.code === "not-rollback")
|
|
27
|
+
) {
|
|
28
|
+
throw error;
|
|
29
|
+
}
|
|
30
|
+
throw cause;
|
|
31
|
+
}
|
|
9
32
|
}
|
|
10
33
|
|
|
11
34
|
const DEFAULT_DEPS: OpenAiTierStartupDeps = {
|
|
@@ -20,7 +43,13 @@ export function runOpenAiTierStartupMigration(
|
|
|
20
43
|
): OcxConfig {
|
|
21
44
|
const projection = deps.project(config);
|
|
22
45
|
if (!projection.changed) return projection.config;
|
|
23
|
-
|
|
46
|
+
try {
|
|
47
|
+
deps.backup();
|
|
48
|
+
} catch (error) {
|
|
49
|
+
if (!(error instanceof OpenAiTierBackupCollisionError)) throw error;
|
|
50
|
+
(deps.preserveRollback ?? defaultPreserveRollback)(error);
|
|
51
|
+
deps.backup();
|
|
52
|
+
}
|
|
24
53
|
deps.save(projection.config);
|
|
25
54
|
for (const warning of projection.warnings) console.warn(`[openai-provider-migration] ${warning}`);
|
|
26
55
|
return projection.config;
|