claude-monitor
Version:
Real-time terminal monitoring tool for Claude AI token usage
111 lines • 4.55 kB
JavaScript
import { CostMode } from '../types/index.js';
import { normalizeModelName } from '../types/index.js';
const FALLBACK_PRICING = {
opus: {
inputPricePerMillion: 15.0,
outputPricePerMillion: 75.0,
cacheCreationPricePerMillion: 18.75,
cacheReadPricePerMillion: 1.5,
},
sonnet: {
inputPricePerMillion: 3.0,
outputPricePerMillion: 15.0,
cacheCreationPricePerMillion: 3.75,
cacheReadPricePerMillion: 0.3,
},
haiku: {
inputPricePerMillion: 0.25,
outputPricePerMillion: 1.25,
cacheCreationPricePerMillion: 0.3,
cacheReadPricePerMillion: 0.03,
},
};
export class PricingCalculator {
pricing;
costCache = new Map();
constructor(customPricing) {
this.pricing = customPricing || {
'claude-3-opus': FALLBACK_PRICING.opus,
'claude-3-sonnet': FALLBACK_PRICING.sonnet,
'claude-3-haiku': FALLBACK_PRICING.haiku,
'claude-3-5-sonnet': FALLBACK_PRICING.sonnet,
'claude-3-5-haiku': FALLBACK_PRICING.haiku,
'claude-sonnet-4-20250514': FALLBACK_PRICING.sonnet,
'claude-opus-4-20250514': FALLBACK_PRICING.opus,
};
}
calculateCost(params) {
const { model, inputTokens = 0, outputTokens = 0, cacheCreationTokens = 0, cacheReadTokens = 0, tokens, strict = false, } = params;
if (model === '<synthetic>') {
return 0.0;
}
const actualInputTokens = tokens?.inputTokens ?? inputTokens;
const actualOutputTokens = tokens?.outputTokens ?? outputTokens;
const actualCacheCreationTokens = tokens?.cacheCreationTokens ?? cacheCreationTokens;
const actualCacheReadTokens = tokens?.cacheReadTokens ?? cacheReadTokens;
const cacheKey = `${model}:${actualInputTokens}:${actualOutputTokens}:${actualCacheCreationTokens}:${actualCacheReadTokens}`;
const cachedCost = this.costCache.get(cacheKey);
if (cachedCost !== undefined) {
return cachedCost;
}
const pricing = this.getPricingForModel(model, strict);
const cost = (actualInputTokens / 1_000_000) * pricing.inputPricePerMillion +
(actualOutputTokens / 1_000_000) * pricing.outputPricePerMillion +
(actualCacheCreationTokens / 1_000_000) * pricing.cacheCreationPricePerMillion +
(actualCacheReadTokens / 1_000_000) * pricing.cacheReadPricePerMillion;
const roundedCost = Math.round(cost * 1_000_000) / 1_000_000;
this.costCache.set(cacheKey, roundedCost);
return roundedCost;
}
getPricingForModel(model, strict) {
const normalized = normalizeModelName(model);
if (normalized in this.pricing) {
return this.pricing[normalized];
}
if (model in this.pricing) {
return this.pricing[model];
}
if (strict) {
throw new Error(`Unknown model: ${model}`);
}
const modelLower = model.toLowerCase();
if (modelLower.includes('opus')) {
return FALLBACK_PRICING.opus;
}
if (modelLower.includes('haiku')) {
return FALLBACK_PRICING.haiku;
}
return FALLBACK_PRICING.sonnet;
}
calculateCostForEntry(entryData, mode) {
if (mode === CostMode.CACHED) {
const costValue = entryData.costUSD ?? entryData.cost_usd;
if (costValue !== null && costValue !== undefined) {
return Number(costValue);
}
}
const model = (entryData.model ?? entryData.Model);
if (!model) {
throw new Error("Missing 'model' key in entry data");
}
const inputTokens = Number(entryData.inputTokens ?? entryData.input_tokens ?? 0);
const outputTokens = Number(entryData.outputTokens ?? entryData.output_tokens ?? 0);
const cacheCreationTokens = Number(entryData.cacheCreationInputTokens ?? entryData.cache_creation_tokens ?? 0);
const cacheReadTokens = Number(entryData.cacheReadInputTokens ??
entryData.cache_read_input_tokens ??
entryData.cache_read_tokens ??
0);
return this.calculateCost({
model,
inputTokens,
outputTokens,
cacheCreationTokens,
cacheReadTokens,
});
}
clearCache() {
this.costCache.clear();
}
}
export const defaultPricingCalculator = new PricingCalculator();
//# sourceMappingURL=pricing.js.map