perf-lens
Version:
AI-powered frontend performance optimizer
63 lines (62 loc) • 2.19 kB
JavaScript
// USD per million tokens. Cache read = 0.1x input, cache write (5m TTL) = 1.25x input.
const PRICING = {
'claude-opus-4-8': { input: 5, output: 25 },
'claude-sonnet-5': { input: 3, output: 15 },
'claude-haiku-4-5': { input: 1, output: 5 },
};
// ponytail: module-level accumulator; fine for a single-run CLI process
const totals = {
inputTokens: 0,
outputTokens: 0,
cacheReadTokens: 0,
cacheWriteTokens: 0,
costUsd: 0,
costKnown: true,
calls: 0,
};
/**
* Records token usage from an API response and accumulates estimated cost.
*/
export function recordUsage(model, usage) {
const input = usage.input_tokens ?? 0;
const output = usage.output_tokens ?? 0;
const cacheRead = usage.cache_read_input_tokens ?? 0;
const cacheWrite = usage.cache_creation_input_tokens ?? 0;
totals.inputTokens += input;
totals.outputTokens += output;
totals.cacheReadTokens += cacheRead;
totals.cacheWriteTokens += cacheWrite;
totals.calls += 1;
const pricing = PRICING[Object.keys(PRICING).find(id => model.startsWith(id)) ?? ''];
if (!pricing) {
totals.costKnown = false;
return;
}
totals.costUsd +=
(input * pricing.input +
output * pricing.output +
cacheRead * pricing.input * 0.1 +
cacheWrite * pricing.input * 1.25) /
1000000;
}
/**
* One-line usage summary printed at the end of a scan.
*/
export function getCostSummary() {
if (totals.calls === 0)
return '';
const tokens = `${totals.inputTokens.toLocaleString()} in / ${totals.outputTokens.toLocaleString()} out`;
const cache = totals.cacheReadTokens > 0 ? `, ${totals.cacheReadTokens.toLocaleString()} cached` : '';
const cost = totals.costKnown ? `$${totals.costUsd.toFixed(4)}` : 'unknown (unrecognized model)';
return `AI usage: ${totals.calls} calls, ${tokens}${cache} tokens — estimated cost ${cost}`;
}
/** Test hook. */
export function resetUsage() {
totals.inputTokens = 0;
totals.outputTokens = 0;
totals.cacheReadTokens = 0;
totals.cacheWriteTokens = 0;
totals.costUsd = 0;
totals.costKnown = true;
totals.calls = 0;
}