fix(ai): show implied Kimi Coding subscription costs
This commit is contained in:
@@ -2,6 +2,10 @@
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Fixed Kimi Coding subscription models to report API-equivalent implied costs when models.dev reports zero pricing.
|
||||||
|
|
||||||
## [0.80.10] - 2026-07-16
|
## [0.80.10] - 2026-07-16
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
@@ -241,6 +241,15 @@ const KIMI_K3_COST = {
|
|||||||
cacheRead: 0.3,
|
cacheRead: 0.3,
|
||||||
cacheWrite: 0,
|
cacheWrite: 0,
|
||||||
} as const;
|
} as const;
|
||||||
|
// Kimi Coding is subscription-backed, so models.dev reports zero cost. Use the
|
||||||
|
// equivalent Moonshot API rates to estimate the value of subscription usage.
|
||||||
|
const KIMI_CODING_IMPLIED_COSTS: Record<string, Model<Api>["cost"]> = {
|
||||||
|
k2p7: { input: 0.95, output: 4, cacheRead: 0.19, cacheWrite: 0 },
|
||||||
|
k3: KIMI_K3_COST,
|
||||||
|
"kimi-for-coding": { input: 0.95, output: 4, cacheRead: 0.19, cacheWrite: 0 },
|
||||||
|
"kimi-for-coding-highspeed": { input: 1.9, output: 8, cacheRead: 0.38, cacheWrite: 0 },
|
||||||
|
"kimi-k2-thinking": { input: 0.6, output: 2.5, cacheRead: 0.15, cacheWrite: 0 },
|
||||||
|
};
|
||||||
const OPENROUTER_KIMI_K3_MODEL_IDS = new Set(["moonshotai/kimi-k3", "~moonshotai/kimi-latest"]);
|
const OPENROUTER_KIMI_K3_MODEL_IDS = new Set(["moonshotai/kimi-k3", "~moonshotai/kimi-latest"]);
|
||||||
|
|
||||||
const ANT_LING_RING_THINKING_LEVEL_MAP = {
|
const ANT_LING_RING_THINKING_LEVEL_MAP = {
|
||||||
@@ -1642,6 +1651,7 @@ async function loadModelsDevData(): Promise<Model<any>[]> {
|
|||||||
const normalizedName = kimiAliases.has(modelId) ? "Kimi For Coding" : m.name || normalizedId;
|
const normalizedName = kimiAliases.has(modelId) ? "Kimi For Coding" : m.name || normalizedId;
|
||||||
const isKimiK3 = normalizedId === "k3";
|
const isKimiK3 = normalizedId === "k3";
|
||||||
const allowEmptySignature = isKimiK3 || normalizedId === "kimi-for-coding";
|
const allowEmptySignature = isKimiK3 || normalizedId === "kimi-for-coding";
|
||||||
|
const impliedCost = KIMI_CODING_IMPLIED_COSTS[normalizedId];
|
||||||
|
|
||||||
models.push({
|
models.push({
|
||||||
id: normalizedId,
|
id: normalizedId,
|
||||||
@@ -1659,10 +1669,10 @@ async function loadModelsDevData(): Promise<Model<any>[]> {
|
|||||||
...(isKimiK3 ? { thinkingLevelMap: KIMI_K3_THINKING_LEVEL_MAP } : {}),
|
...(isKimiK3 ? { thinkingLevelMap: KIMI_K3_THINKING_LEVEL_MAP } : {}),
|
||||||
input: m.modalities?.input?.includes("image") ? ["text", "image"] : ["text"],
|
input: m.modalities?.input?.includes("image") ? ["text", "image"] : ["text"],
|
||||||
cost: {
|
cost: {
|
||||||
input: m.cost?.input || 0,
|
input: m.cost?.input || impliedCost?.input || 0,
|
||||||
output: m.cost?.output || 0,
|
output: m.cost?.output || impliedCost?.output || 0,
|
||||||
cacheRead: m.cost?.cache_read || 0,
|
cacheRead: m.cost?.cache_read || impliedCost?.cacheRead || 0,
|
||||||
cacheWrite: m.cost?.cache_write || 0,
|
cacheWrite: m.cost?.cache_write || impliedCost?.cacheWrite || 0,
|
||||||
},
|
},
|
||||||
contextWindow: m.limit?.context || 4096,
|
contextWindow: m.limit?.context || 4096,
|
||||||
maxTokens: m.limit?.output || 4096,
|
maxTokens: m.limit?.output || 4096,
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ export const KIMI_CODING_MODELS = {
|
|||||||
reasoning: true,
|
reasoning: true,
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
cost: {
|
cost: {
|
||||||
input: 0,
|
input: 0.95,
|
||||||
output: 0,
|
output: 4,
|
||||||
cacheRead: 0,
|
cacheRead: 0.19,
|
||||||
cacheWrite: 0,
|
cacheWrite: 0,
|
||||||
},
|
},
|
||||||
contextWindow: 262144,
|
contextWindow: 262144,
|
||||||
@@ -35,9 +35,9 @@ export const KIMI_CODING_MODELS = {
|
|||||||
thinkingLevelMap: {"off":null,"minimal":null,"low":null,"medium":null,"high":null,"xhigh":null,"max":"max"},
|
thinkingLevelMap: {"off":null,"minimal":null,"low":null,"medium":null,"high":null,"xhigh":null,"max":"max"},
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
cost: {
|
cost: {
|
||||||
input: 0,
|
input: 3,
|
||||||
output: 0,
|
output: 15,
|
||||||
cacheRead: 0,
|
cacheRead: 0.3,
|
||||||
cacheWrite: 0,
|
cacheWrite: 0,
|
||||||
},
|
},
|
||||||
contextWindow: 1048576,
|
contextWindow: 1048576,
|
||||||
@@ -54,9 +54,9 @@ export const KIMI_CODING_MODELS = {
|
|||||||
reasoning: true,
|
reasoning: true,
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
cost: {
|
cost: {
|
||||||
input: 0,
|
input: 0.95,
|
||||||
output: 0,
|
output: 4,
|
||||||
cacheRead: 0,
|
cacheRead: 0.19,
|
||||||
cacheWrite: 0,
|
cacheWrite: 0,
|
||||||
},
|
},
|
||||||
contextWindow: 262144,
|
contextWindow: 262144,
|
||||||
@@ -73,9 +73,9 @@ export const KIMI_CODING_MODELS = {
|
|||||||
reasoning: true,
|
reasoning: true,
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
cost: {
|
cost: {
|
||||||
input: 0,
|
input: 1.9,
|
||||||
output: 0,
|
output: 8,
|
||||||
cacheRead: 0,
|
cacheRead: 0.38,
|
||||||
cacheWrite: 0,
|
cacheWrite: 0,
|
||||||
},
|
},
|
||||||
contextWindow: 262144,
|
contextWindow: 262144,
|
||||||
@@ -92,9 +92,9 @@ export const KIMI_CODING_MODELS = {
|
|||||||
reasoning: true,
|
reasoning: true,
|
||||||
input: ["text"],
|
input: ["text"],
|
||||||
cost: {
|
cost: {
|
||||||
input: 0,
|
input: 0.6,
|
||||||
output: 0,
|
output: 2.5,
|
||||||
cacheRead: 0,
|
cacheRead: 0.15,
|
||||||
cacheWrite: 0,
|
cacheWrite: 0,
|
||||||
},
|
},
|
||||||
contextWindow: 262144,
|
contextWindow: 262144,
|
||||||
|
|||||||
@@ -56,6 +56,21 @@ describe("builtin providers", () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("uses API-equivalent implied pricing for Kimi Coding subscription models", () => {
|
||||||
|
const models = builtinModels();
|
||||||
|
const expectedCosts = {
|
||||||
|
k2p7: { input: 0.95, output: 4, cacheRead: 0.19, cacheWrite: 0 },
|
||||||
|
k3: { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 0 },
|
||||||
|
"kimi-for-coding": { input: 0.95, output: 4, cacheRead: 0.19, cacheWrite: 0 },
|
||||||
|
"kimi-for-coding-highspeed": { input: 1.9, output: 8, cacheRead: 0.38, cacheWrite: 0 },
|
||||||
|
"kimi-k2-thinking": { input: 0.6, output: 2.5, cacheRead: 0.15, cacheWrite: 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const [modelId, cost] of Object.entries(expectedCosts)) {
|
||||||
|
expect(models.getModel("kimi-coding", modelId)?.cost).toEqual(cost);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
it("resolves anthropic auth from env with OAuth token precedence", async () => {
|
it("resolves anthropic auth from env with OAuth token precedence", async () => {
|
||||||
const models = createModels({
|
const models = createModels({
|
||||||
authContext: fakeAuthContext({ ANTHROPIC_API_KEY: "key", ANTHROPIC_OAUTH_TOKEN: "oauth-token" }),
|
authContext: fakeAuthContext({ ANTHROPIC_API_KEY: "key", ANTHROPIC_OAUTH_TOKEN: "oauth-token" }),
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Fixed obsolete custom UI, custom tool, and custom editor examples in the extension documentation ([#6735](https://github.com/earendil-works/pi/issues/6735)).
|
- Fixed obsolete custom UI, custom tool, and custom editor examples in the extension documentation ([#6735](https://github.com/earendil-works/pi/issues/6735)).
|
||||||
|
- Fixed Kimi Coding sessions to show API-equivalent implied costs with the subscription indicator.
|
||||||
|
|
||||||
## [0.80.10] - 2026-07-16
|
## [0.80.10] - 2026-07-16
|
||||||
|
|
||||||
|
|||||||
@@ -137,8 +137,10 @@ export class FooterComponent implements Component {
|
|||||||
if ((totalCacheRead > 0 || totalCacheWrite > 0) && latestCacheHitRate !== undefined) {
|
if ((totalCacheRead > 0 || totalCacheWrite > 0) && latestCacheHitRate !== undefined) {
|
||||||
statsParts.push(`CH${latestCacheHitRate.toFixed(1)}%`);
|
statsParts.push(`CH${latestCacheHitRate.toFixed(1)}%`);
|
||||||
}
|
}
|
||||||
// Show cost with "(sub)" indicator if using OAuth subscription
|
// Kimi Coding is subscription-backed despite using API-key authentication.
|
||||||
const usingSubscription = state.model ? this.session.modelRuntime.isUsingOAuth(state.model.provider) : false;
|
const usingSubscription = state.model
|
||||||
|
? state.model.provider === "kimi-coding" || this.session.modelRuntime.isUsingOAuth(state.model.provider)
|
||||||
|
: false;
|
||||||
if (totalCost || usingSubscription) {
|
if (totalCost || usingSubscription) {
|
||||||
const costStr = `$${totalCost.toFixed(3)}${usingSubscription ? " (sub)" : ""}`;
|
const costStr = `$${totalCost.toFixed(3)}${usingSubscription ? " (sub)" : ""}`;
|
||||||
statsParts.push(costStr);
|
statsParts.push(costStr);
|
||||||
|
|||||||
@@ -141,4 +141,21 @@ describe("FooterComponent width handling", () => {
|
|||||||
const statsLine = stripAnsi(footer.render(120)[1]);
|
const statsLine = stripAnsi(footer.render(120)[1]);
|
||||||
expect(statsLine).toContain("CH25.0%");
|
expect(statsLine).toContain("CH25.0%");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("marks Kimi Coding costs as subscription estimates", () => {
|
||||||
|
const session = createSession({
|
||||||
|
sessionName: "",
|
||||||
|
provider: "kimi-coding",
|
||||||
|
usage: {
|
||||||
|
input: 100,
|
||||||
|
output: 10,
|
||||||
|
cacheRead: 0,
|
||||||
|
cacheWrite: 0,
|
||||||
|
cost: { total: 1.234 },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const footer = new FooterComponent(session, createFooterData(1));
|
||||||
|
|
||||||
|
expect(stripAnsi(footer.render(120)[1])).toContain("$1.234 (sub)");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user