cascade-ai 0.48.0 → 0.49.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.
package/dist/cli.js CHANGED
@@ -59,11 +59,1688 @@ var __export = (target, all) => {
59
59
  __defProp(target, name, { get: all[name], enumerable: true });
60
60
  };
61
61
 
62
+ // src/core/router/pricing-data.json
63
+ var pricing_data_default;
64
+ var init_pricing_data = __esm({
65
+ "src/core/router/pricing-data.json"() {
66
+ pricing_data_default = {
67
+ schemaVersion: 1,
68
+ generatedAt: "2026-07-27",
69
+ defaultCurrency: "USD",
70
+ note: 'Authoritative offline baseline for model pricing, keyed by model x provider (x region). All token rates are per 1,000,000 tokens in the entry currency. A live source (see live-data.ts) may override an entry when it is fresher; disagreements are recorded rather than silently accepted. Every entry must carry currency, asOf, source and provenance \u2014 a model with NO entry is priced "unknown", never $0. Regenerate with scripts/refresh-pricing.mjs.',
71
+ provenanceLegend: {
72
+ "vendor-pricing-page": "Read directly from the vendor's own published pricing page (see `source`).",
73
+ "litellm-catalog": "From BerriAI/litellm model_prices_and_context_window.json, which cites the vendor page per entry. Used where the vendor page refused automated access.",
74
+ "seed-approximation": "NOT sourced \u2014 an approximation. No entry in this file currently uses this value; it exists so an approximation can never masquerade as a measured price."
75
+ },
76
+ entries: [
77
+ {
78
+ model: "claude-opus-5",
79
+ provider: "anthropic",
80
+ modality: "text",
81
+ currency: "USD",
82
+ asOf: "2026-07-27",
83
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
84
+ provenance: "vendor-pricing-page",
85
+ tiers: [
86
+ {
87
+ inputPer1m: 5,
88
+ outputPer1m: 25,
89
+ cachedInputPer1m: 0.5,
90
+ cacheWritePer1m: 6.25,
91
+ reasoningOutputPer1m: 25
92
+ }
93
+ ],
94
+ batchMultiplier: 0.5,
95
+ contextWindow: 1e6
96
+ },
97
+ {
98
+ model: "claude-opus-4-8",
99
+ provider: "anthropic",
100
+ modality: "text",
101
+ currency: "USD",
102
+ asOf: "2026-07-27",
103
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
104
+ provenance: "vendor-pricing-page",
105
+ tiers: [
106
+ {
107
+ inputPer1m: 5,
108
+ outputPer1m: 25,
109
+ cachedInputPer1m: 0.5,
110
+ cacheWritePer1m: 6.25,
111
+ reasoningOutputPer1m: 25
112
+ }
113
+ ],
114
+ batchMultiplier: 0.5,
115
+ contextWindow: 1e6
116
+ },
117
+ {
118
+ model: "claude-opus-4-7",
119
+ provider: "anthropic",
120
+ modality: "text",
121
+ currency: "USD",
122
+ asOf: "2026-07-27",
123
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
124
+ provenance: "vendor-pricing-page",
125
+ tiers: [
126
+ {
127
+ inputPer1m: 5,
128
+ outputPer1m: 25,
129
+ cachedInputPer1m: 0.5,
130
+ cacheWritePer1m: 6.25,
131
+ reasoningOutputPer1m: 25
132
+ }
133
+ ],
134
+ batchMultiplier: 0.5,
135
+ contextWindow: 1e6
136
+ },
137
+ {
138
+ model: "claude-opus-4-6",
139
+ provider: "anthropic",
140
+ modality: "text",
141
+ currency: "USD",
142
+ asOf: "2026-07-27",
143
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
144
+ provenance: "vendor-pricing-page",
145
+ tiers: [
146
+ {
147
+ inputPer1m: 5,
148
+ outputPer1m: 25,
149
+ cachedInputPer1m: 0.5,
150
+ cacheWritePer1m: 6.25,
151
+ reasoningOutputPer1m: 25
152
+ }
153
+ ],
154
+ batchMultiplier: 0.5,
155
+ contextWindow: 1e6
156
+ },
157
+ {
158
+ model: "claude-opus-4-5",
159
+ provider: "anthropic",
160
+ modality: "text",
161
+ currency: "USD",
162
+ asOf: "2026-07-27",
163
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
164
+ provenance: "vendor-pricing-page",
165
+ tiers: [
166
+ {
167
+ inputPer1m: 5,
168
+ outputPer1m: 25,
169
+ cachedInputPer1m: 0.5,
170
+ cacheWritePer1m: 6.25,
171
+ reasoningOutputPer1m: 25
172
+ }
173
+ ],
174
+ batchMultiplier: 0.5,
175
+ contextWindow: 2e5
176
+ },
177
+ {
178
+ model: "claude-opus-4-1",
179
+ provider: "anthropic",
180
+ modality: "text",
181
+ currency: "USD",
182
+ asOf: "2026-07-27",
183
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
184
+ provenance: "vendor-pricing-page",
185
+ tiers: [
186
+ {
187
+ inputPer1m: 15,
188
+ outputPer1m: 75,
189
+ cachedInputPer1m: 1.5,
190
+ cacheWritePer1m: 18.75,
191
+ reasoningOutputPer1m: 75
192
+ }
193
+ ],
194
+ batchMultiplier: 0.5,
195
+ contextWindow: 2e5,
196
+ notes: "Deprecated by Anthropic; priced for historical/cost-reporting accuracy."
197
+ },
198
+ {
199
+ model: "claude-opus-4",
200
+ provider: "anthropic",
201
+ modality: "text",
202
+ currency: "USD",
203
+ asOf: "2026-07-27",
204
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
205
+ provenance: "vendor-pricing-page",
206
+ tiers: [
207
+ {
208
+ inputPer1m: 15,
209
+ outputPer1m: 75,
210
+ cachedInputPer1m: 1.5,
211
+ cacheWritePer1m: 18.75,
212
+ reasoningOutputPer1m: 75
213
+ }
214
+ ],
215
+ batchMultiplier: 0.5,
216
+ contextWindow: 2e5,
217
+ notes: "Retired except on Google Cloud; priced for historical/cost-reporting accuracy."
218
+ },
219
+ {
220
+ model: "claude-sonnet-5",
221
+ provider: "anthropic",
222
+ modality: "text",
223
+ currency: "USD",
224
+ asOf: "2026-07-27",
225
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
226
+ provenance: "vendor-pricing-page",
227
+ tiers: [
228
+ {
229
+ inputPer1m: 2,
230
+ outputPer1m: 10,
231
+ cachedInputPer1m: 0.2,
232
+ cacheWritePer1m: 2.5,
233
+ reasoningOutputPer1m: 10
234
+ }
235
+ ],
236
+ batchMultiplier: 0.5,
237
+ contextWindow: 1e6,
238
+ notes: "Introductory pricing through 2026-08-31. Standard pricing of $3/$15 per 1M takes effect 2026-09-01 \u2014 re-check this entry then."
239
+ },
240
+ {
241
+ model: "claude-sonnet-4-6",
242
+ provider: "anthropic",
243
+ modality: "text",
244
+ currency: "USD",
245
+ asOf: "2026-07-27",
246
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
247
+ provenance: "vendor-pricing-page",
248
+ tiers: [
249
+ {
250
+ inputPer1m: 3,
251
+ outputPer1m: 15,
252
+ cachedInputPer1m: 0.3,
253
+ cacheWritePer1m: 3.75,
254
+ reasoningOutputPer1m: 15
255
+ }
256
+ ],
257
+ batchMultiplier: 0.5,
258
+ contextWindow: 1e6
259
+ },
260
+ {
261
+ model: "claude-sonnet-4-5",
262
+ provider: "anthropic",
263
+ modality: "text",
264
+ currency: "USD",
265
+ asOf: "2026-07-27",
266
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
267
+ provenance: "vendor-pricing-page",
268
+ tiers: [
269
+ {
270
+ maxInputTokens: 2e5,
271
+ inputPer1m: 3,
272
+ outputPer1m: 15,
273
+ cachedInputPer1m: 0.3,
274
+ cacheWritePer1m: 3.75,
275
+ reasoningOutputPer1m: 15
276
+ },
277
+ {
278
+ inputPer1m: 6,
279
+ outputPer1m: 22.5,
280
+ cachedInputPer1m: 0.6,
281
+ cacheWritePer1m: 7.5,
282
+ reasoningOutputPer1m: 22.5
283
+ }
284
+ ],
285
+ batchMultiplier: 0.5,
286
+ contextWindow: 2e5,
287
+ notes: "Long-context (>200K) premium applies to the 1M-context beta. Base rates from the Anthropic pricing page; the >200K tier from the litellm catalog (Anthropic does not tabulate it on the pricing page)."
288
+ },
289
+ {
290
+ model: "claude-sonnet-4",
291
+ provider: "anthropic",
292
+ modality: "text",
293
+ currency: "USD",
294
+ asOf: "2026-07-27",
295
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
296
+ provenance: "vendor-pricing-page",
297
+ tiers: [
298
+ {
299
+ inputPer1m: 3,
300
+ outputPer1m: 15,
301
+ cachedInputPer1m: 0.3,
302
+ cacheWritePer1m: 3.75,
303
+ reasoningOutputPer1m: 15
304
+ }
305
+ ],
306
+ batchMultiplier: 0.5,
307
+ contextWindow: 2e5
308
+ },
309
+ {
310
+ model: "claude-haiku-4-5",
311
+ provider: "anthropic",
312
+ modality: "text",
313
+ currency: "USD",
314
+ asOf: "2026-07-27",
315
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
316
+ provenance: "vendor-pricing-page",
317
+ tiers: [
318
+ {
319
+ inputPer1m: 1,
320
+ outputPer1m: 5,
321
+ cachedInputPer1m: 0.1,
322
+ cacheWritePer1m: 1.25,
323
+ reasoningOutputPer1m: 5
324
+ }
325
+ ],
326
+ batchMultiplier: 0.5,
327
+ contextWindow: 2e5
328
+ },
329
+ {
330
+ model: "claude-haiku-3-5",
331
+ provider: "anthropic",
332
+ modality: "text",
333
+ currency: "USD",
334
+ asOf: "2026-07-27",
335
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
336
+ provenance: "vendor-pricing-page",
337
+ tiers: [
338
+ {
339
+ inputPer1m: 0.8,
340
+ outputPer1m: 4,
341
+ cachedInputPer1m: 0.08,
342
+ cacheWritePer1m: 1,
343
+ reasoningOutputPer1m: 4
344
+ }
345
+ ],
346
+ batchMultiplier: 0.5,
347
+ contextWindow: 2e5
348
+ },
349
+ {
350
+ model: "gpt-5.6-sol",
351
+ provider: "openai",
352
+ aliases: [
353
+ "gpt-5.6"
354
+ ],
355
+ modality: "text",
356
+ currency: "USD",
357
+ asOf: "2026-07-27",
358
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
359
+ provenance: "litellm-catalog",
360
+ tiers: [
361
+ {
362
+ maxInputTokens: 272e3,
363
+ inputPer1m: 5,
364
+ outputPer1m: 30,
365
+ cachedInputPer1m: 0.5,
366
+ cacheWritePer1m: 6.25
367
+ },
368
+ {
369
+ inputPer1m: 10,
370
+ outputPer1m: 45,
371
+ cachedInputPer1m: 1,
372
+ cacheWritePer1m: 12.5
373
+ }
374
+ ],
375
+ batchMultiplier: 0.5,
376
+ contextWindow: 105e4
377
+ },
378
+ {
379
+ model: "gpt-5.6-terra",
380
+ provider: "openai",
381
+ modality: "text",
382
+ currency: "USD",
383
+ asOf: "2026-07-27",
384
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
385
+ provenance: "litellm-catalog",
386
+ tiers: [
387
+ {
388
+ maxInputTokens: 272e3,
389
+ inputPer1m: 2.5,
390
+ outputPer1m: 15,
391
+ cachedInputPer1m: 0.25,
392
+ cacheWritePer1m: 3.125
393
+ },
394
+ {
395
+ inputPer1m: 5,
396
+ outputPer1m: 22.5,
397
+ cachedInputPer1m: 0.5,
398
+ cacheWritePer1m: 6.25
399
+ }
400
+ ],
401
+ batchMultiplier: 0.5,
402
+ contextWindow: 105e4
403
+ },
404
+ {
405
+ model: "gpt-5.6-luna",
406
+ provider: "openai",
407
+ modality: "text",
408
+ currency: "USD",
409
+ asOf: "2026-07-27",
410
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
411
+ provenance: "litellm-catalog",
412
+ tiers: [
413
+ {
414
+ maxInputTokens: 272e3,
415
+ inputPer1m: 1,
416
+ outputPer1m: 6,
417
+ cachedInputPer1m: 0.1,
418
+ cacheWritePer1m: 1.25
419
+ },
420
+ {
421
+ inputPer1m: 2,
422
+ outputPer1m: 9,
423
+ cachedInputPer1m: 0.2,
424
+ cacheWritePer1m: 2.5
425
+ }
426
+ ],
427
+ batchMultiplier: 0.5,
428
+ contextWindow: 105e4
429
+ },
430
+ {
431
+ model: "gpt-5.5",
432
+ provider: "openai",
433
+ modality: "text",
434
+ currency: "USD",
435
+ asOf: "2026-07-27",
436
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
437
+ provenance: "litellm-catalog",
438
+ tiers: [
439
+ {
440
+ maxInputTokens: 272e3,
441
+ inputPer1m: 5,
442
+ outputPer1m: 30,
443
+ cachedInputPer1m: 0.5
444
+ },
445
+ {
446
+ inputPer1m: 10,
447
+ outputPer1m: 45,
448
+ cachedInputPer1m: 1
449
+ }
450
+ ],
451
+ batchMultiplier: 0.5,
452
+ contextWindow: 105e4
453
+ },
454
+ {
455
+ model: "gpt-5.4",
456
+ provider: "openai",
457
+ modality: "text",
458
+ currency: "USD",
459
+ asOf: "2026-07-27",
460
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
461
+ provenance: "litellm-catalog",
462
+ tiers: [
463
+ {
464
+ maxInputTokens: 272e3,
465
+ inputPer1m: 2.5,
466
+ outputPer1m: 15,
467
+ cachedInputPer1m: 0.25
468
+ },
469
+ {
470
+ inputPer1m: 5,
471
+ outputPer1m: 22.5,
472
+ cachedInputPer1m: 0.5
473
+ }
474
+ ],
475
+ batchMultiplier: 0.5,
476
+ contextWindow: 105e4
477
+ },
478
+ {
479
+ model: "gpt-5.4-mini",
480
+ provider: "openai",
481
+ modality: "text",
482
+ currency: "USD",
483
+ asOf: "2026-07-27",
484
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
485
+ provenance: "litellm-catalog",
486
+ tiers: [
487
+ {
488
+ inputPer1m: 0.75,
489
+ outputPer1m: 4.5,
490
+ cachedInputPer1m: 0.075
491
+ }
492
+ ],
493
+ batchMultiplier: 0.5,
494
+ contextWindow: 105e4
495
+ },
496
+ {
497
+ model: "gpt-5",
498
+ provider: "openai",
499
+ modality: "text",
500
+ currency: "USD",
501
+ asOf: "2026-07-27",
502
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
503
+ provenance: "litellm-catalog",
504
+ tiers: [
505
+ {
506
+ inputPer1m: 1.25,
507
+ outputPer1m: 10,
508
+ cachedInputPer1m: 0.125
509
+ }
510
+ ],
511
+ contextWindow: 272e3
512
+ },
513
+ {
514
+ model: "gpt-5-mini",
515
+ provider: "openai",
516
+ modality: "text",
517
+ currency: "USD",
518
+ asOf: "2026-07-27",
519
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
520
+ provenance: "litellm-catalog",
521
+ tiers: [
522
+ {
523
+ inputPer1m: 0.25,
524
+ outputPer1m: 2,
525
+ cachedInputPer1m: 0.025
526
+ }
527
+ ],
528
+ contextWindow: 272e3
529
+ },
530
+ {
531
+ model: "gpt-5-nano",
532
+ provider: "openai",
533
+ modality: "text",
534
+ currency: "USD",
535
+ asOf: "2026-07-27",
536
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
537
+ provenance: "litellm-catalog",
538
+ tiers: [
539
+ {
540
+ inputPer1m: 0.05,
541
+ outputPer1m: 0.4,
542
+ cachedInputPer1m: 5e-3
543
+ }
544
+ ],
545
+ contextWindow: 272e3
546
+ },
547
+ {
548
+ model: "gpt-4.1",
549
+ provider: "openai",
550
+ modality: "text",
551
+ currency: "USD",
552
+ asOf: "2026-07-27",
553
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
554
+ provenance: "litellm-catalog",
555
+ tiers: [
556
+ {
557
+ inputPer1m: 2,
558
+ outputPer1m: 8,
559
+ cachedInputPer1m: 0.5
560
+ }
561
+ ],
562
+ batchMultiplier: 0.5,
563
+ contextWindow: 1047576
564
+ },
565
+ {
566
+ model: "gpt-4.1-mini",
567
+ provider: "openai",
568
+ modality: "text",
569
+ currency: "USD",
570
+ asOf: "2026-07-27",
571
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
572
+ provenance: "litellm-catalog",
573
+ tiers: [
574
+ {
575
+ inputPer1m: 0.4,
576
+ outputPer1m: 1.6,
577
+ cachedInputPer1m: 0.1
578
+ }
579
+ ],
580
+ batchMultiplier: 0.5,
581
+ contextWindow: 1047576
582
+ },
583
+ {
584
+ model: "gpt-4.1-nano",
585
+ provider: "openai",
586
+ modality: "text",
587
+ currency: "USD",
588
+ asOf: "2026-07-27",
589
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
590
+ provenance: "litellm-catalog",
591
+ tiers: [
592
+ {
593
+ inputPer1m: 0.1,
594
+ outputPer1m: 0.4,
595
+ cachedInputPer1m: 0.025
596
+ }
597
+ ],
598
+ batchMultiplier: 0.5,
599
+ contextWindow: 1047576
600
+ },
601
+ {
602
+ model: "gpt-4o",
603
+ provider: "openai",
604
+ modality: "text",
605
+ currency: "USD",
606
+ asOf: "2026-07-27",
607
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
608
+ provenance: "litellm-catalog",
609
+ tiers: [
610
+ {
611
+ inputPer1m: 2.5,
612
+ outputPer1m: 10,
613
+ cachedInputPer1m: 1.25
614
+ }
615
+ ],
616
+ batchMultiplier: 0.5,
617
+ contextWindow: 128e3
618
+ },
619
+ {
620
+ model: "gpt-4o-mini",
621
+ provider: "openai",
622
+ modality: "text",
623
+ currency: "USD",
624
+ asOf: "2026-07-27",
625
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
626
+ provenance: "litellm-catalog",
627
+ tiers: [
628
+ {
629
+ inputPer1m: 0.15,
630
+ outputPer1m: 0.6,
631
+ cachedInputPer1m: 0.075
632
+ }
633
+ ],
634
+ batchMultiplier: 0.5,
635
+ contextWindow: 128e3
636
+ },
637
+ {
638
+ model: "gpt-5.5",
639
+ provider: "azure",
640
+ region: "global",
641
+ modality: "text",
642
+ currency: "USD",
643
+ asOf: "2026-07-27",
644
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
645
+ provenance: "litellm-catalog",
646
+ tiers: [
647
+ {
648
+ maxInputTokens: 272e3,
649
+ inputPer1m: 5,
650
+ outputPer1m: 30,
651
+ cachedInputPer1m: 0.5
652
+ },
653
+ {
654
+ inputPer1m: 10,
655
+ outputPer1m: 45,
656
+ cachedInputPer1m: 1
657
+ }
658
+ ],
659
+ contextWindow: 105e4
660
+ },
661
+ {
662
+ model: "gpt-5.5",
663
+ provider: "azure",
664
+ region: "us",
665
+ modality: "text",
666
+ currency: "USD",
667
+ asOf: "2026-07-27",
668
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
669
+ provenance: "litellm-catalog",
670
+ tiers: [
671
+ {
672
+ maxInputTokens: 272e3,
673
+ inputPer1m: 5.5,
674
+ outputPer1m: 33,
675
+ cachedInputPer1m: 0.55
676
+ },
677
+ {
678
+ inputPer1m: 11,
679
+ outputPer1m: 49.5,
680
+ cachedInputPer1m: 1.1
681
+ }
682
+ ],
683
+ contextWindow: 105e4
684
+ },
685
+ {
686
+ model: "gpt-5.5",
687
+ provider: "azure",
688
+ region: "eu",
689
+ modality: "text",
690
+ currency: "USD",
691
+ asOf: "2026-07-27",
692
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
693
+ provenance: "litellm-catalog",
694
+ tiers: [
695
+ {
696
+ maxInputTokens: 272e3,
697
+ inputPer1m: 5.5,
698
+ outputPer1m: 33,
699
+ cachedInputPer1m: 0.55
700
+ },
701
+ {
702
+ inputPer1m: 11,
703
+ outputPer1m: 49.5,
704
+ cachedInputPer1m: 1.1
705
+ }
706
+ ],
707
+ contextWindow: 105e4
708
+ },
709
+ {
710
+ model: "gpt-5.4",
711
+ provider: "azure",
712
+ region: "global",
713
+ modality: "text",
714
+ currency: "USD",
715
+ asOf: "2026-07-27",
716
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
717
+ provenance: "litellm-catalog",
718
+ tiers: [
719
+ {
720
+ maxInputTokens: 272e3,
721
+ inputPer1m: 2.5,
722
+ outputPer1m: 15,
723
+ cachedInputPer1m: 0.25
724
+ },
725
+ {
726
+ inputPer1m: 5,
727
+ outputPer1m: 22.5,
728
+ cachedInputPer1m: 0.5
729
+ }
730
+ ],
731
+ contextWindow: 105e4
732
+ },
733
+ {
734
+ model: "gpt-5.4",
735
+ provider: "azure",
736
+ region: "us",
737
+ modality: "text",
738
+ currency: "USD",
739
+ asOf: "2026-07-27",
740
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
741
+ provenance: "litellm-catalog",
742
+ tiers: [
743
+ {
744
+ inputPer1m: 2.75,
745
+ outputPer1m: 16.5,
746
+ cachedInputPer1m: 0.28
747
+ }
748
+ ],
749
+ contextWindow: 105e4
750
+ },
751
+ {
752
+ model: "gpt-5.4",
753
+ provider: "azure",
754
+ region: "eu",
755
+ modality: "text",
756
+ currency: "USD",
757
+ asOf: "2026-07-27",
758
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
759
+ provenance: "litellm-catalog",
760
+ tiers: [
761
+ {
762
+ inputPer1m: 2.75,
763
+ outputPer1m: 16.5,
764
+ cachedInputPer1m: 0.28
765
+ }
766
+ ],
767
+ contextWindow: 105e4
768
+ },
769
+ {
770
+ model: "gpt-5.6-terra",
771
+ provider: "azure",
772
+ region: "global",
773
+ modality: "text",
774
+ currency: "USD",
775
+ asOf: "2026-07-27",
776
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
777
+ provenance: "litellm-catalog",
778
+ tiers: [
779
+ {
780
+ maxInputTokens: 272e3,
781
+ inputPer1m: 2.5,
782
+ outputPer1m: 15,
783
+ cachedInputPer1m: 0.25
784
+ },
785
+ {
786
+ inputPer1m: 5,
787
+ outputPer1m: 22.5,
788
+ cachedInputPer1m: 0.5
789
+ }
790
+ ],
791
+ contextWindow: 105e4
792
+ },
793
+ {
794
+ model: "gpt-5.6-terra",
795
+ provider: "azure",
796
+ region: "eu",
797
+ modality: "text",
798
+ currency: "USD",
799
+ asOf: "2026-07-27",
800
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
801
+ provenance: "litellm-catalog",
802
+ tiers: [
803
+ {
804
+ maxInputTokens: 272e3,
805
+ inputPer1m: 2.75,
806
+ outputPer1m: 16.5,
807
+ cachedInputPer1m: 0.275
808
+ },
809
+ {
810
+ inputPer1m: 5.5,
811
+ outputPer1m: 24.75,
812
+ cachedInputPer1m: 0.55
813
+ }
814
+ ],
815
+ contextWindow: 105e4
816
+ },
817
+ {
818
+ model: "gpt-5",
819
+ provider: "azure",
820
+ region: "global",
821
+ modality: "text",
822
+ currency: "USD",
823
+ asOf: "2026-07-27",
824
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
825
+ provenance: "litellm-catalog",
826
+ tiers: [
827
+ {
828
+ inputPer1m: 1.25,
829
+ outputPer1m: 10,
830
+ cachedInputPer1m: 0.125
831
+ }
832
+ ],
833
+ contextWindow: 272e3
834
+ },
835
+ {
836
+ model: "gpt-5-mini",
837
+ provider: "azure",
838
+ region: "global",
839
+ modality: "text",
840
+ currency: "USD",
841
+ asOf: "2026-07-27",
842
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
843
+ provenance: "litellm-catalog",
844
+ tiers: [
845
+ {
846
+ inputPer1m: 0.25,
847
+ outputPer1m: 2,
848
+ cachedInputPer1m: 0.025
849
+ }
850
+ ],
851
+ contextWindow: 272e3
852
+ },
853
+ {
854
+ model: "gpt-5-nano",
855
+ provider: "azure",
856
+ region: "global",
857
+ modality: "text",
858
+ currency: "USD",
859
+ asOf: "2026-07-27",
860
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
861
+ provenance: "litellm-catalog",
862
+ tiers: [
863
+ {
864
+ inputPer1m: 0.05,
865
+ outputPer1m: 0.4,
866
+ cachedInputPer1m: 5e-3
867
+ }
868
+ ],
869
+ contextWindow: 272e3
870
+ },
871
+ {
872
+ model: "gpt-4.1",
873
+ provider: "azure",
874
+ region: "global",
875
+ modality: "text",
876
+ currency: "USD",
877
+ asOf: "2026-07-27",
878
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
879
+ provenance: "litellm-catalog",
880
+ tiers: [
881
+ {
882
+ inputPer1m: 2,
883
+ outputPer1m: 8,
884
+ cachedInputPer1m: 0.5
885
+ }
886
+ ],
887
+ batchMultiplier: 0.5,
888
+ contextWindow: 1047576
889
+ },
890
+ {
891
+ model: "gpt-4o",
892
+ provider: "azure",
893
+ region: "global",
894
+ modality: "text",
895
+ currency: "USD",
896
+ asOf: "2026-07-27",
897
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
898
+ provenance: "litellm-catalog",
899
+ tiers: [
900
+ {
901
+ inputPer1m: 2.5,
902
+ outputPer1m: 10,
903
+ cachedInputPer1m: 1.25
904
+ }
905
+ ],
906
+ contextWindow: 128e3
907
+ },
908
+ {
909
+ model: "gpt-4o-mini",
910
+ provider: "azure",
911
+ region: "global",
912
+ modality: "text",
913
+ currency: "USD",
914
+ asOf: "2026-07-27",
915
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
916
+ provenance: "litellm-catalog",
917
+ tiers: [
918
+ {
919
+ inputPer1m: 0.165,
920
+ outputPer1m: 0.66,
921
+ cachedInputPer1m: 0.075
922
+ }
923
+ ],
924
+ contextWindow: 128e3,
925
+ notes: "Azure charges $0.165/$0.66 per 1M for gpt-4o-mini vs $0.15/$0.60 on OpenAI \u2014 same model, different price."
926
+ },
927
+ {
928
+ model: "gemini-3.1-pro",
929
+ provider: "gemini",
930
+ aliases: [
931
+ "gemini-3.1-pro-preview"
932
+ ],
933
+ modality: "text",
934
+ currency: "USD",
935
+ asOf: "2026-07-27",
936
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
937
+ provenance: "vendor-pricing-page",
938
+ tiers: [
939
+ {
940
+ maxInputTokens: 2e5,
941
+ inputPer1m: 2,
942
+ outputPer1m: 12,
943
+ cachedInputPer1m: 0.2,
944
+ reasoningOutputPer1m: 12
945
+ },
946
+ {
947
+ inputPer1m: 4,
948
+ outputPer1m: 18,
949
+ cachedInputPer1m: 0.4,
950
+ reasoningOutputPer1m: 18
951
+ }
952
+ ],
953
+ batchMultiplier: 0.5,
954
+ contextWindow: 1048576,
955
+ notes: "Long-context tier: $2/$12 per 1M up to 200K prompt tokens, $4/$18 above it."
956
+ },
957
+ {
958
+ model: "gemini-3-pro",
959
+ provider: "gemini",
960
+ aliases: [
961
+ "gemini-3-pro-preview"
962
+ ],
963
+ modality: "text",
964
+ currency: "USD",
965
+ asOf: "2026-07-27",
966
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
967
+ provenance: "vendor-pricing-page",
968
+ tiers: [
969
+ {
970
+ maxInputTokens: 2e5,
971
+ inputPer1m: 2,
972
+ outputPer1m: 12,
973
+ cachedInputPer1m: 0.2,
974
+ reasoningOutputPer1m: 12
975
+ },
976
+ {
977
+ inputPer1m: 4,
978
+ outputPer1m: 18,
979
+ cachedInputPer1m: 0.4,
980
+ reasoningOutputPer1m: 18
981
+ }
982
+ ],
983
+ batchMultiplier: 0.5,
984
+ contextWindow: 1048576
985
+ },
986
+ {
987
+ model: "gemini-3.6-flash",
988
+ provider: "gemini",
989
+ modality: "text",
990
+ currency: "USD",
991
+ asOf: "2026-07-27",
992
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
993
+ provenance: "vendor-pricing-page",
994
+ tiers: [
995
+ {
996
+ inputPer1m: 1.5,
997
+ outputPer1m: 7.5,
998
+ cachedInputPer1m: 0.15,
999
+ reasoningOutputPer1m: 7.5
1000
+ }
1001
+ ],
1002
+ batchMultiplier: 0.5,
1003
+ contextWindow: 1048576,
1004
+ notes: "Released 2026-07-21. Output pricing dropped ~17% from Gemini 3.5 Flash ($9.00 -> $7.50 per 1M); input unchanged."
1005
+ },
1006
+ {
1007
+ model: "gemini-3.5-flash",
1008
+ provider: "gemini",
1009
+ modality: "text",
1010
+ currency: "USD",
1011
+ asOf: "2026-07-27",
1012
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1013
+ provenance: "vendor-pricing-page",
1014
+ tiers: [
1015
+ {
1016
+ inputPer1m: 1.5,
1017
+ outputPer1m: 9,
1018
+ cachedInputPer1m: 0.15,
1019
+ reasoningOutputPer1m: 9
1020
+ }
1021
+ ],
1022
+ batchMultiplier: 0.5,
1023
+ contextWindow: 1048576
1024
+ },
1025
+ {
1026
+ model: "gemini-3.5-flash-lite",
1027
+ provider: "gemini",
1028
+ modality: "text",
1029
+ currency: "USD",
1030
+ asOf: "2026-07-27",
1031
+ source: "https://ai.google.dev/gemini-api/docs/pricing",
1032
+ provenance: "litellm-catalog",
1033
+ tiers: [
1034
+ {
1035
+ inputPer1m: 0.3,
1036
+ outputPer1m: 2.5,
1037
+ cachedInputPer1m: 0.03,
1038
+ reasoningOutputPer1m: 2.5
1039
+ }
1040
+ ],
1041
+ batchMultiplier: 0.5,
1042
+ contextWindow: 1048576
1043
+ },
1044
+ {
1045
+ model: "gemini-3.1-flash-lite",
1046
+ provider: "gemini",
1047
+ modality: "text",
1048
+ currency: "USD",
1049
+ asOf: "2026-07-27",
1050
+ source: "https://ai.google.dev/gemini-api/docs/pricing#gemini-3.1-flash-lite",
1051
+ provenance: "litellm-catalog",
1052
+ tiers: [
1053
+ {
1054
+ inputPer1m: 0.25,
1055
+ outputPer1m: 1.5,
1056
+ cachedInputPer1m: 0.025,
1057
+ reasoningOutputPer1m: 1.5
1058
+ }
1059
+ ],
1060
+ batchMultiplier: 0.5,
1061
+ contextWindow: 1048576
1062
+ },
1063
+ {
1064
+ model: "gemini-3-flash",
1065
+ provider: "gemini",
1066
+ aliases: [
1067
+ "gemini-3-flash-preview"
1068
+ ],
1069
+ modality: "text",
1070
+ currency: "USD",
1071
+ asOf: "2026-07-27",
1072
+ source: "https://ai.google.dev/pricing/gemini-3",
1073
+ provenance: "litellm-catalog",
1074
+ tiers: [
1075
+ {
1076
+ inputPer1m: 0.5,
1077
+ outputPer1m: 3,
1078
+ cachedInputPer1m: 0.05,
1079
+ reasoningOutputPer1m: 3
1080
+ }
1081
+ ],
1082
+ contextWindow: 1048576
1083
+ },
1084
+ {
1085
+ model: "gemini-2.5-pro",
1086
+ provider: "gemini",
1087
+ modality: "text",
1088
+ currency: "USD",
1089
+ asOf: "2026-07-27",
1090
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1091
+ provenance: "litellm-catalog",
1092
+ tiers: [
1093
+ {
1094
+ maxInputTokens: 2e5,
1095
+ inputPer1m: 1.25,
1096
+ outputPer1m: 10,
1097
+ cachedInputPer1m: 0.125
1098
+ },
1099
+ {
1100
+ inputPer1m: 2.5,
1101
+ outputPer1m: 15,
1102
+ cachedInputPer1m: 0.25
1103
+ }
1104
+ ],
1105
+ contextWindow: 1048576
1106
+ },
1107
+ {
1108
+ model: "gemini-2.5-flash",
1109
+ provider: "gemini",
1110
+ modality: "text",
1111
+ currency: "USD",
1112
+ asOf: "2026-07-27",
1113
+ source: "https://ai.google.dev/gemini-api/docs/models#gemini-2.5-flash-preview",
1114
+ provenance: "litellm-catalog",
1115
+ tiers: [
1116
+ {
1117
+ inputPer1m: 0.3,
1118
+ outputPer1m: 2.5,
1119
+ cachedInputPer1m: 0.03,
1120
+ reasoningOutputPer1m: 2.5
1121
+ }
1122
+ ],
1123
+ contextWindow: 1048576
1124
+ },
1125
+ {
1126
+ model: "gemini-2.5-flash-lite",
1127
+ provider: "gemini",
1128
+ modality: "text",
1129
+ currency: "USD",
1130
+ asOf: "2026-07-27",
1131
+ source: "https://ai.google.dev/gemini-api/docs/models#gemini-2.5-flash-lite",
1132
+ provenance: "litellm-catalog",
1133
+ tiers: [
1134
+ {
1135
+ inputPer1m: 0.1,
1136
+ outputPer1m: 0.4,
1137
+ cachedInputPer1m: 0.01,
1138
+ reasoningOutputPer1m: 0.4
1139
+ }
1140
+ ],
1141
+ contextWindow: 1048576
1142
+ },
1143
+ {
1144
+ model: "gemini-2.0-flash",
1145
+ provider: "gemini",
1146
+ modality: "text",
1147
+ currency: "USD",
1148
+ asOf: "2026-07-27",
1149
+ source: "https://ai.google.dev/pricing#2_0flash",
1150
+ provenance: "litellm-catalog",
1151
+ tiers: [
1152
+ {
1153
+ inputPer1m: 0.1,
1154
+ outputPer1m: 0.4,
1155
+ cachedInputPer1m: 0.025
1156
+ }
1157
+ ],
1158
+ contextWindow: 1048576,
1159
+ notes: "Gemini Developer API price. Vertex AI lists $0.15/$0.60 per 1M for the same model \u2014 see the vertex entry."
1160
+ },
1161
+ {
1162
+ model: "gemini-2.0-flash-lite",
1163
+ provider: "gemini",
1164
+ modality: "text",
1165
+ currency: "USD",
1166
+ asOf: "2026-07-27",
1167
+ source: "https://ai.google.dev/gemini-api/docs/pricing#gemini-2.0-flash-lite",
1168
+ provenance: "litellm-catalog",
1169
+ tiers: [
1170
+ {
1171
+ inputPer1m: 0.075,
1172
+ outputPer1m: 0.3,
1173
+ cachedInputPer1m: 0.01875
1174
+ }
1175
+ ],
1176
+ contextWindow: 1048576
1177
+ },
1178
+ {
1179
+ model: "gemini-2.0-flash",
1180
+ provider: "vertex",
1181
+ modality: "text",
1182
+ currency: "USD",
1183
+ asOf: "2026-07-27",
1184
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1185
+ provenance: "vendor-pricing-page",
1186
+ tiers: [
1187
+ {
1188
+ inputPer1m: 0.15,
1189
+ outputPer1m: 0.6
1190
+ }
1191
+ ],
1192
+ batchMultiplier: 0.5,
1193
+ notes: "Vertex AI lists $0.15/$0.60 per 1M; the Gemini Developer API lists $0.10/$0.40 for the same model."
1194
+ },
1195
+ {
1196
+ model: "gemini-3.1-pro",
1197
+ provider: "vertex",
1198
+ aliases: [
1199
+ "gemini-3.1-pro-preview"
1200
+ ],
1201
+ modality: "text",
1202
+ currency: "USD",
1203
+ asOf: "2026-07-27",
1204
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1205
+ provenance: "vendor-pricing-page",
1206
+ tiers: [
1207
+ {
1208
+ maxInputTokens: 2e5,
1209
+ inputPer1m: 2,
1210
+ outputPer1m: 12,
1211
+ cachedInputPer1m: 0.2,
1212
+ reasoningOutputPer1m: 12
1213
+ },
1214
+ {
1215
+ inputPer1m: 4,
1216
+ outputPer1m: 18,
1217
+ cachedInputPer1m: 0.4,
1218
+ reasoningOutputPer1m: 18
1219
+ }
1220
+ ],
1221
+ batchMultiplier: 0.5,
1222
+ contextWindow: 1048576
1223
+ },
1224
+ {
1225
+ model: "gemini-3.6-flash",
1226
+ provider: "vertex",
1227
+ modality: "text",
1228
+ currency: "USD",
1229
+ asOf: "2026-07-27",
1230
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1231
+ provenance: "vendor-pricing-page",
1232
+ tiers: [
1233
+ {
1234
+ inputPer1m: 1.5,
1235
+ outputPer1m: 7.5,
1236
+ cachedInputPer1m: 0.15,
1237
+ reasoningOutputPer1m: 7.5
1238
+ }
1239
+ ],
1240
+ batchMultiplier: 0.5,
1241
+ contextWindow: 1048576
1242
+ },
1243
+ {
1244
+ model: "gemini-2.5-pro",
1245
+ provider: "vertex",
1246
+ modality: "text",
1247
+ currency: "USD",
1248
+ asOf: "2026-07-27",
1249
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1250
+ provenance: "vendor-pricing-page",
1251
+ tiers: [
1252
+ {
1253
+ maxInputTokens: 2e5,
1254
+ inputPer1m: 1.25,
1255
+ outputPer1m: 10,
1256
+ cachedInputPer1m: 0.13
1257
+ },
1258
+ {
1259
+ inputPer1m: 2.5,
1260
+ outputPer1m: 15,
1261
+ cachedInputPer1m: 0.25
1262
+ }
1263
+ ],
1264
+ batchMultiplier: 0.5,
1265
+ contextWindow: 1048576
1266
+ },
1267
+ {
1268
+ model: "gemini-2.5-flash",
1269
+ provider: "vertex",
1270
+ modality: "text",
1271
+ currency: "USD",
1272
+ asOf: "2026-07-27",
1273
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1274
+ provenance: "vendor-pricing-page",
1275
+ tiers: [
1276
+ {
1277
+ inputPer1m: 0.3,
1278
+ outputPer1m: 2.5,
1279
+ cachedInputPer1m: 0.03,
1280
+ reasoningOutputPer1m: 2.5
1281
+ }
1282
+ ],
1283
+ batchMultiplier: 0.5,
1284
+ contextWindow: 1048576
1285
+ },
1286
+ {
1287
+ model: "claude-sonnet-4-6",
1288
+ provider: "openrouter",
1289
+ modality: "text",
1290
+ currency: "USD",
1291
+ asOf: "2026-07-27",
1292
+ source: "https://openrouter.ai/anthropic/claude-sonnet-4.6",
1293
+ provenance: "litellm-catalog",
1294
+ tiers: [
1295
+ {
1296
+ maxInputTokens: 2e5,
1297
+ inputPer1m: 3,
1298
+ outputPer1m: 15,
1299
+ cachedInputPer1m: 0.3,
1300
+ cacheWritePer1m: 3.75
1301
+ },
1302
+ {
1303
+ inputPer1m: 6,
1304
+ outputPer1m: 22.5,
1305
+ cachedInputPer1m: 0.6,
1306
+ cacheWritePer1m: 7.5
1307
+ }
1308
+ ],
1309
+ contextWindow: 1e6
1310
+ },
1311
+ {
1312
+ model: "claude-haiku-4-5",
1313
+ provider: "openrouter",
1314
+ modality: "text",
1315
+ currency: "USD",
1316
+ asOf: "2026-07-27",
1317
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1318
+ provenance: "litellm-catalog",
1319
+ tiers: [
1320
+ {
1321
+ inputPer1m: 1,
1322
+ outputPer1m: 5,
1323
+ cachedInputPer1m: 0.1,
1324
+ cacheWritePer1m: 1.25
1325
+ }
1326
+ ],
1327
+ contextWindow: 2e5
1328
+ },
1329
+ {
1330
+ model: "gpt-5",
1331
+ provider: "openrouter",
1332
+ modality: "text",
1333
+ currency: "USD",
1334
+ asOf: "2026-07-27",
1335
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1336
+ provenance: "litellm-catalog",
1337
+ tiers: [
1338
+ {
1339
+ inputPer1m: 1.25,
1340
+ outputPer1m: 10,
1341
+ cachedInputPer1m: 0.125
1342
+ }
1343
+ ],
1344
+ contextWindow: 272e3
1345
+ },
1346
+ {
1347
+ model: "gpt-5-mini",
1348
+ provider: "openrouter",
1349
+ modality: "text",
1350
+ currency: "USD",
1351
+ asOf: "2026-07-27",
1352
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1353
+ provenance: "litellm-catalog",
1354
+ tiers: [
1355
+ {
1356
+ inputPer1m: 0.25,
1357
+ outputPer1m: 2,
1358
+ cachedInputPer1m: 0.025
1359
+ }
1360
+ ],
1361
+ contextWindow: 272e3
1362
+ },
1363
+ {
1364
+ model: "gemini-3.1-pro",
1365
+ provider: "openrouter",
1366
+ aliases: [
1367
+ "gemini-3.1-pro-preview"
1368
+ ],
1369
+ modality: "text",
1370
+ currency: "USD",
1371
+ asOf: "2026-07-27",
1372
+ source: "https://openrouter.ai/google/gemini-3.1-pro-preview",
1373
+ provenance: "litellm-catalog",
1374
+ tiers: [
1375
+ {
1376
+ maxInputTokens: 2e5,
1377
+ inputPer1m: 2,
1378
+ outputPer1m: 12,
1379
+ cachedInputPer1m: 0.2
1380
+ },
1381
+ {
1382
+ inputPer1m: 4,
1383
+ outputPer1m: 18,
1384
+ cachedInputPer1m: 0.4,
1385
+ cacheWritePer1m: 0.25
1386
+ }
1387
+ ],
1388
+ contextWindow: 1048576
1389
+ },
1390
+ {
1391
+ model: "text-embedding-3-small",
1392
+ provider: "openai",
1393
+ modality: "embedding",
1394
+ currency: "USD",
1395
+ asOf: "2026-07-27",
1396
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1397
+ provenance: "litellm-catalog",
1398
+ tiers: [
1399
+ {
1400
+ inputPer1m: 0.02,
1401
+ outputPer1m: 0
1402
+ }
1403
+ ],
1404
+ batchMultiplier: 0.5,
1405
+ contextWindow: 8191
1406
+ },
1407
+ {
1408
+ model: "text-embedding-3-large",
1409
+ provider: "openai",
1410
+ modality: "embedding",
1411
+ currency: "USD",
1412
+ asOf: "2026-07-27",
1413
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1414
+ provenance: "litellm-catalog",
1415
+ tiers: [
1416
+ {
1417
+ inputPer1m: 0.13,
1418
+ outputPer1m: 0
1419
+ }
1420
+ ],
1421
+ batchMultiplier: 0.5,
1422
+ contextWindow: 8191
1423
+ },
1424
+ {
1425
+ model: "gemini-embedding-001",
1426
+ provider: "gemini",
1427
+ modality: "embedding",
1428
+ currency: "USD",
1429
+ asOf: "2026-07-27",
1430
+ source: "https://ai.google.dev/gemini-api/docs/embeddings#model-versions",
1431
+ provenance: "litellm-catalog",
1432
+ tiers: [
1433
+ {
1434
+ inputPer1m: 0.15,
1435
+ outputPer1m: 0
1436
+ }
1437
+ ],
1438
+ contextWindow: 2048
1439
+ },
1440
+ {
1441
+ model: "dall-e-3",
1442
+ provider: "openai",
1443
+ modality: "image",
1444
+ currency: "USD",
1445
+ asOf: "2026-07-27",
1446
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1447
+ provenance: "litellm-catalog",
1448
+ rates: [
1449
+ {
1450
+ unit: "per_image",
1451
+ amount: 0.04,
1452
+ variant: "1024x1024 standard"
1453
+ }
1454
+ ]
1455
+ },
1456
+ {
1457
+ model: "gemini-3-pro-image",
1458
+ provider: "gemini",
1459
+ modality: "image",
1460
+ currency: "USD",
1461
+ asOf: "2026-07-27",
1462
+ source: "https://ai.google.dev/gemini-api/docs/pricing",
1463
+ provenance: "litellm-catalog",
1464
+ rates: [
1465
+ {
1466
+ unit: "per_image",
1467
+ amount: 0.134,
1468
+ variant: "default output resolution"
1469
+ }
1470
+ ],
1471
+ notes: "Google bills image output per output-token ($120 per 1M image output tokens); $0.134/image is that rate applied to one default-resolution image. Cost per image therefore varies with resolution."
1472
+ },
1473
+ {
1474
+ model: "imagen-4.0-generate-001",
1475
+ provider: "vertex",
1476
+ modality: "image",
1477
+ currency: "USD",
1478
+ asOf: "2026-07-27",
1479
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1480
+ provenance: "litellm-catalog",
1481
+ rates: [
1482
+ {
1483
+ unit: "per_image",
1484
+ amount: 0.04
1485
+ }
1486
+ ]
1487
+ },
1488
+ {
1489
+ model: "veo-3.1-generate-001",
1490
+ provider: "gemini",
1491
+ modality: "video",
1492
+ currency: "USD",
1493
+ asOf: "2026-07-27",
1494
+ source: "https://ai.google.dev/gemini-api/docs/video",
1495
+ provenance: "litellm-catalog",
1496
+ rates: [
1497
+ {
1498
+ unit: "per_second",
1499
+ amount: 0.4
1500
+ }
1501
+ ]
1502
+ },
1503
+ {
1504
+ model: "veo-3.1-generate-001",
1505
+ provider: "vertex",
1506
+ modality: "video",
1507
+ currency: "USD",
1508
+ asOf: "2026-07-27",
1509
+ source: "https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/veo",
1510
+ provenance: "litellm-catalog",
1511
+ rates: [
1512
+ {
1513
+ unit: "per_second",
1514
+ amount: 0.4
1515
+ }
1516
+ ]
1517
+ },
1518
+ {
1519
+ model: "tts-1",
1520
+ provider: "openai",
1521
+ modality: "speech",
1522
+ currency: "USD",
1523
+ asOf: "2026-07-27",
1524
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1525
+ provenance: "litellm-catalog",
1526
+ rates: [
1527
+ {
1528
+ unit: "per_character",
1529
+ amount: 15e-6
1530
+ }
1531
+ ],
1532
+ notes: "$15 per 1M characters."
1533
+ },
1534
+ {
1535
+ model: "tts-1-hd",
1536
+ provider: "openai",
1537
+ modality: "speech",
1538
+ currency: "USD",
1539
+ asOf: "2026-07-27",
1540
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1541
+ provenance: "litellm-catalog",
1542
+ rates: [
1543
+ {
1544
+ unit: "per_character",
1545
+ amount: 3e-5
1546
+ }
1547
+ ],
1548
+ notes: "$30 per 1M characters."
1549
+ },
1550
+ {
1551
+ model: "whisper-1",
1552
+ provider: "openai",
1553
+ modality: "transcription",
1554
+ currency: "USD",
1555
+ asOf: "2026-07-27",
1556
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1557
+ provenance: "litellm-catalog",
1558
+ rates: [
1559
+ {
1560
+ unit: "per_audio_minute",
1561
+ amount: 6e-3
1562
+ }
1563
+ ],
1564
+ notes: "litellm records $0.0001 per audio second; $0.006/minute is that rate x 60."
1565
+ }
1566
+ ]
1567
+ };
1568
+ }
1569
+ });
1570
+
1571
+ // src/core/router/pricing.ts
1572
+ function normalizeForPricing(id) {
1573
+ let s = id.trim().toLowerCase();
1574
+ s = s.replace(/^models\//, "");
1575
+ const slash = s.lastIndexOf("/");
1576
+ if (slash !== -1) s = s.slice(slash + 1);
1577
+ const tag = s.search(/[:@]/);
1578
+ if (tag !== -1) s = s.slice(0, tag);
1579
+ s = s.replace(/-latest$/, "");
1580
+ s = s.replace(/-preview(?:-\d{2}-\d{2})?$/, "");
1581
+ s = s.replace(/-\d{4}-\d{2}-\d{2}$/, "");
1582
+ s = s.replace(/-\d{8}$/, "");
1583
+ s = s.replace(/-preview$/, "");
1584
+ return s;
1585
+ }
1586
+ function indexKey(model, provider, region) {
1587
+ return `${provider}|${normalizeForPricing(model)}|${region ?? ""}`;
1588
+ }
1589
+ function findPricing(modelId, provider, opts = {}) {
1590
+ const ids = [modelId, opts.baseModelId].filter((x) => !!x);
1591
+ const providers = [provider, ...opts.fallbackProviders ?? []];
1592
+ for (const p of providers) {
1593
+ for (const id of ids) {
1594
+ const hit = (opts.region ? INDEX.get(indexKey(id, p, opts.region)) : void 0) ?? INDEX.get(indexKey(id, p));
1595
+ if (hit) return { entry: hit, matchedProvider: p, viaFallback: p !== provider };
1596
+ }
1597
+ }
1598
+ return null;
1599
+ }
1600
+ function pricingDatasetMeta() {
1601
+ const { schemaVersion, generatedAt, defaultCurrency } = DATASET;
1602
+ return { schemaVersion, generatedAt, defaultCurrency };
1603
+ }
1604
+ function tierFor(entry, inputTokens = 0) {
1605
+ const tiers = entry.tiers;
1606
+ if (!tiers?.length) return null;
1607
+ for (const t of tiers) {
1608
+ if (t.maxInputTokens === void 0 || inputTokens <= t.maxInputTokens) return t;
1609
+ }
1610
+ return tiers[tiers.length - 1] ?? null;
1611
+ }
1612
+ function tokenRatesPer1k(entry, opts = {}) {
1613
+ const tier = tierFor(entry, opts.inputTokens ?? 0);
1614
+ if (!tier) return null;
1615
+ const mult = (opts.batch ? entry.batchMultiplier ?? 1 : 1) * PER_1M_TO_PER_1K;
1616
+ const out = {
1617
+ input: tier.inputPer1m * mult,
1618
+ output: tier.outputPer1m * mult
1619
+ };
1620
+ if (tier.cachedInputPer1m !== void 0) out.cachedInput = tier.cachedInputPer1m * mult;
1621
+ if (tier.cacheWritePer1m !== void 0) out.cacheWrite = tier.cacheWritePer1m * mult;
1622
+ if (tier.reasoningOutputPer1m !== void 0) out.reasoningOutput = tier.reasoningOutputPer1m * mult;
1623
+ return out;
1624
+ }
1625
+ function isLoopbackOrPrivateHost(url) {
1626
+ if (!url) return false;
1627
+ try {
1628
+ const host = new URL(url).hostname.toLowerCase().replace(/^\[|\]$/g, "");
1629
+ if (LOOPBACK_HOSTS.has(host) || LOOPBACK_HOSTS.has(`[${host}]`)) return true;
1630
+ if (host.endsWith(".local")) return true;
1631
+ if (/^127\./.test(host)) return true;
1632
+ if (/^10\./.test(host)) return true;
1633
+ if (/^192\.168\./.test(host)) return true;
1634
+ if (/^172\.(1[6-9]|2\d|3[01])\./.test(host)) return true;
1635
+ return false;
1636
+ } catch {
1637
+ return false;
1638
+ }
1639
+ }
1640
+ function isLocalEndpoint(cfg) {
1641
+ if (typeof cfg.local === "boolean") return cfg.local;
1642
+ if (cfg.type === "ollama") return true;
1643
+ if (cfg.type === "openai-compatible") return isLoopbackOrPrivateHost(cfg.baseUrl);
1644
+ return false;
1645
+ }
1646
+ function resolvePricing(model, opts = {}) {
1647
+ if (model.isLocal) return FREE;
1648
+ const fallbackProviders = model.provider === "azure" ? ["openai"] : model.provider === "gemini" ? ["vertex"] : [];
1649
+ const match = findPricing(model.id, model.provider, {
1650
+ region: opts.region,
1651
+ baseModelId: model.baseModelId,
1652
+ fallbackProviders
1653
+ });
1654
+ if (!match) return UNKNOWN;
1655
+ const rates = tokenRatesPer1k(match.entry, { inputTokens: opts.inputTokens, batch: opts.batch });
1656
+ if (!rates) return UNKNOWN;
1657
+ return {
1658
+ input: rates.input,
1659
+ output: rates.output,
1660
+ unknown: false,
1661
+ free: false,
1662
+ entry: match.entry,
1663
+ ...match.viaFallback ? { estimatedFromProvider: match.matchedProvider } : {}
1664
+ };
1665
+ }
1666
+ function withResolvedPricing(model, opts = {}) {
1667
+ const p = resolvePricing(model, opts);
1668
+ return {
1669
+ ...model,
1670
+ inputCostPer1kTokens: p.input,
1671
+ outputCostPer1kTokens: p.output,
1672
+ ...p.unknown ? { pricingUnknown: true } : { pricingUnknown: false }
1673
+ };
1674
+ }
1675
+ function isPricingUnknown(model) {
1676
+ return model.pricingUnknown === true && !model.isLocal;
1677
+ }
1678
+ function blendedCostPer1k(model) {
1679
+ if (isPricingUnknown(model)) return BLENDED_COST_CEILING;
1680
+ return model.inputCostPer1kTokens + model.outputCostPer1kTokens * 2;
1681
+ }
1682
+ function reconcilePrice(model, live) {
1683
+ const baseline = resolvePricing(model);
1684
+ const liveIsZero = !(live.input > 0) && !(live.output > 0);
1685
+ if (liveIsZero && !model.isLocal) {
1686
+ return { input: baseline.input, output: baseline.output, accepted: false };
1687
+ }
1688
+ if (baseline.unknown || !baseline.entry) {
1689
+ return { input: live.input, output: live.output, accepted: true };
1690
+ }
1691
+ const dsBlend = baseline.input + baseline.output * 2;
1692
+ const liveBlend = live.input + live.output * 2;
1693
+ const ratio = dsBlend > 0 ? liveBlend / dsBlend : Number.POSITIVE_INFINITY;
1694
+ const material = dsBlend > 0 && Math.abs(ratio - 1) > DISAGREEMENT_THRESHOLD;
1695
+ return {
1696
+ input: live.input,
1697
+ output: live.output,
1698
+ accepted: true,
1699
+ ...material ? {
1700
+ disagreement: {
1701
+ modelId: model.id,
1702
+ provider: model.provider,
1703
+ dataset: { input: baseline.input, output: baseline.output },
1704
+ live: { input: live.input, output: live.output },
1705
+ ratio: Math.round(ratio * 1e3) / 1e3,
1706
+ datasetAsOf: baseline.entry.asOf,
1707
+ datasetSource: baseline.entry.source
1708
+ }
1709
+ } : {}
1710
+ };
1711
+ }
1712
+ var DATASET, INDEX, PER_1M_TO_PER_1K, LOOPBACK_HOSTS, UNKNOWN, FREE, BLENDED_COST_CEILING, DISAGREEMENT_THRESHOLD;
1713
+ var init_pricing = __esm({
1714
+ "src/core/router/pricing.ts"() {
1715
+ init_pricing_data();
1716
+ DATASET = pricing_data_default;
1717
+ INDEX = /* @__PURE__ */ new Map();
1718
+ for (const entry of DATASET.entries) {
1719
+ for (const name of [entry.model, ...entry.aliases ?? []]) {
1720
+ const withRegion = indexKey(name, entry.provider, entry.region);
1721
+ if (!INDEX.has(withRegion)) INDEX.set(withRegion, entry);
1722
+ const bare = indexKey(name, entry.provider);
1723
+ const existing = INDEX.get(bare);
1724
+ if (!existing || existing.region && existing.region !== "global" && entry.region === "global") {
1725
+ INDEX.set(bare, entry);
1726
+ }
1727
+ }
1728
+ }
1729
+ PER_1M_TO_PER_1K = 1 / 1e3;
1730
+ LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "0.0.0.0", "::1", "[::1]"]);
1731
+ UNKNOWN = { input: 0, output: 0, unknown: true, free: false };
1732
+ FREE = { input: 0, output: 0, unknown: false, free: true };
1733
+ BLENDED_COST_CEILING = 0.05;
1734
+ DISAGREEMENT_THRESHOLD = 0.02;
1735
+ }
1736
+ });
1737
+
62
1738
  // src/constants.ts
