From 07c553a47e2fc3e995266fa461ec4c8a025b68ab Mon Sep 17 00:00:00 2001 From: Marius Wichtner Date: Tue, 27 Jan 2026 15:31:20 +0100 Subject: [PATCH] feat: use provider-reported cost for OpenRouter/Kilo in sidebar --- packages/opencode/src/session/index.ts | 13 +++ .../opencode/test/session/compaction.test.ts | 88 +++++++++++++++++++ 2 files changed, 101 insertions(+) diff --git a/packages/opencode/src/session/index.ts b/packages/opencode/src/session/index.ts index b81a21a57b..a6e79980cb 100644 --- a/packages/opencode/src/session/index.ts +++ b/packages/opencode/src/session/index.ts @@ -451,6 +451,19 @@ export namespace Session { }, } + // kilocode_change start - Use provider-reported cost when available for OpenRouter/Kilo + // The OpenRouter AI SDK provider exposes cost at providerMetadata.openrouter.usage.cost + const openrouterUsage = input.metadata?.["openrouter"]?.["usage"] as { cost?: number } | undefined + const providerCost = openrouterUsage?.cost + + if (providerCost !== undefined && providerCost !== null && Number.isFinite(providerCost)) { + return { + cost: safe(providerCost), + tokens, + } + } + // kilocode_change end + const costInfo = input.model.cost?.experimentalOver200K && tokens.input + tokens.cache.read > 200_000 ? input.model.cost.experimentalOver200K diff --git a/packages/opencode/test/session/compaction.test.ts b/packages/opencode/test/session/compaction.test.ts index 2e9c091870..7482c484f0 100644 --- a/packages/opencode/test/session/compaction.test.ts +++ b/packages/opencode/test/session/compaction.test.ts @@ -290,4 +290,92 @@ describe("session.getUsage", () => { expect(result.cost).toBe(3 + 1.5) }) + + // kilocode_change start - Test for OpenRouter provider cost + test("uses openrouter provider cost when available", () => { + const model = createModel({ + context: 100_000, + output: 32_000, + cost: { + input: 3, + output: 15, + cache: { read: 0.3, write: 3.75 }, + }, + }) + const result = Session.getUsage({ + model, + usage: { + inputTokens: 1_000_000, + outputTokens: 100_000, + totalTokens: 1_100_000, + }, + metadata: { + openrouter: { + usage: { + cost: 0.42, // Provider-reported cost should be used instead of calculated + }, + }, + }, + }) + + // Should use the provider cost (0.42) instead of calculated cost (4.5) + expect(result.cost).toBe(0.42) + }) + + test("falls back to calculated cost when openrouter cost is not available", () => { + const model = createModel({ + context: 100_000, + output: 32_000, + cost: { + input: 3, + output: 15, + cache: { read: 0.3, write: 3.75 }, + }, + }) + const result = Session.getUsage({ + model, + usage: { + inputTokens: 1_000_000, + outputTokens: 100_000, + totalTokens: 1_100_000, + }, + metadata: { + openrouter: { + usage: { + // cost is undefined + }, + }, + }, + }) + + // Should fall back to calculated cost + expect(result.cost).toBe(3 + 1.5) + }) + + test("falls back to calculated cost when openrouter metadata is empty", () => { + const model = createModel({ + context: 100_000, + output: 32_000, + cost: { + input: 3, + output: 15, + cache: { read: 0.3, write: 3.75 }, + }, + }) + const result = Session.getUsage({ + model, + usage: { + inputTokens: 1_000_000, + outputTokens: 100_000, + totalTokens: 1_100_000, + }, + metadata: { + openrouter: {}, + }, + }) + + // Should fall back to calculated cost + expect(result.cost).toBe(3 + 1.5) + }) + // kilocode_change end })