From eefaa6ff5d181a2aaa87eedfe2f6f0211eeb755e Mon Sep 17 00:00:00 2001 From: Mohith Gajjela <109003762+Mohith26@users.noreply.github.com> Date: Tue, 28 Jul 2026 12:54:18 -0500 Subject: [PATCH 1/2] fix(cost): add Kimi K3 (moonshotai) to model cost registry Kimi K3 requests routed through Helicone resolved to no cost registry entry, so all K3 traffic was billed at $0 even though token counts were recorded correctly. The moonshotai author only aggregated kimi-k2 and kimi-k2.5. Add kimi-k3 model config and endpoint configs for the two registry providers currently serving it (openrouter, novita), and register them in the moonshotai author index. Pricing independently verified on 2026-07-28 against both providers' machine-readable model listings: - https://openrouter.ai/api/v1/models (moonshotai/kimi-k3): prompt 0.000003, completion 0.000015, input_cache_read 0.0000003, context_length 1048576 - https://api.novita.ai/v3/openai/models (moonshotai/kimi-k3): input 30000 / output 150000 / cache read 3000 (per-1M price units of $1/10,000, same scale as the existing kimi-k2.5 novita entry), i.e. $3.00 / $15.00 / $0.30 per 1M tokens; max_output_tokens 1048576 Both agree: $3.00/1M input, $15.00/1M output, cached input $0.30/1M (cachedInput multiplier 0.1). Moonshot's official docs (https://platform.moonshot.ai/docs/pricing/chat-k3) confirm the model and its 1M-token context window. OpenRouter supported_parameters used for the openrouter endpoint; novita parameters follow the existing kimi-k2.5 novita entry. Registry snapshots updated for the new endpoints. Fixes #5742 --- .../registrySnapshots.test.ts.snap | 106 +++++++++++++++++- .../cost/models/authors/moonshotai/index.ts | 4 + .../authors/moonshotai/kimi-k3/endpoints.ts | 88 +++++++++++++++ .../authors/moonshotai/kimi-k3/models.ts | 17 +++ 4 files changed, 210 insertions(+), 5 deletions(-) create mode 100644 packages/cost/models/authors/moonshotai/kimi-k3/endpoints.ts create mode 100644 packages/cost/models/authors/moonshotai/kimi-k3/models.ts diff --git a/packages/__tests__/cost/__snapshots__/registrySnapshots.test.ts.snap b/packages/__tests__/cost/__snapshots__/registrySnapshots.test.ts.snap index ab023ddc00..9173f7d50a 100644 --- a/packages/__tests__/cost/__snapshots__/registrySnapshots.test.ts.snap +++ b/packages/__tests__/cost/__snapshots__/registrySnapshots.test.ts.snap @@ -4049,6 +4049,68 @@ exports[`Registry Snapshots endpoint configurations snapshot 1`] = ` ], }, }, + "moonshotai/kimi-k3": { + "kimi-k3:novita": { + "context": 1048576, + "crossRegion": false, + "maxTokens": 1048576, + "modelId": "moonshotai/kimi-k3", + "parameters": [ + "frequency_penalty", + "functions", + "logit_bias", + "max_tokens", + "min_p", + "presence_penalty", + "repetition_penalty", + "response_format", + "seed", + "stop", + "structured_outputs", + "temperature", + "tool_choice", + "tools", + "top_k", + ], + "provider": "novita", + "ptbEnabled": true, + "regions": [ + "*", + ], + }, + "kimi-k3:openrouter": { + "context": 1048576, + "crossRegion": false, + "maxTokens": 1048576, + "modelId": "moonshotai/kimi-k3", + "parameters": [ + "frequency_penalty", + "include_reasoning", + "logit_bias", + "logprobs", + "max_tokens", + "min_p", + "presence_penalty", + "reasoning", + "repetition_penalty", + "response_format", + "seed", + "stop", + "structured_outputs", + "temperature", + "tool_choice", + "tools", + "top_k", + "top_logprobs", + "top_p", + ], + "provider": "openrouter", + "ptbEnabled": true, + "regions": [ + "*", + ], + }, + }, "openai/gpt-4.1": { "gpt-4.1-mini:azure": { "context": 1047576, @@ -7550,6 +7612,10 @@ exports[`Registry Snapshots model coverage snapshot 1`] = ` "novita", "openrouter", ], + "moonshotai/kimi-k3": [ + "novita", + "openrouter", + ], "openai/gpt-4.1": [ "azure", "azure", @@ -9428,6 +9494,28 @@ exports[`Registry Snapshots pricing snapshot 1`] = ` }, ], }, + "moonshotai/kimi-k3": { + "novita": [ + { + "cacheMultipliers": { + "cachedInput": 0.1, + }, + "input": 0.000003, + "output": 0.000015, + "threshold": 0, + }, + ], + "openrouter": [ + { + "cacheMultipliers": { + "cachedInput": 0.1, + }, + "input": 0.000003, + "output": 0.000015, + "threshold": 0, + }, + ], + }, "openai/gpt-4.1": { "azure": [ { @@ -10626,6 +10714,13 @@ exports[`Registry Snapshots verify registry state 1`] = ` "openrouter", ], }, + { + "model": "kimi-k3", + "providers": [ + "novita", + "openrouter", + ], + }, { "model": "llama-3.1-8b-instant", "providers": [ @@ -10906,7 +11001,7 @@ exports[`Registry Snapshots verify registry state 1`] = ` "provider": "nebius", }, { - "modelCount": 22, + "modelCount": 23, "provider": "novita", }, { @@ -10914,7 +11009,7 @@ exports[`Registry Snapshots verify registry state 1`] = ` "provider": "openai", }, { - "modelCount": 71, + "modelCount": 72, "provider": "openrouter", }, { @@ -11007,6 +11102,7 @@ exports[`Registry Snapshots verify registry state 1`] = ` "kimi-k2-0905", "kimi-k2-thinking", "kimi-k2.5", + "kimi-k3", "llama-3.1-8b-instant", "llama-3.1-8b-instruct", "llama-3.1-8b-instruct-turbo", @@ -11049,9 +11145,9 @@ exports[`Registry Snapshots verify registry state 1`] = ` "claude-3.5-haiku:anthropic:*", ], "totalArchivedConfigs": 0, - "totalEndpoints": 329, - "totalModelProviderConfigs": 329, - "totalModelsWithPtb": 108, + "totalEndpoints": 331, + "totalModelProviderConfigs": 331, + "totalModelsWithPtb": 109, "totalProviders": 21, } `; diff --git a/packages/cost/models/authors/moonshotai/index.ts b/packages/cost/models/authors/moonshotai/index.ts index 582adba43d..3061283fd6 100644 --- a/packages/cost/models/authors/moonshotai/index.ts +++ b/packages/cost/models/authors/moonshotai/index.ts @@ -8,19 +8,23 @@ import type { ModelConfig, ModelProviderConfig } from "../../types"; // Import models import { models as kimiK2Models } from "./kimi-k2/models"; import { models as kimiK25Models } from "./kimi-k2.5/models"; +import { models as kimiK3Models } from "./kimi-k3/models"; // Import endpoints import { endpoints as kimiK2Endpoints } from "./kimi-k2/endpoints"; import { endpoints as kimiK25Endpoints } from "./kimi-k2.5/endpoints"; +import { endpoints as kimiK3Endpoints } from "./kimi-k3/endpoints"; // Aggregate models export const moonshotaiModels = { ...kimiK2Models, ...kimiK25Models, + ...kimiK3Models, } satisfies Record; // Aggregate endpoints export const moonshotaiEndpointConfig = { ...kimiK2Endpoints, ...kimiK25Endpoints, + ...kimiK3Endpoints, } satisfies Record; diff --git a/packages/cost/models/authors/moonshotai/kimi-k3/endpoints.ts b/packages/cost/models/authors/moonshotai/kimi-k3/endpoints.ts new file mode 100644 index 0000000000..f916d51df5 --- /dev/null +++ b/packages/cost/models/authors/moonshotai/kimi-k3/endpoints.ts @@ -0,0 +1,88 @@ +import { ModelProviderName } from "../../../providers"; +import type { ModelProviderConfig } from "../../../types"; +import { KimiK3ModelName } from "./models"; + +export const endpoints = { + "kimi-k3:openrouter": { + provider: "openrouter", + author: "moonshotai", + providerModelId: "moonshotai/kimi-k3", + pricing: [ + { + threshold: 0, + input: 0.000003, // $3.00/1M (openrouter.ai/api/v1/models, 2026-07-28) + output: 0.000015, // $15.00/1M + cacheMultipliers: { + cachedInput: 0.1, // $0.30/1M (10% of input) + }, + }, + ], + contextLength: 1_048_576, + maxCompletionTokens: 1_048_576, + supportedParameters: [ + "frequency_penalty", + "include_reasoning", + "logit_bias", + "logprobs", + "max_tokens", + "min_p", + "presence_penalty", + "reasoning", + "repetition_penalty", + "response_format", + "seed", + "stop", + "structured_outputs", + "temperature", + "tool_choice", + "tools", + "top_k", + "top_logprobs", + "top_p", + ], + ptbEnabled: true, + endpointConfigs: { + "*": {}, + }, + }, + "kimi-k3:novita": { + provider: "novita", + author: "moonshotai", + providerModelId: "moonshotai/kimi-k3", + pricing: [ + { + threshold: 0, + input: 0.000003, // $3.00/1M (api.novita.ai/v3/openai/models, 2026-07-28) + output: 0.000015, // $15.00/1M + cacheMultipliers: { + cachedInput: 0.1, // $0.30/1M (10% of input) + }, + }, + ], + contextLength: 1_048_576, + maxCompletionTokens: 1_048_576, + supportedParameters: [ + "structured_outputs", + "functions", + "tool_choice", + "tools", + "response_format", + "max_tokens", + "temperature", + "stop", + "frequency_penalty", + "presence_penalty", + "seed", + "top_k", + "min_p", + "repetition_penalty", + "logit_bias", + ], + ptbEnabled: true, + endpointConfigs: { + "*": {}, + }, + }, +} satisfies Partial< + Record<`${KimiK3ModelName}:${ModelProviderName}`, ModelProviderConfig> +>; diff --git a/packages/cost/models/authors/moonshotai/kimi-k3/models.ts b/packages/cost/models/authors/moonshotai/kimi-k3/models.ts new file mode 100644 index 0000000000..8d3afd79cb --- /dev/null +++ b/packages/cost/models/authors/moonshotai/kimi-k3/models.ts @@ -0,0 +1,17 @@ +import { ModelConfig } from "../../../types"; + +export const models = { + "kimi-k3": { + name: "Kimi K3", + author: "moonshotai", + description: + "Kimi K3 is Moonshot AI's flagship model for long-horizon coding and end-to-end knowledge work, with a 1M-token context window. It always reasons, with configurable reasoning effort, and supports automatic context caching, tool calls, JSON mode, structured output, tool choice constraints, and dynamically loaded tools.", + contextLength: 1_048_576, + maxOutputTokens: 1_048_576, + created: "2026-07-16T00:00:00.000Z", + modality: { inputs: ["text", "image"], outputs: ["text"] }, + tokenizer: "MoonshotAI", + }, +} satisfies Record; + +export type KimiK3ModelName = keyof typeof models; From 3ead1860d9298fc3dcdd4d647dfe8465aa02c855 Mon Sep 17 00:00:00 2001 From: Mohith Gajjela <109003762+Mohith26@users.noreply.github.com> Date: Tue, 28 Jul 2026 12:54:18 -0500 Subject: [PATCH 2/2] test(cost): cover Kimi K3 cost resolution in registry tests Add registry tests following the registry-perplexity conventions: - kimi-k3 model definition and metadata - kimi-k3:openrouter and kimi-k3:novita endpoints exist with the verified $3.00/1M input, $15.00/1M output, 0.1 cached-input multiplier pricing - regression for #5742: modelCostBreakdownFromRegistry and calculateModelCostBreakdown resolve nonzero (exact) cost for providerModelId moonshotai/kimi-k3 on both providers, including the cached-input discount All 12 tests fail on main (cost lookup returns null -> billed $0) and pass with the registry entries added. --- .../cost/registry-moonshotai-kimi-k3.test.ts | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 packages/__tests__/cost/registry-moonshotai-kimi-k3.test.ts diff --git a/packages/__tests__/cost/registry-moonshotai-kimi-k3.test.ts b/packages/__tests__/cost/registry-moonshotai-kimi-k3.test.ts new file mode 100644 index 0000000000..4c1dbda139 --- /dev/null +++ b/packages/__tests__/cost/registry-moonshotai-kimi-k3.test.ts @@ -0,0 +1,110 @@ +import { describe, it, expect } from "@jest/globals"; +import { + moonshotaiModels, + moonshotaiEndpointConfig as moonshotaiEndpoints, +} from "../../cost/models/authors/moonshotai"; +import { calculateModelCostBreakdown } from "../../cost/models/calculate-cost"; +import { modelCostBreakdownFromRegistry } from "../../cost/costCalc"; +import type { ModelProviderName } from "../../cost/models/providers"; +import type { ModelConfig, ModelProviderConfig } from "../../cost/models/types"; + +describe("MoonshotAI Kimi K3 Registry", () => { + describe("Model Definition", () => { + it("should define the kimi-k3 model", () => { + expect(Object.keys(moonshotaiModels)).toContain("kimi-k3"); + }); + + it("should have correct model metadata", () => { + const model = (moonshotaiModels as Record)[ + "kimi-k3" + ]; + expect(model.author).toBe("moonshotai"); + expect(model.tokenizer).toBe("MoonshotAI"); + expect(model.contextLength).toBe(1_048_576); + expect(model.modality.inputs).toContain("text"); + expect(model.modality.outputs).toContain("text"); + }); + }); + + describe("Endpoint Configurations", () => { + const expectedEndpoints = ["kimi-k3:openrouter", "kimi-k3:novita"]; + + it.each(expectedEndpoints)("should define endpoint %s", (endpointKey) => { + expect(Object.keys(moonshotaiEndpoints)).toContain(endpointKey); + }); + + it.each(expectedEndpoints)( + "%s should have verified K3 pricing ($3.00/1M input, $15.00/1M output)", + (endpointKey) => { + const endpoint = ( + moonshotaiEndpoints as Record + )[endpointKey]; + expect(endpoint).toBeDefined(); + const pricing = endpoint.pricing[0]; + expect(pricing.input).toBe(0.000003); // $3.00 per 1M tokens + expect(pricing.output).toBe(0.000015); // $15.00 per 1M tokens + expect(pricing.cacheMultipliers?.cachedInput).toBe(0.1); // $0.30 per 1M tokens + } + ); + + it.each(expectedEndpoints)( + "%s should route to the moonshotai/kimi-k3 provider model id", + (endpointKey) => { + const endpoint = ( + moonshotaiEndpoints as Record + )[endpointKey]; + expect(endpoint.providerModelId).toBe("moonshotai/kimi-k3"); + expect(endpoint.author).toBe("moonshotai"); + } + ); + }); + + describe("Cost Calculation (regression for #5742: K3 traffic billed $0)", () => { + const providersServingK3: ModelProviderName[] = [ + "openrouter" as ModelProviderName, + "novita" as ModelProviderName, + ]; + + it.each(providersServingK3)( + "should resolve a nonzero cost for kimi-k3 usage via %s", + (provider) => { + const breakdown = modelCostBreakdownFromRegistry({ + modelUsage: { input: 1_000_000, output: 1_000_000 }, + providerModelId: "moonshotai/kimi-k3", + provider, + }); + + expect(breakdown).not.toBeNull(); + if (breakdown) { + expect(breakdown.totalCost).toBeGreaterThan(0); + // $3.00 input + $15.00 output for 1M/1M tokens + expect(breakdown.totalCost).toBeCloseTo(18.0, 10); + expect(breakdown.inputCost).toBeCloseTo(3.0, 10); + expect(breakdown.outputCost).toBeCloseTo(15.0, 10); + } + } + ); + + it.each(providersServingK3)( + "should apply the cached-input discount (10% of input) via %s", + (provider) => { + const breakdown = calculateModelCostBreakdown({ + modelUsage: { + input: 1_000_000, + output: 1_000_000, + cacheDetails: { cachedInput: 1_000_000 }, + }, + providerModelId: "moonshotai/kimi-k3", + provider, + }); + + expect(breakdown).not.toBeNull(); + if (breakdown) { + // $3.00 input + $0.30 cached input + $15.00 output + expect(breakdown.cachedInputCost).toBeCloseTo(0.3, 10); + expect(breakdown.totalCost).toBeCloseTo(18.3, 10); + } + } + ); + }); +});