63
1739
  var CASCADE_VERSION, CASCADE_CONFIG_FILE, CASCADE_DB_FILE, CASCADE_DASHBOARD_SECRET_FILE, GLOBAL_CONFIG_DIR, GLOBAL_DB_FILE, GLOBAL_KEYSTORE_FILE, GLOBAL_CREDENTIALS_FILE, GLOBAL_RUNTIME_DB_FILE, DEFAULT_DASHBOARD_PORT, DEFAULT_CONTEXT_LIMIT, DEFAULT_AUTO_SUMMARIZE_AT, MODELS, T1_MODEL_PRIORITY, T2_MODEL_PRIORITY, T3_MODEL_PRIORITY, VISION_MODEL_PRIORITY, COMPLEXITY_T2_COUNT, THEME_NAMES, DEFAULT_THEME, OLLAMA_BASE_URL, LM_STUDIO_BASE_URL, AZURE_BASE_URL_TEMPLATE, TOOL_NAMES, DEFAULT_APPROVAL_REQUIRED;
64
1740
  var init_constants = __esm({
65
1741
  "src/constants.ts"() {
66
- CASCADE_VERSION = "0.48.0";
1742
+ init_pricing();
1743
+ CASCADE_VERSION = "0.49.0";
67
1744
  CASCADE_CONFIG_FILE = ".cascade/config.json";
68
1745
  CASCADE_DB_FILE = ".cascade/memory.db";
69
1746
  CASCADE_DASHBOARD_SECRET_FILE = ".cascade/dashboard-secret";
@@ -404,6 +2081,13 @@ var init_constants = __esm({
404
2081
  for (const _m of Object.values(MODELS)) {
405
2082
  if (_m.supportsToolUse === void 0) _m.supportsToolUse = !_m.isLocal;
406
2083
  }
2084
+ for (const _m of Object.values(MODELS)) {
2085
+ const priced = resolvePricing(_m);
2086
+ if (priced.unknown || priced.free || priced.estimatedFromProvider) continue;
2087
+ _m.inputCostPer1kTokens = priced.input;
2088
+ _m.outputCostPer1kTokens = priced.output;
2089
+ _m.pricingUnknown = false;
2090
+ }
407
2091
  T1_MODEL_PRIORITY = [
408
2092
  "gpt-5.5",
409
2093
  "gpt-5.4",
@@ -488,24 +2172,53 @@ var init_constants = __esm({
488
2172
 
489
2173
  // src/utils/cost.ts
490
2174
  function resolveModelPricing(model) {
491
- let input = model.inputCostPer1kTokens;
492
- let output = model.outputCostPer1kTokens;
493
- if (input === 0 && output === 0 && model.id && !model.isLocal) {
2175
+ if (model.isLocal) return { input: 0, output: 0, unknown: false };
2176
+ if (model.inputCostPer1kTokens > 0 || model.outputCostPer1kTokens > 0) {
2177
+ return {
2178
+ input: model.inputCostPer1kTokens,
2179
+ output: model.outputCostPer1kTokens,
2180
+ unknown: false
2181
+ };
2182
+ }
2183
+ const fromDataset = resolvePricing(model);
2184
+ if (!fromDataset.unknown) {
2185
+ return {
2186
+ input: fromDataset.input,
2187
+ output: fromDataset.output,
2188
+ unknown: false,
2189
+ ...fromDataset.estimatedFromProvider ? { estimatedFromProvider: fromDataset.estimatedFromProvider } : {}
2190
+ };
2191
+ }
2192
+ if (model.id) {
494
2193
  const known = Object.values(MODELS).find((m) => m.id === model.id && !m.isLocal);
495
- if (known) {
496
- input = known.inputCostPer1kTokens;
497
- output = known.outputCostPer1kTokens;
2194
+ if (known && (known.inputCostPer1kTokens > 0 || known.outputCostPer1kTokens > 0)) {
2195
+ return {
2196
+ input: known.inputCostPer1kTokens,
2197
+ output: known.outputCostPer1kTokens,
2198
+ unknown: false
2199
+ };
498
2200
  }
499
2201
  }
500
- return { input, output };
2202
+ return { input: 0, output: 0, unknown: true };
501
2203
  }
502
2204
  function calculateCost(inputTokens, outputTokens, model) {
503
2205
  const { input, output } = resolveModelPricing(model);
504
2206
  return inputTokens / 1e3 * input + outputTokens / 1e3 * output;
505
2207
  }
2208
+ function buildTokenUsage(inputTokens, outputTokens, model) {
2209
+ const { input, output, unknown } = resolveModelPricing(model);
2210
+ return {
2211
+ inputTokens,
2212
+ outputTokens,
2213
+ totalTokens: inputTokens + outputTokens,
2214
+ estimatedCostUsd: inputTokens / 1e3 * input + outputTokens / 1e3 * output,
2215
+ ...unknown ? { costUnknown: true } : {}
2216
+ };
2217
+ }
506
2218
  var init_cost = __esm({
507
2219
  "src/utils/cost.ts"() {
508
2220
  init_constants();
2221
+ init_pricing();
509
2222
  }
510
2223
  });
511
2224
 
@@ -531,12 +2244,7 @@ var init_base = __esm({
531
2244
  return calculateCost(inputTokens, outputTokens, this.model);
532
2245
  }
533
2246
  makeUsage(inputTokens, outputTokens) {
534
- return {
535
- inputTokens,
536
- outputTokens,
537
- totalTokens: inputTokens + outputTokens,
538
- estimatedCostUsd: this.estimateCost(inputTokens, outputTokens)
539
- };
2247
+ return buildTokenUsage(inputTokens, outputTokens, this.model);
540
2248
  }
541
2249
  };
542
2250
  }
@@ -612,6 +2320,7 @@ var init_anthropic = __esm({
612
2320
  "src/providers/anthropic.ts"() {
613
2321
  init_constants();
614
2322
  init_base();
2323
+ init_pricing();
615
2324
  init_model_filter();
616
2325
  AnthropicProvider = class extends BaseProvider {
617
2326
  client;
@@ -722,7 +2431,7 @@ var init_anthropic = __esm({
722
2431
  return data.data.filter((m) => isChatModel(m.id)).map((m) => {
723
2432
  const known = Object.values(MODELS).find((km) => km.id === m.id && km.provider === "anthropic");
724
2433
  if (known) return known;
725
- return {
2434
+ return withResolvedPricing({
726
2435
  id: m.id,
727
2436
  name: m.display_name || m.id,
728
2437
  provider: "anthropic",
@@ -733,7 +2442,7 @@ var init_anthropic = __esm({
733
2442
  maxOutputTokens: 8e3,
734
2443
  supportsStreaming: true,
735
2444
  isLocal: false
736
- };
2445
+ });
737
2446
  });
738
2447
  } catch {
739
2448
  return Object.values(MODELS).filter((m) => m.provider === "anthropic");
@@ -828,6 +2537,7 @@ var init_openai = __esm({
828
2537
  "src/providers/openai.ts"() {
829
2538
  init_constants();
830
2539
  init_base();
2540
+ init_pricing();
831
2541
  init_model_filter();
832
2542
  OpenAIProvider = class extends BaseProvider {
833
2543
  client;
@@ -953,7 +2663,7 @@ var init_openai = __esm({
953
2663
  return response.data.filter((m) => isChatModel(m.id)).map((m) => {
954
2664
  const known = Object.values(MODELS).find((km) => km.id === m.id && km.provider === "openai");
955
2665
  if (known) return known;
956
- return {
2666
+ return withResolvedPricing({
957
2667
  id: m.id,
958
2668
  name: m.id,
959
2669
  provider: "openai",
@@ -964,7 +2674,7 @@ var init_openai = __esm({
964
2674
  maxOutputTokens: 4e3,
965
2675
  supportsStreaming: true,
966
2676
  isLocal: false
967
- };
2677
+ });
968
2678
  });
969
2679
  } catch {
970
2680
  return Object.values(MODELS).filter((m) => m.provider === "openai");
@@ -1067,6 +2777,10 @@ function azureModelForDeployment(cfg) {
1067
2777
  const baseModelId = cfg.model?.trim() || inferAzureBaseModel(id) || void 0;
1068
2778
  const base = baseModelId ? MODELS[baseModelId] : void 0;
1069
2779
  if (base) {
2780
+ const azurePrice = resolvePricing(
2781
+ { id, provider: "azure", isLocal: false, baseModelId },
2782
+ { region: cfg.region }
2783
+ );
1070
2784
  return {
1071
2785
  ...base,
1072
2786
  id,
@@ -1075,7 +2789,12 @@ function azureModelForDeployment(cfg) {
1075
2789
  provider: "azure",
1076
2790
  baseModelId,
1077
2791
  // real identity for benchmark + live pricing
1078
- supportsToolUse: base.supportsToolUse ?? true
2792
+ supportsToolUse: base.supportsToolUse ?? true,
2793
+ ...azurePrice.unknown ? {} : {
2794
+ inputCostPer1kTokens: azurePrice.input,
2795
+ outputCostPer1kTokens: azurePrice.output,
2796
+ pricingUnknown: false
2797
+ }
1079
2798
  };
1080
2799
  }
1081
2800
  return {
@@ -1098,6 +2817,7 @@ var init_azure = __esm({
1098
2817
  "src/providers/azure.ts"() {
1099
2818
  init_constants();
1100
2819
  init_openai();
2820
+ init_pricing();
1101
2821
  DEFAULT_AZURE_API_VERSION = "2024-12-01-preview";
1102
2822
  AzureOpenAIProvider = class extends OpenAIProvider {
1103
2823
  constructor(config, model) {
@@ -1158,6 +2878,7 @@ var init_gemini = __esm({
1158
2878
  "src/providers/gemini.ts"() {
1159
2879
  init_constants();
1160
2880
  init_base();
2881
+ init_pricing();
1161
2882
  init_model_filter();
1162
2883
  GeminiProvider = class extends BaseProvider {
1163
2884
  client;
@@ -1258,7 +2979,7 @@ var init_gemini = __esm({
1258
2979
  (km) => km.id === id && km.provider === "gemini"
1259
2980
  );
1260
2981
  if (known) return known;
1261
- return {
2982
+ return withResolvedPricing({
1262
2983
  id,
1263
2984
  name: m.displayName || id,
1264
2985
  provider: "gemini",
@@ -1269,7 +2990,7 @@ var init_gemini = __esm({
1269
2990
  maxOutputTokens: m.outputTokenLimit || 8e3,
1270
2991
  supportsStreaming: true,
1271
2992
  isLocal: false
1272
- };
2993
+ });
1273
2994
  });
1274
2995
  } catch {
1275
2996
  return Object.values(MODELS).filter((m) => m.provider === "gemini");
@@ -1475,6 +3196,7 @@ var init_ollama = __esm({
1475
3196
  init_constants();
1476
3197
  init_net();
1477
3198
  init_base();
3199
+ init_pricing();
1478
3200
  init_model_filter();
1479
3201
  TOOL_CAPABLE_FAMILIES = [
1480
3202
  "llama3.1",
@@ -1634,9 +3356,10 @@ var init_ollama = __esm({
1634
3356
  return supportedKeywords.some((k) => name.includes(k)) && isChatModel(name);
1635
3357
  });
1636
3358
  const shows = await Promise.all(entries.map((m) => this.showModel(m.name)));
3359
+ const local = isLocalEndpoint({ ...this.config, type: "ollama" });
1637
3360
  return entries.map((m, i) => {
1638
3361
  const show = shows[i];
1639
- return {
3362
+ return withResolvedPricing({
1640
3363
  id: m.name,
1641
3364
  name: m.name,
1642
3365
  provider: "ollama",
@@ -1646,10 +3369,10 @@ var init_ollama = __esm({
1646
3369
  outputCostPer1kTokens: 0,
1647
3370
  maxOutputTokens: 4e3,
1648
3371
  supportsStreaming: true,
1649
- isLocal: true,
3372
+ isLocal: local,
1650
3373
  supportsToolUse: show?.tools ?? isToolCapable(m.name),
1651
3374
  minSizeB: this.parseSizeB(m.details?.parameter_size)
1652
- };
3375
+ });
1653
3376
  });
1654
3377
  } catch {
1655
3378
  return [];
@@ -1733,6 +3456,7 @@ var init_openai_compatible = __esm({
1733
3456
  init_openai();
1734
3457
  init_model_filter();
1735
3458
  init_net();
3459
+ init_pricing();
1736
3460
  OpenAICompatibleProvider = class extends OpenAIProvider {
1737
3461
  constructor(config, model) {
1738
3462
  super({ ...config, apiKey: config.apiKey ?? "not-required" }, model);
@@ -1766,7 +3490,8 @@ var init_openai_compatible = __esm({
1766
3490
  }).filter((x) => typeof x === "string" && x.length > 0);
1767
3491
  if (ids.length === 0) return [this.model];
1768
3492
  const chatIds = ids.filter((id) => isChatModel(id));
1769
- return (chatIds.length ? chatIds : ids).map((id) => ({
3493
+ const local = isLocalEndpoint(this.config);
3494
+ return (chatIds.length ? chatIds : ids).map((id) => withResolvedPricing({
1770
3495
  id,
1771
3496
  name: id,
1772
3497
  provider: "openai-compatible",
@@ -1776,7 +3501,7 @@ var init_openai_compatible = __esm({
1776
3501
  outputCostPer1kTokens: 0,
1777
3502
  maxOutputTokens: 4e3,
1778
3503
  supportsStreaming: true,
1779
- isLocal: false
3504
+ isLocal: local
1780
3505
  }));
1781
3506
  }
1782
3507
  async isAvailable() {
@@ -3098,7 +4823,18 @@ var ProviderConfigSchema = z.object({
3098
4823
  apiVersion: z.string().optional(),
3099
4824
  model: z.string().optional(),
3100
4825
  authToken: z.string().optional(),
3101
- credentialSource: z.string().optional()
4826
+ credentialSource: z.string().optional(),
4827
+ /**
4828
+ * "This endpoint is self-hosted, so inference genuinely costs $0."
4829
+ * Only meaningful for `ollama` and `openai-compatible`. Unset ⇒ inferred:
4830
+ * ollama is local, openai-compatible is local when its baseUrl is
4831
+ * loopback/LAN. Set it explicitly to override — e.g. `false` for an Ollama
4832
+ * instance you rent, `true` for a llama.cpp box on your own LAN reached by
4833
+ * hostname.
4834
+ */
4835
+ local: z.boolean().optional(),
4836
+ /** Region for providers whose price varies by region (Azure: global | us | eu | …). */
4837
+ region: z.string().optional()
3102
4838
  });
3103
4839
  var ModelOverridesSchema = z.object({
3104
4840
  t1: z.string().optional(),
@@ -3947,6 +5683,7 @@ init_openai();
3947
5683
 
3948
5684
  // src/core/router/selector.ts
3949
5685
  init_constants();
5686
+ init_pricing();
3950
5687
  function normalizeModelId(id) {
3951
5688
  return id.replace(/^models\//, "").toLowerCase();
3952
5689
  }
@@ -4148,7 +5885,7 @@ var ModelSelector = class {
4148
5885
  else if (this.availableProviders.size === 1) providerStr = Array.from(this.availableProviders)[0];
4149
5886
  }
4150
5887
  if (providerStr && this.availableProviders.has(providerStr)) {
4151
- const dynamicModel = {
5888
+ const dynamicModel = withResolvedPricing({
4152
5889
  id: actualId,
4153
5890
  name: actualId,
4154
5891
  provider: providerStr,
@@ -4159,7 +5896,7 @@ var ModelSelector = class {
4159
5896
  maxOutputTokens: 8e3,
4160
5897
  supportsStreaming: true,
4161
5898
  isLocal: providerStr === "ollama"
4162
- };
5899
+ });
4163
5900
  this.addDynamicModel(dynamicModel);
4164
5901
  return dynamicModel;
4165
5902
  }
@@ -4529,6 +6266,7 @@ function computeDelegationSavings(stats, t1Model) {
4529
6266
 
4530
6267
  // src/core/router/live-data.ts
4531
6268
  init_constants();
6269
+ init_pricing();
4532
6270
  var DEFAULT_SNAPSHOT_URL = "https://raw.githubusercontent.com/Varun-SV/Cascade-AI/main/src/core/router/benchmark-data.json";
4533
6271
  var OPENROUTER_MODELS_URL = "https://openrouter.ai/api/v1/models";
4534
6272
  var FETCH_TIMEOUT_MS = 8e3;
@@ -4546,6 +6284,8 @@ var LiveDataProvider = class {
4546
6284
  snapshot = null;
4547
6285
  prices = /* @__PURE__ */ new Map();
4548
6286
  capabilities = /* @__PURE__ */ new Map();
6287
+ /** Dataset-vs-live price mismatches, deduped by `provider:modelId`. */
6288
+ disagreements = /* @__PURE__ */ new Map();
4549
6289
  source = "bundled";
4550
6290
  fetchedAt = 0;
4551
6291
  loaded = false;
@@ -4699,14 +6439,45 @@ var LiveDataProvider = class {
4699
6439
  /**
4700
6440
  * Returns a price-corrected copy of each model when live pricing is known,
4701
6441
  * leaving the original untouched (so the shared catalog is never mutated).
6442
+ *
6443
+ * Reconciliation policy (see reconcilePrice in pricing.ts): the bundled
6444
+ * dataset is the authoritative baseline, and a live quote overrides it
6445
+ * because it is fresher by construction — but the disagreement is RECORDED,
6446
+ * not swallowed. A dataset/live mismatch is the best signal available that
6447
+ * the committed prices have gone stale, so it must be visible rather than
6448
+ * silently resolved in either direction. A live quote of $0 for a non-local
6449
+ * model is rejected outright: that is the very failure mode this change
6450
+ * exists to prevent, and a marketplace's free-tier alias must never zero out
6451
+ * the price of the paid model Cascade is actually calling.
4702
6452
  */
4703
6453
  applyLivePricing(models) {
4704
6454
  return models.map((m) => {
4705
6455
  const p = this.getLivePrice(m.baseModelId ?? m.id);
4706
6456
  if (!p) return m;
4707
- return { ...m, inputCostPer1kTokens: p.input, outputCostPer1kTokens: p.output };
6457
+ const reconciled = reconcilePrice(m, p);
6458
+ if (reconciled.disagreement) this.recordDisagreement(reconciled.disagreement);
6459
+ if (!reconciled.accepted) return m;
6460
+ return {
6461
+ ...m,
6462
+ inputCostPer1kTokens: reconciled.input,
6463
+ outputCostPer1kTokens: reconciled.output,
6464
+ pricingUnknown: false
6465
+ };
4708
6466
  });
4709
6467
  }
6468
+ recordDisagreement(d) {
6469
+ const key = `${d.provider}:${d.modelId}`;
6470
+ if (this.disagreements.has(key)) return;
6471
+ this.disagreements.set(key, d);
6472
+ }
6473
+ /**
6474
+ * Dataset-vs-live price mismatches seen this session, newest-model-first
6475
+ * insertion order. Surfaced by `cascade models --verbose`; a non-empty list
6476
+ * means src/core/router/pricing-data.json is probably due a refresh.
6477
+ */
6478
+ getPriceDisagreements() {
6479
+ return [...this.disagreements.values()];
6480
+ }
4710
6481
  /** Current capability facts for a model id, or null when unknown. */
4711
6482
  getCapability(modelId) {
4712
6483
  return this.capabilities.get(normalizeModelId2(modelId)) ?? null;
@@ -4903,7 +6674,9 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter {
4903
6674
  tokensByTier: {},
4904
6675
  inputTokensByTier: {},
4905
6676
  outputTokensByTier: {},
4906
- costByFeature: {}
6677
+ costByFeature: {},
6678
+ untrackedCostCalls: 0,
6679
+ untrackedCostModels: []
4907
6680
  };
4908
6681
  tierModels = /* @__PURE__ */ new Map();
4909
6682
  /**
@@ -5253,7 +7026,7 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter {
5253
7026
  `Model ${model.id} inference timed out after ${cloudTimeoutMs}ms`
5254
7027
  );
5255
7028
  }
5256
- const correctedCost = calculateCost(
7029
+ const corrected = buildTokenUsage(
5257
7030
  result.usage.inputTokens,
5258
7031
  result.usage.outputTokens,
5259
7032
  model
@@ -5262,7 +7035,8 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter {
5262
7035
  ...result,
5263
7036
  usage: {
5264
7037
  ...result.usage,
5265
- estimatedCostUsd: correctedCost
7038
+ estimatedCostUsd: corrected.estimatedCostUsd,
7039
+ ...corrected.costUnknown ? { costUnknown: true } : { costUnknown: void 0 }
5266
7040
  }
5267
7041
  };
5268
7042
  if (!result || typeof result.content !== "string" || !result.usage) {
@@ -5449,7 +7223,9 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter {
5449
7223
  tokensByTier: { ...this.stats.tokensByTier },
5450
7224
  inputTokensByTier: { ...this.stats.inputTokensByTier },
5451
7225
  outputTokensByTier: { ...this.stats.outputTokensByTier },
5452
- costByFeature: { ...this.stats.costByFeature }
7226
+ costByFeature: { ...this.stats.costByFeature },
7227
+ untrackedCostCalls: this.stats.untrackedCostCalls,
7228
+ untrackedCostModels: [...this.stats.untrackedCostModels]
5453
7229
  };
5454
7230
  }
5455
7231
  /**
@@ -5500,7 +7276,9 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter {
5500
7276
  tokensByTier: {},
5501
7277
  inputTokensByTier: {},
5502
7278
  outputTokensByTier: {},
5503
- costByFeature: {}
7279
+ costByFeature: {},
7280
+ untrackedCostCalls: 0,
7281
+ untrackedCostModels: []
5504
7282
  };
5505
7283
  this.sessionCostUsd = 0;
5506
7284
  this.budgetState = "ok";
@@ -5685,6 +7463,18 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter {
5685
7463
  if (featureTag) {
5686
7464
  this.stats.costByFeature[featureTag] = (this.stats.costByFeature[featureTag] ?? 0) + usage.estimatedCostUsd;
5687
7465
  }
7466
+ if (usage.costUnknown) {
7467
+ this.stats.untrackedCostCalls += 1;
7468
+ if (!this.stats.untrackedCostModels.includes(model.id)) {
7469
+ this.stats.untrackedCostModels.push(model.id);
7470
+ const capped = this.config?.budget?.maxCostPerRunUsd != null || this.config?.budget?.sessionBudgetUsd != null;
7471
+ this.emit("cost:untracked", {
7472
+ modelId: model.id,
7473
+ provider: model.provider,
7474
+ reason: capped ? `No published price for ${model.provider}:${model.id}. Its spend is not counted toward your cost budget \u2014 the token cap still applies. Add it to the pricing dataset, or set the provider's \`local: true\` if this endpoint really is free.` : `No published price for ${model.provider}:${model.id}. Cost for this model is reported as "not tracked" rather than $0.00.`
7475
+ });
7476
+ }
7477
+ }
5688
7478
  this.runTokens += usage.totalTokens;
5689
7479
  this.runCostUsd += usage.estimatedCostUsd;
5690
7480
  this.updateBudgetState();
@@ -11215,6 +13005,7 @@ var noopTelemetry = {
11215
13005
  };
11216
13006
 
11217
13007
  // src/core/router/task-analyzer.ts
13008
+ init_pricing();
11218
13009
  var CODE_SIGNALS = [
11219
13010
  /\b(?:function|class|interface|async|await|import|export|const|let|var|def|return|if|else|for|while|try|catch)\b/,
11220
13011
  /\b(?:typescript|javascript|python|rust|go|java|c\+\+|sql|bash|shell|dockerfile|kubernetes|terraform)\b/i,
@@ -11391,8 +13182,8 @@ var TaskAnalyzer = class {
11391
13182
  }
11392
13183
  costEfficiency(model, complexity) {
11393
13184
  if (this.tracker) return this.tracker.costEfficiencyScore(model, complexity);
11394
- const blended = model.inputCostPer1kTokens + model.outputCostPer1kTokens * 2;
11395
- const normalised = Math.min(1, blended / 0.05);
13185
+ const blended = blendedCostPer1k(model);
13186
+ const normalised = Math.min(1, blended / BLENDED_COST_CEILING);
11396
13187
  const complexityWeight = (6 - complexity) / 5;
11397
13188
  return Math.max(0.1, 1 - normalised * complexityWeight);
11398
13189
  }
@@ -11407,6 +13198,9 @@ var TaskAnalyzer = class {
11407
13198
  analysisCache.clear();
11408
13199
  }
11409
13200
  };
13201
+
13202
+ // src/core/router/model-performance-tracker.ts
13203
+ init_pricing();
11410
13204
  var DEFAULT_STATS_FILE = path32.join(os10.homedir(), ".cascade", "model-perf.json");
11411
13205
  var ModelPerformanceTracker = class {
11412
13206
  stats = /* @__PURE__ */ new Map();
@@ -11527,8 +13321,8 @@ var ModelPerformanceTracker = class {
11527
13321
  * normalised over $0.05 blended as the "expensive" ceiling.
11528
13322
  */
11529
13323
  costEfficiencyScore(model, complexity) {
11530
- const blended = model.inputCostPer1kTokens + model.outputCostPer1kTokens * 2;
11531
- const normalised = Math.min(1, blended / 0.05);
13324
+ const blended = blendedCostPer1k(model);
13325
+ const normalised = Math.min(1, blended / BLENDED_COST_CEILING);
11532
13326
  const complexityWeight = (6 - complexity) / 5;
11533
13327
  return Math.max(0.1, 1 - normalised * complexityWeight);
11534
13328
  }
@@ -14332,7 +16126,11 @@ _(incomplete: ${reasons.join("; ")})_` : partial;
14332
16126
  inputTokens: 0,
14333
16127
  outputTokens: 0,
14334
16128
  totalTokens: stats.totalTokens,
14335
- estimatedCostUsd: stats.totalCostUsd
16129
+ estimatedCostUsd: stats.totalCostUsd,
16130
+ // At least one call ran on a model with no known price, so its spend is
16131
+ // missing from the total above. Say so rather than letting the caller
16132
+ // present an undercount as the final figure.
16133
+ ...stats.untrackedCostCalls > 0 ? { costUnknown: true } : {}
14336
16134
  },
14337
16135
  t2Results,
14338
16136
  durationMs,
@@ -14402,7 +16200,8 @@ _(incomplete: ${reasons.join("; ")})_` : partial;
14402
16200
  inputTokens: 0,
14403
16201
  outputTokens: 0,
14404
16202
  totalTokens: stats2.totalTokens,
14405
- estimatedCostUsd: stats2.totalCostUsd
16203
+ estimatedCostUsd: stats2.totalCostUsd,
16204
+ ...stats2.untrackedCostCalls > 0 ? { costUnknown: true } : {}
14406
16205
  },
14407
16206
  t2Results: [],
14408
16207
  durationMs: Date.now() - startMs,
@@ -14426,7 +16225,8 @@ _(incomplete: ${reasons.join("; ")})_` : partial;
14426
16225
  inputTokens: result.usage?.inputTokens ?? 0,
14427
16226
  outputTokens: result.usage?.outputTokens ?? 0,
14428
16227
  totalTokens: stats.totalTokens,
14429
- estimatedCostUsd: stats.totalCostUsd
16228
+ estimatedCostUsd: stats.totalCostUsd,
16229
+ ...stats.untrackedCostCalls > 0 ? { costUnknown: true } : {}
14430
16230
  },
14431
16231
  t2Results: [],
14432
16232
  durationMs: Date.now() - startMs,
@@ -14616,12 +16416,19 @@ var CloudClient = class _CloudClient {
14616
16416
  );
14617
16417
  await openUrl(authorizeUrl);
14618
16418
  const code = await listener.waitForCode;
14619
- const res = await fetch(this.url("/api/native/token"), {
14620
- method: "POST",
14621
- headers: { "Content-Type": "application/json" },
14622
- body: JSON.stringify({ code, code_verifier: verifier })
14623
- });
14624
- if (!res.ok) throw new Error("Sign-in could not be completed. Please try again.");
16419
+ let res;
16420
+ try {
16421
+ res = await fetch(this.url("/api/native/token"), {
16422
+ method: "POST",
16423
+ headers: { "Content-Type": "application/json" },
16424
+ body: JSON.stringify({ code, code_verifier: verifier })
16425
+ });
16426
+ } catch (err) {
16427
+ throw new Error(
16428
+ `Signed in, but could not reach Cascade at ${this.serverUrl} to finish. Check your connection and that the server URL is correct. (${err instanceof Error ? err.message : String(err)})`
16429
+ );
16430
+ }
16431
+ if (!res.ok) throw new Error(await loginFailureMessage(res, this.serverUrl));
14625
16432
  const tokens = await res.json();
14626
16433
  return await this.finishLogin(tokens);
14627
16434
  } finally {
@@ -14795,6 +16602,22 @@ function sleep(ms, signal) {
14795
16602
  }, { once: true });
14796
16603
  });
14797
16604
  }
16605
+ async function loginFailureMessage(res, serverUrl) {
16606
+ const body = await res.text().catch(() => "");
16607
+ let apiError = "";
16608
+ try {
16609
+ apiError = String(JSON.parse(body).error ?? "");
16610
+ } catch {
16611
+ }
16612
+ if (apiError === "invalid_grant") {
16613
+ return "Sign-in expired before it completed \u2014 the code is single-use and short-lived, and restarting the server during sign-in also invalidates it. Please try again.";
16614
+ }
16615
+ if (apiError) return `Sign-in failed: ${apiError} (HTTP ${res.status}).`;
16616
+ if (res.status === 404 || /<html/i.test(body)) {
16617
+ return `Signed in, but ${serverUrl} did not answer the Cascade API (HTTP ${res.status}). If this host was recently pointed at a new server, DNS may still be propagating.`;
16618
+ }
16619
+ return `Sign-in could not be completed (HTTP ${res.status}). Please try again.`;
16620
+ }
14798
16621
  function base64url(buf) {
14799
16622
  return buf.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
14800
16623
  }
@@ -19620,7 +21443,10 @@ var DashboardServer = class {
19620
21443
  this.socket.broadcast("cost:update", {
19621
21444
  sessionId,
19622
21445
  totalTokens: result.usage.totalTokens,
19623
- totalCostUsd: result.usage.estimatedCostUsd
21446
+ totalCostUsd: result.usage.estimatedCostUsd,
21447
+ // True when a model with no known price was used: the total above is
21448
+ // an undercount, and the UI must not present it as the full spend.
21449
+ costUnknown: result.usage.costUnknown === true
19624
21450
  });
19625
21451
  this.throttledBroadcast("workspace");
19626
21452
  } catch (err) {
@@ -19933,7 +21759,8 @@ var DashboardServer = class {
19933
21759
  this.socket.broadcast("cost:update", {
19934
21760
  sessionId,
19935
21761
  totalTokens: result.usage.totalTokens,
19936
- totalCostUsd: result.usage.estimatedCostUsd
21762
+ totalCostUsd: result.usage.estimatedCostUsd,
21763
+ costUnknown: result.usage.costUnknown === true
19937
21764
  });
19938
21765
  this.throttledBroadcast("workspace");
19939
21766
  } catch (err) {
@@ -20475,7 +22302,8 @@ ${prompt}`;
20475
22302
  this.socket.broadcast("cost:update", {
20476
22303
  sessionId,
20477
22304
  totalTokens: result.usage.totalTokens,
20478
- totalCostUsd: result.usage.estimatedCostUsd
22305
+ totalCostUsd: result.usage.estimatedCostUsd,
22306
+ costUnknown: result.usage.costUnknown === true
20479
22307
  });
20480
22308
  this.socket.broadcastToRoom(`session:${sessionId}`, "session:complete", { sessionId, result });
20481
22309
  this.throttledBroadcast("workspace");
@@ -20871,6 +22699,7 @@ function makeIdentityCommand(workspacePath = process.cwd()) {
20871
22699
  });
20872
22700
  return identity;
20873
22701
  }
22702
+ init_pricing();
20874
22703
  async function modelsCommand(options = {}) {
20875
22704
  console.log(chalk7.magenta("\n \u25C8 Cascade Models\n"));
20876
22705
  const cm = new ConfigManager(process.cwd());
@@ -20892,17 +22721,20 @@ async function modelsCommand(options = {}) {
20892
22721
  { tier: "T3", label: "T3 Worker", color: chalk7.hex("#2DD4BF") }
20893
22722
  ];
20894
22723
  let anyMissing = false;
22724
+ let anyUnpriced = false;
20895
22725
  for (const { tier, label, color } of tiers) {
20896
22726
  const model = router.getTierModel(tier);
20897
22727
  if (model) {
20898
- const costIn = model.inputCostPer1kTokens === 0 ? "free" : `$${model.inputCostPer1kTokens.toFixed(4)}/1K in`;
20899
- const costOut = model.outputCostPer1kTokens === 0 ? "free" : `$${model.outputCostPer1kTokens.toFixed(4)}/1K out`;
22728
+ const unpriced = isPricingUnknown(model);
22729
+ if (unpriced) anyUnpriced = true;
22730
+ const costIn = unpriced ? "cost not tracked" : model.inputCostPer1kTokens === 0 ? "free" : `$${model.inputCostPer1kTokens.toFixed(4)}/1K in`;
22731
+ const costOut = unpriced ? "" : model.outputCostPer1kTokens === 0 ? "free" : `, $${model.outputCostPer1kTokens.toFixed(4)}/1K out`;
20900
22732
  const ctx = model.contextWindow >= 1e6 ? `${(model.contextWindow / 1e6).toFixed(1)}M ctx` : `${(model.contextWindow / 1e3).toFixed(0)}K ctx`;
20901
22733
  const local = model.isLocal ? chalk7.gray(" [local]") : "";
20902
22734
  const vision = model.isVisionCapable ? chalk7.gray(" \u{1F441}") : "";
20903
22735
  const bench = Math.round(benchmarkScore01(model, "mixed") * 100);
20904
22736
  console.log(
20905
- ` ${color.bold(tier)} ${chalk7.white(col(model.name, 24))}${chalk7.gray(col(model.provider, 16))}` + (options.verbose ? `${chalk7.gray(col(ctx, 12))}${chalk7.gray(col(`bench ${bench}/100`, 14))}${chalk7.gray(`${costIn}, ${costOut}`)}` : `${chalk7.gray(col(ctx, 10))}${chalk7.gray(`bench ${bench}/100`)}`) + local + vision
22737
+ ` ${color.bold(tier)} ${chalk7.white(col(model.name, 24))}${chalk7.gray(col(model.provider, 16))}` + (options.verbose ? `${chalk7.gray(col(ctx, 12))}${chalk7.gray(col(`bench ${bench}/100`, 14))}${chalk7.gray(`${costIn}${costOut}`)}` : `${chalk7.gray(col(ctx, 10))}${chalk7.gray(`bench ${bench}/100`)}`) + local + vision
20906
22738
  );
20907
22739
  } else {
20908
22740
  console.log(` ${color.bold(tier)} ${chalk7.red("No model available")} ${chalk7.gray(`(check provider config for ${label})`)}`);
@@ -20916,8 +22748,25 @@ async function modelsCommand(options = {}) {
20916
22748
  const src = liveData.getDataSource();
20917
22749
  const gen = liveData.getGeneratedAt();
20918
22750
  const srcLabel = src === "live" ? "live (just fetched)" : src === "cache" ? "cached" : "bundled";
22751
+ const pricingMeta = pricingDatasetMeta();
20919
22752
  console.log(chalk7.gray(
20920
- ` Benchmark data: ${srcLabel}` + (gen ? ` \xB7 updated ${gen.slice(0, 10)}` : "") + ` \xB7 pricing: ${liveData.hasLivePricing() ? "live (OpenRouter)" : "catalog"}`
22753
+ ` Benchmark data: ${srcLabel}` + (gen ? ` \xB7 updated ${gen.slice(0, 10)}` : "") + ` \xB7 pricing: ${liveData.hasLivePricing() ? "live (OpenRouter)" : "dataset"} (baseline ${pricingMeta.generatedAt})`
22754
+ ));
22755
+ const drift = liveData.getPriceDisagreements();
22756
+ if (drift.length) {
22757
+ console.log(chalk7.yellow(`
22758
+ ${drift.length} model${drift.length === 1 ? "" : "s"} priced differently by the live source than by the bundled dataset:`));
22759
+ for (const d of drift.slice(0, 10)) {
22760
+ console.log(chalk7.gray(
22761
+ ` ${d.provider}:${d.modelId} dataset $${d.dataset.input.toFixed(5)}/$${d.dataset.output.toFixed(5)} per 1K (as of ${d.datasetAsOf}) \u2192 live $${d.live.input.toFixed(5)}/$${d.live.output.toFixed(5)} (${d.ratio}\xD7)`
22762
+ ));
22763
+ }
22764
+ console.log(chalk7.gray(" Live pricing is used. Refresh src/core/router/pricing-data.json to clear this."));
22765
+ }
22766
+ }
22767
+ if (anyUnpriced) {
22768
+ console.log(chalk7.yellow(
22769
+ '\n Some tiers use a model with no published price \u2014 their spend is reported as "cost not tracked", never $0.00,\n and is not counted toward a cost budget. Add the model to the pricing dataset, or set `local: true` on the\n provider if the endpoint genuinely costs nothing to run.'
20921
22770
  ));
20922
22771
  }
20923
22772
  if (options.verbose) {