diff --git a/packages/ai/.changes/res-1273-catalog-generation-invariants.md b/packages/ai/.changes/res-1273-catalog-generation-invariants.md new file mode 100644 index 0000000000..2e8951900f --- /dev/null +++ b/packages/ai/.changes/res-1273-catalog-generation-invariants.md @@ -0,0 +1,5 @@ +- Fixed GitHub Copilot Grok and MAI-Code models failing on chat completions by routing them through the Copilot Responses API. +- Raised the Codex subscription (openai-codex) context window for the GPT-5.6 family from 272k to the full 1,050,000 measured on the API side. +- Added low/high reasoning effort levels for Kimi K3 on effort-capable providers (OpenRouter, Prime Inference, Hugging Face, Fireworks, opencode, Kimi Coding, Vercel); the Moonshot and GitHub Copilot transports cannot send effort, so their rows now advertise no selectable levels instead of a no-op max. +- Fixed thinkingmachines/Inkling-Small advertising a maxTokens above its context window. +- Catalog regeneration now validates invariants (maxTokens vs context window, Copilot API classification, Codex context divergence, cross-provider thinking-level consistency) and fails instead of writing a violating catalog. diff --git a/packages/ai/scripts/generate-models.ts b/packages/ai/scripts/generate-models.ts index 5a942ab3a7..b4cc9f8948 100644 --- a/packages/ai/scripts/generate-models.ts +++ b/packages/ai/scripts/generate-models.ts @@ -4,6 +4,13 @@ import { writeFileSync } from "fs"; import { dirname, join } from "path"; import { fileURLToPath } from "url"; import { getAnthropicCacheCosts } from "../src/cache-pricing.js"; +import { supportsAdaptiveThinking } from "../src/providers/anthropic.js"; +import { getCompat } from "../src/providers/openai-completions.js"; +import { + CODEX_SMALLER_WINDOW_VERIFIED, + copilotModelApi, + validateModelCatalog, +} from "./validate-model-catalog.js"; import { COPILOT_CLIENT_HEADERS } from "../src/copilot-client-version.js"; import { getOpenRouterReasoningCapabilities } from "../src/openrouter-reasoning.js"; import { @@ -96,9 +103,9 @@ const DEEPSEEK_V4_THINKING_LEVEL_MAP = { const KIMI_K3_THINKING_LEVEL_MAP = { off: null, minimal: null, - low: null, + low: "low", medium: null, - high: null, + high: "high", xhigh: null, max: "max", } as const; @@ -1257,17 +1264,8 @@ async function loadModelsDevData(): Promise[]> { if (m.tool_call !== true) continue; if (m.status === "deprecated") continue; - // Copilot proxies Claude via the Anthropic Messages API - const isCopilotClaude = modelId.startsWith("claude-"); - // gpt-5/gpt-6 models require responses API, others use completions - const needsResponsesApi = - modelId.startsWith("gpt-5") || modelId.startsWith("gpt-6") || modelId.startsWith("oswe"); - - const api: Api = isCopilotClaude - ? "anthropic-messages" - : needsResponsesApi - ? "openai-responses" - : "openai-completions"; + // Unclassified families still ship a row so validation reports them by name instead of silently misrouting. + const api: Api = copilotModelApi(modelId) ?? "openai-completions"; const anthropicCompat = api === "anthropic-messages" ? getAnthropicMessagesCompat("github-copilot", modelId) : undefined; @@ -1456,6 +1454,14 @@ async function loadModelsDevData(): Promise[]> { } } + // models.dev rows occasionally carry an output limit above the context window; clamp to keep the pair coherent. + for (const model of models) { + if (model.maxTokens > model.contextWindow) { + console.log(`Clamping ${model.provider}/${model.id} maxTokens ${model.maxTokens} -> ${model.contextWindow}`); + model.maxTokens = model.contextWindow; + } + } + console.log(`Loaded ${models.length} tool-capable models from models.dev`); return models; } catch (error) { @@ -2014,6 +2020,14 @@ async function generateModels() { maxTokens: CODEX_MAX_TOKENS, }, ]; + // The ChatGPT backend accepts the 1M+ API-side window (#1597) except upstream-verified smaller rows. + for (const codexModel of codexModels) { + if (CODEX_SMALLER_WINDOW_VERIFIED.has(codexModel.id)) continue; + const openaiTwin = allModels.find((m) => m.provider === "openai" && m.id === codexModel.id); + if (openaiTwin && openaiTwin.contextWindow >= 1_000_000) { + codexModel.contextWindow = openaiTwin.contextWindow; + } + } allModels.push(...codexModels); // Add missing Grok models @@ -2259,6 +2273,30 @@ async function generateModels() { applyThinkingLevelMetadata(model); } + // Non-adaptive anthropic-messages rows think via budget tokens, where xhigh/max clamp to high. + for (const model of allModels) { + if (model.api !== "anthropic-messages" || !model.reasoning || !model.thinkingLevelMap) continue; + if (supportsAdaptiveThinking(model.id)) continue; + const phantom = ["xhigh", "max"].filter((level) => model.thinkingLevelMap?.[level] != null); + if (phantom.length === 0) continue; + console.log(`Nulling budget-clamped thinking levels on ${model.provider}/${model.id}: ${phantom.join(", ")}`); + model.thinkingLevelMap = { ...model.thinkingLevelMap, ...Object.fromEntries(phantom.map((level) => [level, null])) }; + } + + // Family maps can land on transports that never send reasoning effort; null them so the UI offers nothing the request drops. + for (const model of allModels) { + if (model.api !== "openai-completions" || !model.reasoning || !model.thinkingLevelMap) continue; + const compat = getCompat(model as Model<"openai-completions">); + if (compat.thinkingFormat !== "openai" || compat.supportsReasoningEffort) continue; + const selectable = Object.entries(model.thinkingLevelMap).filter(([, mapped]) => mapped !== null); + if (selectable.length === 0) continue; + console.log( + `Nulling unsendable thinking levels on ${model.provider}/${model.id}: ${selectable.map(([level]) => level).join(", ")}`, + ); + // All levels explicitly null: absent keys read as supported at runtime. + model.thinkingLevelMap = { off: null, minimal: null, low: null, medium: null, high: null, xhigh: null, max: null }; + } + // Group by provider and deduplicate by model ID const providers: Record>> = {}; for (const model of allModels) { @@ -2272,6 +2310,14 @@ async function generateModels() { } } + const violations = validateModelCatalog(providers); + if (violations.length > 0) { + for (const violation of violations) { + console.error(`Catalog validation: ${violation}`); + } + throw new Error(`Model catalog validation failed with ${violations.length} violation(s); not writing catalog`); + } + // Generate TypeScript file. JSON string literals prevent remote catalog // text from becoming executable source code. const output = renderModelsFile(providers); @@ -2294,4 +2340,7 @@ async function generateModels() { } // Run the generator -generateModels().catch(console.error); +generateModels().catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/packages/ai/scripts/validate-model-catalog.ts b/packages/ai/scripts/validate-model-catalog.ts new file mode 100644 index 0000000000..937deaea01 --- /dev/null +++ b/packages/ai/scripts/validate-model-catalog.ts @@ -0,0 +1,132 @@ +import { getSupportedThinkingLevels } from "../src/models.js"; +import { supportsAdaptiveThinking } from "../src/providers/anthropic.js"; +import { getCompat } from "../src/providers/openai-completions.js"; +import type { Api, Model } from "../src/types.js"; + +/** The subset of a catalog row the invariants read; MODELS rows satisfy it. */ +export interface CatalogRowLike { + id: string; + api: string; + provider: string; + contextWindow: number; + maxTokens: number; + reasoning: boolean; + baseUrl?: string; + thinkingLevelMap?: Readonly>; + compat?: Readonly>; +} + +export type CatalogLike = Readonly>>>; + +/** Copilot serves each model family through exactly one endpoint; unclassified ids fail validation. */ +export function copilotModelApi(modelId: string): Api | undefined { + if (modelId.startsWith("claude-")) return "anthropic-messages"; + // Responses-only on Copilot; /chat/completions rejects these families (upstream pi-mono #906). + if ( + modelId.startsWith("gpt-5") || + modelId.startsWith("gpt-6") || + modelId.startsWith("oswe") || + modelId.startsWith("grok-") || + modelId.startsWith("mai-") + ) { + return "openai-responses"; + } + if (modelId.startsWith("gemini-") || modelId.startsWith("kimi-")) return "openai-completions"; + return undefined; +} + +// ChatGPT-backend window verified smaller than the API side (Codex CLI models.json, rust-v0.153.4). +export const CODEX_SMALLER_WINDOW_VERIFIED = new Set(["gpt-6-astra"]); + +function familyKey(modelId: string): string { + const segments = modelId.split("/"); + return segments[segments.length - 1].toLowerCase(); +} + +// Runtime-selectable levels via the UI's own function; compared within one transport, declared maps only, modulo "off". +function selectableLevels(model: CatalogRowLike): string { + return getSupportedThinkingLevels(model as Model) + .filter((level) => level !== "off") + .join(","); +} + +// Plain openai-format completions gate reasoning params on compat; other formats use the map as an enable toggle. +function effortIsSendable(model: CatalogRowLike): boolean { + // Model requires baseUrl, so rows without one behave like the empty-string rows: provider-only detection. + const compat = getCompat({ ...model, baseUrl: model.baseUrl ?? "" } as Model<"openai-completions">); + return compat.thinkingFormat !== "openai" || compat.supportsReasoningEffort; +} + +/** Generation-time catalog invariants; an empty return means the catalog is valid. */ +export function validateModelCatalog(catalog: CatalogLike): string[] { + const violations: string[] = []; + + for (const [provider, models] of Object.entries(catalog)) { + for (const model of Object.values(models)) { + if (model.maxTokens > model.contextWindow) { + violations.push( + `${provider}/${model.id}: maxTokens ${model.maxTokens} exceeds contextWindow ${model.contextWindow}`, + ); + } + } + } + + for (const model of Object.values(catalog["github-copilot"] ?? {})) { + const expectedApi = copilotModelApi(model.id); + if (expectedApi === undefined) { + violations.push( + `github-copilot/${model.id}: unclassified model family; add it to copilotModelApi in validate-model-catalog.ts`, + ); + } else if (model.api !== expectedApi) { + violations.push(`github-copilot/${model.id}: api ${model.api} does not match classification ${expectedApi}`); + } + } + + for (const model of Object.values(catalog["openai-codex"] ?? {})) { + const openaiTwin = catalog.openai?.[model.id]; + if (!openaiTwin || CODEX_SMALLER_WINDOW_VERIFIED.has(model.id)) continue; + const ratio = openaiTwin.contextWindow / model.contextWindow; + if (ratio > 2 || ratio < 0.5) { + violations.push( + `openai-codex/${model.id}: contextWindow ${model.contextWindow} diverges more than 2x from openai/${model.id} (${openaiTwin.contextWindow})`, + ); + } + } + + const familyLevels = new Map>(); + for (const [provider, models] of Object.entries(catalog)) { + for (const model of Object.values(models)) { + if (!model.thinkingLevelMap || !model.reasoning) continue; + if (model.api === "anthropic-messages" && !supportsAdaptiveThinking(model.id)) { + const clamped = ["xhigh", "max"].filter((level) => model.thinkingLevelMap?.[level] != null); + if (clamped.length > 0) { + violations.push( + `${provider}/${model.id}: thinkingLevelMap offers [${clamped.join(",")}] but the budget path serializes them as high`, + ); + } + } + if (model.api === "openai-completions" && !effortIsSendable(model)) { + const levels = selectableLevels(model); + if (levels.length > 0) { + violations.push( + `${provider}/${model.id}: thinkingLevelMap offers [${levels}] but the transport cannot send reasoning effort`, + ); + } + continue; + } + const key = `${familyKey(model.id)} [${model.api}]`; + const seen = familyLevels.get(key) ?? new Map(); + seen.set(`${provider}/${model.id}`, selectableLevels(model)); + familyLevels.set(key, seen); + } + } + for (const [key, seen] of familyLevels) { + const distinct = new Set(seen.values()); + if (distinct.size > 1) { + const detail = [...seen.entries()].map(([row, levels]) => `${row}=[${levels}]`).join(", "); + violations.push(`${key}: selectable thinking levels disagree across providers: ${detail}`); + } + } + + return violations; +} diff --git a/packages/ai/src/models.generated.ts b/packages/ai/src/models.generated.ts index ff0f332401..54bf0a61bc 100644 --- a/packages/ai/src/models.generated.ts +++ b/packages/ai/src/models.generated.ts @@ -886,6 +886,23 @@ export const MODELS = { contextWindow: 1050000, maxTokens: 128000, } satisfies Model<"bedrock-converse-stream">, + "global.xai.grok-4.6": { + id: "global.xai.grok-4.6", + name: "Grok 4.6 (Global)", + api: "bedrock-converse-stream", + provider: "amazon-bedrock", + baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", + reasoning: true, + input: ["text", "image"], + cost: { + input: 2, + output: 6, + cacheRead: 0.5, + cacheWrite: 0, + }, + contextWindow: 500000, + maxTokens: 500000, + } satisfies Model<"bedrock-converse-stream">, "google.gemma-3-27b-it": { id: "google.gemma-3-27b-it", name: "Google Gemma 3 27B Instruct", @@ -2009,6 +2026,23 @@ export const MODELS = { contextWindow: 3500000, maxTokens: 16384, } satisfies Model<"bedrock-converse-stream">, + "us.xai.grok-4.6": { + id: "us.xai.grok-4.6", + name: "Grok 4.6 (US)", + api: "bedrock-converse-stream", + provider: "amazon-bedrock", + baseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com", + reasoning: true, + input: ["text", "image"], + cost: { + input: 2.2, + output: 6.6, + cacheRead: 0.55, + cacheWrite: 0, + }, + contextWindow: 500000, + maxTokens: 500000, + } satisfies Model<"bedrock-converse-stream">, "writer.palmyra-x4-v1:0": { id: "writer.palmyra-x4-v1:0", name: "Palmyra X4", @@ -3119,39 +3153,39 @@ export const MODELS = { } satisfies Model<"azure-openai-responses">, }, "cerebras": { - "gemma-4-31b": { - id: "gemma-4-31b", - name: "Gemma 4 31B IT", + "gpt-oss-120b": { + id: "gpt-oss-120b", + name: "GPT OSS 120B", api: "openai-completions", provider: "cerebras", baseUrl: "https://api.cerebras.ai/v1", reasoning: true, - input: ["text", "image"], + input: ["text"], cost: { - input: 0.99, - output: 1.49, + input: 0.35, + output: 0.75, cacheRead: 0, cacheWrite: 0, }, contextWindow: 131072, maxTokens: 40960, } satisfies Model<"openai-completions">, - "gpt-oss-120b": { - id: "gpt-oss-120b", - name: "GPT OSS 120B", + "qwen-3.8-27b": { + id: "qwen-3.8-27b", + name: "Qwen3.8 27B", api: "openai-completions", provider: "cerebras", baseUrl: "https://api.cerebras.ai/v1", reasoning: true, - input: ["text"], + input: ["text", "image"], cost: { - input: 0.35, - output: 0.75, + input: 0.99, + output: 1.49, cacheRead: 0, cacheWrite: 0, }, - contextWindow: 131072, - maxTokens: 40960, + contextWindow: 65536, + maxTokens: 32768, } satisfies Model<"openai-completions">, }, "cloudflare-ai-gateway": { @@ -4267,7 +4301,7 @@ export const MODELS = { provider: "fireworks", baseUrl: "https://api.fireworks.ai/inference", reasoning: true, - thinkingLevelMap: {"off":null,"minimal":null,"low":null,"medium":null,"high":null,"xhigh":null,"max":"max"}, + thinkingLevelMap: {"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":null}, input: ["text", "image"], cost: { input: 3, @@ -4421,7 +4455,7 @@ export const MODELS = { provider: "fireworks", baseUrl: "https://api.fireworks.ai/inference", reasoning: true, - thinkingLevelMap: {"off":null,"minimal":null,"low":null,"medium":null,"high":null,"xhigh":null,"max":"max"}, + thinkingLevelMap: {"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":null}, input: ["text", "image"], cost: { input: 4.5, @@ -4855,11 +4889,10 @@ export const MODELS = { "grok-4.5": { id: "grok-4.5", name: "Grok 4.5", - api: "openai-completions", + api: "openai-responses", provider: "github-copilot", baseUrl: "https://api.individual.githubcopilot.com", headers: {"User-Agent":"GitHubCopilotChat/0.48.1","Editor-Version":"vscode/1.136.1","Editor-Plugin-Version":"copilot-chat/0.48.1","Copilot-Integration-Id":"vscode-chat"}, - compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false}, reasoning: true, input: ["text", "image"], cost: { @@ -4870,15 +4903,14 @@ export const MODELS = { }, contextWindow: 500000, maxTokens: 128000, - } satisfies Model<"openai-completions">, + } satisfies Model<"openai-responses">, "grok-4.6": { id: "grok-4.6", name: "Grok 4.6", - api: "openai-completions", + api: "openai-responses", provider: "github-copilot", baseUrl: "https://api.individual.githubcopilot.com", headers: {"User-Agent":"GitHubCopilotChat/0.48.1","Editor-Version":"vscode/1.136.1","Editor-Plugin-Version":"copilot-chat/0.48.1","Copilot-Integration-Id":"vscode-chat"}, - compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false}, reasoning: true, input: ["text", "image"], cost: { @@ -4889,7 +4921,7 @@ export const MODELS = { }, contextWindow: 500000, maxTokens: 128000, - } satisfies Model<"openai-completions">, + } satisfies Model<"openai-responses">, "kimi-k2.7-code": { id: "kimi-k2.7-code", name: "Kimi K2.7 Code", @@ -4918,7 +4950,7 @@ export const MODELS = { headers: {"User-Agent":"GitHubCopilotChat/0.48.1","Editor-Version":"vscode/1.136.1","Editor-Plugin-Version":"copilot-chat/0.48.1","Copilot-Integration-Id":"vscode-chat"}, compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false}, reasoning: true, - thinkingLevelMap: {"off":null,"minimal":null,"low":null,"medium":null,"high":null,"xhigh":null,"max":"max"}, + thinkingLevelMap: {"off":null,"minimal":null,"low":null,"medium":null,"high":null,"xhigh":null,"max":null}, input: ["text", "image"], cost: { input: 3, @@ -4932,11 +4964,10 @@ export const MODELS = { "mai-code-1-flash-picker": { id: "mai-code-1-flash-picker", name: "MAI-Code-1-Flash", - api: "openai-completions", + api: "openai-responses", provider: "github-copilot", baseUrl: "https://api.individual.githubcopilot.com", headers: {"User-Agent":"GitHubCopilotChat/0.48.1","Editor-Version":"vscode/1.136.1","Editor-Plugin-Version":"copilot-chat/0.48.1","Copilot-Integration-Id":"vscode-chat"}, - compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false}, reasoning: true, input: ["text"], cost: { @@ -4947,15 +4978,14 @@ export const MODELS = { }, contextWindow: 256000, maxTokens: 128000, - } satisfies Model<"openai-completions">, + } satisfies Model<"openai-responses">, "mai-code-1.1-flash": { id: "mai-code-1.1-flash", name: "MAI-Code-1.1-Flash", - api: "openai-completions", + api: "openai-responses", provider: "github-copilot", baseUrl: "https://api.individual.githubcopilot.com", headers: {"User-Agent":"GitHubCopilotChat/0.48.1","Editor-Version":"vscode/1.136.1","Editor-Plugin-Version":"copilot-chat/0.48.1","Copilot-Integration-Id":"vscode-chat"}, - compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false}, reasoning: true, input: ["text", "image"], cost: { @@ -4966,7 +4996,7 @@ export const MODELS = { }, contextWindow: 256000, maxTokens: 128000, - } satisfies Model<"openai-completions">, + } satisfies Model<"openai-responses">, }, "google": { "gemini-2.5-flash": { @@ -6546,7 +6576,7 @@ export const MODELS = { baseUrl: "https://router.huggingface.co/v1", compat: {"supportsDeveloperRole":false}, reasoning: true, - thinkingLevelMap: {"off":null,"minimal":null,"low":null,"medium":null,"high":null,"xhigh":null,"max":"max"}, + thinkingLevelMap: {"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"}, input: ["text", "image"], cost: { input: 3, @@ -6681,7 +6711,7 @@ export const MODELS = { cacheWrite: 0, }, contextWindow: 524288, - maxTokens: 1048576, + maxTokens: 524288, } satisfies Model<"openai-completions">, "zai-org/GLM-4.5": { id: "zai-org/GLM-4.5", @@ -6909,7 +6939,7 @@ export const MODELS = { baseUrl: "https://api.kimi.com/coding", headers: {"User-Agent":"KimiCLI/1.5"}, reasoning: true, - thinkingLevelMap: {"off":null,"minimal":null,"low":null,"medium":null,"high":null,"xhigh":null,"max":"max"}, + thinkingLevelMap: {"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":null}, input: ["text", "image"], cost: { input: 0, @@ -6928,7 +6958,7 @@ export const MODELS = { baseUrl: "https://api.kimi.com/coding", headers: {"User-Agent":"KimiCLI/1.5"}, reasoning: true, - thinkingLevelMap: {"off":null,"minimal":null,"low":null,"medium":null,"high":null,"xhigh":null,"max":"max"}, + thinkingLevelMap: {"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":null}, input: ["text", "image"], cost: { input: 0, @@ -7595,120 +7625,87 @@ export const MODELS = { } satisfies Model<"mistral-conversations">, }, "moonshotai": { - "kimi-k2-0711-preview": { - id: "kimi-k2-0711-preview", - name: "Kimi K2 0711", - api: "openai-completions", - provider: "moonshotai", - baseUrl: "https://api.moonshot.ai/v1", - compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false}, - reasoning: false, - input: ["text"], - cost: { - input: 0.6, - output: 2.5, - cacheRead: 0.15, - cacheWrite: 0, - }, - contextWindow: 131072, - maxTokens: 16384, - } satisfies Model<"openai-completions">, - "kimi-k2-0905-preview": { - id: "kimi-k2-0905-preview", - name: "Kimi K2 0905", + "kimi-k2.6": { + id: "kimi-k2.6", + name: "Kimi K2.6", api: "openai-completions", provider: "moonshotai", baseUrl: "https://api.moonshot.ai/v1", compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false}, - reasoning: false, - input: ["text"], + reasoning: true, + input: ["text", "image"], cost: { - input: 0.6, - output: 2.5, - cacheRead: 0.15, + input: 0.95, + output: 4, + cacheRead: 0.16, cacheWrite: 0, }, contextWindow: 262144, maxTokens: 262144, } satisfies Model<"openai-completions">, - "kimi-k2-thinking": { - id: "kimi-k2-thinking", - name: "Kimi K2 Thinking", + "kimi-k2.7-code": { + id: "kimi-k2.7-code", + name: "Kimi K2.7 Code", api: "openai-completions", provider: "moonshotai", baseUrl: "https://api.moonshot.ai/v1", compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false}, reasoning: true, - input: ["text"], + input: ["text", "image"], cost: { - input: 0.6, - output: 2.5, - cacheRead: 0.15, + input: 0.95, + output: 4, + cacheRead: 0.19, cacheWrite: 0, }, contextWindow: 262144, maxTokens: 262144, } satisfies Model<"openai-completions">, - "kimi-k2-thinking-turbo": { - id: "kimi-k2-thinking-turbo", - name: "Kimi K2 Thinking Turbo", + "kimi-k2.7-code-highspeed": { + id: "kimi-k2.7-code-highspeed", + name: "Kimi K2.7 Code HighSpeed", api: "openai-completions", provider: "moonshotai", baseUrl: "https://api.moonshot.ai/v1", compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false}, reasoning: true, - input: ["text"], + input: ["text", "image"], cost: { - input: 1.15, + input: 1.9, output: 8, - cacheRead: 0.15, - cacheWrite: 0, - }, - contextWindow: 262144, - maxTokens: 262144, - } satisfies Model<"openai-completions">, - "kimi-k2-turbo-preview": { - id: "kimi-k2-turbo-preview", - name: "Kimi K2 Turbo", - api: "openai-completions", - provider: "moonshotai", - baseUrl: "https://api.moonshot.ai/v1", - compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false}, - reasoning: false, - input: ["text"], - cost: { - input: 2.4, - output: 10, - cacheRead: 0.6, + cacheRead: 0.38, cacheWrite: 0, }, contextWindow: 262144, maxTokens: 262144, } satisfies Model<"openai-completions">, - "kimi-k2.5": { - id: "kimi-k2.5", - name: "Kimi K2.5", + "kimi-k3": { + id: "kimi-k3", + name: "Kimi K3", api: "openai-completions", provider: "moonshotai", baseUrl: "https://api.moonshot.ai/v1", compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false}, reasoning: true, + thinkingLevelMap: {"off":null,"minimal":null,"low":null,"medium":null,"high":null,"xhigh":null,"max":null}, input: ["text", "image"], cost: { - input: 0.6, - output: 3, - cacheRead: 0.1, + input: 3, + output: 15, + cacheRead: 0.3, cacheWrite: 0, }, - contextWindow: 262144, - maxTokens: 262144, + contextWindow: 1048576, + maxTokens: 131072, } satisfies Model<"openai-completions">, + }, + "moonshotai-cn": { "kimi-k2.6": { id: "kimi-k2.6", name: "Kimi K2.6", api: "openai-completions", - provider: "moonshotai", - baseUrl: "https://api.moonshot.ai/v1", + provider: "moonshotai-cn", + baseUrl: "https://api.moonshot.cn/v1", compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false}, reasoning: true, input: ["text", "image"], @@ -7725,8 +7722,8 @@ export const MODELS = { id: "kimi-k2.7-code", name: "Kimi K2.7 Code", api: "openai-completions", - provider: "moonshotai", - baseUrl: "https://api.moonshot.ai/v1", + provider: "moonshotai-cn", + baseUrl: "https://api.moonshot.cn/v1", compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false}, reasoning: true, input: ["text", "image"], @@ -7743,8 +7740,8 @@ export const MODELS = { id: "kimi-k2.7-code-highspeed", name: "Kimi K2.7 Code HighSpeed", api: "openai-completions", - provider: "moonshotai", - baseUrl: "https://api.moonshot.ai/v1", + provider: "moonshotai-cn", + baseUrl: "https://api.moonshot.cn/v1", compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false}, reasoning: true, input: ["text", "image"], @@ -7761,11 +7758,11 @@ export const MODELS = { id: "kimi-k3", name: "Kimi K3", api: "openai-completions", - provider: "moonshotai", - baseUrl: "https://api.moonshot.ai/v1", + provider: "moonshotai-cn", + baseUrl: "https://api.moonshot.cn/v1", compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false}, reasoning: true, - thinkingLevelMap: {"off":null,"minimal":null,"low":null,"medium":null,"high":null,"xhigh":null,"max":"max"}, + thinkingLevelMap: {"off":null,"minimal":null,"low":null,"medium":null,"high":null,"xhigh":null,"max":null}, input: ["text", "image"], cost: { input: 3, @@ -7777,236 +7774,53 @@ export const MODELS = { maxTokens: 131072, } satisfies Model<"openai-completions">, }, - "moonshotai-cn": { - "kimi-k2-0711-preview": { - id: "kimi-k2-0711-preview", - name: "Kimi K2 0711", - api: "openai-completions", - provider: "moonshotai-cn", - baseUrl: "https://api.moonshot.cn/v1", - compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false}, + "openai": { + "gpt-4": { + id: "gpt-4", + name: "GPT-4", + api: "openai-responses", + provider: "openai", + baseUrl: "https://api.openai.com/v1", reasoning: false, input: ["text"], cost: { - input: 0.6, - output: 2.5, - cacheRead: 0.15, + input: 30, + output: 60, + cacheRead: 0, cacheWrite: 0, }, - contextWindow: 131072, - maxTokens: 16384, - } satisfies Model<"openai-completions">, - "kimi-k2-0905-preview": { - id: "kimi-k2-0905-preview", - name: "Kimi K2 0905", - api: "openai-completions", - provider: "moonshotai-cn", - baseUrl: "https://api.moonshot.cn/v1", - compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false}, + contextWindow: 8192, + maxTokens: 8192, + } satisfies Model<"openai-responses">, + "gpt-4-turbo": { + id: "gpt-4-turbo", + name: "GPT-4 Turbo", + api: "openai-responses", + provider: "openai", + baseUrl: "https://api.openai.com/v1", reasoning: false, - input: ["text"], - cost: { - input: 0.6, - output: 2.5, - cacheRead: 0.15, - cacheWrite: 0, - }, - contextWindow: 262144, - maxTokens: 262144, - } satisfies Model<"openai-completions">, - "kimi-k2-thinking": { - id: "kimi-k2-thinking", - name: "Kimi K2 Thinking", - api: "openai-completions", - provider: "moonshotai-cn", - baseUrl: "https://api.moonshot.cn/v1", - compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false}, - reasoning: true, - input: ["text"], + input: ["text", "image"], cost: { - input: 0.6, - output: 2.5, - cacheRead: 0.15, + input: 10, + output: 30, + cacheRead: 0, cacheWrite: 0, }, - contextWindow: 262144, - maxTokens: 262144, - } satisfies Model<"openai-completions">, - "kimi-k2-thinking-turbo": { - id: "kimi-k2-thinking-turbo", - name: "Kimi K2 Thinking Turbo", - api: "openai-completions", - provider: "moonshotai-cn", - baseUrl: "https://api.moonshot.cn/v1", - compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false}, - reasoning: true, - input: ["text"], + contextWindow: 128000, + maxTokens: 4096, + } satisfies Model<"openai-responses">, + "gpt-4.1": { + id: "gpt-4.1", + name: "GPT-4.1", + api: "openai-responses", + provider: "openai", + baseUrl: "https://api.openai.com/v1", + reasoning: false, + input: ["text", "image"], cost: { - input: 1.15, + input: 2, output: 8, - cacheRead: 0.15, - cacheWrite: 0, - }, - contextWindow: 262144, - maxTokens: 262144, - } satisfies Model<"openai-completions">, - "kimi-k2-turbo-preview": { - id: "kimi-k2-turbo-preview", - name: "Kimi K2 Turbo", - api: "openai-completions", - provider: "moonshotai-cn", - baseUrl: "https://api.moonshot.cn/v1", - compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false}, - reasoning: false, - input: ["text"], - cost: { - input: 2.4, - output: 10, - cacheRead: 0.6, - cacheWrite: 0, - }, - contextWindow: 262144, - maxTokens: 262144, - } satisfies Model<"openai-completions">, - "kimi-k2.5": { - id: "kimi-k2.5", - name: "Kimi K2.5", - api: "openai-completions", - provider: "moonshotai-cn", - baseUrl: "https://api.moonshot.cn/v1", - compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false}, - reasoning: true, - input: ["text", "image"], - cost: { - input: 0.6, - output: 3, - cacheRead: 0.1, - cacheWrite: 0, - }, - contextWindow: 262144, - maxTokens: 262144, - } satisfies Model<"openai-completions">, - "kimi-k2.6": { - id: "kimi-k2.6", - name: "Kimi K2.6", - api: "openai-completions", - provider: "moonshotai-cn", - baseUrl: "https://api.moonshot.cn/v1", - compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false}, - reasoning: true, - input: ["text", "image"], - cost: { - input: 0.95, - output: 4, - cacheRead: 0.16, - cacheWrite: 0, - }, - contextWindow: 262144, - maxTokens: 262144, - } satisfies Model<"openai-completions">, - "kimi-k2.7-code": { - id: "kimi-k2.7-code", - name: "Kimi K2.7 Code", - api: "openai-completions", - provider: "moonshotai-cn", - baseUrl: "https://api.moonshot.cn/v1", - compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false}, - reasoning: true, - input: ["text", "image"], - cost: { - input: 0.95, - output: 4, - cacheRead: 0.19, - cacheWrite: 0, - }, - contextWindow: 262144, - maxTokens: 262144, - } satisfies Model<"openai-completions">, - "kimi-k2.7-code-highspeed": { - id: "kimi-k2.7-code-highspeed", - name: "Kimi K2.7 Code HighSpeed", - api: "openai-completions", - provider: "moonshotai-cn", - baseUrl: "https://api.moonshot.cn/v1", - compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false}, - reasoning: true, - input: ["text", "image"], - cost: { - input: 1.9, - output: 8, - cacheRead: 0.38, - cacheWrite: 0, - }, - contextWindow: 262144, - maxTokens: 262144, - } satisfies Model<"openai-completions">, - "kimi-k3": { - id: "kimi-k3", - name: "Kimi K3", - api: "openai-completions", - provider: "moonshotai-cn", - baseUrl: "https://api.moonshot.cn/v1", - compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false}, - reasoning: true, - thinkingLevelMap: {"off":null,"minimal":null,"low":null,"medium":null,"high":null,"xhigh":null,"max":"max"}, - input: ["text", "image"], - cost: { - input: 3, - output: 15, - cacheRead: 0.3, - cacheWrite: 0, - }, - contextWindow: 1048576, - maxTokens: 131072, - } satisfies Model<"openai-completions">, - }, - "openai": { - "gpt-4": { - id: "gpt-4", - name: "GPT-4", - api: "openai-responses", - provider: "openai", - baseUrl: "https://api.openai.com/v1", - reasoning: false, - input: ["text"], - cost: { - input: 30, - output: 60, - cacheRead: 0, - cacheWrite: 0, - }, - contextWindow: 8192, - maxTokens: 8192, - } satisfies Model<"openai-responses">, - "gpt-4-turbo": { - id: "gpt-4-turbo", - name: "GPT-4 Turbo", - api: "openai-responses", - provider: "openai", - baseUrl: "https://api.openai.com/v1", - reasoning: false, - input: ["text", "image"], - cost: { - input: 10, - output: 30, - cacheRead: 0, - cacheWrite: 0, - }, - contextWindow: 128000, - maxTokens: 4096, - } satisfies Model<"openai-responses">, - "gpt-4.1": { - id: "gpt-4.1", - name: "GPT-4.1", - api: "openai-responses", - provider: "openai", - baseUrl: "https://api.openai.com/v1", - reasoning: false, - input: ["text", "image"], - cost: { - input: 2, - output: 8, - cacheRead: 0.5, + cacheRead: 0.5, cacheWrite: 0, }, contextWindow: 1047576, @@ -8895,7 +8709,7 @@ export const MODELS = { cacheRead: 0.1, cacheWrite: 1.25, }, - contextWindow: 272000, + contextWindow: 1050000, maxTokens: 128000, } satisfies Model<"openai-codex-responses">, "gpt-5.6-sol": { @@ -8913,7 +8727,7 @@ export const MODELS = { cacheRead: 0.5, cacheWrite: 6.25, }, - contextWindow: 272000, + contextWindow: 1050000, maxTokens: 128000, } satisfies Model<"openai-codex-responses">, "gpt-5.6-terra": { @@ -8931,7 +8745,7 @@ export const MODELS = { cacheRead: 0.25, cacheWrite: 3.125, }, - contextWindow: 272000, + contextWindow: 1050000, maxTokens: 128000, } satisfies Model<"openai-codex-responses">, "gpt-6-astra": { @@ -9920,7 +9734,7 @@ export const MODELS = { provider: "opencode", baseUrl: "https://opencode.ai/zen/v1", reasoning: true, - thinkingLevelMap: {"off":null,"minimal":null,"low":null,"medium":null,"high":null,"xhigh":null,"max":"max"}, + thinkingLevelMap: {"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"}, input: ["text", "image"], cost: { input: 3, @@ -10389,7 +10203,7 @@ export const MODELS = { provider: "opencode-go", baseUrl: "https://opencode.ai/zen/go/v1", reasoning: true, - thinkingLevelMap: {"off":null,"minimal":null,"low":null,"medium":null,"high":null,"xhigh":null,"max":"max"}, + thinkingLevelMap: {"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"}, input: ["text", "image"], cost: { input: 3, @@ -11402,9 +11216,9 @@ export const MODELS = { thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","xhigh":"max","max":null}, input: ["text"], cost: { - input: 0.08106, - output: 0.16212, - cacheRead: 0.016212, + input: 0.088606, + output: 0.177212, + cacheRead: 0.017721200000000003, cacheWrite: 0, }, contextWindow: 1048576, @@ -11421,9 +11235,9 @@ export const MODELS = { thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","xhigh":"max","max":null}, input: ["text"], cost: { - input: 0.049980000000000004, - output: 0.09996000000000001, - cacheRead: 0.009996000000000001, + input: 0.14, + output: 0.28, + cacheRead: 0.028, cacheWrite: 0, }, contextWindow: 1310720, @@ -11459,9 +11273,9 @@ export const MODELS = { thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","xhigh":"max","max":null}, input: ["text"], cost: { - input: 0.7078319999999999, - output: 1.4156639999999998, - cacheRead: 0.058986000000000004, + input: 0.9552599999999999, + output: 1.9105199999999998, + cacheRead: 0.07960500000000001, cacheWrite: 0, }, contextWindow: 1048576, @@ -11478,9 +11292,9 @@ export const MODELS = { thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","xhigh":"max","max":null}, input: ["text"], cost: { - input: 1.12068, - output: 3.36204, - cacheRead: 0.037356, + input: 1.0494, + output: 3.1482, + cacheRead: 0.03498, cacheWrite: 0, }, contextWindow: 1048576, @@ -14556,7 +14370,7 @@ export const MODELS = { cacheWrite: 0, }, contextWindow: 262144, - maxTokens: 32768, + maxTokens: 235929, } satisfies Model<"openai-completions">, "qwen/qwen3-vl-235b-a22b-instruct": { id: "qwen/qwen3-vl-235b-a22b-instruct", @@ -14751,13 +14565,13 @@ export const MODELS = { thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":null}, input: ["text", "image"], cost: { - input: 0.55, - output: 3.5, - cacheRead: 0.22499999999999998, + input: 0.39, + output: 2.34, + cacheRead: 0, cacheWrite: 0, }, contextWindow: 262144, - maxTokens: 235929, + maxTokens: 65536, } satisfies Model<"openai-completions">, "qwen/qwen3.5-9b": { id: "qwen/qwen3.5-9b", @@ -15563,13 +15377,13 @@ export const MODELS = { thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":null}, input: ["text"], cost: { - input: 0.55, - output: 2.2, - cacheRead: 0.11, + input: 0.43, + output: 1.75, + cacheRead: 0.08, cacheWrite: 0, }, contextWindow: 204800, - maxTokens: 131072, + maxTokens: 16384, } satisfies Model<"openai-completions">, "z-ai/glm-4.6v": { id: "z-ai/glm-4.6v", @@ -15703,24 +15517,6 @@ export const MODELS = { contextWindow: 1048576, maxTokens: 131072, } satisfies Model<"openai-completions">, - "z-ai/glm-5.2:free": { - id: "z-ai/glm-5.2:free", - name: "Z.ai: GLM 5.2 (free)", - api: "openai-completions", - provider: "openrouter", - baseUrl: "https://openrouter.ai/api/v1", - reasoning: true, - thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","xhigh":"xhigh","max":null}, - input: ["text"], - cost: { - input: 0, - output: 0, - cacheRead: 0, - cacheWrite: 0, - }, - contextWindow: 256000, - maxTokens: 230400, - } satisfies Model<"openai-completions">, "z-ai/glm-5.3": { id: "z-ai/glm-5.3", name: "Z.ai: GLM 5.3", @@ -15733,11 +15529,11 @@ export const MODELS = { cost: { input: 1.4, output: 4.4, - cacheRead: 0.14, + cacheRead: 0.26, cacheWrite: 0, }, contextWindow: 1310720, - maxTokens: 262144, + maxTokens: 943718, } satisfies Model<"openai-completions">, "z-ai/glm-5.3-flash": { id: "z-ai/glm-5.3-flash", @@ -15860,13 +15656,13 @@ export const MODELS = { thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","xhigh":"max","max":null}, input: ["text"], cost: { - input: 0.045, - output: 0.09, - cacheRead: 0.009, + input: 0.049999999999999996, + output: 0.16, + cacheRead: 0.013000000000000001, cacheWrite: 0, }, contextWindow: 1310720, - maxTokens: 943718, + maxTokens: 393216, } satisfies Model<"openai-completions">, "~google/gemini-flash-latest": { id: "~google/gemini-flash-latest", @@ -15986,13 +15782,13 @@ export const MODELS = { thinkingLevelMap: {"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"}, input: ["text", "image"], cost: { - input: 0.075, - output: 0.25, - cacheRead: 0.015, + input: 0.07125000000000001, + output: 0.2375, + cacheRead: 0.01425, cacheWrite: 0, }, contextWindow: 1310720, - maxTokens: 943718, + maxTokens: 131072, } satisfies Model<"openai-completions">, "~z-ai/glm-latest": { id: "~z-ai/glm-latest", @@ -16004,58 +15800,225 @@ export const MODELS = { thinkingLevelMap: {"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"}, input: ["text"], cost: { - input: 1.17, - output: 3.9600000000000004, - cacheRead: 0.234, + input: 1.12, + output: 3.52, + cacheRead: 0.20800000000000002, cacheWrite: 0, }, contextWindow: 1310720, - maxTokens: 235929, + maxTokens: 943718, } satisfies Model<"openai-completions">, }, "prime-inference": { - "anthropic/claude-fable-5": { - id: "anthropic/claude-fable-5", - name: "Claude Fable 5", + "Qwen/Qwen3-235B-A22B-Instruct-2507": { + id: "Qwen/Qwen3-235B-A22B-Instruct-2507", + name: "Qwen3 235B A22B Instruct 2507", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","supportsStrictMode":false}, - reasoning: true, - thinkingLevelMap: {"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"}, - input: ["text", "image"], + reasoning: false, + input: ["text"], cost: { - input: 10, - output: 50, - cacheRead: 1, - cacheWrite: 12.5, + input: 0.25, + output: 1, + cacheRead: 0, + cacheWrite: 0, }, - contextWindow: 1000000, - maxTokens: 128000, - featured: true, + contextWindow: 262144, + maxTokens: 16384, } satisfies Model<"openai-completions">, - "anthropic/claude-fable-5.1": { - id: "anthropic/claude-fable-5.1", - name: "Claude Fable 5.1", + "Qwen/Qwen3-235B-A22B-Thinking-2507": { + id: "Qwen/Qwen3-235B-A22B-Thinking-2507", + name: "Qwen3 235B A22B Thinking 2507", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", - compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","supportsStrictMode":false}, + compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"thinkingFormat":"openrouter"}, reasoning: true, - thinkingLevelMap: {"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"}, - input: ["text", "image"], + thinkingLevelMap: {"off":null,"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":null}, + input: ["text"], cost: { - input: 10, - output: 50, - cacheRead: 1, - cacheWrite: 12.5, + input: 0.3, + output: 3, + cacheRead: 0, + cacheWrite: 0, }, - contextWindow: 1000000, - maxTokens: 128000, + contextWindow: 131072, + maxTokens: 117964, } satisfies Model<"openai-completions">, - "anthropic/claude-haiku-4.5": { - id: "anthropic/claude-haiku-4.5", - name: "Claude Haiku 4.5", + "Qwen/Qwen3-30B-A3B-Thinking-2507": { + id: "Qwen/Qwen3-30B-A3B-Thinking-2507", + name: "Qwen3 30B A3B Thinking 2507", + api: "openai-completions", + provider: "prime-inference", + baseUrl: "https://api.pinference.ai/api/v1", + compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"thinkingFormat":"openrouter"}, + reasoning: true, + thinkingLevelMap: {"off":null,"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":null}, + input: ["text"], + cost: { + input: 0.2, + output: 2.4, + cacheRead: 0, + cacheWrite: 0, + }, + contextWindow: 81920, + maxTokens: 32768, + } satisfies Model<"openai-completions">, + "Qwen/Qwen3-VL-30B-A3B-Thinking": { + id: "Qwen/Qwen3-VL-30B-A3B-Thinking", + name: "Qwen3 VL 30B A3B Thinking", + api: "openai-completions", + provider: "prime-inference", + baseUrl: "https://api.pinference.ai/api/v1", + compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"thinkingFormat":"openrouter"}, + reasoning: true, + thinkingLevelMap: {"off":null,"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":null}, + input: ["text", "image"], + cost: { + input: 0.2, + output: 2.4, + cacheRead: 0, + cacheWrite: 0, + }, + contextWindow: 262144, + maxTokens: 32768, + } satisfies Model<"openai-completions">, + "Qwen/Qwen3.5-0.8B": { + id: "Qwen/Qwen3.5-0.8B", + name: "QWEN3.5 0.8B", + api: "openai-completions", + provider: "prime-inference", + baseUrl: "https://api.pinference.ai/api/v1", + compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","supportsStrictMode":false}, + reasoning: false, + input: ["text"], + cost: { + input: 0.04, + output: 0.08, + cacheRead: 0.036, + cacheWrite: 0.04, + }, + contextWindow: 128000, + maxTokens: 8192, + } satisfies Model<"openai-completions">, + "Qwen/Qwen3.5-122B-A10B": { + id: "Qwen/Qwen3.5-122B-A10B", + name: "QWEN3.5 122B A10B", + api: "openai-completions", + provider: "prime-inference", + baseUrl: "https://api.pinference.ai/api/v1", + compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"thinkingFormat":"openrouter"}, + reasoning: true, + thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":null}, + input: ["text", "image"], + cost: { + input: 0.3, + output: 0.9, + cacheRead: 0.27, + cacheWrite: 0.3, + }, + contextWindow: 262144, + maxTokens: 81920, + } satisfies Model<"openai-completions">, + "Qwen/Qwen3.5-2B": { + id: "Qwen/Qwen3.5-2B", + name: "QWEN3.5 2B", + api: "openai-completions", + provider: "prime-inference", + baseUrl: "https://api.pinference.ai/api/v1", + compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","supportsStrictMode":false}, + reasoning: false, + input: ["text"], + cost: { + input: 0.06, + output: 0.18, + cacheRead: 0.054, + cacheWrite: 0.06, + }, + contextWindow: 128000, + maxTokens: 8192, + } satisfies Model<"openai-completions">, + "Qwen/Qwen3.5-4B": { + id: "Qwen/Qwen3.5-4B", + name: "QWEN3.5 4B", + api: "openai-completions", + provider: "prime-inference", + baseUrl: "https://api.pinference.ai/api/v1", + compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","supportsStrictMode":false}, + reasoning: false, + input: ["text"], + cost: { + input: 0.1, + output: 0.3, + cacheRead: 0.09, + cacheWrite: 0.1, + }, + contextWindow: 128000, + maxTokens: 8192, + } satisfies Model<"openai-completions">, + "Qwen/Qwen3.5-9B": { + id: "Qwen/Qwen3.5-9B", + name: "QWEN3.5 9B", + api: "openai-completions", + provider: "prime-inference", + baseUrl: "https://api.pinference.ai/api/v1", + compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false,"thinkingFormat":"openrouter"}, + reasoning: true, + thinkingLevelMap: {"minimal":null,"low":null,"medium":null,"high":"high","xhigh":null,"max":null}, + input: ["text", "image"], + cost: { + input: 0.18, + output: 0.54, + cacheRead: 0.162, + cacheWrite: 0.18, + }, + contextWindow: 262144, + maxTokens: 235929, + } satisfies Model<"openai-completions">, + "anthropic/claude-fable-5": { + id: "anthropic/claude-fable-5", + name: "Claude Fable 5", + api: "openai-completions", + provider: "prime-inference", + baseUrl: "https://api.pinference.ai/api/v1", + compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","supportsStrictMode":false}, + reasoning: true, + thinkingLevelMap: {"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"}, + input: ["text", "image"], + cost: { + input: 10, + output: 50, + cacheRead: 1, + cacheWrite: 12.5, + }, + contextWindow: 1000000, + maxTokens: 128000, + featured: true, + } satisfies Model<"openai-completions">, + "anthropic/claude-fable-5.1": { + id: "anthropic/claude-fable-5.1", + name: "Claude Fable 5.1", + api: "openai-completions", + provider: "prime-inference", + baseUrl: "https://api.pinference.ai/api/v1", + compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","supportsStrictMode":false}, + reasoning: true, + thinkingLevelMap: {"off":null,"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"}, + input: ["text", "image"], + cost: { + input: 10, + output: 50, + cacheRead: 1, + cacheWrite: 12.5, + }, + contextWindow: 1000000, + maxTokens: 128000, + } satisfies Model<"openai-completions">, + "anthropic/claude-haiku-4.5": { + id: "anthropic/claude-haiku-4.5", + name: "Claude Haiku 4.5", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -16206,7 +16169,7 @@ export const MODELS = { cacheRead: 0.30000000000000004, cacheWrite: 3.75, }, - contextWindow: 200000, + contextWindow: 1000000, maxTokens: 64000, } satisfies Model<"openai-completions">, "anthropic/claude-sonnet-4.5": { @@ -16225,7 +16188,7 @@ export const MODELS = { cacheRead: 0.30000000000000004, cacheWrite: 3.75, }, - contextWindow: 200000, + contextWindow: 1000000, maxTokens: 64000, featured: true, } satisfies Model<"openai-completions">, @@ -16271,7 +16234,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "deepseek/deepseek-chat": { id: "deepseek/deepseek-chat", - name: "Deepseek Chat", + name: "DeepSeek V3", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -16289,7 +16252,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "deepseek/deepseek-chat-v3-0324": { id: "deepseek/deepseek-chat-v3-0324", - name: "Deepseek Chat V3 0324", + name: "DeepSeek V3 0324", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -16307,7 +16270,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "deepseek/deepseek-chat-v3.1": { id: "deepseek/deepseek-chat-v3.1", - name: "Deepseek Chat V3.1", + name: "DeepSeek V3.1", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -16326,7 +16289,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "deepseek/deepseek-v3.1-terminus": { id: "deepseek/deepseek-v3.1-terminus", - name: "Deepseek V3.1 Terminus", + name: "DeepSeek V3.1 Terminus", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -16345,7 +16308,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "deepseek/deepseek-v3.2": { id: "deepseek/deepseek-v3.2", - name: "Deepseek V3.2", + name: "DeepSeek V3.2", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -16365,7 +16328,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "deepseek/deepseek-v3.2-exp": { id: "deepseek/deepseek-v3.2-exp", - name: "Deepseek V3.2 EXP", + name: "DeepSeek V3.2 Exp", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -16384,7 +16347,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "deepseek/deepseek-v4-flash": { id: "deepseek/deepseek-v4-flash", - name: "Deepseek V4 Flash", + name: "DeepSeek V4 Flash 0423", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -16404,7 +16367,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "deepseek/deepseek-v4-flash-0731": { id: "deepseek/deepseek-v4-flash-0731", - name: "Deepseek V4 Flash 0731", + name: "DeepSeek V4 Flash 0731", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -16423,7 +16386,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "deepseek/deepseek-v4-pro": { id: "deepseek/deepseek-v4-pro", - name: "Deepseek V4 PRO", + name: "DeepSeek V4 Pro 0423", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -16481,7 +16444,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "google/gemini-2.5-pro": { id: "google/gemini-2.5-pro", - name: "Gemini 2.5 PRO", + name: "Gemini 2.5 Pro", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -16519,7 +16482,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "google/gemini-3.1-pro-preview": { id: "google/gemini-3.1-pro-preview", - name: "Gemini 3.1 PRO Preview", + name: "Gemini 3.1 Pro Preview", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -16614,7 +16577,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "google/gemma-3-27b-it": { id: "google/gemma-3-27b-it", - name: "Gemma 3 27B IT", + name: "Gemma 3 27B", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -16663,8 +16626,8 @@ export const MODELS = { cacheRead: 0, cacheWrite: 0, }, - contextWindow: 80000, - maxTokens: 80000, + contextWindow: 131072, + maxTokens: 117964, } satisfies Model<"openai-completions">, "meta-llama/llama-3.3-70b-instruct": { id: "meta-llama/llama-3.3-70b-instruct", @@ -16704,7 +16667,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "minimax/minimax-m2.5": { id: "minimax/minimax-m2.5", - name: "Minimax M2.5", + name: "MiniMax M2.5", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -16723,7 +16686,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "minimax/minimax-m2.7": { id: "minimax/minimax-m2.7", - name: "Minimax M2.7", + name: "MiniMax M2.7", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -16742,7 +16705,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "minimax/minimax-m3": { id: "minimax/minimax-m3", - name: "Minimax M3", + name: "MiniMax M3", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -16756,13 +16719,13 @@ export const MODELS = { cacheRead: 0, cacheWrite: 0, }, - contextWindow: 524288, + contextWindow: 1048576, maxTokens: 512000, featured: true, } satisfies Model<"openai-completions">, "mistralai/mistral-large-2512": { id: "mistralai/mistral-large-2512", - name: "Mistral Large 2512", + name: "Mistral Large 3 2512", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -16798,7 +16761,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "mistralai/mistral-small-2603": { id: "mistralai/mistral-small-2603", - name: "Mistral Small 2603", + name: "Mistral Small 4", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -16817,7 +16780,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "mistralai/mixtral-8x22b-instruct": { id: "mistralai/mixtral-8x22b-instruct", - name: "Mixtral 8X22B Instruct", + name: "Mixtral 8x22B Instruct", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -16848,8 +16811,8 @@ export const MODELS = { cacheRead: 0, cacheWrite: 0, }, - contextWindow: 98304, - maxTokens: 98304, + contextWindow: 262144, + maxTokens: 100352, } satisfies Model<"openai-completions">, "moonshotai/kimi-k2.5": { id: "moonshotai/kimi-k2.5", @@ -16868,7 +16831,7 @@ export const MODELS = { cacheWrite: 0, }, contextWindow: 262144, - maxTokens: 65535, + maxTokens: 235929, } satisfies Model<"openai-completions">, "moonshotai/kimi-k2.6": { id: "moonshotai/kimi-k2.6", @@ -16887,7 +16850,7 @@ export const MODELS = { cacheWrite: 0, }, contextWindow: 262144, - maxTokens: 262144, + maxTokens: 235929, } satisfies Model<"openai-completions">, "moonshotai/kimi-k2.7-code": { id: "moonshotai/kimi-k2.7-code", @@ -16926,7 +16889,7 @@ export const MODELS = { cacheWrite: 0, }, contextWindow: 1048576, - maxTokens: 1048576, + maxTokens: 943718, featured: true, } satisfies Model<"openai-completions">, "nvidia/nemotron-3-nano-30b-a3b": { @@ -16951,7 +16914,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "nvidia/nemotron-3-super-120b-a12b": { id: "nvidia/nemotron-3-super-120b-a12b", - name: "Nemotron 3 Super 120B A12B", + name: "Nemotron 3 Super", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -16965,13 +16928,13 @@ export const MODELS = { cacheRead: 0, cacheWrite: 0, }, - contextWindow: 262144, - maxTokens: 4096, + contextWindow: 1000000, + maxTokens: 16384, featured: true, } satisfies Model<"openai-completions">, "openai/gpt-4.1": { id: "openai/gpt-4.1", - name: "GPT 4.1", + name: "GPT-4.1", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -16989,7 +16952,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "openai/gpt-4.1-mini": { id: "openai/gpt-4.1-mini", - name: "GPT 4.1 Mini", + name: "GPT-4.1 Mini", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17007,7 +16970,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "openai/gpt-4.1-nano": { id: "openai/gpt-4.1-nano", - name: "GPT 4.1 Nano", + name: "GPT-4.1 Nano", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17025,7 +16988,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "openai/gpt-4o": { id: "openai/gpt-4o", - name: "GPT 4O", + name: "GPT-4o", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17043,7 +17006,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "openai/gpt-4o-mini": { id: "openai/gpt-4o-mini", - name: "GPT 4O Mini", + name: "GPT-4o-mini", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17061,7 +17024,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "openai/gpt-5": { id: "openai/gpt-5", - name: "GPT 5", + name: "GPT-5", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17080,7 +17043,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "openai/gpt-5-mini": { id: "openai/gpt-5-mini", - name: "GPT 5 Mini", + name: "GPT-5 Mini", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17099,7 +17062,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "openai/gpt-5-nano": { id: "openai/gpt-5-nano", - name: "GPT 5 Nano", + name: "GPT-5 Nano", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17118,7 +17081,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "openai/gpt-5.1": { id: "openai/gpt-5.1", - name: "GPT 5.1", + name: "GPT-5.1", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17137,7 +17100,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "openai/gpt-5.2": { id: "openai/gpt-5.2", - name: "GPT 5.2", + name: "GPT-5.2", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17156,7 +17119,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "openai/gpt-5.2-pro": { id: "openai/gpt-5.2-pro", - name: "GPT 5.2 PRO", + name: "GPT-5.2 Pro", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17175,7 +17138,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "openai/gpt-5.3-codex": { id: "openai/gpt-5.3-codex", - name: "GPT 5.3 Codex", + name: "GPT-5.3-Codex", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17195,7 +17158,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "openai/gpt-5.4": { id: "openai/gpt-5.4", - name: "GPT 5.4", + name: "GPT-5.4", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17215,7 +17178,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "openai/gpt-5.4-mini": { id: "openai/gpt-5.4-mini", - name: "GPT 5.4 Mini", + name: "GPT-5.4 Mini", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17235,7 +17198,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "openai/gpt-5.4-nano": { id: "openai/gpt-5.4-nano", - name: "GPT 5.4 Nano", + name: "GPT-5.4 Nano", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17254,7 +17217,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "openai/gpt-5.4-pro": { id: "openai/gpt-5.4-pro", - name: "GPT 5.4 PRO", + name: "GPT-5.4 Pro", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17274,7 +17237,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "openai/gpt-5.5": { id: "openai/gpt-5.5", - name: "GPT 5.5", + name: "GPT-5.5", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17311,47 +17274,9 @@ export const MODELS = { contextWindow: 128000, maxTokens: 8192, } satisfies Model<"openai-completions">, - "openai/gpt-5.6-luna": { - id: "openai/gpt-5.6-luna", - name: "GPT 5.6 Luna", - api: "openai-completions", - provider: "prime-inference", - baseUrl: "https://api.pinference.ai/api/v1", - compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","supportsStrictMode":false}, - reasoning: true, - thinkingLevelMap: {"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"}, - input: ["text", "image"], - cost: { - input: 0.2, - output: 1.2, - cacheRead: 0, - cacheWrite: 0, - }, - contextWindow: 1050000, - maxTokens: 128000, - } satisfies Model<"openai-completions">, - "openai/gpt-5.6-luna-pro": { - id: "openai/gpt-5.6-luna-pro", - name: "GPT 5.6 Luna PRO", - api: "openai-completions", - provider: "prime-inference", - baseUrl: "https://api.pinference.ai/api/v1", - compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","supportsStrictMode":false}, - reasoning: true, - thinkingLevelMap: {"minimal":null,"low":"low","medium":"medium","high":"high","xhigh":"xhigh","max":"max"}, - input: ["text", "image"], - cost: { - input: 1, - output: 6, - cacheRead: 0, - cacheWrite: 0, - }, - contextWindow: 1050000, - maxTokens: 128000, - } satisfies Model<"openai-completions">, "openai/gpt-5.6-sol": { id: "openai/gpt-5.6-sol", - name: "GPT 5.6 SOL", + name: "GPT-5.6 Sol", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17370,7 +17295,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "openai/gpt-5.6-sol-pro": { id: "openai/gpt-5.6-sol-pro", - name: "GPT 5.6 SOL PRO", + name: "GPT-5.6 Sol Pro", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17389,7 +17314,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "openai/gpt-5.6-terra": { id: "openai/gpt-5.6-terra", - name: "GPT 5.6 Terra", + name: "GPT-5.6 Terra", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17408,7 +17333,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "openai/gpt-5.6-terra-pro": { id: "openai/gpt-5.6-terra-pro", - name: "GPT 5.6 Terra PRO", + name: "GPT-5.6 Terra Pro", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17427,7 +17352,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "openai/gpt-6-astra": { id: "openai/gpt-6-astra", - name: "GPT 6 Astra", + name: "GPT-6 Astra", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17446,7 +17371,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "openai/gpt-oss-120b": { id: "openai/gpt-oss-120b", - name: "GPT OSS 120B", + name: "gpt-oss-120b", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17465,7 +17390,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "openai/gpt-oss-20b": { id: "openai/gpt-oss-20b", - name: "GPT OSS 20B", + name: "gpt-oss-20b", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17480,7 +17405,7 @@ export const MODELS = { cacheWrite: 0, }, contextWindow: 131072, - maxTokens: 131072, + maxTokens: 117964, } satisfies Model<"openai-completions">, "poolside/laguna-s-2.1": { id: "poolside/laguna-s-2.1", @@ -17522,7 +17447,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "qwen/qwen3-235b-a22b-2507": { id: "qwen/qwen3-235b-a22b-2507", - name: "QWEN3 235B A22B 2507", + name: "Qwen3 235B A22B Instruct 2507", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17540,7 +17465,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "qwen/qwen3-30b-a3b-instruct-2507": { id: "qwen/qwen3-30b-a3b-instruct-2507", - name: "QWEN3 30B A3B Instruct 2507", + name: "Qwen3 30B A3B Instruct 2507", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17559,7 +17484,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "qwen/qwen3-8b": { id: "qwen/qwen3-8b", - name: "QWEN3 8B", + name: "Qwen3 8B", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17578,7 +17503,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "qwen/qwen3-coder": { id: "qwen/qwen3-coder", - name: "QWEN3 Coder", + name: "Qwen3 Coder 480B A35B", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17596,7 +17521,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "qwen/qwen3-coder-next": { id: "qwen/qwen3-coder-next", - name: "QWEN3 Coder Next", + name: "Qwen3 Coder Next", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17615,7 +17540,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "qwen/qwen3-max": { id: "qwen/qwen3-max", - name: "QWEN3 MAX", + name: "Qwen3 Max", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17634,7 +17559,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "qwen/qwen3-vl-235b-a22b-instruct": { id: "qwen/qwen3-vl-235b-a22b-instruct", - name: "QWEN3 VL 235B A22B Instruct", + name: "Qwen3 VL 235B A22B Instruct", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17652,7 +17577,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "qwen/qwen3-vl-235b-a22b-thinking": { id: "qwen/qwen3-vl-235b-a22b-thinking", - name: "QWEN3 VL 235B A22B Thinking", + name: "Qwen3 VL 235B A22B Thinking", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17672,7 +17597,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "qwen/qwen3-vl-30b-a3b-instruct": { id: "qwen/qwen3-vl-30b-a3b-instruct", - name: "QWEN3 VL 30B A3B Instruct", + name: "Qwen3 VL 30B A3B Instruct", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17690,7 +17615,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "qwen/qwen3-vl-8b-instruct": { id: "qwen/qwen3-vl-8b-instruct", - name: "QWEN3 VL 8B Instruct", + name: "Qwen3 VL 8B Instruct", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17708,7 +17633,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "qwen/qwen3.5-35b-a3b": { id: "qwen/qwen3.5-35b-a3b", - name: "QWEN3.5 35B A3B", + name: "Qwen3.5-35B-A3B", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17727,7 +17652,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "qwen/qwen3.5-397b-a17b": { id: "qwen/qwen3.5-397b-a17b", - name: "QWEN3.5 397B A17B", + name: "Qwen3.5 397B A17B", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17746,7 +17671,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "qwen/qwen3.6-27b": { id: "qwen/qwen3.6-27b", - name: "QWEN3.6 27B", + name: "Qwen3.6 27B", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17765,7 +17690,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "qwen/qwen3.6-35b-a3b": { id: "qwen/qwen3.6-35b-a3b", - name: "QWEN3.6 35B A3B", + name: "Qwen3.6 35B A3B", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17784,7 +17709,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "qwen/qwen3.7-flash": { id: "qwen/qwen3.7-flash", - name: "QWEN3.7 Flash", + name: "Qwen3.7 Flash", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17838,12 +17763,12 @@ export const MODELS = { cacheWrite: 0, }, contextWindow: 2000000, - maxTokens: 30000, + maxTokens: 1800000, featured: true, } satisfies Model<"openai-completions">, "x-ai/grok-4.20-multi-agent": { id: "x-ai/grok-4.20-multi-agent", - name: "Grok 4.20 Multi Agent", + name: "Grok 4.20 Multi-Agent", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17858,7 +17783,7 @@ export const MODELS = { cacheWrite: 0, }, contextWindow: 2000000, - maxTokens: 30000, + maxTokens: 1800000, featured: true, } satisfies Model<"openai-completions">, "x-ai/grok-4.6": { @@ -17882,7 +17807,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "xiaomi/mimo-v2.5": { id: "xiaomi/mimo-v2.5", - name: "Mimo V2.5", + name: "MiMo-V2.5", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17901,7 +17826,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "xiaomi/mimo-v2.5-pro": { id: "xiaomi/mimo-v2.5-pro", - name: "Mimo V2.5 PRO", + name: "MiMo-V2.5-Pro", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17939,7 +17864,7 @@ export const MODELS = { } satisfies Model<"openai-completions">, "z-ai/glm-4.5-air": { id: "z-ai/glm-4.5-air", - name: "GLM 4.5 AIR", + name: "GLM 4.5 Air", api: "openai-completions", provider: "prime-inference", baseUrl: "https://api.pinference.ai/api/v1", @@ -17973,7 +17898,7 @@ export const MODELS = { cacheWrite: 0, }, contextWindow: 204800, - maxTokens: 131072, + maxTokens: 16384, } satisfies Model<"openai-completions">, "z-ai/glm-4.7": { id: "z-ai/glm-4.7", @@ -18030,7 +17955,7 @@ export const MODELS = { cacheWrite: 0, }, contextWindow: 204800, - maxTokens: 131072, + maxTokens: 128000, featured: true, } satisfies Model<"openai-completions">, "z-ai/glm-5.1": { @@ -18090,7 +18015,7 @@ export const MODELS = { cacheWrite: 0, }, contextWindow: 1310720, - maxTokens: 262144, + maxTokens: 943718, } satisfies Model<"openai-completions">, "z-ai/glm-5.3-flash": { id: "z-ai/glm-5.3-flash", @@ -18111,6 +18036,24 @@ export const MODELS = { contextWindow: 1310720, maxTokens: 131072, } satisfies Model<"openai-completions">, + "zai-org/GLM-4.7": { + id: "zai-org/GLM-4.7", + name: "GLM 4.7", + api: "openai-completions", + provider: "prime-inference", + baseUrl: "https://api.pinference.ai/api/v1", + compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":true,"maxTokensField":"max_tokens","supportsStrictMode":false}, + reasoning: true, + input: ["text"], + cost: { + input: 0.6, + output: 2.2, + cacheRead: 0, + cacheWrite: 0, + }, + contextWindow: 204800, + maxTokens: 131072, + } satisfies Model<"openai-completions">, }, "vercel-ai-gateway": { "alibaba/qwen-3-14b": { @@ -19942,23 +19885,6 @@ export const MODELS = { contextWindow: 204800, maxTokens: 131000, } satisfies Model<"anthropic-messages">, - "minimax/minimax-m2.7-free": { - id: "minimax/minimax-m2.7-free", - name: "MiniMax M2.7 (Free)", - api: "anthropic-messages", - provider: "vercel-ai-gateway", - baseUrl: "https://ai-gateway.vercel.sh", - reasoning: true, - input: ["text"], - cost: { - input: 0, - output: 0, - cacheRead: 0, - cacheWrite: 0, - }, - contextWindow: 196608, - maxTokens: 196608, - } satisfies Model<"anthropic-messages">, "minimax/minimax-m2.7-highspeed": { id: "minimax/minimax-m2.7-highspeed", name: "MiniMax M2.7 High Speed", @@ -19993,23 +19919,6 @@ export const MODELS = { contextWindow: 512000, maxTokens: 512000, } satisfies Model<"anthropic-messages">, - "minimax/minimax-m3-free": { - id: "minimax/minimax-m3-free", - name: "MiniMax M3 (Free)", - api: "anthropic-messages", - provider: "vercel-ai-gateway", - baseUrl: "https://ai-gateway.vercel.sh", - reasoning: true, - input: ["text", "image"], - cost: { - input: 0, - output: 0, - cacheRead: 0, - cacheWrite: 0, - }, - contextWindow: 1048576, - maxTokens: 1048576, - } satisfies Model<"anthropic-messages">, "mistral/codestral": { id: "mistral/codestral", name: "Mistral Codestral", @@ -20323,7 +20232,7 @@ export const MODELS = { provider: "vercel-ai-gateway", baseUrl: "https://ai-gateway.vercel.sh", reasoning: true, - thinkingLevelMap: {"off":null,"minimal":null,"low":null,"medium":null,"high":null,"xhigh":null,"max":"max"}, + thinkingLevelMap: {"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":null}, input: ["text", "image"], cost: { input: 3, @@ -20341,7 +20250,7 @@ export const MODELS = { provider: "vercel-ai-gateway", baseUrl: "https://ai-gateway.vercel.sh", reasoning: true, - thinkingLevelMap: {"off":null,"minimal":null,"low":null,"medium":null,"high":null,"xhigh":null,"max":"max"}, + thinkingLevelMap: {"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":null}, input: ["text", "image"], cost: { input: 4.5, @@ -20869,7 +20778,7 @@ export const MODELS = { provider: "vercel-ai-gateway", baseUrl: "https://ai-gateway.vercel.sh", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":null}, input: ["text", "image"], cost: { input: 1.75, @@ -20887,7 +20796,7 @@ export const MODELS = { provider: "vercel-ai-gateway", baseUrl: "https://ai-gateway.vercel.sh", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":null}, input: ["text", "image"], cost: { input: 1.75, @@ -20905,7 +20814,7 @@ export const MODELS = { provider: "vercel-ai-gateway", baseUrl: "https://ai-gateway.vercel.sh", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":null}, input: ["text", "image"], cost: { input: 3.5, @@ -20923,7 +20832,7 @@ export const MODELS = { provider: "vercel-ai-gateway", baseUrl: "https://ai-gateway.vercel.sh", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":null}, input: ["text", "image"], cost: { input: 21, @@ -20941,7 +20850,7 @@ export const MODELS = { provider: "vercel-ai-gateway", baseUrl: "https://ai-gateway.vercel.sh", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":null}, input: ["text", "image"], cost: { input: 1.75, @@ -20959,7 +20868,7 @@ export const MODELS = { provider: "vercel-ai-gateway", baseUrl: "https://ai-gateway.vercel.sh", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":null}, input: ["text", "image"], cost: { input: 3.5, @@ -20977,7 +20886,7 @@ export const MODELS = { provider: "vercel-ai-gateway", baseUrl: "https://ai-gateway.vercel.sh", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":null}, input: ["text", "image"], cost: { input: 2.5, @@ -20995,7 +20904,7 @@ export const MODELS = { provider: "vercel-ai-gateway", baseUrl: "https://ai-gateway.vercel.sh", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":null}, input: ["text", "image"], cost: { input: 5, @@ -21013,7 +20922,7 @@ export const MODELS = { provider: "vercel-ai-gateway", baseUrl: "https://ai-gateway.vercel.sh", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":null}, input: ["text", "image"], cost: { input: 0.75, @@ -21031,7 +20940,7 @@ export const MODELS = { provider: "vercel-ai-gateway", baseUrl: "https://ai-gateway.vercel.sh", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":null}, input: ["text", "image"], cost: { input: 1.5, @@ -21049,7 +20958,7 @@ export const MODELS = { provider: "vercel-ai-gateway", baseUrl: "https://ai-gateway.vercel.sh", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":null}, input: ["text", "image"], cost: { input: 0.19999999999999998, @@ -21067,7 +20976,7 @@ export const MODELS = { provider: "vercel-ai-gateway", baseUrl: "https://ai-gateway.vercel.sh", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":null}, input: ["text", "image"], cost: { input: 30, @@ -21085,7 +20994,7 @@ export const MODELS = { provider: "vercel-ai-gateway", baseUrl: "https://ai-gateway.vercel.sh", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":null}, input: ["text", "image"], cost: { input: 5, @@ -21103,7 +21012,7 @@ export const MODELS = { provider: "vercel-ai-gateway", baseUrl: "https://ai-gateway.vercel.sh", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":null}, input: ["text", "image"], cost: { input: 12.5, @@ -21121,7 +21030,7 @@ export const MODELS = { provider: "vercel-ai-gateway", baseUrl: "https://ai-gateway.vercel.sh", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh"}, + thinkingLevelMap: {"xhigh":null}, input: ["text", "image"], cost: { input: 30, @@ -21139,7 +21048,7 @@ export const MODELS = { provider: "vercel-ai-gateway", baseUrl: "https://ai-gateway.vercel.sh", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh","minimal":null,"max":"max"}, + thinkingLevelMap: {"xhigh":null,"minimal":null,"max":null}, input: ["text", "image"], cost: { input: 0.19999999999999998, @@ -21157,7 +21066,7 @@ export const MODELS = { provider: "vercel-ai-gateway", baseUrl: "https://ai-gateway.vercel.sh", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh","minimal":null,"max":"max"}, + thinkingLevelMap: {"xhigh":null,"minimal":null,"max":null}, input: ["text", "image"], cost: { input: 0.39999999999999997, @@ -21175,7 +21084,7 @@ export const MODELS = { provider: "vercel-ai-gateway", baseUrl: "https://ai-gateway.vercel.sh", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh","minimal":null,"max":"max"}, + thinkingLevelMap: {"xhigh":null,"minimal":null,"max":null}, input: ["text", "image"], cost: { input: 2, @@ -21193,7 +21102,7 @@ export const MODELS = { provider: "vercel-ai-gateway", baseUrl: "https://ai-gateway.vercel.sh", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh","minimal":null,"max":"max"}, + thinkingLevelMap: {"xhigh":null,"minimal":null,"max":null}, input: ["text", "image"], cost: { input: 4, @@ -21211,7 +21120,7 @@ export const MODELS = { provider: "vercel-ai-gateway", baseUrl: "https://ai-gateway.vercel.sh", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh","minimal":null,"max":"max"}, + thinkingLevelMap: {"xhigh":null,"minimal":null,"max":null}, input: ["text", "image"], cost: { input: 2, @@ -21229,7 +21138,7 @@ export const MODELS = { provider: "vercel-ai-gateway", baseUrl: "https://ai-gateway.vercel.sh", reasoning: true, - thinkingLevelMap: {"xhigh":"xhigh","minimal":null,"max":"max"}, + thinkingLevelMap: {"xhigh":null,"minimal":null,"max":null}, input: ["text", "image"], cost: { input: 4, @@ -21247,7 +21156,7 @@ export const MODELS = { provider: "vercel-ai-gateway", baseUrl: "https://ai-gateway.vercel.sh", reasoning: true, - thinkingLevelMap: {"minimal":null,"xhigh":"xhigh","max":"max"}, + thinkingLevelMap: {"minimal":null,"xhigh":null,"max":null}, input: ["text", "image"], cost: { input: 10, @@ -21265,7 +21174,7 @@ export const MODELS = { provider: "vercel-ai-gateway", baseUrl: "https://ai-gateway.vercel.sh", reasoning: true, - thinkingLevelMap: {"minimal":null,"xhigh":"xhigh","max":"max"}, + thinkingLevelMap: {"minimal":null,"xhigh":null,"max":null}, input: ["text", "image"], cost: { input: 20, diff --git a/packages/ai/src/providers/anthropic.ts b/packages/ai/src/providers/anthropic.ts index 0be96d24ec..ac65e7ca5c 100644 --- a/packages/ai/src/providers/anthropic.ts +++ b/packages/ai/src/providers/anthropic.ts @@ -756,9 +756,10 @@ function isAlwaysOnAdaptiveThinkingModel(modelId: string): boolean { } /** - * Check if a model supports adaptive thinking (Opus 4.6+, Sonnet 4.6) + * Check if a model supports adaptive thinking (Opus 4.6+, Sonnet 4.6). Exported + * for catalog generation, which must not re-derive the id list. */ -function supportsAdaptiveThinking(modelId: string): boolean { +export function supportsAdaptiveThinking(modelId: string): boolean { // Adaptive-thinking model IDs (with or without date suffix). return ( modelId.includes("opus-4-6") || diff --git a/packages/ai/src/providers/openai-completions.ts b/packages/ai/src/providers/openai-completions.ts index 78496a7593..a1b14868cc 100644 --- a/packages/ai/src/providers/openai-completions.ts +++ b/packages/ai/src/providers/openai-completions.ts @@ -1224,8 +1224,9 @@ function detectCompat(model: Model<"openai-completions">): ResolvedOpenAIComplet /** * Get resolved compatibility settings for a model. * Uses explicit model.compat if provided, otherwise auto-detects from provider/URL. + * Exported for catalog generation, which must not re-derive these rules. */ -function getCompat(model: Model<"openai-completions">): ResolvedOpenAICompletionsCompat { +export function getCompat(model: Model<"openai-completions">): ResolvedOpenAICompletionsCompat { const detected = detectCompat(model); if (!model.compat) return detected; diff --git a/packages/ai/test/model-catalog-validation.test.ts b/packages/ai/test/model-catalog-validation.test.ts new file mode 100644 index 0000000000..d2d20c7568 --- /dev/null +++ b/packages/ai/test/model-catalog-validation.test.ts @@ -0,0 +1,113 @@ +import { describe, expect, it } from "vitest"; +import { + type CatalogLike, + type CatalogRowLike, + validateModelCatalog, +} from "../scripts/validate-model-catalog.js"; +import { MODELS } from "../src/models.generated.js"; + +function row(overrides: Partial & { id: string; provider: string }): CatalogRowLike { + return { + api: "openai-completions", + baseUrl: "https://example.com/v1", + reasoning: false, + contextWindow: 128000, + maxTokens: 8192, + ...overrides, + }; +} + +function catalogOf(...models: CatalogRowLike[]): CatalogLike { + const catalog: Record> = {}; + for (const model of models) { + catalog[model.provider] ??= {}; + catalog[model.provider][model.id] = model; + } + return catalog; +} + +const NULL_MAP = { off: null, minimal: null, low: null, medium: null, high: null, xhigh: null, max: "max" }; +const RICH_MAP = { minimal: null, low: "low", medium: null, high: "high", xhigh: null, max: "max" }; + +describe("model catalog validation", () => { + it("accepts the committed catalog", () => { + expect(validateModelCatalog(MODELS)).toEqual([]); + }); + + it.each<[string, CatalogLike, string[]]>([ + [ + "maxTokens above contextWindow", + catalogOf(row({ id: "swapped", provider: "huggingface", contextWindow: 1000, maxTokens: 2000 })), + ["huggingface/swapped: maxTokens 2000 exceeds contextWindow 1000"], + ], + [ + "unclassified and misrouted GitHub Copilot models", + catalogOf(row({ id: "novel-model-x", provider: "github-copilot" }), row({ id: "grok-9", provider: "github-copilot" })), + [ + "github-copilot/novel-model-x: unclassified model family; add it to copilotModelApi in validate-model-catalog.ts", + "github-copilot/grok-9: api openai-completions does not match classification openai-responses", + ], + ], + [ + "codex contextWindow diverging more than 2x from the openai row", + catalogOf( + row({ id: "gpt-9", provider: "openai", api: "openai-responses", contextWindow: 1050000 }), + row({ id: "gpt-9", provider: "openai-codex", api: "openai-codex-responses", contextWindow: 272000 }), + ), + ["openai-codex/gpt-9: contextWindow 272000 diverges more than 2x from openai/gpt-9 (1050000)"], + ], + [ + "same-model rows whose runtime-selectable thinking levels disagree", + catalogOf( + row({ id: "vendor/model-y", provider: "openrouter", reasoning: true, thinkingLevelMap: RICH_MAP }), + row({ id: "model-y", provider: "huggingface", reasoning: true, thinkingLevelMap: NULL_MAP }), + ), + [ + "model-y [openai-completions]: selectable thinking levels disagree across providers: " + + "openrouter/vendor/model-y=[low,high,max], huggingface/model-y=[max]", + ], + ], + [ + "selectable levels on a transport that cannot send reasoning effort, without crashing on a missing baseUrl", + catalogOf( + row({ id: "model-z", provider: "moonshotai", reasoning: true, thinkingLevelMap: NULL_MAP, baseUrl: undefined }), + ), + ["moonshotai/model-z: thinkingLevelMap offers [max] but the transport cannot send reasoning effort"], + ], + [ + "budget-clamped levels on a non-adaptive anthropic-messages row", + catalogOf( + row({ + id: "kimi-x", + provider: "kimi-coding", + api: "anthropic-messages", + reasoning: true, + thinkingLevelMap: { off: null, low: "low", high: "high", max: "max" }, + }), + ), + ["kimi-coding/kimi-x: thinkingLevelMap offers [max] but the budget path serializes them as high"], + ], + [ + "nothing when maps differ only in off-level support", + catalogOf( + row({ + id: "gpt-5.9", + provider: "openai", + api: "openai-responses", + reasoning: true, + thinkingLevelMap: { off: "none", xhigh: "xhigh" }, + }), + row({ + id: "gpt-5.9", + provider: "github-copilot", + api: "openai-responses", + reasoning: true, + thinkingLevelMap: { off: null, xhigh: "xhigh" }, + }), + ), + [], + ], + ])("reports %s", (_name, catalog, expected) => { + expect(validateModelCatalog(catalog)).toEqual(expected); + }); +}); diff --git a/packages/ai/test/supports-xhigh.test.ts b/packages/ai/test/supports-xhigh.test.ts index 072043589c..2e2b763295 100644 --- a/packages/ai/test/supports-xhigh.test.ts +++ b/packages/ai/test/supports-xhigh.test.ts @@ -80,7 +80,7 @@ describe("getSupportedThinkingLevels", () => { expect(getSupportedThinkingLevels(codexModel!)).toEqual(["off", "low", "medium", "high", "xhigh", "max"]); expect(apiModel!.contextWindow).toBe(1050000); expect(apiModel!.maxTokens).toBe(128000); - expect(codexModel!.contextWindow).toBe(272000); + expect(codexModel!.contextWindow).toBe(1050000); expect(codexModel!.maxTokens).toBe(128000); }, ); diff --git a/packages/coding-agent/.changes/res-1273-fixed-effort-model-default.md b/packages/coding-agent/.changes/res-1273-fixed-effort-model-default.md new file mode 100644 index 0000000000..f33cd6cd75 --- /dev/null +++ b/packages/coding-agent/.changes/res-1273-fixed-effort-model-default.md @@ -0,0 +1 @@ +- Fixed switching to a model with no selectable thinking levels (e.g. Kimi K3 on Moonshot) overwriting the saved thinking default with off and leaving thinking disabled after switching away; cycling effort on such a model is now a no-op. diff --git a/packages/coding-agent/src/core/agent-session.ts b/packages/coding-agent/src/core/agent-session.ts index eec21e2341..bca9916b51 100644 --- a/packages/coding-agent/src/core/agent-session.ts +++ b/packages/coding-agent/src/core/agent-session.ts @@ -7386,7 +7386,8 @@ export class AgentSession { if (isChanging) { this.sessionManager.appendThinkingLevelChange(effectiveLevel); - if (this.supportsThinking() || effectiveLevel !== "off") { + // A forced clamp on a model with no selectable levels is not a user preference; keep the persisted default. + if ((this.supportsThinking() && availableLevels.length > 0) || effectiveLevel !== "off") { this.settingsManager.setDefaultThinkingLevel(effectiveLevel); } this._emit({ type: "thinking_level_changed", level: effectiveLevel }); @@ -7445,6 +7446,7 @@ export class AgentSession { if (!this.supportsThinking()) return undefined; const levels = this.getAvailableThinkingLevels(); + if (levels.length === 0) return undefined; const currentIndex = levels.indexOf(this.thinkingLevel); const nextIndex = (currentIndex + 1) % levels.length; const nextLevel = levels[nextIndex]; @@ -7466,7 +7468,7 @@ export class AgentSession { if (explicitLevel !== undefined) { return explicitLevel; } - if (!this.supportsThinking()) { + if (!this.supportsThinking() || this.getAvailableThinkingLevels().length === 0) { return this.settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL; } return this.thinkingLevel; diff --git a/packages/coding-agent/test/agent-session-services.test.ts b/packages/coding-agent/test/agent-session-services.test.ts index ca25424d6d..8c6f2d74e4 100644 --- a/packages/coding-agent/test/agent-session-services.test.ts +++ b/packages/coding-agent/test/agent-session-services.test.ts @@ -412,4 +412,59 @@ describe("createAgentSessionFromServices", () => { withMessageController.dispose(); } }); + + it("keeps the persisted thinking default when a model offers no selectable levels", async () => { + const tempDir = join(tmpdir(), `pi-session-fixed-effort-${Date.now()}-${Math.random().toString(36).slice(2)}`); + mkdirSync(tempDir, { recursive: true }); + cleanupPaths.push(tempDir); + + const faux = registerFauxProvider({ + models: [ + { id: "capable", reasoning: true }, + { id: "fixed-effort", reasoning: true }, + ], + }); + unregisters.push(() => faux.unregister()); + const [capable, fixedEffort] = faux.models; + // A reasoning model whose transport cannot send effort: every level nulled. + fixedEffort.thinkingLevelMap = { off: null, minimal: null, low: null, medium: null, high: null, xhigh: null, max: null }; + + const authStorage = AuthStorage.inMemory(); + authStorage.setRuntimeApiKey(capable.provider, "faux-key"); + const settingsManager = SettingsManager.inMemory(); + const services = await createAgentSessionServices({ + cwd: tempDir, + agentDir: tempDir, + authStorage, + settingsManager, + resourceLoaderOptions: { noPromptTemplates: true, noThemes: true }, + }); + services.modelRegistry.registerProvider(capable.provider, { + baseUrl: capable.baseUrl, + apiKey: "faux-key", + api: faux.api, + models: faux.models, + }); + + const { session } = await createAgentSessionFromServices({ + services, + sessionManager: SessionManager.create(tempDir, join(tempDir, "sessions")), + model: capable, + }); + try { + session.setThinkingLevel("high"); + expect(settingsManager.getDefaultThinkingLevel()).toBe("high"); + + await session.setModel(fixedEffort, { waitForExtensions: false }); + expect(session.thinkingLevel).toBe("off"); + expect(session.cycleThinkingLevel()).toBeUndefined(); + expect(session.thinkingLevel).toBe("off"); + expect(settingsManager.getDefaultThinkingLevel()).toBe("high"); + + await session.setModel(capable, { waitForExtensions: false }); + expect(session.thinkingLevel).toBe("high"); + } finally { + session.dispose(); + } + }); });