@diogonzafe/tokenwatch 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +132 -6
- package/dist/adapters.d.cts +1 -1
- package/dist/adapters.d.ts +1 -1
- package/dist/cli.js +848 -8
- package/dist/cli.js.map +1 -1
- package/dist/exporters.cjs +76 -0
- package/dist/exporters.cjs.map +1 -0
- package/dist/exporters.d.cts +60 -0
- package/dist/exporters.d.ts +60 -0
- package/dist/exporters.js +56 -0
- package/dist/exporters.js.map +1 -0
- package/dist/{index-CJKk1hHw.d.cts → index-D9xq0RNg.d.cts} +19 -1
- package/dist/{index-CJKk1hHw.d.ts → index-D9xq0RNg.d.ts} +19 -1
- package/dist/index.cjs +63 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +63 -3
- package/dist/index.js.map +1 -1
- package/dist/langchain.d.cts +1 -1
- package/dist/langchain.d.ts +1 -1
- package/package.json +13 -3
- package/prices.json +1 -1
- package/dist/cli.d.ts +0 -1
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../bin/cli.ts","../src/core/sync.ts","../src/core/storage.ts","../src/core/tracker.ts","../src/core/pricing.ts","../src/core/suggestions.ts","../prices.json"],"sourcesContent":["#!/usr/bin/env node\nimport { readFileSync, existsSync } from 'node:fs'\nimport { join, dirname } from 'node:path'\nimport { homedir } from 'node:os'\nimport { fileURLToPath } from 'node:url'\nimport { fetchRemotePrices } from '../src/core/sync.js'\nimport { SqliteStorage } from '../src/core/storage.js'\nimport { createTracker } from '../src/core/tracker.js'\nimport type { PricesFile } from '../src/types/index.js'\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\nconst DB_PATH = join(homedir(), '.tokenwatch', 'usage.db')\n\nfunction loadBundledPrices(): PricesFile['models'] {\n const pricesPath = join(__dirname, '..', 'prices.json')\n const raw = readFileSync(pricesPath, 'utf8')\n const data = JSON.parse(raw) as PricesFile\n return data.models\n}\n\nasync function cmdSync(): Promise<void> {\n console.log('Fetching latest prices from remote...')\n const result = await fetchRemotePrices()\n if (result) {\n console.log(`✓ Prices updated. ${Object.keys(result.models).length} models cached (updated_at: ${result.updated_at}).`)\n } else {\n console.error('✗ Failed to fetch remote prices. Check your internet connection.')\n process.exit(1)\n }\n}\n\nfunction cmdPrices(): void {\n const models = loadBundledPrices()\n const rows = Object.entries(models).map(([name, price]) => ({\n model: name,\n input: `$${price.input.toFixed(2)}/M`,\n output: `$${price.output.toFixed(2)}/M`,\n }))\n\n const maxName = Math.max(...rows.map((r) => r.model.length), 5)\n const header = `${'Model'.padEnd(maxName)} ${'Input'.padStart(12)} ${'Output'.padStart(12)}`\n const sep = '-'.repeat(header.length)\n\n console.log(header)\n console.log(sep)\n for (const row of rows) {\n console.log(`${row.model.padEnd(maxName)} ${row.input.padStart(12)} ${row.output.padStart(12)}`)\n }\n}\n\nasync function cmdReport(): Promise<void> {\n if (!existsSync(DB_PATH)) {\n console.log(`No SQLite database found at ${DB_PATH}`)\n console.log('Start your app with storage: \\'sqlite\\' to begin recording usage.')\n return\n }\n\n let storage: SqliteStorage\n try {\n storage = new SqliteStorage(DB_PATH)\n } catch {\n console.error('Failed to open SQLite database. Is better-sqlite3 installed?')\n console.error('Run: npm install better-sqlite3')\n process.exit(1)\n }\n\n const tracker = createTracker({ storage, syncPrices: false })\n const report = await tracker.getReport()\n\n if (report.totalCostUSD === 0 && Object.keys(report.byModel).length === 0) {\n console.log('No usage recorded yet.')\n return\n }\n\n console.log('\\n── tokenwatch report ──────────────────────────────')\n console.log(` Total cost: $${report.totalCostUSD.toFixed(6)} USD`)\n console.log(` Total tokens: ${report.totalTokens.input.toLocaleString()} in / ${report.totalTokens.output.toLocaleString()} out`)\n console.log(` Period: ${report.period.from} → ${report.period.to}`)\n if (report.pricesUpdatedAt) {\n console.log(` Prices as of: ${report.pricesUpdatedAt}`)\n }\n\n if (Object.keys(report.byModel).length > 0) {\n console.log('\\n By model:')\n for (const [model, stats] of Object.entries(report.byModel)) {\n console.log(` ${model.padEnd(30)} $${stats.costUSD.toFixed(6)} (${stats.calls} calls)`)\n }\n }\n\n if (Object.keys(report.byUser).length > 0) {\n console.log('\\n By user:')\n for (const [user, stats] of Object.entries(report.byUser)) {\n console.log(` ${user.padEnd(30)} $${stats.costUSD.toFixed(6)} (${stats.calls} calls)`)\n }\n }\n\n if (Object.keys(report.bySession).length > 0) {\n console.log('\\n By session:')\n for (const [session, stats] of Object.entries(report.bySession)) {\n console.log(` ${session.padEnd(30)} $${stats.costUSD.toFixed(6)} (${stats.calls} calls)`)\n }\n }\n\n if (Object.keys(report.byFeature).length > 0) {\n console.log('\\n By feature:')\n for (const [feature, stats] of Object.entries(report.byFeature)) {\n console.log(` ${feature.padEnd(30)} $${stats.costUSD.toFixed(6)} (${stats.calls} calls)`)\n }\n }\n\n console.log('───────────────────────────────────────────────────\\n')\n}\n\nfunction cmdHelp(): void {\n console.log(`\ntokenwatch — CLI\n\nCommands:\n sync Fetch and cache latest model prices from remote\n prices List all bundled models and their current prices\n report Show last saved usage report (requires SQLite storage)\n help Show this help message\n`.trim())\n}\n\nasync function main(): Promise<void> {\n const [, , cmd, ...args] = process.argv\n void args\n\n switch (cmd) {\n case 'sync':\n await cmdSync()\n break\n case 'prices':\n cmdPrices()\n break\n case 'report':\n await cmdReport()\n break\n case 'help':\n case undefined:\n cmdHelp()\n break\n default:\n console.error(`Unknown command: ${cmd}\\nRun \"tokenwatch help\" for usage.`)\n process.exit(1)\n }\n}\n\nmain().catch((err: unknown) => {\n console.error(err)\n process.exit(1)\n})\n","import { readFile, writeFile, mkdir } from 'node:fs/promises'\nimport { existsSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport type { PricesFile, PriceMap } from '../types/index.js'\n\nconst CACHE_DIR = join(homedir(), '.tokenwatch')\nconst CACHE_FILE = join(CACHE_DIR, 'prices.json')\nconst CACHE_TTL_MS = 24 * 60 * 60 * 1000 // 24 hours\nconst REMOTE_URL =\n 'https://raw.githubusercontent.com/diogonzafe/tokenwatch/main/prices.json'\n\nexport interface PricesResult {\n models: PriceMap\n updated_at: string\n}\n\nexport async function fetchRemotePrices(url = REMOTE_URL): Promise<PricesResult | null> {\n try {\n const res = await fetch(url, { signal: AbortSignal.timeout(8_000) })\n if (!res.ok) return null\n const data = (await res.json()) as PricesFile\n if (!data?.models) return null\n await persistCache(data)\n return { models: data.models, updated_at: data.updated_at ?? '' }\n } catch {\n return null\n }\n}\n\nexport async function loadCachedPrices(): Promise<PricesResult | null> {\n if (!existsSync(CACHE_FILE)) return null\n try {\n const raw = await readFile(CACHE_FILE, 'utf8')\n const data = JSON.parse(raw) as PricesFile & { _cachedAt?: number }\n const age = Date.now() - (data._cachedAt ?? 0)\n if (age > CACHE_TTL_MS) return null\n if (!data.models) return null\n return { models: data.models, updated_at: data.updated_at ?? '' }\n } catch {\n return null\n }\n}\n\nasync function persistCache(data: PricesFile): Promise<void> {\n try {\n await mkdir(CACHE_DIR, { recursive: true })\n const payload = { ...data, _cachedAt: Date.now() }\n await writeFile(CACHE_FILE, JSON.stringify(payload, null, 2), 'utf8')\n } catch {\n // best-effort — never throw\n }\n}\n\n/**\n * Returns the best available remote price result:\n * 1. Valid local cache (< 24h)\n * 2. Fresh remote fetch (also updates cache)\n * 3. null if both fail\n */\nexport async function getRemotePrices(): Promise<PricesResult | null> {\n const cached = await loadCachedPrices()\n if (cached) return cached\n return fetchRemotePrices()\n}\n","import { createRequire } from 'node:module'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport { mkdirSync } from 'node:fs'\nimport type { IStorage, UsageEntry } from '../types/index.js'\n\n// ─── Memory storage ───────────────────────────────────────────────────────────\n\nexport class MemoryStorage implements IStorage {\n private entries: UsageEntry[] = []\n\n record(entry: UsageEntry): void {\n this.entries.push(entry)\n }\n\n getAll(): UsageEntry[] {\n return [...this.entries]\n }\n\n clearAll(): void {\n this.entries = []\n }\n\n clearSession(sessionId: string): void {\n this.entries = this.entries.filter((e) => e.sessionId !== sessionId)\n }\n}\n\n// ─── SQLite storage ───────────────────────────────────────────────────────────\n\nconst DB_DIR = join(homedir(), '.tokenwatch')\nconst DB_PATH = join(DB_DIR, 'usage.db')\n\nexport class SqliteStorage implements IStorage {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private db: any\n\n constructor(dbPath = DB_PATH) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let BetterSqlite3: any\n try {\n // In CJS context globalThis.require is the native require; in ESM use createRequire.\n // This makes the lazy load work in both output formats produced by tsup.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const req: NodeRequire =\n typeof (globalThis as any).require === 'function'\n ? // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (globalThis as any).require\n : createRequire(import.meta.url)\n BetterSqlite3 = req('better-sqlite3')\n } catch {\n throw new Error(\n '[tokenwatch] SQLite storage requires better-sqlite3. ' +\n 'Run: npm install better-sqlite3',\n )\n }\n\n mkdirSync(DB_DIR, { recursive: true })\n this.db = new BetterSqlite3(dbPath)\n this.migrate()\n }\n\n private migrate(): void {\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS usage (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n model TEXT NOT NULL,\n input_tokens INTEGER NOT NULL,\n output_tokens INTEGER NOT NULL,\n reasoning_tokens INTEGER NOT NULL DEFAULT 0,\n cached_tokens INTEGER NOT NULL DEFAULT 0,\n cache_creation_tokens INTEGER NOT NULL DEFAULT 0,\n cost_usd REAL NOT NULL,\n session_id TEXT,\n user_id TEXT,\n feature TEXT,\n timestamp TEXT NOT NULL\n )\n `)\n // Incremental migrations for databases created before v0.2.0 / v0.3.0\n const cols = (this.db.prepare(`PRAGMA table_info(usage)`).all() as Array<{ name: string }>)\n .map((c) => c.name)\n if (!cols.includes('reasoning_tokens')) {\n this.db.exec(`ALTER TABLE usage ADD COLUMN reasoning_tokens INTEGER NOT NULL DEFAULT 0`)\n }\n if (!cols.includes('feature')) {\n this.db.exec(`ALTER TABLE usage ADD COLUMN feature TEXT`)\n }\n if (!cols.includes('cached_tokens')) {\n this.db.exec(`ALTER TABLE usage ADD COLUMN cached_tokens INTEGER NOT NULL DEFAULT 0`)\n }\n if (!cols.includes('cache_creation_tokens')) {\n this.db.exec(`ALTER TABLE usage ADD COLUMN cache_creation_tokens INTEGER NOT NULL DEFAULT 0`)\n }\n }\n\n record(entry: UsageEntry): void {\n this.db\n .prepare(\n `INSERT INTO usage\n (model, input_tokens, output_tokens, reasoning_tokens, cached_tokens, cache_creation_tokens,\n cost_usd, session_id, user_id, feature, timestamp)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n entry.model,\n entry.inputTokens,\n entry.outputTokens,\n entry.reasoningTokens ?? 0,\n entry.cachedTokens ?? 0,\n entry.cacheCreationTokens ?? 0,\n entry.costUSD,\n entry.sessionId ?? null,\n entry.userId ?? null,\n entry.feature ?? null,\n entry.timestamp,\n )\n }\n\n getAll(): UsageEntry[] {\n const rows = this.db.prepare('SELECT * FROM usage ORDER BY timestamp ASC').all() as Array<{\n model: string\n input_tokens: number\n output_tokens: number\n reasoning_tokens: number\n cached_tokens: number\n cache_creation_tokens: number\n cost_usd: number\n session_id: string | null\n user_id: string | null\n feature: string | null\n timestamp: string\n }>\n\n return rows.map((r) => ({\n model: r.model,\n inputTokens: r.input_tokens,\n outputTokens: r.output_tokens,\n ...(r.reasoning_tokens > 0 && { reasoningTokens: r.reasoning_tokens }),\n ...(r.cached_tokens > 0 && { cachedTokens: r.cached_tokens }),\n ...(r.cache_creation_tokens > 0 && { cacheCreationTokens: r.cache_creation_tokens }),\n costUSD: r.cost_usd,\n ...(r.session_id != null && { sessionId: r.session_id }),\n ...(r.user_id != null && { userId: r.user_id }),\n ...(r.feature != null && { feature: r.feature }),\n timestamp: r.timestamp,\n }))\n }\n\n clearAll(): void {\n this.db.exec('DELETE FROM usage')\n }\n\n clearSession(sessionId: string): void {\n this.db.prepare('DELETE FROM usage WHERE session_id = ?').run(sessionId)\n }\n}\n\n// ─── Factory ──────────────────────────────────────────────────────────────────\n\nexport function createStorage(type: 'memory' | 'sqlite'): IStorage {\n if (type === 'sqlite') return new SqliteStorage()\n return new MemoryStorage()\n}\n","import { z } from 'zod'\nimport type {\n Tracker,\n TrackerConfig,\n UsageEntry,\n Report,\n ReportOptions,\n CostForecast,\n ForecastOptions,\n ModelStats,\n SessionStats,\n UserStats,\n FeatureStats,\n ModelPrice,\n PriceMap,\n IStorage,\n BudgetConfig,\n} from '../types/index.js'\nimport { resolvePrice, findPrice, calculateCost } from './pricing.js'\nimport { maybeSuggestCheaperModel } from './suggestions.js'\nimport { createStorage } from './storage.js'\nimport { getRemotePrices } from './sync.js'\nimport bundledPricesFile from '../../prices.json' assert { type: 'json' }\n\nconst bundledPrices: PriceMap = bundledPricesFile.models as PriceMap\nconst bundledUpdatedAt: string = (bundledPricesFile as { updated_at?: string }).updated_at ?? ''\n\n// ─── Config validation schema ─────────────────────────────────────────────────\n\nconst ModelPriceSchema = z.object({\n input: z.number().nonnegative(),\n output: z.number().nonnegative(),\n cachedInput: z.number().nonnegative().optional(),\n cacheCreationInput: z.number().nonnegative().optional(),\n maxInputTokens: z.number().positive().optional(),\n})\n\nconst BudgetConfigSchema = z.object({\n threshold: z.number().positive(),\n webhookUrl: z.string().url(),\n mode: z.enum(['once', 'always']).optional().default('once'),\n})\n\n// storage can be a string enum or an IStorage instance — validated separately\nconst TrackerConfigSchema = z.object({\n storage: z.union([z.enum(['memory', 'sqlite']), z.custom<IStorage>((v) => {\n return (\n v !== null &&\n typeof v === 'object' &&\n typeof (v as IStorage).record === 'function' &&\n typeof (v as IStorage).getAll === 'function' &&\n typeof (v as IStorage).clearAll === 'function' &&\n typeof (v as IStorage).clearSession === 'function'\n )\n })]).optional().default('memory'),\n alertThreshold: z.number().positive().optional(),\n webhookUrl: z.string().url().optional(),\n syncPrices: z.boolean().optional().default(true),\n customPrices: z.record(z.string(), ModelPriceSchema).optional(),\n warnIfStaleAfterHours: z.number().nonnegative().optional().default(72),\n budgets: z.object({\n perUser: BudgetConfigSchema.optional(),\n perSession: BudgetConfigSchema.optional(),\n }).optional(),\n suggestions: z.boolean().optional().default(false),\n})\n\nexport function createTracker(config: TrackerConfig = {}): Tracker {\n const parsed = TrackerConfigSchema.safeParse(config)\n if (!parsed.success) {\n const issues = parsed.error.issues.map((i) => ` ${i.path.join('.')}: ${i.message}`).join('\\n')\n throw new Error(`[tokenwatch] Invalid config:\\n${issues}`)\n }\n\n const {\n storage: storageOption,\n alertThreshold,\n webhookUrl,\n syncPrices,\n customPrices,\n warnIfStaleAfterHours,\n budgets,\n suggestions,\n } = parsed.data\n\n const storage: IStorage =\n typeof storageOption === 'object'\n ? storageOption\n : createStorage(storageOption)\n\n // Fetch remote prices in the background — bundled prices are used as fallback\n // until the sync resolves. Negligible overhead added to createTracker().\n let remotePrices: PriceMap | undefined\n let pricesUpdatedAt: string = bundledUpdatedAt\n if (syncPrices) {\n getRemotePrices()\n .then((result) => {\n if (result) {\n remotePrices = result.models\n pricesUpdatedAt = result.updated_at\n }\n })\n .catch(() => {\n // best-effort — bundled prices remain in use\n })\n }\n\n // Warn if prices are stale (checked lazily on first access)\n let stalenessChecked = false\n function maybeWarnStaleness(): void {\n if (stalenessChecked || !warnIfStaleAfterHours) return\n stalenessChecked = true\n if (!pricesUpdatedAt) return\n try {\n const updatedMs = new Date(pricesUpdatedAt).getTime()\n const ageHours = (Date.now() - updatedMs) / (1000 * 60 * 60)\n if (ageHours > warnIfStaleAfterHours) {\n console.warn(\n `[tokenwatch] Price data is ${Math.round(ageHours)}h old (updated_at: ${pricesUpdatedAt}). ` +\n `Run \"tokenwatch sync\" to refresh, or set warnIfStaleAfterHours: 0 to suppress.`,\n )\n }\n } catch {\n // best-effort\n }\n }\n\n let alertFired = false\n const firedUserAlerts = new Set<string>()\n const firedSessionAlerts = new Set<string>()\n const startedAt = new Date().toISOString()\n\n function resolveModelPrice(model: string) {\n maybeWarnStaleness()\n return resolvePrice(model, {\n bundledPrices,\n ...(customPrices !== undefined && { customPrices: customPrices as PriceMap }),\n ...(remotePrices !== undefined && { remotePrices }),\n })\n }\n\n function track(entry: Omit<UsageEntry, 'costUSD' | 'timestamp'>): void {\n const price = resolveModelPrice(entry.model)\n const costUSD = calculateCost(\n entry.inputTokens,\n entry.outputTokens,\n price,\n entry.cachedTokens,\n entry.cacheCreationTokens,\n )\n const full: UsageEntry = {\n ...entry,\n costUSD,\n timestamp: new Date().toISOString(),\n }\n storage.record(full)\n maybeFireAlerts(full)\n if (suggestions) {\n maybeSuggestCheaperModel(entry.model, costUSD, entry.inputTokens, entry.outputTokens, {\n bundledPrices,\n ...(customPrices !== undefined && { customPrices: customPrices as PriceMap }),\n ...(remotePrices !== undefined && { remotePrices }),\n })\n }\n }\n\n function maybeFireAlerts(entry: UsageEntry): void {\n // Global threshold alert\n if (alertThreshold && webhookUrl && !alertFired) {\n alertFired = true\n Promise.resolve(storage.getAll()).then((entries) => {\n const total = computeTotal(entries)\n if (total < alertThreshold!) {\n alertFired = false\n return\n }\n fireWebhook(webhookUrl!, {\n text: `[tokenwatch] Alert: total cost reached $${total.toFixed(4)} USD (threshold: $${alertThreshold})`,\n })\n }).catch(() => {\n alertFired = false\n })\n }\n\n // Per-user budget alert\n if (budgets?.perUser && entry.userId) {\n const cfg = budgets.perUser\n const uid = entry.userId\n if (cfg.mode === 'always' || !firedUserAlerts.has(uid)) {\n // Claim the slot synchronously before going async — prevents double-fire\n if (cfg.mode !== 'always') firedUserAlerts.add(uid)\n Promise.resolve(storage.getAll()).then((entries) => {\n const userCost = entries\n .filter((e) => e.userId === uid)\n .reduce((s, e) => s + e.costUSD, 0)\n if (userCost >= cfg.threshold) {\n fireWebhook(cfg.webhookUrl, {\n text: `[tokenwatch] Budget alert: user \"${uid}\" reached $${userCost.toFixed(4)} USD (threshold: $${cfg.threshold})`,\n })\n } else {\n if (cfg.mode !== 'always') firedUserAlerts.delete(uid) // release — threshold not yet met\n }\n }).catch(() => {\n if (cfg.mode !== 'always') firedUserAlerts.delete(uid) // release on storage error\n })\n }\n }\n\n // Per-session budget alert\n if (budgets?.perSession && entry.sessionId) {\n const cfg = budgets.perSession\n const sid = entry.sessionId\n if (cfg.mode === 'always' || !firedSessionAlerts.has(sid)) {\n // Claim the slot synchronously before going async — prevents double-fire\n if (cfg.mode !== 'always') firedSessionAlerts.add(sid)\n Promise.resolve(storage.getAll()).then((entries) => {\n const sessionCost = entries\n .filter((e) => e.sessionId === sid)\n .reduce((s, e) => s + e.costUSD, 0)\n if (sessionCost >= cfg.threshold) {\n fireWebhook(cfg.webhookUrl, {\n text: `[tokenwatch] Budget alert: session \"${sid}\" reached $${sessionCost.toFixed(4)} USD (threshold: $${cfg.threshold})`,\n })\n } else {\n if (cfg.mode !== 'always') firedSessionAlerts.delete(sid) // release\n }\n }).catch(() => {\n if (cfg.mode !== 'always') firedSessionAlerts.delete(sid) // release on storage error\n })\n }\n }\n }\n\n function fireWebhook(url: string, payload: { text: string }): void {\n fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n }).catch(() => {\n // fire-and-forget\n })\n }\n\n async function getReport(options?: ReportOptions): Promise<Report> {\n const allEntries = await Promise.resolve(storage.getAll())\n const entries = filterEntries(allEntries, options)\n\n const byModel: Record<string, ModelStats> = {}\n const bySession: Record<string, SessionStats> = {}\n const byUser: Record<string, UserStats> = {}\n const byFeature: Record<string, FeatureStats> = {}\n\n let totalInput = 0\n let totalOutput = 0\n let totalCost = 0\n let periodFrom = options ? (entries[0]?.timestamp ?? startedAt) : startedAt\n let lastTimestamp = periodFrom\n\n for (const e of entries) {\n totalInput += e.inputTokens + (e.cachedTokens ?? 0) + (e.cacheCreationTokens ?? 0)\n totalOutput += e.outputTokens\n totalCost += e.costUSD\n if (e.timestamp > lastTimestamp) lastTimestamp = e.timestamp\n\n // byModel\n const m = (byModel[e.model] ??= {\n costUSD: 0,\n calls: 0,\n tokens: { input: 0, output: 0, reasoning: 0, cached: 0 },\n })\n m.costUSD += e.costUSD\n m.calls += 1\n m.tokens.input += e.inputTokens + (e.cachedTokens ?? 0) + (e.cacheCreationTokens ?? 0)\n m.tokens.output += e.outputTokens\n m.tokens.reasoning += e.reasoningTokens ?? 0\n m.tokens.cached += e.cachedTokens ?? 0\n\n // bySession\n if (e.sessionId) {\n const s = (bySession[e.sessionId] ??= { costUSD: 0, calls: 0 })\n s.costUSD += e.costUSD\n s.calls += 1\n }\n\n // byUser\n if (e.userId) {\n const u = (byUser[e.userId] ??= { costUSD: 0, calls: 0 })\n u.costUSD += e.costUSD\n u.calls += 1\n }\n\n // byFeature\n if (e.feature) {\n const f = (byFeature[e.feature] ??= { costUSD: 0, calls: 0 })\n f.costUSD += e.costUSD\n f.calls += 1\n }\n }\n\n // When filtering, use the actual first entry's timestamp as period.from\n if (options && entries.length > 0) {\n periodFrom = entries[0]?.timestamp ?? periodFrom\n }\n\n return {\n totalCostUSD: totalCost,\n totalTokens: { input: totalInput, output: totalOutput },\n byModel,\n bySession,\n byUser,\n byFeature,\n period: { from: periodFrom, to: lastTimestamp },\n ...(pricesUpdatedAt ? { pricesUpdatedAt } : {}),\n }\n }\n\n async function getCostForecast(options: ForecastOptions = {}): Promise<CostForecast> {\n const windowHours = options.windowHours ?? 24\n const allEntries = await Promise.resolve(storage.getAll())\n\n const now = Date.now()\n const windowStart = now - windowHours * 60 * 60 * 1000\n const windowEntries = allEntries.filter(\n (e) => new Date(e.timestamp).getTime() >= windowStart,\n )\n\n if (windowEntries.length < 2) {\n return {\n burnRatePerHour: 0,\n projectedDailyCostUSD: 0,\n projectedMonthlyCostUSD: 0,\n basedOnHours: 0,\n basedOnPeriod: null,\n }\n }\n\n const first = windowEntries[0]?.timestamp ?? ''\n const last = windowEntries[windowEntries.length - 1]?.timestamp ?? ''\n const actualMs = new Date(last).getTime() - new Date(first).getTime()\n const actualHours = actualMs / (1000 * 60 * 60)\n\n if (actualHours < 0.001) {\n return {\n burnRatePerHour: 0,\n projectedDailyCostUSD: 0,\n projectedMonthlyCostUSD: 0,\n basedOnHours: 0,\n basedOnPeriod: { from: first, to: last },\n }\n }\n\n const totalCost = windowEntries.reduce((s, e) => s + e.costUSD, 0)\n const burnRatePerHour = totalCost / actualHours\n\n return {\n burnRatePerHour,\n projectedDailyCostUSD: burnRatePerHour * 24,\n projectedMonthlyCostUSD: burnRatePerHour * 24 * 30,\n basedOnHours: Math.round(actualHours * 100) / 100,\n basedOnPeriod: { from: first, to: last },\n }\n }\n\n async function reset(): Promise<void> {\n await Promise.resolve(storage.clearAll())\n alertFired = false\n firedUserAlerts.clear()\n firedSessionAlerts.clear()\n }\n\n async function resetSession(sessionId: string): Promise<void> {\n await Promise.resolve(storage.clearSession(sessionId))\n firedSessionAlerts.delete(sessionId)\n }\n\n async function exportJSON(): Promise<string> {\n return JSON.stringify(await getReport(), null, 2)\n }\n\n async function exportCSV(): Promise<string> {\n const entries = await Promise.resolve(storage.getAll())\n const header =\n 'timestamp,model,inputTokens,outputTokens,reasoningTokens,cachedTokens,cacheCreationTokens,costUSD,sessionId,userId,feature'\n const rows = entries.map((e) =>\n [\n csvEscape(e.timestamp),\n csvEscape(e.model),\n e.inputTokens,\n e.outputTokens,\n e.reasoningTokens ?? 0,\n e.cachedTokens ?? 0,\n e.cacheCreationTokens ?? 0,\n e.costUSD.toFixed(8),\n csvEscape(e.sessionId ?? ''),\n csvEscape(e.userId ?? ''),\n csvEscape(e.feature ?? ''),\n ].join(','),\n )\n return [header, ...rows].join('\\n')\n }\n\n function getModelInfo(model: string): ModelPrice | null {\n return findPrice(model, {\n bundledPrices,\n ...(customPrices !== undefined && { customPrices: customPrices as PriceMap }),\n ...(remotePrices !== undefined && { remotePrices }),\n }) ?? null\n }\n\n return {\n track,\n getReport,\n getCostForecast,\n reset,\n resetSession,\n exportJSON,\n exportCSV,\n getModelInfo,\n }\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction computeTotal(entries: UsageEntry[]): number {\n return entries.reduce((sum, e) => sum + e.costUSD, 0)\n}\n\n/** Parse a 'last' shorthand like '24h', '7d' into milliseconds */\nfunction parseLastMs(last: string): number {\n const match = /^(\\d+(?:\\.\\d+)?)(h|d)$/.exec(last.trim())\n if (!match) throw new Error(`[tokenwatch] Invalid \"last\" value: \"${last}\". Use e.g. \"24h\", \"7d\".`)\n const value = parseFloat(match[1] ?? '0')\n const unit = match[2] ?? 'h'\n return unit === 'h' ? value * 60 * 60 * 1000 : value * 24 * 60 * 60 * 1000\n}\n\nfunction filterEntries(entries: UsageEntry[], options?: ReportOptions): UsageEntry[] {\n if (!options) return entries\n\n let sinceMs: number | undefined\n let untilMs: number | undefined\n\n if (options.last) {\n sinceMs = Date.now() - parseLastMs(options.last)\n } else if (options.since) {\n sinceMs = new Date(options.since).getTime()\n }\n if (options.until) {\n untilMs = new Date(options.until).getTime()\n }\n\n if (sinceMs === undefined && untilMs === undefined) return entries\n\n return entries.filter((e) => {\n const ts = new Date(e.timestamp).getTime()\n if (sinceMs !== undefined && ts < sinceMs) return false\n if (untilMs !== undefined && ts > untilMs) return false\n return true\n })\n}\n\n/** Wrap a CSV field value in double-quotes if it contains commas, quotes, or newlines. */\nfunction csvEscape(value: string): string {\n if (value.includes(',') || value.includes('\"') || value.includes('\\n')) {\n return `\"${value.replace(/\"/g, '\"\"')}\"`\n }\n return value\n}\n","import type { ModelPrice, PriceMap } from '../types/index.js'\n\n/**\n * Resolve price for a model using 3-layer priority:\n * 1. customPrices (user override)\n * 2. remotePrices (synced from GitHub, cached 24h)\n * 3. bundledPrices (always-present fallback)\n *\n * Falls back to zero-cost with a console warning when model is not found anywhere.\n */\nexport function resolvePrice(\n model: string,\n layers: {\n customPrices?: PriceMap\n remotePrices?: PriceMap\n bundledPrices: PriceMap\n },\n): ModelPrice {\n const { customPrices, remotePrices, bundledPrices } = layers\n\n const found =\n lookupInMap(model, customPrices) ??\n lookupInMap(model, remotePrices) ??\n lookupInMap(model, bundledPrices)\n\n if (found) return found\n\n console.warn(\n `[tokenwatch] Unknown model \"${model}\". Cost will be recorded as $0. ` +\n `Add it via customPrices or update prices with: tokenwatch sync`,\n )\n return { input: 0, output: 0 }\n}\n\n/**\n * Find price for a model without the zero-cost fallback.\n * Returns undefined if the model is not found in any layer.\n */\nexport function findPrice(\n model: string,\n layers: {\n customPrices?: PriceMap\n remotePrices?: PriceMap\n bundledPrices: PriceMap\n },\n): ModelPrice | undefined {\n const { customPrices, remotePrices, bundledPrices } = layers\n return (\n lookupInMap(model, customPrices) ??\n lookupInMap(model, remotePrices) ??\n lookupInMap(model, bundledPrices)\n )\n}\n\n/**\n * Look up a model in a PriceMap using:\n * 1. exact key match\n * 2. prefix match — map key is a prefix of the model string (e.g. \"gpt-4o\" matches \"gpt-4o-2024-11-20\")\n * 3. reverse prefix — model string is a prefix of a map key (unusual, safety net)\n */\nfunction lookupInMap(model: string, map: PriceMap | undefined): ModelPrice | undefined {\n if (!map) return undefined\n\n if (model in map) return map[model]\n\n // prefix match\n for (const key of Object.keys(map)) {\n if (model.startsWith(key) || key.startsWith(model)) {\n return map[key]\n }\n }\n\n return undefined\n}\n\n/**\n * Calculate cost in USD given token counts and per-million-token prices.\n *\n * - `inputTokens` — regular (non-cached) input tokens\n * - `outputTokens` — output tokens (includes reasoning tokens for OpenAI, which are billed as output)\n * - `cachedTokens` — cache-read input tokens (billed at price.cachedInput or full input price if absent)\n * - `cacheCreationTokens` — cache-creation input tokens, Anthropic only (billed at price.cacheCreationInput\n * or 1.25× input price if absent)\n */\nexport function calculateCost(\n inputTokens: number,\n outputTokens: number,\n price: ModelPrice,\n cachedTokens = 0,\n cacheCreationTokens = 0,\n): number {\n const regularInputCost = (inputTokens / 1_000_000) * price.input\n const cachedReadCost = (cachedTokens / 1_000_000) * (price.cachedInput ?? price.input)\n const cacheCreationCost =\n (cacheCreationTokens / 1_000_000) * (price.cacheCreationInput ?? price.input * 1.25)\n const outputCost = (outputTokens / 1_000_000) * price.output\n return regularInputCost + cachedReadCost + cacheCreationCost + outputCost\n}\n","import type { PriceMap } from '../types/index.js'\nimport { calculateCost } from './pricing.js'\n\nconst PROVIDER_PREFIXES = ['gpt-', 'claude-', 'gemini-', 'deepseek-'] as const\n\nfunction getProviderPrefix(model: string): string | undefined {\n return PROVIDER_PREFIXES.find((p) => model.startsWith(p))\n}\n\n/**\n * After a tracked call, check if there is a cheaper model in the same provider family\n * (defined by model name prefix). Logs a hint if savings are strictly greater than 50%.\n * No-ops if the model is unknown, costUSD is zero, or no cheaper candidate is found.\n */\nexport function maybeSuggestCheaperModel(\n model: string,\n costUSD: number,\n inputTokens: number,\n outputTokens: number,\n layers: { bundledPrices: PriceMap; customPrices?: PriceMap; remotePrices?: PriceMap },\n): void {\n if (costUSD <= 0) return\n\n const prefix = getProviderPrefix(model)\n if (!prefix) return\n\n // Merge layers: bundled < remote < custom (custom wins)\n const mergedMap: PriceMap = {\n ...layers.bundledPrices,\n ...(layers.remotePrices ?? {}),\n ...(layers.customPrices ?? {}),\n }\n\n let cheapestModel: string | undefined\n let cheapestCost = Infinity\n\n for (const key of Object.keys(mergedMap)) {\n if (key === model || !key.startsWith(prefix)) continue\n const price = mergedMap[key]\n if (!price) continue\n const candidateCost = calculateCost(inputTokens, outputTokens, price)\n if (candidateCost < cheapestCost) {\n cheapestCost = candidateCost\n cheapestModel = key\n }\n }\n\n // Must be strictly more than 50% cheaper\n if (cheapestModel === undefined || cheapestCost >= costUSD * 0.5) return\n\n const savingsPct = Math.round((1 - cheapestCost / costUSD) * 100)\n console.log(\n `[tokenwatch] Suggestion: ${cheapestModel} could handle this for ~$${cheapestCost.toFixed(4)} (${savingsPct}% cheaper than ${model})`,\n )\n}\n","{\n \"updated_at\": \"2026-04-22\",\n \"source\": \"https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json\",\n \"models\": {\n \"gpt-4o\": {\n \"input\": 2.5,\n \"output\": 10,\n \"cachedInput\": 1.25,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-mini\": {\n \"input\": 0.15,\n \"output\": 0.6,\n \"cachedInput\": 0.075,\n \"maxInputTokens\": 128000\n },\n \"gpt-5\": {\n \"input\": 1.25,\n \"output\": 10,\n \"cachedInput\": 0.125,\n \"maxInputTokens\": 272000\n },\n \"gpt-5-mini\": {\n \"input\": 0.25,\n \"output\": 2,\n \"cachedInput\": 0.025,\n \"maxInputTokens\": 272000\n },\n \"gpt-5-nano\": {\n \"input\": 0.05,\n \"output\": 0.4,\n \"cachedInput\": 0.005,\n \"maxInputTokens\": 272000\n },\n \"claude-opus-4-6\": {\n \"input\": 5,\n \"output\": 25,\n \"cachedInput\": 0.5,\n \"cacheCreationInput\": 6.25,\n \"maxInputTokens\": 1000000\n },\n \"claude-sonnet-4-6\": {\n \"input\": 3,\n \"output\": 15,\n \"cachedInput\": 0.3,\n \"cacheCreationInput\": 3.75,\n \"maxInputTokens\": 1000000\n },\n \"claude-haiku-4-5\": {\n \"input\": 1,\n \"output\": 5,\n \"cachedInput\": 0.1,\n \"cacheCreationInput\": 1.25,\n \"maxInputTokens\": 200000\n },\n \"gemini-2.5-pro\": {\n \"input\": 1.25,\n \"output\": 10,\n \"cachedInput\": 0.125,\n \"maxInputTokens\": 1048576\n },\n \"gemini-2.5-flash\": {\n \"input\": 0.3,\n \"output\": 2.5,\n \"cachedInput\": 0.03,\n \"maxInputTokens\": 1048576\n },\n \"deepseek-chat\": {\n \"input\": 0.28,\n \"output\": 0.42,\n \"cachedInput\": 0.028,\n \"maxInputTokens\": 131072\n },\n \"deepseek-reasoner\": {\n \"input\": 0.28,\n \"output\": 0.42,\n \"cachedInput\": 0.028,\n \"maxInputTokens\": 131072\n },\n \"claude-opus-4-5\": {\n \"input\": 5,\n \"output\": 25,\n \"cachedInput\": 0.5,\n \"cacheCreationInput\": 6.25,\n \"maxInputTokens\": 200000\n },\n \"claude-opus-4-7\": {\n \"input\": 5,\n \"output\": 25,\n \"cachedInput\": 0.5,\n \"cacheCreationInput\": 6.25,\n \"maxInputTokens\": 1000000\n },\n \"claude-opus-4-1\": {\n \"input\": 15,\n \"output\": 75,\n \"cachedInput\": 1.5,\n \"cacheCreationInput\": 18.75,\n \"maxInputTokens\": 200000\n },\n \"claude-sonnet-4-5\": {\n \"input\": 3,\n \"output\": 15,\n \"cachedInput\": 0.3,\n \"cacheCreationInput\": 3.75,\n \"maxInputTokens\": 200000\n },\n \"gpt-oss-120b\": {\n \"input\": 3,\n \"output\": 4.5,\n \"maxInputTokens\": 131072\n },\n \"gpt-3.5-turbo\": {\n \"input\": 0.5,\n \"output\": 1.5,\n \"maxInputTokens\": 16385\n },\n \"gpt-3.5-turbo-0125\": {\n \"input\": 0.5,\n \"output\": 1.5,\n \"maxInputTokens\": 16385\n },\n \"gpt-35-turbo\": {\n \"input\": 0.5,\n \"output\": 1.5,\n \"maxInputTokens\": 4097\n },\n \"gpt-35-turbo-0125\": {\n \"input\": 0.5,\n \"output\": 1.5,\n \"maxInputTokens\": 16384\n },\n \"gpt-35-turbo-1106\": {\n \"input\": 1,\n \"output\": 2,\n \"maxInputTokens\": 16384\n },\n \"gpt-35-turbo-16k\": {\n \"input\": 3,\n \"output\": 4,\n \"maxInputTokens\": 16385\n },\n \"gpt-35-turbo-16k-0613\": {\n \"input\": 3,\n \"output\": 4,\n \"maxInputTokens\": 16385\n },\n \"gpt-4\": {\n \"input\": 30,\n \"output\": 60,\n \"maxInputTokens\": 8192\n },\n \"gpt-4-0125-preview\": {\n \"input\": 10,\n \"output\": 30,\n \"maxInputTokens\": 128000\n },\n \"gpt-4-0613\": {\n \"input\": 30,\n \"output\": 60,\n \"maxInputTokens\": 8192\n },\n \"gpt-4-1106-preview\": {\n \"input\": 10,\n \"output\": 30,\n \"maxInputTokens\": 128000\n },\n \"gpt-4-32k\": {\n \"input\": 60,\n \"output\": 120,\n \"maxInputTokens\": 32768\n },\n \"gpt-4-32k-0613\": {\n \"input\": 60,\n \"output\": 120,\n \"maxInputTokens\": 32768\n },\n \"gpt-4-turbo\": {\n \"input\": 10,\n \"output\": 30,\n \"maxInputTokens\": 128000\n },\n \"gpt-4-turbo-2024-04-09\": {\n \"input\": 10,\n \"output\": 30,\n \"maxInputTokens\": 128000\n },\n \"gpt-4-turbo-vision-preview\": {\n \"input\": 10,\n \"output\": 30,\n \"maxInputTokens\": 128000\n },\n \"gpt-4.1\": {\n \"input\": 2,\n \"output\": 8,\n \"cachedInput\": 0.5,\n \"maxInputTokens\": 1047576\n },\n \"gpt-4.1-2025-04-14\": {\n \"input\": 2,\n \"output\": 8,\n \"cachedInput\": 0.5,\n \"maxInputTokens\": 1047576\n },\n \"gpt-4.1-mini\": {\n \"input\": 0.4,\n \"output\": 1.6,\n \"cachedInput\": 0.1,\n \"maxInputTokens\": 1047576\n },\n \"gpt-4.1-mini-2025-04-14\": {\n \"input\": 0.4,\n \"output\": 1.6,\n \"cachedInput\": 0.1,\n \"maxInputTokens\": 1047576\n },\n \"gpt-4.1-nano\": {\n \"input\": 0.1,\n \"output\": 0.4,\n \"cachedInput\": 0.025,\n \"maxInputTokens\": 1047576\n },\n \"gpt-4.1-nano-2025-04-14\": {\n \"input\": 0.1,\n \"output\": 0.4,\n \"cachedInput\": 0.025,\n \"maxInputTokens\": 1047576\n },\n \"gpt-4.5-preview\": {\n \"input\": 75,\n \"output\": 150,\n \"cachedInput\": 37.5,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-2024-05-13\": {\n \"input\": 5,\n \"output\": 15,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-2024-08-06\": {\n \"input\": 2.5,\n \"output\": 10,\n \"cachedInput\": 1.25,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-2024-11-20\": {\n \"input\": 2.5,\n \"output\": 10,\n \"cachedInput\": 1.25,\n \"maxInputTokens\": 128000\n },\n \"gpt-audio-2025-08-28\": {\n \"input\": 2.5,\n \"output\": 10,\n \"maxInputTokens\": 128000\n },\n \"gpt-audio-1.5-2026-02-23\": {\n \"input\": 2.5,\n \"output\": 10,\n \"maxInputTokens\": 128000\n },\n \"gpt-audio-mini-2025-10-06\": {\n \"input\": 0.6,\n \"output\": 2.4,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-audio-preview-2024-12-17\": {\n \"input\": 2.5,\n \"output\": 10,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-mini-2024-07-18\": {\n \"input\": 0.15,\n \"output\": 0.6,\n \"cachedInput\": 0.075,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-mini-audio-preview-2024-12-17\": {\n \"input\": 0.15,\n \"output\": 0.6,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-mini-realtime-preview-2024-12-17\": {\n \"input\": 0.6,\n \"output\": 2.4,\n \"cachedInput\": 0.3,\n \"maxInputTokens\": 128000\n },\n \"gpt-realtime-2025-08-28\": {\n \"input\": 4,\n \"output\": 16,\n \"cachedInput\": 0.4,\n \"maxInputTokens\": 32000\n },\n \"gpt-realtime-1.5-2026-02-23\": {\n \"input\": 4,\n \"output\": 16,\n \"cachedInput\": 4,\n \"maxInputTokens\": 32000\n },\n \"gpt-realtime-mini-2025-10-06\": {\n \"input\": 0.6,\n \"output\": 2.4,\n \"cachedInput\": 0.06,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-mini-transcribe\": {\n \"input\": 1.25,\n \"output\": 5,\n \"maxInputTokens\": 16000\n },\n \"gpt-4o-realtime-preview-2024-10-01\": {\n \"input\": 5,\n \"output\": 20,\n \"cachedInput\": 2.5,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-realtime-preview-2024-12-17\": {\n \"input\": 5,\n \"output\": 20,\n \"cachedInput\": 2.5,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-transcribe\": {\n \"input\": 2.5,\n \"output\": 10,\n \"maxInputTokens\": 16000\n },\n \"gpt-4o-transcribe-diarize\": {\n \"input\": 2.5,\n \"output\": 10,\n \"maxInputTokens\": 16000\n },\n \"gpt-5.1-2025-11-13\": {\n \"input\": 1.25,\n \"output\": 10,\n \"cachedInput\": 0.125,\n \"maxInputTokens\": 272000\n },\n \"gpt-5.1-chat-2025-11-13\": {\n \"input\": 1.25,\n \"output\": 10,\n \"cachedInput\": 0.125,\n \"maxInputTokens\": 128000\n },\n \"gpt-5.1-codex-2025-11-13\": {\n \"input\": 1.25,\n \"output\": 10,\n \"cachedInput\": 0.125,\n \"maxInputTokens\": 272000\n },\n \"gpt-5.1-codex-mini-2025-11-13\": {\n \"input\": 0.25,\n \"output\": 2,\n \"cachedInput\": 0.025,\n \"maxInputTokens\": 272000\n },\n \"gpt-5-2025-08-07\": {\n \"input\": 1.25,\n \"output\": 10,\n \"cachedInput\": 0.125,\n \"maxInputTokens\": 272000\n },\n \"gpt-5-chat\": {\n \"input\": 1.25,\n \"output\": 10,\n \"cachedInput\": 0.125,\n \"maxInputTokens\": 128000\n },\n \"gpt-5-chat-latest\": {\n \"input\": 1.25,\n \"output\": 10,\n \"cachedInput\": 0.125,\n \"maxInputTokens\": 128000\n },\n \"gpt-5-codex\": {\n \"input\": 1.25,\n \"output\": 10,\n \"cachedInput\": 0.125,\n \"maxInputTokens\": 272000\n },\n \"gpt-5-mini-2025-08-07\": {\n \"input\": 0.25,\n \"output\": 2,\n \"cachedInput\": 0.025,\n \"maxInputTokens\": 272000\n },\n \"gpt-5-nano-2025-08-07\": {\n \"input\": 0.05,\n \"output\": 0.4,\n \"cachedInput\": 0.005,\n \"maxInputTokens\": 272000\n },\n \"gpt-5-pro\": {\n \"input\": 15,\n \"output\": 120,\n \"maxInputTokens\": 128000\n },\n \"gpt-5.1\": {\n \"input\": 1.25,\n \"output\": 10,\n \"cachedInput\": 0.125,\n \"maxInputTokens\": 272000\n },\n \"gpt-5.1-chat\": {\n \"input\": 1.25,\n \"output\": 10,\n \"cachedInput\": 0.125,\n \"maxInputTokens\": 128000\n },\n \"gpt-5.1-codex\": {\n \"input\": 1.25,\n \"output\": 10,\n \"cachedInput\": 0.125,\n \"maxInputTokens\": 272000\n },\n \"gpt-5.1-codex-max\": {\n \"input\": 1.25,\n \"output\": 10,\n \"cachedInput\": 0.125,\n \"maxInputTokens\": 272000\n },\n \"gpt-5.1-codex-mini\": {\n \"input\": 0.25,\n \"output\": 2,\n \"cachedInput\": 0.025,\n \"maxInputTokens\": 272000\n },\n \"gpt-5.2\": {\n \"input\": 1.75,\n \"output\": 14,\n \"cachedInput\": 0.175,\n \"maxInputTokens\": 272000\n },\n \"gpt-5.2-2025-12-11\": {\n \"input\": 1.75,\n \"output\": 14,\n \"cachedInput\": 0.175,\n \"maxInputTokens\": 272000\n },\n \"gpt-5.2-chat\": {\n \"input\": 1.75,\n \"output\": 14,\n \"cachedInput\": 0.175,\n \"maxInputTokens\": 128000\n },\n \"gpt-5.2-chat-2025-12-11\": {\n \"input\": 1.75,\n \"output\": 14,\n \"cachedInput\": 0.175,\n \"maxInputTokens\": 128000\n },\n \"gpt-5.2-codex\": {\n \"input\": 1.75,\n \"output\": 14,\n \"cachedInput\": 0.175,\n \"maxInputTokens\": 272000\n },\n \"gpt-5.3-chat\": {\n \"input\": 1.75,\n \"output\": 14,\n \"cachedInput\": 0.175,\n \"maxInputTokens\": 128000\n },\n \"gpt-5.3-codex\": {\n \"input\": 1.75,\n \"output\": 14,\n \"cachedInput\": 0.175,\n \"maxInputTokens\": 272000\n },\n \"gpt-5.2-pro\": {\n \"input\": 21,\n \"output\": 168,\n \"maxInputTokens\": 272000\n },\n \"gpt-5.2-pro-2025-12-11\": {\n \"input\": 21,\n \"output\": 168,\n \"maxInputTokens\": 272000\n },\n \"gpt-5.4\": {\n \"input\": 2.5,\n \"output\": 15,\n \"cachedInput\": 0.25,\n \"maxInputTokens\": 1050000\n },\n \"gpt-5.4-2026-03-05\": {\n \"input\": 2.5,\n \"output\": 15,\n \"cachedInput\": 0.25,\n \"maxInputTokens\": 1050000\n },\n \"gpt-5.4-pro\": {\n \"input\": 30,\n \"output\": 180,\n \"cachedInput\": 3,\n \"maxInputTokens\": 1050000\n },\n \"gpt-5.4-pro-2026-03-05\": {\n \"input\": 30,\n \"output\": 180,\n \"cachedInput\": 3,\n \"maxInputTokens\": 1050000\n },\n \"gpt-5.4-mini\": {\n \"input\": 0.75,\n \"output\": 4.5,\n \"cachedInput\": 0.075,\n \"maxInputTokens\": 272000\n },\n \"gpt-5.4-nano\": {\n \"input\": 0.2,\n \"output\": 1.25,\n \"cachedInput\": 0.02,\n \"maxInputTokens\": 272000\n },\n \"o1-2024-12-17\": {\n \"input\": 15,\n \"output\": 60,\n \"cachedInput\": 7.5,\n \"maxInputTokens\": 200000\n },\n \"o1-mini\": {\n \"input\": 1.21,\n \"output\": 4.84,\n \"cachedInput\": 0.605,\n \"maxInputTokens\": 128000\n },\n \"o1-mini-2024-09-12\": {\n \"input\": 1.1,\n \"output\": 4.4,\n \"cachedInput\": 0.55,\n \"maxInputTokens\": 128000\n },\n \"o1-preview\": {\n \"input\": 15,\n \"output\": 60,\n \"cachedInput\": 7.5,\n \"maxInputTokens\": 128000\n },\n \"o1-preview-2024-09-12\": {\n \"input\": 15,\n \"output\": 60,\n \"cachedInput\": 7.5,\n \"maxInputTokens\": 128000\n },\n \"o3-2025-04-16\": {\n \"input\": 2,\n \"output\": 8,\n \"cachedInput\": 0.5,\n \"maxInputTokens\": 200000\n },\n \"o3-mini\": {\n \"input\": 1.1,\n \"output\": 4.4,\n \"cachedInput\": 0.55,\n \"maxInputTokens\": 200000\n },\n \"o3-mini-2025-01-31\": {\n \"input\": 1.1,\n \"output\": 4.4,\n \"cachedInput\": 0.55,\n \"maxInputTokens\": 200000\n },\n \"o3-pro\": {\n \"input\": 20,\n \"output\": 80,\n \"maxInputTokens\": 200000\n },\n \"o3-pro-2025-06-10\": {\n \"input\": 20,\n \"output\": 80,\n \"maxInputTokens\": 200000\n },\n \"o4-mini\": {\n \"input\": 1.1,\n \"output\": 4.4,\n \"cachedInput\": 0.275,\n \"maxInputTokens\": 200000\n },\n \"o4-mini-2025-04-16\": {\n \"input\": 1.1,\n \"output\": 4.4,\n \"cachedInput\": 0.275,\n \"maxInputTokens\": 200000\n },\n \"deepseek-v3.2\": {\n \"input\": 0.28,\n \"output\": 0.4,\n \"maxInputTokens\": 163840\n },\n \"deepseek-v3.2-speciale\": {\n \"input\": 0.58,\n \"output\": 1.68,\n \"maxInputTokens\": 163840\n },\n \"deepseek-r1\": {\n \"input\": 0.55,\n \"output\": 2.19,\n \"maxInputTokens\": 65536\n },\n \"deepseek-v3\": {\n \"input\": 0.27,\n \"output\": 1.1,\n \"cachedInput\": 0.07,\n \"maxInputTokens\": 65536\n },\n \"deepseek-v3-0324\": {\n \"input\": 0.2,\n \"output\": 0.6,\n \"maxInputTokens\": 131072\n },\n \"chatgpt-4o-latest\": {\n \"input\": 5,\n \"output\": 15,\n \"maxInputTokens\": 128000\n },\n \"claude-haiku-4-5-20251001\": {\n \"input\": 1,\n \"output\": 5,\n \"cachedInput\": 0.1,\n \"cacheCreationInput\": 1.25,\n \"maxInputTokens\": 200000\n },\n \"claude-3-7-sonnet-20250219\": {\n \"input\": 3,\n \"output\": 15,\n \"cachedInput\": 0.3,\n \"cacheCreationInput\": 3.75,\n \"maxInputTokens\": 200000\n },\n \"claude-3-haiku-20240307\": {\n \"input\": 0.25,\n \"output\": 1.25,\n \"cachedInput\": 0.03,\n \"cacheCreationInput\": 0.3,\n \"maxInputTokens\": 200000\n },\n \"claude-3-opus-20240229\": {\n \"input\": 15,\n \"output\": 75,\n \"cachedInput\": 1.5,\n \"cacheCreationInput\": 18.75,\n \"maxInputTokens\": 200000\n },\n \"claude-4-opus-20250514\": {\n \"input\": 15,\n \"output\": 75,\n \"cachedInput\": 1.5,\n \"cacheCreationInput\": 18.75,\n \"maxInputTokens\": 200000\n },\n \"claude-4-sonnet-20250514\": {\n \"input\": 3,\n \"output\": 15,\n \"cachedInput\": 0.3,\n \"cacheCreationInput\": 3.75,\n \"maxInputTokens\": 1000000\n },\n \"claude-sonnet-4-5-20250929\": {\n \"input\": 3,\n \"output\": 15,\n \"cachedInput\": 0.3,\n \"cacheCreationInput\": 3.75,\n \"maxInputTokens\": 200000\n },\n \"claude-sonnet-4-5-20250929-v1:0\": {\n \"input\": 3,\n \"output\": 15,\n \"cachedInput\": 0.3,\n \"cacheCreationInput\": 3.75,\n \"maxInputTokens\": 200000\n },\n \"claude-opus-4-1-20250805\": {\n \"input\": 15,\n \"output\": 75,\n \"cachedInput\": 1.5,\n \"cacheCreationInput\": 18.75,\n \"maxInputTokens\": 200000\n },\n \"claude-opus-4-20250514\": {\n \"input\": 15,\n \"output\": 75,\n \"cachedInput\": 1.5,\n \"cacheCreationInput\": 18.75,\n \"maxInputTokens\": 200000\n },\n \"claude-opus-4-5-20251101\": {\n \"input\": 5,\n \"output\": 25,\n \"cachedInput\": 0.5,\n \"cacheCreationInput\": 6.25,\n \"maxInputTokens\": 200000\n },\n \"claude-opus-4-6-20260205\": {\n \"input\": 5,\n \"output\": 25,\n \"cachedInput\": 0.5,\n \"cacheCreationInput\": 6.25,\n \"maxInputTokens\": 1000000\n },\n \"claude-opus-4-7-20260416\": {\n \"input\": 5,\n \"output\": 25,\n \"cachedInput\": 0.5,\n \"cacheCreationInput\": 6.25,\n \"maxInputTokens\": 1000000\n },\n \"claude-sonnet-4-20250514\": {\n \"input\": 3,\n \"output\": 15,\n \"cachedInput\": 0.3,\n \"cacheCreationInput\": 3.75,\n \"maxInputTokens\": 1000000\n },\n \"codex-mini-latest\": {\n \"input\": 1.5,\n \"output\": 6,\n \"cachedInput\": 0.375,\n \"maxInputTokens\": 200000\n },\n \"deepseek-ai/deepseek-r1\": {\n \"input\": 3,\n \"output\": 7,\n \"maxInputTokens\": 128000\n },\n \"deepseek-ai/deepseek-r1-0528\": {\n \"input\": 135000,\n \"output\": 540000,\n \"maxInputTokens\": 161000\n },\n \"deepseek-ai/deepseek-r1-0528-turbo\": {\n \"input\": 1,\n \"output\": 3,\n \"maxInputTokens\": 32768\n },\n \"deepseek-ai/deepseek-r1-distill-llama-70b\": {\n \"input\": 0.25,\n \"output\": 0.75,\n \"maxInputTokens\": 128000\n },\n \"deepseek-ai/deepseek-r1-distill-qwen-32b\": {\n \"input\": 0.15,\n \"output\": 0.15\n },\n \"deepseek-ai/deepseek-r1-turbo\": {\n \"input\": 1,\n \"output\": 3,\n \"maxInputTokens\": 40960\n },\n \"deepseek-ai/deepseek-v3\": {\n \"input\": 1.25,\n \"output\": 1.25,\n \"maxInputTokens\": 65536\n },\n \"deepseek-ai/deepseek-v3-0324\": {\n \"input\": 114000,\n \"output\": 275000,\n \"maxInputTokens\": 161000\n },\n \"deepseek-ai/deepseek-v3.1\": {\n \"input\": 55000,\n \"output\": 165000,\n \"maxInputTokens\": 128000\n },\n \"deepseek-ai/deepseek-v3.1-terminus\": {\n \"input\": 0.27,\n \"output\": 1,\n \"cachedInput\": 0.216,\n \"maxInputTokens\": 163840\n },\n \"deepseek-coder\": {\n \"input\": 0.14,\n \"output\": 0.28,\n \"maxInputTokens\": 128000\n },\n \"gemini-2.0-flash\": {\n \"input\": 0.1,\n \"output\": 0.4,\n \"cachedInput\": 0.025,\n \"maxInputTokens\": 1048576\n },\n \"gemini-2.0-flash-001\": {\n \"input\": 0.1,\n \"output\": 0.4,\n \"cachedInput\": 0.025,\n \"maxInputTokens\": 1048576\n },\n \"gemini-2.0-flash-lite\": {\n \"input\": 0.075,\n \"output\": 0.3,\n \"cachedInput\": 0.01875,\n \"maxInputTokens\": 1048576\n },\n \"gemini-2.0-flash-lite-001\": {\n \"input\": 0.075,\n \"output\": 0.3,\n \"cachedInput\": 0.01875,\n \"maxInputTokens\": 1048576\n },\n \"gemini-2.5-flash-image\": {\n \"input\": 0.3,\n \"output\": 2.5,\n \"cachedInput\": 0.03,\n \"maxInputTokens\": 32768\n },\n \"gemini-3-pro-image-preview\": {\n \"input\": 2,\n \"output\": 12,\n \"maxInputTokens\": 65536\n },\n \"gemini-3.1-flash-image-preview\": {\n \"input\": 0.5,\n \"output\": 3,\n \"maxInputTokens\": 65536\n },\n \"gemini-3.1-flash-lite-preview\": {\n \"input\": 0.25,\n \"output\": 1.5,\n \"cachedInput\": 0.025,\n \"maxInputTokens\": 1048576\n },\n \"gemini-2.5-flash-lite\": {\n \"input\": 0.1,\n \"output\": 0.4,\n \"cachedInput\": 0.01,\n \"maxInputTokens\": 1048576\n },\n \"gemini-2.5-flash-lite-preview-09-2025\": {\n \"input\": 0.1,\n \"output\": 0.4,\n \"cachedInput\": 0.01,\n \"maxInputTokens\": 1048576\n },\n \"gemini-2.5-flash-preview-09-2025\": {\n \"input\": 0.3,\n \"output\": 2.5,\n \"cachedInput\": 0.075,\n \"maxInputTokens\": 1048576\n },\n \"gemini-live-2.5-flash-preview-native-audio-09-2025\": {\n \"input\": 0.3,\n \"output\": 2,\n \"cachedInput\": 0.075,\n \"maxInputTokens\": 1048576\n },\n \"gemini-2.5-flash-lite-preview-06-17\": {\n \"input\": 0.1,\n \"output\": 0.4,\n \"cachedInput\": 0.025,\n \"maxInputTokens\": 1048576\n },\n \"gemini-3-pro-preview\": {\n \"input\": 2,\n \"output\": 12,\n \"cachedInput\": 0.2,\n \"maxInputTokens\": 1048576\n },\n \"gemini-3.1-pro-preview\": {\n \"input\": 2,\n \"output\": 12,\n \"cachedInput\": 0.2,\n \"maxInputTokens\": 1048576\n },\n \"gemini-3.1-pro-preview-customtools\": {\n \"input\": 2,\n \"output\": 12,\n \"cachedInput\": 0.2,\n \"maxInputTokens\": 1048576\n },\n \"gemini-3-flash-preview\": {\n \"input\": 0.5,\n \"output\": 3,\n \"cachedInput\": 0.05,\n \"maxInputTokens\": 1048576\n },\n \"gemini-robotics-er-1.5-preview\": {\n \"input\": 0.3,\n \"output\": 2.5,\n \"maxInputTokens\": 1048576\n },\n \"gemini-2.5-computer-use-preview-10-2025\": {\n \"input\": 1.25,\n \"output\": 10,\n \"maxInputTokens\": 128000\n },\n \"gemini-flash-latest\": {\n \"input\": 0.3,\n \"output\": 2.5,\n \"cachedInput\": 0.03,\n \"maxInputTokens\": 1048576\n },\n \"gemini-flash-lite-latest\": {\n \"input\": 0.1,\n \"output\": 0.4,\n \"cachedInput\": 0.01,\n \"maxInputTokens\": 1048576\n },\n \"gemini-gemma-2-27b-it\": {\n \"input\": 0.35,\n \"output\": 1.05,\n \"maxInputTokens\": 8192\n },\n \"gemini-gemma-2-9b-it\": {\n \"input\": 0.35,\n \"output\": 1.05,\n \"maxInputTokens\": 8192\n },\n \"deepseek-ai/deepseek-v3.2\": {\n \"input\": 0.28,\n \"output\": 0.4,\n \"maxInputTokens\": 163840\n },\n \"gpt-3.5-turbo-1106\": {\n \"input\": 1,\n \"output\": 2,\n \"maxInputTokens\": 16385\n },\n \"gpt-3.5-turbo-16k\": {\n \"input\": 3,\n \"output\": 4,\n \"maxInputTokens\": 16385\n },\n \"gpt-4-0314\": {\n \"input\": 30,\n \"output\": 60,\n \"maxInputTokens\": 8192\n },\n \"gpt-4-turbo-preview\": {\n \"input\": 10,\n \"output\": 30,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-audio-preview\": {\n \"input\": 2.5,\n \"output\": 10,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-audio-preview-2025-06-03\": {\n \"input\": 2.5,\n \"output\": 10,\n \"maxInputTokens\": 128000\n },\n \"gpt-audio\": {\n \"input\": 2.5,\n \"output\": 10,\n \"maxInputTokens\": 128000\n },\n \"gpt-audio-1.5\": {\n \"input\": 2.5,\n \"output\": 10,\n \"maxInputTokens\": 128000\n },\n \"gpt-audio-mini\": {\n \"input\": 0.6,\n \"output\": 2.4,\n \"maxInputTokens\": 128000\n },\n \"gpt-audio-mini-2025-12-15\": {\n \"input\": 0.6,\n \"output\": 2.4,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-mini-audio-preview\": {\n \"input\": 0.15,\n \"output\": 0.6,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-mini-realtime-preview\": {\n \"input\": 0.6,\n \"output\": 2.4,\n \"cachedInput\": 0.3,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-realtime-preview\": {\n \"input\": 5,\n \"output\": 20,\n \"cachedInput\": 2.5,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-realtime-preview-2025-06-03\": {\n \"input\": 5,\n \"output\": 20,\n \"cachedInput\": 2.5,\n \"maxInputTokens\": 128000\n },\n \"gpt-image-1.5\": {\n \"input\": 5,\n \"output\": 10,\n \"cachedInput\": 1.25\n },\n \"gpt-image-1.5-2025-12-16\": {\n \"input\": 5,\n \"output\": 10,\n \"cachedInput\": 1.25\n },\n \"gpt-5.1-chat-latest\": {\n \"input\": 1.25,\n \"output\": 10,\n \"cachedInput\": 0.125,\n \"maxInputTokens\": 128000\n },\n \"gpt-5.2-chat-latest\": {\n \"input\": 1.75,\n \"output\": 14,\n \"cachedInput\": 0.175,\n \"maxInputTokens\": 128000\n },\n \"gpt-5.3-chat-latest\": {\n \"input\": 1.75,\n \"output\": 14,\n \"cachedInput\": 0.175,\n \"maxInputTokens\": 128000\n },\n \"gpt-5-pro-2025-10-06\": {\n \"input\": 15,\n \"output\": 120,\n \"maxInputTokens\": 128000\n },\n \"gpt-realtime\": {\n \"input\": 4,\n \"output\": 16,\n \"cachedInput\": 0.4,\n \"maxInputTokens\": 32000\n },\n \"gpt-realtime-1.5\": {\n \"input\": 4,\n \"output\": 16,\n \"cachedInput\": 0.4,\n \"maxInputTokens\": 32000\n },\n \"gpt-realtime-mini\": {\n \"input\": 0.6,\n \"output\": 2.4,\n \"maxInputTokens\": 128000\n },\n \"deepseek-r1-distill-llama-70b\": {\n \"input\": 0.99,\n \"output\": 0.99,\n \"maxInputTokens\": 8000\n },\n \"deepseek-llama3.3-70b\": {\n \"input\": 0.2,\n \"output\": 0.6,\n \"maxInputTokens\": 131072\n },\n \"deepseek-r1-0528\": {\n \"input\": 0.2,\n \"output\": 0.6,\n \"maxInputTokens\": 131072\n },\n \"deepseek-r1-671b\": {\n \"input\": 0.8,\n \"output\": 0.8,\n \"maxInputTokens\": 131072\n },\n \"deepseek-ai/deepseek-r1-distill-llama-8b\": {\n \"input\": 0.025,\n \"output\": 0.025\n },\n \"deepseek-ai/deepseek-r1-distill-qwen-1.5b\": {\n \"input\": 0.09,\n \"output\": 0.09\n },\n \"deepseek-ai/deepseek-r1-distill-qwen-14b\": {\n \"input\": 0.07,\n \"output\": 0.07\n },\n \"deepseek-ai/deepseek-r1-distill-qwen-7b\": {\n \"input\": 0.2,\n \"output\": 0.2\n },\n \"o1\": {\n \"input\": 15,\n \"output\": 60,\n \"cachedInput\": 7.5,\n \"maxInputTokens\": 200000\n },\n \"o1-pro\": {\n \"input\": 150,\n \"output\": 600,\n \"maxInputTokens\": 200000\n },\n \"o1-pro-2025-03-19\": {\n \"input\": 150,\n \"output\": 600,\n \"maxInputTokens\": 200000\n },\n \"o3\": {\n \"input\": 2,\n \"output\": 8,\n \"cachedInput\": 0.5,\n \"maxInputTokens\": 200000\n },\n \"gpt-oss-20b\": {\n \"input\": 0.09,\n \"output\": 0.36\n },\n \"deepseek-ai/deepseek-r1-0528-tput\": {\n \"input\": 0.55,\n \"output\": 2.19,\n \"maxInputTokens\": 128000\n },\n \"claude-3-5-haiku\": {\n \"input\": 1,\n \"output\": 5,\n \"maxInputTokens\": 200000\n },\n \"claude-3-5-haiku@20241022\": {\n \"input\": 1,\n \"output\": 5,\n \"maxInputTokens\": 200000\n },\n \"claude-haiku-4-5@20251001\": {\n \"input\": 1,\n \"output\": 5,\n \"cachedInput\": 0.1,\n \"cacheCreationInput\": 1.25,\n \"maxInputTokens\": 200000\n },\n \"claude-3-5-sonnet\": {\n \"input\": 3,\n \"output\": 15,\n \"maxInputTokens\": 200000\n },\n \"claude-3-5-sonnet@20240620\": {\n \"input\": 3,\n \"output\": 15,\n \"maxInputTokens\": 200000\n },\n \"claude-3-7-sonnet@20250219\": {\n \"input\": 3,\n \"output\": 15,\n \"cachedInput\": 0.3,\n \"cacheCreationInput\": 3.75,\n \"maxInputTokens\": 200000\n },\n \"claude-3-haiku\": {\n \"input\": 0.25,\n \"output\": 1.25,\n \"maxInputTokens\": 200000\n },\n \"claude-3-haiku@20240307\": {\n \"input\": 0.25,\n \"output\": 1.25,\n \"maxInputTokens\": 200000\n },\n \"claude-3-opus\": {\n \"input\": 15,\n \"output\": 75,\n \"maxInputTokens\": 200000\n },\n \"claude-3-opus@20240229\": {\n \"input\": 15,\n \"output\": 75,\n \"maxInputTokens\": 200000\n },\n \"claude-3-sonnet\": {\n \"input\": 3,\n \"output\": 15,\n \"maxInputTokens\": 200000\n },\n \"claude-3-sonnet@20240229\": {\n \"input\": 3,\n \"output\": 15,\n \"maxInputTokens\": 200000\n },\n \"claude-opus-4\": {\n \"input\": 15,\n \"output\": 75,\n \"cachedInput\": 1.5,\n \"cacheCreationInput\": 18.75,\n \"maxInputTokens\": 200000\n },\n \"claude-opus-4-1@20250805\": {\n \"input\": 15,\n \"output\": 75,\n \"cachedInput\": 1.5,\n \"cacheCreationInput\": 18.75,\n \"maxInputTokens\": 200000\n },\n \"claude-opus-4-5@20251101\": {\n \"input\": 5,\n \"output\": 25,\n \"cachedInput\": 0.5,\n \"cacheCreationInput\": 6.25,\n \"maxInputTokens\": 200000\n },\n \"claude-opus-4-6@default\": {\n \"input\": 5,\n \"output\": 25,\n \"cachedInput\": 0.5,\n \"cacheCreationInput\": 6.25,\n \"maxInputTokens\": 1000000\n },\n \"claude-opus-4-7@default\": {\n \"input\": 5,\n \"output\": 25,\n \"cachedInput\": 0.5,\n \"cacheCreationInput\": 6.25,\n \"maxInputTokens\": 1000000\n },\n \"claude-sonnet-4-5@20250929\": {\n \"input\": 3,\n \"output\": 15,\n \"cachedInput\": 0.3,\n \"cacheCreationInput\": 3.75,\n \"maxInputTokens\": 200000\n },\n \"claude-opus-4@20250514\": {\n \"input\": 15,\n \"output\": 75,\n \"cachedInput\": 1.5,\n \"cacheCreationInput\": 18.75,\n \"maxInputTokens\": 200000\n },\n \"claude-sonnet-4\": {\n \"input\": 3,\n \"output\": 15,\n \"cachedInput\": 0.3,\n \"cacheCreationInput\": 3.75,\n \"maxInputTokens\": 1000000\n },\n \"claude-sonnet-4@20250514\": {\n \"input\": 3,\n \"output\": 15,\n \"cachedInput\": 0.3,\n \"cacheCreationInput\": 3.75,\n \"maxInputTokens\": 1000000\n },\n \"deepseek-ai/deepseek-v3.1-maas\": {\n \"input\": 1.35,\n \"output\": 5.4,\n \"maxInputTokens\": 163840\n },\n \"deepseek-ai/deepseek-v3.2-maas\": {\n \"input\": 0.56,\n \"output\": 1.68,\n \"maxInputTokens\": 163840\n },\n \"deepseek-ai/deepseek-r1-0528-maas\": {\n \"input\": 1.35,\n \"output\": 5.4,\n \"maxInputTokens\": 65336\n },\n \"deepseek-ai/deepseek-ocr-maas\": {\n \"input\": 0.3,\n \"output\": 1.2\n },\n \"deepseek-r1-8b\": {\n \"input\": 0.1,\n \"output\": 0.2,\n \"maxInputTokens\": 65536\n },\n \"deepseek-r1-7b-qwen\": {\n \"input\": 0.08,\n \"output\": 0.15,\n \"maxInputTokens\": 131072\n },\n \"deepseek-coder-6.7b\": {\n \"input\": 0.06,\n \"output\": 0.12,\n \"maxInputTokens\": 16384\n },\n \"gpt-4o-mini-transcribe-2025-03-20\": {\n \"input\": 1.25,\n \"output\": 5,\n \"maxInputTokens\": 16000\n },\n \"gpt-4o-mini-transcribe-2025-12-15\": {\n \"input\": 1.25,\n \"output\": 5,\n \"maxInputTokens\": 16000\n },\n \"gpt-realtime-mini-2025-12-15\": {\n \"input\": 0.6,\n \"output\": 2.4,\n \"cachedInput\": 0.06,\n \"maxInputTokens\": 128000\n },\n \"gemini-2.5-flash-native-audio-latest\": {\n \"input\": 0.3,\n \"output\": 2.5,\n \"maxInputTokens\": 1048576\n },\n \"gemini-2.5-flash-native-audio-preview-09-2025\": {\n \"input\": 0.3,\n \"output\": 2.5,\n \"maxInputTokens\": 1048576\n },\n \"gemini-2.5-flash-native-audio-preview-12-2025\": {\n \"input\": 0.3,\n \"output\": 2.5,\n \"maxInputTokens\": 1048576\n },\n \"gemini-3.1-flash-live-preview\": {\n \"input\": 0.75,\n \"output\": 4.5,\n \"maxInputTokens\": 131072\n },\n \"gemini-pro-latest\": {\n \"input\": 1.25,\n \"output\": 10,\n \"cachedInput\": 0.125,\n \"maxInputTokens\": 1048576\n },\n \"gemini-exp-1206\": {\n \"input\": 0.3,\n \"output\": 2.5,\n \"cachedInput\": 0.03,\n \"maxInputTokens\": 1048576\n },\n \"claude-sonnet-4-6@default\": {\n \"input\": 3,\n \"output\": 15,\n \"cachedInput\": 0.3,\n \"cacheCreationInput\": 3.75,\n \"maxInputTokens\": 1000000\n }\n }\n}\n"],"mappings":"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","names":["existsSync","join","homedir","homedir","join","bundledPrices","DB_PATH","join","homedir","existsSync"]}
|
|
1
|
+
{"version":3,"sources":["../bin/cli.ts","../src/core/sync.ts","../src/core/storage.ts","../src/core/tracker.ts","../src/core/pricing.ts","../src/core/suggestions.ts","../prices.json","../src/dashboard/server.ts","../src/dashboard/data.ts","../src/dashboard/html.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { readFileSync, existsSync } from 'node:fs'\nimport { join, dirname } from 'node:path'\nimport { homedir } from 'node:os'\nimport { fileURLToPath } from 'node:url'\nimport { fetchRemotePrices } from '../src/core/sync.js'\nimport { SqliteStorage } from '../src/core/storage.js'\nimport { createTracker } from '../src/core/tracker.js'\nimport { startDashboardServer } from '../src/dashboard/server.js'\nimport type { PricesFile } from '../src/types/index.js'\n\nconst __dirname = dirname(fileURLToPath(import.meta.url))\nconst DB_PATH = join(homedir(), '.tokenwatch', 'usage.db')\n\nfunction loadBundledPrices(): PricesFile['models'] {\n const pricesPath = join(__dirname, '..', 'prices.json')\n const raw = readFileSync(pricesPath, 'utf8')\n const data = JSON.parse(raw) as PricesFile\n return data.models\n}\n\nasync function cmdSync(): Promise<void> {\n console.log('Fetching latest prices from remote...')\n const result = await fetchRemotePrices()\n if (result) {\n console.log(`✓ Prices updated. ${Object.keys(result.models).length} models cached (updated_at: ${result.updated_at}).`)\n } else {\n console.error('✗ Failed to fetch remote prices. Check your internet connection.')\n process.exit(1)\n }\n}\n\nfunction cmdPrices(): void {\n const models = loadBundledPrices()\n const rows = Object.entries(models).map(([name, price]) => ({\n model: name,\n input: `$${price.input.toFixed(2)}/M`,\n output: `$${price.output.toFixed(2)}/M`,\n }))\n\n const maxName = Math.max(...rows.map((r) => r.model.length), 5)\n const header = `${'Model'.padEnd(maxName)} ${'Input'.padStart(12)} ${'Output'.padStart(12)}`\n const sep = '-'.repeat(header.length)\n\n console.log(header)\n console.log(sep)\n for (const row of rows) {\n console.log(`${row.model.padEnd(maxName)} ${row.input.padStart(12)} ${row.output.padStart(12)}`)\n }\n}\n\nasync function cmdReport(): Promise<void> {\n if (!existsSync(DB_PATH)) {\n console.log(`No SQLite database found at ${DB_PATH}`)\n console.log('Start your app with storage: \\'sqlite\\' to begin recording usage.')\n return\n }\n\n let storage: SqliteStorage\n try {\n storage = new SqliteStorage(DB_PATH)\n } catch {\n console.error('Failed to open SQLite database. Is better-sqlite3 installed?')\n console.error('Run: npm install better-sqlite3')\n process.exit(1)\n }\n\n const tracker = createTracker({ storage, syncPrices: false })\n const report = await tracker.getReport()\n\n if (report.totalCostUSD === 0 && Object.keys(report.byModel).length === 0) {\n console.log('No usage recorded yet.')\n return\n }\n\n console.log('\\n── tokenwatch report ──────────────────────────────')\n console.log(` Total cost: $${report.totalCostUSD.toFixed(6)} USD`)\n console.log(` Total tokens: ${report.totalTokens.input.toLocaleString()} in / ${report.totalTokens.output.toLocaleString()} out`)\n console.log(` Period: ${report.period.from} → ${report.period.to}`)\n if (report.pricesUpdatedAt) {\n console.log(` Prices as of: ${report.pricesUpdatedAt}`)\n }\n\n if (Object.keys(report.byModel).length > 0) {\n console.log('\\n By model:')\n for (const [model, stats] of Object.entries(report.byModel)) {\n console.log(` ${model.padEnd(30)} $${stats.costUSD.toFixed(6)} (${stats.calls} calls)`)\n }\n }\n\n if (Object.keys(report.byUser).length > 0) {\n console.log('\\n By user:')\n for (const [user, stats] of Object.entries(report.byUser)) {\n console.log(` ${user.padEnd(30)} $${stats.costUSD.toFixed(6)} (${stats.calls} calls)`)\n }\n }\n\n if (Object.keys(report.bySession).length > 0) {\n console.log('\\n By session:')\n for (const [session, stats] of Object.entries(report.bySession)) {\n console.log(` ${session.padEnd(30)} $${stats.costUSD.toFixed(6)} (${stats.calls} calls)`)\n }\n }\n\n if (Object.keys(report.byFeature).length > 0) {\n console.log('\\n By feature:')\n for (const [feature, stats] of Object.entries(report.byFeature)) {\n console.log(` ${feature.padEnd(30)} $${stats.costUSD.toFixed(6)} (${stats.calls} calls)`)\n }\n }\n\n console.log('───────────────────────────────────────────────────\\n')\n}\n\nasync function cmdDashboard(port: number): Promise<void> {\n if (!existsSync(DB_PATH)) {\n console.log(`No SQLite database found at ${DB_PATH}`)\n console.log(\"Start your app with storage: 'sqlite' to begin recording usage.\")\n process.exit(1)\n }\n\n let storage: SqliteStorage\n try {\n storage = new SqliteStorage(DB_PATH)\n } catch {\n console.error('Failed to open SQLite database. Is better-sqlite3 installed?')\n console.error('Run: npm install better-sqlite3')\n process.exit(1)\n }\n\n startDashboardServer(storage, port)\n}\n\nfunction cmdHelp(): void {\n console.log(`\ntokenwatch — CLI\n\nCommands:\n sync Fetch and cache latest model prices from remote\n prices List all bundled models and their current prices\n report Show last saved usage report (requires SQLite storage)\n dashboard [--port N] Open local web dashboard (default port: 4242)\n help Show this help message\n`.trim())\n}\n\nasync function main(): Promise<void> {\n const [, , cmd, ...args] = process.argv\n\n switch (cmd) {\n case 'sync':\n await cmdSync()\n break\n case 'prices':\n cmdPrices()\n break\n case 'report':\n await cmdReport()\n break\n case 'dashboard': {\n const portFlagIdx = args.indexOf('--port')\n const port = portFlagIdx !== -1 ? parseInt(args[portFlagIdx + 1] ?? '4242', 10) : 4242\n await cmdDashboard(port)\n break\n }\n case 'help':\n case undefined:\n cmdHelp()\n break\n default:\n console.error(`Unknown command: ${cmd}\\nRun \"tokenwatch help\" for usage.`)\n process.exit(1)\n }\n}\n\nmain().catch((err: unknown) => {\n console.error(err)\n process.exit(1)\n})\n","import { readFile, writeFile, mkdir } from 'node:fs/promises'\nimport { existsSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport type { PricesFile, PriceMap } from '../types/index.js'\n\nconst CACHE_DIR = join(homedir(), '.tokenwatch')\nconst CACHE_FILE = join(CACHE_DIR, 'prices.json')\nconst CACHE_TTL_MS = 24 * 60 * 60 * 1000 // 24 hours\nconst REMOTE_URL =\n 'https://raw.githubusercontent.com/diogonzafe/tokenwatch/main/prices.json'\n\nexport interface PricesResult {\n models: PriceMap\n updated_at: string\n}\n\nexport async function fetchRemotePrices(url = REMOTE_URL): Promise<PricesResult | null> {\n try {\n const res = await fetch(url, { signal: AbortSignal.timeout(8_000) })\n if (!res.ok) return null\n const data = (await res.json()) as PricesFile\n if (!data?.models) return null\n await persistCache(data)\n return { models: data.models, updated_at: data.updated_at ?? '' }\n } catch {\n return null\n }\n}\n\nexport async function loadCachedPrices(): Promise<PricesResult | null> {\n if (!existsSync(CACHE_FILE)) return null\n try {\n const raw = await readFile(CACHE_FILE, 'utf8')\n const data = JSON.parse(raw) as PricesFile & { _cachedAt?: number }\n const age = Date.now() - (data._cachedAt ?? 0)\n if (age > CACHE_TTL_MS) return null\n if (!data.models) return null\n return { models: data.models, updated_at: data.updated_at ?? '' }\n } catch {\n return null\n }\n}\n\nasync function persistCache(data: PricesFile): Promise<void> {\n try {\n await mkdir(CACHE_DIR, { recursive: true })\n const payload = { ...data, _cachedAt: Date.now() }\n await writeFile(CACHE_FILE, JSON.stringify(payload, null, 2), 'utf8')\n } catch {\n // best-effort — never throw\n }\n}\n\n/**\n * Returns the best available remote price result:\n * 1. Valid local cache (< 24h)\n * 2. Fresh remote fetch (also updates cache)\n * 3. null if both fail\n */\nexport async function getRemotePrices(): Promise<PricesResult | null> {\n const cached = await loadCachedPrices()\n if (cached) return cached\n return fetchRemotePrices()\n}\n","import { createRequire } from 'node:module'\nimport { homedir } from 'node:os'\nimport { join } from 'node:path'\nimport { mkdirSync } from 'node:fs'\nimport type { IStorage, UsageEntry } from '../types/index.js'\n\n// ─── Memory storage ───────────────────────────────────────────────────────────\n\nexport class MemoryStorage implements IStorage {\n private entries: UsageEntry[] = []\n\n record(entry: UsageEntry): void {\n this.entries.push(entry)\n }\n\n getAll(): UsageEntry[] {\n return [...this.entries]\n }\n\n clearAll(): void {\n this.entries = []\n }\n\n clearSession(sessionId: string): void {\n this.entries = this.entries.filter((e) => e.sessionId !== sessionId)\n }\n}\n\n// ─── SQLite storage ───────────────────────────────────────────────────────────\n\nconst DB_DIR = join(homedir(), '.tokenwatch')\nconst DB_PATH = join(DB_DIR, 'usage.db')\n\nexport class SqliteStorage implements IStorage {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private db: any\n\n constructor(dbPath = DB_PATH) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let BetterSqlite3: any\n try {\n // In CJS context globalThis.require is the native require; in ESM use createRequire.\n // This makes the lazy load work in both output formats produced by tsup.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const req: NodeRequire =\n typeof (globalThis as any).require === 'function'\n ? // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (globalThis as any).require\n : createRequire(import.meta.url)\n BetterSqlite3 = req('better-sqlite3')\n } catch {\n throw new Error(\n '[tokenwatch] SQLite storage requires better-sqlite3. ' +\n 'Run: npm install better-sqlite3',\n )\n }\n\n mkdirSync(DB_DIR, { recursive: true })\n this.db = new BetterSqlite3(dbPath)\n this.migrate()\n }\n\n private migrate(): void {\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS usage (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n model TEXT NOT NULL,\n input_tokens INTEGER NOT NULL,\n output_tokens INTEGER NOT NULL,\n reasoning_tokens INTEGER NOT NULL DEFAULT 0,\n cached_tokens INTEGER NOT NULL DEFAULT 0,\n cache_creation_tokens INTEGER NOT NULL DEFAULT 0,\n cost_usd REAL NOT NULL,\n session_id TEXT,\n user_id TEXT,\n feature TEXT,\n timestamp TEXT NOT NULL\n )\n `)\n // Incremental migrations for databases created before v0.2.0 / v0.3.0\n const cols = (this.db.prepare(`PRAGMA table_info(usage)`).all() as Array<{ name: string }>)\n .map((c) => c.name)\n if (!cols.includes('reasoning_tokens')) {\n this.db.exec(`ALTER TABLE usage ADD COLUMN reasoning_tokens INTEGER NOT NULL DEFAULT 0`)\n }\n if (!cols.includes('feature')) {\n this.db.exec(`ALTER TABLE usage ADD COLUMN feature TEXT`)\n }\n if (!cols.includes('cached_tokens')) {\n this.db.exec(`ALTER TABLE usage ADD COLUMN cached_tokens INTEGER NOT NULL DEFAULT 0`)\n }\n if (!cols.includes('cache_creation_tokens')) {\n this.db.exec(`ALTER TABLE usage ADD COLUMN cache_creation_tokens INTEGER NOT NULL DEFAULT 0`)\n }\n }\n\n record(entry: UsageEntry): void {\n this.db\n .prepare(\n `INSERT INTO usage\n (model, input_tokens, output_tokens, reasoning_tokens, cached_tokens, cache_creation_tokens,\n cost_usd, session_id, user_id, feature, timestamp)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n )\n .run(\n entry.model,\n entry.inputTokens,\n entry.outputTokens,\n entry.reasoningTokens ?? 0,\n entry.cachedTokens ?? 0,\n entry.cacheCreationTokens ?? 0,\n entry.costUSD,\n entry.sessionId ?? null,\n entry.userId ?? null,\n entry.feature ?? null,\n entry.timestamp,\n )\n }\n\n getAll(): UsageEntry[] {\n const rows = this.db.prepare('SELECT * FROM usage ORDER BY timestamp ASC').all() as Array<{\n model: string\n input_tokens: number\n output_tokens: number\n reasoning_tokens: number\n cached_tokens: number\n cache_creation_tokens: number\n cost_usd: number\n session_id: string | null\n user_id: string | null\n feature: string | null\n timestamp: string\n }>\n\n return rows.map((r) => ({\n model: r.model,\n inputTokens: r.input_tokens,\n outputTokens: r.output_tokens,\n ...(r.reasoning_tokens > 0 && { reasoningTokens: r.reasoning_tokens }),\n ...(r.cached_tokens > 0 && { cachedTokens: r.cached_tokens }),\n ...(r.cache_creation_tokens > 0 && { cacheCreationTokens: r.cache_creation_tokens }),\n costUSD: r.cost_usd,\n ...(r.session_id != null && { sessionId: r.session_id }),\n ...(r.user_id != null && { userId: r.user_id }),\n ...(r.feature != null && { feature: r.feature }),\n timestamp: r.timestamp,\n }))\n }\n\n clearAll(): void {\n this.db.exec('DELETE FROM usage')\n }\n\n clearSession(sessionId: string): void {\n this.db.prepare('DELETE FROM usage WHERE session_id = ?').run(sessionId)\n }\n}\n\n// ─── Factory ──────────────────────────────────────────────────────────────────\n\nexport function createStorage(type: 'memory' | 'sqlite'): IStorage {\n if (type === 'sqlite') return new SqliteStorage()\n return new MemoryStorage()\n}\n","import { z } from 'zod'\nimport type {\n Tracker,\n TrackerConfig,\n UsageEntry,\n Report,\n ReportOptions,\n CostForecast,\n ForecastOptions,\n ModelStats,\n SessionStats,\n UserStats,\n FeatureStats,\n ModelPrice,\n PriceMap,\n IStorage,\n BudgetConfig,\n IExporter,\n} from '../types/index.js'\nimport { resolvePrice, findPrice, calculateCost } from './pricing.js'\nimport { maybeSuggestCheaperModel } from './suggestions.js'\nimport { createStorage } from './storage.js'\nimport { getRemotePrices } from './sync.js'\nimport bundledPricesFile from '../../prices.json' assert { type: 'json' }\n\nconst bundledPrices: PriceMap = bundledPricesFile.models as PriceMap\nconst bundledUpdatedAt: string = (bundledPricesFile as { updated_at?: string }).updated_at ?? ''\n\n// ─── Config validation schema ─────────────────────────────────────────────────\n\nconst ModelPriceSchema = z.object({\n input: z.number().nonnegative(),\n output: z.number().nonnegative(),\n cachedInput: z.number().nonnegative().optional(),\n cacheCreationInput: z.number().nonnegative().optional(),\n maxInputTokens: z.number().positive().optional(),\n})\n\nconst BudgetConfigSchema = z.object({\n threshold: z.number().positive(),\n webhookUrl: z.string().url(),\n mode: z.enum(['once', 'always']).optional().default('once'),\n})\n\n// storage can be a string enum or an IStorage instance — validated separately\nconst TrackerConfigSchema = z.object({\n storage: z.union([z.enum(['memory', 'sqlite']), z.custom<IStorage>((v) => {\n return (\n v !== null &&\n typeof v === 'object' &&\n typeof (v as IStorage).record === 'function' &&\n typeof (v as IStorage).getAll === 'function' &&\n typeof (v as IStorage).clearAll === 'function' &&\n typeof (v as IStorage).clearSession === 'function'\n )\n })]).optional().default('memory'),\n alertThreshold: z.number().positive().optional(),\n webhookUrl: z.string().url().optional(),\n syncPrices: z.boolean().optional().default(true),\n customPrices: z.record(z.string(), ModelPriceSchema).optional(),\n warnIfStaleAfterHours: z.number().nonnegative().optional().default(72),\n budgets: z.object({\n perUser: BudgetConfigSchema.optional(),\n perSession: BudgetConfigSchema.optional(),\n }).optional(),\n suggestions: z.boolean().optional().default(false),\n anomalyDetection: z.object({\n multiplierThreshold: z.number().positive(),\n webhookUrl: z.string().url(),\n windowHours: z.number().positive().optional().default(24),\n mode: z.enum(['once', 'always']).optional().default('once'),\n }).optional(),\n exporter: z.custom<IExporter>((v) => (\n v !== null &&\n typeof v === 'object' &&\n typeof (v as IExporter).export === 'function'\n )).optional(),\n})\n\nexport function createTracker(config: TrackerConfig = {}): Tracker {\n const parsed = TrackerConfigSchema.safeParse(config)\n if (!parsed.success) {\n const issues = parsed.error.issues.map((i) => ` ${i.path.join('.')}: ${i.message}`).join('\\n')\n throw new Error(`[tokenwatch] Invalid config:\\n${issues}`)\n }\n\n const {\n storage: storageOption,\n alertThreshold,\n webhookUrl,\n syncPrices,\n customPrices,\n warnIfStaleAfterHours,\n budgets,\n suggestions,\n anomalyDetection,\n exporter,\n } = parsed.data\n\n const storage: IStorage =\n typeof storageOption === 'object'\n ? storageOption\n : createStorage(storageOption)\n\n // Fetch remote prices in the background — bundled prices are used as fallback\n // until the sync resolves. Negligible overhead added to createTracker().\n let remotePrices: PriceMap | undefined\n let pricesUpdatedAt: string = bundledUpdatedAt\n if (syncPrices) {\n getRemotePrices()\n .then((result) => {\n if (result) {\n remotePrices = result.models\n pricesUpdatedAt = result.updated_at\n }\n })\n .catch(() => {\n // best-effort — bundled prices remain in use\n })\n }\n\n // Warn if prices are stale (checked lazily on first access)\n let stalenessChecked = false\n function maybeWarnStaleness(): void {\n if (stalenessChecked || !warnIfStaleAfterHours) return\n stalenessChecked = true\n if (!pricesUpdatedAt) return\n try {\n const updatedMs = new Date(pricesUpdatedAt).getTime()\n const ageHours = (Date.now() - updatedMs) / (1000 * 60 * 60)\n if (ageHours > warnIfStaleAfterHours) {\n console.warn(\n `[tokenwatch] Price data is ${Math.round(ageHours)}h old (updated_at: ${pricesUpdatedAt}). ` +\n `Run \"tokenwatch sync\" to refresh, or set warnIfStaleAfterHours: 0 to suppress.`,\n )\n }\n } catch {\n // best-effort\n }\n }\n\n let alertFired = false\n const firedUserAlerts = new Set<string>()\n const firedSessionAlerts = new Set<string>()\n const firedAnomalyKeys = new Set<string>()\n const startedAt = new Date().toISOString()\n\n function resolveModelPrice(model: string) {\n maybeWarnStaleness()\n return resolvePrice(model, {\n bundledPrices,\n ...(customPrices !== undefined && { customPrices: customPrices as PriceMap }),\n ...(remotePrices !== undefined && { remotePrices }),\n })\n }\n\n function track(entry: Omit<UsageEntry, 'costUSD' | 'timestamp'>): void {\n const price = resolveModelPrice(entry.model)\n const costUSD = calculateCost(\n entry.inputTokens,\n entry.outputTokens,\n price,\n entry.cachedTokens,\n entry.cacheCreationTokens,\n )\n const full: UsageEntry = {\n ...entry,\n costUSD,\n timestamp: new Date().toISOString(),\n }\n storage.record(full)\n if (exporter) {\n Promise.resolve(exporter.export(full)).catch(() => { /* fire-and-forget */ })\n }\n maybeFireAlerts(full)\n if (anomalyDetection) maybeDetectAnomaly(full)\n if (suggestions) {\n maybeSuggestCheaperModel(entry.model, costUSD, entry.inputTokens, entry.outputTokens, {\n bundledPrices,\n ...(customPrices !== undefined && { customPrices: customPrices as PriceMap }),\n ...(remotePrices !== undefined && { remotePrices }),\n })\n }\n }\n\n function maybeFireAlerts(entry: UsageEntry): void {\n // Global threshold alert\n if (alertThreshold && webhookUrl && !alertFired) {\n alertFired = true\n Promise.resolve(storage.getAll()).then((entries) => {\n const total = computeTotal(entries)\n if (total < alertThreshold!) {\n alertFired = false\n return\n }\n fireWebhook(webhookUrl!, {\n text: `[tokenwatch] Alert: total cost reached $${total.toFixed(4)} USD (threshold: $${alertThreshold})`,\n })\n }).catch(() => {\n alertFired = false\n })\n }\n\n // Per-user budget alert\n if (budgets?.perUser && entry.userId) {\n const cfg = budgets.perUser\n const uid = entry.userId\n if (cfg.mode === 'always' || !firedUserAlerts.has(uid)) {\n // Claim the slot synchronously before going async — prevents double-fire\n if (cfg.mode !== 'always') firedUserAlerts.add(uid)\n Promise.resolve(storage.getAll()).then((entries) => {\n const userCost = entries\n .filter((e) => e.userId === uid)\n .reduce((s, e) => s + e.costUSD, 0)\n if (userCost >= cfg.threshold) {\n fireWebhook(cfg.webhookUrl, {\n text: `[tokenwatch] Budget alert: user \"${uid}\" reached $${userCost.toFixed(4)} USD (threshold: $${cfg.threshold})`,\n })\n } else {\n if (cfg.mode !== 'always') firedUserAlerts.delete(uid) // release — threshold not yet met\n }\n }).catch(() => {\n if (cfg.mode !== 'always') firedUserAlerts.delete(uid) // release on storage error\n })\n }\n }\n\n // Per-session budget alert\n if (budgets?.perSession && entry.sessionId) {\n const cfg = budgets.perSession\n const sid = entry.sessionId\n if (cfg.mode === 'always' || !firedSessionAlerts.has(sid)) {\n // Claim the slot synchronously before going async — prevents double-fire\n if (cfg.mode !== 'always') firedSessionAlerts.add(sid)\n Promise.resolve(storage.getAll()).then((entries) => {\n const sessionCost = entries\n .filter((e) => e.sessionId === sid)\n .reduce((s, e) => s + e.costUSD, 0)\n if (sessionCost >= cfg.threshold) {\n fireWebhook(cfg.webhookUrl, {\n text: `[tokenwatch] Budget alert: session \"${sid}\" reached $${sessionCost.toFixed(4)} USD (threshold: $${cfg.threshold})`,\n })\n } else {\n if (cfg.mode !== 'always') firedSessionAlerts.delete(sid) // release\n }\n }).catch(() => {\n if (cfg.mode !== 'always') firedSessionAlerts.delete(sid) // release on storage error\n })\n }\n }\n }\n\n function fireWebhook(url: string, payload: { text: string }): void {\n fetch(url, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n }).catch(() => {\n // fire-and-forget\n })\n }\n\n async function getReport(options?: ReportOptions): Promise<Report> {\n const allEntries = await Promise.resolve(storage.getAll())\n const entries = filterEntries(allEntries, options)\n\n const byModel: Record<string, ModelStats> = {}\n const bySession: Record<string, SessionStats> = {}\n const byUser: Record<string, UserStats> = {}\n const byFeature: Record<string, FeatureStats> = {}\n\n let totalInput = 0\n let totalOutput = 0\n let totalCost = 0\n let periodFrom = options ? (entries[0]?.timestamp ?? startedAt) : startedAt\n let lastTimestamp = periodFrom\n\n for (const e of entries) {\n totalInput += e.inputTokens + (e.cachedTokens ?? 0) + (e.cacheCreationTokens ?? 0)\n totalOutput += e.outputTokens\n totalCost += e.costUSD\n if (e.timestamp > lastTimestamp) lastTimestamp = e.timestamp\n\n // byModel\n const m = (byModel[e.model] ??= {\n costUSD: 0,\n calls: 0,\n tokens: { input: 0, output: 0, reasoning: 0, cached: 0 },\n })\n m.costUSD += e.costUSD\n m.calls += 1\n m.tokens.input += e.inputTokens + (e.cachedTokens ?? 0) + (e.cacheCreationTokens ?? 0)\n m.tokens.output += e.outputTokens\n m.tokens.reasoning += e.reasoningTokens ?? 0\n m.tokens.cached += e.cachedTokens ?? 0\n\n // bySession\n if (e.sessionId) {\n const s = (bySession[e.sessionId] ??= { costUSD: 0, calls: 0 })\n s.costUSD += e.costUSD\n s.calls += 1\n }\n\n // byUser\n if (e.userId) {\n const u = (byUser[e.userId] ??= { costUSD: 0, calls: 0 })\n u.costUSD += e.costUSD\n u.calls += 1\n }\n\n // byFeature\n if (e.feature) {\n const f = (byFeature[e.feature] ??= { costUSD: 0, calls: 0 })\n f.costUSD += e.costUSD\n f.calls += 1\n }\n }\n\n // When filtering, use the actual first entry's timestamp as period.from\n if (options && entries.length > 0) {\n periodFrom = entries[0]?.timestamp ?? periodFrom\n }\n\n return {\n totalCostUSD: totalCost,\n totalTokens: { input: totalInput, output: totalOutput },\n byModel,\n bySession,\n byUser,\n byFeature,\n period: { from: periodFrom, to: lastTimestamp },\n ...(pricesUpdatedAt ? { pricesUpdatedAt } : {}),\n }\n }\n\n async function getCostForecast(options: ForecastOptions = {}): Promise<CostForecast> {\n const windowHours = options.windowHours ?? 24\n const allEntries = await Promise.resolve(storage.getAll())\n\n const now = Date.now()\n const windowStart = now - windowHours * 60 * 60 * 1000\n const windowEntries = allEntries.filter(\n (e) => new Date(e.timestamp).getTime() >= windowStart,\n )\n\n if (windowEntries.length < 2) {\n return {\n burnRatePerHour: 0,\n projectedDailyCostUSD: 0,\n projectedMonthlyCostUSD: 0,\n basedOnHours: 0,\n basedOnPeriod: null,\n }\n }\n\n const first = windowEntries[0]?.timestamp ?? ''\n const last = windowEntries[windowEntries.length - 1]?.timestamp ?? ''\n const actualMs = new Date(last).getTime() - new Date(first).getTime()\n const actualHours = actualMs / (1000 * 60 * 60)\n\n if (actualHours < 0.001) {\n return {\n burnRatePerHour: 0,\n projectedDailyCostUSD: 0,\n projectedMonthlyCostUSD: 0,\n basedOnHours: 0,\n basedOnPeriod: { from: first, to: last },\n }\n }\n\n const totalCost = windowEntries.reduce((s, e) => s + e.costUSD, 0)\n const burnRatePerHour = totalCost / actualHours\n\n return {\n burnRatePerHour,\n projectedDailyCostUSD: burnRatePerHour * 24,\n projectedMonthlyCostUSD: burnRatePerHour * 24 * 30,\n basedOnHours: Math.round(actualHours * 100) / 100,\n basedOnPeriod: { from: first, to: last },\n }\n }\n\n function maybeDetectAnomaly(entry: UsageEntry): void {\n if (entry.costUSD <= 0) return\n const { multiplierThreshold, webhookUrl: aUrl, windowHours: wh, mode: modeRaw } = anomalyDetection!\n const wHours = wh ?? 24\n const mode = modeRaw ?? 'once'\n const windowStart = Date.now() - wHours * 60 * 60 * 1000\n const entryTs = new Date(entry.timestamp).getTime()\n\n function checkEntity(key: string, label: string, predicate: (e: UsageEntry) => boolean): void {\n if (mode !== 'always' && firedAnomalyKeys.has(key)) return\n if (mode !== 'always') firedAnomalyKeys.add(key)\n Promise.resolve(storage.getAll()).then((all) => {\n const history = all.filter(\n (e) =>\n predicate(e) &&\n new Date(e.timestamp).getTime() >= windowStart &&\n new Date(e.timestamp).getTime() !== entryTs,\n )\n if (history.length === 0) {\n if (mode !== 'always') firedAnomalyKeys.delete(key)\n return\n }\n const avg = history.reduce((s, e) => s + e.costUSD, 0) / history.length\n if (avg <= 0 || entry.costUSD <= avg * multiplierThreshold) {\n if (mode !== 'always') firedAnomalyKeys.delete(key)\n return\n }\n const multiple = (entry.costUSD / avg).toFixed(1)\n fireWebhook(aUrl, {\n text: `[tokenwatch] Anomaly: ${label} call cost $${entry.costUSD.toFixed(4)} is ${multiple}x above ${wHours}h average ($${avg.toFixed(4)})`,\n })\n }).catch(() => {\n if (mode !== 'always') firedAnomalyKeys.delete(key)\n })\n }\n\n if (entry.userId) {\n checkEntity(\n `user:${entry.userId}`,\n `user \"${entry.userId}\"`,\n (e) => e.userId === entry.userId,\n )\n }\n checkEntity(\n `model:${entry.model}`,\n `model \"${entry.model}\"`,\n (e) => e.model === entry.model,\n )\n }\n\n async function reset(): Promise<void> {\n await Promise.resolve(storage.clearAll())\n alertFired = false\n firedUserAlerts.clear()\n firedSessionAlerts.clear()\n firedAnomalyKeys.clear()\n }\n\n async function resetSession(sessionId: string): Promise<void> {\n await Promise.resolve(storage.clearSession(sessionId))\n firedSessionAlerts.delete(sessionId)\n }\n\n async function exportJSON(): Promise<string> {\n return JSON.stringify(await getReport(), null, 2)\n }\n\n async function exportCSV(): Promise<string> {\n const entries = await Promise.resolve(storage.getAll())\n const header =\n 'timestamp,model,inputTokens,outputTokens,reasoningTokens,cachedTokens,cacheCreationTokens,costUSD,sessionId,userId,feature'\n const rows = entries.map((e) =>\n [\n csvEscape(e.timestamp),\n csvEscape(e.model),\n e.inputTokens,\n e.outputTokens,\n e.reasoningTokens ?? 0,\n e.cachedTokens ?? 0,\n e.cacheCreationTokens ?? 0,\n e.costUSD.toFixed(8),\n csvEscape(e.sessionId ?? ''),\n csvEscape(e.userId ?? ''),\n csvEscape(e.feature ?? ''),\n ].join(','),\n )\n return [header, ...rows].join('\\n')\n }\n\n function getModelInfo(model: string): ModelPrice | null {\n return findPrice(model, {\n bundledPrices,\n ...(customPrices !== undefined && { customPrices: customPrices as PriceMap }),\n ...(remotePrices !== undefined && { remotePrices }),\n }) ?? null\n }\n\n return {\n track,\n getReport,\n getCostForecast,\n reset,\n resetSession,\n exportJSON,\n exportCSV,\n getModelInfo,\n }\n}\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction computeTotal(entries: UsageEntry[]): number {\n return entries.reduce((sum, e) => sum + e.costUSD, 0)\n}\n\n/** Parse a 'last' shorthand like '24h', '7d' into milliseconds */\nfunction parseLastMs(last: string): number {\n const match = /^(\\d+(?:\\.\\d+)?)(h|d)$/.exec(last.trim())\n if (!match) throw new Error(`[tokenwatch] Invalid \"last\" value: \"${last}\". Use e.g. \"24h\", \"7d\".`)\n const value = parseFloat(match[1] ?? '0')\n const unit = match[2] ?? 'h'\n return unit === 'h' ? value * 60 * 60 * 1000 : value * 24 * 60 * 60 * 1000\n}\n\nfunction filterEntries(entries: UsageEntry[], options?: ReportOptions): UsageEntry[] {\n if (!options) return entries\n\n let sinceMs: number | undefined\n let untilMs: number | undefined\n\n if (options.last) {\n sinceMs = Date.now() - parseLastMs(options.last)\n } else if (options.since) {\n sinceMs = new Date(options.since).getTime()\n }\n if (options.until) {\n untilMs = new Date(options.until).getTime()\n }\n\n if (sinceMs === undefined && untilMs === undefined) return entries\n\n return entries.filter((e) => {\n const ts = new Date(e.timestamp).getTime()\n if (sinceMs !== undefined && ts < sinceMs) return false\n if (untilMs !== undefined && ts > untilMs) return false\n return true\n })\n}\n\n/** Wrap a CSV field value in double-quotes if it contains commas, quotes, or newlines. */\nfunction csvEscape(value: string): string {\n if (value.includes(',') || value.includes('\"') || value.includes('\\n')) {\n return `\"${value.replace(/\"/g, '\"\"')}\"`\n }\n return value\n}\n","import type { ModelPrice, PriceMap } from '../types/index.js'\n\n/**\n * Resolve price for a model using 3-layer priority:\n * 1. customPrices (user override)\n * 2. remotePrices (synced from GitHub, cached 24h)\n * 3. bundledPrices (always-present fallback)\n *\n * Falls back to zero-cost with a console warning when model is not found anywhere.\n */\nexport function resolvePrice(\n model: string,\n layers: {\n customPrices?: PriceMap\n remotePrices?: PriceMap\n bundledPrices: PriceMap\n },\n): ModelPrice {\n const { customPrices, remotePrices, bundledPrices } = layers\n\n const found =\n lookupInMap(model, customPrices) ??\n lookupInMap(model, remotePrices) ??\n lookupInMap(model, bundledPrices)\n\n if (found) return found\n\n console.warn(\n `[tokenwatch] Unknown model \"${model}\". Cost will be recorded as $0. ` +\n `Add it via customPrices or update prices with: tokenwatch sync`,\n )\n return { input: 0, output: 0 }\n}\n\n/**\n * Find price for a model without the zero-cost fallback.\n * Returns undefined if the model is not found in any layer.\n */\nexport function findPrice(\n model: string,\n layers: {\n customPrices?: PriceMap\n remotePrices?: PriceMap\n bundledPrices: PriceMap\n },\n): ModelPrice | undefined {\n const { customPrices, remotePrices, bundledPrices } = layers\n return (\n lookupInMap(model, customPrices) ??\n lookupInMap(model, remotePrices) ??\n lookupInMap(model, bundledPrices)\n )\n}\n\n/**\n * Look up a model in a PriceMap using:\n * 1. exact key match\n * 2. prefix match — map key is a prefix of the model string (e.g. \"gpt-4o\" matches \"gpt-4o-2024-11-20\")\n * 3. reverse prefix — model string is a prefix of a map key (unusual, safety net)\n */\nfunction lookupInMap(model: string, map: PriceMap | undefined): ModelPrice | undefined {\n if (!map) return undefined\n\n if (model in map) return map[model]\n\n // prefix match\n for (const key of Object.keys(map)) {\n if (model.startsWith(key) || key.startsWith(model)) {\n return map[key]\n }\n }\n\n return undefined\n}\n\n/**\n * Calculate cost in USD given token counts and per-million-token prices.\n *\n * - `inputTokens` — regular (non-cached) input tokens\n * - `outputTokens` — output tokens (includes reasoning tokens for OpenAI, which are billed as output)\n * - `cachedTokens` — cache-read input tokens (billed at price.cachedInput or full input price if absent)\n * - `cacheCreationTokens` — cache-creation input tokens, Anthropic only (billed at price.cacheCreationInput\n * or 1.25× input price if absent)\n */\nexport function calculateCost(\n inputTokens: number,\n outputTokens: number,\n price: ModelPrice,\n cachedTokens = 0,\n cacheCreationTokens = 0,\n): number {\n const regularInputCost = (inputTokens / 1_000_000) * price.input\n const cachedReadCost = (cachedTokens / 1_000_000) * (price.cachedInput ?? price.input)\n const cacheCreationCost =\n (cacheCreationTokens / 1_000_000) * (price.cacheCreationInput ?? price.input * 1.25)\n const outputCost = (outputTokens / 1_000_000) * price.output\n return regularInputCost + cachedReadCost + cacheCreationCost + outputCost\n}\n","import type { PriceMap } from '../types/index.js'\nimport { calculateCost } from './pricing.js'\n\nconst PROVIDER_PREFIXES = ['gpt-', 'claude-', 'gemini-', 'deepseek-'] as const\n\nfunction getProviderPrefix(model: string): string | undefined {\n return PROVIDER_PREFIXES.find((p) => model.startsWith(p))\n}\n\n/**\n * After a tracked call, check if there is a cheaper model in the same provider family\n * (defined by model name prefix). Logs a hint if savings are strictly greater than 50%.\n * No-ops if the model is unknown, costUSD is zero, or no cheaper candidate is found.\n */\nexport function maybeSuggestCheaperModel(\n model: string,\n costUSD: number,\n inputTokens: number,\n outputTokens: number,\n layers: { bundledPrices: PriceMap; customPrices?: PriceMap; remotePrices?: PriceMap },\n): void {\n if (costUSD <= 0) return\n\n const prefix = getProviderPrefix(model)\n if (!prefix) return\n\n // Merge layers: bundled < remote < custom (custom wins)\n const mergedMap: PriceMap = {\n ...layers.bundledPrices,\n ...(layers.remotePrices ?? {}),\n ...(layers.customPrices ?? {}),\n }\n\n let cheapestModel: string | undefined\n let cheapestCost = Infinity\n\n for (const key of Object.keys(mergedMap)) {\n if (key === model || !key.startsWith(prefix)) continue\n const price = mergedMap[key]\n if (!price) continue\n const candidateCost = calculateCost(inputTokens, outputTokens, price)\n if (candidateCost < cheapestCost) {\n cheapestCost = candidateCost\n cheapestModel = key\n }\n }\n\n // Must be strictly more than 50% cheaper\n if (cheapestModel === undefined || cheapestCost >= costUSD * 0.5) return\n\n const savingsPct = Math.round((1 - cheapestCost / costUSD) * 100)\n console.log(\n `[tokenwatch] Suggestion: ${cheapestModel} could handle this for ~$${cheapestCost.toFixed(4)} (${savingsPct}% cheaper than ${model})`,\n )\n}\n","{\n \"updated_at\": \"2026-04-23\",\n \"source\": \"https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json\",\n \"models\": {\n \"gpt-4o\": {\n \"input\": 2.5,\n \"output\": 10,\n \"cachedInput\": 1.25,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-mini\": {\n \"input\": 0.15,\n \"output\": 0.6,\n \"cachedInput\": 0.075,\n \"maxInputTokens\": 128000\n },\n \"gpt-5\": {\n \"input\": 1.25,\n \"output\": 10,\n \"cachedInput\": 0.125,\n \"maxInputTokens\": 272000\n },\n \"gpt-5-mini\": {\n \"input\": 0.25,\n \"output\": 2,\n \"cachedInput\": 0.025,\n \"maxInputTokens\": 272000\n },\n \"gpt-5-nano\": {\n \"input\": 0.05,\n \"output\": 0.4,\n \"cachedInput\": 0.005,\n \"maxInputTokens\": 272000\n },\n \"claude-opus-4-6\": {\n \"input\": 5,\n \"output\": 25,\n \"cachedInput\": 0.5,\n \"cacheCreationInput\": 6.25,\n \"maxInputTokens\": 1000000\n },\n \"claude-sonnet-4-6\": {\n \"input\": 3,\n \"output\": 15,\n \"cachedInput\": 0.3,\n \"cacheCreationInput\": 3.75,\n \"maxInputTokens\": 1000000\n },\n \"claude-haiku-4-5\": {\n \"input\": 1,\n \"output\": 5,\n \"cachedInput\": 0.1,\n \"cacheCreationInput\": 1.25,\n \"maxInputTokens\": 200000\n },\n \"gemini-2.5-pro\": {\n \"input\": 1.25,\n \"output\": 10,\n \"cachedInput\": 0.125,\n \"maxInputTokens\": 1048576\n },\n \"gemini-2.5-flash\": {\n \"input\": 0.3,\n \"output\": 2.5,\n \"cachedInput\": 0.03,\n \"maxInputTokens\": 1048576\n },\n \"deepseek-chat\": {\n \"input\": 0.28,\n \"output\": 0.42,\n \"cachedInput\": 0.028,\n \"maxInputTokens\": 131072\n },\n \"deepseek-reasoner\": {\n \"input\": 0.28,\n \"output\": 0.42,\n \"cachedInput\": 0.028,\n \"maxInputTokens\": 131072\n },\n \"claude-opus-4-5\": {\n \"input\": 5,\n \"output\": 25,\n \"cachedInput\": 0.5,\n \"cacheCreationInput\": 6.25,\n \"maxInputTokens\": 200000\n },\n \"claude-opus-4-7\": {\n \"input\": 5,\n \"output\": 25,\n \"cachedInput\": 0.5,\n \"cacheCreationInput\": 6.25,\n \"maxInputTokens\": 1000000\n },\n \"claude-opus-4-1\": {\n \"input\": 15,\n \"output\": 75,\n \"cachedInput\": 1.5,\n \"cacheCreationInput\": 18.75,\n \"maxInputTokens\": 200000\n },\n \"claude-sonnet-4-5\": {\n \"input\": 3,\n \"output\": 15,\n \"cachedInput\": 0.3,\n \"cacheCreationInput\": 3.75,\n \"maxInputTokens\": 200000\n },\n \"gpt-oss-120b\": {\n \"input\": 3,\n \"output\": 4.5,\n \"maxInputTokens\": 131072\n },\n \"gpt-3.5-turbo\": {\n \"input\": 0.5,\n \"output\": 1.5,\n \"maxInputTokens\": 16385\n },\n \"gpt-3.5-turbo-0125\": {\n \"input\": 0.5,\n \"output\": 1.5,\n \"maxInputTokens\": 16385\n },\n \"gpt-35-turbo\": {\n \"input\": 0.5,\n \"output\": 1.5,\n \"maxInputTokens\": 4097\n },\n \"gpt-35-turbo-0125\": {\n \"input\": 0.5,\n \"output\": 1.5,\n \"maxInputTokens\": 16384\n },\n \"gpt-35-turbo-1106\": {\n \"input\": 1,\n \"output\": 2,\n \"maxInputTokens\": 16384\n },\n \"gpt-35-turbo-16k\": {\n \"input\": 3,\n \"output\": 4,\n \"maxInputTokens\": 16385\n },\n \"gpt-35-turbo-16k-0613\": {\n \"input\": 3,\n \"output\": 4,\n \"maxInputTokens\": 16385\n },\n \"gpt-4\": {\n \"input\": 30,\n \"output\": 60,\n \"maxInputTokens\": 8192\n },\n \"gpt-4-0125-preview\": {\n \"input\": 10,\n \"output\": 30,\n \"maxInputTokens\": 128000\n },\n \"gpt-4-0613\": {\n \"input\": 30,\n \"output\": 60,\n \"maxInputTokens\": 8192\n },\n \"gpt-4-1106-preview\": {\n \"input\": 10,\n \"output\": 30,\n \"maxInputTokens\": 128000\n },\n \"gpt-4-32k\": {\n \"input\": 60,\n \"output\": 120,\n \"maxInputTokens\": 32768\n },\n \"gpt-4-32k-0613\": {\n \"input\": 60,\n \"output\": 120,\n \"maxInputTokens\": 32768\n },\n \"gpt-4-turbo\": {\n \"input\": 10,\n \"output\": 30,\n \"maxInputTokens\": 128000\n },\n \"gpt-4-turbo-2024-04-09\": {\n \"input\": 10,\n \"output\": 30,\n \"maxInputTokens\": 128000\n },\n \"gpt-4-turbo-vision-preview\": {\n \"input\": 10,\n \"output\": 30,\n \"maxInputTokens\": 128000\n },\n \"gpt-4.1\": {\n \"input\": 2,\n \"output\": 8,\n \"cachedInput\": 0.5,\n \"maxInputTokens\": 1047576\n },\n \"gpt-4.1-2025-04-14\": {\n \"input\": 2,\n \"output\": 8,\n \"cachedInput\": 0.5,\n \"maxInputTokens\": 1047576\n },\n \"gpt-4.1-mini\": {\n \"input\": 0.4,\n \"output\": 1.6,\n \"cachedInput\": 0.1,\n \"maxInputTokens\": 1047576\n },\n \"gpt-4.1-mini-2025-04-14\": {\n \"input\": 0.4,\n \"output\": 1.6,\n \"cachedInput\": 0.1,\n \"maxInputTokens\": 1047576\n },\n \"gpt-4.1-nano\": {\n \"input\": 0.1,\n \"output\": 0.4,\n \"cachedInput\": 0.025,\n \"maxInputTokens\": 1047576\n },\n \"gpt-4.1-nano-2025-04-14\": {\n \"input\": 0.1,\n \"output\": 0.4,\n \"cachedInput\": 0.025,\n \"maxInputTokens\": 1047576\n },\n \"gpt-4.5-preview\": {\n \"input\": 75,\n \"output\": 150,\n \"cachedInput\": 37.5,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-2024-05-13\": {\n \"input\": 5,\n \"output\": 15,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-2024-08-06\": {\n \"input\": 2.5,\n \"output\": 10,\n \"cachedInput\": 1.25,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-2024-11-20\": {\n \"input\": 2.5,\n \"output\": 10,\n \"cachedInput\": 1.25,\n \"maxInputTokens\": 128000\n },\n \"gpt-audio-2025-08-28\": {\n \"input\": 2.5,\n \"output\": 10,\n \"maxInputTokens\": 128000\n },\n \"gpt-audio-1.5-2026-02-23\": {\n \"input\": 2.5,\n \"output\": 10,\n \"maxInputTokens\": 128000\n },\n \"gpt-audio-mini-2025-10-06\": {\n \"input\": 0.6,\n \"output\": 2.4,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-audio-preview-2024-12-17\": {\n \"input\": 2.5,\n \"output\": 10,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-mini-2024-07-18\": {\n \"input\": 0.15,\n \"output\": 0.6,\n \"cachedInput\": 0.075,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-mini-audio-preview-2024-12-17\": {\n \"input\": 0.15,\n \"output\": 0.6,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-mini-realtime-preview-2024-12-17\": {\n \"input\": 0.6,\n \"output\": 2.4,\n \"cachedInput\": 0.3,\n \"maxInputTokens\": 128000\n },\n \"gpt-realtime-2025-08-28\": {\n \"input\": 4,\n \"output\": 16,\n \"cachedInput\": 0.4,\n \"maxInputTokens\": 32000\n },\n \"gpt-realtime-1.5-2026-02-23\": {\n \"input\": 4,\n \"output\": 16,\n \"cachedInput\": 4,\n \"maxInputTokens\": 32000\n },\n \"gpt-realtime-mini-2025-10-06\": {\n \"input\": 0.6,\n \"output\": 2.4,\n \"cachedInput\": 0.06,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-mini-transcribe\": {\n \"input\": 1.25,\n \"output\": 5,\n \"maxInputTokens\": 16000\n },\n \"gpt-4o-realtime-preview-2024-10-01\": {\n \"input\": 5,\n \"output\": 20,\n \"cachedInput\": 2.5,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-realtime-preview-2024-12-17\": {\n \"input\": 5,\n \"output\": 20,\n \"cachedInput\": 2.5,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-transcribe\": {\n \"input\": 2.5,\n \"output\": 10,\n \"maxInputTokens\": 16000\n },\n \"gpt-4o-transcribe-diarize\": {\n \"input\": 2.5,\n \"output\": 10,\n \"maxInputTokens\": 16000\n },\n \"gpt-5.1-2025-11-13\": {\n \"input\": 1.25,\n \"output\": 10,\n \"cachedInput\": 0.125,\n \"maxInputTokens\": 272000\n },\n \"gpt-5.1-chat-2025-11-13\": {\n \"input\": 1.25,\n \"output\": 10,\n \"cachedInput\": 0.125,\n \"maxInputTokens\": 128000\n },\n \"gpt-5.1-codex-2025-11-13\": {\n \"input\": 1.25,\n \"output\": 10,\n \"cachedInput\": 0.125,\n \"maxInputTokens\": 272000\n },\n \"gpt-5.1-codex-mini-2025-11-13\": {\n \"input\": 0.25,\n \"output\": 2,\n \"cachedInput\": 0.025,\n \"maxInputTokens\": 272000\n },\n \"gpt-5-2025-08-07\": {\n \"input\": 1.25,\n \"output\": 10,\n \"cachedInput\": 0.125,\n \"maxInputTokens\": 272000\n },\n \"gpt-5-chat\": {\n \"input\": 1.25,\n \"output\": 10,\n \"cachedInput\": 0.125,\n \"maxInputTokens\": 128000\n },\n \"gpt-5-chat-latest\": {\n \"input\": 1.25,\n \"output\": 10,\n \"cachedInput\": 0.125,\n \"maxInputTokens\": 128000\n },\n \"gpt-5-codex\": {\n \"input\": 1.25,\n \"output\": 10,\n \"cachedInput\": 0.125,\n \"maxInputTokens\": 272000\n },\n \"gpt-5-mini-2025-08-07\": {\n \"input\": 0.25,\n \"output\": 2,\n \"cachedInput\": 0.025,\n \"maxInputTokens\": 272000\n },\n \"gpt-5-nano-2025-08-07\": {\n \"input\": 0.05,\n \"output\": 0.4,\n \"cachedInput\": 0.005,\n \"maxInputTokens\": 272000\n },\n \"gpt-5-pro\": {\n \"input\": 15,\n \"output\": 120,\n \"maxInputTokens\": 128000\n },\n \"gpt-5.1\": {\n \"input\": 1.25,\n \"output\": 10,\n \"cachedInput\": 0.125,\n \"maxInputTokens\": 272000\n },\n \"gpt-5.1-chat\": {\n \"input\": 1.25,\n \"output\": 10,\n \"cachedInput\": 0.125,\n \"maxInputTokens\": 128000\n },\n \"gpt-5.1-codex\": {\n \"input\": 1.25,\n \"output\": 10,\n \"cachedInput\": 0.125,\n \"maxInputTokens\": 272000\n },\n \"gpt-5.1-codex-max\": {\n \"input\": 1.25,\n \"output\": 10,\n \"cachedInput\": 0.125,\n \"maxInputTokens\": 272000\n },\n \"gpt-5.1-codex-mini\": {\n \"input\": 0.25,\n \"output\": 2,\n \"cachedInput\": 0.025,\n \"maxInputTokens\": 272000\n },\n \"gpt-5.2\": {\n \"input\": 1.75,\n \"output\": 14,\n \"cachedInput\": 0.175,\n \"maxInputTokens\": 272000\n },\n \"gpt-5.2-2025-12-11\": {\n \"input\": 1.75,\n \"output\": 14,\n \"cachedInput\": 0.175,\n \"maxInputTokens\": 272000\n },\n \"gpt-5.2-chat\": {\n \"input\": 1.75,\n \"output\": 14,\n \"cachedInput\": 0.175,\n \"maxInputTokens\": 128000\n },\n \"gpt-5.2-chat-2025-12-11\": {\n \"input\": 1.75,\n \"output\": 14,\n \"cachedInput\": 0.175,\n \"maxInputTokens\": 128000\n },\n \"gpt-5.2-codex\": {\n \"input\": 1.75,\n \"output\": 14,\n \"cachedInput\": 0.175,\n \"maxInputTokens\": 272000\n },\n \"gpt-5.3-chat\": {\n \"input\": 1.75,\n \"output\": 14,\n \"cachedInput\": 0.175,\n \"maxInputTokens\": 128000\n },\n \"gpt-5.3-codex\": {\n \"input\": 1.75,\n \"output\": 14,\n \"cachedInput\": 0.175,\n \"maxInputTokens\": 272000\n },\n \"gpt-5.2-pro\": {\n \"input\": 21,\n \"output\": 168,\n \"maxInputTokens\": 272000\n },\n \"gpt-5.2-pro-2025-12-11\": {\n \"input\": 21,\n \"output\": 168,\n \"maxInputTokens\": 272000\n },\n \"gpt-5.4\": {\n \"input\": 2.5,\n \"output\": 15,\n \"cachedInput\": 0.25,\n \"maxInputTokens\": 1050000\n },\n \"gpt-5.4-2026-03-05\": {\n \"input\": 2.5,\n \"output\": 15,\n \"cachedInput\": 0.25,\n \"maxInputTokens\": 1050000\n },\n \"gpt-5.4-pro\": {\n \"input\": 30,\n \"output\": 180,\n \"cachedInput\": 3,\n \"maxInputTokens\": 1050000\n },\n \"gpt-5.4-pro-2026-03-05\": {\n \"input\": 30,\n \"output\": 180,\n \"cachedInput\": 3,\n \"maxInputTokens\": 1050000\n },\n \"gpt-5.4-mini\": {\n \"input\": 0.75,\n \"output\": 4.5,\n \"cachedInput\": 0.075,\n \"maxInputTokens\": 272000\n },\n \"gpt-5.4-nano\": {\n \"input\": 0.2,\n \"output\": 1.25,\n \"cachedInput\": 0.02,\n \"maxInputTokens\": 272000\n },\n \"o1-2024-12-17\": {\n \"input\": 15,\n \"output\": 60,\n \"cachedInput\": 7.5,\n \"maxInputTokens\": 200000\n },\n \"o1-mini\": {\n \"input\": 1.21,\n \"output\": 4.84,\n \"cachedInput\": 0.605,\n \"maxInputTokens\": 128000\n },\n \"o1-mini-2024-09-12\": {\n \"input\": 1.1,\n \"output\": 4.4,\n \"cachedInput\": 0.55,\n \"maxInputTokens\": 128000\n },\n \"o1-preview\": {\n \"input\": 15,\n \"output\": 60,\n \"cachedInput\": 7.5,\n \"maxInputTokens\": 128000\n },\n \"o1-preview-2024-09-12\": {\n \"input\": 15,\n \"output\": 60,\n \"cachedInput\": 7.5,\n \"maxInputTokens\": 128000\n },\n \"o3-2025-04-16\": {\n \"input\": 2,\n \"output\": 8,\n \"cachedInput\": 0.5,\n \"maxInputTokens\": 200000\n },\n \"o3-mini\": {\n \"input\": 1.1,\n \"output\": 4.4,\n \"cachedInput\": 0.55,\n \"maxInputTokens\": 200000\n },\n \"o3-mini-2025-01-31\": {\n \"input\": 1.1,\n \"output\": 4.4,\n \"cachedInput\": 0.55,\n \"maxInputTokens\": 200000\n },\n \"o3-pro\": {\n \"input\": 20,\n \"output\": 80,\n \"maxInputTokens\": 200000\n },\n \"o3-pro-2025-06-10\": {\n \"input\": 20,\n \"output\": 80,\n \"maxInputTokens\": 200000\n },\n \"o4-mini\": {\n \"input\": 1.1,\n \"output\": 4.4,\n \"cachedInput\": 0.275,\n \"maxInputTokens\": 200000\n },\n \"o4-mini-2025-04-16\": {\n \"input\": 1.1,\n \"output\": 4.4,\n \"cachedInput\": 0.275,\n \"maxInputTokens\": 200000\n },\n \"deepseek-v3.2\": {\n \"input\": 0.28,\n \"output\": 0.4,\n \"maxInputTokens\": 163840\n },\n \"deepseek-v3.2-speciale\": {\n \"input\": 0.58,\n \"output\": 1.68,\n \"maxInputTokens\": 163840\n },\n \"deepseek-r1\": {\n \"input\": 0.55,\n \"output\": 2.19,\n \"maxInputTokens\": 65536\n },\n \"deepseek-v3\": {\n \"input\": 0.27,\n \"output\": 1.1,\n \"cachedInput\": 0.07,\n \"maxInputTokens\": 65536\n },\n \"deepseek-v3-0324\": {\n \"input\": 0.2,\n \"output\": 0.6,\n \"maxInputTokens\": 131072\n },\n \"chatgpt-4o-latest\": {\n \"input\": 5,\n \"output\": 15,\n \"maxInputTokens\": 128000\n },\n \"claude-haiku-4-5-20251001\": {\n \"input\": 1,\n \"output\": 5,\n \"cachedInput\": 0.1,\n \"cacheCreationInput\": 1.25,\n \"maxInputTokens\": 200000\n },\n \"claude-3-7-sonnet-20250219\": {\n \"input\": 3,\n \"output\": 15,\n \"cachedInput\": 0.3,\n \"cacheCreationInput\": 3.75,\n \"maxInputTokens\": 200000\n },\n \"claude-3-haiku-20240307\": {\n \"input\": 0.25,\n \"output\": 1.25,\n \"cachedInput\": 0.03,\n \"cacheCreationInput\": 0.3,\n \"maxInputTokens\": 200000\n },\n \"claude-3-opus-20240229\": {\n \"input\": 15,\n \"output\": 75,\n \"cachedInput\": 1.5,\n \"cacheCreationInput\": 18.75,\n \"maxInputTokens\": 200000\n },\n \"claude-4-opus-20250514\": {\n \"input\": 15,\n \"output\": 75,\n \"cachedInput\": 1.5,\n \"cacheCreationInput\": 18.75,\n \"maxInputTokens\": 200000\n },\n \"claude-4-sonnet-20250514\": {\n \"input\": 3,\n \"output\": 15,\n \"cachedInput\": 0.3,\n \"cacheCreationInput\": 3.75,\n \"maxInputTokens\": 1000000\n },\n \"claude-sonnet-4-5-20250929\": {\n \"input\": 3,\n \"output\": 15,\n \"cachedInput\": 0.3,\n \"cacheCreationInput\": 3.75,\n \"maxInputTokens\": 200000\n },\n \"claude-sonnet-4-5-20250929-v1:0\": {\n \"input\": 3,\n \"output\": 15,\n \"cachedInput\": 0.3,\n \"cacheCreationInput\": 3.75,\n \"maxInputTokens\": 200000\n },\n \"claude-opus-4-1-20250805\": {\n \"input\": 15,\n \"output\": 75,\n \"cachedInput\": 1.5,\n \"cacheCreationInput\": 18.75,\n \"maxInputTokens\": 200000\n },\n \"claude-opus-4-20250514\": {\n \"input\": 15,\n \"output\": 75,\n \"cachedInput\": 1.5,\n \"cacheCreationInput\": 18.75,\n \"maxInputTokens\": 200000\n },\n \"claude-opus-4-5-20251101\": {\n \"input\": 5,\n \"output\": 25,\n \"cachedInput\": 0.5,\n \"cacheCreationInput\": 6.25,\n \"maxInputTokens\": 200000\n },\n \"claude-opus-4-6-20260205\": {\n \"input\": 5,\n \"output\": 25,\n \"cachedInput\": 0.5,\n \"cacheCreationInput\": 6.25,\n \"maxInputTokens\": 1000000\n },\n \"claude-opus-4-7-20260416\": {\n \"input\": 5,\n \"output\": 25,\n \"cachedInput\": 0.5,\n \"cacheCreationInput\": 6.25,\n \"maxInputTokens\": 1000000\n },\n \"claude-sonnet-4-20250514\": {\n \"input\": 3,\n \"output\": 15,\n \"cachedInput\": 0.3,\n \"cacheCreationInput\": 3.75,\n \"maxInputTokens\": 1000000\n },\n \"codex-mini-latest\": {\n \"input\": 1.5,\n \"output\": 6,\n \"cachedInput\": 0.375,\n \"maxInputTokens\": 200000\n },\n \"deepseek-ai/deepseek-r1\": {\n \"input\": 3,\n \"output\": 7,\n \"maxInputTokens\": 128000\n },\n \"deepseek-ai/deepseek-r1-0528\": {\n \"input\": 135000,\n \"output\": 540000,\n \"maxInputTokens\": 161000\n },\n \"deepseek-ai/deepseek-r1-0528-turbo\": {\n \"input\": 1,\n \"output\": 3,\n \"maxInputTokens\": 32768\n },\n \"deepseek-ai/deepseek-r1-distill-llama-70b\": {\n \"input\": 0.25,\n \"output\": 0.75,\n \"maxInputTokens\": 128000\n },\n \"deepseek-ai/deepseek-r1-distill-qwen-32b\": {\n \"input\": 0.15,\n \"output\": 0.15\n },\n \"deepseek-ai/deepseek-r1-turbo\": {\n \"input\": 1,\n \"output\": 3,\n \"maxInputTokens\": 40960\n },\n \"deepseek-ai/deepseek-v3\": {\n \"input\": 1.25,\n \"output\": 1.25,\n \"maxInputTokens\": 65536\n },\n \"deepseek-ai/deepseek-v3-0324\": {\n \"input\": 114000,\n \"output\": 275000,\n \"maxInputTokens\": 161000\n },\n \"deepseek-ai/deepseek-v3.1\": {\n \"input\": 55000,\n \"output\": 165000,\n \"maxInputTokens\": 128000\n },\n \"deepseek-ai/deepseek-v3.1-terminus\": {\n \"input\": 0.27,\n \"output\": 1,\n \"cachedInput\": 0.216,\n \"maxInputTokens\": 163840\n },\n \"deepseek-coder\": {\n \"input\": 0.14,\n \"output\": 0.28,\n \"maxInputTokens\": 128000\n },\n \"gemini-2.0-flash\": {\n \"input\": 0.1,\n \"output\": 0.4,\n \"cachedInput\": 0.025,\n \"maxInputTokens\": 1048576\n },\n \"gemini-2.0-flash-001\": {\n \"input\": 0.1,\n \"output\": 0.4,\n \"cachedInput\": 0.025,\n \"maxInputTokens\": 1048576\n },\n \"gemini-2.0-flash-lite\": {\n \"input\": 0.075,\n \"output\": 0.3,\n \"cachedInput\": 0.01875,\n \"maxInputTokens\": 1048576\n },\n \"gemini-2.0-flash-lite-001\": {\n \"input\": 0.075,\n \"output\": 0.3,\n \"cachedInput\": 0.01875,\n \"maxInputTokens\": 1048576\n },\n \"gemini-2.5-flash-image\": {\n \"input\": 0.3,\n \"output\": 2.5,\n \"cachedInput\": 0.03,\n \"maxInputTokens\": 32768\n },\n \"gemini-3-pro-image-preview\": {\n \"input\": 2,\n \"output\": 12,\n \"maxInputTokens\": 65536\n },\n \"gemini-3.1-flash-image-preview\": {\n \"input\": 0.5,\n \"output\": 3,\n \"maxInputTokens\": 65536\n },\n \"gemini-3.1-flash-lite-preview\": {\n \"input\": 0.25,\n \"output\": 1.5,\n \"cachedInput\": 0.025,\n \"maxInputTokens\": 1048576\n },\n \"gemini-2.5-flash-lite\": {\n \"input\": 0.1,\n \"output\": 0.4,\n \"cachedInput\": 0.01,\n \"maxInputTokens\": 1048576\n },\n \"gemini-2.5-flash-lite-preview-09-2025\": {\n \"input\": 0.1,\n \"output\": 0.4,\n \"cachedInput\": 0.01,\n \"maxInputTokens\": 1048576\n },\n \"gemini-2.5-flash-preview-09-2025\": {\n \"input\": 0.3,\n \"output\": 2.5,\n \"cachedInput\": 0.075,\n \"maxInputTokens\": 1048576\n },\n \"gemini-live-2.5-flash-preview-native-audio-09-2025\": {\n \"input\": 0.3,\n \"output\": 2,\n \"cachedInput\": 0.075,\n \"maxInputTokens\": 1048576\n },\n \"gemini-2.5-flash-lite-preview-06-17\": {\n \"input\": 0.1,\n \"output\": 0.4,\n \"cachedInput\": 0.025,\n \"maxInputTokens\": 1048576\n },\n \"gemini-3-pro-preview\": {\n \"input\": 2,\n \"output\": 12,\n \"cachedInput\": 0.2,\n \"maxInputTokens\": 1048576\n },\n \"gemini-3.1-pro-preview\": {\n \"input\": 2,\n \"output\": 12,\n \"cachedInput\": 0.2,\n \"maxInputTokens\": 1048576\n },\n \"gemini-3.1-pro-preview-customtools\": {\n \"input\": 2,\n \"output\": 12,\n \"cachedInput\": 0.2,\n \"maxInputTokens\": 1048576\n },\n \"gemini-3-flash-preview\": {\n \"input\": 0.5,\n \"output\": 3,\n \"cachedInput\": 0.05,\n \"maxInputTokens\": 1048576\n },\n \"gemini-robotics-er-1.5-preview\": {\n \"input\": 0.3,\n \"output\": 2.5,\n \"maxInputTokens\": 1048576\n },\n \"gemini-2.5-computer-use-preview-10-2025\": {\n \"input\": 1.25,\n \"output\": 10,\n \"maxInputTokens\": 128000\n },\n \"gemini-flash-latest\": {\n \"input\": 0.3,\n \"output\": 2.5,\n \"cachedInput\": 0.03,\n \"maxInputTokens\": 1048576\n },\n \"gemini-flash-lite-latest\": {\n \"input\": 0.1,\n \"output\": 0.4,\n \"cachedInput\": 0.01,\n \"maxInputTokens\": 1048576\n },\n \"gemini-gemma-2-27b-it\": {\n \"input\": 0.35,\n \"output\": 1.05,\n \"maxInputTokens\": 8192\n },\n \"gemini-gemma-2-9b-it\": {\n \"input\": 0.35,\n \"output\": 1.05,\n \"maxInputTokens\": 8192\n },\n \"deepseek-ai/deepseek-v3.2\": {\n \"input\": 0.28,\n \"output\": 0.4,\n \"maxInputTokens\": 163840\n },\n \"gpt-3.5-turbo-1106\": {\n \"input\": 1,\n \"output\": 2,\n \"maxInputTokens\": 16385\n },\n \"gpt-3.5-turbo-16k\": {\n \"input\": 3,\n \"output\": 4,\n \"maxInputTokens\": 16385\n },\n \"gpt-4-0314\": {\n \"input\": 30,\n \"output\": 60,\n \"maxInputTokens\": 8192\n },\n \"gpt-4-turbo-preview\": {\n \"input\": 10,\n \"output\": 30,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-audio-preview\": {\n \"input\": 2.5,\n \"output\": 10,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-audio-preview-2025-06-03\": {\n \"input\": 2.5,\n \"output\": 10,\n \"maxInputTokens\": 128000\n },\n \"gpt-audio\": {\n \"input\": 2.5,\n \"output\": 10,\n \"maxInputTokens\": 128000\n },\n \"gpt-audio-1.5\": {\n \"input\": 2.5,\n \"output\": 10,\n \"maxInputTokens\": 128000\n },\n \"gpt-audio-mini\": {\n \"input\": 0.6,\n \"output\": 2.4,\n \"maxInputTokens\": 128000\n },\n \"gpt-audio-mini-2025-12-15\": {\n \"input\": 0.6,\n \"output\": 2.4,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-mini-audio-preview\": {\n \"input\": 0.15,\n \"output\": 0.6,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-mini-realtime-preview\": {\n \"input\": 0.6,\n \"output\": 2.4,\n \"cachedInput\": 0.3,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-realtime-preview\": {\n \"input\": 5,\n \"output\": 20,\n \"cachedInput\": 2.5,\n \"maxInputTokens\": 128000\n },\n \"gpt-4o-realtime-preview-2025-06-03\": {\n \"input\": 5,\n \"output\": 20,\n \"cachedInput\": 2.5,\n \"maxInputTokens\": 128000\n },\n \"gpt-image-1.5\": {\n \"input\": 5,\n \"output\": 10,\n \"cachedInput\": 1.25\n },\n \"gpt-image-1.5-2025-12-16\": {\n \"input\": 5,\n \"output\": 10,\n \"cachedInput\": 1.25\n },\n \"gpt-5.1-chat-latest\": {\n \"input\": 1.25,\n \"output\": 10,\n \"cachedInput\": 0.125,\n \"maxInputTokens\": 128000\n },\n \"gpt-5.2-chat-latest\": {\n \"input\": 1.75,\n \"output\": 14,\n \"cachedInput\": 0.175,\n \"maxInputTokens\": 128000\n },\n \"gpt-5.3-chat-latest\": {\n \"input\": 1.75,\n \"output\": 14,\n \"cachedInput\": 0.175,\n \"maxInputTokens\": 128000\n },\n \"gpt-5-pro-2025-10-06\": {\n \"input\": 15,\n \"output\": 120,\n \"maxInputTokens\": 128000\n },\n \"gpt-realtime\": {\n \"input\": 4,\n \"output\": 16,\n \"cachedInput\": 0.4,\n \"maxInputTokens\": 32000\n },\n \"gpt-realtime-1.5\": {\n \"input\": 4,\n \"output\": 16,\n \"cachedInput\": 0.4,\n \"maxInputTokens\": 32000\n },\n \"gpt-realtime-mini\": {\n \"input\": 0.6,\n \"output\": 2.4,\n \"maxInputTokens\": 128000\n },\n \"deepseek-r1-distill-llama-70b\": {\n \"input\": 0.99,\n \"output\": 0.99,\n \"maxInputTokens\": 8000\n },\n \"deepseek-llama3.3-70b\": {\n \"input\": 0.2,\n \"output\": 0.6,\n \"maxInputTokens\": 131072\n },\n \"deepseek-r1-0528\": {\n \"input\": 0.2,\n \"output\": 0.6,\n \"maxInputTokens\": 131072\n },\n \"deepseek-r1-671b\": {\n \"input\": 0.8,\n \"output\": 0.8,\n \"maxInputTokens\": 131072\n },\n \"deepseek-ai/deepseek-r1-distill-llama-8b\": {\n \"input\": 0.025,\n \"output\": 0.025\n },\n \"deepseek-ai/deepseek-r1-distill-qwen-1.5b\": {\n \"input\": 0.09,\n \"output\": 0.09\n },\n \"deepseek-ai/deepseek-r1-distill-qwen-14b\": {\n \"input\": 0.07,\n \"output\": 0.07\n },\n \"deepseek-ai/deepseek-r1-distill-qwen-7b\": {\n \"input\": 0.2,\n \"output\": 0.2\n },\n \"o1\": {\n \"input\": 15,\n \"output\": 60,\n \"cachedInput\": 7.5,\n \"maxInputTokens\": 200000\n },\n \"o1-pro\": {\n \"input\": 150,\n \"output\": 600,\n \"maxInputTokens\": 200000\n },\n \"o1-pro-2025-03-19\": {\n \"input\": 150,\n \"output\": 600,\n \"maxInputTokens\": 200000\n },\n \"o3\": {\n \"input\": 2,\n \"output\": 8,\n \"cachedInput\": 0.5,\n \"maxInputTokens\": 200000\n },\n \"gpt-oss-20b\": {\n \"input\": 0.09,\n \"output\": 0.36\n },\n \"deepseek-ai/deepseek-r1-0528-tput\": {\n \"input\": 0.55,\n \"output\": 2.19,\n \"maxInputTokens\": 128000\n },\n \"claude-3-5-haiku\": {\n \"input\": 1,\n \"output\": 5,\n \"maxInputTokens\": 200000\n },\n \"claude-3-5-haiku@20241022\": {\n \"input\": 1,\n \"output\": 5,\n \"maxInputTokens\": 200000\n },\n \"claude-haiku-4-5@20251001\": {\n \"input\": 1,\n \"output\": 5,\n \"cachedInput\": 0.1,\n \"cacheCreationInput\": 1.25,\n \"maxInputTokens\": 200000\n },\n \"claude-3-5-sonnet\": {\n \"input\": 3,\n \"output\": 15,\n \"maxInputTokens\": 200000\n },\n \"claude-3-5-sonnet@20240620\": {\n \"input\": 3,\n \"output\": 15,\n \"maxInputTokens\": 200000\n },\n \"claude-3-7-sonnet@20250219\": {\n \"input\": 3,\n \"output\": 15,\n \"cachedInput\": 0.3,\n \"cacheCreationInput\": 3.75,\n \"maxInputTokens\": 200000\n },\n \"claude-3-haiku\": {\n \"input\": 0.25,\n \"output\": 1.25,\n \"maxInputTokens\": 200000\n },\n \"claude-3-haiku@20240307\": {\n \"input\": 0.25,\n \"output\": 1.25,\n \"maxInputTokens\": 200000\n },\n \"claude-3-opus\": {\n \"input\": 15,\n \"output\": 75,\n \"maxInputTokens\": 200000\n },\n \"claude-3-opus@20240229\": {\n \"input\": 15,\n \"output\": 75,\n \"maxInputTokens\": 200000\n },\n \"claude-3-sonnet\": {\n \"input\": 3,\n \"output\": 15,\n \"maxInputTokens\": 200000\n },\n \"claude-3-sonnet@20240229\": {\n \"input\": 3,\n \"output\": 15,\n \"maxInputTokens\": 200000\n },\n \"claude-opus-4\": {\n \"input\": 15,\n \"output\": 75,\n \"cachedInput\": 1.5,\n \"cacheCreationInput\": 18.75,\n \"maxInputTokens\": 200000\n },\n \"claude-opus-4-1@20250805\": {\n \"input\": 15,\n \"output\": 75,\n \"cachedInput\": 1.5,\n \"cacheCreationInput\": 18.75,\n \"maxInputTokens\": 200000\n },\n \"claude-opus-4-5@20251101\": {\n \"input\": 5,\n \"output\": 25,\n \"cachedInput\": 0.5,\n \"cacheCreationInput\": 6.25,\n \"maxInputTokens\": 200000\n },\n \"claude-opus-4-6@default\": {\n \"input\": 5,\n \"output\": 25,\n \"cachedInput\": 0.5,\n \"cacheCreationInput\": 6.25,\n \"maxInputTokens\": 1000000\n },\n \"claude-opus-4-7@default\": {\n \"input\": 5,\n \"output\": 25,\n \"cachedInput\": 0.5,\n \"cacheCreationInput\": 6.25,\n \"maxInputTokens\": 1000000\n },\n \"claude-sonnet-4-5@20250929\": {\n \"input\": 3,\n \"output\": 15,\n \"cachedInput\": 0.3,\n \"cacheCreationInput\": 3.75,\n \"maxInputTokens\": 200000\n },\n \"claude-opus-4@20250514\": {\n \"input\": 15,\n \"output\": 75,\n \"cachedInput\": 1.5,\n \"cacheCreationInput\": 18.75,\n \"maxInputTokens\": 200000\n },\n \"claude-sonnet-4\": {\n \"input\": 3,\n \"output\": 15,\n \"cachedInput\": 0.3,\n \"cacheCreationInput\": 3.75,\n \"maxInputTokens\": 1000000\n },\n \"claude-sonnet-4@20250514\": {\n \"input\": 3,\n \"output\": 15,\n \"cachedInput\": 0.3,\n \"cacheCreationInput\": 3.75,\n \"maxInputTokens\": 1000000\n },\n \"deepseek-ai/deepseek-v3.1-maas\": {\n \"input\": 1.35,\n \"output\": 5.4,\n \"maxInputTokens\": 163840\n },\n \"deepseek-ai/deepseek-v3.2-maas\": {\n \"input\": 0.56,\n \"output\": 1.68,\n \"maxInputTokens\": 163840\n },\n \"deepseek-ai/deepseek-r1-0528-maas\": {\n \"input\": 1.35,\n \"output\": 5.4,\n \"maxInputTokens\": 65336\n },\n \"deepseek-ai/deepseek-ocr-maas\": {\n \"input\": 0.3,\n \"output\": 1.2\n },\n \"deepseek-r1-8b\": {\n \"input\": 0.1,\n \"output\": 0.2,\n \"maxInputTokens\": 65536\n },\n \"deepseek-r1-7b-qwen\": {\n \"input\": 0.08,\n \"output\": 0.15,\n \"maxInputTokens\": 131072\n },\n \"deepseek-coder-6.7b\": {\n \"input\": 0.06,\n \"output\": 0.12,\n \"maxInputTokens\": 16384\n },\n \"gpt-4o-mini-transcribe-2025-03-20\": {\n \"input\": 1.25,\n \"output\": 5,\n \"maxInputTokens\": 16000\n },\n \"gpt-4o-mini-transcribe-2025-12-15\": {\n \"input\": 1.25,\n \"output\": 5,\n \"maxInputTokens\": 16000\n },\n \"gpt-realtime-mini-2025-12-15\": {\n \"input\": 0.6,\n \"output\": 2.4,\n \"cachedInput\": 0.06,\n \"maxInputTokens\": 128000\n },\n \"gemini-2.5-flash-native-audio-latest\": {\n \"input\": 0.3,\n \"output\": 2.5,\n \"maxInputTokens\": 1048576\n },\n \"gemini-2.5-flash-native-audio-preview-09-2025\": {\n \"input\": 0.3,\n \"output\": 2.5,\n \"maxInputTokens\": 1048576\n },\n \"gemini-2.5-flash-native-audio-preview-12-2025\": {\n \"input\": 0.3,\n \"output\": 2.5,\n \"maxInputTokens\": 1048576\n },\n \"gemini-3.1-flash-live-preview\": {\n \"input\": 0.75,\n \"output\": 4.5,\n \"maxInputTokens\": 131072\n },\n \"gemini-pro-latest\": {\n \"input\": 1.25,\n \"output\": 10,\n \"cachedInput\": 0.125,\n \"maxInputTokens\": 1048576\n },\n \"gemini-exp-1206\": {\n \"input\": 0.3,\n \"output\": 2.5,\n \"cachedInput\": 0.03,\n \"maxInputTokens\": 1048576\n },\n \"claude-sonnet-4-6@default\": {\n \"input\": 3,\n \"output\": 15,\n \"cachedInput\": 0.3,\n \"cacheCreationInput\": 3.75,\n \"maxInputTokens\": 1000000\n }\n }\n}\n","import { createServer } from 'node:http'\nimport type { IncomingMessage, ServerResponse } from 'node:http'\nimport { getDashboardData, getFingerprint } from './data.js'\nimport { getHtml } from './html.js'\nimport type { IStorage } from '../types/index.js'\n\nexport function startDashboardServer(storage: IStorage, port: number): void {\n const server = createServer((req: IncomingMessage, res: ServerResponse) => {\n const url = new URL(req.url ?? '/', `http://localhost:${port}`)\n\n if (req.method === 'GET' && url.pathname === '/') {\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' })\n res.end(getHtml(port))\n return\n }\n\n if (req.method === 'GET' && url.pathname === '/events') {\n const filter = url.searchParams.get('filter') ?? '24h'\n\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n 'X-Accel-Buffering': 'no',\n })\n res.flushHeaders()\n\n let lastFingerprint = ''\n\n async function sendData(): Promise<void> {\n try {\n const data = await getDashboardData(storage, filter)\n const fp = getFingerprint(data)\n if (fp !== lastFingerprint) {\n lastFingerprint = fp\n res.write(`data: ${JSON.stringify(data)}\\n\\n`)\n }\n } catch {\n // best-effort — storage errors must not crash the server\n }\n }\n\n // Send immediately on connect\n void sendData()\n\n const timer = setInterval(() => { void sendData() }, 3000)\n\n res.on('close', () => {\n clearInterval(timer)\n })\n return\n }\n\n res.writeHead(404, { 'Content-Type': 'text/plain' })\n res.end('Not found')\n })\n\n server.on('error', (err: NodeJS.ErrnoException) => {\n if (err.code === 'EADDRINUSE') {\n console.error(`[tokenwatch] Port ${port} is already in use. Try: tokenwatch dashboard --port <other>`)\n process.exit(1)\n }\n throw err\n })\n\n server.listen(port, () => {\n console.log(`tokenwatch dashboard → http://localhost:${port}`)\n })\n}\n","import type {\n IStorage,\n UsageEntry,\n Report,\n CostForecast,\n ModelStats,\n SessionStats,\n UserStats,\n FeatureStats,\n} from '../types/index.js'\n\nexport interface TimeSeriesBucket {\n bucket: string\n cost: number\n calls: number\n}\n\nexport interface DashboardData {\n report: Report\n forecast: CostForecast\n timeSeries: TimeSeriesBucket[]\n lastUpdated: string\n}\n\n/**\n * Maps a filter string to a Unix ms timestamp (entries before this are excluded).\n * Returns undefined for 'all' or undefined (no filter).\n */\nexport function parseSince(filter: string | undefined): number | undefined {\n if (!filter || filter === 'all') return undefined\n const now = Date.now()\n switch (filter) {\n case '1h': return now - 60 * 60 * 1000\n case '24h': return now - 24 * 60 * 60 * 1000\n case '7d': return now - 7 * 24 * 60 * 60 * 1000\n case '30d': return now - 30 * 24 * 60 * 60 * 1000\n default: return undefined\n }\n}\n\n/**\n * Groups entries into time-series buckets.\n * Bucket size: 1h window → 5min, 24h window → 1h, 7d/30d/all → 1day.\n */\nexport function buildTimeSeries(\n entries: UsageEntry[],\n sinceMs: number | undefined,\n): TimeSeriesBucket[] {\n const now = Date.now()\n const windowMs = sinceMs !== undefined ? now - sinceMs : undefined\n\n let bucketMs: number\n if (windowMs !== undefined && windowMs <= 60 * 60 * 1000) {\n bucketMs = 5 * 60 * 1000 // 5-min buckets for ≤1h window\n } else if (windowMs !== undefined && windowMs <= 24 * 60 * 60 * 1000) {\n bucketMs = 60 * 60 * 1000 // 1h buckets for ≤24h window\n } else {\n bucketMs = 24 * 60 * 60 * 1000 // 1-day buckets for 7d/30d/all\n }\n\n const filtered = sinceMs !== undefined\n ? entries.filter((e) => new Date(e.timestamp).getTime() >= sinceMs)\n : entries\n\n const buckets = new Map<string, TimeSeriesBucket>()\n\n for (const entry of filtered) {\n const ts = new Date(entry.timestamp).getTime()\n const bucketTs = Math.floor(ts / bucketMs) * bucketMs\n const bucketKey = new Date(bucketTs).toISOString()\n const existing = buckets.get(bucketKey)\n if (existing) {\n existing.cost += entry.costUSD\n existing.calls += 1\n } else {\n buckets.set(bucketKey, { bucket: bucketKey, cost: entry.costUSD, calls: 1 })\n }\n }\n\n return Array.from(buckets.values()).sort((a, b) => a.bucket.localeCompare(b.bucket))\n}\n\nexport function getFingerprint(data: DashboardData): string {\n return `${data.report.totalCostUSD.toFixed(8)}-${data.report.totalTokens.input}-${data.timeSeries.length}`\n}\n\nexport async function getDashboardData(\n storage: IStorage,\n filter?: string,\n): Promise<DashboardData> {\n const allEntries = await Promise.resolve(storage.getAll())\n const sinceMs = parseSince(filter)\n\n const entries = sinceMs !== undefined\n ? allEntries.filter((e) => new Date(e.timestamp).getTime() >= sinceMs)\n : allEntries\n\n // ── Build report ────────────────────────────────────────────────────────────\n const byModel: Record<string, ModelStats> = {}\n const bySession: Record<string, SessionStats> = {}\n const byUser: Record<string, UserStats> = {}\n const byFeature: Record<string, FeatureStats> = {}\n let totalInput = 0\n let totalOutput = 0\n let totalCost = 0\n\n for (const e of entries) {\n totalInput += e.inputTokens + (e.cachedTokens ?? 0) + (e.cacheCreationTokens ?? 0)\n totalOutput += e.outputTokens\n totalCost += e.costUSD\n\n const m = (byModel[e.model] ??= {\n costUSD: 0, calls: 0, tokens: { input: 0, output: 0, reasoning: 0, cached: 0 },\n })\n m.costUSD += e.costUSD\n m.calls += 1\n m.tokens.input += e.inputTokens + (e.cachedTokens ?? 0) + (e.cacheCreationTokens ?? 0)\n m.tokens.output += e.outputTokens\n m.tokens.reasoning += e.reasoningTokens ?? 0\n m.tokens.cached += e.cachedTokens ?? 0\n\n if (e.sessionId) {\n const s = (bySession[e.sessionId] ??= { costUSD: 0, calls: 0 })\n s.costUSD += e.costUSD\n s.calls += 1\n }\n\n if (e.userId) {\n const u = (byUser[e.userId] ??= { costUSD: 0, calls: 0 })\n u.costUSD += e.costUSD\n u.calls += 1\n }\n\n if (e.feature) {\n const f = (byFeature[e.feature] ??= { costUSD: 0, calls: 0 })\n f.costUSD += e.costUSD\n f.calls += 1\n }\n }\n\n const now = new Date().toISOString()\n const periodFrom = entries[0]?.timestamp ?? now\n const periodTo = entries[entries.length - 1]?.timestamp ?? now\n\n const report: Report = {\n totalCostUSD: totalCost,\n totalTokens: { input: totalInput, output: totalOutput },\n byModel,\n bySession,\n byUser,\n byFeature,\n period: { from: periodFrom, to: periodTo },\n }\n\n // ── Build forecast (always 24h window over all entries) ─────────────────────\n const forecastWindowMs = 24 * 60 * 60 * 1000\n const windowStart = Date.now() - forecastWindowMs\n const windowEntries = allEntries.filter(\n (e) => new Date(e.timestamp).getTime() >= windowStart,\n )\n\n let forecast: CostForecast\n if (windowEntries.length < 2) {\n forecast = {\n burnRatePerHour: 0,\n projectedDailyCostUSD: 0,\n projectedMonthlyCostUSD: 0,\n basedOnHours: 0,\n basedOnPeriod: null,\n }\n } else {\n const first = windowEntries[0]?.timestamp ?? ''\n const last = windowEntries[windowEntries.length - 1]?.timestamp ?? ''\n const actualMs = new Date(last).getTime() - new Date(first).getTime()\n const actualHours = actualMs / (1000 * 60 * 60)\n if (actualHours < 0.001) {\n forecast = {\n burnRatePerHour: 0,\n projectedDailyCostUSD: 0,\n projectedMonthlyCostUSD: 0,\n basedOnHours: 0,\n basedOnPeriod: { from: first, to: last },\n }\n } else {\n const windowCost = windowEntries.reduce((s, e) => s + e.costUSD, 0)\n const burnRatePerHour = windowCost / actualHours\n forecast = {\n burnRatePerHour,\n projectedDailyCostUSD: burnRatePerHour * 24,\n projectedMonthlyCostUSD: burnRatePerHour * 24 * 30,\n basedOnHours: Math.round(actualHours * 100) / 100,\n basedOnPeriod: { from: first, to: last },\n }\n }\n }\n\n const timeSeries = buildTimeSeries(allEntries, sinceMs)\n\n return { report, forecast, timeSeries, lastUpdated: now }\n}\n","export function getHtml(port: number): string {\n void port // port is used in the SSE URL in the JS below\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\" />\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n<title>tokenwatch dashboard</title>\n<script src=\"https://cdn.jsdelivr.net/npm/chart.js@4/dist/chart.umd.min.js\"></script>\n<style>\n*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }\n\n:root {\n --bg: #0d1117;\n --surface: #161b22;\n --border: #30363d;\n --text: #e6edf3;\n --muted: #8b949e;\n --accent: #58a6ff;\n --green: #3fb950;\n --yellow: #d29922;\n --red: #f85149;\n --r: 6px;\n}\n\nbody {\n background: var(--bg);\n color: var(--text);\n font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\n font-size: 14px;\n line-height: 1.5;\n min-height: 100vh;\n}\n\n.container { max-width: 1200px; margin: 0 auto; padding: 24px 16px; }\n\n/* ── Header ──────────────────────────────────────────────────── */\nheader {\n display: flex;\n align-items: center;\n justify-content: space-between;\n margin-bottom: 24px;\n}\nheader h1 { font-size: 18px; font-weight: 600; letter-spacing: -0.3px; }\nheader h1 span { color: var(--accent); }\n\n.live-badge {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n color: var(--muted);\n}\n.live-dot {\n width: 8px; height: 8px;\n border-radius: 50%;\n background: var(--green);\n animation: pulse 2s ease-in-out infinite;\n}\n@keyframes pulse {\n 0%, 100% { opacity: 1; }\n 50% { opacity: 0.3; }\n}\n\n/* ── Tabs ─────────────────────────────────────────────────────── */\n.tabs {\n display: flex;\n gap: 4px;\n margin-bottom: 24px;\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: var(--r);\n padding: 4px;\n width: fit-content;\n}\n.tab {\n padding: 6px 14px;\n border-radius: calc(var(--r) - 2px);\n border: none;\n background: transparent;\n color: var(--muted);\n font-size: 13px;\n font-weight: 500;\n cursor: pointer;\n transition: background 0.15s, color 0.15s;\n}\n.tab:hover { color: var(--text); background: rgba(255,255,255,0.05); }\n.tab.active { background: var(--accent); color: #fff; }\n\n/* ── Overview cards ───────────────────────────────────────────── */\n.cards {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));\n gap: 12px;\n margin-bottom: 24px;\n}\n.card {\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: var(--r);\n padding: 16px;\n}\n.card-label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--muted); margin-bottom: 6px; }\n.card-value { font-size: 22px; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; }\n.card-sub { font-size: 11px; color: var(--muted); margin-top: 3px; }\n\n/* ── Chart section ────────────────────────────────────────────── */\n.charts {\n display: grid;\n grid-template-columns: 2fr 1fr;\n gap: 16px;\n margin-bottom: 24px;\n}\n@media (max-width: 768px) { .charts { grid-template-columns: 1fr; } }\n\n.panel {\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: var(--r);\n padding: 16px;\n}\n.panel-title {\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--muted);\n margin-bottom: 14px;\n}\n.chart-wrap { position: relative; height: 220px; }\n\n/* ── Breakdown tables ─────────────────────────────────────────── */\n.section { margin-bottom: 24px; }\n.section-title {\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--muted);\n margin-bottom: 10px;\n}\n\ntable {\n width: 100%;\n border-collapse: collapse;\n background: var(--surface);\n border: 1px solid var(--border);\n border-radius: var(--r);\n overflow: hidden;\n font-size: 13px;\n}\nthead { background: rgba(255,255,255,0.03); }\nth {\n padding: 10px 14px;\n text-align: left;\n font-weight: 600;\n color: var(--muted);\n font-size: 11px;\n text-transform: uppercase;\n letter-spacing: 0.4px;\n border-bottom: 1px solid var(--border);\n}\nth.num, td.num { text-align: right; }\ntd {\n padding: 10px 14px;\n border-bottom: 1px solid rgba(48,54,61,0.5);\n font-variant-numeric: tabular-nums;\n color: var(--text);\n}\ntbody tr:last-child td { border-bottom: none; }\ntbody tr:hover td { background: rgba(255,255,255,0.02); }\n\n.bar-wrap { width: 80px; height: 6px; background: var(--border); border-radius: 3px; display: inline-block; vertical-align: middle; margin-left: 8px; }\n.bar-fill { height: 100%; border-radius: 3px; background: var(--accent); }\n\n/* ── Forecast ─────────────────────────────────────────────────── */\n.forecast-grid {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));\n gap: 12px;\n}\n\n/* ── Empty state ──────────────────────────────────────────────── */\n.empty {\n color: var(--muted);\n font-size: 13px;\n padding: 20px 0;\n text-align: center;\n}\n\n/* ── Collapsible ─────────────────────────────────────────────── */\ndetails summary {\n cursor: pointer;\n list-style: none;\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: 12px;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.5px;\n color: var(--muted);\n margin-bottom: 10px;\n user-select: none;\n}\ndetails summary::before { content: '▶'; font-size: 10px; transition: transform 0.15s; }\ndetails[open] summary::before { transform: rotate(90deg); }\n\n/* ── Last updated ─────────────────────────────────────────────── */\n.footer {\n font-size: 11px;\n color: var(--muted);\n text-align: center;\n padding: 16px 0 0;\n}\n</style>\n</head>\n<body>\n<div class=\"container\">\n\n <header>\n <h1>token<span>watch</span></h1>\n <div class=\"live-badge\">\n <div class=\"live-dot\"></div>\n <span id=\"live-label\">live</span>\n </div>\n </header>\n\n <div class=\"tabs\">\n <button class=\"tab\" data-filter=\"1h\">1h</button>\n <button class=\"tab active\" data-filter=\"24h\">24h</button>\n <button class=\"tab\" data-filter=\"7d\">7d</button>\n <button class=\"tab\" data-filter=\"30d\">30d</button>\n <button class=\"tab\" data-filter=\"all\">All</button>\n </div>\n\n <div class=\"cards\">\n <div class=\"card\">\n <div class=\"card-label\">Total Cost</div>\n <div class=\"card-value\" id=\"card-cost\">—</div>\n <div class=\"card-sub\" id=\"card-period\"></div>\n </div>\n <div class=\"card\">\n <div class=\"card-label\">Input Tokens</div>\n <div class=\"card-value\" id=\"card-input\">—</div>\n </div>\n <div class=\"card\">\n <div class=\"card-label\">Output Tokens</div>\n <div class=\"card-value\" id=\"card-output\">—</div>\n </div>\n <div class=\"card\">\n <div class=\"card-label\">Total Calls</div>\n <div class=\"card-value\" id=\"card-calls\">—</div>\n </div>\n <div class=\"card\">\n <div class=\"card-label\">Burn Rate</div>\n <div class=\"card-value\" id=\"card-burn\">—</div>\n <div class=\"card-sub\">per hour</div>\n </div>\n </div>\n\n <div class=\"charts\">\n <div class=\"panel\">\n <div class=\"panel-title\">Cost over time</div>\n <div class=\"chart-wrap\">\n <canvas id=\"chart-line\"></canvas>\n </div>\n </div>\n <div class=\"panel\">\n <div class=\"panel-title\">By model</div>\n <div class=\"chart-wrap\">\n <canvas id=\"chart-doughnut\"></canvas>\n </div>\n </div>\n </div>\n\n <div class=\"section\">\n <div class=\"section-title\">Model breakdown</div>\n <div id=\"model-table-wrap\"></div>\n </div>\n\n <details id=\"users-section\" style=\"margin-bottom:24px;\">\n <summary>By user</summary>\n <div id=\"user-table-wrap\"></div>\n </details>\n\n <details id=\"features-section\" style=\"margin-bottom:24px;\">\n <summary>By feature</summary>\n <div id=\"feature-table-wrap\"></div>\n </details>\n\n <div class=\"section\">\n <div class=\"section-title\">Cost forecast</div>\n <div class=\"forecast-grid\">\n <div class=\"card\">\n <div class=\"card-label\">Projected daily</div>\n <div class=\"card-value\" id=\"fc-daily\">—</div>\n <div class=\"card-sub\" id=\"fc-window\"></div>\n </div>\n <div class=\"card\">\n <div class=\"card-label\">Projected monthly</div>\n <div class=\"card-value\" id=\"fc-monthly\">—</div>\n </div>\n <div class=\"card\">\n <div class=\"card-label\">Burn rate / hr</div>\n <div class=\"card-value\" id=\"fc-burn\">—</div>\n </div>\n </div>\n </div>\n\n <div class=\"footer\" id=\"footer-updated\"></div>\n\n</div><!-- /container -->\n\n<script>\n(function () {\n 'use strict';\n\n // ── Palette ───────────────────────────────────────────────────────────\n const PALETTE = [\n '#58a6ff','#3fb950','#f78166','#d29922','#bc8cff',\n '#79c0ff','#56d364','#ffa657','#ff7b72','#a5d6ff',\n ];\n\n // ── State ─────────────────────────────────────────────────────────────\n let evtSource = null;\n let activeFilter = '24h';\n let lineChart = null;\n let doughnutChart = null;\n\n // ── Helpers ───────────────────────────────────────────────────────────\n function escHtml(str) {\n return String(str)\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"');\n }\n\n function fmtUSD(n) {\n if (n === 0) return '$0.00';\n if (n < 0.001) return '$' + n.toFixed(6);\n if (n < 1) return '$' + n.toFixed(4);\n return '$' + n.toFixed(2);\n }\n\n function fmtNum(n) {\n return n.toLocaleString('en-US');\n }\n\n function fmtDate(iso) {\n try { return new Date(iso).toLocaleString(); } catch { return iso; }\n }\n\n function totalCalls(byModel) {\n return Object.values(byModel).reduce(function(s, m) { return s + m.calls; }, 0);\n }\n\n // ── Tab setup ─────────────────────────────────────────────────────────\n document.querySelectorAll('.tab').forEach(function(btn) {\n btn.addEventListener('click', function() {\n document.querySelectorAll('.tab').forEach(function(b) { b.classList.remove('active'); });\n btn.classList.add('active');\n activeFilter = btn.dataset.filter;\n reconnect();\n });\n });\n\n // ── SSE ───────────────────────────────────────────────────────────────\n function reconnect() {\n if (evtSource) { evtSource.close(); evtSource = null; }\n evtSource = new EventSource('/events?filter=' + encodeURIComponent(activeFilter));\n evtSource.onmessage = function(e) {\n try { updateUI(JSON.parse(e.data)); } catch (_) {}\n };\n evtSource.onerror = function() {\n document.getElementById('live-label').textContent = 'reconnecting…';\n };\n evtSource.onopen = function() {\n document.getElementById('live-label').textContent = 'live';\n };\n }\n\n // ── UI update ─────────────────────────────────────────────────────────\n function updateUI(data) {\n const r = data.report;\n const fc = data.forecast;\n const ts = data.timeSeries;\n\n // Cards\n document.getElementById('card-cost').textContent = fmtUSD(r.totalCostUSD);\n document.getElementById('card-input').textContent = fmtNum(r.totalTokens.input);\n document.getElementById('card-output').textContent = fmtNum(r.totalTokens.output);\n document.getElementById('card-calls').textContent = fmtNum(totalCalls(r.byModel));\n document.getElementById('card-burn').textContent = fmtUSD(fc.burnRatePerHour);\n document.getElementById('card-period').textContent =\n r.period.from !== r.period.to\n ? fmtDate(r.period.from) + ' – ' + fmtDate(r.period.to)\n : '';\n\n // Line chart\n const labels = ts.map(function(b) {\n try { return new Date(b.bucket).toLocaleTimeString([], {hour:'2-digit', minute:'2-digit'}); }\n catch { return b.bucket; }\n });\n const costs = ts.map(function(b) { return b.cost; });\n\n if (!lineChart) {\n const ctx = document.getElementById('chart-line').getContext('2d');\n lineChart = new Chart(ctx, {\n type: 'line',\n data: {\n labels: labels,\n datasets: [{\n label: 'Cost (USD)',\n data: costs,\n borderColor: '#58a6ff',\n backgroundColor: 'rgba(88,166,255,0.08)',\n borderWidth: 2,\n pointRadius: 3,\n pointBackgroundColor: '#58a6ff',\n fill: true,\n tension: 0.3,\n }],\n },\n options: {\n responsive: true, maintainAspectRatio: false,\n plugins: { legend: { display: false } },\n scales: {\n x: { ticks: { color: '#8b949e', maxTicksLimit: 8 }, grid: { color: '#21262d' } },\n y: {\n ticks: {\n color: '#8b949e',\n callback: function(v) { return '$' + Number(v).toFixed(4); },\n },\n grid: { color: '#21262d' },\n },\n },\n },\n });\n } else {\n lineChart.data.labels = labels;\n lineChart.data.datasets[0].data = costs;\n lineChart.update('none');\n }\n\n // Doughnut chart\n const modelEntries = Object.entries(r.byModel);\n const dLabels = modelEntries.map(function(x) { return x[0]; });\n const dData = modelEntries.map(function(x) { return x[1].costUSD; });\n const dColors = dLabels.map(function(_, i) { return PALETTE[i % PALETTE.length]; });\n\n if (!doughnutChart) {\n const ctx2 = document.getElementById('chart-doughnut').getContext('2d');\n doughnutChart = new Chart(ctx2, {\n type: 'doughnut',\n data: { labels: dLabels, datasets: [{ data: dData, backgroundColor: dColors, borderWidth: 0, hoverOffset: 4 }] },\n options: {\n responsive: true, maintainAspectRatio: false,\n cutout: '65%',\n plugins: {\n legend: {\n position: 'bottom',\n labels: { color: '#8b949e', boxWidth: 10, padding: 12, font: { size: 11 } },\n },\n },\n },\n });\n } else {\n doughnutChart.data.labels = dLabels;\n doughnutChart.data.datasets[0].data = dData;\n doughnutChart.data.datasets[0].backgroundColor = dColors;\n doughnutChart.update('none');\n }\n\n // Model table\n const modelWrap = document.getElementById('model-table-wrap');\n if (modelEntries.length === 0) {\n modelWrap.innerHTML = '<p class=\"empty\">No data for this period.</p>';\n } else {\n const totalCost = r.totalCostUSD || 1;\n let html = '<table><thead><tr>' +\n '<th>Model</th>' +\n '<th class=\"num\">Calls</th>' +\n '<th class=\"num\">In tokens</th>' +\n '<th class=\"num\">Out tokens</th>' +\n '<th class=\"num\">Cost</th>' +\n '<th class=\"num\">Share</th>' +\n '</tr></thead><tbody>';\n const sorted = modelEntries.slice().sort(function(a, b) { return b[1].costUSD - a[1].costUSD; });\n sorted.forEach(function(entry) {\n const name = entry[0]; const m = entry[1];\n const pct = (m.costUSD / totalCost * 100).toFixed(1);\n const barW = Math.round(m.costUSD / totalCost * 80);\n html += '<tr>' +\n '<td>' + escHtml(name) + '</td>' +\n '<td class=\"num\">' + fmtNum(m.calls) + '</td>' +\n '<td class=\"num\">' + fmtNum(m.tokens.input) + '</td>' +\n '<td class=\"num\">' + fmtNum(m.tokens.output) + '</td>' +\n '<td class=\"num\">' + fmtUSD(m.costUSD) + '</td>' +\n '<td class=\"num\">' + pct + '%' +\n '<span class=\"bar-wrap\"><span class=\"bar-fill\" style=\"width:' + barW + 'px\"></span></span>' +\n '</td></tr>';\n });\n html += '</tbody></table>';\n modelWrap.innerHTML = html;\n }\n\n // User table\n const userEntries = Object.entries(r.byUser);\n const usersSection = document.getElementById('users-section');\n usersSection.style.display = userEntries.length === 0 ? 'none' : '';\n if (userEntries.length > 0) {\n let html = '<table><thead><tr><th>User</th><th class=\"num\">Calls</th><th class=\"num\">Cost</th></tr></thead><tbody>';\n userEntries.slice().sort(function(a,b) { return b[1].costUSD - a[1].costUSD; }).forEach(function(e) {\n html += '<tr><td>' + escHtml(e[0]) + '</td><td class=\"num\">' + fmtNum(e[1].calls) + '</td><td class=\"num\">' + fmtUSD(e[1].costUSD) + '</td></tr>';\n });\n html += '</tbody></table>';\n document.getElementById('user-table-wrap').innerHTML = html;\n }\n\n // Feature table\n const featureEntries = Object.entries(r.byFeature);\n const featuresSection = document.getElementById('features-section');\n featuresSection.style.display = featureEntries.length === 0 ? 'none' : '';\n if (featureEntries.length > 0) {\n let html = '<table><thead><tr><th>Feature</th><th class=\"num\">Calls</th><th class=\"num\">Cost</th></tr></thead><tbody>';\n featureEntries.slice().sort(function(a,b) { return b[1].costUSD - a[1].costUSD; }).forEach(function(e) {\n html += '<tr><td>' + escHtml(e[0]) + '</td><td class=\"num\">' + fmtNum(e[1].calls) + '</td><td class=\"num\">' + fmtUSD(e[1].costUSD) + '</td></tr>';\n });\n html += '</tbody></table>';\n document.getElementById('feature-table-wrap').innerHTML = html;\n }\n\n // Forecast\n document.getElementById('fc-daily').textContent = fmtUSD(fc.projectedDailyCostUSD);\n document.getElementById('fc-monthly').textContent = fmtUSD(fc.projectedMonthlyCostUSD);\n document.getElementById('fc-burn').textContent = fmtUSD(fc.burnRatePerHour);\n document.getElementById('fc-window').textContent =\n fc.basedOnHours > 0 ? 'based on ' + fc.basedOnHours.toFixed(1) + 'h of data' : 'insufficient data';\n\n // Footer\n document.getElementById('footer-updated').textContent =\n 'Last updated: ' + fmtDate(data.lastUpdated);\n }\n\n // ── Boot ──────────────────────────────────────────────────────────────\n reconnect();\n})();\n</script>\n</body>\n</html>`\n}\n"],"mappings":"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AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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","names":["existsSync","join","homedir","homedir","join","bundledPrices","DB_PATH","join","homedir","existsSync"]}
|