diff --git a/packages/ai/scripts/generate-models.ts b/packages/ai/scripts/generate-models.ts index 225c89d6..f7eab41b 100644 --- a/packages/ai/scripts/generate-models.ts +++ b/packages/ai/scripts/generate-models.ts @@ -733,6 +733,47 @@ async function loadModelsDevData(): Promise[]> { } } + // Process Moonshot AI models + const moonshotVariants = [ + { key: "moonshotai", provider: "moonshotai", baseUrl: "https://api.moonshot.ai/v1" }, + { key: "moonshotai-cn", provider: "moonshotai-cn", baseUrl: "https://api.moonshot.cn/v1" }, + ] as const; + const moonshotCompat: OpenAICompletionsCompat = { + supportsStore: false, + supportsDeveloperRole: false, + supportsReasoningEffort: false, + maxTokensField: "max_tokens", + supportsStrictMode: false, + }; + + for (const { key, provider, baseUrl } of moonshotVariants) { + if (!data[key]?.models) continue; + + for (const [modelId, model] of Object.entries(data[key].models)) { + const m = model as ModelsDevModel; + if (m.tool_call !== true) continue; + + models.push({ + id: modelId, + name: m.name || modelId, + api: "openai-completions", + provider, + baseUrl, + reasoning: m.reasoning === true, + input: m.modalities?.input?.includes("image") ? ["text", "image"] : ["text"], + cost: { + input: m.cost?.input || 0, + output: m.cost?.output || 0, + cacheRead: m.cost?.cache_read || 0, + cacheWrite: m.cost?.cache_write || 0, + }, + contextWindow: m.limit?.context || 4096, + maxTokens: m.limit?.output || 4096, + compat: moonshotCompat, + }); + } + } + console.log(`Loaded ${models.length} tool-capable models from models.dev`); return models; } catch (error) { diff --git a/packages/ai/src/env-api-keys.ts b/packages/ai/src/env-api-keys.ts index f15f0559..5167819f 100644 --- a/packages/ai/src/env-api-keys.ts +++ b/packages/ai/src/env-api-keys.ts @@ -113,6 +113,8 @@ function getApiKeyEnvVars(provider: string): readonly string[] | undefined { mistral: "MISTRAL_API_KEY", minimax: "MINIMAX_API_KEY", "minimax-cn": "MINIMAX_CN_API_KEY", + moonshotai: "MOONSHOT_API_KEY", + "moonshotai-cn": "MOONSHOT_API_KEY", huggingface: "HF_TOKEN", fireworks: "FIREWORKS_API_KEY", opencode: "OPENCODE_API_KEY", diff --git a/packages/ai/src/models.generated.ts b/packages/ai/src/models.generated.ts index a7082103..c19e6117 100644 --- a/packages/ai/src/models.generated.ts +++ b/packages/ai/src/models.generated.ts @@ -6010,6 +6010,262 @@ export const MODELS = { maxTokens: 128000, } 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", + 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: 262144, + maxTokens: 262144, + } satisfies Model<"openai-completions">, + "kimi-k2-thinking": { + id: "kimi-k2-thinking", + name: "Kimi K2 Thinking", + 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"], + cost: { + input: 0.6, + output: 2.5, + cacheRead: 0.15, + 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", + baseUrl: "https://api.moonshot.ai/v1", + compat: {"supportsStore":false,"supportsDeveloperRole":false,"supportsReasoningEffort":false,"maxTokensField":"max_tokens","supportsStrictMode":false}, + reasoning: true, + input: ["text"], + cost: { + input: 1.15, + 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, + 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", + baseUrl: "https://api.moonshot.ai/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", + baseUrl: "https://api.moonshot.ai/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">, + }, + "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}, + 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", + 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: 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"], + cost: { + input: 0.6, + output: 2.5, + cacheRead: 0.15, + 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"], + cost: { + input: 1.15, + 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">, + }, "openai": { "gpt-4": { id: "gpt-4", @@ -9585,13 +9841,13 @@ export const MODELS = { reasoning: true, input: ["text", "image"], cost: { - input: 0.75, - output: 3.5, - cacheRead: 0.15, + input: 0.74, + output: 3.49, + cacheRead: 0.14, cacheWrite: 0, }, - contextWindow: 262144, - maxTokens: 16384, + contextWindow: 262142, + maxTokens: 262142, } satisfies Model<"openai-completions">, "nex-agi/deepseek-v3.1-nex-n1": { id: "nex-agi/deepseek-v3.1-nex-n1", @@ -10766,6 +11022,23 @@ export const MODELS = { contextWindow: 200000, maxTokens: 4096, } satisfies Model<"openai-completions">, + "openrouter/owl-alpha": { + id: "openrouter/owl-alpha", + name: "Owl Alpha", + api: "openai-completions", + provider: "openrouter", + baseUrl: "https://openrouter.ai/api/v1", + reasoning: false, + input: ["text"], + cost: { + input: 0, + output: 0, + cacheRead: 0, + cacheWrite: 0, + }, + contextWindow: 1048756, + maxTokens: 262144, + } satisfies Model<"openai-completions">, "poolside/laguna-m.1:free": { id: "poolside/laguna-m.1:free", name: "Poolside: Laguna M.1 (free)", @@ -12339,13 +12612,13 @@ export const MODELS = { reasoning: true, input: ["text", "image"], cost: { - input: 0.75, - output: 3.5, - cacheRead: 0.15, + input: 0.74, + output: 3.49, + cacheRead: 0.14, cacheWrite: 0, }, - contextWindow: 262144, - maxTokens: 16384, + contextWindow: 262142, + maxTokens: 262142, } satisfies Model<"openai-completions">, "~openai/gpt-latest": { id: "~openai/gpt-latest", diff --git a/packages/ai/src/providers/openai-completions.ts b/packages/ai/src/providers/openai-completions.ts index 7062dac2..2860b254 100644 --- a/packages/ai/src/providers/openai-completions.ts +++ b/packages/ai/src/providers/openai-completions.ts @@ -1027,6 +1027,7 @@ function detectCompat(model: Model<"openai-completions">): ResolvedOpenAIComplet const baseUrl = model.baseUrl; const isZai = provider === "zai" || baseUrl.includes("api.z.ai"); + const isMoonshot = provider === "moonshotai" || provider === "moonshotai-cn" || baseUrl.includes("api.moonshot."); const isCloudflareWorkersAI = provider === "cloudflare-workers-ai" || baseUrl.includes("api.cloudflare.com"); const isNonStandard = @@ -1037,11 +1038,12 @@ function detectCompat(model: Model<"openai-completions">): ResolvedOpenAIComplet baseUrl.includes("chutes.ai") || baseUrl.includes("deepseek.com") || isZai || + isMoonshot || provider === "opencode" || baseUrl.includes("opencode.ai") || isCloudflareWorkersAI; - const useMaxTokens = baseUrl.includes("chutes.ai"); + const useMaxTokens = baseUrl.includes("chutes.ai") || isMoonshot; const isGrok = provider === "xai" || baseUrl.includes("api.x.ai"); const isGroq = provider === "groq" || baseUrl.includes("groq.com"); @@ -1068,7 +1070,7 @@ function detectCompat(model: Model<"openai-completions">): ResolvedOpenAIComplet return { supportsStore: !isNonStandard, supportsDeveloperRole: !isNonStandard, - supportsReasoningEffort: !isGrok && !isZai, + supportsReasoningEffort: !isGrok && !isZai && !isMoonshot, reasoningEffortMap, supportsUsageInStreaming: true, maxTokensField: useMaxTokens ? "max_tokens" : "max_completion_tokens", @@ -1086,7 +1088,7 @@ function detectCompat(model: Model<"openai-completions">): ResolvedOpenAIComplet openRouterRouting: {}, vercelGatewayRouting: {}, zaiToolStream: false, - supportsStrictMode: true, + supportsStrictMode: !isMoonshot, cacheControlFormat, sendSessionAffinityHeaders: false, supportsLongCacheRetention: true, diff --git a/packages/ai/src/types.ts b/packages/ai/src/types.ts index f9a3f2b0..4befe310 100644 --- a/packages/ai/src/types.ts +++ b/packages/ai/src/types.ts @@ -37,6 +37,8 @@ export type KnownProvider = | "mistral" | "minimax" | "minimax-cn" + | "moonshotai" + | "moonshotai-cn" | "huggingface" | "fireworks" | "opencode" diff --git a/packages/coding-agent/src/cli/args.ts b/packages/coding-agent/src/cli/args.ts index 988fd4f7..7e08bbf4 100644 --- a/packages/coding-agent/src/cli/args.ts +++ b/packages/coding-agent/src/cli/args.ts @@ -314,6 +314,7 @@ ${chalk.bold("Environment Variables:")} ZAI_API_KEY - ZAI API key MISTRAL_API_KEY - Mistral API key MINIMAX_API_KEY - MiniMax API key + MOONSHOT_API_KEY - Moonshot AI API key OPENCODE_API_KEY - OpenCode Zen/OpenCode Go API key KIMI_API_KEY - Kimi For Coding API key CLOUDFLARE_API_KEY - Cloudflare API token (Workers AI) diff --git a/packages/coding-agent/src/core/model-resolver.ts b/packages/coding-agent/src/core/model-resolver.ts index df7f244f..b5ae536b 100644 --- a/packages/coding-agent/src/core/model-resolver.ts +++ b/packages/coding-agent/src/core/model-resolver.ts @@ -32,6 +32,8 @@ export const defaultModelPerProvider: Record = { mistral: "devstral-medium-latest", minimax: "MiniMax-M2.7", "minimax-cn": "MiniMax-M2.7", + moonshotai: "kimi-k2.6", + "moonshotai-cn": "kimi-k2.6", huggingface: "moonshotai/Kimi-K2.6", fireworks: "accounts/fireworks/models/kimi-k2p6", opencode: "kimi-k2.6", diff --git a/packages/coding-agent/src/core/provider-display-names.ts b/packages/coding-agent/src/core/provider-display-names.ts index e645b610..42028ffd 100644 --- a/packages/coding-agent/src/core/provider-display-names.ts +++ b/packages/coding-agent/src/core/provider-display-names.ts @@ -14,6 +14,8 @@ export const BUILT_IN_PROVIDER_DISPLAY_NAMES: Record = { mistral: "Mistral", minimax: "MiniMax", "minimax-cn": "MiniMax (China)", + moonshotai: "Moonshot AI", + "moonshotai-cn": "Moonshot AI (China)", opencode: "OpenCode Zen", "opencode-go": "OpenCode Go", openai: "OpenAI",