import type { Usage } from './types.js'; /** * List prices in USD per 1M tokens (first-party API rates, cached 2026-06). Used only for the * cost ledger (ยง169); billing truth lives with the provider. Update when prices change. */ export interface ModelPrice { input: number; output: number; /** cache read multiplier vs input (Anthropic: 0.1) */ cacheRead: number; /** cache write multiplier vs input (Anthropic: 1.25) */ cacheWrite: number; } export const PRICE_TABLE: Record = { 'claude-opus-5': { input: 5, output: 25, cacheRead: 0.1, cacheWrite: 1.25 }, 'claude-opus-4-8': { input: 5, output: 25, cacheRead: 0.1, cacheWrite: 1.25 }, 'claude-sonnet-5': { input: 2, output: 10, cacheRead: 0.1, cacheWrite: 1.25 }, 'claude-sonnet-4-6': { input: 3, output: 15, cacheRead: 0.1, cacheWrite: 1.25 }, 'claude-haiku-4-5': { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, 'claude-fable-5-1': { input: 10, output: 50, cacheRead: 0.1, cacheWrite: 1.25 }, // OpenAI (approximate list prices; verify before relying on them) 'gpt-5': { input: 1.25, output: 10, cacheRead: 0.1, cacheWrite: 1 }, 'gpt-5-mini': { input: 0.25, output: 2, cacheRead: 0.1, cacheWrite: 1 }, 'gpt-4o-mini': { input: 0.15, output: 0.6, cacheRead: 0.5, cacheWrite: 1 }, 'text-embedding-3-small': { input: 0.02, output: 0, cacheRead: 1, cacheWrite: 1 }, 'text-embedding-3-large': { input: 0.13, output: 0, cacheRead: 1, cacheWrite: 1 }, }; /** Local/self-hosted models cost nothing at the API layer. */ export function priceFor(model: string): ModelPrice | null { if (PRICE_TABLE[model]) return PRICE_TABLE[model]!; const base = Object.keys(PRICE_TABLE).find((k) => model.startsWith(k)); return base ? PRICE_TABLE[base]! : null; } export function estimateUsd(model: string, usage: Usage): number { const p = priceFor(model); if (!p) return 0; const usd = (usage.inputTokens * p.input + usage.outputTokens * p.output + usage.cacheReadTokens * p.input * p.cacheRead + usage.cacheWriteTokens * p.input * p.cacheWrite) / 1_000_000; return Math.round(usd * 1e6) / 1e6; } export const ZERO_USAGE: Usage = { inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheWriteTokens: 0 }; export function addUsage(a: Usage, b: Usage): Usage { return { inputTokens: a.inputTokens + b.inputTokens, outputTokens: a.outputTokens + b.outputTokens, cacheReadTokens: a.cacheReadTokens + b.cacheReadTokens, cacheWriteTokens: a.cacheWriteTokens + b.cacheWriteTokens, }; }