From 9b0dd36cda0b9accb429a7f9f9ad9b054a27d04a Mon Sep 17 00:00:00 2001 From: Shoubhit Dash Date: Tue, 18 Aug 2026 19:49:08 +0530 Subject: [PATCH] fix(session): ignore malformed model costs (#43248) --- packages/opencode/src/session/session.ts | 16 +++++++--------- .../opencode/test/session/compaction.test.ts | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/packages/opencode/src/session/session.ts b/packages/opencode/src/session/session.ts index cfe034146c1..a2a91cd47b5 100644 --- a/packages/opencode/src/session/session.ts +++ b/packages/opencode/src/session/session.ts @@ -336,10 +336,8 @@ export function plan(input: { slug: string; time: { created: number } }, instanc } export const getUsage = (input: { model: Provider.Model; usage: Usage; metadata?: ProviderMetadata }) => { - const safe = (value: number) => { - if (!Number.isFinite(value)) return 0 - return Math.max(0, value) - } + const finite = (value: number) => (Number.isFinite(value) ? value : 0) + const safe = (value: number) => Math.max(0, finite(value)) const inputTokens = safe(input.usage.inputTokens ?? 0) const outputTokens = safe(input.usage.outputTokens ?? 0) const reasoningTokens = safe(input.usage.reasoningTokens ?? 0) @@ -393,13 +391,13 @@ export const getUsage = (input: { model: Provider.Model; usage: Usage; metadata? ? new Decimal(totalNanoAiu).div(100_000_000_000).toNumber() : safe( new Decimal(0) - .add(new Decimal(tokens.input).mul(costInfo?.input ?? 0).div(1_000_000)) - .add(new Decimal(tokens.output).mul(costInfo?.output ?? 0).div(1_000_000)) - .add(new Decimal(tokens.cache.read).mul(costInfo?.cache?.read ?? 0).div(1_000_000)) - .add(new Decimal(tokens.cache.write).mul(costInfo?.cache?.write ?? 0).div(1_000_000)) + .add(new Decimal(tokens.input).mul(finite(costInfo?.input ?? 0)).div(1_000_000)) + .add(new Decimal(tokens.output).mul(finite(costInfo?.output ?? 0)).div(1_000_000)) + .add(new Decimal(tokens.cache.read).mul(finite(costInfo?.cache?.read ?? 0)).div(1_000_000)) + .add(new Decimal(tokens.cache.write).mul(finite(costInfo?.cache?.write ?? 0)).div(1_000_000)) // TODO: update models.dev to have better pricing model, for now: // charge reasoning tokens at the same rate as output tokens - .add(new Decimal(tokens.reasoning).mul(costInfo?.output ?? 0).div(1_000_000)) + .add(new Decimal(tokens.reasoning).mul(finite(costInfo?.output ?? 0)).div(1_000_000)) .toNumber(), ), tokens, diff --git a/packages/opencode/test/session/compaction.test.ts b/packages/opencode/test/session/compaction.test.ts index 4f0981fa647..c76dd98b861 100644 --- a/packages/opencode/test/session/compaction.test.ts +++ b/packages/opencode/test/session/compaction.test.ts @@ -1782,6 +1782,22 @@ describe("SessionNs.getUsage", () => { expect(Number.isNaN(result.cost)).toBe(false) }) + test("ignores malformed cost fields", () => { + const model = createModel({ + context: 100_000, + output: 32_000, + cost: { input: 3, output: 15, cache: { read: 0.3, write: 3.75 } }, + }) + Object.assign(model.cost, { input: {} }) + + const result = SessionNs.getUsage({ + model, + usage: usage({ inputTokens: 1_000_000, outputTokens: 100_000, totalTokens: 1_100_000 }), + }) + + expect(result.cost).toBe(1.5) + }) + test("calculates cost correctly", () => { const model = createModel({ context: 100_000,