@trazum/core 1.9.0 → 1.25.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.
Files changed (108) hide show
  1. package/README.md +12 -5
  2. package/dist/advisories.d.ts.map +1 -1
  3. package/dist/advisories.js +94 -4
  4. package/dist/advisories.js.map +1 -1
  5. package/dist/against.d.ts +32 -0
  6. package/dist/against.d.ts.map +1 -0
  7. package/dist/against.js +34 -0
  8. package/dist/against.js.map +1 -0
  9. package/dist/config-schema.d.ts +42 -1
  10. package/dist/config-schema.d.ts.map +1 -1
  11. package/dist/config-schema.js +61 -0
  12. package/dist/config-schema.js.map +1 -1
  13. package/dist/conversation.d.ts +121 -0
  14. package/dist/conversation.d.ts.map +1 -0
  15. package/dist/conversation.js +157 -0
  16. package/dist/conversation.js.map +1 -0
  17. package/dist/csv.d.ts +61 -0
  18. package/dist/csv.d.ts.map +1 -0
  19. package/dist/csv.js +149 -0
  20. package/dist/csv.js.map +1 -0
  21. package/dist/evaluate.d.ts +24 -0
  22. package/dist/evaluate.d.ts.map +1 -1
  23. package/dist/evaluate.js +5 -2
  24. package/dist/evaluate.js.map +1 -1
  25. package/dist/i18n/en.d.ts.map +1 -1
  26. package/dist/i18n/en.js +18 -7
  27. package/dist/i18n/en.js.map +1 -1
  28. package/dist/i18n/es.d.ts.map +1 -1
  29. package/dist/i18n/es.js +18 -7
  30. package/dist/i18n/es.js.map +1 -1
  31. package/dist/i18n/types.d.ts +28 -1
  32. package/dist/i18n/types.d.ts.map +1 -1
  33. package/dist/index.d.ts +25 -1
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +28 -0
  36. package/dist/index.js.map +1 -1
  37. package/dist/input-shape.d.ts +104 -0
  38. package/dist/input-shape.d.ts.map +1 -0
  39. package/dist/input-shape.js +132 -0
  40. package/dist/input-shape.js.map +1 -0
  41. package/dist/levers.d.ts +151 -0
  42. package/dist/levers.d.ts.map +1 -0
  43. package/dist/levers.js +160 -0
  44. package/dist/levers.js.map +1 -0
  45. package/dist/node.d.ts +1 -1
  46. package/dist/node.d.ts.map +1 -1
  47. package/dist/output-shape.d.ts +96 -0
  48. package/dist/output-shape.d.ts.map +1 -0
  49. package/dist/output-shape.js +145 -0
  50. package/dist/output-shape.js.map +1 -0
  51. package/dist/pricing-overlay.d.ts +1 -1
  52. package/dist/pricing-overlay.d.ts.map +1 -1
  53. package/dist/pricing-overlay.js +46 -0
  54. package/dist/pricing-overlay.js.map +1 -1
  55. package/dist/repeats.d.ts +75 -0
  56. package/dist/repeats.d.ts.map +1 -0
  57. package/dist/repeats.js +82 -0
  58. package/dist/repeats.js.map +1 -0
  59. package/dist/reprice.d.ts +143 -0
  60. package/dist/reprice.d.ts.map +1 -0
  61. package/dist/reprice.js +82 -0
  62. package/dist/reprice.js.map +1 -0
  63. package/dist/session-cost.d.ts +70 -0
  64. package/dist/session-cost.d.ts.map +1 -0
  65. package/dist/session-cost.js +90 -0
  66. package/dist/session-cost.js.map +1 -0
  67. package/dist/session-ledger.d.ts +77 -0
  68. package/dist/session-ledger.d.ts.map +1 -0
  69. package/dist/session-ledger.js +99 -0
  70. package/dist/session-ledger.js.map +1 -0
  71. package/dist/tokenizer.d.ts +33 -26
  72. package/dist/tokenizer.d.ts.map +1 -1
  73. package/dist/tokenizer.js +95 -34
  74. package/dist/tokenizer.js.map +1 -1
  75. package/dist/ttl-fit.d.ts +103 -0
  76. package/dist/ttl-fit.d.ts.map +1 -0
  77. package/dist/ttl-fit.js +184 -0
  78. package/dist/ttl-fit.js.map +1 -0
  79. package/dist/types.d.ts +1 -1
  80. package/dist/types.d.ts.map +1 -1
  81. package/dist/usage.d.ts +637 -0
  82. package/dist/usage.d.ts.map +1 -0
  83. package/dist/usage.js +634 -0
  84. package/dist/usage.js.map +1 -0
  85. package/package.json +1 -1
  86. package/src/advisories.ts +96 -4
  87. package/src/against.ts +48 -0
  88. package/src/config-schema.ts +106 -0
  89. package/src/conversation.ts +305 -0
  90. package/src/csv.ts +184 -0
  91. package/src/evaluate.ts +33 -3
  92. package/src/i18n/en.ts +19 -6
  93. package/src/i18n/es.ts +19 -6
  94. package/src/i18n/types.ts +29 -1
  95. package/src/index.ts +65 -1
  96. package/src/input-shape.ts +259 -0
  97. package/src/levers.ts +331 -0
  98. package/src/node.ts +1 -1
  99. package/src/output-shape.ts +254 -0
  100. package/src/pricing-overlay.ts +52 -1
  101. package/src/repeats.ts +166 -0
  102. package/src/reprice.ts +227 -0
  103. package/src/session-cost.ts +170 -0
  104. package/src/session-ledger.ts +189 -0
  105. package/src/tokenizer.ts +93 -30
  106. package/src/ttl-fit.ts +251 -0
  107. package/src/types.ts +1 -0
  108. package/src/usage.ts +1267 -0
