margin-meter 0.1.0 → 0.3.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.
@@ -0,0 +1,611 @@
1
+ /**
2
+ * Read the measured economics of one LLM call straight off a provider response.
3
+ *
4
+ * The TS twin of `margin_meter.providers`: given the object an OpenAI /
5
+ * Anthropic / Gemini JS client returns, recover the `(provider, model, tokens)`
6
+ * a Margin call row needs — so auto-instrumentation is a few lines with no
7
+ * manual token bookkeeping.
8
+ *
9
+ * Dependency-free and duck-typed on purpose: it never imports the provider SDKs,
10
+ * reading fields by shape so it works on a real SDK object, a plain object (the
11
+ * shape a mocked provider returns in tests), or JSON. The three shapes, as the
12
+ * current JS SDKs publish them:
13
+ *
14
+ * - **OpenAI** — `model`; `usage.prompt_tokens` / `completion_tokens`; cached
15
+ * reads at `usage.prompt_tokens_details.cached_tokens` (Responses API:
16
+ * `usage.input_tokens` / `output_tokens` / `input_tokens_details.cached_tokens`).
17
+ * - **Anthropic** — `model`; `usage.input_tokens` / `output_tokens`; cached
18
+ * reads at `usage.cache_read_input_tokens`; cache WRITES at
19
+ * `usage.cache_creation_input_tokens` (a ~1.25x premium bucket).
20
+ * - **Gemini** (`@google/generative-ai`) — `response.usageMetadata` (the
21
+ * `generateContent` result nests it under `.response`), with
22
+ * `promptTokenCount` / `candidatesTokenCount` / `cachedContentTokenCount`, plus
23
+ * `thoughtsTokenCount` (thinking tokens, billed as output and folded in).
24
+ * The model does not ride the response, so the caller passes it.
25
+ * - **Cohere** (v2 `/chat`) — billed counts nest under `usage.billed_units`
26
+ * (what is charged; raw `usage.tokens` is the fallback), each with
27
+ * `input_tokens` / `output_tokens`. Cohere publishes no chat prompt-cache
28
+ * discount, so cache reads bill as ordinary input (`cacheReadTokens` stays 0);
29
+ * the model does not ride the response, so the caller passes it.
30
+ * - **AWS Bedrock** (`@aws-sdk/client-bedrock-runtime`, Converse) — usage rides
31
+ * `usage.inputTokens` / `outputTokens` in camelCase, with ADDITIVE cache
32
+ * buckets `cacheReadInputTokens` / `cacheWriteInputTokens` (AWS documents
33
+ * `totalTokens = inputTokens + outputTokens + cacheReadInputTokens +
34
+ * cacheWriteInputTokens`), so the three input-side buckets are disjoint and
35
+ * each reads verbatim, no subtraction. The Converse response omits the model
36
+ * id, so the caller passes it (`instrumentBedrock` reads it off the command's
37
+ * `input.modelId`); its gateway form (`us.anthropic.claude-…-v1:0`) prices
38
+ * through the server's `normalize_model`.
39
+ *
40
+ * Numbers are read verbatim — never inflated. A field the provider didn't report
41
+ * reads 0; an unrecognised shape throws `UsageExtractionError` rather than
42
+ * emitting a silently-zero (free-looking) call.
43
+ */
44
+ export const OPENAI = "openai";
45
+ export const ANTHROPIC = "anthropic";
46
+ export const GOOGLE = "google";
47
+ export const COHERE = "cohere";
48
+ export const BEDROCK = "bedrock";
49
+ /** The response object matched no provider shape we can meter. */
50
+ export class UsageExtractionError extends Error {
51
+ constructor(message) {
52
+ super(message);
53
+ this.name = "UsageExtractionError";
54
+ }
55
+ }
56
+ /** Read `obj.name` from an object OR undefined — duck-typed, null-safe. */
57
+ function get(obj, name) {
58
+ if (obj === null || obj === undefined)
59
+ return undefined;
60
+ if (typeof obj !== "object")
61
+ return undefined;
62
+ return obj[name];
63
+ }
64
+ /** Walk a chain of field names, tolerating a missing hop. */
65
+ function getPath(obj, ...names) {
66
+ let cur = obj;
67
+ for (const name of names) {
68
+ cur = get(cur, name);
69
+ if (cur === null || cur === undefined)
70
+ return undefined;
71
+ }
72
+ return cur;
73
+ }
74
+ /** Coerce a reported token count to a non-negative int; missing → 0. Reads
75
+ * verbatim — never rounds a real count up or invents one. */
76
+ function asInt(value) {
77
+ if (value === null || value === undefined)
78
+ return 0;
79
+ const n = Math.trunc(Number(value));
80
+ if (!Number.isFinite(n) || n <= 0)
81
+ return 0;
82
+ return n;
83
+ }
84
+ /** First element of an array-shaped value, else undefined (duck-typed). OpenAI and
85
+ * Gemini nest their stop/finish reason under the first choice / candidate. */
86
+ function first(seq) {
87
+ if (Array.isArray(seq))
88
+ return seq.length > 0 ? seq[0] : undefined;
89
+ return undefined;
90
+ }
91
+ /** A provider's stop/finish reason as a clean string, or undefined (MAR-209).
92
+ * Read VERBATIM — never mapped, normalised, or inferred into a billing verdict.
93
+ * A missing, blank, or non-scalar value is undefined (UNKNOWN, first-class),
94
+ * never defaulted to a plausible value like "stop". A provider that reports an
95
+ * enum stringifies here; the value is stored, never interpreted. */
96
+ function asReason(value) {
97
+ if (value === null || value === undefined)
98
+ return undefined;
99
+ if (typeof value === "object")
100
+ return undefined;
101
+ const s = String(value).trim();
102
+ return s.length > 0 ? s : undefined;
103
+ }
104
+ /** The Gemini `generateContent` result nests usage under `.response`; unwrap it. */
105
+ function usageMetadata(response) {
106
+ const direct = get(response, "usageMetadata");
107
+ if (direct !== undefined)
108
+ return direct;
109
+ return getPath(response, "response", "usageMetadata");
110
+ }
111
+ /**
112
+ * Best-effort provider inference from a response's shape. Prefers unambiguous
113
+ * signals: Gemini exposes `usageMetadata`; Anthropic's usage carries
114
+ * `input_tokens` while OpenAI's carries `prompt_tokens`. Returns undefined when
115
+ * nothing distinguishes it — the caller must then name the provider (the
116
+ * instrumenter always does).
117
+ */
118
+ export function detectProvider(response) {
119
+ if (usageMetadata(response) !== undefined)
120
+ return GOOGLE;
121
+ const usage = get(response, "usage");
122
+ if (usage !== undefined && usage !== null) {
123
+ // Cohere nests billed counts under `billed_units` — a key no other provider
124
+ // carries, so it is an unambiguous signal. Checked before Anthropic so its
125
+ // NESTED input_tokens is never read as Anthropic's top-level one.
126
+ if (get(usage, "billed_units") !== undefined)
127
+ return COHERE;
128
+ // Bedrock's Converse usage is camelCase (`inputTokens`/`outputTokens`) — a
129
+ // shape every other provider spells snake_case, so it is unambiguous (like
130
+ // Cohere's `billed_units`). Checked before the snake_case branches so its
131
+ // camelCase keys are never read as a missing OpenAI/Anthropic usage.
132
+ if (get(usage, "inputTokens") !== undefined || get(usage, "outputTokens") !== undefined) {
133
+ return BEDROCK;
134
+ }
135
+ if (get(usage, "prompt_tokens") !== undefined || get(usage, "completion_tokens") !== undefined) {
136
+ return OPENAI;
137
+ }
138
+ if (get(usage, "input_tokens") !== undefined || get(usage, "output_tokens") !== undefined) {
139
+ return ANTHROPIC;
140
+ }
141
+ }
142
+ return undefined;
143
+ }
144
+ // OpenRouter ROUTER slugs pick a different model per call, so the requested name has no
145
+ // single rate and would price at the server's $1/$3 fallback (MAR-1309). The response's
146
+ // own `model` is the one that served — and billed — the call.
147
+ const OPENROUTER_ROUTERS = new Set(["auto", "auto-beta", "pareto-code"]);
148
+ // FAN-OUT slugs run N panel calls plus an analyst call: no single served model prices
149
+ // them, and the analyst's name would under-state the bill several-fold. They keep their
150
+ // slug and carry OpenRouter's billed `usage.cost` instead.
151
+ const OPENROUTER_FANOUT = new Set(["fusion", "fusion-flash"]);
152
+ /** The route under `openrouter/` (however many prefixes were stacked), else undefined. */
153
+ function openrouterRoute(model) {
154
+ if (!model)
155
+ return undefined;
156
+ let rest = model.trim().toLowerCase();
157
+ if (!rest.startsWith("openrouter/"))
158
+ return undefined;
159
+ while (rest.startsWith("openrouter/"))
160
+ rest = rest.slice("openrouter/".length);
161
+ return rest;
162
+ }
163
+ /** True for `openrouter/fusion` and its siblings (many billed calls per request). */
164
+ export function isFanoutSlug(model) {
165
+ const route = openrouterRoute(model);
166
+ return route !== undefined && OPENROUTER_FANOUT.has(route);
167
+ }
168
+ /** The caller's model, unless it names a router and the response says what served it. */
169
+ function billedModel(requested, response) {
170
+ const served = get(response, "model");
171
+ const route = openrouterRoute(requested);
172
+ if (route !== undefined && OPENROUTER_ROUTERS.has(route) && typeof served === "string" && served.trim()) {
173
+ return served.trim();
174
+ }
175
+ return requested ?? served;
176
+ }
177
+ /** OpenRouter's billed `usage.cost` for a fan-out slug; undefined when absent or not a sane number. */
178
+ function fanoutBilledCost(requested, usage) {
179
+ if (!isFanoutSlug(requested))
180
+ return undefined;
181
+ const cost = saneCost(get(usage, "cost"));
182
+ if (cost === undefined)
183
+ return undefined;
184
+ // BRING-YOUR-OWN-KEY: `usage.cost` is then only OpenRouter's charge and the provider's
185
+ // bill is `cost_details.upstream_inference_cost` (0/absent otherwise). The spend is the
186
+ // sum; a present but garbled upstream figure makes the cost unknown, never half-counted.
187
+ const upstreamRaw = getPath(usage, "cost_details", "upstream_inference_cost");
188
+ if (upstreamRaw === undefined || upstreamRaw === null)
189
+ return cost;
190
+ const upstream = saneCost(upstreamRaw);
191
+ return upstream === undefined ? undefined : cost + upstream;
192
+ }
193
+ /** A finite, non-negative dollar figure, else undefined (never a guessed number). */
194
+ function saneCost(value) {
195
+ if (typeof value !== "number" || !Number.isFinite(value) || value < 0)
196
+ return undefined;
197
+ return value;
198
+ }
199
+ function extractOpenAI(response, model) {
200
+ const usage = get(response, "usage");
201
+ if (usage === undefined || usage === null) {
202
+ throw new UsageExtractionError("openai response carries no .usage");
203
+ }
204
+ const inputRaw = get(usage, "prompt_tokens") ?? get(usage, "input_tokens");
205
+ const outputRaw = get(usage, "completion_tokens") ?? get(usage, "output_tokens");
206
+ // DeepSeek-direct is OpenAI-compatible, so instrument reaches it through the same
207
+ // client — but it reports cache hits in its own prompt_cache_hit_tokens field, not
208
+ // prompt_tokens_details.cached_tokens, and prompt_tokens is inclusive of them. A
209
+ // genuine OpenAI/Azure response never carries this field (reads 0), so the direct
210
+ // path is unchanged; reading it captures DeepSeek's cache discount. Consulted last,
211
+ // so a provider reporting both is never double-counted.
212
+ const cachedRaw = getPath(usage, "prompt_tokens_details", "cached_tokens") ??
213
+ getPath(usage, "input_tokens_details", "cached_tokens") ??
214
+ get(usage, "prompt_cache_hit_tokens");
215
+ const cached = asInt(cachedRaw);
216
+ // prompt_tokens is INCLUSIVE of cached — split so cache reads are not
217
+ // double-billed as fresh input (the server bills the two separately).
218
+ const freshInput = asInt(inputRaw) - cached;
219
+ // A reasoning model (o-series, gpt-5) reports the hidden-thinking share under
220
+ // completion_tokens_details.reasoning_tokens — a BREAKDOWN of completion_tokens,
221
+ // not an addition. outputTokens already counts it; carry it only for the
222
+ // reasoning-share detector, clamped to output so the subset never exceeds the
223
+ // whole. 0 on a non-reasoning response.
224
+ const out = asInt(outputRaw);
225
+ const reasoning = asInt(getPath(usage, "completion_tokens_details", "reasoning_tokens"));
226
+ return {
227
+ provider: OPENAI,
228
+ model: billedModel(model, response),
229
+ inputTokens: freshInput > 0 ? freshInput : 0,
230
+ outputTokens: out,
231
+ cacheReadTokens: cached,
232
+ cacheCreationTokens: 0,
233
+ reasoningTokens: Math.min(reasoning, out),
234
+ // finish_reason nests under the first choice ("stop"/"length"/"content_filter"/
235
+ // "tool_calls"). Absent on a streaming final chunk whose choices is empty → undefined.
236
+ stopReason: asReason(get(first(get(response, "choices")), "finish_reason")),
237
+ billedCostUsd: fanoutBilledCost(model, usage),
238
+ };
239
+ }
240
+ function extractAnthropic(response, model) {
241
+ const usage = get(response, "usage");
242
+ if (usage === undefined || usage === null) {
243
+ throw new UsageExtractionError("anthropic response carries no .usage");
244
+ }
245
+ // Anthropic's input_tokens EXCLUDES both cache reads and cache writes (each a
246
+ // separate field) — read them verbatim, no subtraction. Cache creation
247
+ // (cache_creation_input_tokens) is the write-premium bucket AGGREGATE. When a
248
+ // request pins a 1-hour TTL, Anthropic breaks that down under usage.cache_creation
249
+ // into ephemeral_5m/ephemeral_1h — the 1-hour writes bill ~2x input (vs 5-minute
250
+ // ~1.25x), so split them out. The 1-hour portion goes in its own bucket and the
251
+ // 5-minute bucket is the remainder; no breakdown → 1h is 0 and the whole aggregate
252
+ // stays 5-minute, byte-identical to before.
253
+ const totalCreation = asInt(get(usage, "cache_creation_input_tokens"));
254
+ const creation1h = asInt(getPath(usage, "cache_creation", "ephemeral_1h_input_tokens"));
255
+ const creation5m = totalCreation - creation1h;
256
+ return {
257
+ provider: ANTHROPIC,
258
+ model: model ?? get(response, "model"),
259
+ inputTokens: asInt(get(usage, "input_tokens")),
260
+ outputTokens: asInt(get(usage, "output_tokens")),
261
+ cacheReadTokens: asInt(get(usage, "cache_read_input_tokens")),
262
+ // Never let a malformed breakdown push the 5-minute remainder negative.
263
+ cacheCreationTokens: creation5m > 0 ? creation5m : 0,
264
+ cacheCreation1hTokens: creation1h,
265
+ // Non-streaming carries stop_reason top-level; a STREAMING message_delta carries
266
+ // it under delta.stop_reason — read both so a streamed Fable fallback (MAR-209)
267
+ // is captured either way.
268
+ stopReason: asReason(get(response, "stop_reason") ?? getPath(response, "delta", "stop_reason")),
269
+ };
270
+ }
271
+ function extractGemini(response, model) {
272
+ const meta = usageMetadata(response);
273
+ if (meta === undefined || meta === null) {
274
+ throw new UsageExtractionError("gemini response carries no usageMetadata");
275
+ }
276
+ const cached = asInt(get(meta, "cachedContentTokenCount"));
277
+ const prompt = asInt(get(meta, "promptTokenCount"));
278
+ // promptTokenCount is INCLUSIVE of cached content — split it out.
279
+ const freshInput = prompt - cached;
280
+ // Gemini bills THINKING tokens (thoughtsTokenCount) at the output rate but
281
+ // reports them in a field DISJOINT from candidatesTokenCount (the visible
282
+ // completion). Billed output = candidates + thoughts, which also equals
283
+ // totalTokenCount - promptTokenCount. Take the max so a thinking-enabled call
284
+ // is never under-counted, whichever fields the response populates.
285
+ const candidates = asInt(get(meta, "candidatesTokenCount"));
286
+ const thoughts = asInt(get(meta, "thoughtsTokenCount"));
287
+ const total = asInt(get(meta, "totalTokenCount"));
288
+ const outputTokens = Math.max(candidates + thoughts, total ? total - prompt : 0);
289
+ return {
290
+ provider: GOOGLE,
291
+ model,
292
+ inputTokens: freshInput > 0 ? freshInput : 0,
293
+ outputTokens,
294
+ cacheReadTokens: cached,
295
+ cacheCreationTokens: 0,
296
+ // thoughts already sit inside outputTokens (billed at the output rate);
297
+ // carried here only for the reasoning-share detector, never above output.
298
+ reasoningTokens: Math.min(thoughts, outputTokens),
299
+ // finishReason nests under the first candidate ("STOP"/"MAX_TOKENS"/"SAFETY"/
300
+ // "RECITATION") and may be an enum — stringified verbatim, never interpreted. The
301
+ // generateContent result nests candidates under `.response` (like usageMetadata),
302
+ // so read both; the JS SDK spells the field camelCase.
303
+ stopReason: asReason(get(first(get(response, "candidates") ?? getPath(response, "response", "candidates")), "finishReason")),
304
+ };
305
+ }
306
+ function extractCohere(response, model) {
307
+ const usage = get(response, "usage");
308
+ if (usage === undefined || usage === null) {
309
+ throw new UsageExtractionError("cohere response carries no .usage");
310
+ }
311
+ // Cohere v2 /chat reports billed counts under `billed_units` (what is charged),
312
+ // with a raw `tokens` mirror as the fallback. input_tokens is read VERBATIM:
313
+ // Cohere publishes no chat prompt-cache discount, so a cache read bills at the
314
+ // input rate and is already inside billed_units.input — folding it into input
315
+ // (cacheReadTokens 0) is cost-exact and never over-states a caching win.
316
+ const units = get(usage, "billed_units") ?? get(usage, "tokens");
317
+ if (units === undefined || units === null) {
318
+ throw new UsageExtractionError("cohere usage carries no billed_units/tokens");
319
+ }
320
+ return {
321
+ provider: COHERE,
322
+ model: model ?? get(response, "model"),
323
+ inputTokens: asInt(get(units, "input_tokens")),
324
+ outputTokens: asInt(get(units, "output_tokens")),
325
+ cacheReadTokens: 0,
326
+ cacheCreationTokens: 0,
327
+ // Cohere v2 reports finish_reason top-level ("COMPLETE"/"MAX_TOKENS"/"ERROR").
328
+ stopReason: asReason(get(response, "finish_reason")),
329
+ };
330
+ }
331
+ function extractBedrock(response, model) {
332
+ const usage = get(response, "usage");
333
+ if (usage === undefined || usage === null) {
334
+ throw new UsageExtractionError("bedrock response carries no .usage");
335
+ }
336
+ // Bedrock's Converse usage is camelCase and — like Anthropic native —
337
+ // `inputTokens` EXCLUDES the cache buckets: AWS documents `totalTokens =
338
+ // inputTokens + outputTokens + cacheReadInputTokens + cacheWriteInputTokens`,
339
+ // so the three input-side buckets are disjoint and each reads verbatim, no
340
+ // subtraction. `cacheWriteInputTokens` is the write bucket (a cache-creation
341
+ // premium); `cacheReadInputTokens` the discounted hit. Both absent (→ 0) on a
342
+ // no-cache call. The response omits the model id, so the caller supplies it.
343
+ return {
344
+ provider: BEDROCK,
345
+ model: model ?? get(response, "model"),
346
+ inputTokens: asInt(get(usage, "inputTokens")),
347
+ outputTokens: asInt(get(usage, "outputTokens")),
348
+ cacheReadTokens: asInt(get(usage, "cacheReadInputTokens")),
349
+ cacheCreationTokens: asInt(get(usage, "cacheWriteInputTokens")),
350
+ // Converse reports stopReason ("end_turn"/"max_tokens"/"content_filtered"/
351
+ // "guardrail_intervened").
352
+ stopReason: asReason(get(response, "stopReason")),
353
+ };
354
+ }
355
+ const EXTRACTORS = {
356
+ [OPENAI]: extractOpenAI,
357
+ [ANTHROPIC]: extractAnthropic,
358
+ [GOOGLE]: extractGemini,
359
+ [COHERE]: extractCohere,
360
+ [BEDROCK]: extractBedrock,
361
+ };
362
+ /**
363
+ * Recover the metered `Usage` of one call from its provider response. `provider`
364
+ * forces the shape (the instrumenter always knows which client it patched);
365
+ * omit it and the provider is inferred from the response's shape. `model`
366
+ * overrides a response that omits its model (Gemini). Throws
367
+ * `UsageExtractionError` when the shape matches no known provider or carries no
368
+ * usage block, so a silently-free call is never emitted.
369
+ */
370
+ export function extractUsage(response, opts = {}) {
371
+ const prov = (opts.provider ?? detectProvider(response));
372
+ const extractor = prov ? EXTRACTORS[prov] : undefined;
373
+ if (!extractor) {
374
+ throw new UsageExtractionError(`unknown or undetectable provider ${String(opts.provider)}; ` +
375
+ "pass provider: 'openai' | 'anthropic' | 'google' | 'cohere' | 'bedrock'");
376
+ }
377
+ return extractor(response, opts.model);
378
+ }
379
+ // --------------------------------------------------------------------------- //
380
+ // Streaming — reunite the usage of one STREAMED call across its chunks.
381
+ //
382
+ // A `stream: true` call resolves to an async-iterable of chunks, not a `.usage`
383
+ // response, so `extractUsage` on the resolved value throws and the call would be
384
+ // dropped. Streaming is the DEFAULT mode for interactive JS agents (the Vercel
385
+ // AI SDK, LangChain.js, chat UIs), so that is a whole class of spend going
386
+ // unmetered. These primitives are the TS twin of `margin_meter.providers`'
387
+ // `StreamUsageAccumulator`: read whatever usage each chunk carries, max-merge it
388
+ // across the stream, and finalize to one `Usage` — or `undefined` when the stream
389
+ // carried no usage at all (never a fabricated zero-token, free-looking row).
390
+ // --------------------------------------------------------------------------- //
391
+ /**
392
+ * Read whatever usage ONE streaming chunk/event carries, or `undefined`.
393
+ *
394
+ * The three streamed shapes differ in WHERE (and whether) a chunk carries usage:
395
+ *
396
+ * - **OpenAI** (needs `stream_options: { include_usage: true }`): every content
397
+ * chunk has `usage: null`; only the FINAL chunk carries the full `.usage`.
398
+ * - **Gemini**: every chunk carries a CUMULATIVE `usageMetadata` — the last is
399
+ * authoritative, and the running max keeps it.
400
+ * - **Anthropic**: no single event is complete — `message_start` carries the
401
+ * input + cache counts nested under `event.message.usage`, while `message_delta`
402
+ * carries the final `event.usage.output_tokens`. This reads BOTH carriers so the
403
+ * merge can reunite them.
404
+ *
405
+ * Returns `undefined` (never throws) for a chunk with no usage, so an ordinary
406
+ * content chunk is skipped, not treated as an error.
407
+ */
408
+ export function usageFromStreamChunk(chunk, provider, model) {
409
+ // Straightforward carriers: a top-level `usage` (OpenAI final chunk, Anthropic
410
+ // message_delta) or `usageMetadata` (Gemini) — extractUsage reads either.
411
+ try {
412
+ return extractUsage(chunk, { provider, model });
413
+ }
414
+ catch {
415
+ /* not a complete-usage chunk — try the nested Anthropic carrier below */
416
+ }
417
+ // Anthropic's message_start nests the input/cache counts under
418
+ // `event.message.usage`; extractUsage on the event itself misses them, so read
419
+ // the nested message carrier directly (its usage IS the top-level shape).
420
+ const message = get(chunk, "message");
421
+ if (message !== undefined && message !== null && get(message, "usage") !== undefined) {
422
+ try {
423
+ return extractUsage(message, { provider: provider ?? ANTHROPIC, model });
424
+ }
425
+ catch {
426
+ /* not a readable message_start either */
427
+ }
428
+ }
429
+ return usageFromBedrockStreamEvent(chunk, model);
430
+ }
431
+ /**
432
+ * The usage a Bedrock STREAMING event carries, or `undefined` (MAR-1518).
433
+ *
434
+ * Both streaming calls put the counts one level below where `extractBedrock` looks:
435
+ * `converseStream`'s terminal `metadata` event nests the Converse usage block, and
436
+ * `invokeModelWithResponseStream`'s terminal `chunk.bytes` decodes to JSON carrying
437
+ * `amazon-bedrock-invocationMetrics` (no cache breakdown, so those buckets read 0).
438
+ * Ported from the Python SDK's `_usage_from_bedrock_stream_event`.
439
+ */
440
+ function usageFromBedrockStreamEvent(event, model) {
441
+ const meta = get(event, "metadata");
442
+ if (meta !== undefined && meta !== null && get(meta, "usage") !== undefined) {
443
+ try {
444
+ return extractBedrock(meta, model);
445
+ }
446
+ catch {
447
+ return undefined;
448
+ }
449
+ }
450
+ const raw = getPath(event, "chunk", "bytes");
451
+ if (raw === undefined || raw === null)
452
+ return undefined;
453
+ try {
454
+ const text = typeof raw === "string" ? raw : new TextDecoder().decode(raw);
455
+ return bedrockInvokePayloadUsage(JSON.parse(text), model);
456
+ }
457
+ catch {
458
+ return undefined;
459
+ }
460
+ }
461
+ /**
462
+ * The usage a decoded `invokeModelWithResponseStream` payload carries, or `undefined`
463
+ * (MAR-1535 #1).
464
+ *
465
+ * The payload carries `amazon-bedrock-invocationMetrics` (`inputTokenCount`/`outputTokenCount`).
466
+ * For an Anthropic model it ALSO wraps the Messages event the model streamed — `message_start`
467
+ * nests the input and CACHE counts under `message.usage`, and `message_delta` puts the final
468
+ * output tokens at the top level. Reading only the metrics block metered a cache-heavy call as
469
+ * `0` cache tokens, understating its cost; this reads both and max-merges them, and takes the
470
+ * cache buckets from the metrics block too when AWS reports them (`cacheReadInputTokenCount` /
471
+ * `cacheWriteInputTokenCount`).
472
+ */
473
+ function bedrockInvokePayloadUsage(payload, model) {
474
+ let got;
475
+ const metrics = get(payload, "amazon-bedrock-invocationMetrics");
476
+ if (metrics !== undefined && metrics !== null) {
477
+ const inp = get(metrics, "inputTokenCount");
478
+ const out = get(metrics, "outputTokenCount");
479
+ const cr = get(metrics, "cacheReadInputTokenCount");
480
+ const cw = get(metrics, "cacheWriteInputTokenCount");
481
+ if (inp !== undefined || out !== undefined || cr !== undefined || cw !== undefined) {
482
+ got = {
483
+ provider: BEDROCK,
484
+ model,
485
+ inputTokens: asInt(inp),
486
+ outputTokens: asInt(out),
487
+ cacheReadTokens: asInt(cr),
488
+ cacheCreationTokens: asInt(cw),
489
+ };
490
+ }
491
+ }
492
+ const message = get(payload, "message");
493
+ const nested = message !== undefined && message !== null && get(message, "usage") !== undefined;
494
+ const evt = nested ? message : get(payload, "usage") !== undefined ? payload : undefined;
495
+ if (evt !== undefined) {
496
+ let anthropic;
497
+ try {
498
+ anthropic = extractUsage(evt, { provider: ANTHROPIC, model });
499
+ }
500
+ catch {
501
+ anthropic = undefined;
502
+ }
503
+ if (anthropic !== undefined) {
504
+ got = got === undefined ? anthropic : mergeStreamUsage(got, anthropic);
505
+ }
506
+ }
507
+ return got;
508
+ }
509
+ /**
510
+ * Merge two per-chunk usages, taking the MAX of each token bucket.
511
+ *
512
+ * Every streamed token count is monotonic within one call — cumulative (Gemini),
513
+ * or populated exactly once (OpenAI's final chunk; Anthropic's input-here /
514
+ * output-there split) — so the running max reconstructs the final total no matter
515
+ * which chunk carried which field. The max never invents a token; it only keeps
516
+ * the largest REAL count each field reached.
517
+ */
518
+ export function mergeStreamUsage(a, b) {
519
+ return {
520
+ provider: a.provider ?? b.provider,
521
+ model: a.model ?? b.model,
522
+ inputTokens: Math.max(a.inputTokens, b.inputTokens),
523
+ outputTokens: Math.max(a.outputTokens, b.outputTokens),
524
+ cacheReadTokens: Math.max(a.cacheReadTokens, b.cacheReadTokens),
525
+ cacheCreationTokens: Math.max(a.cacheCreationTokens, b.cacheCreationTokens),
526
+ cacheCreation1hTokens: Math.max(a.cacheCreation1hTokens ?? 0, b.cacheCreation1hTokens ?? 0),
527
+ reasoningTokens: Math.max(a.reasoningTokens ?? 0, b.reasoningTokens ?? 0),
528
+ // Only a usage-bearing chunk reaches this merge, so it sees only a reason that rode
529
+ // WITH usage (Anthropic's message_delta, Gemini's final chunk, a seller that puts
530
+ // finish_reason on its usage chunk). A reason on a usage-less chunk (OpenAI's finish
531
+ // chunk, Bedrock's messageStop) is read by StreamUsageAccumulator instead (MAR-1516).
532
+ stopReason: a.stopReason ?? b.stopReason,
533
+ // A fan-out stream's billed cost rides its final usage chunk (MAR-1309).
534
+ billedCostUsd: a.billedCostUsd ?? b.billedCostUsd,
535
+ };
536
+ }
537
+ /**
538
+ * The stop reason one stream chunk carries, if any. Never throws.
539
+ *
540
+ * A stream rarely puts the reason and the usage on the same chunk (MAR-1516). OpenAI's
541
+ * finish chunk has no `usage` and the usage chunk after it has empty `choices`; Bedrock
542
+ * `converseStream` sends `stopReason` in `messageStop` and usage in a separate
543
+ * `metadata` event. A reader that only looks at usage-bearing chunks records every
544
+ * streamed call with no reason, so this reads it from whichever chunk holds it.
545
+ */
546
+ export function streamChunkStopReason(chunk) {
547
+ try {
548
+ let reason = get(first(get(chunk, "choices")), "finish_reason") ?? // OpenAI
549
+ getPath(chunk, "delta", "stop_reason") ?? // Anthropic message_delta
550
+ getPath(chunk, "messageStop", "stopReason"); // Bedrock converseStream
551
+ if (reason === undefined || reason === null) {
552
+ const raw = getPath(chunk, "chunk", "bytes"); // Bedrock invoke stream
553
+ if (raw !== undefined && raw !== null) {
554
+ const text = typeof raw === "string" ? raw : new TextDecoder().decode(raw);
555
+ const payload = JSON.parse(text);
556
+ reason =
557
+ getPath(payload, "delta", "stop_reason") ??
558
+ get(payload, "stop_reason") ??
559
+ get(payload, "completionReason");
560
+ }
561
+ }
562
+ return asReason(reason);
563
+ }
564
+ catch {
565
+ return undefined;
566
+ }
567
+ }
568
+ /**
569
+ * Accumulates the metered usage of one STREAMING call across its chunks.
570
+ *
571
+ * Feed every chunk to `observe` as the host iterates the stream, then call
572
+ * `finalize` once the stream is exhausted (or closed) to get the single `Usage`
573
+ * for the whole call — or `undefined` when the stream never carried a usage block
574
+ * (e.g. an OpenAI stream opened without `include_usage`, where there is genuinely
575
+ * no count to meter and inventing one would be a lie). Provider-agnostic: the
576
+ * per-chunk read + max-merge handles OpenAI, Anthropic and Gemini streams alike.
577
+ */
578
+ export class StreamUsageAccumulator {
579
+ provider;
580
+ model;
581
+ usage = undefined;
582
+ stopReason = undefined;
583
+ // Explicit assignment (not constructor parameter properties) so the source is
584
+ // erasable TypeScript — `node --experimental-strip-types` runs it with no build.
585
+ constructor(provider, model) {
586
+ this.provider = provider;
587
+ this.model = model;
588
+ }
589
+ /** Fold one chunk's usage (if any) into the running total. Never throws. */
590
+ observe(chunk) {
591
+ this.stopReason = streamChunkStopReason(chunk) ?? this.stopReason;
592
+ let u;
593
+ try {
594
+ u = usageFromStreamChunk(chunk, this.provider, this.model);
595
+ }
596
+ catch {
597
+ return; // a malformed chunk must never break the host's stream
598
+ }
599
+ if (u === undefined)
600
+ return;
601
+ this.usage = this.usage === undefined ? u : mergeStreamUsage(this.usage, u);
602
+ }
603
+ /** The accumulated usage, or `undefined` if the stream carried no usage. */
604
+ finalize() {
605
+ if (this.usage === undefined)
606
+ return undefined;
607
+ // The usage-bearing chunk's own reason wins; otherwise the one another chunk carried.
608
+ return { ...this.usage, stopReason: this.usage.stopReason ?? this.stopReason };
609
+ }
610
+ }
611
+ //# sourceMappingURL=providers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"providers.js","sourceRoot":"","sources":["../src/providers.ts"],"names":[],"mappings":"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"}