diff --git a/src/providers/crush.ts b/src/providers/crush.ts index 5661d82..b56f488 100644 --- a/src/providers/crush.ts +++ b/src/providers/crush.ts @@ -2,7 +2,6 @@ import { readFile } from 'fs/promises' import { join, resolve } from 'path' import { homedir, platform } from 'os' -import { calculateCost } from '../models.js' import { isSqliteAvailable, getSqliteLoadError, openDatabase, type SqliteDatabase } from '../sqlite.js' import type { Provider, SessionSource, SessionParser, ParsedProviderCall } from './types.js' @@ -165,10 +164,7 @@ function createParser(source: SessionSource, seenKeys: Set): SessionPars const model = dominantModel(db, sessionId) // Crush already records cost in dollars; trust it. Fall back to - // pricing-table calculation only when the row is missing a cost. - const costUSD = cost > 0 - ? cost - : calculateCost(model, inputTokens, outputTokens, 0, 0, 0) + // host-side pricing-table calculation only when the row is missing a cost. yield { provider: 'crush', @@ -180,7 +176,9 @@ function createParser(source: SessionSource, seenKeys: Set): SessionPars cachedInputTokens: 0, reasoningTokens: 0, webSearchRequests: 0, - costUSD, + ...(cost > 0 + ? { costUSD: cost, costBasis: 'measured' as const } + : { costBasis: 'estimated' as const }), tools: [], bashCommands: [], timestamp: epochSecondsToIso(session.updated_at ?? session.created_at), diff --git a/src/providers/openclaw.ts b/src/providers/openclaw.ts index bc6da53..4ec954b 100644 --- a/src/providers/openclaw.ts +++ b/src/providers/openclaw.ts @@ -3,7 +3,6 @@ import { basename, join } from 'path' import { homedir } from 'os' import { readSessionFile } from '../fs-utils.js' -import { calculateCost } from '../models.js' import { extractBashCommands } from '../bash-utils.js' import type { Provider, SessionSource, SessionParser, ParsedProviderCall } from './types.js' @@ -172,9 +171,6 @@ function createParser(source: SessionSource, seenKeys: Set): SessionPars const u = call.usage const costFromProvider = u.cost?.total ?? 0 - const costUSD = costFromProvider > 0 - ? costFromProvider - : calculateCost(call.model, u.input, u.output, u.cacheWrite, u.cacheRead, 0) const ts = new Date(call.timestamp) if (isNaN(ts.getTime()) || ts.getTime() < 1_000_000_000_000) continue @@ -189,7 +185,9 @@ function createParser(source: SessionSource, seenKeys: Set): SessionPars cachedInputTokens: u.cacheRead, reasoningTokens: 0, webSearchRequests: 0, - costUSD, + ...(costFromProvider > 0 + ? { costUSD: costFromProvider, costBasis: 'measured' as const } + : { costBasis: 'estimated' as const }), tools: [...new Set(call.tools)], bashCommands: [...new Set(call.bashCommands)], timestamp: ts.toISOString(), diff --git a/tests/providers/crush.test.ts b/tests/providers/crush.test.ts index b86f535..4a373dd 100644 --- a/tests/providers/crush.test.ts +++ b/tests/providers/crush.test.ts @@ -5,6 +5,7 @@ import { tmpdir } from 'os' import { createRequire } from 'node:module' import { describe, it, expect, beforeEach, afterEach } from 'vitest' +import { priceProviderCall } from '../../src/pricing-pass.js' import { isSqliteAvailable } from '../../src/sqlite.js' import { createCrushProvider } from '../../src/providers/crush.js' import type { ParsedProviderCall } from '../../src/providers/types.js' @@ -123,7 +124,7 @@ async function writeRegistry(globalDataDir: string, entries: Record }): Promise { const out: ParsedProviderCall[] = [] - for await (const call of parser.parse()) out.push(call) + for await (const call of parser.parse()) out.push(priceProviderCall(call)) return out } diff --git a/tests/providers/openclaw.test.ts b/tests/providers/openclaw.test.ts index d988aac..01a5049 100644 --- a/tests/providers/openclaw.test.ts +++ b/tests/providers/openclaw.test.ts @@ -1,4 +1,5 @@ import { describe, it, expect, afterAll } from 'vitest' +import { priceProviderCall } from '../../src/pricing-pass.js' import { createOpenClawProvider } from '../../src/providers/openclaw.js' import { writeFile, mkdir, rm } from 'fs/promises' import { join } from 'path' @@ -63,7 +64,7 @@ describe('openclaw provider', () => { const parser = provider.createSessionParser(sources[0], new Set()) const calls: any[] = [] for await (const call of parser.parse()) { - calls.push(call) + calls.push(priceProviderCall(call)) } expect(calls.length).toBe(2) expect(calls[0].provider).toBe('openclaw') @@ -82,7 +83,7 @@ describe('openclaw provider', () => { const sources = await provider.discoverSessions() const parser = provider.createSessionParser(sources[0], new Set()) const calls: any[] = [] - for await (const call of parser.parse()) calls.push(call) + for await (const call of parser.parse()) calls.push(priceProviderCall(call)) expect(calls[1].costUSD).toBe(0.05) }) @@ -93,7 +94,7 @@ describe('openclaw provider', () => { const sources = await provider.discoverSessions() const parser = provider.createSessionParser(sources[0], new Set()) const calls: any[] = [] - for await (const call of parser.parse()) calls.push(call) + for await (const call of parser.parse()) calls.push(priceProviderCall(call)) expect(calls[1].tools).toContain('Bash') expect(calls[1].tools).toContain('Read') expect(calls[1].tools).toContain('Write') @@ -108,11 +109,11 @@ describe('openclaw provider', () => { const seen = new Set() const parser1 = provider.createSessionParser(sources[0], seen) const calls1: any[] = [] - for await (const c of parser1.parse()) calls1.push(c) + for await (const c of parser1.parse()) calls1.push(priceProviderCall(c)) expect(calls1.length).toBe(2) const parser2 = provider.createSessionParser(sources[0], seen) const calls2: any[] = [] - for await (const c of parser2.parse()) calls2.push(c) + for await (const c of parser2.parse()) calls2.push(priceProviderCall(c)) expect(calls2.length).toBe(0) }) @@ -131,7 +132,7 @@ describe('openclaw provider', () => { const sources = await provider.discoverSessions() const parser = provider.createSessionParser(sources[0], new Set()) const calls: any[] = [] - for await (const c of parser.parse()) calls.push(c) + for await (const c of parser.parse()) calls.push(priceProviderCall(c)) expect(calls[0].model).toBe('gpt-5.5') }) @@ -150,7 +151,7 @@ describe('openclaw provider', () => { const sources = await provider.discoverSessions() const parser = provider.createSessionParser(sources[0], new Set()) const calls: any[] = [] - for await (const c of parser.parse()) calls.push(c) + for await (const c of parser.parse()) calls.push(priceProviderCall(c)) expect(calls[0].model).toBe('glm-5.1:cloud') }) @@ -168,7 +169,7 @@ describe('openclaw provider', () => { const sources = await provider.discoverSessions() const parser = provider.createSessionParser(sources[0], new Set()) const calls: any[] = [] - for await (const c of parser.parse()) calls.push(c) + for await (const c of parser.parse()) calls.push(priceProviderCall(c)) expect(calls.length).toBe(0) })