package/dist/usage.js ADDED
@@ -0,0 +1,634 @@
1
+ import { effectivePricing, multipliersFor } from './pricing.js';
2
+ import { createConversationTracker } from './conversation.js';
3
+ import { createOutputShapeTracker } from './output-shape.js';
4
+ import { createInputShapeTracker } from './input-shape.js';
5
+ import { createRepeatsTracker } from './repeats.js';
6
+ import { createTtlFitTracker } from './ttl-fit.js';
7
+ import { createSessionLedgerTracker } from './session-ledger.js';
8
+ import { createSessionCostTracker } from './session-cost.js';
9
+ const EMPTY = () => ({
10
+ calls: 0,
11
+ inputTokens: 0,
12
+ cacheReadTokens: 0,
13
+ cacheWriteTokens: 0,
14
+ cacheWrite5mTokens: 0,
15
+ cacheWrite1hTokens: 0,
16
+ outputTokens: 0,
17
+ assumedWriteTtlCalls: 0,
18
+ maxCallInputTokens: 0,
19
+ inputUsd: 0,
20
+ cacheReadUsd: 0,
21
+ cacheWriteUsd: 0,
22
+ outputUsd: 0,
23
+ totalUsd: 0,
24
+ cachedTokensAtInputRateUsd: 0,
25
+ cacheWriteUsdIfAssumed1h: 0,
26
+ truncatedCalls: 0,
27
+ truncatedOutputUsd: 0,
28
+ stopReasonCalls: 0,
29
+ });
30
+ const OK = (value) => ({ kind: 'ok', value });
31
+ function readCount(...candidates) {
32
+ let sawCorrupt = false;
33
+ for (const value of candidates) {
34
+ if (value === undefined)
35
+ continue;
36
+ if (typeof value === 'number' && Number.isFinite(value) && value >= 0)
37
+ return OK(value);
38
+ // Present and unusable: a string, a null, a negative, a NaN.
39
+ sawCorrupt = true;
40
+ }
41
+ return sawCorrupt ? { kind: 'corrupt' } : { kind: 'absent' };
42
+ }
43
+ /** Zero for an absent count. Callers reject corrupt ones before reaching this. */
44
+ const valueOf = (count) => (count.kind === 'ok' ? count.value : 0);
45
+ function readMoment(...candidates) {
46
+ let sawCorrupt = false;
47
+ for (const value of candidates) {
48
+ if (value === undefined)
49
+ continue;
50
+ if (typeof value === 'number' && Number.isFinite(value)) {
51
+ if (value >= 1e12)
52
+ return { kind: 'ok', ms: value };
53
+ if (value >= 1e8)
54
+ return { kind: 'ok', ms: value * 1000 };
55
+ sawCorrupt = true;
56
+ continue;
57
+ }
58
+ if (typeof value === 'string') {
59
+ const parsed = Date.parse(value);
60
+ if (Number.isFinite(parsed))
61
+ return { kind: 'ok', ms: parsed };
62
+ }
63
+ sawCorrupt = true;
64
+ }
65
+ return sawCorrupt ? { kind: 'corrupt' } : { kind: 'absent' };
66
+ }
67
+ export function parseUsageLine(line) {
68
+ let raw;
69
+ try {
70
+ raw = JSON.parse(line);
71
+ }
72
+ catch {
73
+ return null;
74
+ }
75
+ if (typeof raw !== 'object' || raw === null || Array.isArray(raw))
76
+ return null;
77
+ const record = raw;
78
+ // Anthropic nests usage on a response; a hand-rolled log usually flattens it.
79
+ const usage = typeof record.usage === 'object' && record.usage !== null
80
+ ? record.usage
81
+ : record;
82
+ const model = typeof record.model === 'string' ? record.model : null;
83
+ if (!model)
84
+ return null;
85
+ /**
86
+ * OpenAI reports cached tokens inside `prompt_tokens_details` **and counts them
87
+ * in `prompt_tokens`**, while Anthropic reports them separately and does not.
88
+ * Subtracting in one case and not the other is the difference between a correct
89
+ * bill and one that charges the cached half twice.
90
+ */
91
+ const details = typeof usage.prompt_tokens_details === 'object' && usage.prompt_tokens_details !== null
92
+ ? usage.prompt_tokens_details
93
+ : null;
94
+ const openAiCached = details ? readCount(details.cached_tokens) : { kind: 'absent' };
95
+ /**
96
+ * Anthropic splits cache writes by time-to-live, and the two cost different
97
+ * amounts: 1.25x input for the 5-minute entry, **2x** for the 1-hour one.
98
+ *
99
+ * Reading only the flat `cache_creation_input_tokens` threw that distinction
100
+ * away and then priced everything at the cheaper rate — a 1-hour workload
101
+ * reported 37.5% under, silently, on its largest line. The split is in the log
102
+ * whenever the recording recipe in the README is followed, because it is part of
103
+ * the `usage` object the API returns.
104
+ */
105
+ const creation = typeof usage.cache_creation === 'object' && usage.cache_creation !== null
106
+ ? usage.cache_creation
107
+ : null;
108
+ const write5m = creation ? readCount(creation.ephemeral_5m_input_tokens) : { kind: 'absent' };
109
+ const write1h = creation ? readCount(creation.ephemeral_1h_input_tokens) : { kind: 'absent' };
110
+ const counts = {
111
+ input: readCount(usage.input_tokens, usage.inputTokens, usage.prompt_tokens),
112
+ output: readCount(usage.output_tokens, usage.outputTokens, usage.completion_tokens),
113
+ cacheRead: readCount(usage.cache_read_input_tokens, usage.cacheReadTokens),
114
+ cacheWrite: readCount(usage.cache_creation_input_tokens, usage.cacheWriteTokens),
115
+ openAiCached,
116
+ write5m,
117
+ write1h,
118
+ };
119
+ // Any field present and unreadable rejects the line. See `readCount`.
120
+ if (Object.values(counts).some((c) => c.kind === 'corrupt'))
121
+ return null;
122
+ // Nothing to count at all.
123
+ if (Object.values(counts).every((c) => c.kind === 'absent'))
124
+ return null;
125
+ /**
126
+ * The clock, under the same rule as the counts: a timestamp that is present
127
+ * and unreadable rejects the line rather than becoming a silent absence.
128
+ * `created` is where OpenAI responses carry it (epoch seconds), so a log
129
+ * written by spreading the response already has one.
130
+ */
131
+ const moment = readMoment(record.ts, record.timestamp, record.created_at, record.created);
132
+ if (moment.kind === 'corrupt')
133
+ return null;
134
+ const cached = valueOf(counts.openAiCached);
135
+ const flatWrite = valueOf(counts.cacheWrite);
136
+ const split5m = valueOf(counts.write5m);
137
+ const split1h = valueOf(counts.write1h);
138
+ const hasSplit = counts.write5m.kind === 'ok' || counts.write1h.kind === 'ok';
139
+ return {
140
+ model,
141
+ inputTokens: Math.max(0, valueOf(counts.input) - cached),
142
+ cacheReadTokens: counts.cacheRead.kind === 'ok' ? counts.cacheRead.value : cached,
143
+ /**
144
+ * The split when the log carries it, the flat number otherwise — and
145
+ * `writeTtlKnown` says which, so the report can admit that a rate was assumed
146
+ * rather than quietly choosing the cheaper one.
147
+ */
148
+ cacheWrite5mTokens: hasSplit ? split5m : flatWrite,
149
+ cacheWrite1hTokens: hasSplit ? split1h : 0,
150
+ writeTtlKnown: hasSplit || flatWrite === 0,
151
+ outputTokens: valueOf(counts.output),
152
+ /**
153
+ * Trimmed and internally normalised: any whitespace run becomes one space.
154
+ * A label is a workload name, and it is also used as half of structured keys
155
+ * that split on `\n` — `byLabelAndModel`, the conversation tracker, the
156
+ * output-shape tracker. A label carrying a newline would corrupt that split
157
+ * and mis-file every figure under a truncated name; normalising at the one
158
+ * boundary where labels enter keeps every consumer honest at once.
159
+ */
160
+ label: nameOf(record.label),
161
+ /**
162
+ * Read from either spelling, because both are what people already have:
163
+ * `session` in a hand-rolled log, `conversation_id` in most chat schemas.
164
+ * Refusing one of them would make the field's adoption a chore, and a field
165
+ * nobody sets measures nothing.
166
+ */
167
+ session: nameOf(record.session) ?? nameOf(record.conversation_id),
168
+ ts: moment.kind === 'ok' ? moment.ms : null,
169
+ /**
170
+ * Anthropic spells it `stop_reason: "max_tokens"`, OpenAI
171
+ * `finish_reason: "length"`. Any other recorded reason is a completed
172
+ * answer; an absent field is `null`, which is "not measured" and not "did
173
+ * not happen" — the report treats those differently on purpose.
174
+ */
175
+ truncated: (() => {
176
+ const reason = record.stop_reason ?? record.finish_reason;
177
+ if (typeof reason !== 'string')
178
+ return null;
179
+ return reason === 'max_tokens' || reason === 'length';
180
+ })(),
181
+ };
182
+ }
183
+ /**
184
+ * A label or session identifier, from whatever a real log holds.
185
+ *
186
+ * **Numbers are identifiers too.** A conversation id is an auto-incremented
187
+ * integer in half the databases in existence, and the string-only version
188
+ * dropped `session: 12345` silently and then printed "No call in this log
189
+ * carried a session" — a false claim about a log that carried one on every
190
+ * line. A finite number is taken by its decimal form; booleans, objects and
191
+ * non-finite numbers stay out, because `session: true` names nothing.
192
+ *
193
+ * Strings are trimmed and internally normalised — any whitespace run becomes
194
+ * one space — because labels are half of structured keys that split on a
195
+ * newline, and a label carrying one would mis-file every figure it touches.
196
+ */
197
+ function nameOf(value) {
198
+ if (typeof value === 'number' && Number.isFinite(value))
199
+ return String(value);
200
+ if (typeof value !== 'string')
201
+ return null;
202
+ const trimmed = value.trim().replace(/\s+/g, ' ');
203
+ return trimmed === '' ? null : trimmed;
204
+ }
205
+ /**
206
+ * The bucket unlabelled calls land in.
207
+ *
208
+ * The empty string, because it is the one value a parsed label can never be —
209
+ * `parseUsageLine` trims and rejects empty. The first version used the literal
210
+ * string `'unlabelled'`, and a workload somebody had actually named `unlabelled`
211
+ * merged silently into the missing-label bucket: 200 labelled calls and 200
212
+ * unlabelled ones reported as one row of 400, and the "none of these calls
213
+ * carried a label" warning fired over a log where half of them had.
214
+ *
215
+ * Presentation stays in the CLI, which translates this sentinel through the
216
+ * message catalogue; data consumers can tell `''` from any real label.
217
+ */
218
+ export const UNLABELLED = '';
219
+ /** Token counts only. Used for both halves, because both need them. */
220
+ function countInto(into, record) {
221
+ into.calls += 1;
222
+ into.inputTokens += record.inputTokens;
223
+ into.cacheReadTokens += record.cacheReadTokens;
224
+ into.cacheWriteTokens += record.cacheWrite5mTokens + record.cacheWrite1hTokens;
225
+ into.cacheWrite5mTokens += record.cacheWrite5mTokens;
226
+ into.cacheWrite1hTokens += record.cacheWrite1hTokens;
227
+ if (!record.writeTtlKnown)
228
+ into.assumedWriteTtlCalls += 1;
229
+ into.outputTokens += record.outputTokens;
230
+ into.maxCallInputTokens = Math.max(into.maxCallInputTokens, record.inputTokens + record.cacheReadTokens + record.cacheWrite5mTokens + record.cacheWrite1hTokens);
231
+ if (record.truncated !== null) {
232
+ into.stopReasonCalls += 1;
233
+ if (record.truncated)
234
+ into.truncatedCalls += 1;
235
+ }
236
+ }
237
+ function add(into, record, catalogue, on) {
238
+ /**
239
+ * Looked up directly rather than through `modelFrom`, which **throws** on an id
240
+ * it does not know. A usage log is somebody's production traffic and will
241
+ * contain models this catalogue has never heard of — a fine-tune, a preview, a
242
+ * competitor. Throwing means one unfamiliar id destroys the whole profile;
243
+ * naming it separately means the report is honest about what it could not price
244
+ * and useful about everything else.
245
+ *
246
+ * **Priced first, counted second.** The other order was the bug: counts landed
247
+ * before the lookup could fail, so an unpriced call contributed tokens to a
248
+ * total whose dollars excluded it.
249
+ */
250
+ const model = catalogue.byId.get(record.model);
251
+ if (!model)
252
+ return false;
253
+ countInto(into, record);
254
+ const { inputPerMTok, outputPerMTok } = effectivePricing(model, on);
255
+ const rates = multipliersFor(model);
256
+ const per = (tokens, rate) => (tokens / 1_000_000) * rate;
257
+ into.inputUsd += per(record.inputTokens, inputPerMTok);
258
+ into.cacheReadUsd += per(record.cacheReadTokens, inputPerMTok * rates.cacheRead);
259
+ /**
260
+ * Each TTL at its own rate. Anthropic charges 1.25x input for a 5-minute entry
261
+ * and 2x for a 1-hour one, and the first version applied 1.25x to both — 37.5%
262
+ * under on a 1-hour workload, on the largest line, with nothing on screen
263
+ * saying a rate had been chosen.
264
+ */
265
+ into.cacheWriteUsd += per(record.cacheWrite5mTokens, inputPerMTok * rates.cacheWrite5m);
266
+ into.cacheWriteUsd += per(record.cacheWrite1hTokens, inputPerMTok * rates.cacheWrite1h);
267
+ /**
268
+ * The same writes with the assumption taken the other way.
269
+ *
270
+ * A record whose TTL the log did not state has all of its writes in the
271
+ * 5-minute bucket — `parseUsageLine` puts them there because one rate has to be
272
+ * chosen — so this prices exactly those at the 1-hour rate instead. Accumulated
273
+ * per call, and per model, because the ratio between the two rates is not a
274
+ * constant: 2.0/1.25 on Anthropic, 1.0/1.0 where a write costs what input
275
+ * costs. Scaling the total afterwards would invent a premium for providers that
276
+ * have none.
277
+ */
278
+ const writeRateIfWrong = record.writeTtlKnown ? rates.cacheWrite5m : rates.cacheWrite1h;
279
+ into.cacheWriteUsdIfAssumed1h += per(record.cacheWrite5mTokens, inputPerMTok * writeRateIfWrong);
280
+ into.cacheWriteUsdIfAssumed1h += per(record.cacheWrite1hTokens, inputPerMTok * rates.cacheWrite1h);
281
+ into.outputUsd += per(record.outputTokens, outputPerMTok);
282
+ if (record.truncated === true) {
283
+ into.truncatedOutputUsd += per(record.outputTokens, outputPerMTok);
284
+ }
285
+ /**
286
+ * The same cache-touched tokens at the plain input rate, banked here because
287
+ * `inputPerMTok` is per model and is gone by the time anybody reads the total.
288
+ */
289
+ into.cachedTokensAtInputRateUsd += per(record.cacheReadTokens + record.cacheWrite5mTokens + record.cacheWrite1hTokens, inputPerMTok);
290
+ into.totalUsd =
291
+ into.inputUsd + into.cacheReadUsd + into.cacheWriteUsd + into.outputUsd;
292
+ return true;
293
+ }
294
+ /**
295
+ * Reads a usage log and says where the money went.
296
+ *
297
+ * Takes the whole text rather than a stream: a usage log is measured in megabytes
298
+ * and this package imports no Node builtins, so streaming would mean an interface
299
+ * the browser build cannot satisfy. `@trazum/core/node` is where file reading
300
+ * lives, and it can chunk if it ever needs to.
301
+ */
302
+ export function profileUsage(text, options) {
303
+ const { catalogue, on = new Date(), label: onlyLabel, sinceMs, untilMs } = options;
304
+ const windowed = sinceMs !== undefined || untilMs !== undefined;
305
+ let undatedExcluded = 0;
306
+ const total = EMPTY();
307
+ const unpriced = EMPTY();
308
+ const byLabel = new Map();
309
+ const byModel = new Map();
310
+ // Keyed on a pair, so the key carries a separator that cannot occur in either
311
+ // half. A model id is `[A-Za-z0-9._-]`, so a newline is safe in both.
312
+ const byPair = new Map();
313
+ const unpricedModels = new Set();
314
+ const skippedLines = [];
315
+ /**
316
+ * Fed in the pass this function already makes, rather than by keeping the records
317
+ * for a second one: a usage log is measured in megabytes, and what this holds is
318
+ * bounded by the number of conversations instead.
319
+ */
320
+ const conversations = createConversationTracker({ catalogue, on });
321
+ const output = createOutputShapeTracker({ catalogue, on });
322
+ const input = createInputShapeTracker({ catalogue, on });
323
+ const repeats = createRepeatsTracker({ catalogue, on });
324
+ const ttlFit = createTtlFitTracker({ catalogue, on });
325
+ const ledger = createSessionLedgerTracker({ catalogue, on });
326
+ const sessionCosts = createSessionCostTracker({ catalogue, on });
327
+ let hasSessions = false;
328
+ const coverage = { label: 0, session: 0, ts: 0, stopReason: 0, cacheTtl: 0, cacheWrites: 0, parsed: 0 };
329
+ /**
330
+ * Raw lines already seen, for the duplicate check. Bounded by the number of
331
+ * *timestamped* lines — the price of catching a doubled bill, paid only on
332
+ * logs that carry a clock.
333
+ */
334
+ const seenLines = new Set();
335
+ const duplicates = { count: 0, usd: 0 };
336
+ let spanFrom = Infinity;
337
+ let spanTo = -Infinity;
338
+ let spanCalls = 0;
339
+ /** Per UTC day: spend, calls, and spend per label. Bounded by days × labels. */
340
+ const days = new Map();
341
+ /** Per hour of the UTC day. Bounded by twenty-four entries, whatever the log. */
342
+ const hours = new Map();
343
+ const lines = text.split('\n');
344
+ for (let i = 0; i < lines.length; i += 1) {
345
+ const line = lines[i].trim();
346
+ if (line === '')
347
+ continue;
348
+ const record = parseUsageLine(line);
349
+ if (!record) {
350
+ skippedLines.push(i + 1);
351
+ continue;
352
+ }
353
+ // The drill-down: after the skip accounting, so a corrupt line is reported
354
+ // whatever it might have been labelled.
355
+ if (onlyLabel !== undefined && (record.label ?? UNLABELLED) !== onlyLabel)
356
+ continue;
357
+ /**
358
+ * The time window, after the label filter so `undatedExcluded` counts only
359
+ * the selected workload's clockless calls — a count polluted by every other
360
+ * label's records would overstate how much of *this* answer is missing.
361
+ * Records outside the window are simply not the question; records with no
362
+ * clock are the question left unanswerable, so they are counted.
363
+ */
364
+ if (windowed) {
365
+ if (record.ts === null) {
366
+ undatedExcluded += 1;
367
+ continue;
368
+ }
369
+ if (sinceMs !== undefined && record.ts < sinceMs)
370
+ continue;
371
+ if (untilMs !== undefined && record.ts >= untilMs)
372
+ continue;
373
+ }
374
+ /**
375
+ * Coverage is counted before pricing: whether a field is present is a
376
+ * property of the log, and a record on an unknown model still says
377
+ * whether somebody set `label`.
378
+ */
379
+ coverage.parsed += 1;
380
+ if (record.label !== null)
381
+ coverage.label += 1;
382
+ if (record.session !== null)
383
+ coverage.session += 1;
384
+ if (record.ts !== null)
385
+ coverage.ts += 1;
386
+ if (record.truncated !== null)
387
+ coverage.stopReason += 1;
388
+ if (record.cacheWrite5mTokens + record.cacheWrite1hTokens > 0) {
389
+ coverage.cacheWrites += 1;
390
+ if (record.writeTtlKnown)
391
+ coverage.cacheTtl += 1;
392
+ }
393
+ if (record.session !== null)
394
+ hasSessions = true;
395
+ if (record.ts !== null) {
396
+ spanFrom = Math.min(spanFrom, record.ts);
397
+ spanTo = Math.max(spanTo, record.ts);
398
+ spanCalls += 1;
399
+ }
400
+ conversations.add(record);
401
+ output.add(record);
402
+ input.add(record);
403
+ repeats.add(record);
404
+ ttlFit.add(record);
405
+ ledger.add(record);
406
+ sessionCosts.add(record);
407
+ const usdBefore = total.totalUsd;
408
+ if (!add(total, record, catalogue, on)) {
409
+ unpricedModels.add(record.model);
410
+ countInto(unpriced, record);
411
+ // Still grouped by model, so the reader can see which unknown id is costing
412
+ // them attention — but with zero dollars, which the grouping makes obvious.
413
+ if (!byModel.has(record.model))
414
+ byModel.set(record.model, EMPTY());
415
+ countInto(byModel.get(record.model), record);
416
+ continue;
417
+ }
418
+ /**
419
+ * A line identical to one already read, with a clock to make the claim
420
+ * safe. Counted after pricing so the money is the exact delta this line
421
+ * added, which is what a doubled bill is overstated by.
422
+ */
423
+ if (record.ts !== null) {
424
+ if (seenLines.has(line)) {
425
+ duplicates.count += 1;
426
+ duplicates.usd += total.totalUsd - usdBefore;
427
+ }
428
+ else {
429
+ seenLines.add(line);
430
+ }
431
+ }
432
+ /**
433
+ * The day's spend, as the exact delta this record just added to the total —
434
+ * the one place the per-record dollar exists without re-deriving the rate
435
+ * arithmetic a second time, where the two could drift apart.
436
+ */
437
+ if (record.ts !== null) {
438
+ const day = new Date(record.ts).toISOString().slice(0, 10);
439
+ const usd = total.totalUsd - usdBefore;
440
+ let entry = days.get(day);
441
+ if (!entry) {
442
+ entry = { usd: 0, calls: 0, byLabel: new Map() };
443
+ days.set(day, entry);
444
+ }
445
+ entry.usd += usd;
446
+ entry.calls += 1;
447
+ const labelKey = record.label ?? UNLABELLED;
448
+ entry.byLabel.set(labelKey, (entry.byLabel.get(labelKey) ?? 0) + usd);
449
+ // The same exact per-record dollar, bucketed by hour of the UTC day.
450
+ const hour = new Date(record.ts).getUTCHours();
451
+ const hourEntry = hours.get(hour);
452
+ if (hourEntry) {
453
+ hourEntry.usd += usd;
454
+ hourEntry.calls += 1;
455
+ }
456
+ else {
457
+ hours.set(hour, { usd, calls: 1 });
458
+ }
459
+ }
460
+ const labelKey = record.label ?? UNLABELLED;
461
+ if (!byLabel.has(labelKey))
462
+ byLabel.set(labelKey, EMPTY());
463
+ add(byLabel.get(labelKey), record, catalogue, on);
464
+ if (!byModel.has(record.model))
465
+ byModel.set(record.model, EMPTY());
466
+ add(byModel.get(record.model), record, catalogue, on);
467
+ const pairKey = `${labelKey}\n${record.model}`;
468
+ if (!byPair.has(pairKey))
469
+ byPair.set(pairKey, EMPTY());
470
+ add(byPair.get(pairKey), record, catalogue, on);
471
+ }
472
+ const sorted = (map, key) => [...map.entries()]
473
+ .sort((a, b) => b[1].totalUsd - a[1].totalUsd || a[0].localeCompare(b[0]))
474
+ .map(([name, breakdown]) => ({ [key]: name, breakdown }));
475
+ return {
476
+ total,
477
+ byLabel: sorted(byLabel, 'label'),
478
+ byModel: sorted(byModel, 'model'),
479
+ byLabelAndModel: [...byPair.entries()]
480
+ .sort((a, b) => b[1].totalUsd - a[1].totalUsd || a[0].localeCompare(b[0]))
481
+ .map(([key, breakdown]) => {
482
+ const split = key.indexOf('\n');
483
+ return { label: key.slice(0, split), model: key.slice(split + 1), breakdown };
484
+ }),
485
+ unpricedModels: [...unpricedModels].sort(),
486
+ unpriced,
487
+ skippedLines,
488
+ conversations: conversations.finish(total.totalUsd),
489
+ hasSessions,
490
+ outputShapes: output.finish(total.totalUsd),
491
+ inputShapes: input.finish(total.totalUsd),
492
+ repeatedTurns: repeats.finish(),
493
+ span: spanCalls > 0 ? { fromMs: spanFrom, toMs: spanTo, calls: spanCalls } : null,
494
+ spendByDay: [...days.entries()]
495
+ .sort((a, b) => a[0].localeCompare(b[0]))
496
+ .map(([day, entry]) => {
497
+ let topLabel = null;
498
+ let topLabelUsd = 0;
499
+ for (const [label, usd] of entry.byLabel) {
500
+ if (usd > topLabelUsd) {
501
+ topLabel = label;
502
+ topLabelUsd = usd;
503
+ }
504
+ }
505
+ return { day, usd: entry.usd, calls: entry.calls, topLabel, topLabelUsd };
506
+ }),
507
+ duplicateLines: duplicates,
508
+ fieldCoverage: coverage,
509
+ spendByHour: [...hours.entries()]
510
+ .sort((a, b) => a[0] - b[0])
511
+ .map(([hour, entry]) => ({ hour, usd: entry.usd, calls: entry.calls })),
512
+ cacheTtlFit: ttlFit.finish(),
513
+ timeWindow: windowed
514
+ ? { sinceMs: sinceMs ?? null, untilMs: untilMs ?? null, undatedExcluded }
515
+ : null,
516
+ singleTurnCacheWrites: ledger.finish(),
517
+ sessionCosts: sessionCosts.finish(),
518
+ };
519
+ }
520
+ /**
521
+ * What share of the bill each part is.
522
+ *
523
+ * The point of the whole module in one function: a caller can print "output is
524
+ * 87% of this" without doing arithmetic that would drift from the arithmetic
525
+ * here.
526
+ *
527
+ * All zeroes when nothing was spent, rather than `NaN`. A profile of an empty log
528
+ * is a legitimate result — no calls yet — and a report full of `NaN%` is a bug
529
+ * report from somebody who did nothing wrong.
530
+ */
531
+ export function sharesOf(breakdown) {
532
+ const { totalUsd } = breakdown;
533
+ if (totalUsd <= 0)
534
+ return { input: 0, cacheRead: 0, cacheWrite: 0, output: 0 };
535
+ return {
536
+ input: breakdown.inputUsd / totalUsd,
537
+ cacheRead: breakdown.cacheReadUsd / totalUsd,
538
+ cacheWrite: breakdown.cacheWriteUsd / totalUsd,
539
+ output: breakdown.outputUsd / totalUsd,
540
+ };
541
+ }
542
+ /**
543
+ * How much of the input that could have been cached was.
544
+ *
545
+ * `null` when nothing was cacheable-looking at all — no reads and no writes —
546
+ * because a hit rate over zero attempts is not zero, it is undefined, and
547
+ * printing "0% cache hit rate" for somebody who never turned caching on is a
548
+ * finding about nothing.
549
+ *
550
+ * Reads against reads-plus-full-price-input, deliberately. Cache *writes* are
551
+ * excluded from the denominator: a write is the cost of establishing an entry,
552
+ * not a missed read, and counting it as a miss makes a healthy cache look broken
553
+ * on the day it warms.
554
+ */
555
+ export function cacheHitRate(breakdown) {
556
+ const attempts = breakdown.cacheReadTokens + breakdown.inputTokens;
557
+ if (breakdown.cacheReadTokens === 0 && breakdown.cacheWriteTokens === 0)
558
+ return null;
559
+ if (attempts === 0)
560
+ return null;
561
+ return breakdown.cacheReadTokens / attempts;
562
+ }
563
+ /**
564
+ * Floating-point noise, not a judgement threshold.
565
+ *
566
+ * Summing a million per-call doubles around a $100 bill accumulates roughly
567
+ * `n · eps · magnitude` ≈ $2e-8 of drift, and a verdict that flipped on that would
568
+ * be reporting arithmetic error as a finding. A millionth of a dollar is orders of
569
+ * magnitude below anything this tool prints, so nothing real is being rounded away
570
+ * — deliberately not a "too small to care about" cutoff, which would be a
571
+ * judgement and would belong somewhere a reader can see it.
572
+ */
573
+ const CACHE_DELTA_NOISE_USD = 1e-6;
574
+ /**
575
+ * Did caching pay for itself?
576
+ *
577
+ * The question nothing else in this package can answer, and the one that decides
578
+ * whether the advice the rest of it gives was right. Trazum tells people to cache;
579
+ * on Anthropic a cache **write** costs 1.25x plain input at the 5-minute TTL and
580
+ * **2x** at the 1-hour one, so a prefix that changes faster than it is reused is
581
+ * billed at a premium and returns nothing. That workload would be cheaper with
582
+ * caching switched off, and no other report in this repository would ever say so.
583
+ *
584
+ * The counterfactual is exact, which is why this is allowed to exist here at all:
585
+ * caching changes the multiplier on a token, never the token. Had `cache_control`
586
+ * not been set, the identical prefix would have gone up as ordinary input at 1x.
587
+ * So `withoutCachingUsd` is not an estimate of a different call — it is the same
588
+ * call, arithmetic away.
589
+ *
590
+ * Worth running per label as well as over the whole log. A profitable cache on one
591
+ * workload and a bleeding one on another net out to a comfortable-looking total,
592
+ * and the aggregate is exactly where a loss hides.
593
+ */
594
+ export function cacheEconomics(breakdown) {
595
+ const touchedTokens = breakdown.cacheReadTokens + breakdown.cacheWriteTokens;
596
+ const spentUsd = breakdown.cacheReadUsd + breakdown.cacheWriteUsd;
597
+ const withoutCachingUsd = breakdown.cachedTokensAtInputRateUsd;
598
+ const none = (verdict) => ({
599
+ spentUsd,
600
+ withoutCachingUsd,
601
+ deltaUsd: 0,
602
+ readsPerWrite: null,
603
+ verdict,
604
+ worstCaseDeltaUsd: 0,
605
+ worstCaseVerdict: verdict,
606
+ });
607
+ if (touchedTokens === 0)
608
+ return none('not-attempted');
609
+ /**
610
+ * Tokens went through the cache and no money is attached to either side, so
611
+ * there is nothing to compare. This is what an unpriced model looks like: the
612
+ * counts accumulate through `countInto` and the dollars never do. Without this
613
+ * guard the delta is `0 - 0` and the verdict comes out `no-difference` — a
614
+ * confident claim about a bill that was never computed.
615
+ */
616
+ if (spentUsd === 0 && withoutCachingUsd === 0)
617
+ return none('unpriced');
618
+ const deltaUsd = spentUsd - withoutCachingUsd;
619
+ const worstCaseDeltaUsd = breakdown.cacheReadUsd + breakdown.cacheWriteUsdIfAssumed1h - withoutCachingUsd;
620
+ const readsPerWrite = breakdown.cacheWriteTokens === 0
621
+ ? null
622
+ : breakdown.cacheReadTokens / breakdown.cacheWriteTokens;
623
+ const decide = (delta) => Math.abs(delta) < CACHE_DELTA_NOISE_USD ? 'no-difference' : delta > 0 ? 'lost-money' : 'paid-off';
624
+ return {
625
+ spentUsd,
626
+ withoutCachingUsd,
627
+ deltaUsd,
628
+ readsPerWrite,
629
+ verdict: decide(deltaUsd),
630
+ worstCaseDeltaUsd,
631
+ worstCaseVerdict: decide(worstCaseDeltaUsd),
632
+ };
633
+ }
634
+ //# sourceMappingURL=usage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.js","sourceRoot":"","sources":["../src/usage.ts"],"names":[],"mappings":"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"}