Merge pull request #817 from getagentseal/phase0/kimi-batch3

refactor(pricing): fan-out — openclaw, crush
This commit is contained in:
Resham Joshi 2026-07-26 09:22:23 -07:00 committed by GitHub
commit 6552b10bd8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 18 additions and 20 deletions

View file

@ -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<string>): 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<string>): 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),

View file

@ -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<string>): 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<string>): 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(),

View file

@ -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<string, { pa
async function collect(parser: { parse(): AsyncGenerator<ParsedProviderCall> }): Promise<ParsedProviderCall[]> {
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
}

View file

@ -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<string>()
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)
})