From b928b96af57609195741a63684fb0bd5f4e07f98 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 13 Jan 2026 03:17:46 +0000 Subject: [PATCH] fix: sync Moonshot Kimi K2 models (#818) (thanks @mickahouan) Co-authored-by: mickahouan --- CHANGELOG.md | 2 +- docs/concepts/model-providers.md | 11 ++- docs/providers/moonshot.md | 11 ++- scripts/sync-moonshot-docs.ts | 128 +++++++++++++++++++++++++ ui/src/ui/data/moonshot-kimi-k2.ts | 39 ++++++++ ui/src/ui/views/config.browser.test.ts | 6 ++ ui/src/ui/views/config.ts | 80 +++++----------- 7 files changed, 213 insertions(+), 64 deletions(-) create mode 100644 scripts/sync-moonshot-docs.ts create mode 100644 ui/src/ui/data/moonshot-kimi-k2.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index d28b71998..eff098227 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ ## 2026.1.12-4 ### Changes -- Models/Moonshot: add Kimi K2 turbo + thinking variants to the preset + docs. (#818 — thanks @mickahouan) +- Models/Moonshot: add Kimi K2 0905 + turbo/thinking variants to the preset + docs. (#818 — thanks @mickahouan) - Memory: allow custom OpenAI-compatible embedding endpoints for memory search (remote baseUrl/apiKey/headers). (#819 — thanks @mukhtharcm) ### Fixes diff --git a/docs/concepts/model-providers.md b/docs/concepts/model-providers.md index a98526f88..56d88fb24 100644 --- a/docs/concepts/model-providers.md +++ b/docs/concepts/model-providers.md @@ -117,10 +117,13 @@ Moonshot uses OpenAI-compatible endpoints, so configure it as a custom provider: - Provider: `moonshot` - Auth: `MOONSHOT_API_KEY` - Example model: `moonshot/kimi-k2-0905-preview` -- Other Kimi K2 model IDs: `moonshot/kimi-k2-turbo-preview`, `moonshot/kimi-k2-thinking`, - `moonshot/kimi-k2-thinking-turbo` -- CLI: `clawdbot onboard --auth-choice moonshot-api-key` - +- Kimi K2 model IDs: + + - `moonshot/kimi-k2-0905-preview` + - `moonshot/kimi-k2-turbo-preview` + - `moonshot/kimi-k2-thinking` + - `moonshot/kimi-k2-thinking-turbo` + ```json5 { agents: { diff --git a/docs/providers/moonshot.md b/docs/providers/moonshot.md index 02d7b0437..eb3ee7b91 100644 --- a/docs/providers/moonshot.md +++ b/docs/providers/moonshot.md @@ -9,12 +9,13 @@ read_when: Moonshot provides the Kimi API with OpenAI-compatible endpoints. Configure the provider and set the default model to `moonshot/kimi-k2-0905-preview`. -Other current Kimi K2 model IDs: +Current Kimi K2 model IDs: + +- `kimi-k2-0905-preview` - `kimi-k2-turbo-preview` - `kimi-k2-thinking` - `kimi-k2-thinking-turbo` - -## CLI setup + ```bash clawdbot onboard --auth-choice moonshot-api-key @@ -29,10 +30,12 @@ clawdbot onboard --auth-choice moonshot-api-key defaults: { model: { primary: "moonshot/kimi-k2-0905-preview" }, models: { + // moonshot-kimi-k2-aliases:start "moonshot/kimi-k2-0905-preview": { alias: "Kimi K2" }, "moonshot/kimi-k2-turbo-preview": { alias: "Kimi K2 Turbo" }, "moonshot/kimi-k2-thinking": { alias: "Kimi K2 Thinking" }, "moonshot/kimi-k2-thinking-turbo": { alias: "Kimi K2 Thinking Turbo" } + // moonshot-kimi-k2-aliases:end } } }, @@ -44,6 +47,7 @@ clawdbot onboard --auth-choice moonshot-api-key apiKey: "${MOONSHOT_API_KEY}", api: "openai-completions", models: [ + // moonshot-kimi-k2-models:start { id: "kimi-k2-0905-preview", name: "Kimi K2 0905 Preview", @@ -80,6 +84,7 @@ clawdbot onboard --auth-choice moonshot-api-key contextWindow: 256000, maxTokens: 8192 } + // moonshot-kimi-k2-models:end ] } } diff --git a/scripts/sync-moonshot-docs.ts b/scripts/sync-moonshot-docs.ts new file mode 100644 index 000000000..a0d83c40a --- /dev/null +++ b/scripts/sync-moonshot-docs.ts @@ -0,0 +1,128 @@ +import { readFile, writeFile } from "node:fs/promises"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { + MOONSHOT_KIMI_K2_CONTEXT_WINDOW, + MOONSHOT_KIMI_K2_COST, + MOONSHOT_KIMI_K2_INPUT, + MOONSHOT_KIMI_K2_MAX_TOKENS, + MOONSHOT_KIMI_K2_MODELS, +} from "../ui/src/ui/data/moonshot-kimi-k2"; + +const here = path.dirname(fileURLToPath(import.meta.url)); +const repoRoot = path.resolve(here, ".."); + +function replaceBlockLines( + text: string, + startMarker: string, + endMarker: string, + lines: string[], +): string { + const startIndex = text.indexOf(startMarker); + if (startIndex === -1) { + throw new Error(`Missing start marker: ${startMarker}`); + } + const endIndex = text.indexOf(endMarker, startIndex); + if (endIndex === -1) { + throw new Error(`Missing end marker: ${endMarker}`); + } + + const startLineStart = text.lastIndexOf("\n", startIndex); + const startLineStartIndex = startLineStart === -1 ? 0 : startLineStart + 1; + const indent = text.slice(startLineStartIndex, startIndex); + + const endLineEnd = text.indexOf("\n", endIndex); + const endLineEndIndex = endLineEnd === -1 ? text.length : endLineEnd + 1; + + const before = text.slice(0, startLineStartIndex); + const after = text.slice(endLineEndIndex); + + const replacementLines = [ + `${indent}${startMarker}`, + ...lines.map((line) => `${indent}${line}`), + `${indent}${endMarker}`, + ]; + + const replacement = replacementLines.join("\n"); + if (!after) return `${before}${replacement}`; + return `${before}${replacement}\n${after}`; +} + +function renderKimiK2Ids(prefix: string) { + return MOONSHOT_KIMI_K2_MODELS.map( + (model) => `- \`${prefix}${model.id}\``, + ); +} + +function renderMoonshotAliases() { + return MOONSHOT_KIMI_K2_MODELS.map((model, index) => { + const isLast = index === MOONSHOT_KIMI_K2_MODELS.length - 1; + const suffix = isLast ? "" : ","; + return `"moonshot/${model.id}": { alias: "${model.alias}" }${suffix}`; + }); +} + +function renderMoonshotModels() { + const input = JSON.stringify([...MOONSHOT_KIMI_K2_INPUT]); + const cost = `input: ${MOONSHOT_KIMI_K2_COST.input}, output: ${MOONSHOT_KIMI_K2_COST.output}, cacheRead: ${MOONSHOT_KIMI_K2_COST.cacheRead}, cacheWrite: ${MOONSHOT_KIMI_K2_COST.cacheWrite}`; + + return MOONSHOT_KIMI_K2_MODELS.flatMap((model, index) => { + const isLast = index === MOONSHOT_KIMI_K2_MODELS.length - 1; + const closing = isLast ? "}" : "},"; + return [ + "{", + ` id: "${model.id}",`, + ` name: "${model.name}",`, + ` reasoning: ${model.reasoning},`, + ` input: ${input},`, + ` cost: { ${cost} },`, + ` contextWindow: ${MOONSHOT_KIMI_K2_CONTEXT_WINDOW},`, + ` maxTokens: ${MOONSHOT_KIMI_K2_MAX_TOKENS}`, + closing, + ]; + }); +} + +async function syncMoonshotDocs() { + const moonshotDoc = path.join(repoRoot, "docs/providers/moonshot.md"); + const conceptsDoc = path.join( + repoRoot, + "docs/concepts/model-providers.md", + ); + + let moonshotText = await readFile(moonshotDoc, "utf8"); + moonshotText = replaceBlockLines( + moonshotText, + "", + "", + renderKimiK2Ids(""), + ); + moonshotText = replaceBlockLines( + moonshotText, + "// moonshot-kimi-k2-aliases:start", + "// moonshot-kimi-k2-aliases:end", + renderMoonshotAliases(), + ); + moonshotText = replaceBlockLines( + moonshotText, + "// moonshot-kimi-k2-models:start", + "// moonshot-kimi-k2-models:end", + renderMoonshotModels(), + ); + + let conceptsText = await readFile(conceptsDoc, "utf8"); + conceptsText = replaceBlockLines( + conceptsText, + "", + "", + renderKimiK2Ids("moonshot/"), + ); + + await writeFile(moonshotDoc, moonshotText); + await writeFile(conceptsDoc, conceptsText); +} + +syncMoonshotDocs().catch((error) => { + console.error(error); + process.exitCode = 1; +}); diff --git a/ui/src/ui/data/moonshot-kimi-k2.ts b/ui/src/ui/data/moonshot-kimi-k2.ts new file mode 100644 index 000000000..a5357b5d8 --- /dev/null +++ b/ui/src/ui/data/moonshot-kimi-k2.ts @@ -0,0 +1,39 @@ +export const MOONSHOT_KIMI_K2_DEFAULT_ID = "kimi-k2-0905-preview"; +export const MOONSHOT_KIMI_K2_CONTEXT_WINDOW = 256000; +export const MOONSHOT_KIMI_K2_MAX_TOKENS = 8192; +export const MOONSHOT_KIMI_K2_INPUT = ["text"] as const; +export const MOONSHOT_KIMI_K2_COST = { + input: 0, + output: 0, + cacheRead: 0, + cacheWrite: 0, +} as const; + +export const MOONSHOT_KIMI_K2_MODELS = [ + { + id: "kimi-k2-0905-preview", + name: "Kimi K2 0905 Preview", + alias: "Kimi K2", + reasoning: false, + }, + { + id: "kimi-k2-turbo-preview", + name: "Kimi K2 Turbo", + alias: "Kimi K2 Turbo", + reasoning: false, + }, + { + id: "kimi-k2-thinking", + name: "Kimi K2 Thinking", + alias: "Kimi K2 Thinking", + reasoning: true, + }, + { + id: "kimi-k2-thinking-turbo", + name: "Kimi K2 Thinking Turbo", + alias: "Kimi K2 Thinking Turbo", + reasoning: true, + }, +] as const; + +export type MoonshotKimiK2Model = (typeof MOONSHOT_KIMI_K2_MODELS)[number]; diff --git a/ui/src/ui/views/config.browser.test.ts b/ui/src/ui/views/config.browser.test.ts index 8770b5a7e..fb83a2fb2 100644 --- a/ui/src/ui/views/config.browser.test.ts +++ b/ui/src/ui/views/config.browser.test.ts @@ -173,6 +173,12 @@ describe("config view", () => { const raw = String(onRawChange.mock.calls.at(-1)?.[0] ?? ""); expect(raw).toContain("https://api.moonshot.ai/v1"); expect(raw).toContain("moonshot/kimi-k2-0905-preview"); + expect(raw).toContain("moonshot/kimi-k2-turbo-preview"); + expect(raw).toContain("moonshot/kimi-k2-thinking"); + expect(raw).toContain("moonshot/kimi-k2-thinking-turbo"); + expect(raw).toContain("Kimi K2 Turbo"); + expect(raw).toContain("Kimi K2 Thinking"); + expect(raw).toContain("Kimi K2 Thinking Turbo"); expect(raw).toContain("MOONSHOT_API_KEY"); expect(onFormPatch).toHaveBeenCalledWith( ["agents", "defaults", "model", "primary"], diff --git a/ui/src/ui/views/config.ts b/ui/src/ui/views/config.ts index 2fd753798..67bdf7166 100644 --- a/ui/src/ui/views/config.ts +++ b/ui/src/ui/views/config.ts @@ -1,4 +1,12 @@ import { html, nothing } from "lit"; +import { + MOONSHOT_KIMI_K2_CONTEXT_WINDOW, + MOONSHOT_KIMI_K2_COST, + MOONSHOT_KIMI_K2_DEFAULT_ID, + MOONSHOT_KIMI_K2_INPUT, + MOONSHOT_KIMI_K2_MAX_TOKENS, + MOONSHOT_KIMI_K2_MODELS, +} from "../data/moonshot-kimi-k2"; import type { ConfigUiHints } from "../types"; import { analyzeConfigSchema, renderConfigForm } from "./config-form"; @@ -265,67 +273,27 @@ function buildModelPresetPatches(base: Record): Array<{ value: "openai-completions", }); } + const moonshotModelDefinitions = MOONSHOT_KIMI_K2_MODELS.map((model) => ({ + id: model.id, + name: model.name, + reasoning: model.reasoning, + input: [...MOONSHOT_KIMI_K2_INPUT], + cost: { ...MOONSHOT_KIMI_K2_COST }, + contextWindow: MOONSHOT_KIMI_K2_CONTEXT_WINDOW, + maxTokens: MOONSHOT_KIMI_K2_MAX_TOKENS, + })); + if (!moonshotHasModels) { moonshot.push({ path: moonshotModelsPath as Array, - value: [ - { - id: "kimi-k2-0905-preview", - name: "Kimi K2 0905 Preview", - reasoning: false, - input: ["text"], - cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - contextWindow: 256000, - maxTokens: 8192, - }, - { - id: "kimi-k2-turbo-preview", - name: "Kimi K2 Turbo", - reasoning: false, - input: ["text"], - cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - contextWindow: 256000, - maxTokens: 8192, - }, - { - id: "kimi-k2-thinking", - name: "Kimi K2 Thinking", - reasoning: true, - input: ["text"], - cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - contextWindow: 256000, - maxTokens: 8192, - }, - { - id: "kimi-k2-thinking-turbo", - name: "Kimi K2 Thinking Turbo", - reasoning: true, - input: ["text"], - cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, - contextWindow: 256000, - maxTokens: 8192, - }, - ], + value: moonshotModelDefinitions, }); } - moonshot.push(setPrimary("moonshot/kimi-k2-0905-preview")); - const moonshotAlias = safeAlias("moonshot/kimi-k2-0905-preview", "Kimi K2"); - if (moonshotAlias) moonshot.push(moonshotAlias); - const moonshotTurboAlias = safeAlias( - "moonshot/kimi-k2-turbo-preview", - "Kimi K2 Turbo", - ); - if (moonshotTurboAlias) moonshot.push(moonshotTurboAlias); - const moonshotThinkingAlias = safeAlias( - "moonshot/kimi-k2-thinking", - "Kimi K2 Thinking", - ); - if (moonshotThinkingAlias) moonshot.push(moonshotThinkingAlias); - const moonshotThinkingTurboAlias = safeAlias( - "moonshot/kimi-k2-thinking-turbo", - "Kimi K2 Thinking Turbo", - ); - if (moonshotThinkingTurboAlias) moonshot.push(moonshotThinkingTurboAlias); + moonshot.push(setPrimary(`moonshot/${MOONSHOT_KIMI_K2_DEFAULT_ID}`)); + for (const model of MOONSHOT_KIMI_K2_MODELS) { + const moonshotAlias = safeAlias(`moonshot/${model.id}`, model.alias); + if (moonshotAlias) moonshot.push(moonshotAlias); + } return [ {