TypeScript 61.9%
HTML 37.2%
SQL 0.7%
1import type { Usage } from './types.js';23/**4 * List prices in USD per 1M tokens (first-party API rates, cached 2026-06). Used only for the5 * cost ledger (§169); billing truth lives with the provider. Update when prices change.6 */7export interface ModelPrice {8 input: number;9 output: number;10 /** cache read multiplier vs input (Anthropic: 0.1) */11 cacheRead: number;12 /** cache write multiplier vs input (Anthropic: 1.25) */13 cacheWrite: number;14}1516export const PRICE_TABLE: Record<string, ModelPrice> = {17 'claude-opus-5': { input: 5, output: 25, cacheRead: 0.1, cacheWrite: 1.25 },18 'claude-opus-4-8': { input: 5, output: 25, cacheRead: 0.1, cacheWrite: 1.25 },19 'claude-sonnet-5': { input: 2, output: 10, cacheRead: 0.1, cacheWrite: 1.25 },20 'claude-sonnet-4-6': { input: 3, output: 15, cacheRead: 0.1, cacheWrite: 1.25 },21 'claude-haiku-4-5': { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 },22 'claude-fable-5-1': { input: 10, output: 50, cacheRead: 0.1, cacheWrite: 1.25 },23 // OpenAI (approximate list prices; verify before relying on them)24 'gpt-5': { input: 1.25, output: 10, cacheRead: 0.1, cacheWrite: 1 },25 'gpt-5-mini': { input: 0.25, output: 2, cacheRead: 0.1, cacheWrite: 1 },26 'gpt-4o-mini': { input: 0.15, output: 0.6, cacheRead: 0.5, cacheWrite: 1 },27 'text-embedding-3-small': { input: 0.02, output: 0, cacheRead: 1, cacheWrite: 1 },28 'text-embedding-3-large': { input: 0.13, output: 0, cacheRead: 1, cacheWrite: 1 },29};3031/** Local/self-hosted models cost nothing at the API layer. */32export function priceFor(model: string): ModelPrice | null {33 if (PRICE_TABLE[model]) return PRICE_TABLE[model]!;34 const base = Object.keys(PRICE_TABLE).find((k) => model.startsWith(k));35 return base ? PRICE_TABLE[base]! : null;36}3738export function estimateUsd(model: string, usage: Usage): number {39 const p = priceFor(model);40 if (!p) return 0;41 const usd =42 (usage.inputTokens * p.input + usage.outputTokens * p.output + usage.cacheReadTokens * p.input * p.cacheRead + usage.cacheWriteTokens * p.input * p.cacheWrite) / 1_000_000;43 return Math.round(usd * 1e6) / 1e6;44}4546export const ZERO_USAGE: Usage = { inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0 };4748export function addUsage(a: Usage, b: Usage): Usage {49 return {50 inputTokens: a.inputTokens + b.inputTokens,51 outputTokens: a.outputTokens + b.outputTokens,52 cacheReadTokens: a.cacheReadTokens + b.cacheReadTokens,53 cacheWriteTokens: a.cacheWriteTokens + b.cacheWriteTokens,54 };55}56