Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 101 additions & 5 deletions packages/__tests__/cost/__snapshots__/registrySnapshots.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -7550,6 +7612,10 @@ exports[`Registry Snapshots model coverage snapshot 1`] = `
"novita",
"openrouter",
],
"moonshotai/kimi-k3": [
"novita",
"openrouter",
],
"openai/gpt-4.1": [
"azure",
"azure",
Expand Down Expand Up @@ -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": [
{
Expand Down Expand Up @@ -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": [
Expand Down Expand Up @@ -10906,15 +11001,15 @@ exports[`Registry Snapshots verify registry state 1`] = `
"provider": "nebius",
},
{
"modelCount": 22,
"modelCount": 23,
"provider": "novita",
},
{
"modelCount": 33,
"provider": "openai",
},
{
"modelCount": 71,
"modelCount": 72,
"provider": "openrouter",
},
{
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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,
}
`;
110 changes: 110 additions & 0 deletions packages/__tests__/cost/registry-moonshotai-kimi-k3.test.ts
Original file line number Diff line number Diff line change
@@ -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<string, ModelConfig>)[
"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<string, ModelProviderConfig>
)[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<string, ModelProviderConfig>
)[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);
}
}
);
});
});
4 changes: 4 additions & 0 deletions packages/cost/models/authors/moonshotai/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, ModelConfig>;

// Aggregate endpoints
export const moonshotaiEndpointConfig = {
...kimiK2Endpoints,
...kimiK25Endpoints,
...kimiK3Endpoints,
} satisfies Record<string, ModelProviderConfig>;
88 changes: 88 additions & 0 deletions packages/cost/models/authors/moonshotai/kimi-k3/endpoints.ts
Original file line number Diff line number Diff line change
@@ -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>
>;
Loading