@iislee/opencodex 2.11.0 → 2.31.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS_INSTALL.md +109 -0
- package/README.md +114 -19
- package/bin/ocx.mjs +164 -36
- package/bin/package-main.mjs +1 -1
- package/gui/dist/assets/index-BF38heuV.js +104 -0
- package/gui/dist/assets/index-DMiI18Kv.css +1 -0
- package/gui/dist/index.html +2 -2
- package/gui/dist/provider-icons/alibaba-color.svg +1 -1
- package/gui/dist/provider-icons/antigravity-color.svg +1 -1
- package/gui/dist/provider-icons/claude-color.svg +1 -1
- package/gui/dist/provider-icons/cline-color.svg +16 -0
- package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/commandcode-color.svg +1 -0
- package/gui/dist/provider-icons/copilot-color.svg +1 -1
- package/gui/dist/provider-icons/cursor-color.svg +1 -1
- package/gui/dist/provider-icons/deepseek-color.svg +1 -1
- package/gui/dist/provider-icons/firepass-color.svg +1 -1
- package/gui/dist/provider-icons/fireworks-color.svg +1 -1
- package/gui/dist/provider-icons/gemini-color.svg +1 -1
- package/gui/dist/provider-icons/github-copilot-color.svg +1 -1
- package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -1
- package/gui/dist/provider-icons/grok.svg +1 -1
- package/gui/dist/provider-icons/groq-color.svg +1 -1
- package/gui/dist/provider-icons/huggingface-color.svg +1 -1
- package/gui/dist/provider-icons/kimi-color.svg +1 -1
- package/gui/dist/provider-icons/kiro-color.svg +2 -2
- package/gui/dist/provider-icons/lm-studio-color.svg +1 -1
- package/gui/dist/provider-icons/mistral-color.svg +1 -1
- package/gui/dist/provider-icons/moonshot-color.svg +1 -1
- package/gui/dist/provider-icons/nvidia-color.svg +1 -1
- package/gui/dist/provider-icons/ollama-color.svg +1 -1
- package/gui/dist/provider-icons/openai.svg +1 -1
- package/gui/dist/provider-icons/opencode.svg +2 -1
- package/gui/dist/provider-icons/openrouter-color.svg +1 -1
- package/gui/dist/provider-icons/pi.svg +2 -2
- package/gui/dist/provider-icons/qianfan-color.svg +1 -1
- package/gui/dist/provider-icons/qwen-portal-color.svg +1 -1
- package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -1
- package/gui/dist/provider-icons/vllm-color.svg +1 -1
- package/gui/dist/provider-icons/xiaomi-color.svg +1 -1
- package/package.json +19 -10
- package/src/adapters/anthropic-output-schema.ts +137 -0
- package/src/adapters/anthropic.ts +376 -52
- package/src/adapters/base.ts +54 -7
- package/src/adapters/client-fingerprint.ts +18 -12
- package/src/adapters/cline-pass-deepseek-v4-tool-replay.ts +69 -0
- package/src/adapters/command-code.ts +601 -0
- package/src/adapters/cursor/checkpoint-store.ts +303 -0
- package/src/adapters/cursor/cursor-errors.ts +129 -6
- package/src/adapters/cursor/discovery.ts +61 -4
- package/src/adapters/cursor/effort-map.ts +27 -3
- package/src/adapters/cursor/framing.ts +39 -0
- package/src/adapters/cursor/h2-pool.ts +123 -0
- package/src/adapters/cursor/http1-bidi.ts +361 -0
- package/src/adapters/cursor/images.ts +704 -0
- package/src/adapters/cursor/live-models.ts +174 -58
- package/src/adapters/cursor/live-transport.ts +609 -170
- package/src/adapters/cursor/native-exec-common.ts +23 -2
- package/src/adapters/cursor/native-exec-fs.ts +10 -7
- package/src/adapters/cursor/native-exec-network.ts +1 -1
- package/src/adapters/cursor/native-exec-shell.ts +0 -1
- package/src/adapters/cursor/native-exec.ts +101 -14
- package/src/adapters/cursor/protobuf-events.ts +829 -11
- package/src/adapters/cursor/protobuf-request.ts +383 -65
- package/src/adapters/cursor/request-builder.ts +237 -31
- package/src/adapters/cursor/tool-definitions.ts +242 -12
- package/src/adapters/cursor/tool-result-normalize.ts +92 -0
- package/src/adapters/cursor/transport.ts +22 -0
- package/src/adapters/cursor/types.ts +28 -1
- package/src/adapters/cursor.ts +133 -7
- package/src/adapters/google-antigravity-replay.ts +558 -34
- package/src/adapters/google-antigravity-wire.ts +43 -10
- package/src/adapters/google-http.ts +38 -10
- package/src/adapters/google-tool-schema.ts +80 -15
- package/src/adapters/google-truncation.ts +11 -0
- package/src/adapters/google.ts +618 -74
- package/src/adapters/identity.ts +39 -6
- package/src/adapters/kiro-errors.ts +11 -0
- package/src/adapters/kiro-events.ts +19 -1
- package/src/adapters/kiro-thinking.ts +18 -2
- package/src/adapters/kiro-tools.ts +10 -1
- package/src/adapters/kiro.ts +92 -54
- package/src/adapters/mimo-free.ts +17 -0
- package/src/adapters/openai-chat-url.ts +11 -0
- package/src/adapters/openai-chat.ts +1311 -336
- package/src/adapters/openai-responses-url.ts +16 -0
- package/src/adapters/openai-responses.ts +830 -56
- package/src/adapters/registry.ts +175 -0
- package/src/adapters/responses-tool-schema.ts +67 -0
- package/src/adapters/tool-call-id.ts +119 -0
- package/src/adapters/tool-catalog-nudge.ts +104 -21
- package/src/adapters/xai-web-search.ts +185 -0
- package/src/bridge.ts +428 -61
- package/src/chat/inbound.ts +43 -19
- package/src/chat/outbound.ts +82 -26
- package/src/claude/agents-inject.ts +32 -9
- package/src/claude/context-windows.ts +21 -5
- package/src/claude/desktop-3p.ts +243 -9
- package/src/claude/gateway-cache.ts +41 -4
- package/src/claude/inbound.ts +72 -3
- package/src/claude/model-info.ts +38 -15
- package/src/claude/outbound.ts +70 -16
- package/src/cli/account-api.ts +35 -1
- package/src/cli/account-auth.ts +33 -6
- package/src/cli/account-catalog-refresh.ts +14 -0
- package/src/cli/account-extended.ts +389 -2
- package/src/cli/account-main.ts +317 -0
- package/src/cli/account.ts +30 -6
- package/src/cli/agent.ts +45 -1
- package/src/cli/claude-agent-startup-sync.ts +73 -0
- package/src/cli/claude-desktop.ts +29 -4
- package/src/cli/claude.ts +103 -34
- package/src/cli/codex-log-guard-doctor.ts +103 -0
- package/src/cli/codex-shim-autorestore.ts +2 -0
- package/src/cli/codex-shim-readiness.ts +76 -0
- package/src/cli/combo.ts +8 -0
- package/src/cli/config-command.ts +74 -10
- package/src/cli/dispatch.ts +593 -0
- package/src/cli/doctor.ts +315 -43
- package/src/cli/ensure-desired-integrations.ts +152 -0
- package/src/cli/export-command.ts +46 -20
- package/src/cli/help.ts +20 -271
- package/src/cli/index.ts +378 -519
- package/src/cli/init.ts +4 -17
- package/src/cli/integrations.ts +120 -2
- package/src/cli/lab.ts +607 -0
- package/src/cli/launcher-context.ts +77 -0
- package/src/cli/minimax.ts +497 -0
- package/src/cli/models-runtime.ts +35 -2
- package/src/cli/models.ts +100 -14
- package/src/cli/observe.ts +92 -3
- package/src/cli/opencode.ts +4 -2
- package/src/cli/provider-runtime.ts +18 -1
- package/src/cli/provider.ts +24 -3
- package/src/cli/ready.ts +301 -0
- package/src/cli/registry.ts +437 -0
- package/src/cli/root.ts +86 -0
- package/src/cli/route-policy.ts +92 -0
- package/src/cli/runtime-api.ts +6 -3
- package/src/cli/star-prompt.ts +71 -15
- package/src/cli/status.ts +10 -3
- package/src/cli/system-restart-client.ts +146 -0
- package/src/cli/tray-proxy.ts +153 -6
- package/src/cli/v2.ts +105 -10
- package/src/cli.ts +1 -1
- package/src/clients/config-export.ts +1358 -21
- package/src/codex/account-label.ts +14 -1
- package/src/codex/account-lifecycle.ts +130 -13
- package/src/codex/account-namespaces.ts +49 -3
- package/src/codex/account-priority.ts +83 -0
- package/src/codex/account-store.ts +29 -2
- package/src/codex/account-usability.ts +25 -2
- package/src/codex/admission.ts +256 -0
- package/src/codex/affinity-debug.ts +162 -0
- package/src/codex/app-server-processes.ts +493 -106
- package/src/codex/app-server-restart-service.ts +232 -0
- package/src/codex/auth-api.ts +849 -242
- package/src/codex/auth-collision.ts +5 -3
- package/src/codex/auth-context.ts +345 -32
- package/src/codex/autostart-health.ts +8 -1
- package/src/codex/catalog/account-models.ts +67 -0
- package/src/codex/catalog/aggregation.ts +68 -10
- package/src/codex/catalog/bundled.ts +331 -33
- package/src/codex/catalog/effort.ts +121 -30
- package/src/codex/catalog/filesystem-evidence.ts +302 -0
- package/src/codex/catalog/kinds.ts +2 -0
- package/src/codex/catalog/metadata.ts +529 -45
- package/src/codex/catalog/native-models.ts +72 -0
- package/src/codex/catalog/parsing.ts +224 -30
- package/src/codex/catalog/provider-fetch.ts +1460 -134
- package/src/codex/catalog/sync.ts +1449 -186
- package/src/codex/catalog-admission.ts +199 -0
- package/src/codex/catalog-refresh-status.ts +105 -0
- package/src/codex/catalog-write-serialization.ts +242 -0
- package/src/codex/catalog.ts +6 -3
- package/src/codex/codex-write-lock.ts +384 -0
- package/src/codex/convergence-types.ts +614 -0
- package/src/codex/convergence.ts +651 -0
- package/src/codex/coordinator-doctor.ts +332 -0
- package/src/codex/custom-model-catalog-migration.ts +176 -0
- package/src/codex/desired-state.ts +230 -0
- package/src/codex/features.ts +636 -39
- package/src/codex/generation.ts +202 -0
- package/src/codex/history-job.ts +407 -0
- package/src/codex/history-lock.ts +242 -0
- package/src/codex/history-migration-guardian.ts +26 -20
- package/src/codex/history-provider.ts +231 -28
- package/src/codex/history-transition.ts +105 -0
- package/src/codex/history-worker.ts +220 -0
- package/src/codex/inject-coordination.ts +290 -0
- package/src/codex/inject.ts +1073 -152
- package/src/codex/injected-marker.ts +37 -3
- package/src/codex/integration-record.ts +266 -0
- package/src/codex/internal/catalog-writer.ts +203 -0
- package/src/codex/internal/history-writer.ts +80 -0
- package/src/codex/journal.ts +66 -4
- package/src/codex/log-guard/inspect.ts +506 -0
- package/src/codex/log-guard/lock.ts +150 -0
- package/src/codex/log-guard/maintenance.ts +403 -0
- package/src/codex/log-guard/path-safety.ts +88 -0
- package/src/codex/log-guard/policy.ts +44 -0
- package/src/codex/log-guard/processes.ts +205 -0
- package/src/codex/log-guard/protection.ts +489 -0
- package/src/codex/log-guard/sqlite-errors.ts +9 -0
- package/src/codex/main-account-cache.ts +24 -0
- package/src/codex/main-account.ts +29 -1
- package/src/codex/management-convergence.ts +167 -0
- package/src/codex/model-cache.ts +56 -10
- package/src/codex/model-entitlements.ts +353 -0
- package/src/codex/native-main-admission.ts +47 -0
- package/src/codex/native-main-auth-temp.ts +187 -0
- package/src/codex/native-main-claim.ts +178 -0
- package/src/codex/native-main-lock-file.ts +162 -0
- package/src/codex/native-main-owner.ts +329 -0
- package/src/codex/native-profile-api.ts +247 -0
- package/src/codex/native-profile-manager.ts +1531 -0
- package/src/codex/native-profile-processes.ts +121 -0
- package/src/codex/native-profile-recovery.ts +99 -0
- package/src/codex/native-profile-stage-store.ts +387 -0
- package/src/codex/native-profile-startup.ts +492 -0
- package/src/codex/native-profile-store.ts +855 -0
- package/src/codex/native-profile-types.ts +120 -0
- package/src/codex/native-residue.ts +682 -0
- package/src/codex/paths.ts +80 -1
- package/src/codex/plan-from-token.ts +140 -0
- package/src/codex/plan.ts +40 -0
- package/src/codex/plugins-doctor.ts +1 -1
- package/src/codex/pool-rotation.ts +74 -4
- package/src/codex/project-config-warnings.ts +20 -6
- package/src/codex/prompt-journal.ts +352 -0
- package/src/codex/prompt-layers.ts +967 -0
- package/src/codex/prompt-lock.ts +143 -0
- package/src/codex/quota-rejection.ts +298 -0
- package/src/codex/quota.ts +175 -13
- package/src/codex/refresh.ts +11 -2
- package/src/codex/reset-credit-recovery.ts +1044 -0
- package/src/codex/routing.ts +505 -94
- package/src/codex/runtime.ts +159 -38
- package/src/codex/shim.ts +1009 -28
- package/src/codex/subagent-model-fallback.ts +350 -35
- package/src/codex/sync.ts +191 -2
- package/src/codex/transition-state.ts +612 -0
- package/src/codex/upstream-host-health.ts +368 -0
- package/src/codex/user-identity.ts +557 -0
- package/src/codex/warmup.ts +187 -81
- package/src/codex/write-coordination.ts +114 -0
- package/src/combos/failover.ts +20 -0
- package/src/combos/index.ts +4 -0
- package/src/combos/request.ts +32 -0
- package/src/combos/types.ts +81 -9
- package/src/config/provider-name.ts +24 -0
- package/src/config.ts +1762 -140
- package/src/generated/compatibility-version.json +3164 -0
- package/src/generated/{jawcode-model-metadata.ts → model-metadata.ts} +19 -17
- package/src/grok/inject.ts +16 -5
- package/src/grok/inspect.ts +45 -0
- package/src/grok/sync.ts +2 -2
- package/src/images/loop.ts +152 -29
- package/src/images/plan.ts +23 -13
- package/src/integrations/config-io.ts +269 -0
- package/src/integrations/journal.ts +315 -0
- package/src/integrations/merge.ts +135 -0
- package/src/integrations/mutation-flight.ts +71 -0
- package/src/integrations/native/ownership-preflight.ts +202 -0
- package/src/integrations/omp-yaml-source.ts +358 -0
- package/src/integrations/owned-refresh.ts +74 -0
- package/src/integrations/ownership.ts +111 -0
- package/src/integrations/registry.ts +159 -0
- package/src/integrations/serialize.ts +314 -0
- package/src/integrations/state.ts +361 -0
- package/src/integrations/store.ts +103 -0
- package/src/integrations/writer-lock.ts +98 -0
- package/src/integrations/writer.ts +691 -0
- package/src/lab/artifacts/sanitize.ts +586 -0
- package/src/lab/artifacts/secure-fs.ts +475 -0
- package/src/lab/artifacts/store.ts +310 -0
- package/src/lab/automation/budgets.ts +78 -0
- package/src/lab/automation/config-persistence.ts +256 -0
- package/src/lab/automation/constants.ts +39 -0
- package/src/lab/automation/cooldown.ts +103 -0
- package/src/lab/automation/dispatch.ts +211 -0
- package/src/lab/automation/index.ts +13 -0
- package/src/lab/automation/orchestrator.ts +499 -0
- package/src/lab/automation/persistence.ts +512 -0
- package/src/lab/automation/planner.ts +371 -0
- package/src/lab/automation/policy.ts +136 -0
- package/src/lab/automation/queue.ts +191 -0
- package/src/lab/automation/recovery.ts +24 -0
- package/src/lab/automation/route-context.ts +21 -0
- package/src/lab/automation/run-key.ts +44 -0
- package/src/lab/automation/runs-query.ts +34 -0
- package/src/lab/automation/types.ts +160 -0
- package/src/lab/conformance/assertion.ts +325 -0
- package/src/lab/conformance/digest.ts +22 -0
- package/src/lab/conformance/executor.ts +741 -0
- package/src/lab/conformance/fixture-provider.ts +27 -0
- package/src/lab/conformance/fixtures/live-v1-cases.json +175 -0
- package/src/lab/conformance/fixtures/protocol-v1-cases.json +461 -0
- package/src/lab/conformance/harness-budget.ts +47 -0
- package/src/lab/conformance/index.ts +5 -0
- package/src/lab/conformance/jcs.ts +64 -0
- package/src/lab/conformance/json-pointer.ts +39 -0
- package/src/lab/conformance/manifest.ts +180 -0
- package/src/lab/conformance/mcp-stub.ts +179 -0
- package/src/lab/conformance/negative-controls.ts +164 -0
- package/src/lab/conformance/observation.ts +355 -0
- package/src/lab/conformance/runner.ts +68 -0
- package/src/lab/conformance/sse-normalize.ts +59 -0
- package/src/lab/conformance/suite-manifest.ts +78 -0
- package/src/lab/conformance/types.ts +214 -0
- package/src/lab/constants.ts +126 -0
- package/src/lab/digest.ts +64 -0
- package/src/lab/events/errors.ts +9 -0
- package/src/lab/events/limits.ts +117 -0
- package/src/lab/events/types.ts +229 -0
- package/src/lab/events/validate.ts +781 -0
- package/src/lab/fabric/constants.ts +40 -0
- package/src/lab/fabric/executor.ts +492 -0
- package/src/lab/fabric/index.ts +80 -0
- package/src/lab/fabric/manifest.ts +222 -0
- package/src/lab/fabric/observe.ts +489 -0
- package/src/lab/fabric/patch.ts +79 -0
- package/src/lab/fabric/producer-child.ts +139 -0
- package/src/lab/fabric/producer-isolate.ts +276 -0
- package/src/lab/fabric/producer-protocol.ts +61 -0
- package/src/lab/fabric/scratch.ts +439 -0
- package/src/lab/fabric/subject.ts +106 -0
- package/src/lab/fabric/types.ts +134 -0
- package/src/lab/fabric/verifier.ts +98 -0
- package/src/lab/index.ts +54 -0
- package/src/lab/ledger/artifact-refs.ts +127 -0
- package/src/lab/ledger/invalidation.ts +136 -0
- package/src/lab/ledger/purge.ts +310 -0
- package/src/lab/ledger/store.ts +532 -0
- package/src/lab/live/credential-lease.ts +53 -0
- package/src/lab/live/destination.ts +155 -0
- package/src/lab/live/executor.ts +336 -0
- package/src/lab/live/inert-tools.ts +56 -0
- package/src/lab/live/manifest.ts +85 -0
- package/src/lab/live/mcp-loopback.ts +57 -0
- package/src/lab/live/runner.ts +19 -0
- package/src/lab/live/sandbox.ts +61 -0
- package/src/lab/live/suite-manifest.ts +41 -0
- package/src/lab/live/transport.ts +118 -0
- package/src/lab/live/types.ts +197 -0
- package/src/lab/observe/from-conformance.ts +301 -0
- package/src/lab/observe/from-live.ts +117 -0
- package/src/lab/paths.ts +153 -0
- package/src/lab/projection/rebuild.ts +495 -0
- package/src/lab/projection/schema.ts +135 -0
- package/src/lab/projection/verdicts.ts +474 -0
- package/src/lab/projection/verification.ts +412 -0
- package/src/lab/public/bundle.ts +217 -0
- package/src/lab/public/community-authority.ts +175 -0
- package/src/lab/public/community-files.ts +29 -0
- package/src/lab/public/community.ts +479 -0
- package/src/lab/public/file-safety.ts +155 -0
- package/src/lab/public/ids.ts +26 -0
- package/src/lab/public/index.ts +16 -0
- package/src/lab/public/mutation-lock.ts +424 -0
- package/src/lab/public/operator.ts +353 -0
- package/src/lab/public/origin-purge.ts +79 -0
- package/src/lab/public/origin.ts +203 -0
- package/src/lab/public/privacy.ts +143 -0
- package/src/lab/public/private-file.ts +261 -0
- package/src/lab/public/project.ts +124 -0
- package/src/lab/public/purge-test-fault.ts +21 -0
- package/src/lab/public/purge.ts +223 -0
- package/src/lab/public/registry.ts +44 -0
- package/src/lab/public/revocation.ts +252 -0
- package/src/lab/public/signature.ts +243 -0
- package/src/lab/public/storage.ts +105 -0
- package/src/lab/public/strict-json.ts +206 -0
- package/src/lab/public/time.ts +26 -0
- package/src/lab/public/types.ts +172 -0
- package/src/lab/public/validate.ts +391 -0
- package/src/lab/query/catalog.ts +101 -0
- package/src/lab/query/connection.ts +107 -0
- package/src/lab/query/constants.ts +4 -0
- package/src/lab/query/cursor.ts +132 -0
- package/src/lab/query/dto-map.ts +277 -0
- package/src/lab/query/errors.ts +22 -0
- package/src/lab/query/freshness.ts +53 -0
- package/src/lab/query/index.ts +45 -0
- package/src/lab/query/latest-observation.ts +59 -0
- package/src/lab/query/passive-production.ts +159 -0
- package/src/lab/query/queries.ts +444 -0
- package/src/lab/query/types.ts +266 -0
- package/src/lab/subject/behavior-fingerprint.ts +77 -0
- package/src/lab/subject/installation-salt.ts +112 -0
- package/src/lab/subject/protocol-subject.ts +80 -0
- package/src/lab/subject/route-subject.ts +74 -0
- package/src/lib/app-owned-memory-stores.ts +22 -0
- package/src/lib/bounded-body.ts +153 -9
- package/src/lib/bun-runtime.ts +125 -12
- package/src/lib/bun-stream-caps.ts +13 -9
- package/src/lib/codex-restart-contract.ts +120 -0
- package/src/lib/config-ownership.ts +6 -2
- package/src/lib/destination-policy.ts +65 -1
- package/src/lib/errors.ts +44 -2
- package/src/lib/fabric-task-execution-authority.ts +7 -0
- package/src/lib/fabric-task-host.ts +29 -0
- package/src/lib/lab-activation.ts +223 -0
- package/src/lib/lab-live-execution-authority.ts +13 -0
- package/src/lib/lab-live-host.ts +30 -0
- package/src/lib/lab-live-pinned-sender.ts +56 -0
- package/src/lib/lab-live-route-production.ts +130 -0
- package/src/lib/lab-passive-linker-registration.ts +26 -0
- package/src/lib/local-management-attestation.ts +51 -0
- package/src/lib/local-management-capability.ts +100 -0
- package/src/lib/local-provider-reload-contract.ts +100 -0
- package/src/lib/optional-shutdown-hooks.ts +57 -0
- package/src/lib/pinned-http.ts +145 -26
- package/src/lib/process-control.ts +4 -1
- package/src/lib/provider-outbound.ts +49 -9
- package/src/lib/redact.ts +419 -3
- package/src/lib/self-launch-argv.ts +15 -0
- package/src/lib/server-resource-ownership.ts +71 -0
- package/src/lib/shadow-call.ts +35 -4
- package/src/lib/sse-decoder.ts +41 -0
- package/src/lib/state-store-registrations.ts +10 -2
- package/src/lib/system-restart-contract.ts +73 -0
- package/src/lib/token-estimate.ts +19 -2
- package/src/lib/tool-argument-integers.ts +202 -0
- package/src/lib/translator-budget.ts +44 -0
- package/src/lib/upstream-http-version.ts +57 -0
- package/src/lib/upstream-reachability.ts +95 -0
- package/src/lib/upstream-retry.ts +156 -3
- package/src/lib/windows-atomic-replace.ts +155 -0
- package/src/lib/windows-elevation.ts +70 -2
- package/src/lib/windows-secret-acl.ts +409 -69
- package/src/lib/windows-service-wrappers.ts +72 -0
- package/src/lib/windows-text.ts +106 -0
- package/src/lib/windows-user-principal.ts +341 -0
- package/src/lib/winsw.ts +33 -5
- package/src/oauth/account-import/google-antigravity-adapter.ts +74 -0
- package/src/oauth/account-import/index.ts +15 -0
- package/src/oauth/account-import/parser.ts +83 -0
- package/src/oauth/account-import/registry.ts +18 -0
- package/src/oauth/account-import/service.ts +75 -0
- package/src/oauth/account-import/types.ts +91 -0
- package/src/oauth/anthropic.ts +12 -1
- package/src/oauth/callback-server.ts +8 -2
- package/src/oauth/chatgpt.ts +12 -1
- package/src/oauth/command-code.ts +239 -0
- package/src/oauth/cursor.ts +46 -5
- package/src/oauth/google-antigravity.ts +35 -3
- package/src/oauth/health.ts +20 -12
- package/src/oauth/index.ts +398 -66
- package/src/oauth/key-providers.ts +16 -0
- package/src/oauth/kimi.ts +16 -2
- package/src/oauth/kiro.ts +50 -6
- package/src/oauth/local-token-detect.ts +11 -2
- package/src/oauth/log.ts +3 -1
- package/src/oauth/login-cli.ts +88 -28
- package/src/oauth/nous.ts +798 -0
- package/src/oauth/store.ts +119 -21
- package/src/oauth/token-guardian.ts +9 -3
- package/src/pi/models.ts +2 -2
- package/src/providers/alibaba-region-migration.ts +1 -1
- package/src/providers/antigravity-models.ts +521 -31
- package/src/providers/base-url-choices.ts +10 -0
- package/src/providers/codex-capacity.ts +292 -0
- package/src/providers/command-code-efforts.ts +144 -0
- package/src/providers/context-cap.ts +22 -5
- package/src/providers/cursor-pool.ts +72 -0
- package/src/providers/derive.ts +253 -6
- package/src/providers/fastwire.ts +501 -0
- package/src/providers/free-directory.ts +10 -7
- package/src/providers/google-vertex-location.ts +14 -0
- package/src/providers/key-failover.ts +71 -3
- package/src/providers/label.ts +1 -1
- package/src/providers/model-discovery-limits.ts +16 -0
- package/src/providers/model-discovery.ts +115 -22
- package/src/providers/model-rename-migration.ts +255 -0
- package/src/providers/model-rename-startup.ts +28 -0
- package/src/providers/openai-sidecar.ts +72 -4
- package/src/providers/openai-tier-startup.ts +31 -2
- package/src/providers/openai-tiers.ts +119 -4
- package/src/providers/openai-virtual-models.ts +1 -0
- package/src/providers/opencode-zen-rate-limit.ts +102 -0
- package/src/providers/provider-id-rewrite.ts +29 -0
- package/src/providers/quota.ts +1319 -38
- package/src/providers/registry.ts +1429 -111
- package/src/providers/request-pacing.ts +310 -0
- package/src/providers/service-tier.ts +277 -0
- package/src/providers/slug-codec.ts +42 -6
- package/src/providers/static-model-discovery.ts +86 -0
- package/src/providers/xai-responses-opt-in.ts +15 -0
- package/src/providers/xai-transport.ts +11 -4
- package/src/reasoning-effort.ts +49 -1
- package/src/responses/compaction.ts +26 -1
- package/src/responses/custom-tool-compat.ts +266 -0
- package/src/responses/hosted-tool-policy.ts +9 -0
- package/src/responses/namespace-tool-compat.ts +355 -0
- package/src/responses/parser.ts +220 -38
- package/src/responses/provider-continuation.ts +98 -0
- package/src/responses/provider-opaque-metadata.ts +73 -0
- package/src/responses/reasoning-envelope.ts +9 -1
- package/src/responses/reasoning-replay-cache.ts +426 -0
- package/src/responses/schema.ts +7 -1
- package/src/responses/spill-store.ts +75 -10
- package/src/responses/state.ts +565 -27
- package/src/responses/thought-signature-replay.ts +347 -0
- package/src/responses/tool-search-compat.ts +301 -0
- package/src/responses/truncated-stop-reason.ts +60 -0
- package/src/router.ts +366 -30
- package/src/routing/analytics.ts +378 -0
- package/src/routing/capability.ts +244 -0
- package/src/routing/compatibility/assemble.ts +73 -0
- package/src/routing/compatibility/behavior.ts +278 -0
- package/src/routing/compatibility/catalog.ts +99 -0
- package/src/routing/compatibility/endpoint.ts +52 -0
- package/src/routing/compatibility/lab-evidence-provider.ts +130 -0
- package/src/routing/compatibility/policy.ts +181 -0
- package/src/routing/compatibility/provider-slot.ts +56 -0
- package/src/routing/compatibility/reader.ts +110 -0
- package/src/routing/compatibility/subject.ts +191 -0
- package/src/routing/compatibility/types.ts +64 -0
- package/src/routing/compatibility/version.ts +104 -0
- package/src/routing/cost.ts +77 -0
- package/src/routing/evaluator.ts +495 -0
- package/src/routing/health.ts +412 -0
- package/src/routing/history/cursor.ts +43 -0
- package/src/routing/history/indexer.ts +605 -0
- package/src/routing/history/schema.ts +72 -0
- package/src/routing/profile-namespace.ts +15 -0
- package/src/routing/profile.ts +547 -0
- package/src/routing/quota.ts +145 -0
- package/src/routing/request-evidence.ts +45 -0
- package/src/routing/trace.ts +776 -0
- package/src/server/adapter-resolve.ts +2 -29
- package/src/server/auth-cors.ts +267 -46
- package/src/server/background-lifecycle.ts +182 -0
- package/src/server/chat-completions.ts +130 -56
- package/src/server/chat-native-sse.ts +331 -0
- package/src/server/chat-native.ts +426 -0
- package/src/server/claude-messages.ts +159 -43
- package/src/server/direct-local-http.ts +347 -0
- package/src/server/effort-policy.ts +18 -0
- package/src/server/github-copilot-responses-repair.ts +338 -0
- package/src/server/gui-static.ts +39 -10
- package/src/server/images.ts +94 -12
- package/src/server/index.ts +865 -181
- package/src/server/lifecycle.ts +284 -13
- package/src/server/live.ts +136 -17
- package/src/server/local-management-read-client.ts +90 -0
- package/src/server/local-provider-reload-client.ts +137 -0
- package/src/server/management/agent-settings-routes.ts +398 -103
- package/src/server/management/api-key-usage.ts +31 -5
- package/src/server/management/body.ts +6 -0
- package/src/server/management/combo-routes.ts +62 -24
- package/src/server/management/config-routes.ts +464 -51
- package/src/server/management/context.ts +80 -2
- package/src/server/management/integration-routes.ts +498 -0
- package/src/server/management/lab-automation-routes.ts +206 -0
- package/src/server/management/lab-routes.ts +563 -0
- package/src/server/management/logs-usage-routes.ts +101 -32
- package/src/server/management/model-routes.ts +189 -131
- package/src/server/management/model-rows.ts +163 -0
- package/src/server/management/native-integration-routes.ts +769 -0
- package/src/server/management/oauth-account-routes.ts +80 -4
- package/src/server/management/provider-capability-config.ts +48 -0
- package/src/server/management/provider-routes.ts +764 -157
- package/src/server/management/request-history-routes.ts +191 -0
- package/src/server/management/routing-analytics-routes.ts +74 -0
- package/src/server/management/routing-profile-routes.ts +380 -0
- package/src/server/management/shared.ts +27 -11
- package/src/server/management/sidebar-routes.ts +47 -31
- package/src/server/management/storage-log-guard-routes.ts +186 -0
- package/src/server/management/sync-response.ts +69 -0
- package/src/server/management/system-restart.ts +288 -32
- package/src/server/management/system-routes.ts +77 -0
- package/src/server/management/usage-summary-cache.ts +9 -1
- package/src/server/management/vision-sidecar-options.ts +167 -0
- package/src/server/management/web-search-sidecar-options.ts +120 -0
- package/src/server/management-api.ts +115 -14
- package/src/server/management-auth.ts +220 -5
- package/src/server/passive-route-linker.ts +66 -0
- package/src/server/ports.ts +41 -1
- package/src/server/proxy-liveness.ts +132 -5
- package/src/server/readiness.ts +99 -0
- package/src/server/relay-eager.ts +82 -42
- package/src/server/relay.ts +236 -76
- package/src/server/request-decompress.ts +113 -6
- package/src/server/request-log.ts +235 -22
- package/src/server/responses/agent-task-recovery-cache.ts +143 -0
- package/src/server/responses/agent-task-recovery.ts +465 -0
- package/src/server/responses/collaboration.ts +204 -35
- package/src/server/responses/compact.ts +442 -55
- package/src/server/responses/core.ts +2872 -331
- package/src/server/responses/empty-completion-guard.ts +276 -0
- package/src/server/responses/encrypted-payload.ts +62 -39
- package/src/server/responses/fetch-helpers.ts +79 -4
- package/src/server/responses/input-admission.ts +185 -0
- package/src/server/responses/pacing-overload.ts +13 -0
- package/src/server/responses/policy-fallback.ts +178 -0
- package/src/server/responses/responses-field-backfill.ts +251 -0
- package/src/server/responses/terminal-guard.ts +26 -5
- package/src/server/responses/upstream-error.ts +5 -0
- package/src/server/responses/ws-upstream.ts +308 -0
- package/src/server/responses-custom-tool-repair.ts +282 -0
- package/src/server/responses-item-id-repair.ts +54 -6
- package/src/server/responses-json-events.ts +90 -0
- package/src/server/responses-model-rewrite.ts +29 -0
- package/src/server/responses-reasoning-summary-rewrite.ts +178 -0
- package/src/server/responses-snapshot-repair.ts +621 -0
- package/src/server/responses-terminal-repair.ts +342 -0
- package/src/server/responses-tool-search-repair.ts +267 -0
- package/src/server/responses-undeclared-tool-guard.ts +153 -0
- package/src/server/responses.ts +18 -2
- package/src/server/search.ts +78 -13
- package/src/server/sse-frame-buffer.ts +292 -0
- package/src/server/sse-payload-rewrite.ts +110 -22
- package/src/server/startup-action-control.ts +8 -1
- package/src/server/startup-health-cache.ts +19 -1
- package/src/server/system-env.ts +80 -9
- package/src/server/ws-bridge.ts +39 -38
- package/src/service-manager-probe.ts +892 -0
- package/src/service.ts +1111 -90
- package/src/sidecar/auth.ts +92 -0
- package/src/sidecar/candidates.ts +83 -0
- package/src/storage/cleanup.ts +2 -2
- package/src/storage/scanner.ts +1 -1
- package/src/storage/worker-lifecycle.ts +14 -14
- package/src/tray/windows-tray.ps1 +83 -9
- package/src/tray/windows.ts +43 -16
- package/src/types/accounts.ts +37 -0
- package/src/types/config.ts +845 -0
- package/src/types/provider.ts +545 -0
- package/src/types/request.ts +384 -0
- package/src/types/tools.ts +131 -0
- package/src/types/wire.ts +80 -0
- package/src/types.ts +104 -1236
- package/src/update/index.ts +32 -19
- package/src/update/job.ts +442 -67
- package/src/update/notify.ts +12 -6
- package/src/update/npm-cache-preflight.d.mts +47 -0
- package/src/update/npm-cache-preflight.mjs +201 -0
- package/src/update/transactional-install.d.mts +22 -0
- package/src/update/transactional-install.mjs +259 -0
- package/src/usage/cost.ts +0 -0
- package/src/usage/expected-prices.ts +268 -16
- package/src/usage/log.ts +606 -41
- package/src/usage/summary.ts +177 -9
- package/src/usage/user-cost-overlay-reconciler.ts +313 -0
- package/src/usage/user-cost-overlays.ts +314 -0
- package/src/vision/anthropic-describe.ts +10 -6
- package/src/vision/backends.ts +97 -0
- package/src/vision/describe.ts +9 -3
- package/src/vision/eligibility.ts +250 -0
- package/src/vision/index.ts +238 -24
- package/src/vision/reasoning.ts +55 -0
- package/src/vision/routed-describe.ts +175 -0
- package/src/vision/timeout-bounds.ts +9 -0
- package/src/web-search/anthropic-executor.ts +13 -7
- package/src/web-search/backends.ts +108 -0
- package/src/web-search/exa-executor.ts +88 -0
- package/src/web-search/executor.ts +11 -3
- package/src/web-search/gemini-executor.ts +141 -0
- package/src/web-search/index.ts +150 -15
- package/src/web-search/loop.ts +279 -50
- package/src/web-search/parse.ts +125 -30
- package/src/web-search/sources.ts +60 -0
- package/src/web-search/xai-executor.ts +219 -0
- package/gui/dist/assets/index-DTpMHS4F.js +0 -67
- package/gui/dist/assets/index-ZNVDE3C7.css +0 -1
- package/gui/dist/provider-icons/antigravity.svg +0 -1
- package/gui/dist/provider-icons/claude.svg +0 -1
- package/gui/dist/provider-icons/copilot.svg +0 -1
- package/gui/dist/provider-icons/cursor.svg +0 -2
- package/gui/dist/provider-icons/gemini.svg +0 -1
- package/gui/dist/provider-icons/grok-color.svg +0 -1
- package/gui/dist/provider-icons/kiro.svg +0 -14
- package/src/cli/internal-dispatch.ts +0 -20
|
@@ -29,8 +29,48 @@ function readInputModalities(raw: unknown): { values?: string[]; error?: string
|
|
|
29
29
|
}
|
|
30
30
|
return { values: raw as string[] };
|
|
31
31
|
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Custom-row reasoning ladder. Labels are validated against the Codex ladder (low..ultra)
|
|
35
|
+
* exactly like provider `modelReasoningEfforts` values; unknown labels would otherwise
|
|
36
|
+
* surface in a catalog the upstream never accepts. An empty array is meaningful (explicit
|
|
37
|
+
* "no reasoning" hides the effort control) and must be preserved, not cleared.
|
|
38
|
+
*/
|
|
39
|
+
function readReasoningEfforts(raw: unknown): { values?: string[]; error?: string } {
|
|
40
|
+
if (raw === undefined) return {};
|
|
41
|
+
if (!Array.isArray(raw)) return { error: "reasoningEfforts must be an array" };
|
|
42
|
+
const rejected: string[] = [];
|
|
43
|
+
const values: string[] = [];
|
|
44
|
+
for (const value of raw) {
|
|
45
|
+
if (typeof value !== "string") return { error: "reasoningEfforts must contain only strings" };
|
|
46
|
+
if (!isDeclaredReasoningEffort(value)) { rejected.push(value); continue; }
|
|
47
|
+
if (!values.includes(value)) values.push(value);
|
|
48
|
+
}
|
|
49
|
+
if (rejected.length > 0) {
|
|
50
|
+
return { error: `unsupported reasoning effort: ${rejected.join(", ")} (allowed: none, minimal, low, medium, high, xhigh, max, ultra)` };
|
|
51
|
+
}
|
|
52
|
+
// Canonical order: the catalog writes supported_reasoning_levels in input order and the
|
|
53
|
+
// fallback default picks the first entry, so a caller-chosen order must not leak through.
|
|
54
|
+
return { values: canonicalizeReasoningEfforts(values) };
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Default effort must be a ladder member that the declared ladder actually includes. */
|
|
58
|
+
function readDefaultReasoningEffort(raw: unknown, efforts: string[] | undefined): { value?: string; error?: string } {
|
|
59
|
+
if (raw === undefined) return {};
|
|
60
|
+
if (raw === null) return { value: undefined };
|
|
61
|
+
if (typeof raw !== "string" || !isDeclaredReasoningEffort(raw)) {
|
|
62
|
+
return { error: "defaultReasoningEffort must be one of: none, minimal, low, medium, high, xhigh, max, ultra" };
|
|
63
|
+
}
|
|
64
|
+
if (efforts === undefined || efforts.length === 0) {
|
|
65
|
+
return { error: "defaultReasoningEffort requires a non-empty reasoningEfforts ladder" };
|
|
66
|
+
}
|
|
67
|
+
if (!efforts.includes(raw)) {
|
|
68
|
+
return { error: `defaultReasoningEffort "${raw}" is not in the declared reasoningEfforts ladder` };
|
|
69
|
+
}
|
|
70
|
+
return { value: raw };
|
|
71
|
+
}
|
|
32
72
|
import type { CatalogModel } from "../../codex/catalog";
|
|
33
|
-
import { catalogModelSlug, disabledNativeSlugs, invalidateCodexModelsCache, nativeModelRows, uniqueCatalogModelsForPublicList } from "../../codex/catalog";
|
|
73
|
+
import { accountBoundNativeOpenAiSlugsBySelector, catalogModelSlug, configuredNativeAliasSlugs, disabledNativeSlugs, invalidateCodexModelsCache, nativeModelRows, shouldIncludeAccountBoundNativeOpenAi, uniqueCatalogModelsForPublicList } from "../../codex/catalog";
|
|
34
74
|
import { CatalogGatherBusyError } from "../../codex/catalog/provider-fetch";
|
|
35
75
|
import { getProviderLiveModelCount } from "../../codex/model-cache";
|
|
36
76
|
import {
|
|
@@ -57,8 +97,9 @@ import { providerDestinationResolvedError } from "../../lib/destination-policy";
|
|
|
57
97
|
import { enrichProviderFromCatalog, listKeyLoginProviders } from "../../oauth/key-providers";
|
|
58
98
|
import { deriveProviderPresets } from "../../providers/derive";
|
|
59
99
|
import { providerCodexAccountMode } from "../../providers/registry";
|
|
60
|
-
import { routedSlug, slugEquals } from "../../providers/slug-codec";
|
|
61
|
-
import {
|
|
100
|
+
import { encodedModelIdCollides, routedSlug, slugEquals } from "../../providers/slug-codec";
|
|
101
|
+
import { knownModelIdsForProvider } from "../../router";
|
|
102
|
+
import { COMBO_NAMESPACE, comboDisabledModelSelectors, comboModelId, preservesPhysicalComboProvider } from "../../combos";
|
|
62
103
|
import { clearProviderQuotaCache, fetchProviderQuotaReports } from "../../providers/quota";
|
|
63
104
|
import { isCanonicalOpenAiForwardProvider } from "../../providers/openai-tiers";
|
|
64
105
|
import { clearThreadAccountMap } from "../../codex/routing";
|
|
@@ -71,6 +112,7 @@ import { parseRange, parseUsageSurface, summarizeUsage } from "../../usage/summa
|
|
|
71
112
|
import { stripCodexRuntimeProviderFields } from "../../codex/auth-context";
|
|
72
113
|
import { getProviderRegistryEntry } from "../../providers/registry";
|
|
73
114
|
import { getDebugLogEntries } from "../../lib/debug-log-buffer";
|
|
115
|
+
import { canonicalizeReasoningEfforts, isDeclaredReasoningEffort } from "../../reasoning-effort";
|
|
74
116
|
import { getInjectionDebugLogEntries } from "../../lib/injection-debug-log";
|
|
75
117
|
import {
|
|
76
118
|
clearDebugSettings,
|
|
@@ -87,10 +129,11 @@ import type { PersistedUsageAttempt } from "../../usage/log";
|
|
|
87
129
|
import { isAllowedRequestOrigin, jsonResponse, providerManagementConfigError, publicProviderBaseUrl, safeConfigDTO, corsHeaders } from "../auth-cors";
|
|
88
130
|
import { applySystemEnvToggle } from "../system-env";
|
|
89
131
|
import {
|
|
132
|
+
ClientPathError,
|
|
90
133
|
EXPORT_CLIENTS,
|
|
91
134
|
EXPORT_CLIENT_IDS,
|
|
92
135
|
OPENCODE_PROVIDER_ID,
|
|
93
|
-
|
|
136
|
+
buildClientConfigText,
|
|
94
137
|
isExportClientId,
|
|
95
138
|
opencodeProxyBaseUrl,
|
|
96
139
|
} from "../../clients/config-export";
|
|
@@ -104,93 +147,9 @@ import type {
|
|
|
104
147
|
import { isPlainRecord, parseDebugLogQuery, tokPerSecondResult, unavailableCostReason, costResult, requestLogDto, stripRegistryOnlyStaticHeaders, fetchAllModels } from "./shared";
|
|
105
148
|
import type { MetricUnavailableReason, TokPerSecondResult, CostEstimateReason, CostResult, MetricSource } from "./shared";
|
|
106
149
|
import type { ManagementContext } from "./context";
|
|
150
|
+
import { listManagementModelRows, loadExportModels } from "./model-rows";
|
|
107
151
|
import { readManagementJsonBody, rethrowManagementBodyTooLarge } from "./body";
|
|
108
152
|
|
|
109
|
-
/**
|
|
110
|
-
* One row of the `/api/models` list. Routed rows spread a `CatalogModel`, so the shape is
|
|
111
|
-
* that model plus the identity/visibility fields this boundary computes for every row
|
|
112
|
-
* regardless of source. `disabled` is always present; the rest vary by row origin.
|
|
113
|
-
*/
|
|
114
|
-
type ManagementModelRow = Partial<CatalogModel> & {
|
|
115
|
-
provider: string;
|
|
116
|
-
id: string;
|
|
117
|
-
namespaced: string;
|
|
118
|
-
disabled: boolean;
|
|
119
|
-
native?: boolean;
|
|
120
|
-
custom?: boolean;
|
|
121
|
-
customId?: string;
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* The exact row list `/api/models` returns. Extracted so `/api/client-config` exports the
|
|
126
|
-
* models the GUI's Models tab shows — including this function's `disabled` computation,
|
|
127
|
-
* which the export core (src/clients/config-export.ts) deliberately does not perform.
|
|
128
|
-
*/
|
|
129
|
-
async function listManagementModelRows(config: OcxConfig): Promise<ManagementModelRow[]> {
|
|
130
|
-
const models = await fetchAllModels(config);
|
|
131
|
-
const disabled = new Set(config.disabledModels ?? []);
|
|
132
|
-
// Native GPT passthrough rows lead (provider "openai", bare-slug namespaced ids): sourced
|
|
133
|
-
// from the static supported set so a disabled model stays listed and re-enableable.
|
|
134
|
-
const native: ManagementModelRow[] = nativeModelRows(config).map(row => ({
|
|
135
|
-
provider: "openai",
|
|
136
|
-
id: row.slug,
|
|
137
|
-
namespaced: row.slug,
|
|
138
|
-
disabled: row.disabled,
|
|
139
|
-
native: true,
|
|
140
|
-
...(row.contextWindow !== undefined ? { contextWindow: row.contextWindow } : {}),
|
|
141
|
-
}));
|
|
142
|
-
const customModels: ManagementModelRow[] = (config.customModels ?? []).map(cm => {
|
|
143
|
-
const namespaced = routedSlug(cm.provider, cm.modelId);
|
|
144
|
-
return {
|
|
145
|
-
provider: cm.provider,
|
|
146
|
-
id: cm.modelId,
|
|
147
|
-
namespaced,
|
|
148
|
-
disabled: [...disabled].some(stored => slugEquals(stored, cm.provider, cm.modelId)),
|
|
149
|
-
custom: true,
|
|
150
|
-
customId: cm.id,
|
|
151
|
-
displayName: cm.displayName,
|
|
152
|
-
...(cm.contextWindow ? { contextWindow: cm.contextWindow } : {}),
|
|
153
|
-
...(cm.inputModalities ? { inputModalities: cm.inputModalities } : {}),
|
|
154
|
-
};
|
|
155
|
-
});
|
|
156
|
-
const publicModels = uniqueCatalogModelsForPublicList(models);
|
|
157
|
-
const comboNamespaced = new Set(
|
|
158
|
-
publicModels.filter(model => model.provider === "combo").map(catalogModelSlug),
|
|
159
|
-
);
|
|
160
|
-
const visibleCustomModels = customModels.filter(model => !comboNamespaced.has(model.namespaced));
|
|
161
|
-
// Custom metadata wins when a physical live/static row resolves to the same Codex-facing
|
|
162
|
-
// slug, while a combo keeps the same precedence it has in routing and /v1/models.
|
|
163
|
-
const customNamespaced = new Set(visibleCustomModels.map(c => c.namespaced));
|
|
164
|
-
const dedupedRouted = publicModels.map((m): ManagementModelRow | null => {
|
|
165
|
-
// Codex-facing slug (one "/", slug-codec); disabledModels compares tolerate both forms.
|
|
166
|
-
const namespaced = catalogModelSlug(m);
|
|
167
|
-
if (m.provider !== "combo" && customNamespaced.has(namespaced)) return null;
|
|
168
|
-
const contextCap = providerContextCap(config, m.provider);
|
|
169
|
-
return {
|
|
170
|
-
...m,
|
|
171
|
-
namespaced,
|
|
172
|
-
disabled: [...disabled].some(stored => (
|
|
173
|
-
stored === namespaced || slugEquals(stored, m.provider, m.id)
|
|
174
|
-
)),
|
|
175
|
-
...(contextCap !== undefined ? { contextCap, contextCapped: m.contextCapped === true } : {}),
|
|
176
|
-
};
|
|
177
|
-
}).filter((row): row is ManagementModelRow => row !== null);
|
|
178
|
-
return [...native, ...dedupedRouted, ...visibleCustomModels];
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/** `/api/models` row → the narrower input the client-config serializers accept. */
|
|
182
|
-
function toExportModel(row: ManagementModelRow): ExportModel {
|
|
183
|
-
return {
|
|
184
|
-
namespaced: row.namespaced,
|
|
185
|
-
provider: row.provider,
|
|
186
|
-
id: row.id,
|
|
187
|
-
...(row.native ? { native: true } : {}),
|
|
188
|
-
...(row.displayName ? { displayName: row.displayName } : {}),
|
|
189
|
-
...(row.contextWindow !== undefined ? { contextWindow: row.contextWindow } : {}),
|
|
190
|
-
...(row.inputModalities ? { inputModalities: row.inputModalities } : {}),
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
|
|
194
153
|
/**
|
|
195
154
|
* Counts read back off the SERIALIZED document rather than recomputed from the input rows.
|
|
196
155
|
* `modelsWithoutLimits` drives a GUI line claiming "these models ship without limits", so it
|
|
@@ -198,17 +157,14 @@ function toExportModel(row: ManagementModelRow): ExportModel {
|
|
|
198
157
|
* core's "authoritative context window" rule would be free to drift from it silently.
|
|
199
158
|
*/
|
|
200
159
|
function summarizeExportedModels(client: ExportClientId, document: unknown): { modelCount: number; modelsWithoutLimits: number } {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
}
|
|
206
|
-
const models = (document as PiGeneratedConfig).providers[OPENCODE_PROVIDER_ID].models;
|
|
207
|
-
return { modelCount: models.length, modelsWithoutLimits: models.filter(entry => entry.contextWindow === undefined).length };
|
|
160
|
+
// Each client counts its own document shape. The previous branch assumed
|
|
161
|
+
// "anything that is not OpenCode must be Pi", which silently misread the
|
|
162
|
+
// moment a third client existed.
|
|
163
|
+
return EXPORT_CLIENTS[client].summarize(document);
|
|
208
164
|
}
|
|
209
165
|
|
|
210
166
|
export async function handleModelRoutes(ctx: ManagementContext): Promise<Response | null> {
|
|
211
|
-
const { req, url, config, deps,
|
|
167
|
+
const { req, url, config, deps, convergeCodexCatalog, syncClaudeAgentDefsBestEffort } = ctx;
|
|
212
168
|
// A handler persists the exact config object passed in. Production defaults to
|
|
213
169
|
// the real store; tests that pass an in-memory fixture inject a no-op/spy. Do not
|
|
214
170
|
// bypass this seam with a dynamic config import — doing so replaced a user's
|
|
@@ -249,9 +205,33 @@ export async function handleModelRoutes(ctx: ManagementContext): Promise<Respons
|
|
|
249
205
|
);
|
|
250
206
|
}
|
|
251
207
|
const spec = EXPORT_CLIENTS[requested];
|
|
252
|
-
|
|
208
|
+
// Resolved before the catalog load on purpose. A refused override is a
|
|
209
|
+
// property of the request, not of the catalog: validating it afterwards
|
|
210
|
+
// let a busy or failing catalog answer 503 first, so a user with a
|
|
211
|
+
// relative override never saw the message that says how to fix it — and
|
|
212
|
+
// the route did the enumeration work anyway for input it was going to
|
|
213
|
+
// reject.
|
|
214
|
+
let destination: string;
|
|
253
215
|
try {
|
|
254
|
-
|
|
216
|
+
destination = spec.destination(process.env);
|
|
217
|
+
} catch (error) {
|
|
218
|
+
// A client's own environment override can name a path the resolver
|
|
219
|
+
// refuses — a relative value, which this process and the client would
|
|
220
|
+
// resolve against different working directories. That is a
|
|
221
|
+
// user-correctable configuration error, not a server fault, so it leaves
|
|
222
|
+
// this boundary as a bounded 400 instead of escaping handleManagementAPI
|
|
223
|
+
// as a generic 500 and stripping the message that says how to fix it.
|
|
224
|
+
// `integrations/state.ts` and `integrations/writer.ts` already catch the
|
|
225
|
+
// same error on their paths; this route was the one that did not.
|
|
226
|
+
if (!(error instanceof ClientPathError)) throw error;
|
|
227
|
+
return jsonResponse({ error: error.message }, 400, req, config);
|
|
228
|
+
}
|
|
229
|
+
let models: ExportModel[];
|
|
230
|
+
try {
|
|
231
|
+
// The ONE loader every export surface uses. It carries the visibility
|
|
232
|
+
// filter with it, so this route and the integration routes cannot end up
|
|
233
|
+
// telling a client about different models.
|
|
234
|
+
models = await loadExportModels(config);
|
|
255
235
|
} catch (error) {
|
|
256
236
|
// A partial or empty `models` block reads as a valid config while offering nothing,
|
|
257
237
|
// so a catalog failure is surfaced as unavailable rather than serialized. The
|
|
@@ -264,21 +244,24 @@ export async function handleModelRoutes(ctx: ManagementContext): Promise<Respons
|
|
|
264
244
|
config,
|
|
265
245
|
);
|
|
266
246
|
}
|
|
267
|
-
|
|
268
|
-
// user disabled in the Models tab is absent from /v1/models, so exporting it would hand the
|
|
269
|
-
// client a selector the proxy refuses to route.
|
|
270
|
-
const models = rows.filter(row => !row.disabled).map(toExportModel);
|
|
271
|
-
const document = buildClientConfig(requested, {
|
|
247
|
+
const built = buildClientConfigText(requested, {
|
|
272
248
|
baseUrl: opencodeProxyBaseUrl(Number(url.port) || config.port, config.hostname),
|
|
273
249
|
models,
|
|
274
250
|
config,
|
|
275
251
|
});
|
|
252
|
+
const document = built.document;
|
|
276
253
|
return jsonResponse({
|
|
277
254
|
client: spec.id,
|
|
278
255
|
filename: spec.filename,
|
|
279
|
-
destination
|
|
256
|
+
destination,
|
|
280
257
|
apiKeyEnv: spec.apiKeyEnv,
|
|
281
258
|
exportHint: spec.exportHint,
|
|
259
|
+
// The client's own format and the exact bytes for it. The GUI previously
|
|
260
|
+
// re-serialized `config` as JSON, which is wrong for four of the six
|
|
261
|
+
// clients; `mediaType` also drives the download blob.
|
|
262
|
+
format: built.format,
|
|
263
|
+
mediaType: built.mediaType,
|
|
264
|
+
text: built.text,
|
|
282
265
|
...summarizeExportedModels(requested, document),
|
|
283
266
|
config: document,
|
|
284
267
|
}, 200, req, config);
|
|
@@ -292,8 +275,8 @@ export async function handleModelRoutes(ctx: ManagementContext): Promise<Respons
|
|
|
292
275
|
const disabled = Array.isArray(body.models) ? body.models.filter((m): m is string => typeof m === "string") : [];
|
|
293
276
|
config.disabledModels = disabled;
|
|
294
277
|
persistConfig(config);
|
|
295
|
-
await
|
|
296
|
-
return jsonResponse({ ok: true, disabled });
|
|
278
|
+
const catalogRefresh = await convergeCodexCatalog();
|
|
279
|
+
return jsonResponse({ ok: true, disabled, catalogRefresh });
|
|
297
280
|
}
|
|
298
281
|
|
|
299
282
|
// One user-facing visibility switch spans two persisted filters: a provider allowlist and the
|
|
@@ -315,7 +298,14 @@ export async function handleModelRoutes(ctx: ManagementContext): Promise<Respons
|
|
|
315
298
|
if (!providerConfig && provider !== "openai" && !isVirtualComboNamespace) {
|
|
316
299
|
return jsonResponse({ error: "unknown model visibility provider" }, 400);
|
|
317
300
|
}
|
|
318
|
-
const
|
|
301
|
+
const accountNativeQualified = shouldIncludeAccountBoundNativeOpenAi(config)
|
|
302
|
+
? [...accountBoundNativeOpenAiSlugsBySelector(config).entries()].flatMap(([selector, slugs]) =>
|
|
303
|
+
slugs.filter(slug => !nativeModelRows(config).some(row => row.slug === slug)).map(slug => `${selector}/${slug}`))
|
|
304
|
+
: [];
|
|
305
|
+
const supportedNative = new Set([
|
|
306
|
+
...nativeModelRows(config).map(row => row.slug),
|
|
307
|
+
...accountNativeQualified,
|
|
308
|
+
]);
|
|
319
309
|
const targets: Array<{ id: string; native: boolean }> = [];
|
|
320
310
|
const seen = new Set<string>();
|
|
321
311
|
for (const value of body.targets) {
|
|
@@ -336,17 +326,16 @@ export async function handleModelRoutes(ctx: ManagementContext): Promise<Respons
|
|
|
336
326
|
if (targets.length === 0) return jsonResponse({ error: "model visibility targets required" }, 400);
|
|
337
327
|
|
|
338
328
|
const knownComboSelectors = new Set(
|
|
339
|
-
Object.entries(config.combos ?? {}).flatMap(([id, combo]) =>
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
]),
|
|
329
|
+
Object.entries(config.combos ?? {}).flatMap(([id, combo]) => (
|
|
330
|
+
comboDisabledModelSelectors(id, combo)
|
|
331
|
+
)),
|
|
343
332
|
);
|
|
344
333
|
const targetComboSelectors = new Map<string, Set<string>>();
|
|
345
334
|
if (isVirtualComboNamespace) {
|
|
346
335
|
for (const target of targets) {
|
|
347
336
|
const combo = config.combos && Object.hasOwn(config.combos, target.id) ? config.combos[target.id] : undefined;
|
|
348
337
|
if (!combo) return jsonResponse({ error: "invalid model visibility target" }, 400);
|
|
349
|
-
targetComboSelectors.set(target.id, new Set(
|
|
338
|
+
targetComboSelectors.set(target.id, new Set(comboDisabledModelSelectors(target.id, combo)));
|
|
350
339
|
}
|
|
351
340
|
}
|
|
352
341
|
const matchesTarget = (stored: string, target: { id: string; native: boolean }) => target.native
|
|
@@ -365,9 +354,14 @@ export async function handleModelRoutes(ctx: ManagementContext): Promise<Respons
|
|
|
365
354
|
const nativeIds = provider === "openai"
|
|
366
355
|
? disabledNativeSlugs({ disabledModels: disabled })
|
|
367
356
|
: new Set<string>();
|
|
357
|
+
const accountNativeIds = provider === "openai" ? new Set(accountNativeQualified) : new Set<string>();
|
|
358
|
+
const nativeAliasSlugs = provider === "openai"
|
|
359
|
+
? configuredNativeAliasSlugs(config)
|
|
360
|
+
: new Set<string>();
|
|
368
361
|
disabled = disabled.filter(stored => (
|
|
369
362
|
knownComboSelectors.has(stored)
|
|
370
|
-
||
|
|
363
|
+
|| nativeAliasSlugs.has(stored)
|
|
364
|
+
|| (!stored.startsWith(`${provider}/`) && !nativeIds.has(stored) && !accountNativeIds.has(stored))
|
|
371
365
|
));
|
|
372
366
|
}
|
|
373
367
|
} else {
|
|
@@ -391,8 +385,8 @@ export async function handleModelRoutes(ctx: ManagementContext): Promise<Respons
|
|
|
391
385
|
|
|
392
386
|
config.disabledModels = disabled;
|
|
393
387
|
persistConfig(config);
|
|
394
|
-
await
|
|
395
|
-
return jsonResponse({ ok: true, scope, provider, enabled: body.enabled, disabled });
|
|
388
|
+
const catalogRefresh = await convergeCodexCatalog();
|
|
389
|
+
return jsonResponse({ ok: true, scope, provider, enabled: body.enabled, disabled, catalogRefresh });
|
|
396
390
|
}
|
|
397
391
|
|
|
398
392
|
if (url.pathname === "/api/custom-models" && req.method === "GET") {
|
|
@@ -400,12 +394,11 @@ export async function handleModelRoutes(ctx: ManagementContext): Promise<Respons
|
|
|
400
394
|
}
|
|
401
395
|
|
|
402
396
|
if (url.pathname === "/api/custom-models" && req.method === "POST") {
|
|
403
|
-
let body: { provider?: unknown; modelId?: unknown; displayName?: unknown; contextWindow?: unknown; inputModalities?: unknown };
|
|
397
|
+
let body: { provider?: unknown; modelId?: unknown; displayName?: unknown; contextWindow?: unknown; inputModalities?: unknown; reasoningEfforts?: unknown; defaultReasoningEffort?: unknown };
|
|
404
398
|
try { body = await readManagementJsonBody(req); } catch (error) { rethrowManagementBodyTooLarge(error); return jsonResponse({ error: "invalid JSON body" }, 400); }
|
|
405
399
|
const provider = typeof body.provider === "string" ? body.provider.trim() : "";
|
|
406
400
|
const modelId = typeof body.modelId === "string" ? body.modelId.trim() : "";
|
|
407
401
|
if (!provider || !modelId) return jsonResponse({ error: "provider and modelId are required" }, 400);
|
|
408
|
-
if (modelId.includes("/")) return jsonResponse({ error: "modelId must not contain /" }, 400);
|
|
409
402
|
if (!isValidProviderName(provider)) return jsonResponse({ error: "invalid provider name" }, 400);
|
|
410
403
|
if (!hasOwnProvider(config.providers, provider)) return jsonResponse({ error: "provider not configured" }, 404);
|
|
411
404
|
const displayName = typeof body.displayName === "string" && body.displayName.trim() ? body.displayName.trim() : undefined;
|
|
@@ -414,11 +407,19 @@ export async function handleModelRoutes(ctx: ManagementContext): Promise<Respons
|
|
|
414
407
|
const modalities = readInputModalities(body.inputModalities);
|
|
415
408
|
if (modalities.error) return jsonResponse({ error: modalities.error }, 400);
|
|
416
409
|
const inputModalities = modalities.values;
|
|
410
|
+
const reasoning = readReasoningEfforts(body.reasoningEfforts);
|
|
411
|
+
if (reasoning.error) return jsonResponse({ error: reasoning.error }, 400);
|
|
412
|
+
const defaultEffort = readDefaultReasoningEffort(body.defaultReasoningEffort, reasoning.values);
|
|
413
|
+
if (defaultEffort.error) return jsonResponse({ error: defaultEffort.error }, 400);
|
|
417
414
|
const existing = config.customModels ?? [];
|
|
418
415
|
const newSlug = routedSlug(provider, modelId);
|
|
419
416
|
if (existing.some(cm => routedSlug(cm.provider, cm.modelId) === newSlug)) {
|
|
420
417
|
return jsonResponse({ error: "duplicate model" }, 409);
|
|
421
418
|
}
|
|
419
|
+
const known = knownModelIdsForProvider(provider, config.providers[provider], config);
|
|
420
|
+
if (encodedModelIdCollides(modelId, known)) {
|
|
421
|
+
return jsonResponse({ error: "ambiguous model id" }, 409);
|
|
422
|
+
}
|
|
422
423
|
const entry: OcxCustomModel = {
|
|
423
424
|
id: randomUUID(),
|
|
424
425
|
provider,
|
|
@@ -426,26 +427,27 @@ export async function handleModelRoutes(ctx: ManagementContext): Promise<Respons
|
|
|
426
427
|
...(displayName ? { displayName } : {}),
|
|
427
428
|
...(contextWindow ? { contextWindow } : {}),
|
|
428
429
|
...(inputModalities && inputModalities.length > 0 ? { inputModalities } : {}),
|
|
430
|
+
...(reasoning.values !== undefined ? { reasoningEfforts: reasoning.values } : {}),
|
|
431
|
+
...(defaultEffort.value ? { defaultReasoningEffort: defaultEffort.value } : {}),
|
|
429
432
|
addedAt: new Date().toISOString(),
|
|
430
433
|
};
|
|
431
434
|
config.customModels = [...existing, entry];
|
|
432
435
|
persistConfig(config);
|
|
433
|
-
await
|
|
434
|
-
return jsonResponse(entry, 201);
|
|
436
|
+
const catalogRefresh = await convergeCodexCatalog();
|
|
437
|
+
return jsonResponse({ ...entry, catalogRefresh }, 201);
|
|
435
438
|
}
|
|
436
439
|
|
|
437
440
|
const customPutMatch = url.pathname.match(/^\/api\/custom-models\/([^/]+)$/);
|
|
438
441
|
if (customPutMatch && req.method === "PUT") {
|
|
439
442
|
let id: string;
|
|
440
443
|
try { id = decodeURIComponent(customPutMatch[1]); } catch { return jsonResponse({ error: "invalid id encoding" }, 400); }
|
|
441
|
-
let body: { displayName?: unknown; contextWindow?: unknown; inputModalities?: unknown; modelId?: unknown };
|
|
444
|
+
let body: { displayName?: unknown; contextWindow?: unknown; inputModalities?: unknown; modelId?: unknown; reasoningEfforts?: unknown; defaultReasoningEffort?: unknown };
|
|
442
445
|
try { body = await readManagementJsonBody(req); } catch (error) { rethrowManagementBodyTooLarge(error); return jsonResponse({ error: "invalid JSON body" }, 400); }
|
|
443
446
|
const list = config.customModels ?? [];
|
|
444
447
|
const idx = list.findIndex(cm => cm.id === id);
|
|
445
448
|
if (idx === -1) return jsonResponse({ error: "not found" }, 404);
|
|
446
449
|
const cm = { ...list[idx] };
|
|
447
450
|
if (typeof body.modelId === "string" && body.modelId.trim()) {
|
|
448
|
-
if (body.modelId.includes("/")) return jsonResponse({ error: "modelId must not contain /" }, 400);
|
|
449
451
|
cm.modelId = body.modelId.trim();
|
|
450
452
|
}
|
|
451
453
|
if (body.displayName !== undefined) {
|
|
@@ -461,15 +463,48 @@ export async function handleModelRoutes(ctx: ManagementContext): Promise<Respons
|
|
|
461
463
|
if (edited.error) return jsonResponse({ error: edited.error }, 400);
|
|
462
464
|
cm.inputModalities = edited.values && edited.values.length > 0 ? edited.values : undefined;
|
|
463
465
|
}
|
|
466
|
+
// `null` clears the stored ladder back to "inherit from the provider row"; `[]` stays
|
|
467
|
+
// stored as an explicit "no reasoning" override. The default effort rides along and is
|
|
468
|
+
// validated against the ladder the row ends up with.
|
|
469
|
+
if (body.reasoningEfforts !== undefined) {
|
|
470
|
+
if (body.reasoningEfforts === null) {
|
|
471
|
+
cm.reasoningEfforts = undefined;
|
|
472
|
+
} else {
|
|
473
|
+
const edited = readReasoningEfforts(body.reasoningEfforts);
|
|
474
|
+
if (edited.error) return jsonResponse({ error: edited.error }, 400);
|
|
475
|
+
cm.reasoningEfforts = edited.values;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
if (body.defaultReasoningEffort !== undefined) {
|
|
479
|
+
const edited = readDefaultReasoningEffort(body.defaultReasoningEffort, cm.reasoningEfforts);
|
|
480
|
+
if (edited.error) return jsonResponse({ error: edited.error }, 400);
|
|
481
|
+
cm.defaultReasoningEffort = edited.value;
|
|
482
|
+
}
|
|
483
|
+
// Mirror of the POST invariant: a default only survives as a member of the final ladder.
|
|
484
|
+
// Without this, a ladder shrink/clear on a row that was created with a default leaves a
|
|
485
|
+
// stale default that re-applies itself onto the inherited ladder in the generated catalog
|
|
486
|
+
// (the GUI toggle-off path sends only reasoningEfforts, never the default).
|
|
487
|
+
if (cm.defaultReasoningEffort !== undefined) {
|
|
488
|
+
const ladder = cm.reasoningEfforts;
|
|
489
|
+
if (!ladder || ladder.length === 0 || !ladder.includes(cm.defaultReasoningEffort)) {
|
|
490
|
+
cm.defaultReasoningEffort = undefined;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
464
493
|
const updatedSlug = routedSlug(cm.provider, cm.modelId);
|
|
465
494
|
if (list.some((other, i) => i !== idx && routedSlug(other.provider, other.modelId) === updatedSlug)) {
|
|
466
495
|
return jsonResponse({ error: "duplicate model" }, 409);
|
|
467
496
|
}
|
|
497
|
+
const known = knownModelIdsForProvider(cm.provider, config.providers[cm.provider], {
|
|
498
|
+
customModels: list.filter((_, i) => i !== idx),
|
|
499
|
+
});
|
|
500
|
+
if (encodedModelIdCollides(cm.modelId, known)) {
|
|
501
|
+
return jsonResponse({ error: "ambiguous model id" }, 409);
|
|
502
|
+
}
|
|
468
503
|
list[idx] = cm;
|
|
469
504
|
config.customModels = list;
|
|
470
505
|
persistConfig(config);
|
|
471
|
-
await
|
|
472
|
-
return jsonResponse(cm);
|
|
506
|
+
const catalogRefresh = await convergeCodexCatalog();
|
|
507
|
+
return jsonResponse({ ...cm, catalogRefresh });
|
|
473
508
|
}
|
|
474
509
|
|
|
475
510
|
const customDelMatch = url.pathname.match(/^\/api\/custom-models\/([^/]+)$/);
|
|
@@ -482,15 +517,24 @@ export async function handleModelRoutes(ctx: ManagementContext): Promise<Respons
|
|
|
482
517
|
list.splice(idx, 1);
|
|
483
518
|
config.customModels = list.length > 0 ? list : undefined;
|
|
484
519
|
persistConfig(config);
|
|
485
|
-
await
|
|
486
|
-
return jsonResponse({ ok: true });
|
|
520
|
+
const catalogRefresh = await convergeCodexCatalog();
|
|
521
|
+
return jsonResponse({ ok: true, catalogRefresh });
|
|
487
522
|
}
|
|
488
523
|
|
|
489
524
|
// Per-provider catalog allowlist (issue #52): when a provider has a non-empty selectedModels list,
|
|
490
525
|
// only those ids ship to Codex's catalog / /v1/models. GET returns the CURRENT selection plus the
|
|
491
|
-
// FULL available set per provider
|
|
526
|
+
// FULL available set per provider for the management picker.
|
|
527
|
+
//
|
|
528
|
+
// `fetchAllModels` hides media-generation ids (image/video) from the Codex-facing catalog, but the
|
|
529
|
+
// Providers → Models tab must still list every id the user fetched and saved on the provider
|
|
530
|
+
// (e.g. grok2api's grok-imagine-*). Merge `providers[name].models` on top so those rows are not
|
|
531
|
+
// silently dropped after a successful refresh-models persist.
|
|
532
|
+
//
|
|
533
|
+
// Cold path: prefer cache/configured seeds so the Providers page paints in milliseconds instead
|
|
534
|
+
// of waiting on every upstream `/models` (often multi-second). When any live provider still needs
|
|
535
|
+
// a network probe, kick a background gather and set `refreshing: true` so the GUI can re-poll.
|
|
492
536
|
if (url.pathname === "/api/selected-models" && req.method === "GET") {
|
|
493
|
-
const models = await fetchAllModels(config);
|
|
537
|
+
const models = await fetchAllModels(config, { preferCached: true });
|
|
494
538
|
const available: Record<string, string[]> = {};
|
|
495
539
|
for (const m of models) (available[m.provider] ??= []).push(m.id);
|
|
496
540
|
const selected: Record<string, string[]> = {};
|
|
@@ -501,8 +545,22 @@ export async function handleModelRoutes(ctx: ManagementContext): Promise<Respons
|
|
|
501
545
|
if (Array.isArray(prov.selectedModels) && prov.selectedModels.length > 0) selected[name] = [...prov.selectedModels];
|
|
502
546
|
const liveCount = getProviderLiveModelCount(name);
|
|
503
547
|
if (liveCount !== undefined) liveModelCounts[name] = liveCount;
|
|
548
|
+
const configured = prov.models;
|
|
549
|
+
if (!Array.isArray(configured) || configured.length === 0) continue;
|
|
550
|
+
const bucket = available[name] ?? (available[name] = []);
|
|
551
|
+
const seen = new Set(bucket);
|
|
552
|
+
for (const id of configured) {
|
|
553
|
+
if (typeof id !== "string" || !id || seen.has(id)) continue;
|
|
554
|
+
seen.add(id);
|
|
555
|
+
bucket.push(id);
|
|
556
|
+
}
|
|
504
557
|
}
|
|
505
|
-
|
|
558
|
+
// Re-check after the local gather: preferCached may have kicked a background flight whose
|
|
559
|
+
// first probe already filled some caches, but `refreshing` still means "more work in flight
|
|
560
|
+
// or still needed" for the GUI re-poll loop.
|
|
561
|
+
const { catalogGatherNeedsLiveRefresh } = await import("../../codex/catalog");
|
|
562
|
+
const refreshing = catalogGatherNeedsLiveRefresh(config);
|
|
563
|
+
return jsonResponse({ selected, available, liveModelCounts, refreshing });
|
|
506
564
|
}
|
|
507
565
|
if (url.pathname === "/api/selected-models" && req.method === "PUT") {
|
|
508
566
|
let body: { provider?: unknown; models?: unknown };
|
|
@@ -518,8 +576,8 @@ export async function handleModelRoutes(ctx: ManagementContext): Promise<Respons
|
|
|
518
576
|
if (models.length > 0) config.providers[provider].selectedModels = models;
|
|
519
577
|
else delete config.providers[provider].selectedModels;
|
|
520
578
|
persistConfig(config);
|
|
521
|
-
await
|
|
522
|
-
return jsonResponse({ ok: true, provider, selected: models });
|
|
579
|
+
const catalogRefresh = await convergeCodexCatalog();
|
|
580
|
+
return jsonResponse({ ok: true, provider, selected: models, catalogRefresh });
|
|
523
581
|
}
|
|
524
582
|
return null;
|
|
525
583
|
}
|