diff --git a/packages/ai/CHANGELOG.md b/packages/ai/CHANGELOG.md index 7ef1fbf50..3de8e047d 100644 --- a/packages/ai/CHANGELOG.md +++ b/packages/ai/CHANGELOG.md @@ -18,6 +18,9 @@ - Fixed safety setting application for Google Vertex AI models - Ensured Gemini service tier is correctly passed through to the API - Corrected priority request accounting for supported providers +### Fixed + +- Fixed Kimi Code's Anthropic-compatible request path to keep thinking enabled and downgrade forced tool choice for Kimi K2.7 Code title generation. ([#3852](https://github.com/can1357/oh-my-pi/issues/3852)) ## [16.2.6] - 2026-06-29 diff --git a/packages/ai/src/providers/__tests__/kimi-code-thinking.test.ts b/packages/ai/src/providers/__tests__/kimi-code-thinking.test.ts new file mode 100644 index 000000000..b76cbd6cb --- /dev/null +++ b/packages/ai/src/providers/__tests__/kimi-code-thinking.test.ts @@ -0,0 +1,112 @@ +import { describe, expect, it } from "bun:test"; +import { getBundledModel } from "@oh-my-pi/pi-catalog"; +import type { Context } from "../../types"; +import type { MessageCreateParamsStreaming } from "../anthropic-wire"; +import { streamOpenAIAnthropicShim } from "../openai-anthropic-shim"; +import { + applyChatCompletionsCompatPolicy, + type OpenAICompletionsParams, + resolveOpenAICompatPolicy, +} from "../openai-shared"; + +const BASE_CHAT_COMPLETIONS_PARAMS: OpenAICompletionsParams = { messages: [], model: "unused", stream: true }; +const TITLE_CONTEXT: Context = { + systemPrompt: ["Generate a title."], + messages: [{ role: "user", content: "Explain the login failure", timestamp: 0 }], + tools: [ + { + name: "set_title", + description: "Set title", + parameters: { + type: "object", + properties: { title: { type: "string" } }, + required: ["title"], + additionalProperties: false, + }, + }, + ], +}; + +describe("Kimi K2.7 Code thinking policy", () => { + it("omits disabled thinking for title-generator-style Kimi Code requests", () => { + const model = getBundledModel<"openai-completions">("kimi-code", "kimi-for-coding"); + const policy = resolveOpenAICompatPolicy(model, { + endpoint: "chat-completions", + disableReasoning: true, + toolChoice: { type: "tool", name: "set_title" }, + }); + const params = { ...BASE_CHAT_COMPLETIONS_PARAMS }; + + applyChatCompletionsCompatPolicy(params, policy); + + expect("thinking" in params).toBe(false); + expect(model.compat.supportsForcedToolChoice).toBe(false); + }); + + it("enables thinking and downgrades forced tool choice on Kimi Code's Anthropic endpoint", async () => { + const model = getBundledModel<"openai-completions">("kimi-code", "kimi-for-coding"); + let payload: MessageCreateParamsStreaming | undefined; + const stream = streamOpenAIAnthropicShim( + model, + TITLE_CONTEXT, + { + apiKey: "test-key", + maxTokens: 1024, + disableReasoning: true, + toolChoice: { type: "tool", name: "set_title" }, + onPayload: body => { + payload = body as MessageCreateParamsStreaming; + throw new Error("stop after payload capture"); + }, + }, + { + anthropicBaseUrl: "https://api.kimi.com/coding", + defaultFormat: "anthropic", + }, + ); + + await stream.result(); + + expect(payload?.thinking?.type).toBe("enabled"); + expect(payload?.tool_choice).toEqual({ type: "auto" }); + }); + + it("omits disabled thinking for native Moonshot Kimi K2.7 Code variants", () => { + for (const modelId of ["kimi-k2.7-code", "kimi-k2.7-code-highspeed"]) { + const model = getBundledModel<"openai-completions">("moonshot", modelId); + const policy = resolveOpenAICompatPolicy(model, { + endpoint: "chat-completions", + disableReasoning: true, + }); + const params = { ...BASE_CHAT_COMPLETIONS_PARAMS }; + applyChatCompletionsCompatPolicy(params, policy); + + expect("thinking" in params).toBe(false); + expect(model.compat.supportsForcedToolChoice).toBe(false); + } + }); + + it("keeps the openai disable shape for non-native Kimi K2.7 Code aliases", () => { + for (const { provider, id } of [ + { provider: "fireworks", id: "kimi-k2.7-code" }, + { provider: "openrouter", id: "moonshotai/kimi-k2.7-code" }, + ] as const) { + const model = getBundledModel<"openai-completions">(provider, id); + expect(model.compat.supportsForcedToolChoice).toBe(true); + expect(model.compat.reasoningDisableMode).not.toBe("omit"); + } + }); + + it("keeps explicit disabled thinking for Kimi K2.6", () => { + const model = getBundledModel<"openai-completions">("moonshot", "kimi-k2.6"); + const policy = resolveOpenAICompatPolicy(model, { + endpoint: "chat-completions", + disableReasoning: true, + }); + const params = { ...BASE_CHAT_COMPLETIONS_PARAMS }; + + applyChatCompletionsCompatPolicy(params, policy); + + expect(params.thinking).toEqual({ type: "disabled" }); + }); +}); diff --git a/packages/ai/src/providers/anthropic.ts b/packages/ai/src/providers/anthropic.ts index c89aaaa29..14b027dab 100644 --- a/packages/ai/src/providers/anthropic.ts +++ b/packages/ai/src/providers/anthropic.ts @@ -2876,9 +2876,10 @@ function buildParams( let thinking: MessageCreateParamsStreaming["thinking"] | undefined; let outputConfigEffort: AnthropicOutputEffort | undefined; if (model.reasoning) { - if (options?.thinkingEnabled) { + if (options?.thinkingEnabled || model.compat.requiresThinkingEnabled) { + const thinkingOptions = options ?? {}; const mode = model.thinking?.mode; - const effort = resolveAnthropicAdaptiveEffort(model, options); + const effort = resolveAnthropicAdaptiveEffort(model, thinkingOptions); const compat = model.compat; if (mode === "anthropic-adaptive" && !compat.disableAdaptiveThinking) { const adaptive: { type: "adaptive"; display?: AnthropicThinkingDisplay } = { type: "adaptive" }; @@ -2889,15 +2890,15 @@ function buildParams( // support: Opus 4.6 / Sonnet 4.6+ reject it with a 400, so an explicit // `thinkingDisplay` MUST NOT force it onto a model that can't accept it. if (model.thinking?.supportsDisplay) { - adaptive.display = options.thinkingDisplay ?? "summarized"; + adaptive.display = thinkingOptions.thinkingDisplay ?? "summarized"; } thinking = adaptive; if (effort && effort !== "adaptive") outputConfigEffort = effort; } else { thinking = { type: "enabled", - budget_tokens: options.thinkingBudgetTokens || 1024, - display: options.thinkingDisplay ?? "summarized", + budget_tokens: thinkingOptions.thinkingBudgetTokens || 1024, + display: thinkingOptions.thinkingDisplay ?? "summarized", }; if (mode === "anthropic-budget-effort" && effort && effort !== "adaptive") outputConfigEffort = effort; } diff --git a/packages/catalog/CHANGELOG.md b/packages/catalog/CHANGELOG.md index 09b0580c6..4d2edc7d5 100644 --- a/packages/catalog/CHANGELOG.md +++ b/packages/catalog/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Fixed + +- Fixed Kimi K2.7 Code compatibility to avoid disabled thinking and forced tool choice on native Kimi endpoints that require thinking mode. ([#3852](https://github.com/can1357/oh-my-pi/issues/3852)) + ## [16.2.6] - 2026-06-29 ### Fixed diff --git a/packages/catalog/src/compat/anthropic.ts b/packages/catalog/src/compat/anthropic.ts index 93390b0e3..cdff05ec2 100644 --- a/packages/catalog/src/compat/anthropic.ts +++ b/packages/catalog/src/compat/anthropic.ts @@ -28,6 +28,14 @@ export function isOfficialAnthropicApiUrl(baseUrl?: string): boolean { return lower === OFFICIAL_ANTHROPIC_URL || lower.startsWith(`${OFFICIAL_ANTHROPIC_URL}/`); } +/** Mirrors `compat/openai.ts`; native-only host gating is the caller's responsibility. */ +const KIMI_K27_CODE_MODEL_PATTERN = /(?:^|\/)kimi[-._]?k2(?:[._-]?|p)7[-._]?code(?:[-._]?highspeed)?$/i; + +function matchesKimiK27CodeFamily(spec: ModelSpec<"anthropic-messages">): boolean { + if (KIMI_K27_CODE_MODEL_PATTERN.test(spec.id)) return true; + return spec.id === "kimi-for-coding" && /k2\.?7 code/i.test(spec.name ?? ""); +} + /** Build the resolved anthropic-messages compat record for a model spec. */ export function buildAnthropicCompat(spec: ModelSpec<"anthropic-messages">): ResolvedAnthropicCompat { const baseUrl = spec.baseUrl; @@ -40,6 +48,7 @@ export function buildAnthropicCompat(spec: ModelSpec<"anthropic-messages">): Res // doesn't whitelist the `fine-grained-tool-streaming-2025-05-14` beta either // (issue #2558), so eager tool-input streaming is unavailable on this host. const isCopilot = modelMatchesHost(spec, "githubCopilot"); + const requiresThinkingEnabled = modelMatchesHost(spec, "moonshotNative") && matchesKimiK27CodeFamily(spec); const compat: ResolvedAnthropicCompat = { officialEndpoint: official, disableStrictTools: false, @@ -53,12 +62,13 @@ export function buildAnthropicCompat(spec: ModelSpec<"anthropic-messages">): Res // detection requires the canonical api.anthropic.com host plus a // supported model id. supportsMidConversationSystem: official && supportsMidConversationSystemMessages(spec.id), - supportsForcedToolChoice: !isAnthropicFableOrMythosModel(spec.id), + supportsForcedToolChoice: !requiresThinkingEnabled && !isAnthropicFableOrMythosModel(spec.id), // Opus 4.7+ and Fable/Mythos reject temperature/top_p/top_k with a 400. supportsSamplingParams: !hasOpus47ApiRestrictions(spec.id), // Z.AI workaround (issue #814): its proxy deserializes tool_result blocks // into a class that reads `.id`. requiresToolResultId: isZai, + requiresThinkingEnabled, // Official Anthropic enforces signature-based thinking-chain integrity, so // unsigned thinking blocks must stay text there. Anthropic-compatible // reasoning endpoints commonly emit unsigned thinking blocks while still diff --git a/packages/catalog/src/compat/openai.ts b/packages/catalog/src/compat/openai.ts index 26ae8b357..d0ca9447e 100644 --- a/packages/catalog/src/compat/openai.ts +++ b/packages/catalog/src/compat/openai.ts @@ -39,6 +39,20 @@ const GLM_CODING_PLAN_STREAM_IDLE_TIMEOUT_MS = 600_000; const DEEPSEEK_REASONING_STREAM_IDLE_TIMEOUT_MS = 300_000; /** Kimi K2.6 can spend several minutes reasoning before the first visible token. */ const KIMI_K26_REASONING_STREAM_IDLE_TIMEOUT_MS = 300_000; +/** + * Native Kimi K2.7 Code requires `thinking.type: "enabled"` and rejects + * disabled thinking. Match the public id, its Fast variant, and the + * `kimi-code/kimi-for-coding` alias (which keeps the family name). + * Caller-disabled requests on non-native dialects (Fireworks `openai`, + * OpenRouter `openrouter`, …) MUST keep their per-dialect disable shape — + * gating on `isMoonshotKimi` is the caller's responsibility. + */ +const KIMI_K27_CODE_MODEL_PATTERN = /(?:^|\/)kimi[-._]?k2(?:[._-]?|p)7[-._]?code(?:[-._]?highspeed)?$/i; + +function matchesKimiK27CodeFamily(spec: ModelSpec<"openai-completions">): boolean { + if (KIMI_K27_CODE_MODEL_PATTERN.test(spec.id)) return true; + return spec.id === "kimi-for-coding" && /k2\.?7 code/i.test(spec.name ?? ""); +} /** Xiaomi MiMo Pro on api.xiaomimimo.com can stall ~2min before the first event (issue #1770). */ const XIAOMI_MIMO_STREAM_IDLE_TIMEOUT_MS = 300_000; /** Alibaba Coding Plan (coding-intl.dashscope) qwen models idle before the first event (issue #1770). */ @@ -231,6 +245,7 @@ export function buildOpenAICompat(spec: ModelSpec<"openai-completions">): Resolv const isKimiModel = isKimiModelId(spec.id); const isMoonshotNative = modelMatchesHost(hostModel, "moonshotNative"); const isMoonshotKimi = isKimiModel && isMoonshotNative; + const requiresEnabledThinking = isMoonshotKimi && matchesKimiK27CodeFamily(spec); const usesMoonshotKimiPreservedThinking = isMoonshotKimi && isKimiK26ModelId(spec.id); const isAnthropicModel = modelMatchesHost(hostModel, "anthropic") || isClaudeModelId(spec.id) || isAnthropicNamespacedModelId(spec.id); @@ -403,7 +418,7 @@ export function buildOpenAICompat(spec: ModelSpec<"openai-completions">): Resolv disableReasoningOnForcedToolChoice: isKimiModel || isAnthropicModel, disableReasoningOnToolChoice: isDeepseekFamily && Boolean(spec.reasoning) && !isOpenRouter, supportsToolChoice: !isDirectDeepseekReasoning, - supportsForcedToolChoice: true, + supportsForcedToolChoice: !requiresEnabledThinking, supportsNamedToolChoice: provider !== "llama.cpp", maxTokensField: useMaxTokens ? "max_tokens" : "max_completion_tokens", requiresToolResultName: isMistral, @@ -509,7 +524,9 @@ export function buildOpenAICompat(spec: ModelSpec<"openai-completions">): Resolv applyCompatOverrides(compat, spec.compat); if (spec.compat?.reasoningDisableMode === undefined) { - compat.reasoningDisableMode = resolveReasoningDisableMode(compat.thinkingFormat); + compat.reasoningDisableMode = requiresEnabledThinking + ? "omit" + : resolveReasoningDisableMode(compat.thinkingFormat); } if (spec.compat?.omitReasoningEffort === undefined && !compat.supportsReasoningEffort) { compat.omitReasoningEffort = true; diff --git a/packages/catalog/src/models.json b/packages/catalog/src/models.json index 492404b0c..a95d863af 100644 --- a/packages/catalog/src/models.json +++ b/packages/catalog/src/models.json @@ -2476,7 +2476,7 @@ "api": "openai-completions", "provider": "aimlapi", "baseUrl": "https://api.aimlapi.com/v1", - "reasoning": true, + "reasoning": false, "input": [ "text" ], @@ -2487,24 +2487,7 @@ "cacheWrite": 0 }, "contextWindow": 163840, - "maxTokens": 16384, - "thinking": { - "mode": "effort", - "efforts": [ - "minimal", - "low", - "medium", - "high", - "xhigh" - ], - "effortMap": { - "minimal": "high", - "low": "high", - "medium": "high", - "high": "high", - "xhigh": "max" - } - } + "maxTokens": 16384 }, "deepseek/deepseek-chat-v3.1": { "id": "deepseek/deepseek-chat-v3.1", @@ -10620,6 +10603,35 @@ ] } }, + "xai.grok-4.3": { + "id": "xai.grok-4.3", + "name": "Grok 4.3", + "api": "bedrock-converse-stream", + "provider": "amazon-bedrock", + "baseUrl": "https://bedrock-runtime.us-east-1.amazonaws.com", + "reasoning": true, + "input": [ + "text", + "image" + ], + "cost": { + "input": 1.25, + "output": 2.5, + "cacheRead": 0.2, + "cacheWrite": 0 + }, + "contextWindow": 1000000, + "maxTokens": 131072, + "thinking": { + "mode": "budget", + "efforts": [ + "minimal", + "low", + "medium", + "high" + ] + } + }, "zai.glm-4.7": { "id": "zai.glm-4.7", "name": "GLM-4.7", @@ -13672,7 +13684,7 @@ "api": "openai-completions", "provider": "coreweave", "baseUrl": "https://api.inference.wandb.ai/v1", - "reasoning": true, + "reasoning": false, "input": [ "text" ], @@ -13683,17 +13695,7 @@ "cacheWrite": 0 }, "contextWindow": 128000, - "maxTokens": 128000, - "thinking": { - "mode": "effort", - "efforts": [ - "minimal", - "low", - "medium", - "high", - "xhigh" - ] - } + "maxTokens": 128000 }, "meta-llama/Llama-3.3-70B-Instruct": { "id": "meta-llama/Llama-3.3-70B-Instruct", @@ -13701,7 +13703,7 @@ "api": "openai-completions", "provider": "coreweave", "baseUrl": "https://api.inference.wandb.ai/v1", - "reasoning": true, + "reasoning": false, "input": [ "text" ], @@ -13712,17 +13714,7 @@ "cacheWrite": 0 }, "contextWindow": 128000, - "maxTokens": 128000, - "thinking": { - "mode": "effort", - "efforts": [ - "minimal", - "low", - "medium", - "high", - "xhigh" - ] - } + "maxTokens": 128000 }, "meta-llama/Llama-4-Scout-17B-16E-Instruct": { "id": "meta-llama/Llama-4-Scout-17B-16E-Instruct", @@ -13730,7 +13722,7 @@ "api": "openai-completions", "provider": "coreweave", "baseUrl": "https://api.inference.wandb.ai/v1", - "reasoning": true, + "reasoning": false, "input": [ "text", "image" @@ -13742,17 +13734,7 @@ "cacheWrite": 0 }, "contextWindow": 64000, - "maxTokens": 64000, - "thinking": { - "mode": "effort", - "efforts": [ - "minimal", - "low", - "medium", - "high", - "xhigh" - ] - } + "maxTokens": 64000 }, "microsoft/Phi-4-mini-instruct": { "id": "microsoft/Phi-4-mini-instruct", @@ -13760,7 +13742,7 @@ "api": "openai-completions", "provider": "coreweave", "baseUrl": "https://api.inference.wandb.ai/v1", - "reasoning": true, + "reasoning": false, "input": [ "text" ], @@ -13771,17 +13753,7 @@ "cacheWrite": 0 }, "contextWindow": 128000, - "maxTokens": 128000, - "thinking": { - "mode": "effort", - "efforts": [ - "minimal", - "low", - "medium", - "high", - "xhigh" - ] - } + "maxTokens": 128000 }, "MiniMaxAI/MiniMax-M2.5": { "id": "MiniMaxAI/MiniMax-M2.5", @@ -13789,7 +13761,7 @@ "api": "openai-completions", "provider": "coreweave", "baseUrl": "https://api.inference.wandb.ai/v1", - "reasoning": false, + "reasoning": true, "input": [ "text" ], @@ -13800,7 +13772,16 @@ "cacheWrite": 0 }, "contextWindow": 196608, - "maxTokens": 196608 + "maxTokens": 196608, + "thinking": { + "mode": "effort", + "efforts": [ + "low", + "medium", + "high" + ], + "requiresEffort": true + } }, "moonshotai/Kimi-K2.5": { "id": "moonshotai/Kimi-K2.5", @@ -13898,7 +13879,7 @@ "api": "openai-completions", "provider": "coreweave", "baseUrl": "https://api.inference.wandb.ai/v1", - "reasoning": false, + "reasoning": true, "input": [ "text" ], @@ -13909,7 +13890,17 @@ "cacheWrite": 0 }, "contextWindow": 262144, - "maxTokens": 262144 + "maxTokens": 262144, + "thinking": { + "mode": "effort", + "efforts": [ + "minimal", + "low", + "medium", + "high", + "xhigh" + ] + } }, "nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B": { "id": "nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B", @@ -21734,7 +21725,7 @@ "cost": { "input": 0.075, "output": 0.3, - "cacheRead": 0.037, + "cacheRead": 0, "cacheWrite": 0 }, "contextWindow": 131072, @@ -22420,13 +22411,13 @@ "text" ], "cost": { - "input": 0, - "output": 0, + "input": 0.25, + "output": 0.69, "cacheRead": 0, "cacheWrite": 0 }, "contextWindow": 131072, - "maxTokens": 65536, + "maxTokens": 32768, "thinking": { "mode": "effort", "efforts": [ @@ -25048,7 +25039,7 @@ "api": "openai-completions", "provider": "kilo", "baseUrl": "https://api.kilo.ai/api/gateway", - "reasoning": true, + "reasoning": false, "input": [ "text" ], @@ -25059,24 +25050,7 @@ "cacheWrite": 0 }, "contextWindow": 163840, - "maxTokens": 65536, - "thinking": { - "mode": "effort", - "efforts": [ - "minimal", - "low", - "medium", - "high", - "xhigh" - ], - "effortMap": { - "minimal": "high", - "low": "high", - "medium": "high", - "high": "high", - "xhigh": "max" - } - } + "maxTokens": 65536 }, "deepseek/deepseek-chat-v3.1": { "id": "deepseek/deepseek-chat-v3.1", @@ -30816,6 +30790,7 @@ "supportsStrictMode": false, "toolStrictMode": "mixed", "stripDeepseekSpecialTokens": false, + "streamMarkupHealingPattern": "thinking", "reasoningDeltasMayBeCumulative": false, "emptyLengthFinishIsContextError": false, "usesOpenAIToolCallIdLimit": false, @@ -54444,6 +54419,36 @@ "requiresEffort": true } }, + "minimaxai/minimax-m3": { + "id": "minimaxai/minimax-m3", + "name": "MiniMax-M3", + "api": "openai-completions", + "provider": "nvidia", + "baseUrl": "https://integrate.api.nvidia.com/v1", + "reasoning": true, + "input": [ + "text", + "image" + ], + "cost": { + "input": 0, + "output": 0, + "cacheRead": 0, + "cacheWrite": 0 + }, + "contextWindow": 1000000, + "maxTokens": 16384, + "thinking": { + "mode": "effort", + "efforts": [ + "minimal", + "low", + "medium", + "high", + "xhigh" + ] + } + }, "mistralai/codestral-22b-instruct-v0.1": { "id": "mistralai/codestral-22b-instruct-v0.1", "name": "Codestral 22b Instruct V0.1", @@ -62195,9 +62200,9 @@ "image" ], "cost": { - "input": 0.66, - "output": 3.41, - "cacheRead": 0.144, + "input": 0.55, + "output": 3.1999999999999997, + "cacheRead": 0.11, "cacheWrite": 0 }, "contextWindow": 262144, @@ -63522,7 +63527,7 @@ "api": "openrouter", "baseUrl": "https://openrouter.ai/api/v1", "provider": "openrouter", - "reasoning": true, + "reasoning": false, "input": [ "text" ], @@ -63533,22 +63538,7 @@ "cacheWrite": 0 }, "contextWindow": 163840, - "maxTokens": 16384, - "thinking": { - "mode": "effort", - "efforts": [ - "minimal", - "low", - "medium", - "high" - ], - "effortMap": { - "minimal": "high", - "low": "high", - "medium": "high", - "high": "high" - } - } + "maxTokens": 16384 }, "deepseek/deepseek-chat-v3.1": { "id": "deepseek/deepseek-chat-v3.1", @@ -65751,7 +65741,7 @@ "cacheWrite": 0 }, "contextWindow": 131072, - "maxTokens": 32768 + "maxTokens": 100352 }, "moonshotai/kimi-k2-0905": { "id": "moonshotai/kimi-k2-0905", @@ -65770,7 +65760,7 @@ "cacheWrite": 0 }, "contextWindow": 262144, - "maxTokens": 262144 + "maxTokens": 100352 }, "moonshotai/kimi-k2-0905:exacto": { "id": "moonshotai/kimi-k2-0905:exacto", @@ -65861,9 +65851,9 @@ "image" ], "cost": { - "input": 0.66, - "output": 3.41, - "cacheRead": 0.144, + "input": 0.55, + "output": 3.1999999999999997, + "cacheRead": 0.11, "cacheWrite": 0 }, "contextWindow": 262144, @@ -69347,8 +69337,8 @@ "image" ], "cost": { - "input": 0.28850000000000003, - "output": 2.65, + "input": 0.2596, + "output": 2.3850000000000002, "cacheRead": 0.15, "cacheWrite": 0 }, @@ -69758,13 +69748,13 @@ "text" ], "cost": { - "input": 0.09, + "input": 0.09999999999999999, "output": 0.3, "cacheRead": 0.02, "cacheWrite": 0 }, "contextWindow": 262144, - "maxTokens": 16384, + "maxTokens": 65536, "thinking": { "mode": "effort", "efforts": [ @@ -70846,8 +70836,8 @@ "text" ], "cost": { - "input": 0.98, - "output": 3.08, + "input": 0.975, + "output": 4.300000000000001, "cacheRead": 0.182, "cacheWrite": 0 }, @@ -70874,7 +70864,7 @@ "text" ], "cost": { - "input": 0.95, + "input": 0.94, "output": 3, "cacheRead": 0.18, "cacheWrite": 0 @@ -71096,7 +71086,7 @@ "synthetic": { "hf:MiniMaxAI/MiniMax-M3": { "id": "hf:MiniMaxAI/MiniMax-M3", - "name": "MiniMaxAI/MiniMax-M3", + "name": "MiniMax-M3", "api": "openai-completions", "provider": "synthetic", "baseUrl": "https://api.synthetic.new/openai/v1", @@ -71111,7 +71101,7 @@ "cacheRead": 0.6, "cacheWrite": 0 }, - "contextWindow": 262144, + "contextWindow": 524288, "maxTokens": 65536, "thinking": { "mode": "effort", @@ -71126,7 +71116,7 @@ }, "hf:moonshotai/Kimi-K2.6": { "id": "hf:moonshotai/Kimi-K2.6", - "name": "moonshotai/Kimi-K2.6", + "name": "Kimi K2.6", "api": "openai-completions", "provider": "synthetic", "baseUrl": "https://api.synthetic.new/openai/v1", @@ -71156,7 +71146,7 @@ }, "hf:nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4": { "id": "hf:nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4", - "name": "nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-NVFP4", + "name": "Nemotron 3 Super 120B A12B", "api": "openai-completions", "provider": "synthetic", "baseUrl": "https://api.synthetic.new/openai/v1", @@ -71185,7 +71175,7 @@ }, "hf:openai/gpt-oss-120b": { "id": "hf:openai/gpt-oss-120b", - "name": "openai/gpt-oss-120b", + "name": "GPT OSS 120B", "api": "openai-completions", "provider": "synthetic", "baseUrl": "https://api.synthetic.new/openai/v1", @@ -71196,7 +71186,7 @@ "cost": { "input": 0.1, "output": 0.1, - "cacheRead": 0, + "cacheRead": 0.1, "cacheWrite": 0 }, "contextWindow": 131072, @@ -71212,7 +71202,7 @@ }, "hf:Qwen/Qwen3.5-397B-A17B": { "id": "hf:Qwen/Qwen3.5-397B-A17B", - "name": "Qwen/Qwen3.5-397B-A17B", + "name": "Qwen3.5 397B-A17B", "api": "openai-completions", "provider": "synthetic", "baseUrl": "https://api.synthetic.new/openai/v1", @@ -71223,7 +71213,7 @@ ], "cost": { "input": 0.6, - "output": 3, + "output": 3.6, "cacheRead": 0.6, "cacheWrite": 0 }, @@ -71241,26 +71231,36 @@ }, "hf:Qwen/Qwen3.6-27B": { "id": "hf:Qwen/Qwen3.6-27B", - "name": "Qwen/Qwen3.6-27B", + "name": "Qwen3.6 27B", "api": "openai-completions", "provider": "synthetic", "baseUrl": "https://api.synthetic.new/openai/v1", - "reasoning": false, + "reasoning": true, "input": [ - "text" + "text", + "image" ], "cost": { - "input": 0, - "output": 0, - "cacheRead": 0, + "input": 0.45, + "output": 3.6, + "cacheRead": 0.45, "cacheWrite": 0 }, "contextWindow": 262144, - "maxTokens": 8192 + "maxTokens": 65536, + "thinking": { + "mode": "effort", + "efforts": [ + "minimal", + "low", + "medium", + "high" + ] + } }, "hf:zai-org/GLM-4.7": { "id": "hf:zai-org/GLM-4.7", - "name": "zai-org/GLM-4.7", + "name": "GLM-4.7", "api": "openai-completions", "provider": "synthetic", "baseUrl": "https://api.synthetic.new/openai/v1", @@ -71269,13 +71269,13 @@ "text" ], "cost": { - "input": 0.55, + "input": 0.45, "output": 2.19, - "cacheRead": 0, + "cacheRead": 0.45, "cacheWrite": 0 }, "contextWindow": 202752, - "maxTokens": 64000, + "maxTokens": 65536, "thinking": { "mode": "effort", "efforts": [ @@ -71289,7 +71289,7 @@ }, "hf:zai-org/GLM-4.7-Flash": { "id": "hf:zai-org/GLM-4.7-Flash", - "name": "zai-org/GLM-4.7-Flash", + "name": "GLM-4.7-Flash", "api": "openai-completions", "provider": "synthetic", "baseUrl": "https://api.synthetic.new/openai/v1", @@ -71298,9 +71298,9 @@ "text" ], "cost": { - "input": 0.06, - "output": 0.4, - "cacheRead": 0.06, + "input": 0.1, + "output": 0.5, + "cacheRead": 0.1, "cacheWrite": 0 }, "contextWindow": 196608, @@ -71318,7 +71318,7 @@ }, "hf:zai-org/GLM-5.1": { "id": "hf:zai-org/GLM-5.1", - "name": "zai-org/GLM-5.1", + "name": "GLM-5.1", "api": "openai-completions", "provider": "synthetic", "baseUrl": "https://api.synthetic.new/openai/v1", @@ -71347,22 +71347,32 @@ }, "hf:zai-org/GLM-5.2": { "id": "hf:zai-org/GLM-5.2", - "name": "zai-org/GLM-5.2", + "name": "GLM-5.2", "api": "openai-completions", "provider": "synthetic", "baseUrl": "https://api.synthetic.new/openai/v1", - "reasoning": false, + "reasoning": true, "input": [ "text" ], "cost": { - "input": 0, - "output": 0, - "cacheRead": 0, + "input": 1.4, + "output": 4.4, + "cacheRead": 1.4, "cacheWrite": 0 }, "contextWindow": 524288, - "maxTokens": 8192 + "maxTokens": 65536, + "thinking": { + "mode": "effort", + "efforts": [ + "minimal", + "low", + "medium", + "high", + "xhigh" + ] + } }, "syn:large:text": { "id": "syn:large:text", @@ -71682,7 +71692,7 @@ "api": "openai-completions", "provider": "together", "baseUrl": "https://api.together.xyz/v1", - "reasoning": true, + "reasoning": false, "input": [ "text", "image" @@ -71694,17 +71704,7 @@ "cacheWrite": 0.18 }, "contextWindow": 10000000, - "maxTokens": 32768, - "thinking": { - "mode": "effort", - "efforts": [ - "minimal", - "low", - "medium", - "high", - "xhigh" - ] - } + "maxTokens": 32768 }, "MiniMaxAI/MiniMax-M2.5": { "id": "MiniMaxAI/MiniMax-M2.5", @@ -72381,6 +72381,38 @@ "escapeBuiltinToolNames": true } }, + "umans-glm-5.2-nvfp4": { + "id": "umans-glm-5.2-nvfp4", + "name": "Umans GLM 5.2 NVFP4 (experimental, short test from Jun 29)", + "api": "anthropic-messages", + "provider": "umans", + "baseUrl": "https://api.code.umans.ai", + "reasoning": true, + "thinking": { + "mode": "anthropic-budget-effort", + "efforts": [ + "high", + "xhigh" + ], + "effortMap": { + "xhigh": "max" + } + }, + "input": [ + "text" + ], + "cost": { + "input": 0, + "output": 0, + "cacheRead": 0, + "cacheWrite": 0 + }, + "contextWindow": 405504, + "maxTokens": 131071, + "compat": { + "escapeBuiltinToolNames": true + } + }, "umans-kimi-k2.7": { "id": "umans-kimi-k2.7", "name": "Umans Kimi K2.7 Code", @@ -75747,6 +75779,7 @@ "supportsForcedToolChoice": true, "supportsSamplingParams": true, "requiresToolResultId": false, + "requiresThinkingEnabled": false, "replayUnsignedThinking": false, "escapeBuiltinToolNames": false } @@ -80633,7 +80666,7 @@ }, "zai/glm-4.5": { "id": "zai/glm-4.5", - "name": "GLM-4.5", + "name": "GLM 4.5", "api": "anthropic-messages", "baseUrl": "https://ai-gateway.vercel.sh", "provider": "vercel-ai-gateway", @@ -82062,6 +82095,14 @@ }, "contextWindow": 2000000, "maxTokens": 2000000, + "compat": { + "reasoningEffortMap": { + "minimal": "low" + }, + "includeEncryptedReasoning": false, + "filterReasoningHistory": true, + "omitReasoningEffort": false + }, "thinking": { "mode": "effort", "efforts": [ @@ -82074,14 +82115,6 @@ "effortMap": { "minimal": "low" } - }, - "compat": { - "reasoningEffortMap": { - "minimal": "low" - }, - "includeEncryptedReasoning": false, - "filterReasoningHistory": true, - "omitReasoningEffort": false } }, "grok-4.3": { @@ -82103,6 +82136,14 @@ }, "contextWindow": 1000000, "maxTokens": 1000000, + "compat": { + "reasoningEffortMap": { + "minimal": "low" + }, + "includeEncryptedReasoning": false, + "filterReasoningHistory": true, + "omitReasoningEffort": false + }, "thinking": { "mode": "effort", "efforts": [ @@ -82115,14 +82156,6 @@ "effortMap": { "minimal": "low" } - }, - "compat": { - "reasoningEffortMap": { - "minimal": "low" - }, - "includeEncryptedReasoning": false, - "filterReasoningHistory": true, - "omitReasoningEffort": false } }, "grok-build": { @@ -82174,12 +82207,12 @@ "contextWindow": 256000, "maxTokens": 256000, "compat": { - "includeEncryptedReasoning": false, - "filterReasoningHistory": true, - "omitReasoningEffort": true, "reasoningEffortMap": { "minimal": "low" }, + "includeEncryptedReasoning": false, + "filterReasoningHistory": true, + "omitReasoningEffort": true, "supportsReasoningEffort": false } }, @@ -82223,9 +82256,9 @@ "text" ], "cost": { - "input": 0.1, - "output": 0.3, - "cacheRead": 0.01, + "input": 0.14, + "output": 0.28, + "cacheRead": 0.0028, "cacheWrite": 0 }, "contextWindow": 262144, @@ -82259,9 +82292,9 @@ "image" ], "cost": { - "input": 0.4, - "output": 2, - "cacheRead": 0.08, + "input": 0.14, + "output": 0.28, + "cacheRead": 0.0028, "cacheWrite": 0 }, "contextWindow": 262144, @@ -82294,9 +82327,9 @@ "text" ], "cost": { - "input": 1, - "output": 3, - "cacheRead": 0.2, + "input": 0.435, + "output": 0.87, + "cacheRead": 0.0036, "cacheWrite": 0 }, "contextWindow": 1048576, @@ -82330,9 +82363,9 @@ "image" ], "cost": { - "input": 0.4, - "output": 2, - "cacheRead": 0.08, + "input": 0.14, + "output": 0.28, + "cacheRead": 0.0028, "cacheWrite": 0 }, "contextWindow": 1048576, @@ -82365,9 +82398,9 @@ "text" ], "cost": { - "input": 1, - "output": 3, - "cacheRead": 0.2, + "input": 0.435, + "output": 0.87, + "cacheRead": 0.0036, "cacheWrite": 0 }, "contextWindow": 1048576, diff --git a/packages/catalog/src/provider-models/openai-compat.ts b/packages/catalog/src/provider-models/openai-compat.ts index 12776ea48..ea448e488 100644 --- a/packages/catalog/src/provider-models/openai-compat.ts +++ b/packages/catalog/src/provider-models/openai-compat.ts @@ -1294,7 +1294,7 @@ export function clampFireworksKimiMaxTokens(modelId: string, candidate: number | export const KIMI_K27_CODE_RECOMMENDED_MAX_TOKENS = 32_768; export function isKimiK27CodeModelId(modelId: string): boolean { - return /(?:^|\/)kimi[-._]?k2(?:[._-]?|p)7[-._]?code$/i.test(modelId); + return /(?:^|\/)kimi[-._]?k2(?:[._-]?|p)7[-._]?code(?:[-._]?highspeed)?$/i.test(modelId); } export function clampKimiK27CodeMaxTokens(modelId: string, candidate: number): number; diff --git a/packages/catalog/src/types.ts b/packages/catalog/src/types.ts index 29c0a9571..c41d76d3c 100644 --- a/packages/catalog/src/types.ts +++ b/packages/catalog/src/types.ts @@ -420,6 +420,11 @@ export interface AnthropicCompat { * Default: auto-detected from provider/baseUrl and `model.reasoning`. */ replayUnsignedThinking?: boolean; + /** + * Whether the endpoint requires `thinking.type: "enabled"` whenever the + * model reasons. Use for models that reject omitted or disabled thinking. + */ + requiresThinkingEnabled?: boolean; /** * Prefix Anthropic built-in tool names (`web_search`, `code_execution`, ...) * when they are ordinary client tools. Some Anthropic-compatible gateways