floe-guard 0.10.0 → 0.12.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,1391 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/adapters/livekit.ts
21
+ var livekit_exports = {};
22
+ __export(livekit_exports, {
23
+ LiveKitBudgetGuard: () => LiveKitBudgetGuard
24
+ });
25
+ module.exports = __toCommonJS(livekit_exports);
26
+
27
+ // src/errors.ts
28
+ var FloeGuardError = class extends Error {
29
+ constructor(message) {
30
+ super(message);
31
+ this.name = "FloeGuardError";
32
+ Object.setPrototypeOf(this, new.target.prototype);
33
+ }
34
+ };
35
+ var BudgetExceeded = class extends FloeGuardError {
36
+ spentUsd;
37
+ limitUsd;
38
+ constructor(spentUsd, limitUsd, message) {
39
+ super(
40
+ message ?? `BUDGET EXCEEDED \u2014 call blocked (spent $${spentUsd.toFixed(6)} of $${limitUsd.toFixed(6)} ceiling)`
41
+ );
42
+ this.name = "BudgetExceeded";
43
+ this.spentUsd = spentUsd;
44
+ this.limitUsd = limitUsd;
45
+ }
46
+ };
47
+ var UnpriceableVoiceError = class extends FloeGuardError {
48
+ vendor;
49
+ mode;
50
+ constructor(vendor, mode) {
51
+ const shown = vendor === null ? "None" : `'${vendor}'`;
52
+ super(
53
+ `Cannot price ${mode} vendor ${shown}: not in the bundled voice cost map (or its entry has the wrong unit for a ${mode} leg) and no per-unit override was given. The guard cannot enforce a budget on spend it cannot measure. Pass a per-unit rate to enable enforcement.`
54
+ );
55
+ this.name = "UnpriceableVoiceError";
56
+ this.vendor = vendor;
57
+ this.mode = mode;
58
+ }
59
+ };
60
+
61
+ // src/gates.ts
62
+ function budgetExhausted(guard, options = {}) {
63
+ const estimatedCallUsd = options.estimatedCallUsd === void 0 ? 0 : options.estimatedCallUsd;
64
+ if (!Number.isFinite(estimatedCallUsd) || estimatedCallUsd < 0) {
65
+ throw new RangeError(
66
+ `estimatedCallUsd must be a finite, non-negative number, got ${estimatedCallUsd}`
67
+ );
68
+ }
69
+ const remainingUsd = guard.remainingUsd;
70
+ return remainingUsd <= 0 || remainingUsd < estimatedCallUsd;
71
+ }
72
+ function preCall(guard, options = {}) {
73
+ return !budgetExhausted(guard, options);
74
+ }
75
+
76
+ // src/cost_map.json
77
+ var cost_map_default = {
78
+ "chatgpt-4o-latest": {
79
+ input_cost_per_token: 5e-6,
80
+ output_cost_per_token: 15e-6,
81
+ litellm_provider: "openai",
82
+ mode: "chat"
83
+ },
84
+ "claude-3-7-sonnet-20250219": {
85
+ input_cost_per_token: 3e-6,
86
+ output_cost_per_token: 15e-6,
87
+ litellm_provider: "anthropic",
88
+ mode: "chat"
89
+ },
90
+ "claude-3-haiku-20240307": {
91
+ input_cost_per_token: 25e-8,
92
+ output_cost_per_token: 125e-8,
93
+ litellm_provider: "anthropic",
94
+ mode: "chat"
95
+ },
96
+ "claude-3-opus-20240229": {
97
+ input_cost_per_token: 15e-6,
98
+ output_cost_per_token: 75e-6,
99
+ litellm_provider: "anthropic",
100
+ mode: "chat"
101
+ },
102
+ "claude-4-opus-20250514": {
103
+ input_cost_per_token: 15e-6,
104
+ output_cost_per_token: 75e-6,
105
+ litellm_provider: "anthropic",
106
+ mode: "chat"
107
+ },
108
+ "claude-4-sonnet-20250514": {
109
+ input_cost_per_token: 3e-6,
110
+ output_cost_per_token: 15e-6,
111
+ litellm_provider: "anthropic",
112
+ mode: "chat"
113
+ },
114
+ "claude-fable-5": {
115
+ input_cost_per_token: 1e-5,
116
+ output_cost_per_token: 5e-5,
117
+ litellm_provider: "anthropic",
118
+ mode: "chat"
119
+ },
120
+ "claude-haiku-4-5": {
121
+ input_cost_per_token: 1e-6,
122
+ output_cost_per_token: 5e-6,
123
+ litellm_provider: "anthropic",
124
+ mode: "chat"
125
+ },
126
+ "claude-haiku-4-5-20251001": {
127
+ input_cost_per_token: 1e-6,
128
+ output_cost_per_token: 5e-6,
129
+ litellm_provider: "anthropic",
130
+ mode: "chat"
131
+ },
132
+ "claude-opus-4-1": {
133
+ input_cost_per_token: 15e-6,
134
+ output_cost_per_token: 75e-6,
135
+ litellm_provider: "anthropic",
136
+ mode: "chat"
137
+ },
138
+ "claude-opus-4-1-20250805": {
139
+ input_cost_per_token: 15e-6,
140
+ output_cost_per_token: 75e-6,
141
+ litellm_provider: "anthropic",
142
+ mode: "chat"
143
+ },
144
+ "claude-opus-4-20250514": {
145
+ input_cost_per_token: 15e-6,
146
+ output_cost_per_token: 75e-6,
147
+ litellm_provider: "anthropic",
148
+ mode: "chat"
149
+ },
150
+ "claude-opus-4-5": {
151
+ input_cost_per_token: 5e-6,
152
+ output_cost_per_token: 25e-6,
153
+ litellm_provider: "anthropic",
154
+ mode: "chat"
155
+ },
156
+ "claude-opus-4-5-20251101": {
157
+ input_cost_per_token: 5e-6,
158
+ output_cost_per_token: 25e-6,
159
+ litellm_provider: "anthropic",
160
+ mode: "chat"
161
+ },
162
+ "claude-opus-4-6": {
163
+ input_cost_per_token: 5e-6,
164
+ output_cost_per_token: 25e-6,
165
+ litellm_provider: "anthropic",
166
+ mode: "chat"
167
+ },
168
+ "claude-opus-4-6-20260205": {
169
+ input_cost_per_token: 5e-6,
170
+ output_cost_per_token: 25e-6,
171
+ litellm_provider: "anthropic",
172
+ mode: "chat"
173
+ },
174
+ "claude-opus-4-7": {
175
+ input_cost_per_token: 5e-6,
176
+ output_cost_per_token: 25e-6,
177
+ litellm_provider: "anthropic",
178
+ mode: "chat"
179
+ },
180
+ "claude-opus-4-7-20260416": {
181
+ input_cost_per_token: 5e-6,
182
+ output_cost_per_token: 25e-6,
183
+ litellm_provider: "anthropic",
184
+ mode: "chat"
185
+ },
186
+ "claude-opus-4-8": {
187
+ input_cost_per_token: 5e-6,
188
+ output_cost_per_token: 25e-6,
189
+ litellm_provider: "anthropic",
190
+ mode: "chat"
191
+ },
192
+ "claude-opus-5": {
193
+ input_cost_per_token: 5e-6,
194
+ output_cost_per_token: 25e-6,
195
+ litellm_provider: "anthropic",
196
+ mode: "chat"
197
+ },
198
+ "claude-sonnet-4-20250514": {
199
+ input_cost_per_token: 3e-6,
200
+ output_cost_per_token: 15e-6,
201
+ litellm_provider: "anthropic",
202
+ mode: "chat"
203
+ },
204
+ "claude-sonnet-4-5": {
205
+ input_cost_per_token: 3e-6,
206
+ output_cost_per_token: 15e-6,
207
+ litellm_provider: "anthropic",
208
+ mode: "chat"
209
+ },
210
+ "claude-sonnet-4-5-20250929": {
211
+ input_cost_per_token: 3e-6,
212
+ output_cost_per_token: 15e-6,
213
+ litellm_provider: "anthropic",
214
+ mode: "chat"
215
+ },
216
+ "claude-sonnet-4-6": {
217
+ input_cost_per_token: 3e-6,
218
+ output_cost_per_token: 15e-6,
219
+ litellm_provider: "anthropic",
220
+ mode: "chat"
221
+ },
222
+ "claude-sonnet-5": {
223
+ input_cost_per_token: 2e-6,
224
+ output_cost_per_token: 1e-5,
225
+ litellm_provider: "anthropic",
226
+ mode: "chat"
227
+ },
228
+ "ft:gpt-3.5-turbo": {
229
+ input_cost_per_token: 3e-6,
230
+ output_cost_per_token: 6e-6,
231
+ litellm_provider: "openai",
232
+ mode: "chat"
233
+ },
234
+ "ft:gpt-3.5-turbo-0125": {
235
+ input_cost_per_token: 3e-6,
236
+ output_cost_per_token: 6e-6,
237
+ litellm_provider: "openai",
238
+ mode: "chat"
239
+ },
240
+ "ft:gpt-3.5-turbo-0613": {
241
+ input_cost_per_token: 3e-6,
242
+ output_cost_per_token: 6e-6,
243
+ litellm_provider: "openai",
244
+ mode: "chat"
245
+ },
246
+ "ft:gpt-3.5-turbo-1106": {
247
+ input_cost_per_token: 3e-6,
248
+ output_cost_per_token: 6e-6,
249
+ litellm_provider: "openai",
250
+ mode: "chat"
251
+ },
252
+ "ft:gpt-4-0613": {
253
+ input_cost_per_token: 3e-5,
254
+ output_cost_per_token: 6e-5,
255
+ litellm_provider: "openai",
256
+ mode: "chat"
257
+ },
258
+ "ft:gpt-4.1-2025-04-14": {
259
+ input_cost_per_token: 3e-6,
260
+ output_cost_per_token: 12e-6,
261
+ litellm_provider: "openai",
262
+ mode: "chat"
263
+ },
264
+ "ft:gpt-4.1-mini-2025-04-14": {
265
+ input_cost_per_token: 8e-7,
266
+ output_cost_per_token: 32e-7,
267
+ litellm_provider: "openai",
268
+ mode: "chat"
269
+ },
270
+ "ft:gpt-4.1-nano-2025-04-14": {
271
+ input_cost_per_token: 2e-7,
272
+ output_cost_per_token: 8e-7,
273
+ litellm_provider: "openai",
274
+ mode: "chat"
275
+ },
276
+ "ft:gpt-4o-2024-08-06": {
277
+ input_cost_per_token: 375e-8,
278
+ output_cost_per_token: 15e-6,
279
+ litellm_provider: "openai",
280
+ mode: "chat"
281
+ },
282
+ "ft:gpt-4o-2024-11-20": {
283
+ input_cost_per_token: 375e-8,
284
+ output_cost_per_token: 15e-6,
285
+ litellm_provider: "openai",
286
+ mode: "chat"
287
+ },
288
+ "ft:gpt-4o-mini-2024-07-18": {
289
+ input_cost_per_token: 3e-7,
290
+ output_cost_per_token: 12e-7,
291
+ litellm_provider: "openai",
292
+ mode: "chat"
293
+ },
294
+ "ft:o4-mini-2025-04-16": {
295
+ input_cost_per_token: 4e-6,
296
+ output_cost_per_token: 16e-6,
297
+ litellm_provider: "openai",
298
+ mode: "chat"
299
+ },
300
+ "gemini-2.0-flash": {
301
+ input_cost_per_token: 1e-7,
302
+ output_cost_per_token: 4e-7,
303
+ litellm_provider: "gemini",
304
+ mode: "chat"
305
+ },
306
+ "gemini-2.0-flash-001": {
307
+ input_cost_per_token: 1e-7,
308
+ output_cost_per_token: 4e-7,
309
+ litellm_provider: "gemini",
310
+ mode: "chat"
311
+ },
312
+ "gemini-2.0-flash-lite": {
313
+ input_cost_per_token: 75e-9,
314
+ output_cost_per_token: 3e-7,
315
+ litellm_provider: "gemini",
316
+ mode: "chat"
317
+ },
318
+ "gemini-2.0-flash-lite-001": {
319
+ input_cost_per_token: 75e-9,
320
+ output_cost_per_token: 3e-7,
321
+ litellm_provider: "gemini",
322
+ mode: "chat"
323
+ },
324
+ "gemini-2.5-computer-use-preview-10-2025": {
325
+ input_cost_per_token: 125e-8,
326
+ output_cost_per_token: 1e-5,
327
+ litellm_provider: "gemini",
328
+ mode: "chat"
329
+ },
330
+ "gemini-2.5-flash": {
331
+ input_cost_per_token: 3e-7,
332
+ output_cost_per_token: 25e-7,
333
+ litellm_provider: "gemini",
334
+ mode: "chat"
335
+ },
336
+ "gemini-2.5-flash-lite": {
337
+ input_cost_per_token: 1e-7,
338
+ output_cost_per_token: 4e-7,
339
+ litellm_provider: "gemini",
340
+ mode: "chat"
341
+ },
342
+ "gemini-2.5-flash-lite-preview-06-17": {
343
+ input_cost_per_token: 1e-7,
344
+ output_cost_per_token: 4e-7,
345
+ litellm_provider: "gemini",
346
+ mode: "chat"
347
+ },
348
+ "gemini-2.5-flash-lite-preview-09-2025": {
349
+ input_cost_per_token: 1e-7,
350
+ output_cost_per_token: 4e-7,
351
+ litellm_provider: "gemini",
352
+ mode: "chat"
353
+ },
354
+ "gemini-2.5-flash-native-audio-latest": {
355
+ input_cost_per_token: 3e-7,
356
+ output_cost_per_token: 25e-7,
357
+ litellm_provider: "gemini",
358
+ mode: "chat"
359
+ },
360
+ "gemini-2.5-flash-native-audio-preview-09-2025": {
361
+ input_cost_per_token: 3e-7,
362
+ output_cost_per_token: 25e-7,
363
+ litellm_provider: "gemini",
364
+ mode: "chat"
365
+ },
366
+ "gemini-2.5-flash-native-audio-preview-12-2025": {
367
+ input_cost_per_token: 3e-7,
368
+ output_cost_per_token: 25e-7,
369
+ litellm_provider: "gemini",
370
+ mode: "chat"
371
+ },
372
+ "gemini-2.5-flash-preview-09-2025": {
373
+ input_cost_per_token: 3e-7,
374
+ output_cost_per_token: 25e-7,
375
+ litellm_provider: "gemini",
376
+ mode: "chat"
377
+ },
378
+ "gemini-2.5-pro": {
379
+ input_cost_per_token: 125e-8,
380
+ output_cost_per_token: 1e-5,
381
+ litellm_provider: "gemini",
382
+ mode: "chat"
383
+ },
384
+ "gemini-2.5-pro-preview-tts": {
385
+ input_cost_per_token: 125e-8,
386
+ output_cost_per_token: 1e-5,
387
+ litellm_provider: "gemini",
388
+ mode: "chat"
389
+ },
390
+ "gemini-3-flash-preview": {
391
+ input_cost_per_token: 5e-7,
392
+ output_cost_per_token: 3e-6,
393
+ litellm_provider: "gemini",
394
+ mode: "chat"
395
+ },
396
+ "gemini-3-pro-preview": {
397
+ input_cost_per_token: 2e-6,
398
+ output_cost_per_token: 12e-6,
399
+ litellm_provider: "gemini",
400
+ mode: "chat"
401
+ },
402
+ "gemini-3.1-flash-lite": {
403
+ input_cost_per_token: 25e-8,
404
+ output_cost_per_token: 15e-7,
405
+ litellm_provider: "gemini",
406
+ mode: "chat"
407
+ },
408
+ "gemini-3.1-flash-lite-preview": {
409
+ input_cost_per_token: 25e-8,
410
+ output_cost_per_token: 15e-7,
411
+ litellm_provider: "gemini",
412
+ mode: "chat"
413
+ },
414
+ "gemini-3.1-flash-live-preview": {
415
+ input_cost_per_token: 75e-8,
416
+ output_cost_per_token: 45e-7,
417
+ litellm_provider: "gemini",
418
+ mode: "chat"
419
+ },
420
+ "gemini-3.1-pro-preview": {
421
+ input_cost_per_token: 2e-6,
422
+ output_cost_per_token: 12e-6,
423
+ litellm_provider: "gemini",
424
+ mode: "chat"
425
+ },
426
+ "gemini-3.1-pro-preview-customtools": {
427
+ input_cost_per_token: 2e-6,
428
+ output_cost_per_token: 12e-6,
429
+ litellm_provider: "gemini",
430
+ mode: "chat"
431
+ },
432
+ "gemini-3.5-flash": {
433
+ input_cost_per_token: 15e-7,
434
+ output_cost_per_token: 9e-6,
435
+ litellm_provider: "gemini",
436
+ mode: "chat"
437
+ },
438
+ "gemini-3.5-flash-lite": {
439
+ input_cost_per_token: 3e-7,
440
+ output_cost_per_token: 25e-7,
441
+ litellm_provider: "gemini",
442
+ mode: "chat"
443
+ },
444
+ "gemini-3.6-flash": {
445
+ input_cost_per_token: 15e-7,
446
+ output_cost_per_token: 75e-7,
447
+ litellm_provider: "gemini",
448
+ mode: "chat"
449
+ },
450
+ "gemini-embedding-001": {
451
+ input_cost_per_token: 15e-8,
452
+ output_cost_per_token: 0,
453
+ litellm_provider: "gemini",
454
+ mode: "embedding"
455
+ },
456
+ "gemini-embedding-2": {
457
+ input_cost_per_token: 2e-7,
458
+ output_cost_per_token: 0,
459
+ litellm_provider: "gemini",
460
+ mode: "embedding"
461
+ },
462
+ "gemini-embedding-2-preview": {
463
+ input_cost_per_token: 2e-7,
464
+ output_cost_per_token: 0,
465
+ litellm_provider: "gemini",
466
+ mode: "embedding"
467
+ },
468
+ "gemini-exp-1206": {
469
+ input_cost_per_token: 3e-7,
470
+ output_cost_per_token: 25e-7,
471
+ litellm_provider: "gemini",
472
+ mode: "chat"
473
+ },
474
+ "gemini-flash-latest": {
475
+ input_cost_per_token: 3e-7,
476
+ output_cost_per_token: 25e-7,
477
+ litellm_provider: "gemini",
478
+ mode: "chat"
479
+ },
480
+ "gemini-flash-lite-latest": {
481
+ input_cost_per_token: 1e-7,
482
+ output_cost_per_token: 4e-7,
483
+ litellm_provider: "gemini",
484
+ mode: "chat"
485
+ },
486
+ "gemini-gemma-2-27b-it": {
487
+ input_cost_per_token: 35e-8,
488
+ output_cost_per_token: 105e-8,
489
+ litellm_provider: "gemini",
490
+ mode: "chat"
491
+ },
492
+ "gemini-gemma-2-9b-it": {
493
+ input_cost_per_token: 35e-8,
494
+ output_cost_per_token: 105e-8,
495
+ litellm_provider: "gemini",
496
+ mode: "chat"
497
+ },
498
+ "gemini-omni-flash-preview": {
499
+ input_cost_per_token: 15e-7,
500
+ output_cost_per_token: 9e-6,
501
+ litellm_provider: "gemini",
502
+ mode: "chat"
503
+ },
504
+ "gemini-pro-latest": {
505
+ input_cost_per_token: 125e-8,
506
+ output_cost_per_token: 1e-5,
507
+ litellm_provider: "gemini",
508
+ mode: "chat"
509
+ },
510
+ "gemini-robotics-er-1.5-preview": {
511
+ input_cost_per_token: 3e-7,
512
+ output_cost_per_token: 25e-7,
513
+ litellm_provider: "gemini",
514
+ mode: "chat"
515
+ },
516
+ "gemini-robotics-er-1.6-preview": {
517
+ input_cost_per_token: 1e-6,
518
+ output_cost_per_token: 5e-6,
519
+ litellm_provider: "gemini",
520
+ mode: "chat"
521
+ },
522
+ "gemini-robotics-er-2-preview": {
523
+ input_cost_per_token: 2e-6,
524
+ output_cost_per_token: 1e-5,
525
+ litellm_provider: "gemini",
526
+ mode: "chat"
527
+ },
528
+ "gpt-3.5-turbo": {
529
+ input_cost_per_token: 5e-7,
530
+ output_cost_per_token: 15e-7,
531
+ litellm_provider: "openai",
532
+ mode: "chat"
533
+ },
534
+ "gpt-3.5-turbo-0125": {
535
+ input_cost_per_token: 5e-7,
536
+ output_cost_per_token: 15e-7,
537
+ litellm_provider: "openai",
538
+ mode: "chat"
539
+ },
540
+ "gpt-3.5-turbo-1106": {
541
+ input_cost_per_token: 1e-6,
542
+ output_cost_per_token: 2e-6,
543
+ litellm_provider: "openai",
544
+ mode: "chat"
545
+ },
546
+ "gpt-3.5-turbo-16k": {
547
+ input_cost_per_token: 3e-6,
548
+ output_cost_per_token: 4e-6,
549
+ litellm_provider: "openai",
550
+ mode: "chat"
551
+ },
552
+ "gpt-4": {
553
+ input_cost_per_token: 3e-5,
554
+ output_cost_per_token: 6e-5,
555
+ litellm_provider: "openai",
556
+ mode: "chat"
557
+ },
558
+ "gpt-4-0125-preview": {
559
+ input_cost_per_token: 1e-5,
560
+ output_cost_per_token: 3e-5,
561
+ litellm_provider: "openai",
562
+ mode: "chat"
563
+ },
564
+ "gpt-4-0314": {
565
+ input_cost_per_token: 3e-5,
566
+ output_cost_per_token: 6e-5,
567
+ litellm_provider: "openai",
568
+ mode: "chat"
569
+ },
570
+ "gpt-4-0613": {
571
+ input_cost_per_token: 3e-5,
572
+ output_cost_per_token: 6e-5,
573
+ litellm_provider: "openai",
574
+ mode: "chat"
575
+ },
576
+ "gpt-4-1106-preview": {
577
+ input_cost_per_token: 1e-5,
578
+ output_cost_per_token: 3e-5,
579
+ litellm_provider: "openai",
580
+ mode: "chat"
581
+ },
582
+ "gpt-4-turbo": {
583
+ input_cost_per_token: 1e-5,
584
+ output_cost_per_token: 3e-5,
585
+ litellm_provider: "openai",
586
+ mode: "chat"
587
+ },
588
+ "gpt-4-turbo-2024-04-09": {
589
+ input_cost_per_token: 1e-5,
590
+ output_cost_per_token: 3e-5,
591
+ litellm_provider: "openai",
592
+ mode: "chat"
593
+ },
594
+ "gpt-4-turbo-preview": {
595
+ input_cost_per_token: 1e-5,
596
+ output_cost_per_token: 3e-5,
597
+ litellm_provider: "openai",
598
+ mode: "chat"
599
+ },
600
+ "gpt-4.1": {
601
+ input_cost_per_token: 2e-6,
602
+ output_cost_per_token: 8e-6,
603
+ litellm_provider: "openai",
604
+ mode: "chat"
605
+ },
606
+ "gpt-4.1-2025-04-14": {
607
+ input_cost_per_token: 2e-6,
608
+ output_cost_per_token: 8e-6,
609
+ litellm_provider: "openai",
610
+ mode: "chat"
611
+ },
612
+ "gpt-4.1-mini": {
613
+ input_cost_per_token: 4e-7,
614
+ output_cost_per_token: 16e-7,
615
+ litellm_provider: "openai",
616
+ mode: "chat"
617
+ },
618
+ "gpt-4.1-mini-2025-04-14": {
619
+ input_cost_per_token: 4e-7,
620
+ output_cost_per_token: 16e-7,
621
+ litellm_provider: "openai",
622
+ mode: "chat"
623
+ },
624
+ "gpt-4.1-nano": {
625
+ input_cost_per_token: 1e-7,
626
+ output_cost_per_token: 4e-7,
627
+ litellm_provider: "openai",
628
+ mode: "chat"
629
+ },
630
+ "gpt-4.1-nano-2025-04-14": {
631
+ input_cost_per_token: 1e-7,
632
+ output_cost_per_token: 4e-7,
633
+ litellm_provider: "openai",
634
+ mode: "chat"
635
+ },
636
+ "gpt-4o": {
637
+ input_cost_per_token: 25e-7,
638
+ output_cost_per_token: 1e-5,
639
+ litellm_provider: "openai",
640
+ mode: "chat"
641
+ },
642
+ "gpt-4o-2024-05-13": {
643
+ input_cost_per_token: 5e-6,
644
+ output_cost_per_token: 15e-6,
645
+ litellm_provider: "openai",
646
+ mode: "chat"
647
+ },
648
+ "gpt-4o-2024-08-06": {
649
+ input_cost_per_token: 25e-7,
650
+ output_cost_per_token: 1e-5,
651
+ litellm_provider: "openai",
652
+ mode: "chat"
653
+ },
654
+ "gpt-4o-2024-11-20": {
655
+ input_cost_per_token: 25e-7,
656
+ output_cost_per_token: 1e-5,
657
+ litellm_provider: "openai",
658
+ mode: "chat"
659
+ },
660
+ "gpt-4o-audio-preview": {
661
+ input_cost_per_token: 25e-7,
662
+ output_cost_per_token: 1e-5,
663
+ litellm_provider: "openai",
664
+ mode: "chat"
665
+ },
666
+ "gpt-4o-audio-preview-2024-12-17": {
667
+ input_cost_per_token: 25e-7,
668
+ output_cost_per_token: 1e-5,
669
+ litellm_provider: "openai",
670
+ mode: "chat"
671
+ },
672
+ "gpt-4o-audio-preview-2025-06-03": {
673
+ input_cost_per_token: 25e-7,
674
+ output_cost_per_token: 1e-5,
675
+ litellm_provider: "openai",
676
+ mode: "chat"
677
+ },
678
+ "gpt-4o-mini": {
679
+ input_cost_per_token: 15e-8,
680
+ output_cost_per_token: 6e-7,
681
+ litellm_provider: "openai",
682
+ mode: "chat"
683
+ },
684
+ "gpt-4o-mini-2024-07-18": {
685
+ input_cost_per_token: 15e-8,
686
+ output_cost_per_token: 6e-7,
687
+ litellm_provider: "openai",
688
+ mode: "chat"
689
+ },
690
+ "gpt-4o-mini-audio-preview": {
691
+ input_cost_per_token: 15e-8,
692
+ output_cost_per_token: 6e-7,
693
+ litellm_provider: "openai",
694
+ mode: "chat"
695
+ },
696
+ "gpt-4o-mini-audio-preview-2024-12-17": {
697
+ input_cost_per_token: 15e-8,
698
+ output_cost_per_token: 6e-7,
699
+ litellm_provider: "openai",
700
+ mode: "chat"
701
+ },
702
+ "gpt-4o-mini-search-preview": {
703
+ input_cost_per_token: 15e-8,
704
+ output_cost_per_token: 6e-7,
705
+ litellm_provider: "openai",
706
+ mode: "chat"
707
+ },
708
+ "gpt-4o-mini-search-preview-2025-03-11": {
709
+ input_cost_per_token: 15e-8,
710
+ output_cost_per_token: 6e-7,
711
+ litellm_provider: "openai",
712
+ mode: "chat"
713
+ },
714
+ "gpt-4o-search-preview": {
715
+ input_cost_per_token: 25e-7,
716
+ output_cost_per_token: 1e-5,
717
+ litellm_provider: "openai",
718
+ mode: "chat"
719
+ },
720
+ "gpt-4o-search-preview-2025-03-11": {
721
+ input_cost_per_token: 25e-7,
722
+ output_cost_per_token: 1e-5,
723
+ litellm_provider: "openai",
724
+ mode: "chat"
725
+ },
726
+ "gpt-5": {
727
+ input_cost_per_token: 125e-8,
728
+ output_cost_per_token: 1e-5,
729
+ litellm_provider: "openai",
730
+ mode: "chat"
731
+ },
732
+ "gpt-5-2025-08-07": {
733
+ input_cost_per_token: 125e-8,
734
+ output_cost_per_token: 1e-5,
735
+ litellm_provider: "openai",
736
+ mode: "chat"
737
+ },
738
+ "gpt-5-chat": {
739
+ input_cost_per_token: 125e-8,
740
+ output_cost_per_token: 1e-5,
741
+ litellm_provider: "openai",
742
+ mode: "chat"
743
+ },
744
+ "gpt-5-chat-latest": {
745
+ input_cost_per_token: 125e-8,
746
+ output_cost_per_token: 1e-5,
747
+ litellm_provider: "openai",
748
+ mode: "chat"
749
+ },
750
+ "gpt-5-mini": {
751
+ input_cost_per_token: 25e-8,
752
+ output_cost_per_token: 2e-6,
753
+ litellm_provider: "openai",
754
+ mode: "chat"
755
+ },
756
+ "gpt-5-mini-2025-08-07": {
757
+ input_cost_per_token: 25e-8,
758
+ output_cost_per_token: 2e-6,
759
+ litellm_provider: "openai",
760
+ mode: "chat"
761
+ },
762
+ "gpt-5-nano": {
763
+ input_cost_per_token: 5e-8,
764
+ output_cost_per_token: 4e-7,
765
+ litellm_provider: "openai",
766
+ mode: "chat"
767
+ },
768
+ "gpt-5-nano-2025-08-07": {
769
+ input_cost_per_token: 5e-8,
770
+ output_cost_per_token: 4e-7,
771
+ litellm_provider: "openai",
772
+ mode: "chat"
773
+ },
774
+ "gpt-5-search-api": {
775
+ input_cost_per_token: 125e-8,
776
+ output_cost_per_token: 1e-5,
777
+ litellm_provider: "openai",
778
+ mode: "chat"
779
+ },
780
+ "gpt-5-search-api-2025-10-14": {
781
+ input_cost_per_token: 125e-8,
782
+ output_cost_per_token: 1e-5,
783
+ litellm_provider: "openai",
784
+ mode: "chat"
785
+ },
786
+ "gpt-5.1": {
787
+ input_cost_per_token: 125e-8,
788
+ output_cost_per_token: 1e-5,
789
+ litellm_provider: "openai",
790
+ mode: "chat"
791
+ },
792
+ "gpt-5.1-2025-11-13": {
793
+ input_cost_per_token: 125e-8,
794
+ output_cost_per_token: 1e-5,
795
+ litellm_provider: "openai",
796
+ mode: "chat"
797
+ },
798
+ "gpt-5.1-chat-latest": {
799
+ input_cost_per_token: 125e-8,
800
+ output_cost_per_token: 1e-5,
801
+ litellm_provider: "openai",
802
+ mode: "chat"
803
+ },
804
+ "gpt-5.2": {
805
+ input_cost_per_token: 175e-8,
806
+ output_cost_per_token: 14e-6,
807
+ litellm_provider: "openai",
808
+ mode: "chat"
809
+ },
810
+ "gpt-5.2-2025-12-11": {
811
+ input_cost_per_token: 175e-8,
812
+ output_cost_per_token: 14e-6,
813
+ litellm_provider: "openai",
814
+ mode: "chat"
815
+ },
816
+ "gpt-5.2-chat-latest": {
817
+ input_cost_per_token: 175e-8,
818
+ output_cost_per_token: 14e-6,
819
+ litellm_provider: "openai",
820
+ mode: "chat"
821
+ },
822
+ "gpt-5.3-chat-latest": {
823
+ input_cost_per_token: 175e-8,
824
+ output_cost_per_token: 14e-6,
825
+ litellm_provider: "openai",
826
+ mode: "chat"
827
+ },
828
+ "gpt-5.4": {
829
+ input_cost_per_token: 25e-7,
830
+ output_cost_per_token: 15e-6,
831
+ litellm_provider: "openai",
832
+ mode: "chat"
833
+ },
834
+ "gpt-5.4-2026-03-05": {
835
+ input_cost_per_token: 25e-7,
836
+ output_cost_per_token: 15e-6,
837
+ litellm_provider: "openai",
838
+ mode: "chat"
839
+ },
840
+ "gpt-5.4-mini": {
841
+ input_cost_per_token: 75e-8,
842
+ output_cost_per_token: 45e-7,
843
+ litellm_provider: "openai",
844
+ mode: "chat"
845
+ },
846
+ "gpt-5.4-mini-2026-03-17": {
847
+ input_cost_per_token: 75e-8,
848
+ output_cost_per_token: 45e-7,
849
+ litellm_provider: "openai",
850
+ mode: "chat"
851
+ },
852
+ "gpt-5.4-nano": {
853
+ input_cost_per_token: 2e-7,
854
+ output_cost_per_token: 125e-8,
855
+ litellm_provider: "openai",
856
+ mode: "chat"
857
+ },
858
+ "gpt-5.4-nano-2026-03-17": {
859
+ input_cost_per_token: 2e-7,
860
+ output_cost_per_token: 125e-8,
861
+ litellm_provider: "openai",
862
+ mode: "chat"
863
+ },
864
+ "gpt-5.5": {
865
+ input_cost_per_token: 5e-6,
866
+ output_cost_per_token: 3e-5,
867
+ litellm_provider: "openai",
868
+ mode: "chat"
869
+ },
870
+ "gpt-5.5-2026-04-23": {
871
+ input_cost_per_token: 5e-6,
872
+ output_cost_per_token: 3e-5,
873
+ litellm_provider: "openai",
874
+ mode: "chat"
875
+ },
876
+ "gpt-5.6": {
877
+ input_cost_per_token: 5e-6,
878
+ output_cost_per_token: 3e-5,
879
+ litellm_provider: "openai",
880
+ mode: "chat"
881
+ },
882
+ "gpt-5.6-luna": {
883
+ input_cost_per_token: 2e-7,
884
+ output_cost_per_token: 12e-7,
885
+ litellm_provider: "openai",
886
+ mode: "chat"
887
+ },
888
+ "gpt-5.6-sol": {
889
+ input_cost_per_token: 5e-6,
890
+ output_cost_per_token: 3e-5,
891
+ litellm_provider: "openai",
892
+ mode: "chat"
893
+ },
894
+ "gpt-5.6-terra": {
895
+ input_cost_per_token: 2e-6,
896
+ output_cost_per_token: 12e-6,
897
+ litellm_provider: "openai",
898
+ mode: "chat"
899
+ },
900
+ "gpt-audio": {
901
+ input_cost_per_token: 25e-7,
902
+ output_cost_per_token: 1e-5,
903
+ litellm_provider: "openai",
904
+ mode: "chat"
905
+ },
906
+ "gpt-audio-1.5": {
907
+ input_cost_per_token: 25e-7,
908
+ output_cost_per_token: 1e-5,
909
+ litellm_provider: "openai",
910
+ mode: "chat"
911
+ },
912
+ "gpt-audio-2025-08-28": {
913
+ input_cost_per_token: 25e-7,
914
+ output_cost_per_token: 1e-5,
915
+ litellm_provider: "openai",
916
+ mode: "chat"
917
+ },
918
+ "gpt-audio-mini": {
919
+ input_cost_per_token: 6e-7,
920
+ output_cost_per_token: 24e-7,
921
+ litellm_provider: "openai",
922
+ mode: "chat"
923
+ },
924
+ "gpt-audio-mini-2025-10-06": {
925
+ input_cost_per_token: 6e-7,
926
+ output_cost_per_token: 24e-7,
927
+ litellm_provider: "openai",
928
+ mode: "chat"
929
+ },
930
+ "gpt-audio-mini-2025-12-15": {
931
+ input_cost_per_token: 6e-7,
932
+ output_cost_per_token: 24e-7,
933
+ litellm_provider: "openai",
934
+ mode: "chat"
935
+ },
936
+ "llama-3.1-8b-instant": {
937
+ input_cost_per_token: 5e-8,
938
+ output_cost_per_token: 8e-8,
939
+ litellm_provider: "groq",
940
+ mode: "chat"
941
+ },
942
+ "llama-3.3-70b-versatile": {
943
+ input_cost_per_token: 59e-8,
944
+ output_cost_per_token: 79e-8,
945
+ litellm_provider: "groq",
946
+ mode: "chat"
947
+ },
948
+ "meta-llama/llama-4-scout-17b-16e-instruct": {
949
+ input_cost_per_token: 11e-8,
950
+ output_cost_per_token: 34e-8,
951
+ litellm_provider: "groq",
952
+ mode: "chat"
953
+ },
954
+ o1: {
955
+ input_cost_per_token: 15e-6,
956
+ output_cost_per_token: 6e-5,
957
+ litellm_provider: "openai",
958
+ mode: "chat"
959
+ },
960
+ "o1-2024-12-17": {
961
+ input_cost_per_token: 15e-6,
962
+ output_cost_per_token: 6e-5,
963
+ litellm_provider: "openai",
964
+ mode: "chat"
965
+ },
966
+ o3: {
967
+ input_cost_per_token: 2e-6,
968
+ output_cost_per_token: 8e-6,
969
+ litellm_provider: "openai",
970
+ mode: "chat"
971
+ },
972
+ "o3-2025-04-16": {
973
+ input_cost_per_token: 2e-6,
974
+ output_cost_per_token: 8e-6,
975
+ litellm_provider: "openai",
976
+ mode: "chat"
977
+ },
978
+ "o3-mini": {
979
+ input_cost_per_token: 11e-7,
980
+ output_cost_per_token: 44e-7,
981
+ litellm_provider: "openai",
982
+ mode: "chat"
983
+ },
984
+ "o3-mini-2025-01-31": {
985
+ input_cost_per_token: 11e-7,
986
+ output_cost_per_token: 44e-7,
987
+ litellm_provider: "openai",
988
+ mode: "chat"
989
+ },
990
+ "o4-mini": {
991
+ input_cost_per_token: 11e-7,
992
+ output_cost_per_token: 44e-7,
993
+ litellm_provider: "openai",
994
+ mode: "chat"
995
+ },
996
+ "o4-mini-2025-04-16": {
997
+ input_cost_per_token: 11e-7,
998
+ output_cost_per_token: 44e-7,
999
+ litellm_provider: "openai",
1000
+ mode: "chat"
1001
+ },
1002
+ "openai/gpt-oss-120b": {
1003
+ input_cost_per_token: 15e-8,
1004
+ output_cost_per_token: 6e-7,
1005
+ litellm_provider: "groq",
1006
+ mode: "chat"
1007
+ },
1008
+ "openai/gpt-oss-20b": {
1009
+ input_cost_per_token: 75e-9,
1010
+ output_cost_per_token: 3e-7,
1011
+ litellm_provider: "groq",
1012
+ mode: "chat"
1013
+ },
1014
+ "openai/gpt-oss-safeguard-20b": {
1015
+ input_cost_per_token: 75e-9,
1016
+ output_cost_per_token: 3e-7,
1017
+ litellm_provider: "groq",
1018
+ mode: "chat"
1019
+ },
1020
+ "qwen/qwen3-32b": {
1021
+ input_cost_per_token: 29e-8,
1022
+ output_cost_per_token: 59e-8,
1023
+ litellm_provider: "groq",
1024
+ mode: "chat"
1025
+ },
1026
+ "text-embedding-3-large": {
1027
+ input_cost_per_token: 13e-8,
1028
+ output_cost_per_token: 0,
1029
+ litellm_provider: "openai",
1030
+ mode: "embedding"
1031
+ },
1032
+ "text-embedding-3-small": {
1033
+ input_cost_per_token: 2e-8,
1034
+ output_cost_per_token: 0,
1035
+ litellm_provider: "openai",
1036
+ mode: "embedding"
1037
+ },
1038
+ "text-embedding-ada-002": {
1039
+ input_cost_per_token: 1e-7,
1040
+ output_cost_per_token: 0,
1041
+ litellm_provider: "openai",
1042
+ mode: "embedding"
1043
+ },
1044
+ "text-embedding-ada-002-v2": {
1045
+ input_cost_per_token: 1e-7,
1046
+ output_cost_per_token: 0,
1047
+ litellm_provider: "openai",
1048
+ mode: "embedding"
1049
+ },
1050
+ __voice__: {
1051
+ "deepgram-nova-3": {
1052
+ mode: "stt",
1053
+ unit: "usd_per_second",
1054
+ rate: 1283333e-10,
1055
+ provider: "deepgram"
1056
+ },
1057
+ "deepgram-nova-3-multilingual": {
1058
+ mode: "stt",
1059
+ unit: "usd_per_second",
1060
+ rate: 1533333e-10,
1061
+ provider: "deepgram"
1062
+ },
1063
+ "deepgram-nova-3-base": {
1064
+ mode: "stt",
1065
+ unit: "usd_per_second",
1066
+ rate: 2416667e-10,
1067
+ provider: "deepgram"
1068
+ },
1069
+ "assemblyai-universal-streaming": {
1070
+ mode: "stt",
1071
+ unit: "usd_per_second",
1072
+ rate: 416667e-10,
1073
+ provider: "assemblyai"
1074
+ },
1075
+ "elevenlabs-multilingual-v2": {
1076
+ mode: "tts",
1077
+ unit: "usd_per_1k_chars",
1078
+ rate: 0.1,
1079
+ provider: "elevenlabs"
1080
+ },
1081
+ "elevenlabs-flash-v2.5": {
1082
+ mode: "tts",
1083
+ unit: "usd_per_1k_chars",
1084
+ rate: 0.05,
1085
+ provider: "elevenlabs"
1086
+ },
1087
+ "elevenlabs-turbo-v2.5": {
1088
+ mode: "tts",
1089
+ unit: "usd_per_1k_chars",
1090
+ rate: 0.05,
1091
+ provider: "elevenlabs"
1092
+ },
1093
+ "cartesia-sonic": {
1094
+ mode: "tts",
1095
+ unit: "usd_per_1k_chars",
1096
+ rate: 0.03,
1097
+ provider: "cartesia"
1098
+ },
1099
+ "cartesia-line": {
1100
+ mode: "telephony",
1101
+ unit: "usd_per_minute",
1102
+ rate: 0.06,
1103
+ provider: "cartesia"
1104
+ },
1105
+ "rime-mist-v2": {
1106
+ mode: "tts",
1107
+ unit: "usd_per_1k_chars",
1108
+ rate: 0.03,
1109
+ provider: "rime"
1110
+ },
1111
+ "twilio-us-inbound-local": {
1112
+ mode: "telephony",
1113
+ unit: "usd_per_minute",
1114
+ rate: 85e-4,
1115
+ provider: "twilio"
1116
+ },
1117
+ "twilio-us-outbound-local": {
1118
+ mode: "telephony",
1119
+ unit: "usd_per_minute",
1120
+ rate: 0.014,
1121
+ provider: "twilio"
1122
+ },
1123
+ "twilio-us-sip-inbound": {
1124
+ mode: "telephony",
1125
+ unit: "usd_per_minute",
1126
+ rate: 4e-3,
1127
+ provider: "twilio"
1128
+ }
1129
+ }
1130
+ };
1131
+
1132
+ // src/voice-pricing.ts
1133
+ var VOICE_MAP = cost_map_default["__voice__"] ?? {};
1134
+ var unitForMode = {
1135
+ stt: "usd_per_second",
1136
+ tts: "usd_per_1k_chars",
1137
+ telephony: "usd_per_minute"
1138
+ };
1139
+ function finiteNonNegative(value) {
1140
+ return typeof value === "number" && Number.isFinite(value) && value >= 0;
1141
+ }
1142
+ function lookupVoiceRate(model, mode) {
1143
+ if (model === null || model === void 0) return null;
1144
+ const entry = Object.prototype.hasOwnProperty.call(VOICE_MAP, model) ? VOICE_MAP[model] : void 0;
1145
+ if (!entry) return null;
1146
+ if (entry.mode !== mode) return null;
1147
+ if (entry.unit !== unitForMode[mode]) return null;
1148
+ const rate = entry.rate;
1149
+ if (!finiteNonNegative(rate)) return null;
1150
+ return rate;
1151
+ }
1152
+ function resolveVoiceRate(model, mode, override) {
1153
+ if (override !== void 0 && override !== null) {
1154
+ if (!finiteNonNegative(override)) {
1155
+ throw new RangeError(
1156
+ `voice ${mode} override must be a finite, non-negative number, got ${override}`
1157
+ );
1158
+ }
1159
+ return { mode, unit: unitForMode[mode], rate: override, source: "override" };
1160
+ }
1161
+ const rate = lookupVoiceRate(model, mode);
1162
+ if (rate === null) throw new UnpriceableVoiceError(model ?? null, mode);
1163
+ return { mode, unit: unitForMode[mode], rate, source: "cost_map" };
1164
+ }
1165
+ function voiceLegCost(mode, quantity, rate) {
1166
+ if (!Number.isFinite(quantity)) {
1167
+ throw new RangeError(`voice ${mode} quantity must be a finite number, got ${quantity}`);
1168
+ }
1169
+ const q = Math.max(0, quantity);
1170
+ if (mode === "stt") return q * rate;
1171
+ if (mode === "tts") return q / 1e3 * rate;
1172
+ if (mode === "telephony") return q * rate;
1173
+ throw new RangeError(`unknown voice mode ${mode}`);
1174
+ }
1175
+ function priceVoiceLeg(mode, quantity, options = {}) {
1176
+ const model = options.model ?? null;
1177
+ const override = options.override ?? null;
1178
+ if (model === null && override === null) return null;
1179
+ const resolved = resolveVoiceRate(model, mode, override);
1180
+ return voiceLegCost(mode, quantity, resolved.rate);
1181
+ }
1182
+
1183
+ // src/adapters/livekit.ts
1184
+ var LiveKitBudgetGuard = class _LiveKitBudgetGuard {
1185
+ guard;
1186
+ model;
1187
+ onBudgetExceeded;
1188
+ sttModel;
1189
+ ttsModel;
1190
+ telephony;
1191
+ sttUsdPerSecond;
1192
+ ttsUsdPer1kChars;
1193
+ telephonyUsdPerMinute;
1194
+ pending = false;
1195
+ attached = false;
1196
+ active = null;
1197
+ /** FIFO of turns that may still emit `LLMMetrics` (including early-released). */
1198
+ slots = [];
1199
+ /**
1200
+ * Cap on the FIFO. A realtime / text-only turn returns no stream and emits
1201
+ * `realtime_metrics` (not `llm_metrics`), so its slot never settles and would
1202
+ * linger; on a long call the queue would grow without bound. Past this many
1203
+ * slots we drop the oldest (releasing an open hold), bounding memory and the
1204
+ * settlement drift a stale slot introduces.
1205
+ */
1206
+ static MAX_SLOTS = 64;
1207
+ constructor(guard, options) {
1208
+ this.guard = guard;
1209
+ this.model = options.model;
1210
+ this.onBudgetExceeded = options.onBudgetExceeded;
1211
+ this.sttModel = options.sttModel;
1212
+ this.ttsModel = options.ttsModel;
1213
+ this.telephony = options.telephony;
1214
+ this.sttUsdPerSecond = options.sttUsdPerSecond;
1215
+ this.ttsUsdPer1kChars = options.ttsUsdPer1kChars;
1216
+ this.telephonyUsdPerMinute = options.telephonyUsdPerMinute;
1217
+ this.onMetrics = this.onMetrics.bind(this);
1218
+ this.onClose = this.onClose.bind(this);
1219
+ priceVoiceLeg("stt", 0, { model: this.sttModel, override: this.sttUsdPerSecond });
1220
+ priceVoiceLeg("tts", 0, { model: this.ttsModel, override: this.ttsUsdPer1kChars });
1221
+ priceVoiceLeg("telephony", 0, { model: this.telephony, override: this.telephonyUsdPerMinute });
1222
+ }
1223
+ /**
1224
+ * Wire reserve (`agent.llmNode`), settle/meter (`metrics_collected`) and release
1225
+ * (`close`) onto a session + agent pair. Reserving before the LLM turn is what
1226
+ * blocks a turn before its TTS/audio spend piles on.
1227
+ */
1228
+ attach(session, agent) {
1229
+ if (this.attached) {
1230
+ throw new Error(
1231
+ "LiveKitBudgetGuard.attach() called twice \u2014 a guard instance binds one session/agent pair. Create a new LiveKitBudgetGuard to re-attach."
1232
+ );
1233
+ }
1234
+ this.attached = true;
1235
+ const origLlmNode = agent.llmNode.bind(agent);
1236
+ const guardedLlmNode = async (...args) => {
1237
+ if (this.pending) this.earlyReleaseActive();
1238
+ let handle;
1239
+ try {
1240
+ handle = this.guard.reserve();
1241
+ } catch (err) {
1242
+ this.clearActive();
1243
+ if (err instanceof BudgetExceeded && this.onBudgetExceeded !== void 0) {
1244
+ await this.onBudgetExceeded(err);
1245
+ return null;
1246
+ }
1247
+ throw err;
1248
+ }
1249
+ const slot = { amount: handle, open: true };
1250
+ this.slots.push(slot);
1251
+ this.active = slot;
1252
+ this.pending = true;
1253
+ this.trimSlots(slot);
1254
+ let stream;
1255
+ try {
1256
+ stream = await origLlmNode(...args);
1257
+ } catch (err) {
1258
+ if (this.active === slot) this.earlyReleaseActive();
1259
+ throw err;
1260
+ }
1261
+ if (stream === null) return null;
1262
+ return this.guardStream(stream, slot);
1263
+ };
1264
+ agent.llmNode = guardedLlmNode;
1265
+ session.on("metrics_collected", this.onMetrics);
1266
+ session.on("close", this.onClose);
1267
+ }
1268
+ /**
1269
+ * Pre-call admission decision (`true` = admit, `false` = reject), delegating to
1270
+ * {@link preCall} on the wrapped guard's remaining budget. A coarse,
1271
+ * non-binding preflight — the binding hard-stop is the per-turn reserve wired by
1272
+ * {@link attach}. Pass `estimatedCallUsd` (e.g. `$/min × expected minutes`) to
1273
+ * reject earlier, when the remaining budget can't cover the call.
1274
+ */
1275
+ admitCall(options = {}) {
1276
+ return preCall(this.guard, options);
1277
+ }
1278
+ /**
1279
+ * Accrue telephony spend for `minutes` of call time (per-minute).
1280
+ *
1281
+ * LiveKit emits no telephony metric, so the transport/caller drives this — call
1282
+ * it as the call accrues minutes, or once with the final duration. This is
1283
+ * per-minute accrual, not live line-cutting: the guard meters the leg, it does
1284
+ * not cut the phone line mid-call. Priced from the voice map when `telephony` is
1285
+ * set, or the `telephonyUsdPerMinute` override; returns `null` (no-op) when the
1286
+ * leg is unconfigured, and fails closed on a vendor the voice map cannot price.
1287
+ * Returns the USD accrued, if any.
1288
+ */
1289
+ meterTelephony(minutes) {
1290
+ const cost = priceVoiceLeg("telephony", minutes, {
1291
+ model: this.telephony,
1292
+ override: this.telephonyUsdPerMinute
1293
+ });
1294
+ if (cost !== null) this.guard.recordTool("livekit-telephony", cost);
1295
+ return cost;
1296
+ }
1297
+ /**
1298
+ * Wrap the `llmNode` stream so a consumer cancel (interrupt) releases this turn's
1299
+ * hold — the JS twin of Python's generator `except BaseException`. Chunks pass
1300
+ * through untouched; a clean end leaves the hold for the metrics event to settle.
1301
+ */
1302
+ guardStream(stream, slot) {
1303
+ const release = () => {
1304
+ if (this.active === slot) this.earlyReleaseActive();
1305
+ };
1306
+ return stream.pipeThrough(
1307
+ new TransformStream({
1308
+ transform(chunk, controller) {
1309
+ controller.enqueue(chunk);
1310
+ },
1311
+ // Clean completion: do NOT release — leave the hold for the metrics event
1312
+ // to settle against (mirrors Python's generator finishing normally).
1313
+ flush() {
1314
+ },
1315
+ // Interrupt / downstream cancel: free the held budget. `Transformer.cancel`
1316
+ // is honored on Node >=20.14; Node 18 does NOT invoke it — there the hold is
1317
+ // released at the next turn's early-release or on session close instead
1318
+ // (delayed, never leaked). TS's Transformer lib type lags and omits cancel —
1319
+ // cast to keep the type check (as the Vercel-AI middleware does).
1320
+ cancel() {
1321
+ release();
1322
+ }
1323
+ })
1324
+ );
1325
+ }
1326
+ onMetrics(ev) {
1327
+ const m = ev.metrics;
1328
+ if (m.type === "llm_metrics") {
1329
+ const metrics = m;
1330
+ let reserved = 0;
1331
+ const slot = this.slots.shift();
1332
+ if (slot !== void 0) {
1333
+ if (slot.open) {
1334
+ reserved = slot.amount;
1335
+ slot.open = false;
1336
+ }
1337
+ if (this.active === slot) this.clearActive();
1338
+ }
1339
+ this.guard.settle(this.model, metrics.promptTokens, metrics.completionTokens, { reserved });
1340
+ } else if (m.type === "stt_metrics") {
1341
+ const seconds = m.audioDurationMs / 1e3;
1342
+ const cost = priceVoiceLeg("stt", seconds, {
1343
+ model: this.sttModel,
1344
+ override: this.sttUsdPerSecond
1345
+ });
1346
+ if (cost !== null) this.guard.recordTool("livekit-stt", cost);
1347
+ } else if (m.type === "tts_metrics") {
1348
+ const cost = priceVoiceLeg("tts", m.charactersCount, {
1349
+ model: this.ttsModel,
1350
+ override: this.ttsUsdPer1kChars
1351
+ });
1352
+ if (cost !== null) this.guard.recordTool("livekit-tts", cost);
1353
+ }
1354
+ }
1355
+ onClose() {
1356
+ if (this.pending) this.earlyReleaseActive();
1357
+ this.slots.length = 0;
1358
+ }
1359
+ clearActive() {
1360
+ this.active = null;
1361
+ this.pending = false;
1362
+ }
1363
+ /** Drop the open guard hold; leave a zeroed queue slot for delayed metrics. */
1364
+ earlyReleaseActive() {
1365
+ const slot = this.active;
1366
+ if (slot === null || !slot.open) {
1367
+ this.clearActive();
1368
+ return;
1369
+ }
1370
+ this.guard.release(slot.amount);
1371
+ slot.open = false;
1372
+ slot.amount = 0;
1373
+ this.clearActive();
1374
+ }
1375
+ /**
1376
+ * Bound the FIFO: drop oldest slots past {@link MAX_SLOTS}, releasing an open
1377
+ * hold as it goes. Never drops the just-reserved active slot. Prevents a long
1378
+ * call from accumulating slots for turns that never emit `llm_metrics`.
1379
+ */
1380
+ trimSlots(active) {
1381
+ while (this.slots.length > _LiveKitBudgetGuard.MAX_SLOTS && this.slots[0] !== active) {
1382
+ const stale = this.slots.shift();
1383
+ if (stale !== void 0 && stale.open) this.guard.release(stale.amount);
1384
+ }
1385
+ }
1386
+ };
1387
+ // Annotate the CommonJS export names for ESM import in node:
1388
+ 0 && (module.exports = {
1389
+ LiveKitBudgetGuard
1390
+ });
1391
+ //# sourceMappingURL=livekit.cjs.map