@remodex/rmx 1.0.2
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 +91 -0
- package/LICENSE +21 -0
- package/README.md +242 -0
- package/assets/architecture.png +0 -0
- package/assets/banner.png +0 -0
- package/assets/claude-code-models.gif +0 -0
- package/assets/codex-app-picker.png +0 -0
- package/bin/ocx.mjs +584 -0
- package/bin/package-main.mjs +9 -0
- package/gui/dist/assets/index-CZqebSPQ.css +1 -0
- package/gui/dist/assets/index-CkETtt7P.js +71 -0
- package/gui/dist/favicon.png +0 -0
- package/gui/dist/fonts/google-sans-cyrillic.woff2 +0 -0
- package/gui/dist/fonts/google-sans-latin.woff2 +0 -0
- package/gui/dist/icons.svg +24 -0
- package/gui/dist/index.html +25 -0
- package/gui/dist/logo.png +0 -0
- package/gui/dist/provider-icons/alibaba-color.svg +1 -0
- package/gui/dist/provider-icons/antigravity-color.svg +1 -0
- package/gui/dist/provider-icons/claude-color.svg +1 -0
- package/gui/dist/provider-icons/cline-color.svg +16 -0
- package/gui/dist/provider-icons/cloudflare-ai-gateway-color.svg +1 -0
- package/gui/dist/provider-icons/commandcode-color.svg +1 -0
- package/gui/dist/provider-icons/copilot-color.svg +1 -0
- package/gui/dist/provider-icons/cursor-color.svg +2 -0
- package/gui/dist/provider-icons/deepseek-color.svg +1 -0
- package/gui/dist/provider-icons/discord.svg +1 -0
- package/gui/dist/provider-icons/firepass-color.svg +1 -0
- package/gui/dist/provider-icons/fireworks-color.svg +1 -0
- package/gui/dist/provider-icons/gemini-color.svg +1 -0
- package/gui/dist/provider-icons/github-copilot-color.svg +1 -0
- package/gui/dist/provider-icons/gitlab-duo-color.svg +1 -0
- package/gui/dist/provider-icons/grok.svg +1 -0
- package/gui/dist/provider-icons/groq-color.svg +1 -0
- package/gui/dist/provider-icons/huggingface-color.svg +1 -0
- package/gui/dist/provider-icons/kimi-color.svg +1 -0
- package/gui/dist/provider-icons/kiro-color.svg +15 -0
- package/gui/dist/provider-icons/lm-studio-color.svg +1 -0
- package/gui/dist/provider-icons/mistral-color.svg +1 -0
- package/gui/dist/provider-icons/moonshot-color.svg +1 -0
- package/gui/dist/provider-icons/nvidia-color.svg +1 -0
- package/gui/dist/provider-icons/ollama-color.svg +1 -0
- package/gui/dist/provider-icons/openai.svg +1 -0
- package/gui/dist/provider-icons/opencode.svg +2 -0
- package/gui/dist/provider-icons/openrouter-color.svg +1 -0
- package/gui/dist/provider-icons/pi.svg +21 -0
- package/gui/dist/provider-icons/qianfan-color.svg +1 -0
- package/gui/dist/provider-icons/qwen-portal-color.svg +1 -0
- package/gui/dist/provider-icons/telegram.svg +1 -0
- package/gui/dist/provider-icons/vercel-ai-gateway-color.svg +1 -0
- package/gui/dist/provider-icons/vllm-color.svg +1 -0
- package/gui/dist/provider-icons/xiaomi-color.svg +1 -0
- package/package.json +118 -0
- package/src/AGENTS.md +28 -0
- package/src/adapters/anthropic-image-guard.ts +251 -0
- package/src/adapters/anthropic-image-normalize.ts +518 -0
- package/src/adapters/anthropic.ts +1205 -0
- package/src/adapters/azure.ts +36 -0
- package/src/adapters/base.ts +83 -0
- package/src/adapters/client-fingerprint.ts +59 -0
- package/src/adapters/command-code.ts +453 -0
- package/src/adapters/cursor/arg-codec.ts +38 -0
- package/src/adapters/cursor/arg-normalize.ts +104 -0
- package/src/adapters/cursor/cursor-errors.ts +165 -0
- package/src/adapters/cursor/discovery.ts +276 -0
- package/src/adapters/cursor/effort-map.ts +139 -0
- package/src/adapters/cursor/exec-policy.ts +88 -0
- package/src/adapters/cursor/framing.ts +250 -0
- package/src/adapters/cursor/gen/agent_pb.ts +15274 -0
- package/src/adapters/cursor/kv-store.ts +52 -0
- package/src/adapters/cursor/live-models.ts +153 -0
- package/src/adapters/cursor/live-smoke-gate.ts +41 -0
- package/src/adapters/cursor/live-transport.ts +1235 -0
- package/src/adapters/cursor/mcp-config.ts +42 -0
- package/src/adapters/cursor/mcp-manager.ts +333 -0
- package/src/adapters/cursor/message-mapper.ts +49 -0
- package/src/adapters/cursor/native-exec-common.ts +59 -0
- package/src/adapters/cursor/native-exec-desktop.ts +184 -0
- package/src/adapters/cursor/native-exec-fs.ts +332 -0
- package/src/adapters/cursor/native-exec-mcp.ts +153 -0
- package/src/adapters/cursor/native-exec-network.ts +43 -0
- package/src/adapters/cursor/native-exec-shell.ts +548 -0
- package/src/adapters/cursor/native-exec-tools.ts +118 -0
- package/src/adapters/cursor/native-exec.ts +604 -0
- package/src/adapters/cursor/protobuf-events.ts +735 -0
- package/src/adapters/cursor/protobuf-request.ts +719 -0
- package/src/adapters/cursor/request-builder.ts +280 -0
- package/src/adapters/cursor/thread-continuity.ts +67 -0
- package/src/adapters/cursor/tool-definitions.ts +621 -0
- package/src/adapters/cursor/transport-retry.ts +132 -0
- package/src/adapters/cursor/transport.ts +57 -0
- package/src/adapters/cursor/types.ts +59 -0
- package/src/adapters/cursor.ts +196 -0
- package/src/adapters/google-antigravity-replay.ts +520 -0
- package/src/adapters/google-antigravity-wire.ts +140 -0
- package/src/adapters/google-errors.ts +85 -0
- package/src/adapters/google-http.ts +100 -0
- package/src/adapters/google-tool-schema.ts +173 -0
- package/src/adapters/google-truncation.ts +24 -0
- package/src/adapters/google-wire-compiler.ts +232 -0
- package/src/adapters/google.ts +859 -0
- package/src/adapters/identity.ts +77 -0
- package/src/adapters/image.ts +23 -0
- package/src/adapters/kiro-constants.ts +16 -0
- package/src/adapters/kiro-errors.ts +208 -0
- package/src/adapters/kiro-events.ts +197 -0
- package/src/adapters/kiro-images.ts +129 -0
- package/src/adapters/kiro-retry.ts +312 -0
- package/src/adapters/kiro-thinking.ts +104 -0
- package/src/adapters/kiro-tool-fallback.ts +36 -0
- package/src/adapters/kiro-tools.ts +224 -0
- package/src/adapters/kiro-truncation.ts +33 -0
- package/src/adapters/kiro-wire.ts +129 -0
- package/src/adapters/kiro.ts +1924 -0
- package/src/adapters/mimo-free.ts +263 -0
- package/src/adapters/openai-chat.ts +1265 -0
- package/src/adapters/openai-responses.ts +1309 -0
- package/src/adapters/run-turn-queue.ts +114 -0
- package/src/adapters/tool-catalog-nudge.ts +71 -0
- package/src/adapters/upstream-http-error.ts +48 -0
- package/src/android-remote/assets.ts +218 -0
- package/src/android-remote/attachments.ts +168 -0
- package/src/android-remote/auth.ts +237 -0
- package/src/android-remote/cloudflare-provisioning.ts +409 -0
- package/src/android-remote/cloudflare-secret.ts +106 -0
- package/src/android-remote/cloudflare-tunnel.ts +488 -0
- package/src/android-remote/cloudflared.ts +286 -0
- package/src/android-remote/codex-app-server.ts +565 -0
- package/src/android-remote/desktop-history-page.ts +936 -0
- package/src/android-remote/desktop-ipc.ts +3643 -0
- package/src/android-remote/desktop-ownership-store.ts +98 -0
- package/src/android-remote/desktop-project-registration.ts +129 -0
- package/src/android-remote/desktop-session-stream.ts +1110 -0
- package/src/android-remote/desktop-workspace-state.ts +443 -0
- package/src/android-remote/file-change-parser.ts +112 -0
- package/src/android-remote/gateway.ts +9108 -0
- package/src/android-remote/mutation-store.ts +299 -0
- package/src/android-remote/projection.ts +1780 -0
- package/src/android-remote/queued-turn-store.ts +248 -0
- package/src/android-remote/session-command-recovery.ts +1384 -0
- package/src/android-remote/store.ts +466 -0
- package/src/android-remote/thread-reconciliation.ts +133 -0
- package/src/android-remote/thread-source-paths.ts +307 -0
- package/src/android-remote/thread-stream.ts +546 -0
- package/src/android-remote/turn-activity.ts +235 -0
- package/src/android-remote/user-message-identity.ts +94 -0
- package/src/bridge.ts +1793 -0
- package/src/chat/inbound.ts +295 -0
- package/src/chat/outbound.ts +821 -0
- package/src/claude/agents-inject.ts +267 -0
- package/src/claude/alias.ts +149 -0
- package/src/claude/auth-detect.ts +229 -0
- package/src/claude/auth-mode-migration.ts +32 -0
- package/src/claude/auth-mode.ts +62 -0
- package/src/claude/context-windows.ts +189 -0
- package/src/claude/desktop-3p-guard.ts +35 -0
- package/src/claude/desktop-3p-paths.ts +84 -0
- package/src/claude/desktop-3p.ts +601 -0
- package/src/claude/desktop-health.ts +26 -0
- package/src/claude/desktop-profile.ts +263 -0
- package/src/claude/gateway-cache.ts +70 -0
- package/src/claude/inbound-debug.ts +163 -0
- package/src/claude/inbound.ts +519 -0
- package/src/claude/model-info.ts +154 -0
- package/src/claude/outbound.ts +898 -0
- package/src/cli/access.ts +108 -0
- package/src/cli/account-api.ts +296 -0
- package/src/cli/account-auth.ts +250 -0
- package/src/cli/account-catalog-refresh.ts +14 -0
- package/src/cli/account-extended.ts +476 -0
- package/src/cli/account-main.ts +317 -0
- package/src/cli/account.ts +297 -0
- package/src/cli/agent-driven.ts +70 -0
- package/src/cli/agent.ts +184 -0
- package/src/cli/catalog-prewarm.ts +27 -0
- package/src/cli/claude-desktop.ts +211 -0
- package/src/cli/claude.ts +302 -0
- package/src/cli/codex-shim-autorestore.ts +45 -0
- package/src/cli/codex-shim-readiness.ts +69 -0
- package/src/cli/combo.ts +124 -0
- package/src/cli/config-command.ts +183 -0
- package/src/cli/debug.ts +228 -0
- package/src/cli/desktop-first-run.ts +25 -0
- package/src/cli/doctor.ts +1022 -0
- package/src/cli/export-command.ts +201 -0
- package/src/cli/help.ts +370 -0
- package/src/cli/index.ts +1565 -0
- package/src/cli/init.ts +224 -0
- package/src/cli/integrations.ts +225 -0
- package/src/cli/interactive-confirm.ts +133 -0
- package/src/cli/internal-dispatch.ts +35 -0
- package/src/cli/launcher-context.ts +77 -0
- package/src/cli/models-runtime.ts +224 -0
- package/src/cli/models.ts +340 -0
- package/src/cli/observe.ts +170 -0
- package/src/cli/opencode.ts +587 -0
- package/src/cli/provider-runtime.ts +179 -0
- package/src/cli/provider.ts +476 -0
- package/src/cli/ready.ts +301 -0
- package/src/cli/route-policy.ts +92 -0
- package/src/cli/runtime-api.ts +328 -0
- package/src/cli/star-prompt.ts +211 -0
- package/src/cli/status-oauth.ts +78 -0
- package/src/cli/status.ts +321 -0
- package/src/cli/system-command.ts +196 -0
- package/src/cli/system-restart-client.ts +146 -0
- package/src/cli/tray-proxy.ts +205 -0
- package/src/cli/v2.ts +200 -0
- package/src/cli.ts +10 -0
- package/src/clients/config-export.ts +1109 -0
- package/src/codex/account-id.ts +34 -0
- package/src/codex/account-label.ts +34 -0
- package/src/codex/account-lifecycle.ts +172 -0
- package/src/codex/account-namespace-match.ts +63 -0
- package/src/codex/account-namespaces.ts +195 -0
- package/src/codex/account-pause.ts +20 -0
- package/src/codex/account-priority.ts +83 -0
- package/src/codex/account-runtime-state.ts +31 -0
- package/src/codex/account-store.ts +517 -0
- package/src/codex/account-usability.ts +40 -0
- package/src/codex/admission.ts +263 -0
- package/src/codex/app-server-processes.ts +799 -0
- package/src/codex/auth-api.ts +2098 -0
- package/src/codex/auth-collision.ts +107 -0
- package/src/codex/auth-context.ts +480 -0
- package/src/codex/autostart-health.ts +156 -0
- package/src/codex/catalog/account-models.ts +67 -0
- package/src/codex/catalog/aggregation.ts +471 -0
- package/src/codex/catalog/bundled.ts +533 -0
- package/src/codex/catalog/effort.ts +432 -0
- package/src/codex/catalog/filesystem-evidence.ts +302 -0
- package/src/codex/catalog/kinds.ts +2 -0
- package/src/codex/catalog/metadata.ts +287 -0
- package/src/codex/catalog/native-models.ts +7 -0
- package/src/codex/catalog/parsing.ts +503 -0
- package/src/codex/catalog/provider-fetch.ts +2267 -0
- package/src/codex/catalog/sync.ts +1606 -0
- package/src/codex/catalog-admission.ts +197 -0
- package/src/codex/catalog-refresh-status.ts +87 -0
- package/src/codex/catalog-write-serialization.ts +242 -0
- package/src/codex/catalog.ts +15 -0
- package/src/codex/codex-write-lock.ts +384 -0
- package/src/codex/convergence-types.ts +593 -0
- package/src/codex/convergence.ts +580 -0
- package/src/codex/custom-model-catalog-migration.ts +176 -0
- package/src/codex/data/upstream-models.json +830 -0
- package/src/codex/desired-state.ts +230 -0
- package/src/codex/desktop-client-processes.ts +521 -0
- package/src/codex/exec-invocation.ts +22 -0
- package/src/codex/features.ts +1091 -0
- package/src/codex/generation.ts +202 -0
- package/src/codex/history-job.ts +347 -0
- package/src/codex/history-lock.ts +242 -0
- package/src/codex/history-migration-guardian.ts +115 -0
- package/src/codex/history-provider.ts +1075 -0
- package/src/codex/history-transition.ts +105 -0
- package/src/codex/history-worker.ts +204 -0
- package/src/codex/home.ts +206 -0
- package/src/codex/inject-coordination.ts +257 -0
- package/src/codex/inject.ts +1857 -0
- package/src/codex/injected-marker.ts +79 -0
- package/src/codex/integration-record.ts +266 -0
- package/src/codex/internal/catalog-writer.ts +203 -0
- package/src/codex/internal/history-writer.ts +105 -0
- package/src/codex/journal.ts +172 -0
- package/src/codex/main-account-cache.ts +56 -0
- package/src/codex/main-account.ts +40 -0
- package/src/codex/management-convergence.ts +114 -0
- package/src/codex/model-cache.ts +267 -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 +167 -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 +348 -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 +691 -0
- package/src/codex/paths.ts +78 -0
- package/src/codex/plugins-doctor.ts +242 -0
- package/src/codex/pool-rotation.ts +295 -0
- package/src/codex/project-config-warnings.ts +426 -0
- package/src/codex/prompt-journal.ts +311 -0
- package/src/codex/prompt-layers.ts +967 -0
- package/src/codex/prompt-lock.ts +143 -0
- package/src/codex/provider-adoption.ts +242 -0
- package/src/codex/quota-rejection.ts +224 -0
- package/src/codex/quota.ts +494 -0
- package/src/codex/refresh.ts +60 -0
- package/src/codex/routing.ts +1855 -0
- package/src/codex/runtime.ts +659 -0
- package/src/codex/shim.ts +1215 -0
- package/src/codex/subagent-defaults.ts +557 -0
- package/src/codex/subagent-model-fallback.ts +560 -0
- package/src/codex/sync.ts +238 -0
- package/src/codex/transition-state.ts +612 -0
- package/src/codex/upstream-host-health.ts +368 -0
- package/src/codex/user-identity.ts +374 -0
- package/src/codex/warmup.ts +192 -0
- package/src/codex/websocket-registry.ts +100 -0
- package/src/codex/write-coordination.ts +114 -0
- package/src/combos/failover.ts +140 -0
- package/src/combos/index.ts +44 -0
- package/src/combos/request.ts +64 -0
- package/src/combos/resolve.ts +232 -0
- package/src/combos/types.ts +392 -0
- package/src/config.ts +3270 -0
- package/src/generated/model-metadata.ts +144 -0
- package/src/github/star-state.ts +203 -0
- package/src/grok/inject.ts +540 -0
- package/src/grok/inspect.ts +45 -0
- package/src/grok/status.ts +127 -0
- package/src/grok/sync.ts +66 -0
- package/src/images/artifacts.ts +516 -0
- package/src/images/fulfill-video.ts +163 -0
- package/src/images/fulfill.ts +149 -0
- package/src/images/index.ts +4 -0
- package/src/images/loop.ts +922 -0
- package/src/images/plan.ts +133 -0
- package/src/images/synthetic-tool.ts +133 -0
- package/src/images/types.ts +41 -0
- package/src/images/xai-client.ts +141 -0
- package/src/images/xai-video-client.ts +163 -0
- package/src/index.ts +22 -0
- package/src/integrations/config-io.ts +151 -0
- package/src/integrations/journal.ts +315 -0
- package/src/integrations/merge.ts +135 -0
- package/src/integrations/native/ownership-preflight.ts +202 -0
- package/src/integrations/ownership.ts +111 -0
- package/src/integrations/registry.ts +108 -0
- package/src/integrations/serialize.ts +235 -0
- package/src/integrations/state.ts +290 -0
- package/src/integrations/store.ts +103 -0
- package/src/integrations/writer.ts +492 -0
- package/src/lib/abort.ts +146 -0
- package/src/lib/admin-secrets.ts +25 -0
- package/src/lib/admission.ts +83 -0
- package/src/lib/app-owned-memory-stores.ts +173 -0
- package/src/lib/app-owned-memory.ts +265 -0
- package/src/lib/bounded-body.ts +242 -0
- package/src/lib/bun-binary-validator.d.mts +3 -0
- package/src/lib/bun-binary-validator.mjs +18 -0
- package/src/lib/bun-runtime.ts +184 -0
- package/src/lib/bun-stream-caps.ts +127 -0
- package/src/lib/config-ownership.ts +438 -0
- package/src/lib/crash-guard.ts +344 -0
- package/src/lib/debug-log-buffer.ts +83 -0
- package/src/lib/debug-settings.ts +108 -0
- package/src/lib/debug.ts +31 -0
- package/src/lib/destination-policy.ts +316 -0
- package/src/lib/errors.ts +364 -0
- package/src/lib/eventstream-decoder.ts +253 -0
- package/src/lib/gcp-adc.ts +341 -0
- package/src/lib/injection-debug-log.ts +58 -0
- package/src/lib/local-management-attestation.ts +51 -0
- package/src/lib/open-url.ts +25 -0
- package/src/lib/pinned-http.ts +182 -0
- package/src/lib/privacy.ts +20 -0
- package/src/lib/process-control.ts +168 -0
- package/src/lib/provider-environment.ts +470 -0
- package/src/lib/provider-outbound.ts +203 -0
- package/src/lib/provider-url.ts +14 -0
- package/src/lib/proxy-env.ts +18 -0
- package/src/lib/redact.ts +510 -0
- package/src/lib/remodex-home.ts +616 -0
- package/src/lib/retry-after.ts +55 -0
- package/src/lib/service-secrets.ts +178 -0
- package/src/lib/shadow-call.ts +54 -0
- package/src/lib/sidecar-tracker.ts +52 -0
- package/src/lib/sse-decoder.ts +364 -0
- package/src/lib/state-store-registrations.ts +109 -0
- package/src/lib/state-store-sweeper.ts +184 -0
- package/src/lib/system-restart-contract.ts +73 -0
- package/src/lib/test-home-guard.ts +98 -0
- package/src/lib/token-estimate.ts +69 -0
- package/src/lib/translator-budget.ts +366 -0
- package/src/lib/upstream-reachability.ts +91 -0
- package/src/lib/upstream-retry.ts +508 -0
- package/src/lib/win-exec.ts +115 -0
- package/src/lib/win-paths.ts +68 -0
- package/src/lib/windows-elevation.ts +705 -0
- package/src/lib/windows-secret-acl.ts +817 -0
- package/src/lib/windows-user-principal.ts +283 -0
- package/src/lib/winsw.ts +402 -0
- package/src/model-sources.ts +73 -0
- package/src/oauth/anthropic-routing.ts +594 -0
- package/src/oauth/anthropic.ts +177 -0
- package/src/oauth/callback-server.ts +294 -0
- package/src/oauth/chatgpt.ts +150 -0
- package/src/oauth/command-code.ts +239 -0
- package/src/oauth/cursor.ts +231 -0
- package/src/oauth/github-copilot.ts +428 -0
- package/src/oauth/google-antigravity.ts +230 -0
- package/src/oauth/health.ts +443 -0
- package/src/oauth/index.ts +1280 -0
- package/src/oauth/key-providers.ts +128 -0
- package/src/oauth/kimi.ts +213 -0
- package/src/oauth/kiro-credentials.ts +726 -0
- package/src/oauth/kiro.ts +621 -0
- package/src/oauth/local-token-detect.ts +121 -0
- package/src/oauth/log.ts +48 -0
- package/src/oauth/login-cli.ts +163 -0
- package/src/oauth/pkce.ts +15 -0
- package/src/oauth/store.ts +655 -0
- package/src/oauth/token-guardian.ts +309 -0
- package/src/oauth/types.ts +62 -0
- package/src/oauth/xai.ts +241 -0
- package/src/providers/alibaba-region-backup.ts +75 -0
- package/src/providers/alibaba-region-migration.ts +156 -0
- package/src/providers/alibaba-region-startup.ts +36 -0
- package/src/providers/antigravity-models.ts +317 -0
- package/src/providers/api-keys.ts +140 -0
- package/src/providers/base-url-choices.ts +64 -0
- package/src/providers/codex-capacity.ts +288 -0
- package/src/providers/command-code-efforts.ts +85 -0
- package/src/providers/context-cap.ts +73 -0
- package/src/providers/derive.ts +451 -0
- package/src/providers/free-directory.ts +187 -0
- package/src/providers/github-copilot-transport.ts +56 -0
- package/src/providers/google-vertex-location.ts +14 -0
- package/src/providers/key-failover.ts +271 -0
- package/src/providers/kiro-models.ts +67 -0
- package/src/providers/label.ts +19 -0
- package/src/providers/model-discovery-limits.ts +16 -0
- package/src/providers/model-discovery.ts +361 -0
- package/src/providers/openai-sidecar.ts +235 -0
- package/src/providers/openai-tier-startup.ts +27 -0
- package/src/providers/openai-tiers.ts +301 -0
- package/src/providers/openai-virtual-models.ts +83 -0
- package/src/providers/openrouter-routing.ts +102 -0
- package/src/providers/provider-id-rewrite.ts +179 -0
- package/src/providers/quota.ts +1942 -0
- package/src/providers/reasoning-capabilities.ts +336 -0
- package/src/providers/registry.ts +2375 -0
- package/src/providers/slug-codec.ts +74 -0
- package/src/providers/xai-transport.ts +149 -0
- package/src/reasoning-effort.ts +243 -0
- package/src/responses/compaction.ts +124 -0
- package/src/responses/hosted-tool-policy.ts +9 -0
- package/src/responses/parser.ts +714 -0
- package/src/responses/reasoning-envelope.ts +60 -0
- package/src/responses/reasoning-replay-cache.ts +106 -0
- package/src/responses/schema.ts +159 -0
- package/src/responses/spill-store.ts +431 -0
- package/src/responses/state.ts +1039 -0
- package/src/responses/tool-groups.ts +19 -0
- package/src/router.ts +802 -0
- package/src/routing/analytics.ts +377 -0
- package/src/routing/capability.ts +205 -0
- package/src/routing/cost.ts +77 -0
- package/src/routing/evaluator.ts +444 -0
- package/src/routing/health.ts +401 -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 +424 -0
- package/src/routing/quota.ts +145 -0
- package/src/routing/request-evidence.ts +45 -0
- package/src/routing/trace.ts +686 -0
- package/src/server/adapter-resolve.ts +83 -0
- package/src/server/auth-cors.ts +606 -0
- package/src/server/chat-completions.ts +379 -0
- package/src/server/claude-messages.ts +980 -0
- package/src/server/effort-policy.ts +251 -0
- package/src/server/github-copilot-responses-repair.ts +338 -0
- package/src/server/gui-static.ts +152 -0
- package/src/server/image-retry.ts +42 -0
- package/src/server/images.ts +485 -0
- package/src/server/index.ts +1633 -0
- package/src/server/lifecycle.ts +482 -0
- package/src/server/live.ts +609 -0
- package/src/server/management/agent-settings-routes.ts +1180 -0
- package/src/server/management/android-remote-routes.ts +390 -0
- package/src/server/management/api-access.ts +141 -0
- package/src/server/management/api-key-usage.ts +167 -0
- package/src/server/management/body.ts +35 -0
- package/src/server/management/combo-routes.ts +244 -0
- package/src/server/management/config-routes.ts +602 -0
- package/src/server/management/context.ts +88 -0
- package/src/server/management/integration-routes.ts +538 -0
- package/src/server/management/logs-usage-routes.ts +516 -0
- package/src/server/management/model-routes.ts +519 -0
- package/src/server/management/model-rows.ts +143 -0
- package/src/server/management/native-integration-routes.ts +781 -0
- package/src/server/management/oauth-account-routes.ts +573 -0
- package/src/server/management/provider-routes.ts +781 -0
- package/src/server/management/request-history-routes.ts +191 -0
- package/src/server/management/routing-analytics-routes.ts +74 -0
- package/src/server/management/routing-profile-routes.ts +384 -0
- package/src/server/management/shared.ts +277 -0
- package/src/server/management/sidebar-routes.ts +106 -0
- package/src/server/management/sync-response.ts +69 -0
- package/src/server/management/system-restart.ts +433 -0
- package/src/server/management/system-routes.ts +141 -0
- package/src/server/management/usage-summary-cache.ts +86 -0
- package/src/server/management-api.ts +269 -0
- package/src/server/management-auth.ts +353 -0
- package/src/server/memory-watchdog.ts +156 -0
- package/src/server/port-reclaim.ts +307 -0
- package/src/server/ports.ts +156 -0
- package/src/server/proxy-liveness.ts +326 -0
- package/src/server/proxy-stop.ts +92 -0
- package/src/server/readiness.ts +99 -0
- package/src/server/relay-eager.ts +353 -0
- package/src/server/relay.ts +1179 -0
- package/src/server/request-decompress.ts +132 -0
- package/src/server/request-log-conversation.ts +168 -0
- package/src/server/request-log.ts +1072 -0
- package/src/server/responses/collaboration.ts +409 -0
- package/src/server/responses/compact.ts +710 -0
- package/src/server/responses/core.ts +3561 -0
- package/src/server/responses/encrypted-payload.ts +308 -0
- package/src/server/responses/fetch-helpers.ts +171 -0
- package/src/server/responses/passthrough-error.ts +78 -0
- package/src/server/responses/policy-fallback.ts +152 -0
- package/src/server/responses/terminal-guard.ts +230 -0
- package/src/server/responses/upstream-error.ts +48 -0
- package/src/server/responses-image-gen-repair.ts +132 -0
- package/src/server/responses-item-id-repair.ts +272 -0
- package/src/server/responses-json-events.ts +52 -0
- package/src/server/responses-model-rewrite.ts +29 -0
- package/src/server/responses-snapshot-repair.ts +621 -0
- package/src/server/responses.ts +10 -0
- package/src/server/search.ts +181 -0
- package/src/server/sse-frame-buffer.ts +292 -0
- package/src/server/sse-payload-rewrite.ts +263 -0
- package/src/server/startup-action-control.ts +308 -0
- package/src/server/startup-health-cache.ts +119 -0
- package/src/server/system-env.ts +418 -0
- package/src/server/windows-tcp-drop.ts +184 -0
- package/src/server/windows-tray-control.ts +41 -0
- package/src/server/ws-bridge.ts +470 -0
- package/src/service-manager-probe.ts +824 -0
- package/src/service.ts +3011 -0
- package/src/stall-timeout.ts +20 -0
- package/src/storage/cleanup-job.ts +57 -0
- package/src/storage/cleanup.ts +3085 -0
- package/src/storage/policy-job.ts +457 -0
- package/src/storage/policy-scheduler.ts +40 -0
- package/src/storage/policy-worker.ts +59 -0
- package/src/storage/policy.ts +527 -0
- package/src/storage/restore-job.ts +299 -0
- package/src/storage/restore-worker.ts +58 -0
- package/src/storage/scanner.ts +238 -0
- package/src/storage/storage-mutation-coordinator.ts +139 -0
- package/src/storage/worker-lifecycle.ts +215 -0
- package/src/tray/assets/opencodex-tray-offline.ico +0 -0
- package/src/tray/assets/opencodex-tray-online.ico +0 -0
- package/src/tray/assets/opencodex-tray-warning.ico +0 -0
- package/src/tray/assets/opencodex-tray.png +0 -0
- package/src/tray/windows-tray.ps1 +364 -0
- package/src/tray/windows.ts +738 -0
- package/src/types.ts +1531 -0
- package/src/update/badge.ts +72 -0
- package/src/update/desktop-release.ts +1620 -0
- package/src/update/index.ts +402 -0
- package/src/update/job.ts +1906 -0
- package/src/update/notify.ts +261 -0
- package/src/update/npm-cache-preflight.d.mts +47 -0
- package/src/update/npm-cache-preflight.mjs +201 -0
- package/src/update/npm-invocation.d.mts +23 -0
- package/src/update/npm-invocation.mjs +94 -0
- package/src/update/tray-update-plan.d.mts +18 -0
- package/src/update/tray-update-plan.mjs +38 -0
- package/src/usage/cost.ts +0 -0
- package/src/usage/debug.ts +97 -0
- package/src/usage/expected-prices.ts +283 -0
- package/src/usage/log.ts +695 -0
- package/src/usage/summary.ts +585 -0
- package/src/usage/totals.ts +14 -0
- package/src/vision/anthropic-describe.ts +185 -0
- package/src/vision/describe.ts +127 -0
- package/src/vision/index.ts +558 -0
- package/src/vision/reasoning.ts +55 -0
- package/src/web-search/anthropic-executor.ts +189 -0
- package/src/web-search/executor.ts +105 -0
- package/src/web-search/format-result.ts +89 -0
- package/src/web-search/index.ts +196 -0
- package/src/web-search/loop.ts +791 -0
- package/src/web-search/parse.ts +235 -0
- package/src/web-search/progress-stream.ts +342 -0
- package/src/web-search/synthetic-tool.ts +47 -0
|
@@ -0,0 +1,2375 @@
|
|
|
1
|
+
import type { CodexAccountMode, OcxProviderConfig } from "../types";
|
|
2
|
+
import { KIRO_MODELS, KIRO_MODEL_CONTEXT_WINDOWS, KIRO_MODEL_REASONING_EFFORTS } from "./kiro-models";
|
|
3
|
+
import { ANTIGRAVITY_MODELS, ANTIGRAVITY_MODEL_CONTEXT_WINDOWS, ANTIGRAVITY_MODEL_EFFORTS, ANTIGRAVITY_MODEL_INPUT_MODALITIES } from "./antigravity-models";
|
|
4
|
+
import type { ProviderBaseUrlChoice } from "./base-url-choices";
|
|
5
|
+
import {
|
|
6
|
+
QWEN_CLOUD_BASE_URL_CHOICES, QWEN_CLOUD_TOKEN_PLAN_BASE_URL,
|
|
7
|
+
ALIBABA_INTL_BASE_URL_CHOICES, ALIBABA_INTL_TOKEN_PLAN_BASE_URL,
|
|
8
|
+
ALIBABA_CODING_BASE_URL_CHOICES, ALIBABA_CODING_INTL_BASE_URL,
|
|
9
|
+
} from "./base-url-choices";
|
|
10
|
+
import {
|
|
11
|
+
CURSOR_STATIC_MODELS,
|
|
12
|
+
cursorModelContextWindows,
|
|
13
|
+
cursorModelIds,
|
|
14
|
+
cursorModelInputModalities,
|
|
15
|
+
cursorModelReasoningEfforts,
|
|
16
|
+
} from "../adapters/cursor/discovery";
|
|
17
|
+
import { COMMAND_CODE_MODEL_REASONING_EFFORTS } from "./command-code-efforts";
|
|
18
|
+
|
|
19
|
+
export type ProviderAuthKind = "forward" | "oauth" | "key" | "local";
|
|
20
|
+
export type MetadataModelIdNormalize = "case-insensitive";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Wire protocol a client spoke when it reached the proxy. Chat and Anthropic surfaces
|
|
24
|
+
* translate into a Responses-shaped body and replay through `handleResponses`, so the
|
|
25
|
+
* original inbound has to travel with the request or the replay looks native.
|
|
26
|
+
*/
|
|
27
|
+
export type InboundWire = "responses" | "chat" | "anthropic";
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* A per-model wire default: a bare string applies to every inbound, while the object
|
|
31
|
+
* form applies only to the listed inbound protocols.
|
|
32
|
+
*/
|
|
33
|
+
export type ModelWireDefault = string | { wire: string; inbound: readonly InboundWire[] };
|
|
34
|
+
|
|
35
|
+
export type ProviderModelDiscoveryScalar = string | number | boolean;
|
|
36
|
+
|
|
37
|
+
export type ProviderModelDiscoveryPredicate =
|
|
38
|
+
| {
|
|
39
|
+
path: readonly string[];
|
|
40
|
+
equalsAny: readonly ProviderModelDiscoveryScalar[];
|
|
41
|
+
caseInsensitive?: boolean;
|
|
42
|
+
}
|
|
43
|
+
| {
|
|
44
|
+
path: readonly string[];
|
|
45
|
+
/**
|
|
46
|
+
* A string-valued upstream target uses substring matching; an array-valued target uses
|
|
47
|
+
* exact element matching. Use `equalsAny` when the string must match in full.
|
|
48
|
+
*/
|
|
49
|
+
containsAny: readonly ProviderModelDiscoveryScalar[];
|
|
50
|
+
caseInsensitive?: boolean;
|
|
51
|
+
}
|
|
52
|
+
| {
|
|
53
|
+
path: readonly string[];
|
|
54
|
+
/** Uses the same string-substring and array-element semantics as `containsAny`. */
|
|
55
|
+
containsAll: readonly ProviderModelDiscoveryScalar[];
|
|
56
|
+
caseInsensitive?: boolean;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export interface ProviderModelDiscoveryFilter {
|
|
60
|
+
/** Every predicate must match. */
|
|
61
|
+
allOf?: readonly ProviderModelDiscoveryPredicate[];
|
|
62
|
+
/** At least one predicate must match. */
|
|
63
|
+
anyOf?: readonly ProviderModelDiscoveryPredicate[];
|
|
64
|
+
/** No predicate may match. */
|
|
65
|
+
noneOf?: readonly ProviderModelDiscoveryPredicate[];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
interface ProviderModelDiscoverySharedSpec {
|
|
69
|
+
/** Query parameters applied to the resolved discovery URL. */
|
|
70
|
+
query?: Readonly<Record<string, string>>;
|
|
71
|
+
/** Declarative eligibility rules evaluated against each untrusted model row. */
|
|
72
|
+
filter?: ProviderModelDiscoveryFilter;
|
|
73
|
+
/** Optional lower byte ceiling; the process-wide hard ceiling still wins. */
|
|
74
|
+
maxResponseBytes?: number;
|
|
75
|
+
/** Optional lower raw-row ceiling; the process-wide hard ceiling still wins. */
|
|
76
|
+
maxModels?: number;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
type ProviderModelDiscoveryLocation =
|
|
80
|
+
| {
|
|
81
|
+
/** Registry-owned absolute endpoint. Mutually exclusive with `path`. */
|
|
82
|
+
url: string;
|
|
83
|
+
path?: never;
|
|
84
|
+
}
|
|
85
|
+
| {
|
|
86
|
+
/** Resource path relative to baseUrl; query strings and fragments are disallowed. */
|
|
87
|
+
path: string;
|
|
88
|
+
url?: never;
|
|
89
|
+
}
|
|
90
|
+
| {
|
|
91
|
+
/** Keep the adapter-derived default discovery endpoint. */
|
|
92
|
+
url?: never;
|
|
93
|
+
path?: never;
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Trusted live-model discovery policy. This metadata is registry-only: it must never be copied
|
|
98
|
+
* into config.json, where a same-named custom provider could otherwise redirect a stored key.
|
|
99
|
+
*/
|
|
100
|
+
export type ProviderModelDiscoverySpec = ProviderModelDiscoverySharedSpec & ProviderModelDiscoveryLocation;
|
|
101
|
+
|
|
102
|
+
export interface ProviderRegistryEntry {
|
|
103
|
+
id: string;
|
|
104
|
+
label: string;
|
|
105
|
+
adapter: string;
|
|
106
|
+
baseUrl: string;
|
|
107
|
+
apiKeyTransport?: OcxProviderConfig["apiKeyTransport"];
|
|
108
|
+
authKind: ProviderAuthKind;
|
|
109
|
+
codexAccountMode?: CodexAccountMode;
|
|
110
|
+
/** OAuth preset may explicitly honor a persisted API-key billing mode. */
|
|
111
|
+
allowKeyAuthOverride?: boolean;
|
|
112
|
+
allowPrivateNetworkByDefault?: boolean;
|
|
113
|
+
keyOptional?: boolean;
|
|
114
|
+
/**
|
|
115
|
+
* Registry-only key-login policy for public model catalogs that cannot authenticate a key.
|
|
116
|
+
* The dashboard flow then reports the key as unverifiable instead of a false positive.
|
|
117
|
+
*/
|
|
118
|
+
apiKeyValidation?: "unknown";
|
|
119
|
+
/**
|
|
120
|
+
* Free-tier pricing (no paid subscription required). Distinct from `keyOptional`:
|
|
121
|
+
* free tiers may still require an API key (e.g. NVIDIA NIM free credits).
|
|
122
|
+
*/
|
|
123
|
+
freeTier?: boolean;
|
|
124
|
+
allowBaseUrlOverride?: boolean;
|
|
125
|
+
/**
|
|
126
|
+
* Do not claim an existing same-named key provider whose fixed destination differs from this
|
|
127
|
+
* preset. Enable for newly promoted ids so an older custom key cannot be silently retargeted.
|
|
128
|
+
*/
|
|
129
|
+
preserveCustomDestination?: boolean;
|
|
130
|
+
/**
|
|
131
|
+
* Optional endpoint picker for providers with multiple official hosts
|
|
132
|
+
* (e.g. Qwen Cloud token plan vs pay-as-you-go). Requires `allowBaseUrlOverride`
|
|
133
|
+
* so the selected URL is honored at route time. A choice without `baseUrl` is "Custom".
|
|
134
|
+
*/
|
|
135
|
+
baseUrlChoices?: readonly ProviderBaseUrlChoice[];
|
|
136
|
+
/** Static headers merged into every upstream request for this provider. */
|
|
137
|
+
staticHeaders?: Record<string, string>;
|
|
138
|
+
modelSuffixBracketStrip?: boolean;
|
|
139
|
+
featured?: boolean;
|
|
140
|
+
dashboardPreset?: boolean;
|
|
141
|
+
note?: string;
|
|
142
|
+
dashboardUrl?: string;
|
|
143
|
+
defaultModel?: string;
|
|
144
|
+
models?: string[];
|
|
145
|
+
liveModels?: boolean;
|
|
146
|
+
/**
|
|
147
|
+
* Registry-only per-model wire defaults for mixed OpenAI-compatible gateways.
|
|
148
|
+
* These are intentionally not seeded into saved config: an explicit `modelAdapters`
|
|
149
|
+
* entry must remain distinguishable and must always win over a default.
|
|
150
|
+
*
|
|
151
|
+
* A bare string applies to every inbound protocol. The object form scopes the
|
|
152
|
+
* default to the inbound surfaces named in `inbound`, which is how a model that is
|
|
153
|
+
* native on two wires can serve each client on the wire it already speaks instead
|
|
154
|
+
* of paying a translation hop.
|
|
155
|
+
*/
|
|
156
|
+
modelWireDefaults?: Record<string, ModelWireDefault>;
|
|
157
|
+
/**
|
|
158
|
+
* Registry-only per-model override for the upstream request shape used behind a
|
|
159
|
+
* Codex Responses WebSocket turn. `false` keeps the client-facing WebSocket but
|
|
160
|
+
* asks the upstream Responses endpoint for bounded JSON, which the bridge then
|
|
161
|
+
* reframes as Responses events. Use only for upstreams whose streaming response
|
|
162
|
+
* can omit or indefinitely delay the terminal event.
|
|
163
|
+
*/
|
|
164
|
+
modelResponsesUpstreamStreaming?: Record<string, boolean>;
|
|
165
|
+
/**
|
|
166
|
+
* Registry-only pre-stream recovery for provider edges that can intermittently
|
|
167
|
+
* return a non-JSON error page under an otherwise deterministic HTTP status.
|
|
168
|
+
* Valid JSON errors are never retried. Fixed-destination matching is required
|
|
169
|
+
* before this capability is applied.
|
|
170
|
+
*/
|
|
171
|
+
preStreamNonJsonRetryStatuses?: readonly number[];
|
|
172
|
+
/**
|
|
173
|
+
* Registry-only client-facing item-id repair policy (#938), filled onto the
|
|
174
|
+
* runtime provider only when the user has no explicit policy (derive.ts);
|
|
175
|
+
* never seeded into saved config.
|
|
176
|
+
*/
|
|
177
|
+
responsesItemIdRepair?: {
|
|
178
|
+
message?: string[];
|
|
179
|
+
reasoning?: string[];
|
|
180
|
+
repairMissingTerminalIds?: boolean;
|
|
181
|
+
repairInvalidIds?: boolean;
|
|
182
|
+
};
|
|
183
|
+
/**
|
|
184
|
+
* Responses-API resource path for providers whose route is not `/v1/responses`.
|
|
185
|
+
* Unlike `modelWireDefaults` above, this IS seeded into saved config: it describes
|
|
186
|
+
* the provider's fixed endpoint rather than a default a user might want to override
|
|
187
|
+
* per model. DeepSeek documents `POST /responses` with no `/v1` segment.
|
|
188
|
+
*/
|
|
189
|
+
responsesPath?: string;
|
|
190
|
+
/**
|
|
191
|
+
* Responses upstream that stores nothing server-side. Stateful request parameters
|
|
192
|
+
* are dropped and `store` is pinned false, and orphaned tool results left by a
|
|
193
|
+
* replay miss are repaired rather than forwarded.
|
|
194
|
+
*/
|
|
195
|
+
statelessResponses?: boolean;
|
|
196
|
+
/**
|
|
197
|
+
* Registry default for the provider's Responses `service_tier` support; see
|
|
198
|
+
* `OcxProviderConfig.supportsServiceTier`. Registry-only: backfilled (never
|
|
199
|
+
* overriding) at enrich/route time and deliberately NOT seeded into saved
|
|
200
|
+
* config, so an explicit user value stays distinguishable from the default
|
|
201
|
+
* (and the canonical openai seed comparison keeps its exact key set).
|
|
202
|
+
*/
|
|
203
|
+
supportsServiceTier?: boolean;
|
|
204
|
+
/** Registry default for plaintext reasoning replay; see `OcxProviderConfig.preserveResponsesReasoningContent`. Registry-only like `supportsServiceTier`. */
|
|
205
|
+
preserveResponsesReasoningContent?: boolean;
|
|
206
|
+
/** Registry defaults for per-model Codex reasoning propagation; explicit user keys win during enrichment. */
|
|
207
|
+
modelSupportsReasoningSummaries?: Record<string, boolean>;
|
|
208
|
+
modelDiscovery?: ProviderModelDiscoverySpec;
|
|
209
|
+
contextWindow?: number;
|
|
210
|
+
modelContextWindows?: Record<string, number>;
|
|
211
|
+
modelInputModalities?: Record<string, string[]>;
|
|
212
|
+
defaultMaxOutputTokens?: number;
|
|
213
|
+
modelMaxOutputTokens?: Record<string, number>;
|
|
214
|
+
reasoningEfforts?: string[];
|
|
215
|
+
modelReasoningEfforts?: Record<string, string[]>;
|
|
216
|
+
modelDefaultReasoningEfforts?: Record<string, string>;
|
|
217
|
+
/** Registry-only default for models that reject omitted or disabled reasoning. */
|
|
218
|
+
modelReasoningRequired?: Record<string, boolean>;
|
|
219
|
+
reasoningEffortMap?: Record<string, string>;
|
|
220
|
+
modelReasoningEffortMap?: Record<string, Record<string, string>>;
|
|
221
|
+
reasoningWireFormat?: OcxProviderConfig["reasoningWireFormat"];
|
|
222
|
+
/**
|
|
223
|
+
* Registry-owned model-discovery dialect. This never enters saved provider config; it only
|
|
224
|
+
* teaches the bounded catalog parser how to interpret provider-specific metadata semantics.
|
|
225
|
+
*/
|
|
226
|
+
reasoningMetadataFormat?: "openrouter";
|
|
227
|
+
noVisionModels?: string[];
|
|
228
|
+
noReasoningModels?: string[];
|
|
229
|
+
noTemperatureModels?: string[];
|
|
230
|
+
noTopPModels?: string[];
|
|
231
|
+
noPenaltyModels?: string[];
|
|
232
|
+
/** Opt this provider into parallel tool calls (see OcxProviderConfig.parallelToolCalls). */
|
|
233
|
+
parallelToolCalls?: boolean;
|
|
234
|
+
/** Opt this provider into forwarding prompt_cache_key (OpenAI-specific; strict backends reject it). */
|
|
235
|
+
promptCacheKey?: boolean;
|
|
236
|
+
autoToolChoiceOnlyModels?: string[];
|
|
237
|
+
preserveReasoningContentModels?: string[];
|
|
238
|
+
reasoningSplitModels?: string[];
|
|
239
|
+
thinkingToggleModels?: string[];
|
|
240
|
+
thinkingBudgetModels?: string[];
|
|
241
|
+
escapeBuiltinToolNames?: boolean;
|
|
242
|
+
oauthId?: string;
|
|
243
|
+
virtualModels?: Record<string, { wireModelId: string; reasoningMode: "pro" }>;
|
|
244
|
+
modelMaxInputTokens?: Record<string, number>;
|
|
245
|
+
jawcodeBundle?: string;
|
|
246
|
+
extraMetadataAliases?: string[];
|
|
247
|
+
metadataModelIdNormalize?: MetadataModelIdNormalize;
|
|
248
|
+
googleMode?: "ai-studio" | "vertex" | "cloud-code-assist";
|
|
249
|
+
project?: string;
|
|
250
|
+
location?: string;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export type ProviderConfigSeed = Pick<
|
|
254
|
+
OcxProviderConfig,
|
|
255
|
+
"adapter" | "baseUrl" | "apiKeyTransport" | "responsesPath" | "authMode" | "keyOptional" | "freeTier" | "modelSuffixBracketStrip" | "defaultModel" | "models"
|
|
256
|
+
| "liveModels" | "contextWindow" | "modelContextWindows" | "modelInputModalities"
|
|
257
|
+
| "modelMaxInputTokens" | "defaultMaxOutputTokens" | "modelMaxOutputTokens"
|
|
258
|
+
| "reasoningEfforts" | "modelReasoningEfforts" | "modelDefaultReasoningEfforts" | "reasoningEffortMap" | "modelReasoningEffortMap" | "reasoningWireFormat"
|
|
259
|
+
| "noVisionModels" | "noReasoningModels" | "noTemperatureModels" | "noTopPModels" | "noPenaltyModels"
|
|
260
|
+
| "autoToolChoiceOnlyModels" | "preserveReasoningContentModels" | "reasoningSplitModels" | "thinkingToggleModels" | "thinkingBudgetModels" | "escapeBuiltinToolNames"
|
|
261
|
+
| "googleMode" | "project" | "location" | "headers"
|
|
262
|
+
>;
|
|
263
|
+
|
|
264
|
+
// Shared between the OAuth (Claude account) and API-key Anthropic entries so both expose the
|
|
265
|
+
// same static model seed.
|
|
266
|
+
// 260710 context refresh: Tier-2 evidence in
|
|
267
|
+
// devlog/_plan/260710_provider_hardening/001_research_frontier.md.
|
|
268
|
+
const ANTHROPIC_MODELS = ["claude-fable-5", "claude-sonnet-5", "claude-opus-5", "claude-opus-4-8", "claude-opus-4-7", "claude-opus-4-6", "claude-sonnet-4-6", "claude-haiku-4-5"];
|
|
269
|
+
const ANTHROPIC_MODEL_CONTEXT_WINDOWS: Record<string, number> = { "claude-sonnet-5": 1_000_000, "claude-fable-5": 1_000_000, "claude-opus-5": 1_000_000, "claude-opus-4-8": 1_000_000, "claude-opus-4-7": 1_000_000, "claude-opus-4-6": 1_000_000, "claude-sonnet-4-6": 1_000_000, "claude-haiku-4-5": 200_000 };
|
|
270
|
+
|
|
271
|
+
const ZAI_GLM_52_MODELS = ["glm-5.2", "glm-5.2[1m]"];
|
|
272
|
+
const ZAI_GLM_52_REASONING_EFFORTS = ["low", "medium", "high", "xhigh", "max"];
|
|
273
|
+
// Console Go rejects disabled thinking for GLM 5.3 and explicitly accepts only these tiers.
|
|
274
|
+
// `low` is the conservative fallback for an omitted/stale `none` selection.
|
|
275
|
+
const OPENCODE_GO_GLM_53_REASONING_EFFORTS = ["low", "high", "max"];
|
|
276
|
+
// 260710 MiniMax models and context windows: Tier-2 evidence in
|
|
277
|
+
// devlog/_plan/260710_provider_hardening/002_research_cn.md.
|
|
278
|
+
const MINIMAX_MODELS = [
|
|
279
|
+
"MiniMax-M3",
|
|
280
|
+
"MiniMax-M2.7", "MiniMax-M2.7-highspeed",
|
|
281
|
+
"MiniMax-M2.5", "MiniMax-M2.5-highspeed",
|
|
282
|
+
"MiniMax-M2.1", "MiniMax-M2.1-highspeed",
|
|
283
|
+
"MiniMax-M2",
|
|
284
|
+
];
|
|
285
|
+
const MINIMAX_MODEL_CONTEXT_WINDOWS: Record<string, number> = Object.fromEntries(
|
|
286
|
+
MINIMAX_MODELS.map(id => [id, id === "MiniMax-M3" ? 1_000_000 : 204_800]),
|
|
287
|
+
);
|
|
288
|
+
const MINIMAX_M3_REASONING_EFFORTS = ["low", "medium", "high", "xhigh", "max"];
|
|
289
|
+
const MINIMAX_M3_REASONING_EFFORT_MAP: Record<string, string> = {
|
|
290
|
+
none: "disabled",
|
|
291
|
+
minimal: "disabled",
|
|
292
|
+
low: "disabled",
|
|
293
|
+
medium: "adaptive",
|
|
294
|
+
high: "adaptive",
|
|
295
|
+
xhigh: "adaptive",
|
|
296
|
+
max: "adaptive",
|
|
297
|
+
};
|
|
298
|
+
const OPENAI_GPT56_MODELS = ["gpt-5.6", "gpt-5.6-sol", "gpt-5.6-terra", "gpt-5.6-luna"];
|
|
299
|
+
const OPENAI_GPT56_PRO_MODELS = ["gpt-5.6-sol-pro", "gpt-5.6-terra-pro", "gpt-5.6-luna-pro"];
|
|
300
|
+
const OPENAI_API_GPT56_CONTEXT_WINDOW = 1_050_000;
|
|
301
|
+
const OPENAI_CODEX_GPT56_CONTEXT_WINDOW = 372_000;
|
|
302
|
+
const OPENAI_GPT56_CONTEXT_WINDOWS = {
|
|
303
|
+
"gpt-5.6-sol": OPENAI_CODEX_GPT56_CONTEXT_WINDOW,
|
|
304
|
+
"gpt-5.6-terra": OPENAI_CODEX_GPT56_CONTEXT_WINDOW,
|
|
305
|
+
"gpt-5.6-luna": OPENAI_CODEX_GPT56_CONTEXT_WINDOW,
|
|
306
|
+
};
|
|
307
|
+
const OPENAI_API_GPT56_CONTEXT_WINDOWS: Record<string, number> = {
|
|
308
|
+
...Object.fromEntries([...OPENAI_GPT56_MODELS, ...OPENAI_GPT56_PRO_MODELS].map(id => [id, OPENAI_API_GPT56_CONTEXT_WINDOW])),
|
|
309
|
+
"gpt-5.5": OPENAI_API_GPT56_CONTEXT_WINDOW,
|
|
310
|
+
};
|
|
311
|
+
const OPENAI_API_GPT56_MAX_INPUT_TOKENS: Record<string, number> = {
|
|
312
|
+
...Object.fromEntries([...OPENAI_GPT56_MODELS, ...OPENAI_GPT56_PRO_MODELS].map(id => [id, 922_000])),
|
|
313
|
+
"gpt-5.5": 922_000,
|
|
314
|
+
};
|
|
315
|
+
const OPENAI_API_GPT56_VIRTUAL_MODELS: Record<string, { wireModelId: string; reasoningMode: "pro" }> = {
|
|
316
|
+
"gpt-5.6-sol-pro": { wireModelId: "gpt-5.6-sol", reasoningMode: "pro" },
|
|
317
|
+
"gpt-5.6-terra-pro": { wireModelId: "gpt-5.6-terra", reasoningMode: "pro" },
|
|
318
|
+
"gpt-5.6-luna-pro": { wireModelId: "gpt-5.6-luna", reasoningMode: "pro" },
|
|
319
|
+
};
|
|
320
|
+
const OPENAI_API_GPT56_REASONING_EFFORTS = ["low", "medium", "high", "xhigh", "max"];
|
|
321
|
+
const OPENROUTER_GPT56_MODELS = OPENAI_GPT56_MODELS.map(id => `openai/${id}`);
|
|
322
|
+
// OpenRouter's live /endpoints routes report 1,050,000; keep this separate from the
|
|
323
|
+
// unverified OpenAI API-key seed. Evidence: devlog/_plan/260710_provider_hardening/003_research_aggregators.md.
|
|
324
|
+
const OPENROUTER_GPT56_CONTEXT_WINDOW = 1_050_000;
|
|
325
|
+
const OPENROUTER_GPT56_CONTEXT_WINDOWS = {
|
|
326
|
+
"openai/gpt-5.6-sol": OPENROUTER_GPT56_CONTEXT_WINDOW,
|
|
327
|
+
"openai/gpt-5.6-terra": OPENROUTER_GPT56_CONTEXT_WINDOW,
|
|
328
|
+
"openai/gpt-5.6-luna": OPENROUTER_GPT56_CONTEXT_WINDOW,
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Vendor thinking-toggle models (MiMo v2.x, GLM 5/5.1 on Zen Go): the wire knob is
|
|
333
|
+
* `thinking: {type: enabled|disabled}` — a binary. Advertise the full Codex picker ladder
|
|
334
|
+
* and map efforts onto the toggle. Zen Go
|
|
335
|
+
* pass-through probed live 2026-07-07 (glm-5.2 toggle verified; mimo/minimax accept shape).
|
|
336
|
+
*/
|
|
337
|
+
const THINKING_TOGGLE_EFFORTS = ["low", "medium", "high", "xhigh", "max"];
|
|
338
|
+
const THINKING_TOGGLE_MAP: Record<string, string> = {
|
|
339
|
+
none: "disabled",
|
|
340
|
+
minimal: "disabled",
|
|
341
|
+
low: "disabled",
|
|
342
|
+
medium: "enabled",
|
|
343
|
+
high: "enabled",
|
|
344
|
+
xhigh: "enabled",
|
|
345
|
+
max: "enabled",
|
|
346
|
+
};
|
|
347
|
+
const OPENCODE_GO_THINKING_TOGGLE_MODELS = [
|
|
348
|
+
"mimo-v2.5", "mimo-v2.5-pro", "mimo-v2-omni", "mimo-v2-pro", "glm-5", "glm-5.1",
|
|
349
|
+
];
|
|
350
|
+
/**
|
|
351
|
+
* Zhipu's domestic BigModel platform. Text families first, then the vision member: modalities are
|
|
352
|
+
* declared per model because `noVisionModels` means the opposite of "text only" here — it routes
|
|
353
|
+
* images through the proxy's vision sidecar (src/codex/catalog/provider-fetch.ts), a claim nobody
|
|
354
|
+
* has verified for BigModel-hosted GLM.
|
|
355
|
+
*/
|
|
356
|
+
const ZHIPU_BIGMODEL_TEXT_MODELS = ["glm-4.6", "glm-4.7", "glm-4.7-flash", "glm-5", "glm-5.1"];
|
|
357
|
+
const ZHIPU_BIGMODEL_MODELS = [...ZHIPU_BIGMODEL_TEXT_MODELS, "glm-4.6v"];
|
|
358
|
+
const ZHIPU_BIGMODEL_INPUT_MODALITIES: Record<string, string[]> = {
|
|
359
|
+
...Object.fromEntries(ZHIPU_BIGMODEL_TEXT_MODELS.map(id => [id, ["text"]])),
|
|
360
|
+
"glm-4.6v": ["text", "image"],
|
|
361
|
+
};
|
|
362
|
+
const ZHIPU_BIGMODEL_THINKING_TOGGLE_MODELS = ["glm-4.6", "glm-4.7", "glm-5", "glm-5.1"];
|
|
363
|
+
const THINKING_BUDGET_EFFORTS = ["low", "medium", "high", "xhigh", "max"];
|
|
364
|
+
const THINKING_BUDGET_MODELS = [
|
|
365
|
+
"qwen3.5-397b", "qwen3.6-35b",
|
|
366
|
+
"qwen3.5-plus", "qwen3.6-plus", "qwen3.7-max", "qwen3.7-plus",
|
|
367
|
+
];
|
|
368
|
+
const OPENCODE_GO_THINKING_BUDGET_MODELS = ["qwen3.5-plus", "qwen3.6-plus", "qwen3.7-max", "qwen3.7-plus"];
|
|
369
|
+
const DEEPSEEK_THINKING_MODELS = ["deepseek-v4-pro", "deepseek-v4-flash"];
|
|
370
|
+
const OPENCODE_FREE_DEEPSEEK_MODELS = ["deepseek-v4-flash-free"];
|
|
371
|
+
// Zen's live /models row for Ox Alpha is id-only. The published OpenCode roster declares the
|
|
372
|
+
// exact low/high/max effort ladder and interleaved `reasoning_content` field (verified 2026-08-21),
|
|
373
|
+
// so both registry aliases need the same model-scoped fallback.
|
|
374
|
+
const OPENCODE_OX_ALPHA_MODELS = ["x-preview-f-free"];
|
|
375
|
+
const OPENCODE_OX_ALPHA_REASONING_EFFORTS = ["low", "high", "max"];
|
|
376
|
+
/*
|
|
377
|
+
* Zen free models that reject `image_url` upstream (#1043, and the reproducible
|
|
378
|
+
* half of #1024).
|
|
379
|
+
*
|
|
380
|
+
* Zen publishes NO modality metadata — its `/v1/models` returns only id, object,
|
|
381
|
+
* created, owned_by — so this list is measured, not derived. Each id was probed
|
|
382
|
+
* once against https://opencode.ai/zen/v1 on 2026-08-05 with a text control first
|
|
383
|
+
* and then a 1x1 PNG; the six below failed the image request, four of them with
|
|
384
|
+
* `[404] No endpoints found that support image input` and `big-pickle` with the
|
|
385
|
+
* exact deserialize error quoted in #1043.
|
|
386
|
+
*
|
|
387
|
+
* `mimo-v2.5-free` and `longcat-2.0-free` ACCEPT images and are deliberately
|
|
388
|
+
* absent. Adding them would silently replace a working image with a caption,
|
|
389
|
+
* which is worse than the loud 400 this list exists to prevent — see the negative
|
|
390
|
+
* assertion in tests/provider-registry-parity.test.ts.
|
|
391
|
+
*
|
|
392
|
+
* Zen's roster is discovered live while this list is static, so it is a dated
|
|
393
|
+
* exception list, not a capability model. Re-probe before extending it.
|
|
394
|
+
* Evidence: devlog/_plan/260805_bug_fix_stack/002_zen_modality_probe.md
|
|
395
|
+
*/
|
|
396
|
+
const OPENCODE_ZEN_TEXT_ONLY_MODELS = [
|
|
397
|
+
"big-pickle",
|
|
398
|
+
"nemotron-3-ultra-free",
|
|
399
|
+
"ling-3.0-flash-free",
|
|
400
|
+
"north-mini-code-free",
|
|
401
|
+
"laguna-s-2.1-free",
|
|
402
|
+
"deepseek-v4-flash-free",
|
|
403
|
+
];
|
|
404
|
+
/*
|
|
405
|
+
* DeepSeek's Codex ladder is low/high/max, and the two V4 models resolve it
|
|
406
|
+
* DIFFERENTLY. From the official thinking-mode table (api-docs.deepseek.com,
|
|
407
|
+
* EN and zh-cn agree, re-verified 2026-08-06):
|
|
408
|
+
*
|
|
409
|
+
* requested | v4-flash | v4-pro
|
|
410
|
+
* low | low | high
|
|
411
|
+
* high | high | high
|
|
412
|
+
* xhigh | high | max
|
|
413
|
+
* max | max | max
|
|
414
|
+
*
|
|
415
|
+
* Two consequences (#1057):
|
|
416
|
+
*
|
|
417
|
+
* - `xhigh` is a COMPATIBILITY ALIAS, not a native tier. It stays in the wire maps
|
|
418
|
+
* so existing requests and saved configs keep working, but it is not advertised.
|
|
419
|
+
* - Pro does NOT honor `low` — the vendor silently upgrades it to `high`. So Pro
|
|
420
|
+
* advertises only the two levels it actually distinguishes. Advertising `low`
|
|
421
|
+
* there would put a tier in the picker that costs `high`, which is the same
|
|
422
|
+
* defect this fixes wearing a different value.
|
|
423
|
+
*
|
|
424
|
+
* The vendor page footnotes that Pro's mapping updates in early August 2026; as of
|
|
425
|
+
* the re-verification above it had not changed. When it does, Pro gains `low` here.
|
|
426
|
+
*
|
|
427
|
+
* `medium` has no row in the vendor table — mapping it to `high` is OUR
|
|
428
|
+
* compatibility choice for clients that only speak the OpenAI ladder.
|
|
429
|
+
*/
|
|
430
|
+
const DEEPSEEK_FLASH_THINKING_EFFORTS = ["low", "high", "max"];
|
|
431
|
+
const DEEPSEEK_PRO_THINKING_EFFORTS = ["high", "max"];
|
|
432
|
+
const DEEPSEEK_PRO_REASONING_MAP: Record<string, string> = {
|
|
433
|
+
low: "high",
|
|
434
|
+
medium: "high",
|
|
435
|
+
high: "high",
|
|
436
|
+
xhigh: "max",
|
|
437
|
+
max: "max",
|
|
438
|
+
};
|
|
439
|
+
const DEEPSEEK_FLASH_REASONING_MAP: Record<string, string> = {
|
|
440
|
+
low: "low",
|
|
441
|
+
medium: "high",
|
|
442
|
+
high: "high",
|
|
443
|
+
xhigh: "high",
|
|
444
|
+
max: "max",
|
|
445
|
+
};
|
|
446
|
+
/**
|
|
447
|
+
* Flash-versus-Pro classification for DeepSeek V4 model ids, including prefixed
|
|
448
|
+
* (`deepseek/deepseek-v4-pro`) and suffixed (`deepseek-v4-flash-free`) forms.
|
|
449
|
+
* `tests/provider-registry-parity.test.ts` enumerates every id the registry
|
|
450
|
+
* actually passes here, so a future id this substring test would misread cannot
|
|
451
|
+
* land silently.
|
|
452
|
+
*/
|
|
453
|
+
const isDeepseekFlashModel = (modelId: string): boolean =>
|
|
454
|
+
modelId.toLowerCase().includes("flash");
|
|
455
|
+
const deepseekThinkingEffortsFor = (modelId: string): string[] =>
|
|
456
|
+
isDeepseekFlashModel(modelId) ? DEEPSEEK_FLASH_THINKING_EFFORTS : DEEPSEEK_PRO_THINKING_EFFORTS;
|
|
457
|
+
const deepseekReasoningMapFor = (modelId: string): Record<string, string> =>
|
|
458
|
+
isDeepseekFlashModel(modelId) ? DEEPSEEK_FLASH_REASONING_MAP : DEEPSEEK_PRO_REASONING_MAP;
|
|
459
|
+
// 260719 Alibaba Token Plan Personal Edition (China/Beijing). Keep it distinct from
|
|
460
|
+
// Coding Plan: the products use different exact allowlists and different base URLs.
|
|
461
|
+
// Evidence: https://help.aliyun.com/en/model-studio/token-plan-personal-overview
|
|
462
|
+
// https://help.aliyun.com/en/model-studio/token-plan-quickstart
|
|
463
|
+
const ALIBABA_TOKEN_PLAN_MODELS = [
|
|
464
|
+
"qwen3.8-max", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-flash",
|
|
465
|
+
"glm-5.2", "deepseek-v4-pro",
|
|
466
|
+
];
|
|
467
|
+
const ALIBABA_TOKEN_PLAN_QWEN_MODELS = [
|
|
468
|
+
"qwen3.8-max", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-flash",
|
|
469
|
+
];
|
|
470
|
+
const ALIBABA_TOKEN_PLAN_INPUT_MODALITIES: Record<string, string[]> = {
|
|
471
|
+
"qwen3.8-max": ["text", "image"],
|
|
472
|
+
"qwen3.7-max": ["text", "image"],
|
|
473
|
+
"qwen3.7-plus": ["text", "image"],
|
|
474
|
+
"qwen3.6-flash": ["text", "image"],
|
|
475
|
+
"glm-5.2": ["text"],
|
|
476
|
+
"deepseek-v4-pro": ["text"],
|
|
477
|
+
};
|
|
478
|
+
|
|
479
|
+
// 260721 Alibaba Token Plan International (ap-southeast-1 / Singapore, hardened 260721).
|
|
480
|
+
// Multi-vendor lineup distinct from Beijing — includes DeepSeek V4 flash, Kimi K2.7, MiniMax.
|
|
481
|
+
// Evidence: https://www.alibabacloud.com/help/en/model-studio/token-plan-overview
|
|
482
|
+
// https://qwencloud.com/pricing/token-plan (qwen3.8 metadata)
|
|
483
|
+
const ALIBABA_INTL_TOKEN_PLAN_MODELS = [
|
|
484
|
+
"qwen3.8-max", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-plus", "qwen3.6-flash",
|
|
485
|
+
"deepseek-v4-pro", "deepseek-v4-flash", "deepseek-v3.2",
|
|
486
|
+
"kimi-k2.7-code", "kimi-k2.6", "kimi-k2.5",
|
|
487
|
+
"glm-5.2", "glm-5.1", "glm-5",
|
|
488
|
+
"MiniMax-M2.5",
|
|
489
|
+
];
|
|
490
|
+
const ALIBABA_INTL_TOKEN_PLAN_QWEN_MODELS = [
|
|
491
|
+
"qwen3.8-max", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-plus", "qwen3.6-flash",
|
|
492
|
+
];
|
|
493
|
+
|
|
494
|
+
// 260722 Tencent Cloud Coding Plan. The plan's model set is explicitly dynamic; these are the
|
|
495
|
+
// current documented ids and live discovery remains enabled so successful /models responses win.
|
|
496
|
+
// Tencent marks every Coding Plan model as text-only input and restricts plan keys to interactive
|
|
497
|
+
// coding tools (not custom application backends or non-interactive batch automation).
|
|
498
|
+
// Evidence: https://cloud.tencent.cn/document/product/1823/130092
|
|
499
|
+
const TENCENT_CODING_PLAN_MODELS = ["tc-code-latest", "glm-5", "kimi-k2.5", "minimax-m2.5"];
|
|
500
|
+
// Volcengine's authenticated /api/v3/models catalog mixes chat models with embedding,
|
|
501
|
+
// image, video, and 3D generation resources. Keep the Codex-facing presets scoped to
|
|
502
|
+
// models documented for text/agent or Coding Plan use.
|
|
503
|
+
//
|
|
504
|
+
// Maintenance owner: @lidge-jun. Verified 2026-08-01 against the vendor's own docs —
|
|
505
|
+
// endpoints https://docs.volcengine.com/docs/82379/1528783 (Coding Plan) and
|
|
506
|
+
// https://docs.volcengine.com/docs/82379/2165245 (Agent Plan); Codex CLI integration
|
|
507
|
+
// https://www.volcengine.com/docs/82379/2556056; supported clients
|
|
508
|
+
// https://www.volcengine.com/docs/82379/2188957; terms https://www.volcengine.com/docs/6256/64903
|
|
509
|
+
// (北京火山引擎科技有限公司). Plan quota is restricted to supported AI coding tools and misuse
|
|
510
|
+
// is documented as grounds for suspension — see the `note` on both Plan entries.
|
|
511
|
+
// Report a break by opening an issue tagging the owner; the three things that rot first are the
|
|
512
|
+
// static catalogs (liveModels:false cannot self-heal), the base URLs, and those Plan terms.
|
|
513
|
+
// Full evidence ledger: devlog/_fin/260801_pr611_volcengine_evidence/000_evidence_ledger.md
|
|
514
|
+
const VOLCENGINE_ARK_MODELS = [
|
|
515
|
+
"doubao-seed-2-1-pro-260628",
|
|
516
|
+
"doubao-seed-2-1-turbo-260628",
|
|
517
|
+
"doubao-seed-evolving",
|
|
518
|
+
"deepseek-v4-pro-260425",
|
|
519
|
+
"deepseek-v4-flash-260425",
|
|
520
|
+
"deepseek-v3-2-251201",
|
|
521
|
+
"glm-5-2-260617",
|
|
522
|
+
"glm-4-7-251222",
|
|
523
|
+
];
|
|
524
|
+
const VOLCENGINE_DOUBAO_THINKING_MODELS = [
|
|
525
|
+
"doubao-seed-2-1-pro-260628",
|
|
526
|
+
"doubao-seed-2-1-turbo-260628",
|
|
527
|
+
"doubao-seed-evolving",
|
|
528
|
+
];
|
|
529
|
+
const VOLCENGINE_CODING_PLAN_MODELS = [
|
|
530
|
+
"ark-code-latest",
|
|
531
|
+
"doubao-seed-2.0-code",
|
|
532
|
+
"deepseek-v4-pro",
|
|
533
|
+
"deepseek-v4-flash",
|
|
534
|
+
"glm-5.2",
|
|
535
|
+
"kimi-k2.6",
|
|
536
|
+
"minimax-m3",
|
|
537
|
+
];
|
|
538
|
+
const VOLCENGINE_AGENT_PLAN_MODELS = [
|
|
539
|
+
"deepseek-v4-pro",
|
|
540
|
+
"deepseek-v4-flash",
|
|
541
|
+
"glm-5.2",
|
|
542
|
+
"kimi-k2.6",
|
|
543
|
+
"minimax-m3",
|
|
544
|
+
"doubao-seed-2.0-pro",
|
|
545
|
+
];
|
|
546
|
+
const VOLCENGINE_PLAN_INPUT_MODALITIES: Record<string, string[]> = {
|
|
547
|
+
"kimi-k2.6": ["text", "image"],
|
|
548
|
+
"minimax-m3": ["text", "image"],
|
|
549
|
+
};
|
|
550
|
+
// Every other Plan model is text-only. Declaring this explicitly keeps the vision
|
|
551
|
+
// sidecar from advertising image input for models that cannot accept it — the same
|
|
552
|
+
// treatment tencent-coding-plan gives its (entirely text-only) plan catalog.
|
|
553
|
+
const VOLCENGINE_PLAN_TEXT_ONLY_MODELS = [
|
|
554
|
+
"ark-code-latest",
|
|
555
|
+
"doubao-seed-2.0-code",
|
|
556
|
+
"deepseek-v4-pro",
|
|
557
|
+
"deepseek-v4-flash",
|
|
558
|
+
"glm-5.2",
|
|
559
|
+
"doubao-seed-2.0-pro",
|
|
560
|
+
];
|
|
561
|
+
const ALIBABA_INTL_TOKEN_PLAN_INPUT_MODALITIES: Record<string, string[]> = {
|
|
562
|
+
"qwen3.8-max": ["text", "image"],
|
|
563
|
+
"qwen3.7-max": ["text", "image"],
|
|
564
|
+
"qwen3.7-plus": ["text", "image"],
|
|
565
|
+
"qwen3.6-plus": ["text", "image"],
|
|
566
|
+
"qwen3.6-flash": ["text", "image"],
|
|
567
|
+
"deepseek-v4-pro": ["text"],
|
|
568
|
+
"deepseek-v4-flash": ["text"],
|
|
569
|
+
"deepseek-v3.2": ["text"],
|
|
570
|
+
"kimi-k2.7-code": ["text", "image"],
|
|
571
|
+
"kimi-k2.6": ["text", "image"],
|
|
572
|
+
"kimi-k2.5": ["text", "image"],
|
|
573
|
+
"glm-5.2": ["text"],
|
|
574
|
+
"glm-5.1": ["text"],
|
|
575
|
+
"glm-5": ["text"],
|
|
576
|
+
"MiniMax-M2.5": ["text"],
|
|
577
|
+
};
|
|
578
|
+
|
|
579
|
+
// 260717 Kimi K3: the subscription endpoint uses one upstream id (`k3`) for both
|
|
580
|
+
// entitlement tiers. Bare `k3` advertises the Moderato 256K ceiling; the local `[1m]`
|
|
581
|
+
// alias advertises Allegretto's 1M ceiling and is stripped before the upstream request.
|
|
582
|
+
// The separately billed Moonshot API uses `kimi-k3`.
|
|
583
|
+
// Evidence: https://www.kimi.com/code/docs/en/kimi-code/models.html
|
|
584
|
+
// https://www.kimi.com/code/docs/en/kimi-code/error-reference.html
|
|
585
|
+
const KIMI_K3_STANDARD_CONTEXT_WINDOW = 262_144;
|
|
586
|
+
const KIMI_K3_1M_CONTEXT_WINDOW = 1_048_576;
|
|
587
|
+
const KIMI_CODING_K3_MODELS = ["k3", "k3[1m]"];
|
|
588
|
+
const KIMI_LEGACY_API_MODELS = ["kimi-k2.7-code", "kimi-k2.7-code-highspeed", "kimi-k2.6", "kimi-k2.5"];
|
|
589
|
+
const KIMI_API_MODELS = ["kimi-k3", ...KIMI_LEGACY_API_MODELS];
|
|
590
|
+
const KIMI_CODING_MODELS = [...KIMI_CODING_K3_MODELS, ...KIMI_LEGACY_API_MODELS, "kimi-for-coding"];
|
|
591
|
+
const KIMI_THINKING_MODELS = KIMI_CODING_MODELS;
|
|
592
|
+
const KIMI_CODING_NO_REASONING_MODELS = KIMI_CODING_MODELS.filter(id => !KIMI_CODING_K3_MODELS.includes(id));
|
|
593
|
+
const KIMI_API_NO_REASONING_MODELS = KIMI_API_MODELS.filter(id => id !== "kimi-k3");
|
|
594
|
+
const KIMI_CODING_K3_REASONING_EFFORTS = ["low", "high", "max"];
|
|
595
|
+
const KIMI_CODING_K3_REASONING_EFFORT_MAP: Record<string, string> = {
|
|
596
|
+
none: "none",
|
|
597
|
+
low: "low",
|
|
598
|
+
medium: "high",
|
|
599
|
+
high: "high",
|
|
600
|
+
xhigh: "max",
|
|
601
|
+
max: "max",
|
|
602
|
+
};
|
|
603
|
+
const KIMI_CODING_REASONING_EFFORTS = Object.fromEntries(
|
|
604
|
+
KIMI_CODING_MODELS.map(id => [id, KIMI_CODING_K3_MODELS.includes(id) ? KIMI_CODING_K3_REASONING_EFFORTS : []]),
|
|
605
|
+
);
|
|
606
|
+
const KIMI_CODING_DEFAULT_REASONING_EFFORTS = Object.fromEntries(
|
|
607
|
+
KIMI_CODING_K3_MODELS.map(id => [id, "max"]),
|
|
608
|
+
);
|
|
609
|
+
const KIMI_CODING_REASONING_EFFORT_MAPS = Object.fromEntries(
|
|
610
|
+
KIMI_CODING_K3_MODELS.map(id => [id, KIMI_CODING_K3_REASONING_EFFORT_MAP]),
|
|
611
|
+
);
|
|
612
|
+
const KIMI_API_REASONING_EFFORTS = Object.fromEntries(
|
|
613
|
+
KIMI_API_MODELS.map(id => [id, id === "kimi-k3" ? ["max"] : []]),
|
|
614
|
+
);
|
|
615
|
+
const KIMI_LOCKED_PARAMETER_MODELS = KIMI_CODING_MODELS;
|
|
616
|
+
const KIMI_AUTO_TOOL_CHOICE_ONLY_MODELS = ["kimi-k2.7-code", "kimi-k2.7-code-highspeed", "kimi-for-coding"];
|
|
617
|
+
const KIMI_API_MODEL_CONTEXT_WINDOWS: Record<string, number> = Object.fromEntries(
|
|
618
|
+
KIMI_API_MODELS.map(id => [id, id === "kimi-k3" ? KIMI_K3_1M_CONTEXT_WINDOW : 262_144]),
|
|
619
|
+
);
|
|
620
|
+
const KIMI_API_MODEL_INPUT_MODALITIES = { "kimi-k3": ["text", "image"] };
|
|
621
|
+
|
|
622
|
+
// 260715 NVIDIA NIM kimi family (issue #126): documented served ids on integrate
|
|
623
|
+
// chat/completions per docs.api.nvidia.com/nim/reference/llm-apis; live /v1/models
|
|
624
|
+
// currently lists only kimi-k2.6 but the list is dynamic, so carry the documented family.
|
|
625
|
+
const NVIDIA_NIM_KIMI_THINKING_MODELS = [
|
|
626
|
+
"moonshotai/kimi-k2.6", "moonshotai/kimi-k2.5", "moonshotai/kimi-k2-thinking",
|
|
627
|
+
];
|
|
628
|
+
const NVIDIA_NIM_KIMI_MODELS = [
|
|
629
|
+
...NVIDIA_NIM_KIMI_THINKING_MODELS,
|
|
630
|
+
"moonshotai/kimi-k2-instruct", "moonshotai/kimi-k2-instruct-0905",
|
|
631
|
+
];
|
|
632
|
+
/**
|
|
633
|
+
* 260804 issue #956: NIM publishes no input-modality metadata on `/v1/models`, so the
|
|
634
|
+
* registry is the only source of truth for which models can see images.
|
|
635
|
+
*
|
|
636
|
+
* Two lists, both verified per-model against NVIDIA documentation on 2026-08-04
|
|
637
|
+
* (build.nvidia.com model pages and docs.api.nvidia.com/nim/reference/*). Evidence and
|
|
638
|
+
* the per-id audit: devlog/_fin/260804_stack7_service_vision/011_nim_id_audit.md.
|
|
639
|
+
*
|
|
640
|
+
* Read `noVisionModels` carefully — it lists models that CANNOT see images, which is
|
|
641
|
+
* what routes them through the proxy's vision sidecar (src/vision/index.ts) and makes the
|
|
642
|
+
* catalog advertise image input for them. Membership is wrong in BOTH directions:
|
|
643
|
+
* - a text-only model missing from it keeps issue #956 (images blocked or rejected);
|
|
644
|
+
* - a vision model wrongly IN it gets its image silently replaced by another model's
|
|
645
|
+
* text description — no error, worse answers, extra cost.
|
|
646
|
+
*
|
|
647
|
+
* A new NIM id must be classified DELIBERATELY against its NVIDIA page, never assumed
|
|
648
|
+
* from its name: `google/gemma-4-31b-it` carries no vision marker yet accepts images,
|
|
649
|
+
* `-vl` also appears on embedding/reranking models, and `google/codegemma-7b` is
|
|
650
|
+
* text-only while `google/codegemma-1.1-7b` has no current page at all. An unclassified
|
|
651
|
+
* id is intentionally left alone rather than defaulted, because NIM serves non-chat
|
|
652
|
+
* endpoints (embeddings, rerankers, guards, OCR) that reach the same code path.
|
|
653
|
+
*/
|
|
654
|
+
const NVIDIA_NIM_VISION_MODELS = [
|
|
655
|
+
"meta/llama-3.2-11b-vision-instruct", "meta/llama-3.2-90b-vision-instruct",
|
|
656
|
+
"nvidia/llama-3.1-nemotron-nano-vl-8b-v1", "nvidia/nemotron-nano-12b-v2-vl",
|
|
657
|
+
"nvidia/nemotron-3-nano-omni-30b-a3b-reasoning", "nvidia/cosmos3-nano-reasoner",
|
|
658
|
+
"nvidia/ising-calibration-1.5-31b", "nvidia/ising-calibration-1-35b-a3b",
|
|
659
|
+
"google/gemma-4-31b-it", "google/diffusiongemma-26b-a4b-it",
|
|
660
|
+
"minimaxai/minimax-m3", "moonshotai/kimi-k2.6", "moonshotai/kimi-k2.5",
|
|
661
|
+
"stepfun-ai/step-3.7-flash", "thinkingmachines/inkling",
|
|
662
|
+
"mistralai/mistral-medium-3.5-128b",
|
|
663
|
+
];
|
|
664
|
+
/**
|
|
665
|
+
* The catalog advertises image input only for `noVisionModels` members, so a natively
|
|
666
|
+
* vision-capable model would otherwise be published as text-only and the Codex app would
|
|
667
|
+
* block attachments before the native path ever runs.
|
|
668
|
+
*/
|
|
669
|
+
const NVIDIA_NIM_VISION_INPUT_MODALITIES: Record<string, string[]> = Object.fromEntries(
|
|
670
|
+
NVIDIA_NIM_VISION_MODELS.map(id => [id, ["text", "image"]]),
|
|
671
|
+
);
|
|
672
|
+
/**
|
|
673
|
+
* Text-only NIM chat models — 26 ids, each carrying an explicit `Input Modalities: Text`
|
|
674
|
+
* (or equivalent) on its NVIDIA page. PR #964 proposed ~64; six of those are natively
|
|
675
|
+
* image-capable and live in NVIDIA_NIM_VISION_MODELS above, and 32 more had no current
|
|
676
|
+
* NVIDIA page and were dropped rather than assumed.
|
|
677
|
+
*
|
|
678
|
+
* kimi-k2-thinking and kimi-k2-instruct are text-only while k2.5/k2.6 are not — vision
|
|
679
|
+
* and reasoning are independent axes, so all four stay in NVIDIA_NIM_KIMI_MODELS for
|
|
680
|
+
* reasoning suppression regardless of which list they appear in here.
|
|
681
|
+
*/
|
|
682
|
+
const NVIDIA_NIM_NO_VISION_MODELS = [
|
|
683
|
+
"deepseek-ai/deepseek-v4-flash", "deepseek-ai/deepseek-v4-pro",
|
|
684
|
+
"google/codegemma-7b",
|
|
685
|
+
"meta/llama-3.1-70b-instruct", "meta/llama-3.1-8b-instruct",
|
|
686
|
+
"meta/llama-3.2-1b-instruct", "meta/llama-3.2-3b-instruct",
|
|
687
|
+
"meta/llama-3.3-70b-instruct", "meta/llama2-70b",
|
|
688
|
+
"mistralai/mistral-7b-instruct-v0.3", "mistralai/mistral-nemotron",
|
|
689
|
+
"moonshotai/kimi-k2-thinking", "moonshotai/kimi-k2-instruct",
|
|
690
|
+
"nvidia/llama-3.1-nemotron-nano-8b-v1", "nvidia/llama-3.1-nemotron-ultra-253b-v1",
|
|
691
|
+
"nvidia/llama-3.3-nemotron-super-49b-v1", "nvidia/llama-3.3-nemotron-super-49b-v1.5",
|
|
692
|
+
"nvidia/nemotron-3-nano-30b-a3b", "nvidia/nemotron-3-super-120b-a12b",
|
|
693
|
+
"nvidia/nemotron-3-ultra-550b-a55b", "nvidia/nemotron-mini-4b-instruct",
|
|
694
|
+
"nvidia/nvidia-nemotron-nano-9b-v2",
|
|
695
|
+
"openai/gpt-oss-120b", "openai/gpt-oss-20b",
|
|
696
|
+
"poolside/laguna-xs-2.1", "z-ai/glm-5.2",
|
|
697
|
+
];
|
|
698
|
+
const KIMI_CODING_MODEL_CONTEXT_WINDOWS: Record<string, number> = Object.fromEntries(
|
|
699
|
+
KIMI_CODING_MODELS.map(id => [id, id === "k3[1m]" ? KIMI_K3_1M_CONTEXT_WINDOW : KIMI_K3_STANDARD_CONTEXT_WINDOW]),
|
|
700
|
+
);
|
|
701
|
+
const KIMI_CODING_MODEL_INPUT_MODALITIES = Object.fromEntries(
|
|
702
|
+
KIMI_CODING_K3_MODELS.map(id => [id, ["text", "image"]]),
|
|
703
|
+
);
|
|
704
|
+
const NEURALWATT_REASONING_HISTORY_MODELS = [
|
|
705
|
+
"glm-5.2", "glm-5.2-short",
|
|
706
|
+
"kimi-k2.6", "kimi-k2.7-code",
|
|
707
|
+
"qwen3.5-397b", "qwen3.6-35b",
|
|
708
|
+
];
|
|
709
|
+
|
|
710
|
+
// 260728 Baseten Model APIs: `/v1/models` owns the live lineup, while these hints
|
|
711
|
+
// describe only capabilities that Baseten documents per slug. Unlisted live models
|
|
712
|
+
// intentionally inherit the empty provider ladder instead of being advertised with
|
|
713
|
+
// Remodex's generic reasoning defaults. Audio is omitted because the current proxy
|
|
714
|
+
// request model does not carry OpenAI `audio_url` parts.
|
|
715
|
+
// Evidence: https://docs.baseten.co/inference/model-apis/reasoning
|
|
716
|
+
// https://docs.baseten.co/inference/model-apis/vision
|
|
717
|
+
const BASETEN_FULL_REASONING_EFFORTS = ["low", "medium", "high", "xhigh", "max"];
|
|
718
|
+
const BASETEN_MODEL_REASONING_EFFORTS: Record<string, string[]> = {
|
|
719
|
+
"deepseek-ai/DeepSeek-V4-Pro": BASETEN_FULL_REASONING_EFFORTS,
|
|
720
|
+
"thinkingmachines/inkling": BASETEN_FULL_REASONING_EFFORTS,
|
|
721
|
+
"openai/gpt-oss-120b": BASETEN_FULL_REASONING_EFFORTS,
|
|
722
|
+
"moonshotai/Kimi-K3": ["low", "high", "max"],
|
|
723
|
+
"zai-org/GLM-5.2": ["high", "max"],
|
|
724
|
+
"zai-org/GLM-5.2-Fast": ["high", "max"],
|
|
725
|
+
};
|
|
726
|
+
const BASETEN_MODEL_REASONING_EFFORT_MAP: Record<string, Record<string, string>> = {
|
|
727
|
+
"deepseek-ai/DeepSeek-V4-Pro": { none: "none", minimal: "minimal" },
|
|
728
|
+
"thinkingmachines/inkling": { none: "none", minimal: "minimal" },
|
|
729
|
+
"openai/gpt-oss-120b": { none: "none", minimal: "minimal" },
|
|
730
|
+
"moonshotai/Kimi-K3": { none: "none" },
|
|
731
|
+
"zai-org/GLM-5.2": { none: "none" },
|
|
732
|
+
"zai-org/GLM-5.2-Fast": { none: "none" },
|
|
733
|
+
};
|
|
734
|
+
const BASETEN_MODEL_DEFAULT_REASONING_EFFORTS: Record<string, string> = {
|
|
735
|
+
"deepseek-ai/DeepSeek-V4-Pro": "medium",
|
|
736
|
+
"thinkingmachines/inkling": "high",
|
|
737
|
+
"openai/gpt-oss-120b": "medium",
|
|
738
|
+
"moonshotai/Kimi-K3": "max",
|
|
739
|
+
};
|
|
740
|
+
const BASETEN_MODEL_INPUT_MODALITIES: Record<string, string[]> = {
|
|
741
|
+
"thinkingmachines/inkling": ["text", "image"],
|
|
742
|
+
"moonshotai/Kimi-K2.6": ["text", "image"],
|
|
743
|
+
"moonshotai/Kimi-K2.7-Code": ["text", "image"],
|
|
744
|
+
"moonshotai/Kimi-K3": ["text", "image"],
|
|
745
|
+
};
|
|
746
|
+
|
|
747
|
+
// 260801 DigitalOcean and Scaleway expose OpenAI-shaped `/v1/models` rows with only
|
|
748
|
+
// id/object/created/owned_by, while their shared serverless catalogs also contain
|
|
749
|
+
// non-chat and endpoint-specific models. Fail closed by intersecting live discovery
|
|
750
|
+
// with ids that the providers' current first-party model tables establish for Chat
|
|
751
|
+
// Completions. A newly listed id therefore needs a docs-backed registry refresh before
|
|
752
|
+
// it can enter the Codex catalog.
|
|
753
|
+
// Evidence: https://docs.digitalocean.com/products/inference/details/models/
|
|
754
|
+
// https://docs.digitalocean.com/reference/api/reference/serverless-inference/
|
|
755
|
+
// https://www.scaleway.com/en/docs/generative-apis/reference-content/supported-models/
|
|
756
|
+
const DIGITALOCEAN_CHAT_COMPLETION_MODELS = [
|
|
757
|
+
"arcee-trinity-large-thinking",
|
|
758
|
+
"openai-gpt-5.6-sol",
|
|
759
|
+
"openai-gpt-5.6-terra",
|
|
760
|
+
"openai-gpt-5.6-luna",
|
|
761
|
+
"qwen3-coder-flash",
|
|
762
|
+
"qwen3.5-397b-a17b",
|
|
763
|
+
"deepseek-v4-pro",
|
|
764
|
+
"deepseek-4-flash",
|
|
765
|
+
"deepseek-3.2",
|
|
766
|
+
"gemma-4-31B-it",
|
|
767
|
+
"minimax-m2.5",
|
|
768
|
+
"kimi-k3",
|
|
769
|
+
"kimi-k2.6",
|
|
770
|
+
"kimi-k2.5",
|
|
771
|
+
"llama3.3-70b-instruct",
|
|
772
|
+
"llama-4-maverick",
|
|
773
|
+
"mistral-3-14B",
|
|
774
|
+
"nemotron-3-ultra-550b",
|
|
775
|
+
"nvidia-nemotron-3-super-120b",
|
|
776
|
+
"nemotron-3-nano-omni",
|
|
777
|
+
"nemotron-nano-12b-v2-vl",
|
|
778
|
+
"mimo-v2.5-pro",
|
|
779
|
+
"glm-5.2",
|
|
780
|
+
"glm-5.1",
|
|
781
|
+
"glm-5",
|
|
782
|
+
// The API reference uses this native slash id in its Chat Completions example.
|
|
783
|
+
"meta-llama/Meta-Llama-3.1-8B-Instruct",
|
|
784
|
+
] as const;
|
|
785
|
+
const SCALEWAY_SERVERLESS_CHAT_MODELS = [
|
|
786
|
+
"glm-5.2",
|
|
787
|
+
// gpt-oss-120b is intentionally omitted: Scaleway requires Responses API for tool calling,
|
|
788
|
+
// while this preset routes Codex agent tools through Chat Completions.
|
|
789
|
+
"qwen3.6-35b-a3b",
|
|
790
|
+
"qwen3.5-397b-a17b",
|
|
791
|
+
"qwen3-235b-a22b-instruct-2507",
|
|
792
|
+
"qwen3-coder-30b-a3b-instruct",
|
|
793
|
+
"gemma-4-26b-a4b-it",
|
|
794
|
+
"llama-3.3-70b-instruct",
|
|
795
|
+
"mistral-medium-3.5-128b",
|
|
796
|
+
"mistral-small-3.2-24b-instruct-2506",
|
|
797
|
+
"pixtral-12b-2409",
|
|
798
|
+
] as const;
|
|
799
|
+
const SCALEWAY_MODEL_INPUT_MODALITIES: Record<string, string[]> = {
|
|
800
|
+
"pixtral-12b-2409": ["text", "image"],
|
|
801
|
+
};
|
|
802
|
+
const UMANS_MODELS = [
|
|
803
|
+
"umans-coder",
|
|
804
|
+
"umans-kimi-k2.7",
|
|
805
|
+
"umans-flash",
|
|
806
|
+
"umans-glm-5.2",
|
|
807
|
+
"umans-glm-5.1",
|
|
808
|
+
"umans-qwen3.6-35b-a3b",
|
|
809
|
+
];
|
|
810
|
+
const UMANS_REASONING_EFFORTS = ["low", "medium", "high", "xhigh", "max"];
|
|
811
|
+
const UMANS_GLM_REASONING_EFFORTS = ["high", "xhigh", "max"];
|
|
812
|
+
const UMANS_TEXT_ONLY_MODELS = ["umans-glm-5.2", "umans-glm-5.1"];
|
|
813
|
+
const UMANS_MODEL_CONTEXT_WINDOWS: Record<string, number> = {
|
|
814
|
+
"umans-coder": 262_144,
|
|
815
|
+
"umans-kimi-k2.7": 262_144,
|
|
816
|
+
"umans-flash": 262_144,
|
|
817
|
+
"umans-glm-5.2": 405_504,
|
|
818
|
+
"umans-glm-5.1": 202_752,
|
|
819
|
+
"umans-qwen3.6-35b-a3b": 262_144,
|
|
820
|
+
};
|
|
821
|
+
const UMANS_MODEL_INPUT_MODALITIES: Record<string, string[]> = Object.fromEntries(
|
|
822
|
+
UMANS_MODELS.map(id => [id, UMANS_TEXT_ONLY_MODELS.includes(id) ? ["text"] : ["text", "image"]]),
|
|
823
|
+
);
|
|
824
|
+
const CLINE_PASS_MODELS = [
|
|
825
|
+
"cline-pass/glm-5.2",
|
|
826
|
+
"cline-pass/kimi-k3",
|
|
827
|
+
"cline-pass/kimi-k2.7-code",
|
|
828
|
+
"cline-pass/kimi-k2.6",
|
|
829
|
+
"cline-pass/deepseek-v4-pro",
|
|
830
|
+
"cline-pass/deepseek-v4-flash",
|
|
831
|
+
"cline-pass/mimo-v2.5",
|
|
832
|
+
"cline-pass/mimo-v2.5-pro",
|
|
833
|
+
"cline-pass/minimax-m3",
|
|
834
|
+
"cline-pass/qwen3.7-max",
|
|
835
|
+
"cline-pass/qwen3.7-plus",
|
|
836
|
+
];
|
|
837
|
+
const CLINE_PASS_MODEL_CONTEXT_WINDOWS: Record<string, number> = {
|
|
838
|
+
"cline-pass/glm-5.2": 1_048_576,
|
|
839
|
+
"cline-pass/kimi-k3": 1_048_576,
|
|
840
|
+
"cline-pass/kimi-k2.7-code": 262_144,
|
|
841
|
+
"cline-pass/kimi-k2.6": 262_144,
|
|
842
|
+
"cline-pass/deepseek-v4-pro": 1_048_576,
|
|
843
|
+
"cline-pass/deepseek-v4-flash": 1_048_576,
|
|
844
|
+
"cline-pass/mimo-v2.5": 1_050_000,
|
|
845
|
+
"cline-pass/mimo-v2.5-pro": 1_050_000,
|
|
846
|
+
"cline-pass/minimax-m3": 1_048_576,
|
|
847
|
+
"cline-pass/qwen3.7-max": 1_000_000,
|
|
848
|
+
"cline-pass/qwen3.7-plus": 1_000_000,
|
|
849
|
+
};
|
|
850
|
+
const CLINE_PASS_IMAGE_MODELS = new Set([
|
|
851
|
+
"cline-pass/kimi-k3",
|
|
852
|
+
"cline-pass/kimi-k2.7-code",
|
|
853
|
+
"cline-pass/kimi-k2.6",
|
|
854
|
+
"cline-pass/mimo-v2.5",
|
|
855
|
+
"cline-pass/minimax-m3",
|
|
856
|
+
"cline-pass/qwen3.7-plus",
|
|
857
|
+
]);
|
|
858
|
+
const CLINE_PASS_TEXT_ONLY_MODELS = CLINE_PASS_MODELS.filter(id => !CLINE_PASS_IMAGE_MODELS.has(id));
|
|
859
|
+
const CLINE_PASS_MODEL_INPUT_MODALITIES: Record<string, string[]> = Object.fromEntries(
|
|
860
|
+
CLINE_PASS_MODELS.map(id => [id, CLINE_PASS_IMAGE_MODELS.has(id) ? ["text", "image"] : ["text"]]),
|
|
861
|
+
);
|
|
862
|
+
|
|
863
|
+
export const PROVIDER_REGISTRY: readonly ProviderRegistryEntry[] = [
|
|
864
|
+
{
|
|
865
|
+
id: "openai",
|
|
866
|
+
label: "OpenAI (Codex login)",
|
|
867
|
+
adapter: "openai-responses",
|
|
868
|
+
baseUrl: "https://chatgpt.com/backend-api/codex",
|
|
869
|
+
authKind: "forward",
|
|
870
|
+
codexAccountMode: "pool",
|
|
871
|
+
supportsServiceTier: true,
|
|
872
|
+
featured: true,
|
|
873
|
+
note: "Codex login account pool (default) or Direct main-account mode via codexAccountMode",
|
|
874
|
+
},
|
|
875
|
+
{
|
|
876
|
+
id: "cursor",
|
|
877
|
+
label: "Cursor (experimental)",
|
|
878
|
+
adapter: "cursor",
|
|
879
|
+
baseUrl: "https://api2.cursor.sh",
|
|
880
|
+
authKind: "oauth",
|
|
881
|
+
featured: false,
|
|
882
|
+
dashboardPreset: true,
|
|
883
|
+
note: "Experimental Cursor bridge. Live transport and live model discovery are enabled after a standalone PKCE browser login via 'rmx login cursor'; native read/write/delete/shell/fetch execution is disabled by default and request text such as Codex sandbox markers never authorizes it. Set \"nativeLocalExec\": \"on\" on providers.cursor in ~/.remodex/config.json (dashboard: Providers → Cursor → Edit JSON) only for a trusted local experiment where every data-plane caller is trusted. \"off\" denies all, \"codex-sandbox\" is accepted for backwards compatibility but fails closed, and legacy \"unsafeAllowNativeLocalExec\": true still means explicit operator opt-in.",
|
|
884
|
+
models: cursorModelIds(CURSOR_STATIC_MODELS),
|
|
885
|
+
liveModels: true,
|
|
886
|
+
defaultModel: "auto",
|
|
887
|
+
modelContextWindows: cursorModelContextWindows(CURSOR_STATIC_MODELS),
|
|
888
|
+
modelInputModalities: cursorModelInputModalities(CURSOR_STATIC_MODELS),
|
|
889
|
+
modelReasoningEfforts: cursorModelReasoningEfforts(CURSOR_STATIC_MODELS),
|
|
890
|
+
// Kimi K3 documents `max` as its API default, and its Cursor ladder has no `medium`
|
|
891
|
+
// rung — so applyReasoningLevels' medium->high->first fallback would settle the catalog
|
|
892
|
+
// default on `high`, the picker would send `high` explicitly, and the request builder's
|
|
893
|
+
// no-effort fallback to `kimi-k3-max` would never be reached. Mirrors the other K3
|
|
894
|
+
// routes (kimi, kimi-code, opencode-go).
|
|
895
|
+
modelDefaultReasoningEfforts: { "kimi-k3": "max" },
|
|
896
|
+
// Cursor's wire protocol never forwards image parts (request-builder emits an unsupported-
|
|
897
|
+
// content marker), so the vision sidecar covers ALL cursor models regardless of what the
|
|
898
|
+
// upstream model could natively do. Live-discovered models outside the static list fall back
|
|
899
|
+
// to the same marker until they appear here.
|
|
900
|
+
noVisionModels: cursorModelIds(CURSOR_STATIC_MODELS),
|
|
901
|
+
},
|
|
902
|
+
{
|
|
903
|
+
id: "xai",
|
|
904
|
+
label: "xAI Grok",
|
|
905
|
+
adapter: "openai-chat",
|
|
906
|
+
baseUrl: "https://api.x.ai/v1",
|
|
907
|
+
authKind: "oauth",
|
|
908
|
+
allowKeyAuthOverride: true,
|
|
909
|
+
featured: true,
|
|
910
|
+
oauthId: "xai",
|
|
911
|
+
jawcodeBundle: "xai",
|
|
912
|
+
note: "Log in with your Grok account",
|
|
913
|
+
// Parallel tool calls: officially supported and default-on per docs.x.ai function-calling
|
|
914
|
+
// (verified 260709, devlog/_plan/260709_parallel_tool_calls). Streamed calls arrive whole
|
|
915
|
+
// per chunk, so the buffered parser assembles them losslessly.
|
|
916
|
+
parallelToolCalls: true,
|
|
917
|
+
// Live /v1/models discovery is the authoritative lineup (verified 260709: returns grok-4.5);
|
|
918
|
+
// the static list below is the logged-out fallback seed.
|
|
919
|
+
liveModels: true,
|
|
920
|
+
// 260709 refresh: lineup + metadata from official docs.x.ai (grok-4.5 announced 07-08);
|
|
921
|
+
// grok-composer-2.5-fast kept as account-verified (absent from public docs). Evidence:
|
|
922
|
+
// devlog/model_update/260709_model_refresh/001_xai_lineup.md.
|
|
923
|
+
// grok-4.20-multi-agent-0309 is intentionally absent: the OAuth chat-completions
|
|
924
|
+
// transport returns 400 ("Multi Agent requests are not allowed on chat completions").
|
|
925
|
+
models: ["grok-4.5", "grok-4.3", "grok-4.20-0309-reasoning", "grok-4.20-0309-non-reasoning", "grok-build-0.1", "grok-composer-2.5-fast"],
|
|
926
|
+
defaultModel: "grok-4.5",
|
|
927
|
+
// Vision lineup per docs.x.ai model-capabilities/images/understanding: the grok-4.x chat
|
|
928
|
+
// models accept image input (JPEG/PNG, URL or base64). Without this the catalog leaves
|
|
929
|
+
// inputModalities undefined, and deriveComboCatalogModel defaults an undefined member to
|
|
930
|
+
// ["text"] — so any combo containing an xAI target is advertised to Codex as text-only and
|
|
931
|
+
// the app blocks attachments client-side. grok-build-0.1 / grok-composer-2.5-fast stay out
|
|
932
|
+
// (they are already listed in noVisionModels below).
|
|
933
|
+
modelInputModalities: {
|
|
934
|
+
"grok-4.5": ["text", "image"],
|
|
935
|
+
"grok-4.3": ["text", "image"],
|
|
936
|
+
"grok-4.20-0309-reasoning": ["text", "image"],
|
|
937
|
+
"grok-4.20-0309-non-reasoning": ["text", "image"],
|
|
938
|
+
},
|
|
939
|
+
noReasoningModels: ["grok-4.20-0309-non-reasoning", "grok-build-0.1", "grok-composer-2.5-fast"],
|
|
940
|
+
// Replay assistant reasoning_content for grok reasoning models: xAI documents dropped
|
|
941
|
+
// reasoning_content as the top cause of prompt-cache misses on multi-turn conversations
|
|
942
|
+
// (docs.x.ai prompt-caching/multi-turn, verified 2026-07-13 — devlog/_plan/260713_grok_caching).
|
|
943
|
+
// Models that never emit reasoning simply have no thinking parts to replay (no-op).
|
|
944
|
+
preserveReasoningContentModels: ["grok-4.5", "grok-4.3", "grok-4.20-0309-reasoning"],
|
|
945
|
+
// grok-4.5 reasoning is always-on with low/medium/high control (no off tier upstream).
|
|
946
|
+
modelReasoningEfforts: { "grok-4.5": ["low", "medium", "high"] },
|
|
947
|
+
modelContextWindows: {
|
|
948
|
+
"grok-4.5": 500_000,
|
|
949
|
+
"grok-4.3": 1_000_000,
|
|
950
|
+
"grok-4.20-0309-reasoning": 1_000_000,
|
|
951
|
+
"grok-4.20-0309-non-reasoning": 1_000_000,
|
|
952
|
+
"grok-build-0.1": 256_000,
|
|
953
|
+
},
|
|
954
|
+
noVisionModels: ["grok-build-0.1", "grok-composer-2.5-fast"],
|
|
955
|
+
},
|
|
956
|
+
{
|
|
957
|
+
id: "command-code",
|
|
958
|
+
label: "Command Code - Auth",
|
|
959
|
+
adapter: "command-code",
|
|
960
|
+
baseUrl: "https://api.commandcode.ai",
|
|
961
|
+
authKind: "oauth",
|
|
962
|
+
oauthId: "command-code",
|
|
963
|
+
featured: true,
|
|
964
|
+
note: "Log in with your Command Code account",
|
|
965
|
+
// OAuth needs one initial selection, but the exposed catalog is always discovered from the
|
|
966
|
+
// signed-in account. Do not add a static model list here.
|
|
967
|
+
defaultModel: "deepseek/deepseek-v4-flash",
|
|
968
|
+
liveModels: true,
|
|
969
|
+
modelDiscovery: {
|
|
970
|
+
url: "https://api.commandcode.ai/provider/v1/models",
|
|
971
|
+
maxResponseBytes: 262_144,
|
|
972
|
+
maxModels: 256,
|
|
973
|
+
},
|
|
974
|
+
// These are capability facts from official Command Code model profiles, not seeded models.
|
|
975
|
+
// Unknown/new live models deliberately do not advertise a reasoning picker.
|
|
976
|
+
reasoningEfforts: [],
|
|
977
|
+
modelReasoningEfforts: COMMAND_CODE_MODEL_REASONING_EFFORTS,
|
|
978
|
+
defaultMaxOutputTokens: 64_000,
|
|
979
|
+
// The proprietary generate wire has no verified per-request serialization flag.
|
|
980
|
+
parallelToolCalls: false,
|
|
981
|
+
},
|
|
982
|
+
{
|
|
983
|
+
id: "anthropic",
|
|
984
|
+
label: "Anthropic Claude",
|
|
985
|
+
adapter: "anthropic",
|
|
986
|
+
baseUrl: "https://api.anthropic.com",
|
|
987
|
+
authKind: "oauth",
|
|
988
|
+
featured: true,
|
|
989
|
+
oauthId: "anthropic",
|
|
990
|
+
jawcodeBundle: "anthropic",
|
|
991
|
+
note: "Log in with your Claude account",
|
|
992
|
+
models: [...ANTHROPIC_MODELS],
|
|
993
|
+
modelContextWindows: { ...ANTHROPIC_MODEL_CONTEXT_WINDOWS },
|
|
994
|
+
defaultModel: "claude-sonnet-5",
|
|
995
|
+
},
|
|
996
|
+
{
|
|
997
|
+
id: "anthropic-apikey",
|
|
998
|
+
label: "Anthropic (API key)",
|
|
999
|
+
adapter: "anthropic",
|
|
1000
|
+
baseUrl: "https://api.anthropic.com",
|
|
1001
|
+
authKind: "key",
|
|
1002
|
+
featured: true,
|
|
1003
|
+
dashboardUrl: "https://console.anthropic.com/settings/keys",
|
|
1004
|
+
jawcodeBundle: "anthropic",
|
|
1005
|
+
extraMetadataAliases: ["anthropic-key"],
|
|
1006
|
+
note: "Direct Anthropic API billing — no Claude subscription",
|
|
1007
|
+
models: [...ANTHROPIC_MODELS],
|
|
1008
|
+
liveModels: true,
|
|
1009
|
+
modelContextWindows: { ...ANTHROPIC_MODEL_CONTEXT_WINDOWS },
|
|
1010
|
+
defaultModel: "claude-sonnet-5",
|
|
1011
|
+
},
|
|
1012
|
+
{
|
|
1013
|
+
id: "kimi",
|
|
1014
|
+
label: "Kimi",
|
|
1015
|
+
adapter: "openai-chat",
|
|
1016
|
+
baseUrl: "https://api.kimi.com/coding/v1",
|
|
1017
|
+
authKind: "oauth",
|
|
1018
|
+
modelSuffixBracketStrip: true,
|
|
1019
|
+
// Kimi Code Plan documents a stable session/task prompt_cache_key as required to improve
|
|
1020
|
+
// cache hit rates.
|
|
1021
|
+
// The chat adapter only forwards a key already on the internal request (Codex's session key,
|
|
1022
|
+
// or the one the Claude /v1/messages inbound derives); the adapter itself never invents one.
|
|
1023
|
+
// Evidence: https://platform.kimi.com/docs/api/chat
|
|
1024
|
+
promptCacheKey: true,
|
|
1025
|
+
featured: true,
|
|
1026
|
+
oauthId: "kimi",
|
|
1027
|
+
jawcodeBundle: "moonshot",
|
|
1028
|
+
note: "Log in with your Kimi account",
|
|
1029
|
+
models: KIMI_CODING_MODELS,
|
|
1030
|
+
defaultModel: "kimi-k2.7-code",
|
|
1031
|
+
modelContextWindows: KIMI_CODING_MODEL_CONTEXT_WINDOWS,
|
|
1032
|
+
modelInputModalities: KIMI_CODING_MODEL_INPUT_MODALITIES,
|
|
1033
|
+
// K3 accepts low/high/max; Codex aliases are normalized by the model-scoped wire map.
|
|
1034
|
+
noReasoningModels: KIMI_CODING_NO_REASONING_MODELS,
|
|
1035
|
+
modelReasoningEfforts: KIMI_CODING_REASONING_EFFORTS,
|
|
1036
|
+
modelDefaultReasoningEfforts: KIMI_CODING_DEFAULT_REASONING_EFFORTS,
|
|
1037
|
+
modelReasoningEffortMap: KIMI_CODING_REASONING_EFFORT_MAPS,
|
|
1038
|
+
noTemperatureModels: KIMI_LOCKED_PARAMETER_MODELS,
|
|
1039
|
+
noTopPModels: KIMI_LOCKED_PARAMETER_MODELS,
|
|
1040
|
+
noPenaltyModels: KIMI_LOCKED_PARAMETER_MODELS,
|
|
1041
|
+
autoToolChoiceOnlyModels: KIMI_AUTO_TOOL_CHOICE_ONLY_MODELS,
|
|
1042
|
+
preserveReasoningContentModels: KIMI_THINKING_MODELS,
|
|
1043
|
+
},
|
|
1044
|
+
{
|
|
1045
|
+
id: "kiro",
|
|
1046
|
+
label: "Kiro (AWS CodeWhisperer)",
|
|
1047
|
+
adapter: "kiro",
|
|
1048
|
+
baseUrl: "https://runtime.us-east-1.kiro.dev",
|
|
1049
|
+
authKind: "oauth",
|
|
1050
|
+
oauthId: "kiro",
|
|
1051
|
+
note: "Import-first: reuses your installed and signed-in Kiro CLI session (requires `kiro-cli login`). Add account logs `kiro-cli` out, switches it through a fresh browser login, stores the account by profile ARN, and restores the previous CLI session on cancellation or failure. Experimental third-party harness — see Kiro ToS.",
|
|
1052
|
+
models: KIRO_MODELS,
|
|
1053
|
+
defaultModel: "kiro-auto",
|
|
1054
|
+
// Kiro speaks CodeWhisperer wire, not OpenAI-style GET /models. Keep the static
|
|
1055
|
+
// catalog authoritative so a spurious 2xx from runtime.../models cannot drop seeded ids
|
|
1056
|
+
// (e.g. newly listed GPT-5.6 tiers) via live-discovery reconciliation.
|
|
1057
|
+
liveModels: false,
|
|
1058
|
+
// Per-model context metadata is maintained next to the Kiro model list.
|
|
1059
|
+
modelContextWindows: KIRO_MODEL_CONTEXT_WINDOWS,
|
|
1060
|
+
modelReasoningEfforts: KIRO_MODEL_REASONING_EFFORTS,
|
|
1061
|
+
},
|
|
1062
|
+
{
|
|
1063
|
+
id: "openai-apikey",
|
|
1064
|
+
label: "OpenAI API",
|
|
1065
|
+
adapter: "openai-responses",
|
|
1066
|
+
baseUrl: "https://api.openai.com/v1",
|
|
1067
|
+
authKind: "key",
|
|
1068
|
+
supportsServiceTier: true,
|
|
1069
|
+
featured: true,
|
|
1070
|
+
dashboardUrl: "https://platform.openai.com/api-keys",
|
|
1071
|
+
defaultModel: "gpt-5.5",
|
|
1072
|
+
models: ["gpt-5.5", ...OPENAI_GPT56_MODELS, ...OPENAI_GPT56_PRO_MODELS],
|
|
1073
|
+
liveModels: true,
|
|
1074
|
+
modelContextWindows: OPENAI_API_GPT56_CONTEXT_WINDOWS,
|
|
1075
|
+
modelMaxInputTokens: OPENAI_API_GPT56_MAX_INPUT_TOKENS,
|
|
1076
|
+
modelInputModalities: Object.fromEntries(
|
|
1077
|
+
["gpt-5.5", ...OPENAI_GPT56_MODELS, ...OPENAI_GPT56_PRO_MODELS].map(id => [id, ["text", "image"]]),
|
|
1078
|
+
),
|
|
1079
|
+
modelReasoningEfforts: Object.fromEntries(
|
|
1080
|
+
[...OPENAI_GPT56_MODELS, ...OPENAI_GPT56_PRO_MODELS].map(id => [id, OPENAI_API_GPT56_REASONING_EFFORTS]),
|
|
1081
|
+
),
|
|
1082
|
+
virtualModels: OPENAI_API_GPT56_VIRTUAL_MODELS,
|
|
1083
|
+
},
|
|
1084
|
+
{
|
|
1085
|
+
id: "umans",
|
|
1086
|
+
label: "Umans AI Coding Plan",
|
|
1087
|
+
adapter: "anthropic",
|
|
1088
|
+
baseUrl: "https://api.code.umans.ai",
|
|
1089
|
+
authKind: "key",
|
|
1090
|
+
featured: true,
|
|
1091
|
+
dashboardUrl: "https://app.umans.ai/billing",
|
|
1092
|
+
defaultModel: "umans-coder",
|
|
1093
|
+
models: UMANS_MODELS,
|
|
1094
|
+
modelContextWindows: UMANS_MODEL_CONTEXT_WINDOWS,
|
|
1095
|
+
modelInputModalities: UMANS_MODEL_INPUT_MODALITIES,
|
|
1096
|
+
note: "Coding plan via Anthropic Messages",
|
|
1097
|
+
modelReasoningEfforts: {
|
|
1098
|
+
"umans-coder": UMANS_REASONING_EFFORTS,
|
|
1099
|
+
"umans-kimi-k2.7": UMANS_REASONING_EFFORTS,
|
|
1100
|
+
"umans-flash": UMANS_REASONING_EFFORTS,
|
|
1101
|
+
"umans-glm-5.2": UMANS_GLM_REASONING_EFFORTS,
|
|
1102
|
+
"umans-glm-5.1": UMANS_GLM_REASONING_EFFORTS,
|
|
1103
|
+
"umans-qwen3.6-35b-a3b": UMANS_REASONING_EFFORTS,
|
|
1104
|
+
},
|
|
1105
|
+
noVisionModels: UMANS_TEXT_ONLY_MODELS,
|
|
1106
|
+
escapeBuiltinToolNames: true,
|
|
1107
|
+
},
|
|
1108
|
+
{
|
|
1109
|
+
id: "opencode-go", label: "opencode go", adapter: "openai-chat", baseUrl: "https://opencode.ai/zen/go/v1",
|
|
1110
|
+
authKind: "key", featured: true, dashboardUrl: "https://opencode.ai/auth", defaultModel: "kimi-k2.7-code",
|
|
1111
|
+
jawcodeBundle: "opencode-go", note: "GLM, DeepSeek, Kimi, Qwen, MiMo…",
|
|
1112
|
+
modelContextWindows: { "kimi-k3": KIMI_K3_STANDARD_CONTEXT_WINDOW },
|
|
1113
|
+
modelInputModalities: { "kimi-k3": ["text", "image"] },
|
|
1114
|
+
modelReasoningEfforts: {
|
|
1115
|
+
"qwen3.8-max": ["none", "minimal", "low", "medium", "high", "xhigh"],
|
|
1116
|
+
"glm-5.3": OPENCODE_GO_GLM_53_REASONING_EFFORTS,
|
|
1117
|
+
"glm-5.2": ZAI_GLM_52_REASONING_EFFORTS,
|
|
1118
|
+
"kimi-k3": KIMI_CODING_K3_REASONING_EFFORTS,
|
|
1119
|
+
"kimi-k2.7-code": [],
|
|
1120
|
+
"kimi-k2.7-code-highspeed": [],
|
|
1121
|
+
...Object.fromEntries(OPENCODE_GO_THINKING_TOGGLE_MODELS.map(id => [id, THINKING_TOGGLE_EFFORTS])),
|
|
1122
|
+
...Object.fromEntries(OPENCODE_GO_THINKING_BUDGET_MODELS.map(id => [id, THINKING_BUDGET_EFFORTS])),
|
|
1123
|
+
...Object.fromEntries(DEEPSEEK_THINKING_MODELS.map(id => [id, deepseekThinkingEffortsFor(id)])),
|
|
1124
|
+
},
|
|
1125
|
+
modelDefaultReasoningEfforts: { "glm-5.3": "low", "kimi-k3": "max" },
|
|
1126
|
+
modelReasoningRequired: { "glm-5.3": true },
|
|
1127
|
+
// glm-5.2 uses identity labels now that `max` is a native Codex level (no alias map);
|
|
1128
|
+
// the thinking-toggle map is a REAL wire alias (effort -> enabled/disabled) and stays.
|
|
1129
|
+
modelReasoningEffortMap: {
|
|
1130
|
+
"kimi-k3": KIMI_CODING_K3_REASONING_EFFORT_MAP,
|
|
1131
|
+
...Object.fromEntries(OPENCODE_GO_THINKING_TOGGLE_MODELS.map(id => [id, THINKING_TOGGLE_MAP])),
|
|
1132
|
+
...Object.fromEntries(DEEPSEEK_THINKING_MODELS.map(id => [id, deepseekReasoningMapFor(id)])),
|
|
1133
|
+
},
|
|
1134
|
+
modelSupportsReasoningSummaries: {
|
|
1135
|
+
"glm-5.2": true,
|
|
1136
|
+
"glm-5.1": true,
|
|
1137
|
+
"glm-5": true,
|
|
1138
|
+
...Object.fromEntries(DEEPSEEK_THINKING_MODELS.map(id => [id, true])),
|
|
1139
|
+
},
|
|
1140
|
+
thinkingToggleModels: OPENCODE_GO_THINKING_TOGGLE_MODELS,
|
|
1141
|
+
thinkingBudgetModels: THINKING_BUDGET_MODELS,
|
|
1142
|
+
noReasoningModels: ["kimi-k2.7-code", "kimi-k2.7-code-highspeed"],
|
|
1143
|
+
// Text-only Zen Go models (jawcode metadata) — the vision sidecar describes images for
|
|
1144
|
+
// every model listed here (and the catalog advertises image input on their behalf).
|
|
1145
|
+
// Kimi K2.7 Code accepts text+image+video: do NOT list it here.
|
|
1146
|
+
noVisionModels: [
|
|
1147
|
+
"glm-5.2", "glm-5", "glm-5.1",
|
|
1148
|
+
"deepseek-v4-flash", "deepseek-v4-pro",
|
|
1149
|
+
"mimo-v2-pro", "mimo-v2.5-pro",
|
|
1150
|
+
"minimax-m2.5", "minimax-m2.7",
|
|
1151
|
+
"qwen3.7-max",
|
|
1152
|
+
],
|
|
1153
|
+
noTemperatureModels: ["kimi-k3", "kimi-k2.7-code", "kimi-k2.7-code-highspeed"],
|
|
1154
|
+
noTopPModels: ["kimi-k3", "kimi-k2.7-code", "kimi-k2.7-code-highspeed"],
|
|
1155
|
+
noPenaltyModels: ["kimi-k3", "kimi-k2.7-code", "kimi-k2.7-code-highspeed"],
|
|
1156
|
+
autoToolChoiceOnlyModels: ["kimi-k2.7-code", "kimi-k2.7-code-highspeed"],
|
|
1157
|
+
// Issue #78: DeepSeek V4 thinking mode requires reasoning_content replay on tool-call turns.
|
|
1158
|
+
preserveReasoningContentModels: ["glm-5.2", "kimi-k3", "kimi-k2.7-code", "kimi-k2.7-code-highspeed", ...DEEPSEEK_THINKING_MODELS],
|
|
1159
|
+
},
|
|
1160
|
+
{
|
|
1161
|
+
id: "neuralwatt",
|
|
1162
|
+
label: "Neuralwatt Cloud",
|
|
1163
|
+
adapter: "openai-chat",
|
|
1164
|
+
baseUrl: "https://api.neuralwatt.com/v1",
|
|
1165
|
+
authKind: "key",
|
|
1166
|
+
dashboardUrl: "https://portal.neuralwatt.com",
|
|
1167
|
+
defaultModel: "glm-5.2",
|
|
1168
|
+
// 2026-07-10 live /v1/models: K2.5 rows were removed and GLM-5.2 short variants added.
|
|
1169
|
+
// Evidence: devlog/_plan/260710_provider_hardening/003_research_aggregators.md and https://api.neuralwatt.com/v1/models.
|
|
1170
|
+
models: [
|
|
1171
|
+
"glm-5.2", "glm-5.2-fast", "glm-5.2-short", "glm-5.2-short-fast",
|
|
1172
|
+
"kimi-k2.6", "kimi-k2.6-fast",
|
|
1173
|
+
"kimi-k2.7-code",
|
|
1174
|
+
"qwen3.5-397b", "qwen3.5-397b-fast", "qwen3.6-35b", "qwen3.6-35b-fast",
|
|
1175
|
+
],
|
|
1176
|
+
// Neuralwatt's /v1/models metadata is authoritative; these static hints are the offline fallback.
|
|
1177
|
+
modelReasoningEfforts: {
|
|
1178
|
+
"glm-5.2": ZAI_GLM_52_REASONING_EFFORTS,
|
|
1179
|
+
"glm-5.2-fast": [],
|
|
1180
|
+
"glm-5.2-short": ZAI_GLM_52_REASONING_EFFORTS,
|
|
1181
|
+
"glm-5.2-short-fast": [],
|
|
1182
|
+
"kimi-k2.6": [],
|
|
1183
|
+
"kimi-k2.6-fast": [],
|
|
1184
|
+
"kimi-k2.7-code": [],
|
|
1185
|
+
// Qwen3.x uses thinking_budget, NOT graded reasoning_effort; the adapter maps the five
|
|
1186
|
+
// Codex picker levels onto budget fractions.
|
|
1187
|
+
"qwen3.5-397b": THINKING_BUDGET_EFFORTS,
|
|
1188
|
+
"qwen3.5-397b-fast": [],
|
|
1189
|
+
"qwen3.6-35b": THINKING_BUDGET_EFFORTS,
|
|
1190
|
+
"qwen3.6-35b-fast": [],
|
|
1191
|
+
},
|
|
1192
|
+
thinkingBudgetModels: THINKING_BUDGET_MODELS,
|
|
1193
|
+
noReasoningModels: ["glm-5.2-fast", "glm-5.2-short-fast", "kimi-k2.6-fast", "qwen3.5-397b-fast", "qwen3.6-35b-fast"],
|
|
1194
|
+
noVisionModels: ["glm-5.2", "glm-5.2-fast", "glm-5.2-short", "glm-5.2-short-fast", "qwen3.5-397b", "qwen3.5-397b-fast"],
|
|
1195
|
+
noTemperatureModels: ["kimi-k2.7-code"],
|
|
1196
|
+
noTopPModels: ["kimi-k2.7-code"],
|
|
1197
|
+
noPenaltyModels: ["kimi-k2.7-code"],
|
|
1198
|
+
autoToolChoiceOnlyModels: ["kimi-k2.7-code"],
|
|
1199
|
+
preserveReasoningContentModels: NEURALWATT_REASONING_HISTORY_MODELS,
|
|
1200
|
+
},
|
|
1201
|
+
{
|
|
1202
|
+
id: "openrouter",
|
|
1203
|
+
label: "OpenRouter",
|
|
1204
|
+
adapter: "openai-chat",
|
|
1205
|
+
baseUrl: "https://openrouter.ai/api/v1",
|
|
1206
|
+
authKind: "key",
|
|
1207
|
+
featured: true,
|
|
1208
|
+
dashboardUrl: "https://openrouter.ai/keys",
|
|
1209
|
+
jawcodeBundle: "openrouter",
|
|
1210
|
+
models: ["anthropic/claude-sonnet-5", ...OPENROUTER_GPT56_MODELS],
|
|
1211
|
+
modelContextWindows: {
|
|
1212
|
+
"anthropic/claude-sonnet-5": 1_000_000,
|
|
1213
|
+
...OPENROUTER_GPT56_CONTEXT_WINDOWS,
|
|
1214
|
+
},
|
|
1215
|
+
// OpenRouter publishes a nested reasoning capability object from /models and accepts the
|
|
1216
|
+
// unified `reasoning: { enabled, effort }` request shape across routed model families.
|
|
1217
|
+
reasoningMetadataFormat: "openrouter",
|
|
1218
|
+
reasoningWireFormat: "gateway-object",
|
|
1219
|
+
},
|
|
1220
|
+
{
|
|
1221
|
+
// Primary sources checked 2026-08-02:
|
|
1222
|
+
// - docs.cline.bot/getting-started/clinepass publishes this exact catalog and explicitly
|
|
1223
|
+
// authorizes using the full slugs through Cline's external API.
|
|
1224
|
+
// - docs.cline.bot/api/chat-completions and /api/errors define the endpoint, reasoning delta,
|
|
1225
|
+
// and choice-scoped mid-stream error contract.
|
|
1226
|
+
// - Cline's official catalog source resolves per-model capabilities through OpenRouter data;
|
|
1227
|
+
// the static context/modality snapshot below was cross-checked against that catalog.
|
|
1228
|
+
// - cline.bot/tos identifies Cline Bot Inc. as the operator. Maintenance owner: @lidge-jun.
|
|
1229
|
+
id: "cline-pass",
|
|
1230
|
+
label: "ClinePass",
|
|
1231
|
+
adapter: "openai-chat",
|
|
1232
|
+
baseUrl: "https://api.cline.bot/api/v1",
|
|
1233
|
+
authKind: "key",
|
|
1234
|
+
dashboardUrl: "https://app.cline.bot",
|
|
1235
|
+
defaultModel: "cline-pass/kimi-k3",
|
|
1236
|
+
models: CLINE_PASS_MODELS,
|
|
1237
|
+
modelContextWindows: CLINE_PASS_MODEL_CONTEXT_WINDOWS,
|
|
1238
|
+
modelInputModalities: CLINE_PASS_MODEL_INPUT_MODALITIES,
|
|
1239
|
+
noVisionModels: CLINE_PASS_TEXT_ONLY_MODELS,
|
|
1240
|
+
// Only low and the `reasoning: { enabled, effort }` request shape have been accepted by a live
|
|
1241
|
+
// ClinePass request. Neither wire detail is currently documented, so clamp higher Codex
|
|
1242
|
+
// requests to the verified tier until the gateway documents or is live-probed more broadly.
|
|
1243
|
+
reasoningEfforts: ["low"],
|
|
1244
|
+
reasoningWireFormat: "gateway-object",
|
|
1245
|
+
preserveCustomDestination: true,
|
|
1246
|
+
note: "ClinePass subscription API. Uses a Cline API key and the full cline-pass/<model> upstream slug; quota is shared across the account's rolling 5-hour, weekly, and monthly limits.",
|
|
1247
|
+
},
|
|
1248
|
+
// Cline API (usage-billing): OpenAI-compatible Chat Completions. Model IDs follow the
|
|
1249
|
+
// OpenRouter-style `provider/model` convention. Live /models discovery is key-gated (401
|
|
1250
|
+
// without auth), so the static seed is the cold-start fallback. Evidence: docs.cline.bot/api/*.
|
|
1251
|
+
{
|
|
1252
|
+
id: "cline",
|
|
1253
|
+
label: "Cline",
|
|
1254
|
+
adapter: "openai-chat",
|
|
1255
|
+
baseUrl: "https://api.cline.bot/api/v1",
|
|
1256
|
+
authKind: "key",
|
|
1257
|
+
dashboardUrl: "https://app.cline.bot",
|
|
1258
|
+
liveModels: true,
|
|
1259
|
+
defaultModel: "anthropic/claude-sonnet-4-6",
|
|
1260
|
+
models: [
|
|
1261
|
+
"anthropic/claude-sonnet-4-6",
|
|
1262
|
+
"openai/gpt-4o",
|
|
1263
|
+
"google/gemini-2.5-pro",
|
|
1264
|
+
"deepseek/deepseek-chat",
|
|
1265
|
+
"minimax/minimax-m2.5",
|
|
1266
|
+
],
|
|
1267
|
+
preserveCustomDestination: true,
|
|
1268
|
+
note: "Cline usage-billing API: one key, 100+ models, OpenRouter-style ids. Promotional free models are IDE/CLI-only per Cline docs; minimax/minimax-m2.5 is the documented API free experimentation model.",
|
|
1269
|
+
},
|
|
1270
|
+
{
|
|
1271
|
+
// OrcaRouter: OpenAI-compatible adaptive router (api.orcarouter.ai). Model ids are
|
|
1272
|
+
// vendor-namespaced (`<vendor>/<model>`) and pass through to the upstream as-is.
|
|
1273
|
+
// The default pins a tool-capable model; the adaptive `orcarouter/auto` router is also
|
|
1274
|
+
// selectable. Live-verified 2026-07-20: /v1/chat/completions accepts the `tools` field
|
|
1275
|
+
// and routes to a function-calling-capable upstream.
|
|
1276
|
+
id: "orcarouter", label: "OrcaRouter", adapter: "openai-chat", baseUrl: "https://api.orcarouter.ai/v1",
|
|
1277
|
+
authKind: "key", dashboardUrl: "https://www.orcarouter.ai/console",
|
|
1278
|
+
defaultModel: "openai/gpt-5.5",
|
|
1279
|
+
models: [
|
|
1280
|
+
"openai/gpt-5.5",
|
|
1281
|
+
"anthropic/claude-opus-4.8",
|
|
1282
|
+
"google/gemini-3.5-flash",
|
|
1283
|
+
"deepseek/deepseek-v4-pro",
|
|
1284
|
+
"orcarouter/auto",
|
|
1285
|
+
],
|
|
1286
|
+
// Text-only models → the vision sidecar describes images instead.
|
|
1287
|
+
noVisionModels: ["deepseek/deepseek-v4-pro"],
|
|
1288
|
+
// Reasoning/temperature behavior verified live 2026-07-20 against api.orcarouter.ai:
|
|
1289
|
+
// - openai/gpt-5.5 accepts reasoning_effort none|low|medium|high|xhigh but rejects `max` (400),
|
|
1290
|
+
// so advertise up to xhigh and let mapReasoningEffort clamp a `max`/`ultra` request to xhigh.
|
|
1291
|
+
// - deepseek/deepseek-v4-pro mirrors the direct-DeepSeek wiring (thinking-effort map +
|
|
1292
|
+
// reasoning_content history replay) so the namespaced selection behaves identically.
|
|
1293
|
+
// - temperature is accepted by every seeded model (gpt-5.5, claude-opus-4.8, deepseek-v4-pro all
|
|
1294
|
+
// returned 200), so no noTemperatureModels entry is warranted here.
|
|
1295
|
+
modelReasoningEfforts: {
|
|
1296
|
+
"openai/gpt-5.5": ["low", "medium", "high", "xhigh"],
|
|
1297
|
+
"deepseek/deepseek-v4-pro": deepseekThinkingEffortsFor("deepseek/deepseek-v4-pro"),
|
|
1298
|
+
},
|
|
1299
|
+
modelReasoningEffortMap: { "deepseek/deepseek-v4-pro": deepseekReasoningMapFor("deepseek/deepseek-v4-pro") },
|
|
1300
|
+
preserveReasoningContentModels: ["deepseek/deepseek-v4-pro"],
|
|
1301
|
+
note: "OpenAI-compatible adaptive router. Default is a tool-capable model; orcarouter/auto (adaptive routing) is also selectable. Full catalog: https://www.orcarouter.ai/models",
|
|
1302
|
+
},
|
|
1303
|
+
{
|
|
1304
|
+
// BizRouter: Korean enterprise LLM gateway (api.bizrouter.ai). Model ids are
|
|
1305
|
+
// vendor-namespaced (`<vendor>/<model>`) and pass through to the upstream as-is.
|
|
1306
|
+
// Live-verified 2026-07-24: /v1/chat/completions accepts the `tools` field and
|
|
1307
|
+
// streams, and GET /v1/models returns the per-API-key allowed catalog in the
|
|
1308
|
+
// OpenAI list shape, so live model discovery narrows to what the key can use.
|
|
1309
|
+
id: "bizrouter", label: "BizRouter", adapter: "openai-chat", baseUrl: "https://api.bizrouter.ai/v1",
|
|
1310
|
+
authKind: "key", dashboardUrl: "https://bizrouter.ai/settings/keys",
|
|
1311
|
+
defaultModel: "openai/gpt-5.6-sol",
|
|
1312
|
+
models: ["openai/gpt-5.6-sol", "anthropic/claude-sonnet-5", "google/gemini-3.5-flash"],
|
|
1313
|
+
note: "Korean enterprise LLM gateway. Per-key allowed models are discovered live from /v1/models. Full catalog: https://bizrouter.ai/models",
|
|
1314
|
+
},
|
|
1315
|
+
{ id: "groq", label: "Groq", adapter: "openai-chat", baseUrl: "https://api.groq.com/openai/v1", authKind: "key", featured: true, dashboardUrl: "https://console.groq.com/keys" },
|
|
1316
|
+
// 2026-07-10 Gemini API refresh: Tier-2 ai.google.dev evidence recorded in
|
|
1317
|
+
// devlog/_plan/260710_provider_hardening/001_research_frontier.md.
|
|
1318
|
+
{
|
|
1319
|
+
id: "google", label: "Google Gemini", adapter: "google", baseUrl: "https://generativelanguage.googleapis.com", authKind: "key", featured: true,
|
|
1320
|
+
dashboardUrl: "https://aistudio.google.com/apikey", defaultModel: "gemini-3.5-flash", models: ["gemini-3.6-flash", "gemini-3.5-flash", "gemini-3.5-flash-lite", "gemini-3.1-pro-preview"],
|
|
1321
|
+
modelContextWindows: { "gemini-3.6-flash": 1_048_576, "gemini-3.5-flash": 1_000_000, "gemini-3.5-flash-lite": 1_048_576 },
|
|
1322
|
+
modelInputModalities: { "gemini-3.6-flash": ["text", "image"], "gemini-3.5-flash-lite": ["text", "image"] },
|
|
1323
|
+
modelReasoningEfforts: {
|
|
1324
|
+
"gemini-3.6-flash": ["minimal", "low", "medium", "high"],
|
|
1325
|
+
"gemini-3.5-flash": ["minimal", "low", "medium", "high"],
|
|
1326
|
+
"gemini-3.1-pro-preview": ["low", "medium", "high"],
|
|
1327
|
+
},
|
|
1328
|
+
jawcodeBundle: "google", extraMetadataAliases: ["gemini"],
|
|
1329
|
+
},
|
|
1330
|
+
// 2026-07-10: defaultModel is frozen pending Vertex-specific Tier-2 evidence; Gemini API
|
|
1331
|
+
// evidence from ai.google.dev does not establish Vertex publisher availability.
|
|
1332
|
+
{ id: "google-vertex", label: "Google Vertex AI", adapter: "google", baseUrl: "https://aiplatform.googleapis.com", authKind: "key", dashboardUrl: "https://console.cloud.google.com/vertex-ai", defaultModel: "gemini-3-pro", googleMode: "vertex", jawcodeBundle: "google", extraMetadataAliases: ["gemini-vertex"] },
|
|
1333
|
+
{ id: "google-antigravity", label: "Google Antigravity", adapter: "google", baseUrl: "https://daily-cloudcode-pa.googleapis.com", authKind: "oauth", dashboardUrl: "https://antigravity.google", models: ANTIGRAVITY_MODELS, liveModels: true, defaultModel: "gemini-3.6-flash", modelContextWindows: ANTIGRAVITY_MODEL_CONTEXT_WINDOWS, modelInputModalities: ANTIGRAVITY_MODEL_INPUT_MODALITIES, modelReasoningEfforts: ANTIGRAVITY_MODEL_EFFORTS, googleMode: "cloud-code-assist", jawcodeBundle: "google", extraMetadataAliases: ["antigravity", "gemini-antigravity"] },
|
|
1334
|
+
{ id: "azure-openai", label: "Azure OpenAI", adapter: "azure-openai", baseUrl: "https://{resource}.openai.azure.com/openai", authKind: "key", featured: true, dashboardUrl: "https://portal.azure.com" },
|
|
1335
|
+
{ id: "ollama", label: "Ollama (local)", adapter: "openai-chat", baseUrl: "http://localhost:11434/v1", authKind: "local", allowPrivateNetworkByDefault: true, allowBaseUrlOverride: true, featured: true, note: "Local — key usually blank" },
|
|
1336
|
+
{ id: "vllm", label: "vLLM (local)", adapter: "openai-chat", baseUrl: "http://localhost:8000/v1", authKind: "local", allowPrivateNetworkByDefault: true, allowBaseUrlOverride: true, featured: true, note: "Local — key usually blank" },
|
|
1337
|
+
{ id: "lm-studio", label: "LM Studio (local)", adapter: "openai-chat", baseUrl: "http://localhost:1234/v1", authKind: "local", allowPrivateNetworkByDefault: true, allowBaseUrlOverride: true, featured: true, note: "Local — no key needed" },
|
|
1338
|
+
{
|
|
1339
|
+
id: "deepseek",
|
|
1340
|
+
label: "DeepSeek",
|
|
1341
|
+
baseUrl: "https://api.deepseek.com",
|
|
1342
|
+
adapter: "openai-chat",
|
|
1343
|
+
authKind: "key",
|
|
1344
|
+
dashboardUrl: "https://platform.deepseek.com/api_keys",
|
|
1345
|
+
// Route DeepSeek's own catalog bundle so routed rebuilds restore the official
|
|
1346
|
+
// context window from the vendored model-metadata bundle instead of falling
|
|
1347
|
+
// back to the 128k strict-fields default (scripts/model-metadata.source.json,
|
|
1348
|
+
// verified 2026-08-08).
|
|
1349
|
+
jawcodeBundle: "deepseek",
|
|
1350
|
+
// deepseek-chat/deepseek-reasoner were deprecated upstream on 2026-07-24 15:59 UTC;
|
|
1351
|
+
// official identifiers are now deepseek-v4-flash / deepseek-v4-pro. They stay in
|
|
1352
|
+
// the list only as compatibility aliases so existing saved configs and requests
|
|
1353
|
+
// keep validating and routing (they previously mapped to v4-flash; devlog
|
|
1354
|
+
// _fin/260710_provider_hardening/002_research_cn.md). The current offerings are
|
|
1355
|
+
// the V4 ids — defaultModel and the model-specific wiring above use them.
|
|
1356
|
+
models: ["deepseek-chat", "deepseek-reasoner", ...DEEPSEEK_THINKING_MODELS],
|
|
1357
|
+
defaultModel: "deepseek-v4-flash",
|
|
1358
|
+
// Official DeepSeek Codex setup (codex-deepseek-setup.sh) advertises 1,048,576
|
|
1359
|
+
// for both V4 models; the older 1,000,000 figure was a rounded approximation.
|
|
1360
|
+
modelContextWindows: { "deepseek-v4-flash": 1_048_576, "deepseek-v4-pro": 1_048_576 },
|
|
1361
|
+
// DeepSeek documents V4-Flash as a native Responses API model adapted for Codex. The
|
|
1362
|
+
// API id is `deepseek-v4-flash`; `DeepSeek-V4-Flash-0731` is a release/version label.
|
|
1363
|
+
modelWireDefaults: {
|
|
1364
|
+
// Codex speaks Responses natively and DeepSeek ships a Codex-compatible
|
|
1365
|
+
// apply_patch tool on that wire, so a Responses inbound goes straight out with
|
|
1366
|
+
// no translation. Claude Code and OpenAI-compatible clients keep the
|
|
1367
|
+
// provider-wide Chat wire: DeepSeek serves Chat Completions natively too, so
|
|
1368
|
+
// translating them into Responses would add a hop onto our newest upstream path
|
|
1369
|
+
// for no gain.
|
|
1370
|
+
"deepseek-v4-flash": { wire: "openai-responses", inbound: ["responses"] },
|
|
1371
|
+
},
|
|
1372
|
+
// The #875-era bounded-JSON force (`modelResponsesUpstreamStreaming`) is retired
|
|
1373
|
+
// for this entry: the official guide documents a `response.completed` /
|
|
1374
|
+
// `response.incomplete` / `response.failed` terminal with NO `data: [DONE]`
|
|
1375
|
+
// sentinel, and live probes (2026-08-07, including the tool-result replay shape
|
|
1376
|
+
// that originally stalled) close on the terminal. The relay's terminal boundary
|
|
1377
|
+
// (src/server/relay.ts) already cuts the stream at that event and synthesizes
|
|
1378
|
+
// `[DONE]`, so forcing stream:false only delayed every byte until generation
|
|
1379
|
+
// finished (28-46 s of silence on long turns). The registry knob itself remains
|
|
1380
|
+
// for providers that need it — re-adding one line here restores the old policy.
|
|
1381
|
+
// Evidence: https://api-docs.deepseek.com/guides/responses_api/ +
|
|
1382
|
+
// devlog/_plan/260807_deepseek_responses_streaming/000_plan.md.
|
|
1383
|
+
// DeepSeek's Responses route emits bare UUID item ids, which leave Codex
|
|
1384
|
+
// clients stuck on an uncommitted turn (#938). Client-facing only — raw
|
|
1385
|
+
// continuation snapshots keep the upstream ids.
|
|
1386
|
+
responsesItemIdRepair: { repairInvalidIds: true, repairMissingTerminalIds: true },
|
|
1387
|
+
// DeepSeek's Responses route is `POST /responses` with no `/v1` segment. Without
|
|
1388
|
+
// this the passthrough adapter falls back to its legacy `/v1/responses`
|
|
1389
|
+
// construction and the wire above can never route.
|
|
1390
|
+
// Evidence: https://api-docs.deepseek.com/api/create-response/
|
|
1391
|
+
responsesPath: "/responses",
|
|
1392
|
+
// DeepSeek's Responses reference does not list `service_tier`; unsupported
|
|
1393
|
+
// parameters are documented as silently ignored, but the fail-closed policy
|
|
1394
|
+
// strips the field rather than forwarding a knob the upstream never asked for.
|
|
1395
|
+
supportsServiceTier: false,
|
|
1396
|
+
// DeepSeek's Responses compatibility guide accepts plaintext reasoning items and
|
|
1397
|
+
// merges them into the adjacent assistant message, so replayed reasoning must
|
|
1398
|
+
// not be blanked the way the ChatGPT backend requires. (Whether the Responses
|
|
1399
|
+
// route REQUIRES replay on tool-call continuations is an inference from the
|
|
1400
|
+
// Chat Thinking-Mode docs, not a confirmed Responses contract.)
|
|
1401
|
+
preserveResponsesReasoningContent: true,
|
|
1402
|
+
// "The API is stateless: responses and conversations are not stored on the
|
|
1403
|
+
// server." https://api-docs.deepseek.com/api/create-response/
|
|
1404
|
+
statelessResponses: true,
|
|
1405
|
+
/* [Decision Log]
|
|
1406
|
+
- 목적: DeepSeek V4 thinking mode multi-turn/tool-call requests must replay prior assistant reasoning_content.
|
|
1407
|
+
- 대안 분석: Globally preserve reasoning_content for all OpenAI-compatible models; preserve it for legacy deepseek-reasoner too; mark only V4 thinking models in registry metadata.
|
|
1408
|
+
- 선택 근거: DeepSeek V4 thinking mode requires history replay, while older DeepSeek reasoner has different compatibility rules. A model-scoped registry flag fixes built-in and stale saved configs without broad provider regressions.
|
|
1409
|
+
*/
|
|
1410
|
+
modelReasoningEfforts: Object.fromEntries(DEEPSEEK_THINKING_MODELS.map(id => [id, deepseekThinkingEffortsFor(id)])),
|
|
1411
|
+
modelReasoningEffortMap: Object.fromEntries(DEEPSEEK_THINKING_MODELS.map(id => [id, deepseekReasoningMapFor(id)])),
|
|
1412
|
+
modelSupportsReasoningSummaries: Object.fromEntries(DEEPSEEK_THINKING_MODELS.map(id => [id, true])),
|
|
1413
|
+
preserveReasoningContentModels: DEEPSEEK_THINKING_MODELS,
|
|
1414
|
+
// Issue #88: every DeepSeek API model is text-only input (no image support upstream) — the
|
|
1415
|
+
// vision sidecar describes attached images for them, and the catalog advertises image input
|
|
1416
|
+
// on their behalf (same treatment as opencode-go's DeepSeek V4 entries above).
|
|
1417
|
+
noVisionModels: ["deepseek-chat", "deepseek-reasoner", ...DEEPSEEK_THINKING_MODELS],
|
|
1418
|
+
},
|
|
1419
|
+
// llama-3.3-70b was deprecated by Cerebras on 2026-02-16. Evidence: devlog/_plan/260710_provider_hardening/003_research_aggregators.md.
|
|
1420
|
+
{ id: "cerebras", label: "Cerebras", baseUrl: "https://api.cerebras.ai/v1", adapter: "openai-chat", authKind: "key", dashboardUrl: "https://cloud.cerebras.ai/platform/apikeys", defaultModel: "gpt-oss-120b" },
|
|
1421
|
+
{
|
|
1422
|
+
id: "deepinfra",
|
|
1423
|
+
label: "DeepInfra",
|
|
1424
|
+
baseUrl: "https://api.deepinfra.com/v1/openai",
|
|
1425
|
+
adapter: "openai-chat",
|
|
1426
|
+
authKind: "key",
|
|
1427
|
+
dashboardUrl: "https://deepinfra.com/dash/api_keys",
|
|
1428
|
+
liveModels: true,
|
|
1429
|
+
preserveCustomDestination: true,
|
|
1430
|
+
modelDiscovery: {
|
|
1431
|
+
// DeepInfra documents the OpenAI model catalog outside the chat-compatible `/v1/openai`
|
|
1432
|
+
// namespace, so keep this destination registry-owned instead of deriving it from baseUrl.
|
|
1433
|
+
url: "https://api.deepinfra.com/v1/models",
|
|
1434
|
+
maxResponseBytes: 512 * 1024,
|
|
1435
|
+
maxModels: 512,
|
|
1436
|
+
filter: {
|
|
1437
|
+
allOf: [{ path: ["metadata", "tags"], containsAny: ["chat"] }],
|
|
1438
|
+
},
|
|
1439
|
+
},
|
|
1440
|
+
note: "OpenAI-compatible chat models only; live discovery excludes non-chat rows from DeepInfra's mixed model catalog.",
|
|
1441
|
+
},
|
|
1442
|
+
{
|
|
1443
|
+
id: "hyperbolic",
|
|
1444
|
+
label: "Hyperbolic",
|
|
1445
|
+
baseUrl: "https://api.hyperbolic.xyz/v1",
|
|
1446
|
+
adapter: "openai-chat",
|
|
1447
|
+
authKind: "key",
|
|
1448
|
+
dashboardUrl: "https://app.hyperbolic.ai",
|
|
1449
|
+
liveModels: true,
|
|
1450
|
+
preserveCustomDestination: true,
|
|
1451
|
+
modelDiscovery: {
|
|
1452
|
+
path: "models",
|
|
1453
|
+
maxResponseBytes: 256 * 1024,
|
|
1454
|
+
maxModels: 256,
|
|
1455
|
+
},
|
|
1456
|
+
note: "Serverless text and vision-language chat models only; Hyperbolic's separate image, audio, and GPU endpoints are out of scope.",
|
|
1457
|
+
},
|
|
1458
|
+
{
|
|
1459
|
+
// Primary sources checked 2026-08-03:
|
|
1460
|
+
// - docs.nscale.com documents the production OpenAI-compatible endpoint, bearer service
|
|
1461
|
+
// tokens, /v1/models, and a tool-calling request using this exact Llama model id.
|
|
1462
|
+
// - nscale.com/policies/terms-conditions identifies Nscale AS as the service operator and
|
|
1463
|
+
// covers customers using its public-cloud inference offering. Maintainer: @olddonkey;
|
|
1464
|
+
// no affiliation with Nscale.
|
|
1465
|
+
id: "nscale",
|
|
1466
|
+
label: "Nscale Serverless Inference",
|
|
1467
|
+
baseUrl: "https://inference.api.nscale.com/v1",
|
|
1468
|
+
adapter: "openai-chat",
|
|
1469
|
+
authKind: "key",
|
|
1470
|
+
dashboardUrl: "https://console.nscale.com",
|
|
1471
|
+
defaultModel: "meta-llama/Llama-3.1-8B-Instruct",
|
|
1472
|
+
models: ["meta-llama/Llama-3.1-8B-Instruct"],
|
|
1473
|
+
liveModels: true,
|
|
1474
|
+
preserveCustomDestination: true,
|
|
1475
|
+
// Nscale documents tools but not parallel tool calls. Keep requests serialized.
|
|
1476
|
+
parallelToolCalls: false,
|
|
1477
|
+
// The API schema accepts reasoning_effort, but does not publish per-model tiers.
|
|
1478
|
+
reasoningEfforts: [],
|
|
1479
|
+
modelDiscovery: {
|
|
1480
|
+
path: "models",
|
|
1481
|
+
maxResponseBytes: 256 * 1024,
|
|
1482
|
+
maxModels: 256,
|
|
1483
|
+
filter: {
|
|
1484
|
+
// Nscale's catalog mixes chat, image, and embedding rows without a modality field.
|
|
1485
|
+
// Admit only the exact model used in its official tool-calling API example.
|
|
1486
|
+
allOf: [{ path: ["id"], equalsAny: ["meta-llama/Llama-3.1-8B-Instruct"] }],
|
|
1487
|
+
},
|
|
1488
|
+
},
|
|
1489
|
+
note: "Serverless OpenAI-compatible inference. Live discovery admits only the tool-capable model established by Nscale's official API example; other mixed-catalog rows remain hidden pending equivalent evidence.",
|
|
1490
|
+
},
|
|
1491
|
+
{
|
|
1492
|
+
// Primary sources checked 2026-08-03:
|
|
1493
|
+
// - docs.vultr.com documents the fixed OpenAI-compatible base URL, per-subscription bearer
|
|
1494
|
+
// key, /v1/models, and states that tool calling is currently limited to kimi-k2-instruct.
|
|
1495
|
+
// - Vultr's official properties identify VULTR as a The Constant Company, LLC trademark and
|
|
1496
|
+
// document customer API integrations. Maintainer: @olddonkey; no affiliation with Vultr.
|
|
1497
|
+
id: "vultr",
|
|
1498
|
+
label: "Vultr Serverless Inference",
|
|
1499
|
+
baseUrl: "https://api.vultrinference.com/v1",
|
|
1500
|
+
adapter: "openai-chat",
|
|
1501
|
+
authKind: "key",
|
|
1502
|
+
dashboardUrl: "https://my.vultr.com",
|
|
1503
|
+
defaultModel: "kimi-k2-instruct",
|
|
1504
|
+
models: ["kimi-k2-instruct"],
|
|
1505
|
+
liveModels: true,
|
|
1506
|
+
preserveCustomDestination: true,
|
|
1507
|
+
parallelToolCalls: false,
|
|
1508
|
+
reasoningEfforts: [],
|
|
1509
|
+
modelDiscovery: {
|
|
1510
|
+
path: "models",
|
|
1511
|
+
maxResponseBytes: 256 * 1024,
|
|
1512
|
+
maxModels: 256,
|
|
1513
|
+
filter: {
|
|
1514
|
+
// Vultr explicitly limits tool calling to this model. A coding agent must not select
|
|
1515
|
+
// another chat model that cannot complete its tool loop.
|
|
1516
|
+
allOf: [{ path: ["id"], equalsAny: ["kimi-k2-instruct"] }],
|
|
1517
|
+
},
|
|
1518
|
+
},
|
|
1519
|
+
note: "Serverless Inference subscription API. Live discovery exposes only kimi-k2-instruct because Vultr documents it as the sole tool-calling model.",
|
|
1520
|
+
},
|
|
1521
|
+
{
|
|
1522
|
+
id: "baseten",
|
|
1523
|
+
label: "Baseten Model APIs",
|
|
1524
|
+
baseUrl: "https://inference.baseten.co/v1",
|
|
1525
|
+
adapter: "openai-chat",
|
|
1526
|
+
authKind: "key",
|
|
1527
|
+
dashboardUrl: "https://app.baseten.co/settings/api_keys",
|
|
1528
|
+
liveModels: true,
|
|
1529
|
+
preserveCustomDestination: true,
|
|
1530
|
+
// Baseten's Chat Completions contract documents parallel_tool_calls as default-on.
|
|
1531
|
+
parallelToolCalls: true,
|
|
1532
|
+
// Baseten says models outside its reasoning table do not support reasoning. Keep
|
|
1533
|
+
// unknown/new live slugs conservative until an official-docs registry refresh proves it.
|
|
1534
|
+
reasoningEfforts: [],
|
|
1535
|
+
modelReasoningEfforts: BASETEN_MODEL_REASONING_EFFORTS,
|
|
1536
|
+
modelReasoningEffortMap: BASETEN_MODEL_REASONING_EFFORT_MAP,
|
|
1537
|
+
modelDefaultReasoningEfforts: BASETEN_MODEL_DEFAULT_REASONING_EFFORTS,
|
|
1538
|
+
modelInputModalities: BASETEN_MODEL_INPUT_MODALITIES,
|
|
1539
|
+
modelDiscovery: {
|
|
1540
|
+
path: "models",
|
|
1541
|
+
maxResponseBytes: 1_048_576,
|
|
1542
|
+
maxModels: 256,
|
|
1543
|
+
},
|
|
1544
|
+
note: "Shared Model APIs only (personal API key, or team key with Call Model APIs access); dedicated Truss predict endpoints are outside this preset.",
|
|
1545
|
+
},
|
|
1546
|
+
{
|
|
1547
|
+
id: "commandcode",
|
|
1548
|
+
label: "Command Code - API",
|
|
1549
|
+
adapter: "openai-chat",
|
|
1550
|
+
baseUrl: "https://api.commandcode.ai/provider/v1",
|
|
1551
|
+
authKind: "key",
|
|
1552
|
+
dashboardUrl: "https://commandcode.ai/studio/",
|
|
1553
|
+
liveModels: true,
|
|
1554
|
+
preserveCustomDestination: true,
|
|
1555
|
+
defaultModel: "deepseek/deepseek-v4-flash",
|
|
1556
|
+
// The default is also the cold-start seed: live discovery failure must not empty the catalog
|
|
1557
|
+
// for a freshly configured provider with no stale cache (issue #308 pattern).
|
|
1558
|
+
models: ["deepseek/deepseek-v4-flash"],
|
|
1559
|
+
// The public model catalog is unauthenticated, so a Bearer probe cannot prove key validity.
|
|
1560
|
+
apiKeyValidation: "unknown",
|
|
1561
|
+
// The public catalog reports ids/context windows only; no trustworthy reasoning contract.
|
|
1562
|
+
reasoningEfforts: [],
|
|
1563
|
+
modelDiscovery: {
|
|
1564
|
+
path: "models",
|
|
1565
|
+
maxResponseBytes: 256 * 1024,
|
|
1566
|
+
maxModels: 256,
|
|
1567
|
+
},
|
|
1568
|
+
// Verified 2026-08-03: public /provider/v1/models returns 51 rows; /chat/completions returns
|
|
1569
|
+
// 401 UNAUTHORIZED without a Bearer key. Primary source: https://commandcode.ai/docs/provider.
|
|
1570
|
+
note: "Command Code Provider API (OpenAI-compatible); API access requires the Provider plan. Use `rmx login command-code` for OAuth account login (imports an existing local Command Code CLI credential when present). Docs: https://commandcode.ai/docs/provider.",
|
|
1571
|
+
},
|
|
1572
|
+
{
|
|
1573
|
+
id: "sambanova",
|
|
1574
|
+
label: "SambaNova Cloud",
|
|
1575
|
+
baseUrl: "https://api.sambanova.ai/v1",
|
|
1576
|
+
adapter: "openai-chat",
|
|
1577
|
+
authKind: "key",
|
|
1578
|
+
dashboardUrl: "https://cloud.sambanova.ai/apis",
|
|
1579
|
+
liveModels: true,
|
|
1580
|
+
preserveCustomDestination: true,
|
|
1581
|
+
apiKeyValidation: "unknown",
|
|
1582
|
+
// SambaNova documents this request field but does not yet support parallel function calls.
|
|
1583
|
+
parallelToolCalls: false,
|
|
1584
|
+
// The public catalog does not report a trustworthy per-model reasoning contract.
|
|
1585
|
+
reasoningEfforts: [],
|
|
1586
|
+
modelDiscovery: {
|
|
1587
|
+
path: "models",
|
|
1588
|
+
maxResponseBytes: 128 * 1024,
|
|
1589
|
+
maxModels: 128,
|
|
1590
|
+
},
|
|
1591
|
+
note: "SambaNova Cloud text-generation models only; private SambaStudio deployment endpoints are outside this preset.",
|
|
1592
|
+
},
|
|
1593
|
+
{
|
|
1594
|
+
id: "nebius",
|
|
1595
|
+
label: "Nebius Token Factory",
|
|
1596
|
+
baseUrl: "https://api.tokenfactory.nebius.com/v1",
|
|
1597
|
+
adapter: "openai-chat",
|
|
1598
|
+
authKind: "key",
|
|
1599
|
+
dashboardUrl: "https://tokenfactory.nebius.com",
|
|
1600
|
+
liveModels: true,
|
|
1601
|
+
preserveCustomDestination: true,
|
|
1602
|
+
// The public tools guide documents single function selection, not parallel tool calls.
|
|
1603
|
+
parallelToolCalls: false,
|
|
1604
|
+
// Missing reasoning metadata must not promote a model to Codex's full fallback ladder.
|
|
1605
|
+
reasoningEfforts: [],
|
|
1606
|
+
modelDiscovery: {
|
|
1607
|
+
path: "models",
|
|
1608
|
+
query: { verbose: "true" },
|
|
1609
|
+
maxResponseBytes: 512 * 1024,
|
|
1610
|
+
maxModels: 512,
|
|
1611
|
+
filter: {
|
|
1612
|
+
// Keep rows whose reported architecture output includes text (for example,
|
|
1613
|
+
// text->text or text+image->text); embedding and image-generation rows are excluded.
|
|
1614
|
+
allOf: [{ path: ["architecture", "modality"], containsAny: ["->text"] }],
|
|
1615
|
+
},
|
|
1616
|
+
},
|
|
1617
|
+
note: "Shared Token Factory text-output inference only; live discovery excludes embedding and image-generation rows.",
|
|
1618
|
+
},
|
|
1619
|
+
{
|
|
1620
|
+
id: "digitalocean",
|
|
1621
|
+
label: "DigitalOcean Serverless Inference",
|
|
1622
|
+
baseUrl: "https://inference.do-ai.run/v1",
|
|
1623
|
+
adapter: "openai-chat",
|
|
1624
|
+
authKind: "key",
|
|
1625
|
+
dashboardUrl: "https://cloud.digitalocean.com/model-studio/manage-keys",
|
|
1626
|
+
liveModels: true,
|
|
1627
|
+
preserveCustomDestination: true,
|
|
1628
|
+
// The Chat Completions contract documents function calls but not universal parallel support.
|
|
1629
|
+
parallelToolCalls: false,
|
|
1630
|
+
// Unknown catalog rows must not inherit Codex's full fallback reasoning ladder.
|
|
1631
|
+
reasoningEfforts: [],
|
|
1632
|
+
modelDiscovery: {
|
|
1633
|
+
path: "models",
|
|
1634
|
+
maxResponseBytes: 256 * 1024,
|
|
1635
|
+
maxModels: 256,
|
|
1636
|
+
filter: {
|
|
1637
|
+
allOf: [{ path: ["id"], equalsAny: DIGITALOCEAN_CHAT_COMPLETION_MODELS }],
|
|
1638
|
+
},
|
|
1639
|
+
},
|
|
1640
|
+
note: "Shared Serverless Inference Chat Completions only; agent-specific, dedicated, Responses-only, embedding, and media-generation models are outside this preset.",
|
|
1641
|
+
},
|
|
1642
|
+
{
|
|
1643
|
+
id: "scaleway",
|
|
1644
|
+
label: "Scaleway Generative APIs",
|
|
1645
|
+
baseUrl: "https://api.scaleway.ai/v1",
|
|
1646
|
+
adapter: "openai-chat",
|
|
1647
|
+
authKind: "key",
|
|
1648
|
+
dashboardUrl: "https://console.scaleway.com/generative-api",
|
|
1649
|
+
liveModels: true,
|
|
1650
|
+
freeTier: true,
|
|
1651
|
+
preserveCustomDestination: true,
|
|
1652
|
+
// Parallel support varies by model; avoid advertising it as a provider-wide capability.
|
|
1653
|
+
parallelToolCalls: false,
|
|
1654
|
+
// The generic `/models` rows carry no trustworthy reasoning metadata.
|
|
1655
|
+
reasoningEfforts: [],
|
|
1656
|
+
modelInputModalities: SCALEWAY_MODEL_INPUT_MODALITIES,
|
|
1657
|
+
modelDiscovery: {
|
|
1658
|
+
path: "models",
|
|
1659
|
+
maxResponseBytes: 128 * 1024,
|
|
1660
|
+
maxModels: 128,
|
|
1661
|
+
filter: {
|
|
1662
|
+
allOf: [{ path: ["id"], equalsAny: SCALEWAY_SERVERLESS_CHAT_MODELS }],
|
|
1663
|
+
},
|
|
1664
|
+
},
|
|
1665
|
+
note: "Shared Generative APIs Serverless Chat Completions only; project-qualified and dedicated deployment hosts require a custom provider.",
|
|
1666
|
+
},
|
|
1667
|
+
// FREEZE 2026-07-10: exact serverless ids remain auth-gated/unverified. Evidence: devlog/_plan/260710_provider_hardening/003_research_aggregators.md.
|
|
1668
|
+
{ id: "together", label: "Together", baseUrl: "https://api.together.xyz/v1", adapter: "openai-chat", authKind: "key", dashboardUrl: "https://api.together.xyz/settings/api-keys" },
|
|
1669
|
+
{ id: "fireworks", label: "Fireworks", baseUrl: "https://api.fireworks.ai/inference/v1", adapter: "openai-chat", authKind: "key", dashboardUrl: "https://fireworks.ai/account/api-keys" },
|
|
1670
|
+
{
|
|
1671
|
+
id: "firepass", label: "Fire Pass (Fireworks Kimi)", baseUrl: "https://api.fireworks.ai/inference/v1", adapter: "openai-chat", authKind: "key",
|
|
1672
|
+
dashboardUrl: "https://fireworks.ai/account/api-keys",
|
|
1673
|
+
note: "Model data frozen pending Tier-2 entitlement proof",
|
|
1674
|
+
},
|
|
1675
|
+
{
|
|
1676
|
+
id: "moonshot", label: "Moonshot (Kimi API)", baseUrl: "https://api.moonshot.ai/v1", adapter: "openai-chat", authKind: "key",
|
|
1677
|
+
dashboardUrl: "https://platform.moonshot.ai/console/api-keys", defaultModel: "kimi-k2.7-code", jawcodeBundle: "moonshot",
|
|
1678
|
+
models: KIMI_API_MODELS,
|
|
1679
|
+
modelContextWindows: KIMI_API_MODEL_CONTEXT_WINDOWS,
|
|
1680
|
+
modelInputModalities: KIMI_API_MODEL_INPUT_MODALITIES,
|
|
1681
|
+
noReasoningModels: KIMI_API_NO_REASONING_MODELS,
|
|
1682
|
+
modelReasoningEfforts: KIMI_API_REASONING_EFFORTS,
|
|
1683
|
+
noTemperatureModels: KIMI_API_MODELS,
|
|
1684
|
+
noTopPModels: KIMI_API_MODELS,
|
|
1685
|
+
noPenaltyModels: KIMI_API_MODELS,
|
|
1686
|
+
autoToolChoiceOnlyModels: ["kimi-k2.7-code", "kimi-k2.7-code-highspeed"],
|
|
1687
|
+
preserveReasoningContentModels: KIMI_API_MODELS,
|
|
1688
|
+
},
|
|
1689
|
+
{ id: "huggingface", label: "Hugging Face", baseUrl: "https://router.huggingface.co/v1", adapter: "openai-chat", authKind: "key", dashboardUrl: "https://huggingface.co/settings/tokens" },
|
|
1690
|
+
// 260715 NIM hardening (issue #126, devlog/_plan/260715_issue126_nim_kimi):
|
|
1691
|
+
// - NIM kimi rejects `parallel_tool_calls: true` with 400 "This model only supports single
|
|
1692
|
+
// tool-calls at once!" (openclaw#37048). NVIDIA's own function-calling docs default the
|
|
1693
|
+
// Boolean to false, so provider-wide `false` is the documented-safe wire value.
|
|
1694
|
+
// - `reasoning_effort` is not portable on NIM (models use chat_template_kwargs); the kimi
|
|
1695
|
+
// family is live-discovered with no capability metadata, so Codex would otherwise send
|
|
1696
|
+
// reasoning_effort=medium. Exact-id lists per modelInList semantics; gpt-oss on NIM keeps
|
|
1697
|
+
// its working reasoning_effort. Future kimi ids must be appended individually.
|
|
1698
|
+
{
|
|
1699
|
+
id: "nvidia", label: "NVIDIA NIM", baseUrl: "https://integrate.api.nvidia.com/v1", adapter: "openai-chat", authKind: "key", dashboardUrl: "https://build.nvidia.com",
|
|
1700
|
+
// Free pricing, but an API key is still required (free key from build.nvidia.com).
|
|
1701
|
+
freeTier: true,
|
|
1702
|
+
parallelToolCalls: false,
|
|
1703
|
+
// 260804 issue #956: NIM exposes no input modalities, so vision capability is
|
|
1704
|
+
// classified here. Both lists are verified per-model; unlisted ids stay unclassified
|
|
1705
|
+
// by design (see the comment on NVIDIA_NIM_VISION_MODELS).
|
|
1706
|
+
noVisionModels: NVIDIA_NIM_NO_VISION_MODELS,
|
|
1707
|
+
modelInputModalities: NVIDIA_NIM_VISION_INPUT_MODALITIES,
|
|
1708
|
+
noReasoningModels: NVIDIA_NIM_KIMI_MODELS,
|
|
1709
|
+
modelReasoningEfforts: {
|
|
1710
|
+
...Object.fromEntries(NVIDIA_NIM_KIMI_MODELS.map(id => [id, []])),
|
|
1711
|
+
// NIM's GPT-OSS endpoints accept the standard low/medium/high effort enum; unlike the Kimi
|
|
1712
|
+
// family above, this is a real provider wire capability and must remain selectable.
|
|
1713
|
+
"openai/gpt-oss-120b": ["low", "medium", "high"],
|
|
1714
|
+
"openai/gpt-oss-20b": ["low", "medium", "high"],
|
|
1715
|
+
},
|
|
1716
|
+
preserveReasoningContentModels: NVIDIA_NIM_KIMI_THINKING_MODELS,
|
|
1717
|
+
note: "Free tier on NVIDIA NIM — API key still required (get a free key at build.nvidia.com).",
|
|
1718
|
+
},
|
|
1719
|
+
{ id: "venice", label: "Venice", baseUrl: "https://api.venice.ai/api/v1", adapter: "openai-chat", authKind: "key", dashboardUrl: "https://venice.ai/settings/api" },
|
|
1720
|
+
// 260710 GLM-5.2 context and path-specific ids: Tier-2 evidence in
|
|
1721
|
+
// devlog/_plan/260710_provider_hardening/002_research_cn.md.
|
|
1722
|
+
{
|
|
1723
|
+
id: "zai", label: "Z.AI — GLM Coding Plan", baseUrl: "https://api.z.ai/api/coding/paas/v4", adapter: "openai-chat", authKind: "key",
|
|
1724
|
+
dashboardUrl: "https://z.ai/manage-apikey/apikey-list", defaultModel: "glm-5.2",
|
|
1725
|
+
note: "GLM-5.2 coding subscription",
|
|
1726
|
+
models: ["glm-5.2", "glm-5.2[1m]", "glm-5.1", "glm-5", "glm-4.6"],
|
|
1727
|
+
modelContextWindows: { "glm-5.2": 1_000_000, "glm-5.2[1m]": 1_000_000 },
|
|
1728
|
+
// Z.AI's OpenAI path returns 400 code 1211 for bracketed model ids.
|
|
1729
|
+
modelSuffixBracketStrip: true,
|
|
1730
|
+
noVisionModels: ZAI_GLM_52_MODELS,
|
|
1731
|
+
modelReasoningEfforts: Object.fromEntries(ZAI_GLM_52_MODELS.map(id => [id, ZAI_GLM_52_REASONING_EFFORTS])),
|
|
1732
|
+
modelSupportsReasoningSummaries: Object.fromEntries(ZAI_GLM_52_MODELS.map(id => [id, true])),
|
|
1733
|
+
preserveReasoningContentModels: ZAI_GLM_52_MODELS,
|
|
1734
|
+
},
|
|
1735
|
+
// Zhipu's domestic BigModel platform: OpenAI-compatible pay-as-you-go on open.bigmodel.cn — a
|
|
1736
|
+
// different host and billing product from the `zai` coding-plan subscription above.
|
|
1737
|
+
// The id is deliberately NOT `glm` or `glm-cn`: both are already bound in FREE_PROVIDER_DIRECTORY
|
|
1738
|
+
// (to api.z.ai and to the BigModel *coding* path), and routedProviderConfig() canonicalizes a
|
|
1739
|
+
// saved provider onto the registry baseUrl — reusing either id would silently retarget an
|
|
1740
|
+
// existing config's endpoint and send its API key to another host.
|
|
1741
|
+
// Evidence: docs.bigmodel.cn/api-reference (OpenAI-compatible chat completions),
|
|
1742
|
+
// docs.bigmodel.cn/cn/guide/models/text/glm-4.6 (thinking: {type: enabled|disabled}).
|
|
1743
|
+
// Originally proposed in #536 by @Lucinegogo.
|
|
1744
|
+
{
|
|
1745
|
+
id: "zhipu-bigmodel",
|
|
1746
|
+
label: "Zhipu AI — BigModel",
|
|
1747
|
+
baseUrl: "https://open.bigmodel.cn/api/paas/v4",
|
|
1748
|
+
adapter: "openai-chat",
|
|
1749
|
+
authKind: "key",
|
|
1750
|
+
dashboardUrl: "https://bigmodel.cn/console/usercenter/apikeys",
|
|
1751
|
+
defaultModel: "glm-4.6",
|
|
1752
|
+
models: ZHIPU_BIGMODEL_MODELS,
|
|
1753
|
+
// The GLM families here are the same ones the `zai` metadata bundle already describes, so the
|
|
1754
|
+
// bundle owns context windows and modalities for the whole list instead of a hand-copied table.
|
|
1755
|
+
jawcodeBundle: "zai",
|
|
1756
|
+
// Declared explicitly for the default model so its window survives a bundle-lookup miss:
|
|
1757
|
+
// without it, catalog normalization falls back to a generic 128k and compacts ~76,800 early.
|
|
1758
|
+
modelContextWindows: { "glm-4.6": 204_800 },
|
|
1759
|
+
modelInputModalities: ZHIPU_BIGMODEL_INPUT_MODALITIES,
|
|
1760
|
+
// GLM exposes a binary thinking knob, not an effort ladder: the adapter emits
|
|
1761
|
+
// `thinking: {type}` for these ids and would otherwise send a rejected reasoning_effort.
|
|
1762
|
+
thinkingToggleModels: ZHIPU_BIGMODEL_THINKING_TOGGLE_MODELS,
|
|
1763
|
+
modelReasoningEfforts: Object.fromEntries(
|
|
1764
|
+
ZHIPU_BIGMODEL_THINKING_TOGGLE_MODELS.map(id => [id, THINKING_TOGGLE_EFFORTS]),
|
|
1765
|
+
),
|
|
1766
|
+
modelReasoningEffortMap: Object.fromEntries(
|
|
1767
|
+
ZHIPU_BIGMODEL_THINKING_TOGGLE_MODELS.map(id => [id, THINKING_TOGGLE_MAP]),
|
|
1768
|
+
),
|
|
1769
|
+
modelSupportsReasoningSummaries: Object.fromEntries(
|
|
1770
|
+
ZHIPU_BIGMODEL_THINKING_TOGGLE_MODELS.map(id => [id, true]),
|
|
1771
|
+
),
|
|
1772
|
+
preserveReasoningContentModels: ZHIPU_BIGMODEL_THINKING_TOGGLE_MODELS,
|
|
1773
|
+
// No liveModels: GET /api/paas/v4/models has not been observed to answer on this host, and a
|
|
1774
|
+
// false live claim yields an empty picker at runtime. Flip it on once someone verifies it.
|
|
1775
|
+
note: "Domestic BigModel pay-as-you-go endpoint (open.bigmodel.cn)",
|
|
1776
|
+
},
|
|
1777
|
+
// BigModel's Coding Plan is a SEPARATE endpoint from the pay-as-you-go row above, and that is
|
|
1778
|
+
// the whole reason this one exists. #1100 was reported against
|
|
1779
|
+
// `https://open.bigmodel.cn/api/coding/paas/v4`; the row above covers only `/api/paas/v4`, so
|
|
1780
|
+
// destination enrichment matched nothing, `modelSupportsReasoningSummaries` stayed unset, and
|
|
1781
|
+
// Codex kept dropping the inbound reasoning object — effort displayed as `-`.
|
|
1782
|
+
//
|
|
1783
|
+
// A prefix or fuzzy endpoint match would have been the shortcut. It is also how a config
|
|
1784
|
+
// pointed at one vendor route silently inherits another route's metadata, so endpoints stay
|
|
1785
|
+
// exact and each one gets its own row.
|
|
1786
|
+
//
|
|
1787
|
+
// The id is NOT `glm-cn`, which the free-provider directory already binds to this same coding
|
|
1788
|
+
// path: registering it here would let routedProviderConfig() canonicalize a saved `glm-cn`
|
|
1789
|
+
// config onto this baseUrl. Same reasoning as `zhipu-bigmodel` above.
|
|
1790
|
+
//
|
|
1791
|
+
// Models follow Z.AI's coding-plan list rather than the pay-as-you-go one. This endpoint is
|
|
1792
|
+
// the subscription product, and the reporter's `glm-5.2` is only on that side.
|
|
1793
|
+
{
|
|
1794
|
+
id: "zhipu-bigmodel-coding",
|
|
1795
|
+
label: "Zhipu AI — BigModel Coding Plan",
|
|
1796
|
+
baseUrl: "https://open.bigmodel.cn/api/coding/paas/v4",
|
|
1797
|
+
adapter: "openai-chat",
|
|
1798
|
+
authKind: "key",
|
|
1799
|
+
dashboardUrl: "https://bigmodel.cn/console/usercenter/apikeys",
|
|
1800
|
+
defaultModel: "glm-5.2",
|
|
1801
|
+
models: ["glm-5.2", "glm-5.2[1m]", "glm-5.1", "glm-5", "glm-4.6"],
|
|
1802
|
+
jawcodeBundle: "zai",
|
|
1803
|
+
modelContextWindows: { "glm-5.2": 1_000_000, "glm-5.2[1m]": 1_000_000 },
|
|
1804
|
+
modelSuffixBracketStrip: true,
|
|
1805
|
+
noVisionModels: ZAI_GLM_52_MODELS,
|
|
1806
|
+
modelReasoningEfforts: Object.fromEntries(ZAI_GLM_52_MODELS.map(id => [id, ZAI_GLM_52_REASONING_EFFORTS])),
|
|
1807
|
+
modelSupportsReasoningSummaries: Object.fromEntries(ZAI_GLM_52_MODELS.map(id => [id, true])),
|
|
1808
|
+
preserveReasoningContentModels: ZAI_GLM_52_MODELS,
|
|
1809
|
+
// No liveModels: the same reasoning as the pay-as-you-go row — an unverified live claim
|
|
1810
|
+
// yields an empty picker at runtime.
|
|
1811
|
+
note: "Domestic BigModel Coding Plan endpoint (open.bigmodel.cn)",
|
|
1812
|
+
},
|
|
1813
|
+
{ id: "nanogpt", label: "NanoGPT", baseUrl: "https://nano-gpt.com/api/v1", adapter: "openai-chat", authKind: "key", dashboardUrl: "https://nano-gpt.com/api" },
|
|
1814
|
+
{ id: "synthetic", label: "Synthetic", baseUrl: "https://api.synthetic.new/openai/v1", adapter: "openai-chat", authKind: "key", dashboardUrl: "https://synthetic.new" },
|
|
1815
|
+
// SiliconFlow publishes an OpenAI-compatible chat endpoint and a dynamic model catalog. Do not
|
|
1816
|
+
// freeze reasoning controls here: enable_thinking/thinking_budget support and limits vary by
|
|
1817
|
+
// model, so live metadata or an explicit user override must own those capabilities.
|
|
1818
|
+
// Evidence: https://docs.siliconflow.cn/en/api-reference/chat-completions/chat-completions
|
|
1819
|
+
{
|
|
1820
|
+
id: "siliconflow",
|
|
1821
|
+
label: "SiliconFlow",
|
|
1822
|
+
baseUrl: "https://api.siliconflow.cn/v1",
|
|
1823
|
+
adapter: "openai-chat",
|
|
1824
|
+
authKind: "key",
|
|
1825
|
+
dashboardUrl: "https://cloud.siliconflow.cn/account/ak",
|
|
1826
|
+
liveModels: true,
|
|
1827
|
+
note: "OpenAI-compatible live model catalog; reasoning controls vary by model.",
|
|
1828
|
+
},
|
|
1829
|
+
// Qwen Cloud: token plan is the preset default; GUI offers pay-as-you-go + custom via baseUrlChoices.
|
|
1830
|
+
// Formerly `qwen-portal` / portal.qwen.ai — that host is outdated.
|
|
1831
|
+
{
|
|
1832
|
+
id: "qwen-cloud",
|
|
1833
|
+
label: "Qwen Cloud",
|
|
1834
|
+
baseUrl: QWEN_CLOUD_TOKEN_PLAN_BASE_URL,
|
|
1835
|
+
adapter: "openai-chat",
|
|
1836
|
+
authKind: "key",
|
|
1837
|
+
allowBaseUrlOverride: true,
|
|
1838
|
+
baseUrlChoices: QWEN_CLOUD_BASE_URL_CHOICES,
|
|
1839
|
+
dashboardUrl: "https://docs.qwencloud.com",
|
|
1840
|
+
note: "Pick token plan, pay as you go, or a custom compatible-mode base URL",
|
|
1841
|
+
},
|
|
1842
|
+
{
|
|
1843
|
+
id: "tencent-coding-plan",
|
|
1844
|
+
label: "Tencent Cloud Coding Plan",
|
|
1845
|
+
baseUrl: "https://api.lkeap.cloud.tencent.com/coding/v3",
|
|
1846
|
+
adapter: "openai-chat",
|
|
1847
|
+
authKind: "key",
|
|
1848
|
+
dashboardUrl: "https://console.cloud.tencent.com/tokenhub/codingplan",
|
|
1849
|
+
defaultModel: "tc-code-latest",
|
|
1850
|
+
models: TENCENT_CODING_PLAN_MODELS,
|
|
1851
|
+
liveModels: true,
|
|
1852
|
+
modelInputModalities: Object.fromEntries(TENCENT_CODING_PLAN_MODELS.map(id => [id, ["text"]])),
|
|
1853
|
+
noVisionModels: TENCENT_CODING_PLAN_MODELS,
|
|
1854
|
+
note: "Coding tools only. Tencent forbids general API automation, custom backends, and non-interactive batch use.",
|
|
1855
|
+
},
|
|
1856
|
+
{
|
|
1857
|
+
id: "volcengine",
|
|
1858
|
+
label: "Volcengine Ark",
|
|
1859
|
+
baseUrl: "https://ark.cn-beijing.volces.com/api/v3",
|
|
1860
|
+
adapter: "openai-chat",
|
|
1861
|
+
authKind: "key",
|
|
1862
|
+
preserveCustomDestination: true,
|
|
1863
|
+
dashboardUrl: "https://console.volcengine.com/ark/region:ark+cn-beijing/apikey",
|
|
1864
|
+
defaultModel: "doubao-seed-2-1-pro-260628",
|
|
1865
|
+
models: VOLCENGINE_ARK_MODELS,
|
|
1866
|
+
liveModels: false,
|
|
1867
|
+
modelReasoningEfforts: Object.fromEntries(
|
|
1868
|
+
VOLCENGINE_DOUBAO_THINKING_MODELS.map(id => [id, THINKING_TOGGLE_EFFORTS]),
|
|
1869
|
+
),
|
|
1870
|
+
modelReasoningEffortMap: Object.fromEntries(
|
|
1871
|
+
VOLCENGINE_DOUBAO_THINKING_MODELS.map(id => [id, THINKING_TOGGLE_MAP]),
|
|
1872
|
+
),
|
|
1873
|
+
thinkingToggleModels: VOLCENGINE_DOUBAO_THINKING_MODELS,
|
|
1874
|
+
preserveReasoningContentModels: [
|
|
1875
|
+
"deepseek-v4-pro-260425",
|
|
1876
|
+
"deepseek-v4-flash-260425",
|
|
1877
|
+
"glm-5-2-260617",
|
|
1878
|
+
"glm-4-7-251222",
|
|
1879
|
+
],
|
|
1880
|
+
noVisionModels: [
|
|
1881
|
+
"deepseek-v4-pro-260425",
|
|
1882
|
+
"deepseek-v4-flash-260425",
|
|
1883
|
+
"deepseek-v3-2-251201",
|
|
1884
|
+
"glm-5-2-260617",
|
|
1885
|
+
"glm-4-7-251222",
|
|
1886
|
+
],
|
|
1887
|
+
note: "Pay-as-you-go Ark API with a curated text/agent catalog. Calls on this endpoint do not consume Coding Plan or Agent Plan quota.",
|
|
1888
|
+
},
|
|
1889
|
+
{
|
|
1890
|
+
id: "volcengine-coding-plan",
|
|
1891
|
+
label: "Volcengine Ark Coding Plan",
|
|
1892
|
+
baseUrl: "https://ark.cn-beijing.volces.com/api/coding/v3",
|
|
1893
|
+
adapter: "openai-chat",
|
|
1894
|
+
authKind: "key",
|
|
1895
|
+
preserveCustomDestination: true,
|
|
1896
|
+
dashboardUrl: "https://console.volcengine.com/ark/region:ark+cn-beijing/overview",
|
|
1897
|
+
defaultModel: "ark-code-latest",
|
|
1898
|
+
models: VOLCENGINE_CODING_PLAN_MODELS,
|
|
1899
|
+
liveModels: false,
|
|
1900
|
+
modelInputModalities: VOLCENGINE_PLAN_INPUT_MODALITIES,
|
|
1901
|
+
noVisionModels: VOLCENGINE_PLAN_TEXT_ONLY_MODELS,
|
|
1902
|
+
modelReasoningEfforts: Object.fromEntries(
|
|
1903
|
+
DEEPSEEK_THINKING_MODELS.map(id => [id, deepseekThinkingEffortsFor(id)]),
|
|
1904
|
+
),
|
|
1905
|
+
modelReasoningEffortMap: Object.fromEntries(
|
|
1906
|
+
DEEPSEEK_THINKING_MODELS.map(id => [id, deepseekReasoningMapFor(id)]),
|
|
1907
|
+
),
|
|
1908
|
+
preserveReasoningContentModels: DEEPSEEK_THINKING_MODELS,
|
|
1909
|
+
note: "Coding tools only. Volcengine restricts Coding Plan quota to supported AI coding tools and warns that using this key for general API calls may suspend the subscription or ban the account. Use the plan key issued by the Ark console.",
|
|
1910
|
+
},
|
|
1911
|
+
{
|
|
1912
|
+
id: "volcengine-agent-plan",
|
|
1913
|
+
label: "Volcengine Ark Agent Plan",
|
|
1914
|
+
baseUrl: "https://ark.cn-beijing.volces.com/api/plan/v3",
|
|
1915
|
+
responsesPath: "/responses",
|
|
1916
|
+
adapter: "openai-responses",
|
|
1917
|
+
authKind: "key",
|
|
1918
|
+
// Ark's plan route does not document `service_tier`; fail closed like DeepSeek.
|
|
1919
|
+
supportsServiceTier: false,
|
|
1920
|
+
preserveCustomDestination: true,
|
|
1921
|
+
dashboardUrl: "https://console.volcengine.com/ark/region:ark+cn-beijing/overview",
|
|
1922
|
+
defaultModel: "deepseek-v4-pro",
|
|
1923
|
+
models: VOLCENGINE_AGENT_PLAN_MODELS,
|
|
1924
|
+
liveModels: false,
|
|
1925
|
+
modelInputModalities: VOLCENGINE_PLAN_INPUT_MODALITIES,
|
|
1926
|
+
noVisionModels: VOLCENGINE_PLAN_TEXT_ONLY_MODELS,
|
|
1927
|
+
note: "Coding tools only. Agent Plan is a subscription endpoint over the native Responses API with a static fallback catalog; Ark plan quota is intended for supported AI coding and agent tools, so avoid using this key as a general-purpose API key.",
|
|
1928
|
+
},
|
|
1929
|
+
// 2026-07-10: docs unverified; model data frozen. Evidence: devlog/_plan/260710_provider_hardening/002_research_cn.md.
|
|
1930
|
+
{ id: "qianfan", label: "Qianfan (Baidu)", baseUrl: "https://qianfan.baidubce.com/v2", adapter: "openai-chat", authKind: "key", dashboardUrl: "https://console.bce.baidu.com/iam/#/iam/apikey/list" },
|
|
1931
|
+
// 2026-07-10: docs unverified; model data frozen. Evidence: devlog/_plan/260710_provider_hardening/002_research_cn.md.
|
|
1932
|
+
{ id: "alibaba", label: "Alibaba Coding Plan", baseUrl: ALIBABA_CODING_INTL_BASE_URL, adapter: "openai-chat", authKind: "key", allowBaseUrlOverride: true, baseUrlChoices: ALIBABA_CODING_BASE_URL_CHOICES, dashboardUrl: "https://dashscope.console.aliyun.com/apiKey" },
|
|
1933
|
+
{
|
|
1934
|
+
id: "alibaba-token-plan",
|
|
1935
|
+
label: "Alibaba Token Plan (Beijing)",
|
|
1936
|
+
baseUrl: "https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1",
|
|
1937
|
+
adapter: "openai-chat",
|
|
1938
|
+
authKind: "key",
|
|
1939
|
+
dashboardUrl: "https://bailian.console.aliyun.com/cn-beijing?tab=plan",
|
|
1940
|
+
defaultModel: "qwen3.8-max",
|
|
1941
|
+
models: ALIBABA_TOKEN_PLAN_MODELS,
|
|
1942
|
+
liveModels: false,
|
|
1943
|
+
note: "Token Plan Personal Edition · China (Beijing)",
|
|
1944
|
+
modelInputModalities: ALIBABA_TOKEN_PLAN_INPUT_MODALITIES,
|
|
1945
|
+
modelContextWindows: {
|
|
1946
|
+
"qwen3.8-max": 983_616, "qwen3.7-max": 1_000_000, "qwen3.7-plus": 1_000_000,
|
|
1947
|
+
"qwen3.6-flash": 1_000_000, "glm-5.2": 1_000_000, "deepseek-v4-pro": 1_000_000,
|
|
1948
|
+
},
|
|
1949
|
+
modelReasoningEfforts: {
|
|
1950
|
+
...Object.fromEntries(ALIBABA_TOKEN_PLAN_QWEN_MODELS.map(id => [id, THINKING_BUDGET_EFFORTS])),
|
|
1951
|
+
"glm-5.2": ZAI_GLM_52_REASONING_EFFORTS,
|
|
1952
|
+
"deepseek-v4-pro": deepseekThinkingEffortsFor("deepseek-v4-pro"),
|
|
1953
|
+
},
|
|
1954
|
+
modelReasoningEffortMap: { "deepseek-v4-pro": deepseekReasoningMapFor("deepseek-v4-pro") },
|
|
1955
|
+
thinkingBudgetModels: ALIBABA_TOKEN_PLAN_QWEN_MODELS,
|
|
1956
|
+
preserveReasoningContentModels: ["glm-5.2", "deepseek-v4-pro", "qwen3.8-max", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-flash"],
|
|
1957
|
+
noVisionModels: ["glm-5.2", "deepseek-v4-pro"],
|
|
1958
|
+
},
|
|
1959
|
+
{
|
|
1960
|
+
id: "alibaba-token-plan-intl",
|
|
1961
|
+
label: "Alibaba Token Plan (International)",
|
|
1962
|
+
baseUrl: ALIBABA_INTL_TOKEN_PLAN_BASE_URL,
|
|
1963
|
+
adapter: "openai-chat",
|
|
1964
|
+
authKind: "key",
|
|
1965
|
+
allowBaseUrlOverride: true,
|
|
1966
|
+
baseUrlChoices: ALIBABA_INTL_BASE_URL_CHOICES,
|
|
1967
|
+
dashboardUrl: "https://modelstudio.console.alibabacloud.com/?tab=api#/api",
|
|
1968
|
+
defaultModel: "qwen3.7-max",
|
|
1969
|
+
models: ALIBABA_INTL_TOKEN_PLAN_MODELS,
|
|
1970
|
+
liveModels: false,
|
|
1971
|
+
note: "Token Plan Team Edition · Singapore (ap-southeast-1)",
|
|
1972
|
+
metadataModelIdNormalize: "case-insensitive",
|
|
1973
|
+
modelInputModalities: ALIBABA_INTL_TOKEN_PLAN_INPUT_MODALITIES,
|
|
1974
|
+
modelContextWindows: {
|
|
1975
|
+
"qwen3.8-max": 983_616,
|
|
1976
|
+
"qwen3.7-max": 1_000_000, "qwen3.7-plus": 1_000_000, "qwen3.6-plus": 1_000_000, "qwen3.6-flash": 1_000_000,
|
|
1977
|
+
"deepseek-v4-pro": 1_000_000, "deepseek-v4-flash": 1_000_000, "deepseek-v3.2": 131_072,
|
|
1978
|
+
"kimi-k2.7-code": 262_144, "kimi-k2.6": 262_144, "kimi-k2.5": 262_144,
|
|
1979
|
+
"glm-5.2": 1_000_000, "glm-5.1": 1_000_000, "glm-5": 1_000_000,
|
|
1980
|
+
"MiniMax-M2.5": 204_800,
|
|
1981
|
+
},
|
|
1982
|
+
modelReasoningEfforts: {
|
|
1983
|
+
...Object.fromEntries(ALIBABA_INTL_TOKEN_PLAN_QWEN_MODELS.map(id => [id, THINKING_BUDGET_EFFORTS])),
|
|
1984
|
+
"qwen3.8-max": ["low", "high", "xhigh"],
|
|
1985
|
+
"glm-5.2": ZAI_GLM_52_REASONING_EFFORTS,
|
|
1986
|
+
"deepseek-v4-pro": deepseekThinkingEffortsFor("deepseek-v4-pro"),
|
|
1987
|
+
"deepseek-v4-flash": deepseekThinkingEffortsFor("deepseek-v4-flash"),
|
|
1988
|
+
},
|
|
1989
|
+
modelReasoningEffortMap: {
|
|
1990
|
+
"deepseek-v4-pro": deepseekReasoningMapFor("deepseek-v4-pro"),
|
|
1991
|
+
"deepseek-v4-flash": deepseekReasoningMapFor("deepseek-v4-flash"),
|
|
1992
|
+
},
|
|
1993
|
+
thinkingBudgetModels: ALIBABA_INTL_TOKEN_PLAN_QWEN_MODELS,
|
|
1994
|
+
preserveReasoningContentModels: ["glm-5.2", "deepseek-v4-pro", "deepseek-v4-flash", "qwen3.8-max", "qwen3.7-max", "qwen3.7-plus", "qwen3.6-plus", "qwen3.6-flash"],
|
|
1995
|
+
noVisionModels: ["deepseek-v4-pro", "deepseek-v4-flash", "deepseek-v3.2", "glm-5.2", "glm-5.1", "glm-5", "MiniMax-M2.5"],
|
|
1996
|
+
noReasoningModels: ["kimi-k2.7-code", "kimi-k2.6", "kimi-k2.5", "deepseek-v3.2", "glm-5.1", "glm-5", "MiniMax-M2.5"],
|
|
1997
|
+
modelDefaultReasoningEfforts: { "qwen3.8-max": "xhigh" },
|
|
1998
|
+
},
|
|
1999
|
+
// NEEDS_HUMAN 2026-07-10: kept for config compatibility, but this is a dashboard URL,
|
|
2000
|
+
// no /models endpoint is documented, and tools are silently ignored upstream per docs.parallel.ai.
|
|
2001
|
+
// Evidence: devlog/_plan/260710_provider_hardening/003_research_aggregators.md.
|
|
2002
|
+
{ id: "parallel", label: "Parallel", baseUrl: "https://platform.parallel.ai", adapter: "openai-chat", authKind: "key", dashboardUrl: "https://platform.parallel.ai" },
|
|
2003
|
+
// ZenMux native ids are vendor-namespaced (`<vendor>/<model>`), verified live against
|
|
2004
|
+
// https://zenmux.ai/api/v1/models on 2026-07-18. The static seed doubles as the
|
|
2005
|
+
// cold-cache decode source for the Codex slug codec (src/providers/slug-codec.ts);
|
|
2006
|
+
// live discovery still owns the full catalog.
|
|
2007
|
+
{
|
|
2008
|
+
id: "zenmux", label: "ZenMux", baseUrl: "https://zenmux.ai/api/v1", adapter: "openai-chat", authKind: "key", dashboardUrl: "https://zenmux.ai",
|
|
2009
|
+
models: ["moonshotai/kimi-k3-free", "moonshotai/kimi-k3"],
|
|
2010
|
+
},
|
|
2011
|
+
{
|
|
2012
|
+
id: "litellm", label: "LiteLLM (self-hosted)", baseUrl: "http://localhost:4000/v1", adapter: "openai-chat", authKind: "key",
|
|
2013
|
+
dashboardUrl: "https://docs.litellm.ai/docs/proxy/quick_start",
|
|
2014
|
+
allowPrivateNetworkByDefault: true,
|
|
2015
|
+
allowBaseUrlOverride: true,
|
|
2016
|
+
// A self-hosted proxy may legitimately run without a master key.
|
|
2017
|
+
keyOptional: true,
|
|
2018
|
+
},
|
|
2019
|
+
{
|
|
2020
|
+
id: "ollama-cloud",
|
|
2021
|
+
label: "Ollama Cloud",
|
|
2022
|
+
baseUrl: "https://ollama.com/v1",
|
|
2023
|
+
adapter: "openai-chat",
|
|
2024
|
+
authKind: "key",
|
|
2025
|
+
dashboardUrl: "https://ollama.com/settings/keys",
|
|
2026
|
+
// Live IDs verified 2026-07-10; qwen3-coder:480b retires 2026-07-15.
|
|
2027
|
+
models: ["glm-5.2", "deepseek-v4-pro", "qwen3-coder:480b", "gpt-oss:120b", "kimi-k2.6", "minimax-m3", "qwen3.5:397b", "gemma4:31b"],
|
|
2028
|
+
defaultModel: "glm-5.2",
|
|
2029
|
+
noVisionModels: [
|
|
2030
|
+
"glm-5.2", "glm-5.1", "glm-5", "glm-4.7",
|
|
2031
|
+
"minimax-m2.7", "minimax-m2.5", "minimax-m2.1",
|
|
2032
|
+
"nemotron-3-ultra", "nemotron-3-super",
|
|
2033
|
+
"deepseek-v4-pro", "deepseek-v4-flash",
|
|
2034
|
+
"gpt-oss", "qwen3-coder:480b",
|
|
2035
|
+
],
|
|
2036
|
+
},
|
|
2037
|
+
// FREEZE 2026-07-10: codestral-latest is unconfirmed behind auth. Evidence: devlog/_plan/260710_provider_hardening/003_research_aggregators.md.
|
|
2038
|
+
{ id: "mistral", label: "Mistral", baseUrl: "https://api.mistral.ai/v1", adapter: "openai-chat", authKind: "key", dashboardUrl: "https://console.mistral.ai/api-keys", defaultModel: "codestral-latest" },
|
|
2039
|
+
{
|
|
2040
|
+
id: "minimax", label: "MiniMax — Coding Plan", baseUrl: "https://api.minimax.io/v1", adapter: "openai-chat", authKind: "key",
|
|
2041
|
+
dashboardUrl: "https://platform.minimax.io", defaultModel: "MiniMax-M3", models: MINIMAX_MODELS,
|
|
2042
|
+
modelContextWindows: MINIMAX_MODEL_CONTEXT_WINDOWS,
|
|
2043
|
+
modelReasoningEfforts: { "MiniMax-M3": MINIMAX_M3_REASONING_EFFORTS },
|
|
2044
|
+
modelDefaultReasoningEfforts: { "MiniMax-M3": "medium" },
|
|
2045
|
+
modelReasoningEffortMap: { "MiniMax-M3": MINIMAX_M3_REASONING_EFFORT_MAP },
|
|
2046
|
+
preserveReasoningContentModels: MINIMAX_MODELS,
|
|
2047
|
+
reasoningSplitModels: MINIMAX_MODELS,
|
|
2048
|
+
thinkingToggleModels: ["MiniMax-M3"],
|
|
2049
|
+
jawcodeBundle: "minimax", metadataModelIdNormalize: "case-insensitive", note: "Subscription Key or API Key",
|
|
2050
|
+
},
|
|
2051
|
+
{
|
|
2052
|
+
id: "minimax-cn", label: "MiniMax — Coding Plan (CN)", baseUrl: "https://api.minimaxi.com/v1", adapter: "openai-chat", authKind: "key",
|
|
2053
|
+
dashboardUrl: "https://platform.minimaxi.com", defaultModel: "MiniMax-M3", models: MINIMAX_MODELS,
|
|
2054
|
+
modelContextWindows: MINIMAX_MODEL_CONTEXT_WINDOWS,
|
|
2055
|
+
modelReasoningEfforts: { "MiniMax-M3": MINIMAX_M3_REASONING_EFFORTS },
|
|
2056
|
+
modelDefaultReasoningEfforts: { "MiniMax-M3": "medium" },
|
|
2057
|
+
modelReasoningEffortMap: { "MiniMax-M3": MINIMAX_M3_REASONING_EFFORT_MAP },
|
|
2058
|
+
preserveReasoningContentModels: MINIMAX_MODELS,
|
|
2059
|
+
reasoningSplitModels: MINIMAX_MODELS,
|
|
2060
|
+
thinkingToggleModels: ["MiniMax-M3"],
|
|
2061
|
+
jawcodeBundle: "minimax", metadataModelIdNormalize: "case-insensitive", note: "中国区 Subscription Key",
|
|
2062
|
+
},
|
|
2063
|
+
{
|
|
2064
|
+
id: "kimi-code", label: "Kimi (coding)", baseUrl: "https://api.kimi.com/coding/v1", adapter: "openai-chat", authKind: "key",
|
|
2065
|
+
dashboardUrl: "https://platform.moonshot.cn/console/api-keys", defaultModel: "kimi-k2.7-code",
|
|
2066
|
+
modelSuffixBracketStrip: true,
|
|
2067
|
+
// API-key form of the same Kimi Code Plan transport; keep cache affinity identical to OAuth.
|
|
2068
|
+
promptCacheKey: true,
|
|
2069
|
+
models: KIMI_CODING_MODELS,
|
|
2070
|
+
modelContextWindows: KIMI_CODING_MODEL_CONTEXT_WINDOWS,
|
|
2071
|
+
modelInputModalities: KIMI_CODING_MODEL_INPUT_MODALITIES,
|
|
2072
|
+
noReasoningModels: KIMI_CODING_NO_REASONING_MODELS,
|
|
2073
|
+
modelReasoningEfforts: KIMI_CODING_REASONING_EFFORTS,
|
|
2074
|
+
modelDefaultReasoningEfforts: KIMI_CODING_DEFAULT_REASONING_EFFORTS,
|
|
2075
|
+
modelReasoningEffortMap: KIMI_CODING_REASONING_EFFORT_MAPS,
|
|
2076
|
+
noTemperatureModels: KIMI_LOCKED_PARAMETER_MODELS,
|
|
2077
|
+
noTopPModels: KIMI_LOCKED_PARAMETER_MODELS,
|
|
2078
|
+
noPenaltyModels: KIMI_LOCKED_PARAMETER_MODELS,
|
|
2079
|
+
autoToolChoiceOnlyModels: KIMI_AUTO_TOOL_CHOICE_ONLY_MODELS,
|
|
2080
|
+
preserveReasoningContentModels: KIMI_THINKING_MODELS,
|
|
2081
|
+
},
|
|
2082
|
+
{
|
|
2083
|
+
id: "opencode-zen", label: "opencode zen", baseUrl: "https://opencode.ai/zen/v1", adapter: "openai-chat", authKind: "key", dashboardUrl: "https://opencode.ai/auth",
|
|
2084
|
+
// Zen's edge has intermittently returned a non-JSON/HTML 405 for the documented
|
|
2085
|
+
// POST /chat/completions route. A JSON 405 still represents a real method mismatch.
|
|
2086
|
+
preStreamNonJsonRetryStatuses: [405],
|
|
2087
|
+
// Same opencode.ai/zen/v1 gateway as `opencode-free` (keyed tier): DeepSeek thinking mode
|
|
2088
|
+
// requires the assistant's original reasoning_content to be replayed on tool-call
|
|
2089
|
+
// continuations, or the gateway answers HTTP 400 (issues #950/#994). Mirror the DeepSeek
|
|
2090
|
+
// reasoning + thinking metadata so `opencode-zen/deepseek-v4-flash-free` — and the other
|
|
2091
|
+
// Zen DeepSeek thinking models — never serialize a bare tool-call turn.
|
|
2092
|
+
modelReasoningEfforts: {
|
|
2093
|
+
...Object.fromEntries(
|
|
2094
|
+
[...DEEPSEEK_THINKING_MODELS, ...OPENCODE_FREE_DEEPSEEK_MODELS].map(id => [id, deepseekThinkingEffortsFor(id)]),
|
|
2095
|
+
),
|
|
2096
|
+
...Object.fromEntries(OPENCODE_OX_ALPHA_MODELS.map(id => [id, OPENCODE_OX_ALPHA_REASONING_EFFORTS])),
|
|
2097
|
+
},
|
|
2098
|
+
modelReasoningEffortMap: Object.fromEntries(
|
|
2099
|
+
[...DEEPSEEK_THINKING_MODELS, ...OPENCODE_FREE_DEEPSEEK_MODELS].map(id => [id, deepseekReasoningMapFor(id)]),
|
|
2100
|
+
),
|
|
2101
|
+
preserveReasoningContentModels: [
|
|
2102
|
+
...DEEPSEEK_THINKING_MODELS,
|
|
2103
|
+
...OPENCODE_FREE_DEEPSEEK_MODELS,
|
|
2104
|
+
...OPENCODE_OX_ALPHA_MODELS,
|
|
2105
|
+
],
|
|
2106
|
+
noVisionModels: [...OPENCODE_ZEN_TEXT_ONLY_MODELS, ...DEEPSEEK_THINKING_MODELS],
|
|
2107
|
+
},
|
|
2108
|
+
{ id: "vercel-ai-gateway", label: "Vercel AI Gateway", baseUrl: "https://ai-gateway.vercel.sh/v1", adapter: "openai-chat", authKind: "key", dashboardUrl: "https://vercel.com/dashboard" },
|
|
2109
|
+
{
|
|
2110
|
+
id: "opencode-free",
|
|
2111
|
+
label: "OpenCode Free",
|
|
2112
|
+
adapter: "openai-chat",
|
|
2113
|
+
baseUrl: "https://opencode.ai/zen/v1",
|
|
2114
|
+
authKind: "key",
|
|
2115
|
+
keyOptional: true,
|
|
2116
|
+
featured: true,
|
|
2117
|
+
liveModels: true,
|
|
2118
|
+
note: "No key needed — public desktop tier. OpenCode currently advertises about 200 Big Pickle/free-model requests per 5 hours. Free models are discovered live from Zen. Data use: per OpenCode's Zen docs (https://opencode.ai/docs/zen/), prompts sent to free models may be retained and used for training/improvement — do not send confidential material through this provider.",
|
|
2119
|
+
dashboardUrl: "https://opencode.ai",
|
|
2120
|
+
staticHeaders: {
|
|
2121
|
+
"x-opencode-client": "desktop",
|
|
2122
|
+
},
|
|
2123
|
+
modelReasoningEfforts: {
|
|
2124
|
+
...Object.fromEntries(OPENCODE_FREE_DEEPSEEK_MODELS.map(id => [id, deepseekThinkingEffortsFor(id)])),
|
|
2125
|
+
...Object.fromEntries(OPENCODE_OX_ALPHA_MODELS.map(id => [id, OPENCODE_OX_ALPHA_REASONING_EFFORTS])),
|
|
2126
|
+
},
|
|
2127
|
+
modelReasoningEffortMap: Object.fromEntries(OPENCODE_FREE_DEEPSEEK_MODELS.map(id => [id, deepseekReasoningMapFor(id)])),
|
|
2128
|
+
preserveReasoningContentModels: [...OPENCODE_FREE_DEEPSEEK_MODELS, ...OPENCODE_OX_ALPHA_MODELS],
|
|
2129
|
+
// Same Zen roster behind the same base URL, so it carries the same measured
|
|
2130
|
+
// text-only list rather than only its DeepSeek member (#1043).
|
|
2131
|
+
noVisionModels: OPENCODE_ZEN_TEXT_ONLY_MODELS,
|
|
2132
|
+
},
|
|
2133
|
+
{ id: "xiaomi", label: "Xiaomi MiMo", baseUrl: "https://api.xiaomimimo.com/anthropic", adapter: "anthropic", authKind: "key", dashboardUrl: "https://xiaomimimo.com", defaultModel: "mimo-v2.5-pro" },
|
|
2134
|
+
{ id: "kilo", label: "Kilo", baseUrl: "https://api.kilo.ai/api/gateway", adapter: "openai-chat", authKind: "key", dashboardUrl: "https://kilo.ai" },
|
|
2135
|
+
{
|
|
2136
|
+
id: "mimo-free",
|
|
2137
|
+
label: "MiMo Free",
|
|
2138
|
+
adapter: "mimo-free",
|
|
2139
|
+
baseUrl: "https://api.xiaomimimo.com/api/free-ai/openai/chat",
|
|
2140
|
+
authKind: "key",
|
|
2141
|
+
keyOptional: true,
|
|
2142
|
+
featured: true,
|
|
2143
|
+
liveModels: true,
|
|
2144
|
+
dashboardUrl: "https://xiaomimimo.com",
|
|
2145
|
+
defaultModel: "mimo-auto",
|
|
2146
|
+
models: ["mimo-auto"],
|
|
2147
|
+
note: "No key needed — uses Xiaomi MiMo's free public tier (limited-time offer). A JWT is bootstrapped automatically with an anonymous random client id stored locally. The endpoint contract mirrors the official MiMoCode client and is not publicly documented — Xiaomi may change or restrict it at any time. Prompts may be processed/retained by Xiaomi; do not send confidential material.",
|
|
2148
|
+
},
|
|
2149
|
+
// Xiaomi MiMo paid token plan. Separate host and wire from both `xiaomi` (Anthropic) and
|
|
2150
|
+
// `mimo-free` (free tier, bespoke adapter), so it needs its own entry rather than a variant.
|
|
2151
|
+
//
|
|
2152
|
+
// Pinned to openai-chat deliberately (#1158). The endpoint answers the Responses wire for
|
|
2153
|
+
// plain turns, which is why users configuring it by hand pick `openai-responses` — MiMo
|
|
2154
|
+
// documents Responses support. But its gateway rejects `type: "custom"` tools with
|
|
2155
|
+
// `400 responses_feature_not_supported`, and `apply_patch` is a custom tool, so every agentic
|
|
2156
|
+
// turn fails while chat turns succeed. The Chat path lowers custom tools to `{input: string}`
|
|
2157
|
+
// functions and restores them as `custom_tool_call`, so the capability survives intact.
|
|
2158
|
+
// Stripping the tools instead would stop the 400 and disable the agent loop.
|
|
2159
|
+
{
|
|
2160
|
+
id: "mimo",
|
|
2161
|
+
label: "Xiaomi MiMo (token plan)",
|
|
2162
|
+
baseUrl: "https://token-plan-cn.xiaomimimo.com/v1",
|
|
2163
|
+
adapter: "openai-chat",
|
|
2164
|
+
authKind: "key",
|
|
2165
|
+
dashboardUrl: "https://xiaomimimo.com",
|
|
2166
|
+
defaultModel: "mimo-v2.5-pro",
|
|
2167
|
+
models: ["mimo-v2.5-pro", "mimo-v2.5"],
|
|
2168
|
+
// The gateway validates the ladder strictly and rejects anything above `high`.
|
|
2169
|
+
reasoningEfforts: ["low", "medium", "high"],
|
|
2170
|
+
reasoningEffortMap: { xhigh: "high", max: "high", ultra: "high" },
|
|
2171
|
+
// A user may already have hand-rolled a provider under this id against a different host;
|
|
2172
|
+
// without this, routedProviderConfig() would canonicalize their base URL onto ours and send
|
|
2173
|
+
// their key somewhere they did not choose.
|
|
2174
|
+
preserveCustomDestination: true,
|
|
2175
|
+
note: "Xiaomi MiMo paid token plan. Pinned to the Chat wire: the Responses endpoint rejects freeform (custom) tools such as apply_patch with 400 responses_feature_not_supported, so agentic turns fail there while plain turns succeed. Reasoning tiers above high are clamped.",
|
|
2176
|
+
},
|
|
2177
|
+
{ id: "cloudflare-ai-gateway", label: "Cloudflare AI Gateway", baseUrl: "https://gateway.ai.cloudflare.com/v1/{account-id}/{gateway}/anthropic", adapter: "anthropic", authKind: "key", dashboardUrl: "https://dash.cloudflare.com/?to=/:account/ai/ai-gateway" },
|
|
2178
|
+
{
|
|
2179
|
+
// Cloudflare Workers AI: OpenAI-compatible endpoint. The base URL contains {account_id}
|
|
2180
|
+
// which must be resolved by the user at setup time. Model IDs use the @cf/ prefix.
|
|
2181
|
+
// Live-verified 2026-07-21 against https://developers.cloudflare.com/workers-ai/models/
|
|
2182
|
+
id: "cloudflare-workers-ai", label: "Cloudflare Workers AI",
|
|
2183
|
+
baseUrl: "https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/v1",
|
|
2184
|
+
adapter: "openai-chat", authKind: "key", freeTier: true,
|
|
2185
|
+
dashboardUrl: "https://dash.cloudflare.com/?to=/:account/ai/workers-ai",
|
|
2186
|
+
defaultModel: "@cf/meta/llama-3.3-70b-instruct-fp8-fast",
|
|
2187
|
+
models: [
|
|
2188
|
+
"@cf/meta/llama-3.3-70b-instruct-fp8-fast",
|
|
2189
|
+
"@cf/qwen/qwq-32b",
|
|
2190
|
+
"@cf/deepseek-ai/deepseek-r1-distill-qwen-32b",
|
|
2191
|
+
"@cf/moonshotai/kimi-k2.7-code",
|
|
2192
|
+
"@cf/zai-org/glm-5.2",
|
|
2193
|
+
"@cf/mistralai/mistral-small-3.1-24b-instruct",
|
|
2194
|
+
],
|
|
2195
|
+
note: "Workers AI · Free tier included · Account ID required in base URL",
|
|
2196
|
+
},
|
|
2197
|
+
// FREEZE 2026-07-10: /models was auth-gated under key login. OAuth device-flow + copilot_internal
|
|
2198
|
+
// exchange (issue #151) unlocks live discovery; static seed is a cold-start fallback only.
|
|
2199
|
+
{
|
|
2200
|
+
id: "github-copilot",
|
|
2201
|
+
label: "GitHub Copilot",
|
|
2202
|
+
baseUrl: "https://api.githubcopilot.com",
|
|
2203
|
+
adapter: "openai-chat",
|
|
2204
|
+
authKind: "oauth",
|
|
2205
|
+
allowKeyAuthOverride: true,
|
|
2206
|
+
featured: false,
|
|
2207
|
+
dashboardUrl: "https://github.com/settings/copilot",
|
|
2208
|
+
liveModels: true,
|
|
2209
|
+
models: ["gpt-4o", "gpt-4.1", "gpt-4.1-mini", "claude-sonnet-4", "gemini-2.5-pro", "gpt-5-mini", "gpt-5.3-codex", "gpt-5.4", "gpt-5.4-mini", "gpt-5.5", "gpt-5.6-luna", "gpt-5.6-sol", "gpt-5.6-terra"],
|
|
2210
|
+
defaultModel: "gpt-4o",
|
|
2211
|
+
// Copilot fronts a mixed-wire catalog: these models reject /chat/completions for
|
|
2212
|
+
// real Codex-agent traffic (function tools + reasoning), so every inbound wire
|
|
2213
|
+
// rides Responses. Evidence: issue #748 field runs, pi.dev/models/github-copilot/*
|
|
2214
|
+
// wire declarations, BerriAI/litellm#23332 (gpt-5.4), JetBrains LLM-29711
|
|
2215
|
+
// (gpt-5.6-sol). gpt-5.4-nano is deliberately absent — it has no field report; a
|
|
2216
|
+
// user can opt it in with an explicit modelAdapters entry, which always wins.
|
|
2217
|
+
modelWireDefaults: {
|
|
2218
|
+
"gpt-5.3-codex": "openai-responses",
|
|
2219
|
+
"gpt-5.4": "openai-responses",
|
|
2220
|
+
"gpt-5.4-mini": "openai-responses",
|
|
2221
|
+
"gpt-5.5": "openai-responses",
|
|
2222
|
+
"gpt-5.6-luna": "openai-responses",
|
|
2223
|
+
"gpt-5.6-sol": "openai-responses",
|
|
2224
|
+
"gpt-5.6-terra": "openai-responses",
|
|
2225
|
+
},
|
|
2226
|
+
note: "Experimental unofficial Copilot bridge. Logs in via GitHub device flow using the public VS Code OAuth client id, then exchanges for a short-lived Copilot API token (copilot_internal). Requires an active Copilot subscription. GitHub may tighten or revoke this path; do not send confidential material you would not paste into Copilot Chat.",
|
|
2227
|
+
},
|
|
2228
|
+
// FREEZE 2026-07-10: no public OpenAI-compatible endpoint is documented. Evidence: devlog/_plan/260710_provider_hardening/003_research_aggregators.md.
|
|
2229
|
+
{ id: "gitlab-duo", label: "GitLab Duo", baseUrl: "https://cloud.gitlab.com/ai/v1/proxy/openai/v1", adapter: "openai-chat", authKind: "key", dashboardUrl: "https://gitlab.com/-/user_settings/personal_access_tokens" },
|
|
2230
|
+
];
|
|
2231
|
+
|
|
2232
|
+
export function getProviderRegistryEntry(id: string): ProviderRegistryEntry | undefined {
|
|
2233
|
+
return PROVIDER_REGISTRY.find(entry => entry.id === id);
|
|
2234
|
+
}
|
|
2235
|
+
|
|
2236
|
+
function normalizedProviderEndpoint(value: string): string {
|
|
2237
|
+
const trimmed = value.trim();
|
|
2238
|
+
try {
|
|
2239
|
+
const parsed = new URL(trimmed);
|
|
2240
|
+
parsed.pathname = parsed.pathname.replace(/\/+$/, "") || "/";
|
|
2241
|
+
return parsed.toString().replace(/\/$/, "");
|
|
2242
|
+
} catch {
|
|
2243
|
+
return trimmed.replace(/\/+$/, "");
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
|
|
2247
|
+
/**
|
|
2248
|
+
* Whether registry transport defaults own this configured row.
|
|
2249
|
+
*
|
|
2250
|
+
* OAuth/forward providers stay pinned because their credentials must never be sent to an
|
|
2251
|
+
* arbitrary same-named host. Existing key presets keep their historical pinning behavior; a new
|
|
2252
|
+
* preset can opt into collision preservation, in which case its fixed endpoint owns only rows
|
|
2253
|
+
* that still match that destination.
|
|
2254
|
+
*/
|
|
2255
|
+
export function providerMatchesRegistryTransport(
|
|
2256
|
+
id: string,
|
|
2257
|
+
provider: Pick<OcxProviderConfig, "baseUrl" | "adapter"> & Partial<Pick<OcxProviderConfig, "authMode">>,
|
|
2258
|
+
): boolean {
|
|
2259
|
+
const entry = getProviderRegistryEntry(id);
|
|
2260
|
+
if (!entry) return false;
|
|
2261
|
+
if (entry.authKind !== "key" || entry.preserveCustomDestination !== true) return true;
|
|
2262
|
+
// The opt-in is intentionally limited to fixed key destinations. Fail closed if a future
|
|
2263
|
+
// registry edit combines it with an override/template despite the registry parity tests.
|
|
2264
|
+
if (entry.allowBaseUrlOverride || /\{[^}]*\}/.test(entry.baseUrl)) return false;
|
|
2265
|
+
if (typeof provider.baseUrl !== "string") return false;
|
|
2266
|
+
if (provider.adapter !== entry.adapter) return false;
|
|
2267
|
+
if (provider.authMode !== undefined && provider.authMode !== "key") return false;
|
|
2268
|
+
return normalizedProviderEndpoint(provider.baseUrl) === normalizedProviderEndpoint(entry.baseUrl);
|
|
2269
|
+
}
|
|
2270
|
+
|
|
2271
|
+
/**
|
|
2272
|
+
* Resolve the registry entry a configured provider actually points at, by TRANSPORT
|
|
2273
|
+
* rather than by name.
|
|
2274
|
+
*
|
|
2275
|
+
* `providerMatchesRegistryTransport` answers "does the row named X still point at X's
|
|
2276
|
+
* documented destination", which is the right question for routing but the wrong one
|
|
2277
|
+
* for user-facing metadata: the GUI lets a preset be saved under any name, and a
|
|
2278
|
+
* renamed row would silently lose a usage restriction it still needs to display.
|
|
2279
|
+
*
|
|
2280
|
+
* Only fixed key destinations are matched. Entries with an overridable or templated
|
|
2281
|
+
* base URL are skipped, because their configured URL cannot identify one vendor route.
|
|
2282
|
+
*/
|
|
2283
|
+
export function registryEntryForProviderDestination(
|
|
2284
|
+
provider: Pick<OcxProviderConfig, "baseUrl" | "adapter"> & Partial<Pick<OcxProviderConfig, "authMode">>,
|
|
2285
|
+
): ProviderRegistryEntry | undefined {
|
|
2286
|
+
if (typeof provider.baseUrl !== "string" || !provider.baseUrl) return undefined;
|
|
2287
|
+
if (provider.authMode !== undefined && provider.authMode !== "key") return undefined;
|
|
2288
|
+
const endpoint = normalizedProviderEndpoint(provider.baseUrl);
|
|
2289
|
+
return PROVIDER_REGISTRY.find(entry =>
|
|
2290
|
+
entry.authKind === "key"
|
|
2291
|
+
&& !entry.allowBaseUrlOverride
|
|
2292
|
+
&& !/\{[^}]*\}/.test(entry.baseUrl)
|
|
2293
|
+
&& entry.adapter === provider.adapter
|
|
2294
|
+
&& normalizedProviderEndpoint(entry.baseUrl) === endpoint);
|
|
2295
|
+
}
|
|
2296
|
+
|
|
2297
|
+
/**
|
|
2298
|
+
* Resolve a registry-only default for a mixed-wire provider. Defaults only move a provider
|
|
2299
|
+
* between the two OpenAI-shaped adapters and never override a provider configured on another
|
|
2300
|
+
* wire. The resolver receives the allow-list so this helper cannot accidentally widen the
|
|
2301
|
+
* adapter-selection boundary when a new registry entry is added.
|
|
2302
|
+
*/
|
|
2303
|
+
export function providerModelWireDefault(
|
|
2304
|
+
id: string,
|
|
2305
|
+
provider: Pick<OcxProviderConfig, "baseUrl" | "adapter"> & Partial<Pick<OcxProviderConfig, "authMode">>,
|
|
2306
|
+
modelId: string,
|
|
2307
|
+
allowedWires: ReadonlySet<string>,
|
|
2308
|
+
inbound: InboundWire,
|
|
2309
|
+
): string | undefined {
|
|
2310
|
+
if (!allowedWires.has(provider.adapter)) return undefined;
|
|
2311
|
+
const entry = getProviderRegistryEntry(id);
|
|
2312
|
+
if (!entry?.modelWireDefaults || !providerMatchesRegistryTransport(id, provider)) return undefined;
|
|
2313
|
+
const declared = entry.modelWireDefaults[modelId.trim().toLowerCase()];
|
|
2314
|
+
if (declared === undefined) return undefined;
|
|
2315
|
+
// A bare string applies to every inbound; the object form only to the listed ones.
|
|
2316
|
+
if (typeof declared !== "string" && !declared.inbound.includes(inbound)) return undefined;
|
|
2317
|
+
const wire = typeof declared === "string" ? declared : declared.wire;
|
|
2318
|
+
return wire !== undefined && allowedWires.has(wire) ? wire : undefined;
|
|
2319
|
+
}
|
|
2320
|
+
|
|
2321
|
+
/** Resolve a registry-only upstream-streaming compatibility hint for Responses turns. */
|
|
2322
|
+
export function providerModelResponsesUpstreamStreaming(
|
|
2323
|
+
id: string,
|
|
2324
|
+
provider: Pick<OcxProviderConfig, "baseUrl" | "adapter"> & Partial<Pick<OcxProviderConfig, "authMode">>,
|
|
2325
|
+
modelId: string,
|
|
2326
|
+
): boolean | undefined {
|
|
2327
|
+
const entry = getProviderRegistryEntry(id);
|
|
2328
|
+
if (!entry?.modelResponsesUpstreamStreaming || !providerMatchesRegistryTransport(id, provider)) return undefined;
|
|
2329
|
+
return entry.modelResponsesUpstreamStreaming[modelId.trim().toLowerCase()];
|
|
2330
|
+
}
|
|
2331
|
+
|
|
2332
|
+
/**
|
|
2333
|
+
* Resolve a fixed-destination provider's registry-owned non-JSON status retry list.
|
|
2334
|
+
*
|
|
2335
|
+
* This intentionally uses stricter matching than `providerMatchesRegistryTransport`:
|
|
2336
|
+
* a same-named custom destination must never inherit a retry for the registry host.
|
|
2337
|
+
*/
|
|
2338
|
+
export function providerPreStreamNonJsonRetryStatuses(
|
|
2339
|
+
id: string,
|
|
2340
|
+
provider: Pick<OcxProviderConfig, "baseUrl" | "adapter"> & Partial<Pick<OcxProviderConfig, "authMode">>,
|
|
2341
|
+
): readonly number[] {
|
|
2342
|
+
const entry = getProviderRegistryEntry(id);
|
|
2343
|
+
if (!entry?.preStreamNonJsonRetryStatuses?.length) return [];
|
|
2344
|
+
if (entry.authKind !== "key" || entry.allowBaseUrlOverride || /\{[^}]*\}/.test(entry.baseUrl)) return [];
|
|
2345
|
+
if (provider.adapter !== entry.adapter) return [];
|
|
2346
|
+
if (provider.authMode !== undefined && provider.authMode !== "key") return [];
|
|
2347
|
+
if (normalizedProviderEndpoint(provider.baseUrl) !== normalizedProviderEndpoint(entry.baseUrl)) return [];
|
|
2348
|
+
return entry.preStreamNonJsonRetryStatuses;
|
|
2349
|
+
}
|
|
2350
|
+
|
|
2351
|
+
/**
|
|
2352
|
+
* Effective Codex account mode for a provider. For canonical `openai`, a valid persisted
|
|
2353
|
+
* `codexAccountMode` on the provider config wins and a missing/invalid value defaults to
|
|
2354
|
+
* `"pool"`. Other providers keep registry-only metadata (there is no mode for `openai-apikey`).
|
|
2355
|
+
*/
|
|
2356
|
+
export function providerCodexAccountMode(id: string, provider?: OcxProviderConfig): CodexAccountMode | undefined {
|
|
2357
|
+
const registryMode = getProviderRegistryEntry(id)?.codexAccountMode;
|
|
2358
|
+
if (id !== "openai") return registryMode;
|
|
2359
|
+
const persisted = provider?.codexAccountMode;
|
|
2360
|
+
if (persisted === "pool" || persisted === "direct") return persisted;
|
|
2361
|
+
return registryMode ?? "pool";
|
|
2362
|
+
}
|
|
2363
|
+
|
|
2364
|
+
/**
|
|
2365
|
+
* Effective Google wire mode for a provider: config value, else registry backfill (a saved
|
|
2366
|
+
* key-login config may omit `googleMode` — mirrors the router's backfill), else "ai-studio"
|
|
2367
|
+
* (the Generative Language API default). Null for non-google adapters.
|
|
2368
|
+
*/
|
|
2369
|
+
export function effectiveGoogleMode(
|
|
2370
|
+
providerId: string,
|
|
2371
|
+
prov: { adapter?: string; googleMode?: "ai-studio" | "vertex" | "cloud-code-assist" },
|
|
2372
|
+
): "ai-studio" | "vertex" | "cloud-code-assist" | null {
|
|
2373
|
+
if (prov.adapter !== "google") return null;
|
|
2374
|
+
return prov.googleMode ?? getProviderRegistryEntry(providerId)?.googleMode ?? "ai-studio";
|
|
2375
|
+
}
|