-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathusage.mjs
More file actions
92 lines (78 loc) · 4.62 KB
/
Copy pathusage.mjs
File metadata and controls
92 lines (78 loc) · 4.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
const MODEL_PRICING = {
'gpt-5.6-luna': { input: 200n, cached: 20n, output: 1_200n },
'gpt-5.6-terra': { input: 2_000n, cached: 200n, output: 12_000n },
'gpt-5.6-sol': { input: 5_000n, cached: 500n, output: 30_000n },
};
const DEFAULT_MODEL = 'gpt-5.6-luna';
const JUMBO_PROMPT_THRESHOLD = 272_000;
const NANO_DOLLARS_PER_DISPLAY_UNIT = 1_000_000n;
const JUMBO_WARNING = '\u001b[91mLong-context pricing applied\u001b[0m';
export function normalizeUsage({ inputTokens = 0, cachedTokens = 0, outputTokens = 0 } = {}) {
const totalInputTokens = Number(inputTokens ?? 0);
const totalCachedTokens = Number(cachedTokens ?? 0);
const hiddenInputTokens = Math.max(totalInputTokens - totalCachedTokens, 0);
return { inputTokens: hiddenInputTokens, cachedTokens: totalCachedTokens, outputTokens: Number(outputTokens ?? 0) };
}
export function getModelPricing(model = DEFAULT_MODEL) {
return MODEL_PRICING[String(model || '').toLowerCase()] || MODEL_PRICING[DEFAULT_MODEL];
}
export function isJumboPrompt({ inputTokens = 0, cachedTokens = 0 } = {}) {
const hiddenInputTokens = Math.max(Number(inputTokens ?? 0) - Number(cachedTokens ?? 0), 0);
return hiddenInputTokens > JUMBO_PROMPT_THRESHOLD;
}
function ratesForUsage({ inputTokens, cachedTokens, model }) {
const pricing = getModelPricing(model);
if (!isJumboPrompt({ inputTokens, cachedTokens })) return pricing;
return { input: pricing.input * 2n, cached: pricing.cached * 2n, output: pricing.output * 3n / 2n };
}
function toTokenCount(value) { return BigInt(Math.max(0, Math.trunc(Number(value ?? 0)))); }
export function calculateUsageCostNanoDollars({ inputTokens = 0, cachedTokens = 0, outputTokens = 0, model = DEFAULT_MODEL } = {}) {
const rates = ratesForUsage({ inputTokens, cachedTokens, model });
return (toTokenCount(inputTokens) * rates.input)
+ (toTokenCount(cachedTokens) * rates.cached)
+ (toTokenCount(outputTokens) * rates.output);
}
export function calculateUsageCost(fields = {}) {
return Number(calculateUsageCostNanoDollars(fields)) / 1_000_000_000;
}
export function formatMoney(value) {
const nanoDollars = typeof value === 'bigint' ? value : BigInt(Math.trunc(Number(value ?? 0) * 1_000_000_000));
const roundedThousandths = nanoDollars >= 0n
? (nanoDollars + (NANO_DOLLARS_PER_DISPLAY_UNIT / 2n)) / NANO_DOLLARS_PER_DISPLAY_UNIT
: -(((-nanoDollars) + (NANO_DOLLARS_PER_DISPLAY_UNIT / 2n)) / NANO_DOLLARS_PER_DISPLAY_UNIT);
const sign = roundedThousandths < 0n ? '-' : '';
const absolute = roundedThousandths < 0n ? -roundedThousandths : roundedThousandths;
const whole = absolute / 1000n;
const fractional = (absolute % 1000n).toString().padStart(3, '0');
return `$${sign}${whole.toString()}.${fractional}`;
}
function formatTokenCount(tokens) { return Number(tokens).toLocaleString('en-US'); }
function formatTokenCost(tokens, rateNanoDollarsPerToken) {
return `${formatTokenCount(tokens)} (${formatMoney(BigInt(Math.trunc(Number(tokens ?? 0))) * rateNanoDollarsPerToken)})`;
}
function formatUsageJson(fields) { return JSON.stringify(fields).replaceAll('\\u001b', '\u001b'); }
export function formatUsageReport({ inputTokens = 0, cachedTokens = 0, outputTokens = 0, turns = 0, model = DEFAULT_MODEL } = {}) {
const rates = ratesForUsage({ inputTokens, cachedTokens, model });
const totalCost = calculateUsageCostNanoDollars({ inputTokens, cachedTokens, outputTokens, model });
const avgCostPerTurn = turns > 0 ? totalCost / BigInt(turns) : 0n;
const report = {
in: formatTokenCost(inputTokens, rates.input),
cache: formatTokenCost(cachedTokens, rates.cached),
out: formatTokenCost(outputTokens, rates.output),
turns: String(turns), avg: formatMoney(avgCostPerTurn), total: formatMoney(totalCost),
};
if (isJumboPrompt({ inputTokens, cachedTokens })) report.warning = JUMBO_WARNING;
return formatUsageJson(report);
}
export function formatTurnUsageReport({ inputTokens = 0, cachedTokens = 0, outputTokens = 0, model = DEFAULT_MODEL } = {}) {
const rates = ratesForUsage({ inputTokens, cachedTokens, model });
const totalCost = calculateUsageCostNanoDollars({ inputTokens, cachedTokens, outputTokens, model });
const report = {
in: formatTokenCost(inputTokens, rates.input), cache: formatTokenCost(cachedTokens, rates.cached),
out: formatTokenCost(outputTokens, rates.output), total: formatMoney(totalCost),
};
if (isJumboPrompt({ inputTokens, cachedTokens })) report.warning = JUMBO_WARNING;
return formatUsageJson(report);
}
export function formatTurnUsage(fields = {}) { return formatUsageReport({ ...fields, turns: 1 }); }
export const usageInternals = { DEFAULT_MODEL, JUMBO_PROMPT_THRESHOLD, JUMBO_WARNING, MODEL_PRICING };