diff --git a/src/providers/droid.ts b/src/providers/droid.ts index 4ec8cf6..7689f7c 100644 --- a/src/providers/droid.ts +++ b/src/providers/droid.ts @@ -3,7 +3,7 @@ import { join } from 'path' import { homedir } from 'os' import { readSessionFile, readSessionLines } from '../fs-utils.js' -import { calculateCost, getShortModelName } from '../models.js' +import { getShortModelName } from '../models.js' import { extractBashCommands } from '../bash-utils.js' import { normalizeContentBlocks } from '../content-utils.js' import type { @@ -255,15 +255,6 @@ function createParser( if (seenKeys.has(dedupKey)) continue seenKeys.add(dedupKey) - const costUSD = calculateCost( - sessionModelDisplay.toLowerCase(), - inputTokens, - outputTokens + thinkingTokens, - cacheCreationTokens, - cacheReadTokens, - 0, - ) - // Use the call's timestamp, or session_start timestamp const timestamp = call.timestamp || '' @@ -277,7 +268,7 @@ function createParser( cachedInputTokens: cacheReadTokens, reasoningTokens: thinkingTokens, webSearchRequests: 0, - costUSD, + costBasis: 'estimated', tools: call.tools, bashCommands: call.bashCommands, timestamp, diff --git a/src/providers/goose.ts b/src/providers/goose.ts index 7109709..ca149e8 100644 --- a/src/providers/goose.ts +++ b/src/providers/goose.ts @@ -1,7 +1,7 @@ import { join } from 'path' import { homedir, platform } from 'os' -import { calculateCost, getShortModelName } from '../models.js' +import { getShortModelName } from '../models.js' import { extractBashCommands } from '../bash-utils.js' import { isSqliteAvailable, getSqliteLoadError, openDatabase, blobToText, type SqliteDatabase } from '../sqlite.js' import type { ToolCall } from '../types.js' @@ -190,7 +190,6 @@ function createParser(source: SessionSource, seenKeys: Set): SessionPars const config = parseModelConfig(blobToText(session.model_config_json)) const model = config.model_name ?? 'unknown' - const costUSD = calculateCost(model, inputTokens, outputTokens, 0, 0, 0) const { tools, bashCommands, toolSequence } = extractToolsFromMessages(db, sessionId) const userMessage = getFirstUserMessage(db, sessionId) @@ -210,7 +209,7 @@ function createParser(source: SessionSource, seenKeys: Set): SessionPars cachedInputTokens: 0, reasoningTokens: 0, webSearchRequests: 0, - costUSD, + costBasis: 'estimated', tools, bashCommands, toolSequence: toolSequence.length > 1 ? toolSequence : undefined, diff --git a/src/providers/lingtai-tui.ts b/src/providers/lingtai-tui.ts index bec5d93..63f622d 100644 --- a/src/providers/lingtai-tui.ts +++ b/src/providers/lingtai-tui.ts @@ -3,7 +3,7 @@ import { basename, delimiter, dirname, join, resolve } from 'path' import { homedir } from 'os' import { readSessionLines } from '../fs-utils.js' -import { calculateCost, getShortModelName } from '../models.js' +import { getShortModelName } from '../models.js' import type { ParsedProviderCall, Provider, SessionParser, SessionSource } from './types.js' type JsonObject = Record @@ -366,15 +366,6 @@ function createParser(source: SessionSource): SessionParser { cachedInputTokens, ].join(':') - const costUSD = calculateCost( - model, - inputTokens, - outputTokens + reasoningTokens, - 0, - cachedInputTokens, - 0, - ) - yield { provider: 'lingtai-tui', model, @@ -385,7 +376,7 @@ function createParser(source: SessionSource): SessionParser { cachedInputTokens, reasoningTokens, webSearchRequests: 0, - costUSD, + costBasis: 'estimated', tools: activity.tools, bashCommands: [], subagentTypes: activity.subagentTypes, diff --git a/src/providers/mux.ts b/src/providers/mux.ts index 4ebd919..dab5aa9 100644 --- a/src/providers/mux.ts +++ b/src/providers/mux.ts @@ -3,7 +3,7 @@ import { basename, dirname, join, resolve } from 'path' import { homedir } from 'os' import { readSessionLines } from '../fs-utils.js' -import { calculateCost, getShortModelName } from '../models.js' +import { getShortModelName } from '../models.js' import { extractBashCommands } from '../bash-utils.js' import type { Provider, SessionSource, SessionParser, ParsedProviderCall } from './types.js' import { safeNumber } from '../parser.js' @@ -217,15 +217,6 @@ function createParser(source: SessionSource, seenKeys: Set): SessionPars return typeof script === 'string' ? extractBashCommands(script) : [] }) - const costUSD = calculateCost( - model, - inputTokens, - outputTokens + reasoning, - cacheCreate, - cacheRead, - 0, - ) - const timestamp = toIsoTimestamp(meta.timestamp, msg.createdAt) yield { @@ -238,7 +229,7 @@ function createParser(source: SessionSource, seenKeys: Set): SessionPars cachedInputTokens: cacheRead, reasoningTokens: reasoning, webSearchRequests: 0, - costUSD, + costBasis: 'estimated', tools, bashCommands, timestamp, diff --git a/src/providers/open-design.ts b/src/providers/open-design.ts index 5a2a079..6cb0d63 100644 --- a/src/providers/open-design.ts +++ b/src/providers/open-design.ts @@ -3,7 +3,6 @@ import { basename, dirname, join } from 'path' import { homedir, platform } from 'os' import { readSessionLines } from '../fs-utils.js' -import { calculateCost } from '../models.js' import type { Provider, SessionSource, SessionParser, ParsedProviderCall } from './types.js' const PROVIDER_NAME = 'open-design' @@ -199,14 +198,6 @@ function createParser(source: SessionSource, seenKeys: Set): SessionPars seenKeys.add(dedupKey) const uncachedInputTokens = Math.max(0, usage.inputTokens - usage.cacheReadTokens) - const costUSD = calculateCost( - currentModel, - uncachedInputTokens, - usage.outputTokens + usage.reasoningTokens, - 0, - usage.cacheReadTokens, - 0, - ) yield { provider: PROVIDER_NAME, @@ -220,7 +211,7 @@ function createParser(source: SessionSource, seenKeys: Set): SessionPars cachedInputTokens: usage.cacheReadTokens, reasoningTokens: usage.reasoningTokens, webSearchRequests: 0, - costUSD, + costBasis: 'estimated', tools: [], bashCommands: [], timestamp: timestampValue(entry.timestamp), diff --git a/tests/providers/mux.test.ts b/tests/providers/mux.test.ts index 1957be3..48f6759 100644 --- a/tests/providers/mux.test.ts +++ b/tests/providers/mux.test.ts @@ -5,6 +5,7 @@ import { tmpdir } from 'os' import { createMuxProvider } from '../../src/providers/mux.js' import type { ParsedProviderCall } from '../../src/providers/types.js' +import { priceProviderCall } from '../../src/pricing-pass.js' let tmpDir: string @@ -187,7 +188,7 @@ describe('mux provider - session discovery', () => { const sessions = await provider.discoverSessions() const calls: ParsedProviderCall[] = [] for (const source of sessions) { - for await (const call of provider.createSessionParser(source, seenKeys).parse()) calls.push(call) + for await (const call of provider.createSessionParser(source, seenKeys).parse()) calls.push(priceProviderCall(call)) } expect(calls).toHaveLength(2) @@ -217,7 +218,7 @@ describe('mux provider - chat.jsonl parsing', () => { const source = { path: filePath, project: 'myproject', provider: 'mux' } const calls: ParsedProviderCall[] = [] for await (const call of provider.createSessionParser(source, new Set()).parse()) { - calls.push(call) + calls.push(priceProviderCall(call)) } expect(calls).toHaveLength(1) @@ -253,7 +254,7 @@ describe('mux provider - chat.jsonl parsing', () => { const source = { path: filePath, project: 'myproject', provider: 'mux' } const calls: ParsedProviderCall[] = [] for await (const call of provider.createSessionParser(source, new Set()).parse()) { - calls.push(call) + calls.push(priceProviderCall(call)) } expect(calls[0]!.tools).toEqual(['Read', 'Edit', 'Bash']) @@ -274,7 +275,7 @@ describe('mux provider - chat.jsonl parsing', () => { const source = { path: filePath, project: 'myproject', provider: 'mux' } const calls: ParsedProviderCall[] = [] for await (const call of provider.createSessionParser(source, new Set()).parse()) { - calls.push(call) + calls.push(priceProviderCall(call)) } expect(calls).toHaveLength(0) }) @@ -288,7 +289,7 @@ describe('mux provider - chat.jsonl parsing', () => { const source = { path: filePath, project: 'myproject', provider: 'mux' } const calls: ParsedProviderCall[] = [] for await (const call of provider.createSessionParser(source, new Set()).parse()) { - calls.push(call) + calls.push(priceProviderCall(call)) } expect(calls).toHaveLength(0) }) @@ -301,9 +302,9 @@ describe('mux provider - chat.jsonl parsing', () => { const seenKeys = new Set() const first: ParsedProviderCall[] = [] - for await (const call of provider.createSessionParser(source, seenKeys).parse()) first.push(call) + for await (const call of provider.createSessionParser(source, seenKeys).parse()) first.push(priceProviderCall(call)) const second: ParsedProviderCall[] = [] - for await (const call of provider.createSessionParser(source, seenKeys).parse()) second.push(call) + for await (const call of provider.createSessionParser(source, seenKeys).parse()) second.push(priceProviderCall(call)) expect(first).toHaveLength(1) expect(second).toHaveLength(0) @@ -320,7 +321,7 @@ describe('mux provider - chat.jsonl parsing', () => { const provider = createMuxProvider(tmpDir) const source = { path: filePath, project: 'myproject', provider: 'mux' } const calls: ParsedProviderCall[] = [] - for await (const call of provider.createSessionParser(source, new Set()).parse()) calls.push(call) + for await (const call of provider.createSessionParser(source, new Set()).parse()) calls.push(priceProviderCall(call)) expect(calls).toHaveLength(2) expect(calls[0]!.userMessage).toBe('first question') @@ -333,7 +334,7 @@ describe('mux provider - chat.jsonl parsing', () => { const provider = createMuxProvider(tmpDir) const source = { path: join(tmpDir, 'sessions', 'nope', 'chat.jsonl'), project: 'x', provider: 'mux' } const calls: ParsedProviderCall[] = [] - for await (const call of provider.createSessionParser(source, new Set()).parse()) calls.push(call) + for await (const call of provider.createSessionParser(source, new Set()).parse()) calls.push(priceProviderCall(call)) expect(calls).toHaveLength(0) }) @@ -350,7 +351,7 @@ describe('mux provider - chat.jsonl parsing', () => { const provider = createMuxProvider(tmpDir) const source = { path: filePath, project: 'p', provider: 'mux' } const calls: ParsedProviderCall[] = [] - for await (const call of provider.createSessionParser(source, new Set()).parse()) calls.push(call) + for await (const call of provider.createSessionParser(source, new Set()).parse()) calls.push(priceProviderCall(call)) expect(calls).toHaveLength(2) expect(new Set(calls.map(c => c.deduplicationKey)).size).toBe(2) @@ -368,7 +369,7 @@ describe('mux provider - chat.jsonl parsing', () => { const provider = createMuxProvider(tmpDir) const source = { path: filePath, project: 'p', provider: 'mux' } const calls: ParsedProviderCall[] = [] - for await (const call of provider.createSessionParser(source, new Set()).parse()) calls.push(call) + for await (const call of provider.createSessionParser(source, new Set()).parse()) calls.push(priceProviderCall(call)) expect(calls).toHaveLength(3) // none of the malformed lines aborted the parse expect(calls.find(c => c.deduplicationKey === 'mux:ws-abc:good')?.inputTokens).toBe(100) diff --git a/tests/providers/open-design.test.ts b/tests/providers/open-design.test.ts index 1595c5f..72451d2 100644 --- a/tests/providers/open-design.test.ts +++ b/tests/providers/open-design.test.ts @@ -8,6 +8,7 @@ import { clearSessionCache, filterProjectsByDateRange, parseAllSessions } from ' import { allProviderNames } from '../../src/providers/index.js' import { createOpenDesignProvider } from '../../src/providers/open-design.js' import type { ParsedProviderCall, SessionSource } from '../../src/providers/types.js' +import { priceProviderCall } from '../../src/pricing-pass.js' const fixtureRoot = join(import.meta.dirname, '../fixtures/open-design') const dataDir = join(fixtureRoot, 'namespaces', 'release-stable', 'data') @@ -19,7 +20,7 @@ let cacheDir: string | undefined async function collect(source: SessionSource, seenKeys = new Set()): Promise { const provider = createOpenDesignProvider() const calls: ParsedProviderCall[] = [] - for await (const call of provider.createSessionParser(source, seenKeys).parse()) calls.push(call) + for await (const call of provider.createSessionParser(source, seenKeys).parse()) calls.push(priceProviderCall(call)) return calls }