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.cjs CHANGED
@@ -112,11 +112,1688 @@ var __export = (target, all) => {
112
112
  __defProp(target, name, { get: all[name], enumerable: true });
113
113
  };
114
114
 
115
+ // src/core/router/pricing-data.json
116
+ var pricing_data_default;
117
+ var init_pricing_data = __esm({
118
+ "src/core/router/pricing-data.json"() {
119
+ pricing_data_default = {
120
+ schemaVersion: 1,
121
+ generatedAt: "2026-07-27",
122
+ defaultCurrency: "USD",
123
+ 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.',
124
+ provenanceLegend: {
125
+ "vendor-pricing-page": "Read directly from the vendor's own published pricing page (see `source`).",
126
+ "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.",
127
+ "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."
128
+ },
129
+ entries: [
130
+ {
131
+ model: "claude-opus-5",
132
+ provider: "anthropic",
133
+ modality: "text",
134
+ currency: "USD",
135
+ asOf: "2026-07-27",
136
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
137
+ provenance: "vendor-pricing-page",
138
+ tiers: [
139
+ {
140
+ inputPer1m: 5,
141
+ outputPer1m: 25,
142
+ cachedInputPer1m: 0.5,
143
+ cacheWritePer1m: 6.25,
144
+ reasoningOutputPer1m: 25
145
+ }
146
+ ],
147
+ batchMultiplier: 0.5,
148
+ contextWindow: 1e6
149
+ },
150
+ {
151
+ model: "claude-opus-4-8",
152
+ provider: "anthropic",
153
+ modality: "text",
154
+ currency: "USD",
155
+ asOf: "2026-07-27",
156
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
157
+ provenance: "vendor-pricing-page",
158
+ tiers: [
159
+ {
160
+ inputPer1m: 5,
161
+ outputPer1m: 25,
162
+ cachedInputPer1m: 0.5,
163
+ cacheWritePer1m: 6.25,
164
+ reasoningOutputPer1m: 25
165
+ }
166
+ ],
167
+ batchMultiplier: 0.5,
168
+ contextWindow: 1e6
169
+ },
170
+ {
171
+ model: "claude-opus-4-7",
172
+ provider: "anthropic",
173
+ modality: "text",
174
+ currency: "USD",
175
+ asOf: "2026-07-27",
176
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
177
+ provenance: "vendor-pricing-page",
178
+ tiers: [
179
+ {
180
+ inputPer1m: 5,
181
+ outputPer1m: 25,
182
+ cachedInputPer1m: 0.5,
183
+ cacheWritePer1m: 6.25,
184
+ reasoningOutputPer1m: 25
185
+ }
186
+ ],
187
+ batchMultiplier: 0.5,
188
+ contextWindow: 1e6
189
+ },
190
+ {
191
+ model: "claude-opus-4-6",
192
+ provider: "anthropic",
193
+ modality: "text",
194
+ currency: "USD",
195
+ asOf: "2026-07-27",
196
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
197
+ provenance: "vendor-pricing-page",
198
+ tiers: [
199
+ {
200
+ inputPer1m: 5,
201
+ outputPer1m: 25,
202
+ cachedInputPer1m: 0.5,
203
+ cacheWritePer1m: 6.25,
204
+ reasoningOutputPer1m: 25
205
+ }
206
+ ],
207
+ batchMultiplier: 0.5,
208
+ contextWindow: 1e6
209
+ },
210
+ {
211
+ model: "claude-opus-4-5",
212
+ provider: "anthropic",
213
+ modality: "text",
214
+ currency: "USD",
215
+ asOf: "2026-07-27",
216
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
217
+ provenance: "vendor-pricing-page",
218
+ tiers: [
219
+ {
220
+ inputPer1m: 5,
221
+ outputPer1m: 25,
222
+ cachedInputPer1m: 0.5,
223
+ cacheWritePer1m: 6.25,
224
+ reasoningOutputPer1m: 25
225
+ }
226
+ ],
227
+ batchMultiplier: 0.5,
228
+ contextWindow: 2e5
229
+ },
230
+ {
231
+ model: "claude-opus-4-1",
232
+ provider: "anthropic",
233
+ modality: "text",
234
+ currency: "USD",
235
+ asOf: "2026-07-27",
236
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
237
+ provenance: "vendor-pricing-page",
238
+ tiers: [
239
+ {
240
+ inputPer1m: 15,
241
+ outputPer1m: 75,
242
+ cachedInputPer1m: 1.5,
243
+ cacheWritePer1m: 18.75,
244
+ reasoningOutputPer1m: 75
245
+ }
246
+ ],
247
+ batchMultiplier: 0.5,
248
+ contextWindow: 2e5,
249
+ notes: "Deprecated by Anthropic; priced for historical/cost-reporting accuracy."
250
+ },
251
+ {
252
+ model: "claude-opus-4",
253
+ provider: "anthropic",
254
+ modality: "text",
255
+ currency: "USD",
256
+ asOf: "2026-07-27",
257
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
258
+ provenance: "vendor-pricing-page",
259
+ tiers: [
260
+ {
261
+ inputPer1m: 15,
262
+ outputPer1m: 75,
263
+ cachedInputPer1m: 1.5,
264
+ cacheWritePer1m: 18.75,
265
+ reasoningOutputPer1m: 75
266
+ }
267
+ ],
268
+ batchMultiplier: 0.5,
269
+ contextWindow: 2e5,
270
+ notes: "Retired except on Google Cloud; priced for historical/cost-reporting accuracy."
271
+ },
272
+ {
273
+ model: "claude-sonnet-5",
274
+ provider: "anthropic",
275
+ modality: "text",
276
+ currency: "USD",
277
+ asOf: "2026-07-27",
278
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
279
+ provenance: "vendor-pricing-page",
280
+ tiers: [
281
+ {
282
+ inputPer1m: 2,
283
+ outputPer1m: 10,
284
+ cachedInputPer1m: 0.2,
285
+ cacheWritePer1m: 2.5,
286
+ reasoningOutputPer1m: 10
287
+ }
288
+ ],
289
+ batchMultiplier: 0.5,
290
+ contextWindow: 1e6,
291
+ 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."
292
+ },
293
+ {
294
+ model: "claude-sonnet-4-6",
295
+ provider: "anthropic",
296
+ modality: "text",
297
+ currency: "USD",
298
+ asOf: "2026-07-27",
299
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
300
+ provenance: "vendor-pricing-page",
301
+ tiers: [
302
+ {
303
+ inputPer1m: 3,
304
+ outputPer1m: 15,
305
+ cachedInputPer1m: 0.3,
306
+ cacheWritePer1m: 3.75,
307
+ reasoningOutputPer1m: 15
308
+ }
309
+ ],
310
+ batchMultiplier: 0.5,
311
+ contextWindow: 1e6
312
+ },
313
+ {
314
+ model: "claude-sonnet-4-5",
315
+ provider: "anthropic",
316
+ modality: "text",
317
+ currency: "USD",
318
+ asOf: "2026-07-27",
319
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
320
+ provenance: "vendor-pricing-page",
321
+ tiers: [
322
+ {
323
+ maxInputTokens: 2e5,
324
+ inputPer1m: 3,
325
+ outputPer1m: 15,
326
+ cachedInputPer1m: 0.3,
327
+ cacheWritePer1m: 3.75,
328
+ reasoningOutputPer1m: 15
329
+ },
330
+ {
331
+ inputPer1m: 6,
332
+ outputPer1m: 22.5,
333
+ cachedInputPer1m: 0.6,
334
+ cacheWritePer1m: 7.5,
335
+ reasoningOutputPer1m: 22.5
336
+ }
337
+ ],
338
+ batchMultiplier: 0.5,
339
+ contextWindow: 2e5,
340
+ 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)."
341
+ },
342
+ {
343
+ model: "claude-sonnet-4",
344
+ provider: "anthropic",
345
+ modality: "text",
346
+ currency: "USD",
347
+ asOf: "2026-07-27",
348
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
349
+ provenance: "vendor-pricing-page",
350
+ tiers: [
351
+ {
352
+ inputPer1m: 3,
353
+ outputPer1m: 15,
354
+ cachedInputPer1m: 0.3,
355
+ cacheWritePer1m: 3.75,
356
+ reasoningOutputPer1m: 15
357
+ }
358
+ ],
359
+ batchMultiplier: 0.5,
360
+ contextWindow: 2e5
361
+ },
362
+ {
363
+ model: "claude-haiku-4-5",
364
+ provider: "anthropic",
365
+ modality: "text",
366
+ currency: "USD",
367
+ asOf: "2026-07-27",
368
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
369
+ provenance: "vendor-pricing-page",
370
+ tiers: [
371
+ {
372
+ inputPer1m: 1,
373
+ outputPer1m: 5,
374
+ cachedInputPer1m: 0.1,
375
+ cacheWritePer1m: 1.25,
376
+ reasoningOutputPer1m: 5
377
+ }
378
+ ],
379
+ batchMultiplier: 0.5,
380
+ contextWindow: 2e5
381
+ },
382
+ {
383
+ model: "claude-haiku-3-5",
384
+ provider: "anthropic",
385
+ modality: "text",
386
+ currency: "USD",
387
+ asOf: "2026-07-27",
388
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
389
+ provenance: "vendor-pricing-page",
390
+ tiers: [
391
+ {
392
+ inputPer1m: 0.8,
393
+ outputPer1m: 4,
394
+ cachedInputPer1m: 0.08,
395
+ cacheWritePer1m: 1,
396
+ reasoningOutputPer1m: 4
397
+ }
398
+ ],
399
+ batchMultiplier: 0.5,
400
+ contextWindow: 2e5
401
+ },
402
+ {
403
+ model: "gpt-5.6-sol",
404
+ provider: "openai",
405
+ aliases: [
406
+ "gpt-5.6"
407
+ ],
408
+ modality: "text",
409
+ currency: "USD",
410
+ asOf: "2026-07-27",
411
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
412
+ provenance: "litellm-catalog",
413
+ tiers: [
414
+ {
415
+ maxInputTokens: 272e3,
416
+ inputPer1m: 5,
417
+ outputPer1m: 30,
418
+ cachedInputPer1m: 0.5,
419
+ cacheWritePer1m: 6.25
420
+ },
421
+ {
422
+ inputPer1m: 10,
423
+ outputPer1m: 45,
424
+ cachedInputPer1m: 1,
425
+ cacheWritePer1m: 12.5
426
+ }
427
+ ],
428
+ batchMultiplier: 0.5,
429
+ contextWindow: 105e4
430
+ },
431
+ {
432
+ model: "gpt-5.6-terra",
433
+ provider: "openai",
434
+ modality: "text",
435
+ currency: "USD",
436
+ asOf: "2026-07-27",
437
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
438
+ provenance: "litellm-catalog",
439
+ tiers: [
440
+ {
441
+ maxInputTokens: 272e3,
442
+ inputPer1m: 2.5,
443
+ outputPer1m: 15,
444
+ cachedInputPer1m: 0.25,
445
+ cacheWritePer1m: 3.125
446
+ },
447
+ {
448
+ inputPer1m: 5,
449
+ outputPer1m: 22.5,
450
+ cachedInputPer1m: 0.5,
451
+ cacheWritePer1m: 6.25
452
+ }
453
+ ],
454
+ batchMultiplier: 0.5,
455
+ contextWindow: 105e4
456
+ },
457
+ {
458
+ model: "gpt-5.6-luna",
459
+ provider: "openai",
460
+ modality: "text",
461
+ currency: "USD",
462
+ asOf: "2026-07-27",
463
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
464
+ provenance: "litellm-catalog",
465
+ tiers: [
466
+ {
467
+ maxInputTokens: 272e3,
468
+ inputPer1m: 1,
469
+ outputPer1m: 6,
470
+ cachedInputPer1m: 0.1,
471
+ cacheWritePer1m: 1.25
472
+ },
473
+ {
474
+ inputPer1m: 2,
475
+ outputPer1m: 9,
476
+ cachedInputPer1m: 0.2,
477
+ cacheWritePer1m: 2.5
478
+ }
479
+ ],
480
+ batchMultiplier: 0.5,
481
+ contextWindow: 105e4
482
+ },
483
+ {
484
+ model: "gpt-5.5",
485
+ provider: "openai",
486
+ modality: "text",
487
+ currency: "USD",
488
+ asOf: "2026-07-27",
489
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
490
+ provenance: "litellm-catalog",
491
+ tiers: [
492
+ {
493
+ maxInputTokens: 272e3,
494
+ inputPer1m: 5,
495
+ outputPer1m: 30,
496
+ cachedInputPer1m: 0.5
497
+ },
498
+ {
499
+ inputPer1m: 10,
500
+ outputPer1m: 45,
501
+ cachedInputPer1m: 1
502
+ }
503
+ ],
504
+ batchMultiplier: 0.5,
505
+ contextWindow: 105e4
506
+ },
507
+ {
508
+ model: "gpt-5.4",
509
+ provider: "openai",
510
+ modality: "text",
511
+ currency: "USD",
512
+ asOf: "2026-07-27",
513
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
514
+ provenance: "litellm-catalog",
515
+ tiers: [
516
+ {
517
+ maxInputTokens: 272e3,
518
+ inputPer1m: 2.5,
519
+ outputPer1m: 15,
520
+ cachedInputPer1m: 0.25
521
+ },
522
+ {
523
+ inputPer1m: 5,
524
+ outputPer1m: 22.5,
525
+ cachedInputPer1m: 0.5
526
+ }
527
+ ],
528
+ batchMultiplier: 0.5,
529
+ contextWindow: 105e4
530
+ },
531
+ {
532
+ model: "gpt-5.4-mini",
533
+ provider: "openai",
534
+ modality: "text",
535
+ currency: "USD",
536
+ asOf: "2026-07-27",
537
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
538
+ provenance: "litellm-catalog",
539
+ tiers: [
540
+ {
541
+ inputPer1m: 0.75,
542
+ outputPer1m: 4.5,
543
+ cachedInputPer1m: 0.075
544
+ }
545
+ ],
546
+ batchMultiplier: 0.5,
547
+ contextWindow: 105e4
548
+ },
549
+ {
550
+ model: "gpt-5",
551
+ provider: "openai",
552
+ modality: "text",
553
+ currency: "USD",
554
+ asOf: "2026-07-27",
555
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
556
+ provenance: "litellm-catalog",
557
+ tiers: [
558
+ {
559
+ inputPer1m: 1.25,
560
+ outputPer1m: 10,
561
+ cachedInputPer1m: 0.125
562
+ }
563
+ ],
564
+ contextWindow: 272e3
565
+ },
566
+ {
567
+ model: "gpt-5-mini",
568
+ provider: "openai",
569
+ modality: "text",
570
+ currency: "USD",
571
+ asOf: "2026-07-27",
572
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
573
+ provenance: "litellm-catalog",
574
+ tiers: [
575
+ {
576
+ inputPer1m: 0.25,
577
+ outputPer1m: 2,
578
+ cachedInputPer1m: 0.025
579
+ }
580
+ ],
581
+ contextWindow: 272e3
582
+ },
583
+ {
584
+ model: "gpt-5-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.05,
594
+ outputPer1m: 0.4,
595
+ cachedInputPer1m: 5e-3
596
+ }
597
+ ],
598
+ contextWindow: 272e3
599
+ },
600
+ {
601
+ model: "gpt-4.1",
602
+ provider: "openai",
603
+ modality: "text",
604
+ currency: "USD",
605
+ asOf: "2026-07-27",
606
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
607
+ provenance: "litellm-catalog",
608
+ tiers: [
609
+ {
610
+ inputPer1m: 2,
611
+ outputPer1m: 8,
612
+ cachedInputPer1m: 0.5
613
+ }
614
+ ],
615
+ batchMultiplier: 0.5,
616
+ contextWindow: 1047576
617
+ },
618
+ {
619
+ model: "gpt-4.1-mini",
620
+ provider: "openai",
621
+ modality: "text",
622
+ currency: "USD",
623
+ asOf: "2026-07-27",
624
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
625
+ provenance: "litellm-catalog",
626
+ tiers: [
627
+ {
628
+ inputPer1m: 0.4,
629
+ outputPer1m: 1.6,
630
+ cachedInputPer1m: 0.1
631
+ }
632
+ ],
633
+ batchMultiplier: 0.5,
634
+ contextWindow: 1047576
635
+ },
636
+ {
637
+ model: "gpt-4.1-nano",
638
+ provider: "openai",
639
+ modality: "text",
640
+ currency: "USD",
641
+ asOf: "2026-07-27",
642
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
643
+ provenance: "litellm-catalog",
644
+ tiers: [
645
+ {
646
+ inputPer1m: 0.1,
647
+ outputPer1m: 0.4,
648
+ cachedInputPer1m: 0.025
649
+ }
650
+ ],
651
+ batchMultiplier: 0.5,
652
+ contextWindow: 1047576
653
+ },
654
+ {
655
+ model: "gpt-4o",
656
+ provider: "openai",
657
+ modality: "text",
658
+ currency: "USD",
659
+ asOf: "2026-07-27",
660
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
661
+ provenance: "litellm-catalog",
662
+ tiers: [
663
+ {
664
+ inputPer1m: 2.5,
665
+ outputPer1m: 10,
666
+ cachedInputPer1m: 1.25
667
+ }
668
+ ],
669
+ batchMultiplier: 0.5,
670
+ contextWindow: 128e3
671
+ },
672
+ {
673
+ model: "gpt-4o-mini",
674
+ provider: "openai",
675
+ modality: "text",
676
+ currency: "USD",
677
+ asOf: "2026-07-27",
678
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
679
+ provenance: "litellm-catalog",
680
+ tiers: [
681
+ {
682
+ inputPer1m: 0.15,
683
+ outputPer1m: 0.6,
684
+ cachedInputPer1m: 0.075
685
+ }
686
+ ],
687
+ batchMultiplier: 0.5,
688
+ contextWindow: 128e3
689
+ },
690
+ {
691
+ model: "gpt-5.5",
692
+ provider: "azure",
693
+ region: "global",
694
+ modality: "text",
695
+ currency: "USD",
696
+ asOf: "2026-07-27",
697
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
698
+ provenance: "litellm-catalog",
699
+ tiers: [
700
+ {
701
+ maxInputTokens: 272e3,
702
+ inputPer1m: 5,
703
+ outputPer1m: 30,
704
+ cachedInputPer1m: 0.5
705
+ },
706
+ {
707
+ inputPer1m: 10,
708
+ outputPer1m: 45,
709
+ cachedInputPer1m: 1
710
+ }
711
+ ],
712
+ contextWindow: 105e4
713
+ },
714
+ {
715
+ model: "gpt-5.5",
716
+ provider: "azure",
717
+ region: "us",
718
+ modality: "text",
719
+ currency: "USD",
720
+ asOf: "2026-07-27",
721
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
722
+ provenance: "litellm-catalog",
723
+ tiers: [
724
+ {
725
+ maxInputTokens: 272e3,
726
+ inputPer1m: 5.5,
727
+ outputPer1m: 33,
728
+ cachedInputPer1m: 0.55
729
+ },
730
+ {
731
+ inputPer1m: 11,
732
+ outputPer1m: 49.5,
733
+ cachedInputPer1m: 1.1
734
+ }
735
+ ],
736
+ contextWindow: 105e4
737
+ },
738
+ {
739
+ model: "gpt-5.5",
740
+ provider: "azure",
741
+ region: "eu",
742
+ modality: "text",
743
+ currency: "USD",
744
+ asOf: "2026-07-27",
745
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
746
+ provenance: "litellm-catalog",
747
+ tiers: [
748
+ {
749
+ maxInputTokens: 272e3,
750
+ inputPer1m: 5.5,
751
+ outputPer1m: 33,
752
+ cachedInputPer1m: 0.55
753
+ },
754
+ {
755
+ inputPer1m: 11,
756
+ outputPer1m: 49.5,
757
+ cachedInputPer1m: 1.1
758
+ }
759
+ ],
760
+ contextWindow: 105e4
761
+ },
762
+ {
763
+ model: "gpt-5.4",
764
+ provider: "azure",
765
+ region: "global",
766
+ modality: "text",
767
+ currency: "USD",
768
+ asOf: "2026-07-27",
769
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
770
+ provenance: "litellm-catalog",
771
+ tiers: [
772
+ {
773
+ maxInputTokens: 272e3,
774
+ inputPer1m: 2.5,
775
+ outputPer1m: 15,
776
+ cachedInputPer1m: 0.25
777
+ },
778
+ {
779
+ inputPer1m: 5,
780
+ outputPer1m: 22.5,
781
+ cachedInputPer1m: 0.5
782
+ }
783
+ ],
784
+ contextWindow: 105e4
785
+ },
786
+ {
787
+ model: "gpt-5.4",
788
+ provider: "azure",
789
+ region: "us",
790
+ modality: "text",
791
+ currency: "USD",
792
+ asOf: "2026-07-27",
793
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
794
+ provenance: "litellm-catalog",
795
+ tiers: [
796
+ {
797
+ inputPer1m: 2.75,
798
+ outputPer1m: 16.5,
799
+ cachedInputPer1m: 0.28
800
+ }
801
+ ],
802
+ contextWindow: 105e4
803
+ },
804
+ {
805
+ model: "gpt-5.4",
806
+ provider: "azure",
807
+ region: "eu",
808
+ modality: "text",
809
+ currency: "USD",
810
+ asOf: "2026-07-27",
811
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
812
+ provenance: "litellm-catalog",
813
+ tiers: [
814
+ {
815
+ inputPer1m: 2.75,
816
+ outputPer1m: 16.5,
817
+ cachedInputPer1m: 0.28
818
+ }
819
+ ],
820
+ contextWindow: 105e4
821
+ },
822
+ {
823
+ model: "gpt-5.6-terra",
824
+ provider: "azure",
825
+ region: "global",
826
+ modality: "text",
827
+ currency: "USD",
828
+ asOf: "2026-07-27",
829
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
830
+ provenance: "litellm-catalog",
831
+ tiers: [
832
+ {
833
+ maxInputTokens: 272e3,
834
+ inputPer1m: 2.5,
835
+ outputPer1m: 15,
836
+ cachedInputPer1m: 0.25
837
+ },
838
+ {
839
+ inputPer1m: 5,
840
+ outputPer1m: 22.5,
841
+ cachedInputPer1m: 0.5
842
+ }
843
+ ],
844
+ contextWindow: 105e4
845
+ },
846
+ {
847
+ model: "gpt-5.6-terra",
848
+ provider: "azure",
849
+ region: "eu",
850
+ modality: "text",
851
+ currency: "USD",
852
+ asOf: "2026-07-27",
853
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
854
+ provenance: "litellm-catalog",
855
+ tiers: [
856
+ {
857
+ maxInputTokens: 272e3,
858
+ inputPer1m: 2.75,
859
+ outputPer1m: 16.5,
860
+ cachedInputPer1m: 0.275
861
+ },
862
+ {
863
+ inputPer1m: 5.5,
864
+ outputPer1m: 24.75,
865
+ cachedInputPer1m: 0.55
866
+ }
867
+ ],
868
+ contextWindow: 105e4
869
+ },
870
+ {
871
+ model: "gpt-5",
872
+ provider: "azure",
873
+ region: "global",
874
+ modality: "text",
875
+ currency: "USD",
876
+ asOf: "2026-07-27",
877
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
878
+ provenance: "litellm-catalog",
879
+ tiers: [
880
+ {
881
+ inputPer1m: 1.25,
882
+ outputPer1m: 10,
883
+ cachedInputPer1m: 0.125
884
+ }
885
+ ],
886
+ contextWindow: 272e3
887
+ },
888
+ {
889
+ model: "gpt-5-mini",
890
+ provider: "azure",
891
+ region: "global",
892
+ modality: "text",
893
+ currency: "USD",
894
+ asOf: "2026-07-27",
895
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
896
+ provenance: "litellm-catalog",
897
+ tiers: [
898
+ {
899
+ inputPer1m: 0.25,
900
+ outputPer1m: 2,
901
+ cachedInputPer1m: 0.025
902
+ }
903
+ ],
904
+ contextWindow: 272e3
905
+ },
906
+ {
907
+ model: "gpt-5-nano",
908
+ provider: "azure",
909
+ region: "global",
910
+ modality: "text",
911
+ currency: "USD",
912
+ asOf: "2026-07-27",
913
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
914
+ provenance: "litellm-catalog",
915
+ tiers: [
916
+ {
917
+ inputPer1m: 0.05,
918
+ outputPer1m: 0.4,
919
+ cachedInputPer1m: 5e-3
920
+ }
921
+ ],
922
+ contextWindow: 272e3
923
+ },
924
+ {
925
+ model: "gpt-4.1",
926
+ provider: "azure",
927
+ region: "global",
928
+ modality: "text",
929
+ currency: "USD",
930
+ asOf: "2026-07-27",
931
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
932
+ provenance: "litellm-catalog",
933
+ tiers: [
934
+ {
935
+ inputPer1m: 2,
936
+ outputPer1m: 8,
937
+ cachedInputPer1m: 0.5
938
+ }
939
+ ],
940
+ batchMultiplier: 0.5,
941
+ contextWindow: 1047576
942
+ },
943
+ {
944
+ model: "gpt-4o",
945
+ provider: "azure",
946
+ region: "global",
947
+ modality: "text",
948
+ currency: "USD",
949
+ asOf: "2026-07-27",
950
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
951
+ provenance: "litellm-catalog",
952
+ tiers: [
953
+ {
954
+ inputPer1m: 2.5,
955
+ outputPer1m: 10,
956
+ cachedInputPer1m: 1.25
957
+ }
958
+ ],
959
+ contextWindow: 128e3
960
+ },
961
+ {
962
+ model: "gpt-4o-mini",
963
+ provider: "azure",
964
+ region: "global",
965
+ modality: "text",
966
+ currency: "USD",
967
+ asOf: "2026-07-27",
968
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
969
+ provenance: "litellm-catalog",
970
+ tiers: [
971
+ {
972
+ inputPer1m: 0.165,
973
+ outputPer1m: 0.66,
974
+ cachedInputPer1m: 0.075
975
+ }
976
+ ],
977
+ contextWindow: 128e3,
978
+ 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."
979
+ },
980
+ {
981
+ model: "gemini-3.1-pro",
982
+ provider: "gemini",
983
+ aliases: [
984
+ "gemini-3.1-pro-preview"
985
+ ],
986
+ modality: "text",
987
+ currency: "USD",
988
+ asOf: "2026-07-27",
989
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
990
+ provenance: "vendor-pricing-page",
991
+ tiers: [
992
+ {
993
+ maxInputTokens: 2e5,
994
+ inputPer1m: 2,
995
+ outputPer1m: 12,
996
+ cachedInputPer1m: 0.2,
997
+ reasoningOutputPer1m: 12
998
+ },
999
+ {
1000
+ inputPer1m: 4,
1001
+ outputPer1m: 18,
1002
+ cachedInputPer1m: 0.4,
1003
+ reasoningOutputPer1m: 18
1004
+ }
1005
+ ],
1006
+ batchMultiplier: 0.5,
1007
+ contextWindow: 1048576,
1008
+ notes: "Long-context tier: $2/$12 per 1M up to 200K prompt tokens, $4/$18 above it."
1009
+ },
1010
+ {
1011
+ model: "gemini-3-pro",
1012
+ provider: "gemini",
1013
+ aliases: [
1014
+ "gemini-3-pro-preview"
1015
+ ],
1016
+ modality: "text",
1017
+ currency: "USD",
1018
+ asOf: "2026-07-27",
1019
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1020
+ provenance: "vendor-pricing-page",
1021
+ tiers: [
1022
+ {
1023
+ maxInputTokens: 2e5,
1024
+ inputPer1m: 2,
1025
+ outputPer1m: 12,
1026
+ cachedInputPer1m: 0.2,
1027
+ reasoningOutputPer1m: 12
1028
+ },
1029
+ {
1030
+ inputPer1m: 4,
1031
+ outputPer1m: 18,
1032
+ cachedInputPer1m: 0.4,
1033
+ reasoningOutputPer1m: 18
1034
+ }
1035
+ ],
1036
+ batchMultiplier: 0.5,
1037
+ contextWindow: 1048576
1038
+ },
1039
+ {
1040
+ model: "gemini-3.6-flash",
1041
+ provider: "gemini",
1042
+ modality: "text",
1043
+ currency: "USD",
1044
+ asOf: "2026-07-27",
1045
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1046
+ provenance: "vendor-pricing-page",
1047
+ tiers: [
1048
+ {
1049
+ inputPer1m: 1.5,
1050
+ outputPer1m: 7.5,
1051
+ cachedInputPer1m: 0.15,
1052
+ reasoningOutputPer1m: 7.5
1053
+ }
1054
+ ],
1055
+ batchMultiplier: 0.5,
1056
+ contextWindow: 1048576,
1057
+ notes: "Released 2026-07-21. Output pricing dropped ~17% from Gemini 3.5 Flash ($9.00 -> $7.50 per 1M); input unchanged."
1058
+ },
1059
+ {
1060
+ model: "gemini-3.5-flash",
1061
+ provider: "gemini",
1062
+ modality: "text",
1063
+ currency: "USD",
1064
+ asOf: "2026-07-27",
1065
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1066
+ provenance: "vendor-pricing-page",
1067
+ tiers: [
1068
+ {
1069
+ inputPer1m: 1.5,
1070
+ outputPer1m: 9,
1071
+ cachedInputPer1m: 0.15,
1072
+ reasoningOutputPer1m: 9
1073
+ }
1074
+ ],
1075
+ batchMultiplier: 0.5,
1076
+ contextWindow: 1048576
1077
+ },
1078
+ {
1079
+ model: "gemini-3.5-flash-lite",
1080
+ provider: "gemini",
1081
+ modality: "text",
1082
+ currency: "USD",
1083
+ asOf: "2026-07-27",
1084
+ source: "https://ai.google.dev/gemini-api/docs/pricing",
1085
+ provenance: "litellm-catalog",
1086
+ tiers: [
1087
+ {
1088
+ inputPer1m: 0.3,
1089
+ outputPer1m: 2.5,
1090
+ cachedInputPer1m: 0.03,
1091
+ reasoningOutputPer1m: 2.5
1092
+ }
1093
+ ],
1094
+ batchMultiplier: 0.5,
1095
+ contextWindow: 1048576
1096
+ },
1097
+ {
1098
+ model: "gemini-3.1-flash-lite",
1099
+ provider: "gemini",
1100
+ modality: "text",
1101
+ currency: "USD",
1102
+ asOf: "2026-07-27",
1103
+ source: "https://ai.google.dev/gemini-api/docs/pricing#gemini-3.1-flash-lite",
1104
+ provenance: "litellm-catalog",
1105
+ tiers: [
1106
+ {
1107
+ inputPer1m: 0.25,
1108
+ outputPer1m: 1.5,
1109
+ cachedInputPer1m: 0.025,
1110
+ reasoningOutputPer1m: 1.5
1111
+ }
1112
+ ],
1113
+ batchMultiplier: 0.5,
1114
+ contextWindow: 1048576
1115
+ },
1116
+ {
1117
+ model: "gemini-3-flash",
1118
+ provider: "gemini",
1119
+ aliases: [
1120
+ "gemini-3-flash-preview"
1121
+ ],
1122
+ modality: "text",
1123
+ currency: "USD",
1124
+ asOf: "2026-07-27",
1125
+ source: "https://ai.google.dev/pricing/gemini-3",
1126
+ provenance: "litellm-catalog",
1127
+ tiers: [
1128
+ {
1129
+ inputPer1m: 0.5,
1130
+ outputPer1m: 3,
1131
+ cachedInputPer1m: 0.05,
1132
+ reasoningOutputPer1m: 3
1133
+ }
1134
+ ],
1135
+ contextWindow: 1048576
1136
+ },
1137
+ {
1138
+ model: "gemini-2.5-pro",
1139
+ provider: "gemini",
1140
+ modality: "text",
1141
+ currency: "USD",
1142
+ asOf: "2026-07-27",
1143
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1144
+ provenance: "litellm-catalog",
1145
+ tiers: [
1146
+ {
1147
+ maxInputTokens: 2e5,
1148
+ inputPer1m: 1.25,
1149
+ outputPer1m: 10,
1150
+ cachedInputPer1m: 0.125
1151
+ },
1152
+ {
1153
+ inputPer1m: 2.5,
1154
+ outputPer1m: 15,
1155
+ cachedInputPer1m: 0.25
1156
+ }
1157
+ ],
1158
+ contextWindow: 1048576
1159
+ },
1160
+ {
1161
+ model: "gemini-2.5-flash",
1162
+ provider: "gemini",
1163
+ modality: "text",
1164
+ currency: "USD",
1165
+ asOf: "2026-07-27",
1166
+ source: "https://ai.google.dev/gemini-api/docs/models#gemini-2.5-flash-preview",
1167
+ provenance: "litellm-catalog",
1168
+ tiers: [
1169
+ {
1170
+ inputPer1m: 0.3,
1171
+ outputPer1m: 2.5,
1172
+ cachedInputPer1m: 0.03,
1173
+ reasoningOutputPer1m: 2.5
1174
+ }
1175
+ ],
1176
+ contextWindow: 1048576
1177
+ },
1178
+ {
1179
+ model: "gemini-2.5-flash-lite",
1180
+ provider: "gemini",
1181
+ modality: "text",
1182
+ currency: "USD",
1183
+ asOf: "2026-07-27",
1184
+ source: "https://ai.google.dev/gemini-api/docs/models#gemini-2.5-flash-lite",
1185
+ provenance: "litellm-catalog",
1186
+ tiers: [
1187
+ {
1188
+ inputPer1m: 0.1,
1189
+ outputPer1m: 0.4,
1190
+ cachedInputPer1m: 0.01,
1191
+ reasoningOutputPer1m: 0.4
1192
+ }
1193
+ ],
1194
+ contextWindow: 1048576
1195
+ },
1196
+ {
1197
+ model: "gemini-2.0-flash",
1198
+ provider: "gemini",
1199
+ modality: "text",
1200
+ currency: "USD",
1201
+ asOf: "2026-07-27",
1202
+ source: "https://ai.google.dev/pricing#2_0flash",
1203
+ provenance: "litellm-catalog",
1204
+ tiers: [
1205
+ {
1206
+ inputPer1m: 0.1,
1207
+ outputPer1m: 0.4,
1208
+ cachedInputPer1m: 0.025
1209
+ }
1210
+ ],
1211
+ contextWindow: 1048576,
1212
+ notes: "Gemini Developer API price. Vertex AI lists $0.15/$0.60 per 1M for the same model \u2014 see the vertex entry."
1213
+ },
1214
+ {
1215
+ model: "gemini-2.0-flash-lite",
1216
+ provider: "gemini",
1217
+ modality: "text",
1218
+ currency: "USD",
1219
+ asOf: "2026-07-27",
1220
+ source: "https://ai.google.dev/gemini-api/docs/pricing#gemini-2.0-flash-lite",
1221
+ provenance: "litellm-catalog",
1222
+ tiers: [
1223
+ {
1224
+ inputPer1m: 0.075,
1225
+ outputPer1m: 0.3,
1226
+ cachedInputPer1m: 0.01875
1227
+ }
1228
+ ],
1229
+ contextWindow: 1048576
1230
+ },
1231
+ {
1232
+ model: "gemini-2.0-flash",
1233
+ provider: "vertex",
1234
+ modality: "text",
1235
+ currency: "USD",
1236
+ asOf: "2026-07-27",
1237
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1238
+ provenance: "vendor-pricing-page",
1239
+ tiers: [
1240
+ {
1241
+ inputPer1m: 0.15,
1242
+ outputPer1m: 0.6
1243
+ }
1244
+ ],
1245
+ batchMultiplier: 0.5,
1246
+ notes: "Vertex AI lists $0.15/$0.60 per 1M; the Gemini Developer API lists $0.10/$0.40 for the same model."
1247
+ },
1248
+ {
1249
+ model: "gemini-3.1-pro",
1250
+ provider: "vertex",
1251
+ aliases: [
1252
+ "gemini-3.1-pro-preview"
1253
+ ],
1254
+ modality: "text",
1255
+ currency: "USD",
1256
+ asOf: "2026-07-27",
1257
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1258
+ provenance: "vendor-pricing-page",
1259
+ tiers: [
1260
+ {
1261
+ maxInputTokens: 2e5,
1262
+ inputPer1m: 2,
1263
+ outputPer1m: 12,
1264
+ cachedInputPer1m: 0.2,
1265
+ reasoningOutputPer1m: 12
1266
+ },
1267
+ {
1268
+ inputPer1m: 4,
1269
+ outputPer1m: 18,
1270
+ cachedInputPer1m: 0.4,
1271
+ reasoningOutputPer1m: 18
1272
+ }
1273
+ ],
1274
+ batchMultiplier: 0.5,
1275
+ contextWindow: 1048576
1276
+ },
1277
+ {
1278
+ model: "gemini-3.6-flash",
1279
+ provider: "vertex",
1280
+ modality: "text",
1281
+ currency: "USD",
1282
+ asOf: "2026-07-27",
1283
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1284
+ provenance: "vendor-pricing-page",
1285
+ tiers: [
1286
+ {
1287
+ inputPer1m: 1.5,
1288
+ outputPer1m: 7.5,
1289
+ cachedInputPer1m: 0.15,
1290
+ reasoningOutputPer1m: 7.5
1291
+ }
1292
+ ],
1293
+ batchMultiplier: 0.5,
1294
+ contextWindow: 1048576
1295
+ },
1296
+ {
1297
+ model: "gemini-2.5-pro",
1298
+ provider: "vertex",
1299
+ modality: "text",
1300
+ currency: "USD",
1301
+ asOf: "2026-07-27",
1302
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1303
+ provenance: "vendor-pricing-page",
1304
+ tiers: [
1305
+ {
1306
+ maxInputTokens: 2e5,
1307
+ inputPer1m: 1.25,
1308
+ outputPer1m: 10,
1309
+ cachedInputPer1m: 0.13
1310
+ },
1311
+ {
1312
+ inputPer1m: 2.5,
1313
+ outputPer1m: 15,
1314
+ cachedInputPer1m: 0.25
1315
+ }
1316
+ ],
1317
+ batchMultiplier: 0.5,
1318
+ contextWindow: 1048576
1319
+ },
1320
+ {
1321
+ model: "gemini-2.5-flash",
1322
+ provider: "vertex",
1323
+ modality: "text",
1324
+ currency: "USD",
1325
+ asOf: "2026-07-27",
1326
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1327
+ provenance: "vendor-pricing-page",
1328
+ tiers: [
1329
+ {
1330
+ inputPer1m: 0.3,
1331
+ outputPer1m: 2.5,
1332
+ cachedInputPer1m: 0.03,
1333
+ reasoningOutputPer1m: 2.5
1334
+ }
1335
+ ],
1336
+ batchMultiplier: 0.5,
1337
+ contextWindow: 1048576
1338
+ },
1339
+ {
1340
+ model: "claude-sonnet-4-6",
1341
+ provider: "openrouter",
1342
+ modality: "text",
1343
+ currency: "USD",
1344
+ asOf: "2026-07-27",
1345
+ source: "https://openrouter.ai/anthropic/claude-sonnet-4.6",
1346
+ provenance: "litellm-catalog",
1347
+ tiers: [
1348
+ {
1349
+ maxInputTokens: 2e5,
1350
+ inputPer1m: 3,
1351
+ outputPer1m: 15,
1352
+ cachedInputPer1m: 0.3,
1353
+ cacheWritePer1m: 3.75
1354
+ },
1355
+ {
1356
+ inputPer1m: 6,
1357
+ outputPer1m: 22.5,
1358
+ cachedInputPer1m: 0.6,
1359
+ cacheWritePer1m: 7.5
1360
+ }
1361
+ ],
1362
+ contextWindow: 1e6
1363
+ },
1364
+ {
1365
+ model: "claude-haiku-4-5",
1366
+ provider: "openrouter",
1367
+ modality: "text",
1368
+ currency: "USD",
1369
+ asOf: "2026-07-27",
1370
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1371
+ provenance: "litellm-catalog",
1372
+ tiers: [
1373
+ {
1374
+ inputPer1m: 1,
1375
+ outputPer1m: 5,
1376
+ cachedInputPer1m: 0.1,
1377
+ cacheWritePer1m: 1.25
1378
+ }
1379
+ ],
1380
+ contextWindow: 2e5
1381
+ },
1382
+ {
1383
+ model: "gpt-5",
1384
+ provider: "openrouter",
1385
+ modality: "text",
1386
+ currency: "USD",
1387
+ asOf: "2026-07-27",
1388
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1389
+ provenance: "litellm-catalog",
1390
+ tiers: [
1391
+ {
1392
+ inputPer1m: 1.25,
1393
+ outputPer1m: 10,
1394
+ cachedInputPer1m: 0.125
1395
+ }
1396
+ ],
1397
+ contextWindow: 272e3
1398
+ },
1399
+ {
1400
+ model: "gpt-5-mini",
1401
+ provider: "openrouter",
1402
+ modality: "text",
1403
+ currency: "USD",
1404
+ asOf: "2026-07-27",
1405
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1406
+ provenance: "litellm-catalog",
1407
+ tiers: [
1408
+ {
1409
+ inputPer1m: 0.25,
1410
+ outputPer1m: 2,
1411
+ cachedInputPer1m: 0.025
1412
+ }
1413
+ ],
1414
+ contextWindow: 272e3
1415
+ },
1416
+ {
1417
+ model: "gemini-3.1-pro",
1418
+ provider: "openrouter",
1419
+ aliases: [
1420
+ "gemini-3.1-pro-preview"
1421
+ ],
1422
+ modality: "text",
1423
+ currency: "USD",
1424
+ asOf: "2026-07-27",
1425
+ source: "https://openrouter.ai/google/gemini-3.1-pro-preview",
1426
+ provenance: "litellm-catalog",
1427
+ tiers: [
1428
+ {
1429
+ maxInputTokens: 2e5,
1430
+ inputPer1m: 2,
1431
+ outputPer1m: 12,
1432
+ cachedInputPer1m: 0.2
1433
+ },
1434
+ {
1435
+ inputPer1m: 4,
1436
+ outputPer1m: 18,
1437
+ cachedInputPer1m: 0.4,
1438
+ cacheWritePer1m: 0.25
1439
+ }
1440
+ ],
1441
+ contextWindow: 1048576
1442
+ },
1443
+ {
1444
+ model: "text-embedding-3-small",
1445
+ provider: "openai",
1446
+ modality: "embedding",
1447
+ currency: "USD",
1448
+ asOf: "2026-07-27",
1449
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1450
+ provenance: "litellm-catalog",
1451
+ tiers: [
1452
+ {
1453
+ inputPer1m: 0.02,
1454
+ outputPer1m: 0
1455
+ }
1456
+ ],
1457
+ batchMultiplier: 0.5,
1458
+ contextWindow: 8191
1459
+ },
1460
+ {
1461
+ model: "text-embedding-3-large",
1462
+ provider: "openai",
1463
+ modality: "embedding",
1464
+ currency: "USD",
1465
+ asOf: "2026-07-27",
1466
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1467
+ provenance: "litellm-catalog",
1468
+ tiers: [
1469
+ {
1470
+ inputPer1m: 0.13,
1471
+ outputPer1m: 0
1472
+ }
1473
+ ],
1474
+ batchMultiplier: 0.5,
1475
+ contextWindow: 8191
1476
+ },
1477
+ {
1478
+ model: "gemini-embedding-001",
1479
+ provider: "gemini",
1480
+ modality: "embedding",
1481
+ currency: "USD",
1482
+ asOf: "2026-07-27",
1483
+ source: "https://ai.google.dev/gemini-api/docs/embeddings#model-versions",
1484
+ provenance: "litellm-catalog",
1485
+ tiers: [
1486
+ {
1487
+ inputPer1m: 0.15,
1488
+ outputPer1m: 0
1489
+ }
1490
+ ],
1491
+ contextWindow: 2048
1492
+ },
1493
+ {
1494
+ model: "dall-e-3",
1495
+ provider: "openai",
1496
+ modality: "image",
1497
+ currency: "USD",
1498
+ asOf: "2026-07-27",
1499
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1500
+ provenance: "litellm-catalog",
1501
+ rates: [
1502
+ {
1503
+ unit: "per_image",
1504
+ amount: 0.04,
1505
+ variant: "1024x1024 standard"
1506
+ }
1507
+ ]
1508
+ },
1509
+ {
1510
+ model: "gemini-3-pro-image",
1511
+ provider: "gemini",
1512
+ modality: "image",
1513
+ currency: "USD",
1514
+ asOf: "2026-07-27",
1515
+ source: "https://ai.google.dev/gemini-api/docs/pricing",
1516
+ provenance: "litellm-catalog",
1517
+ rates: [
1518
+ {
1519
+ unit: "per_image",
1520
+ amount: 0.134,
1521
+ variant: "default output resolution"
1522
+ }
1523
+ ],
1524
+ 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."
1525
+ },
1526
+ {
1527
+ model: "imagen-4.0-generate-001",
1528
+ provider: "vertex",
1529
+ modality: "image",
1530
+ currency: "USD",
1531
+ asOf: "2026-07-27",
1532
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1533
+ provenance: "litellm-catalog",
1534
+ rates: [
1535
+ {
1536
+ unit: "per_image",
1537
+ amount: 0.04
1538
+ }
1539
+ ]
1540
+ },
1541
+ {
1542
+ model: "veo-3.1-generate-001",
1543
+ provider: "gemini",
1544
+ modality: "video",
1545
+ currency: "USD",
1546
+ asOf: "2026-07-27",
1547
+ source: "https://ai.google.dev/gemini-api/docs/video",
1548
+ provenance: "litellm-catalog",
1549
+ rates: [
1550
+ {
1551
+ unit: "per_second",
1552
+ amount: 0.4
1553
+ }
1554
+ ]
1555
+ },
1556
+ {
1557
+ model: "veo-3.1-generate-001",
1558
+ provider: "vertex",
1559
+ modality: "video",
1560
+ currency: "USD",
1561
+ asOf: "2026-07-27",
1562
+ source: "https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/veo",
1563
+ provenance: "litellm-catalog",
1564
+ rates: [
1565
+ {
1566
+ unit: "per_second",
1567
+ amount: 0.4
1568
+ }
1569
+ ]
1570
+ },
1571
+ {
1572
+ model: "tts-1",
1573
+ provider: "openai",
1574
+ modality: "speech",
1575
+ currency: "USD",
1576
+ asOf: "2026-07-27",
1577
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1578
+ provenance: "litellm-catalog",
1579
+ rates: [
1580
+ {
1581
+ unit: "per_character",
1582
+ amount: 15e-6
1583
+ }
1584
+ ],
1585
+ notes: "$15 per 1M characters."
1586
+ },
1587
+ {
1588
+ model: "tts-1-hd",
1589
+ provider: "openai",
1590
+ modality: "speech",
1591
+ currency: "USD",
1592
+ asOf: "2026-07-27",
1593
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1594
+ provenance: "litellm-catalog",
1595
+ rates: [
1596
+ {
1597
+ unit: "per_character",
1598
+ amount: 3e-5
1599
+ }
1600
+ ],
1601
+ notes: "$30 per 1M characters."
1602
+ },
1603
+ {
1604
+ model: "whisper-1",
1605
+ provider: "openai",
1606
+ modality: "transcription",
1607
+ currency: "USD",
1608
+ asOf: "2026-07-27",
1609
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1610
+ provenance: "litellm-catalog",
1611
+ rates: [
1612
+ {
1613
+ unit: "per_audio_minute",
1614
+ amount: 6e-3
1615
+ }
1616
+ ],
1617
+ notes: "litellm records $0.0001 per audio second; $0.006/minute is that rate x 60."
1618
+ }
1619
+ ]
1620
+ };
1621
+ }
1622
+ });
1623
+
1624
+ // src/core/router/pricing.ts
1625
+ function normalizeForPricing(id) {
1626
+ let s = id.trim().toLowerCase();
1627
+ s = s.replace(/^models\//, "");
1628
+ const slash = s.lastIndexOf("/");
1629
+ if (slash !== -1) s = s.slice(slash + 1);
1630
+ const tag = s.search(/[:@]/);
1631
+ if (tag !== -1) s = s.slice(0, tag);
1632
+ s = s.replace(/-latest$/, "");
1633
+ s = s.replace(/-preview(?:-\d{2}-\d{2})?$/, "");
1634
+ s = s.replace(/-\d{4}-\d{2}-\d{2}$/, "");
1635
+ s = s.replace(/-\d{8}$/, "");
1636
+ s = s.replace(/-preview$/, "");
1637
+ return s;
1638
+ }
1639
+ function indexKey(model, provider, region) {
1640
+ return `${provider}|${normalizeForPricing(model)}|${region ?? ""}`;
1641
+ }
1642
+ function findPricing(modelId, provider, opts = {}) {
1643
+ const ids = [modelId, opts.baseModelId].filter((x) => !!x);
1644
+ const providers = [provider, ...opts.fallbackProviders ?? []];
1645
+ for (const p of providers) {
1646
+ for (const id of ids) {
1647
+ const hit = (opts.region ? INDEX.get(indexKey(id, p, opts.region)) : void 0) ?? INDEX.get(indexKey(id, p));
1648
+ if (hit) return { entry: hit, matchedProvider: p, viaFallback: p !== provider };
1649
+ }
1650
+ }
1651
+ return null;
1652
+ }
1653
+ function pricingDatasetMeta() {
1654
+ const { schemaVersion, generatedAt, defaultCurrency } = DATASET;
1655
+ return { schemaVersion, generatedAt, defaultCurrency };
1656
+ }
1657
+ function tierFor(entry, inputTokens = 0) {
1658
+ const tiers = entry.tiers;
1659
+ if (!tiers?.length) return null;
1660
+ for (const t of tiers) {
1661
+ if (t.maxInputTokens === void 0 || inputTokens <= t.maxInputTokens) return t;
1662
+ }
1663
+ return tiers[tiers.length - 1] ?? null;
1664
+ }
1665
+ function tokenRatesPer1k(entry, opts = {}) {
1666
+ const tier = tierFor(entry, opts.inputTokens ?? 0);
1667
+ if (!tier) return null;
1668
+ const mult = (opts.batch ? entry.batchMultiplier ?? 1 : 1) * PER_1M_TO_PER_1K;
1669
+ const out = {
1670
+ input: tier.inputPer1m * mult,
1671
+ output: tier.outputPer1m * mult
1672
+ };
1673
+ if (tier.cachedInputPer1m !== void 0) out.cachedInput = tier.cachedInputPer1m * mult;
1674
+ if (tier.cacheWritePer1m !== void 0) out.cacheWrite = tier.cacheWritePer1m * mult;
1675
+ if (tier.reasoningOutputPer1m !== void 0) out.reasoningOutput = tier.reasoningOutputPer1m * mult;
1676
+ return out;
1677
+ }
1678
+ function isLoopbackOrPrivateHost(url) {
1679
+ if (!url) return false;
1680
+ try {
1681
+ const host = new URL(url).hostname.toLowerCase().replace(/^\[|\]$/g, "");
1682
+ if (LOOPBACK_HOSTS.has(host) || LOOPBACK_HOSTS.has(`[${host}]`)) return true;
1683
+ if (host.endsWith(".local")) return true;
1684
+ if (/^127\./.test(host)) return true;
1685
+ if (/^10\./.test(host)) return true;
1686
+ if (/^192\.168\./.test(host)) return true;
1687
+ if (/^172\.(1[6-9]|2\d|3[01])\./.test(host)) return true;
1688
+ return false;
1689
+ } catch {
1690
+ return false;
1691
+ }
1692
+ }
1693
+ function isLocalEndpoint(cfg) {
1694
+ if (typeof cfg.local === "boolean") return cfg.local;
1695
+ if (cfg.type === "ollama") return true;
1696
+ if (cfg.type === "openai-compatible") return isLoopbackOrPrivateHost(cfg.baseUrl);
1697
+ return false;
1698
+ }
1699
+ function resolvePricing(model, opts = {}) {
1700
+ if (model.isLocal) return FREE;
1701
+ const fallbackProviders = model.provider === "azure" ? ["openai"] : model.provider === "gemini" ? ["vertex"] : [];
1702
+ const match = findPricing(model.id, model.provider, {
1703
+ region: opts.region,
1704
+ baseModelId: model.baseModelId,
1705
+ fallbackProviders
1706
+ });
1707
+ if (!match) return UNKNOWN;
1708
+ const rates = tokenRatesPer1k(match.entry, { inputTokens: opts.inputTokens, batch: opts.batch });
1709
+ if (!rates) return UNKNOWN;
1710
+ return {
1711
+ input: rates.input,
1712
+ output: rates.output,
1713
+ unknown: false,
1714
+ free: false,
1715
+ entry: match.entry,
1716
+ ...match.viaFallback ? { estimatedFromProvider: match.matchedProvider } : {}
1717
+ };
1718
+ }
1719
+ function withResolvedPricing(model, opts = {}) {
1720
+ const p = resolvePricing(model, opts);
1721
+ return {
1722
+ ...model,
1723
+ inputCostPer1kTokens: p.input,
1724
+ outputCostPer1kTokens: p.output,
1725
+ ...p.unknown ? { pricingUnknown: true } : { pricingUnknown: false }
1726
+ };
1727
+ }
1728
+ function isPricingUnknown(model) {
1729
+ return model.pricingUnknown === true && !model.isLocal;
1730
+ }
1731
+ function blendedCostPer1k(model) {
1732
+ if (isPricingUnknown(model)) return BLENDED_COST_CEILING;
1733
+ return model.inputCostPer1kTokens + model.outputCostPer1kTokens * 2;
1734
+ }
1735
+ function reconcilePrice(model, live) {
1736
+ const baseline = resolvePricing(model);
1737
+ const liveIsZero = !(live.input > 0) && !(live.output > 0);
1738
+ if (liveIsZero && !model.isLocal) {
1739
+ return { input: baseline.input, output: baseline.output, accepted: false };
1740
+ }
1741
+ if (baseline.unknown || !baseline.entry) {
1742
+ return { input: live.input, output: live.output, accepted: true };
1743
+ }
1744
+ const dsBlend = baseline.input + baseline.output * 2;
1745
+ const liveBlend = live.input + live.output * 2;
1746
+ const ratio = dsBlend > 0 ? liveBlend / dsBlend : Number.POSITIVE_INFINITY;
1747
+ const material = dsBlend > 0 && Math.abs(ratio - 1) > DISAGREEMENT_THRESHOLD;
1748
+ return {
1749
+ input: live.input,
1750
+ output: live.output,
1751
+ accepted: true,
1752
+ ...material ? {
1753
+ disagreement: {
1754
+ modelId: model.id,
1755
+ provider: model.provider,
1756
+ dataset: { input: baseline.input, output: baseline.output },
1757
+ live: { input: live.input, output: live.output },
1758
+ ratio: Math.round(ratio * 1e3) / 1e3,
1759
+ datasetAsOf: baseline.entry.asOf,
1760
+ datasetSource: baseline.entry.source
1761
+ }
1762
+ } : {}
1763
+ };
1764
+ }
1765
+ var DATASET, INDEX, PER_1M_TO_PER_1K, LOOPBACK_HOSTS, UNKNOWN, FREE, BLENDED_COST_CEILING, DISAGREEMENT_THRESHOLD;
1766
+ var init_pricing = __esm({
1767
+ "src/core/router/pricing.ts"() {
1768
+ init_pricing_data();
1769
+ DATASET = pricing_data_default;
1770
+ INDEX = /* @__PURE__ */ new Map();
1771
+ for (const entry of DATASET.entries) {
1772
+ for (const name of [entry.model, ...entry.aliases ?? []]) {
1773
+ const withRegion = indexKey(name, entry.provider, entry.region);
1774
+ if (!INDEX.has(withRegion)) INDEX.set(withRegion, entry);
1775
+ const bare = indexKey(name, entry.provider);
1776
+ const existing = INDEX.get(bare);
1777
+ if (!existing || existing.region && existing.region !== "global" && entry.region === "global") {
1778
+ INDEX.set(bare, entry);
1779
+ }
1780
+ }
1781
+ }
1782
+ PER_1M_TO_PER_1K = 1 / 1e3;
1783
+ LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "0.0.0.0", "::1", "[::1]"]);
1784
+ UNKNOWN = { input: 0, output: 0, unknown: true, free: false };
1785
+ FREE = { input: 0, output: 0, unknown: false, free: true };
1786
+ BLENDED_COST_CEILING = 0.05;
1787
+ DISAGREEMENT_THRESHOLD = 0.02;
1788
+ }
1789
+ });
1790
+
115
1791
  // src/constants.ts
116
1792
  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;
117
1793
  var init_constants = __esm({
118
1794
  "src/constants.ts"() {
119
- CASCADE_VERSION = "0.48.0";
1795
+ init_pricing();
1796
+ CASCADE_VERSION = "0.49.0";
120
1797
  CASCADE_CONFIG_FILE = ".cascade/config.json";
121
1798
  CASCADE_DB_FILE = ".cascade/memory.db";
122
1799
  CASCADE_DASHBOARD_SECRET_FILE = ".cascade/dashboard-secret";
@@ -457,6 +2134,13 @@ var init_constants = __esm({
457
2134
  for (const _m of Object.values(MODELS)) {
458
2135
  if (_m.supportsToolUse === void 0) _m.supportsToolUse = !_m.isLocal;
459
2136
  }
2137
+ for (const _m of Object.values(MODELS)) {
2138
+ const priced = resolvePricing(_m);
2139
+ if (priced.unknown || priced.free || priced.estimatedFromProvider) continue;
2140
+ _m.inputCostPer1kTokens = priced.input;
2141
+ _m.outputCostPer1kTokens = priced.output;
2142
+ _m.pricingUnknown = false;
2143
+ }
460
2144
  T1_MODEL_PRIORITY = [
461
2145
  "gpt-5.5",
462
2146
  "gpt-5.4",
@@ -541,24 +2225,53 @@ var init_constants = __esm({
541
2225
 
542
2226
  // src/utils/cost.ts
543
2227
  function resolveModelPricing(model) {
544
- let input = model.inputCostPer1kTokens;
545
- let output = model.outputCostPer1kTokens;
546
- if (input === 0 && output === 0 && model.id && !model.isLocal) {
2228
+ if (model.isLocal) return { input: 0, output: 0, unknown: false };
2229
+ if (model.inputCostPer1kTokens > 0 || model.outputCostPer1kTokens > 0) {
2230
+ return {
2231
+ input: model.inputCostPer1kTokens,
2232
+ output: model.outputCostPer1kTokens,
2233
+ unknown: false
2234
+ };
2235
+ }
2236
+ const fromDataset = resolvePricing(model);
2237
+ if (!fromDataset.unknown) {
2238
+ return {
2239
+ input: fromDataset.input,
2240
+ output: fromDataset.output,
2241
+ unknown: false,
2242
+ ...fromDataset.estimatedFromProvider ? { estimatedFromProvider: fromDataset.estimatedFromProvider } : {}
2243
+ };
2244
+ }
2245
+ if (model.id) {
547
2246
  const known = Object.values(MODELS).find((m) => m.id === model.id && !m.isLocal);
548
- if (known) {
549
- input = known.inputCostPer1kTokens;
550
- output = known.outputCostPer1kTokens;
2247
+ if (known && (known.inputCostPer1kTokens > 0 || known.outputCostPer1kTokens > 0)) {
2248
+ return {
2249
+ input: known.inputCostPer1kTokens,
2250
+ output: known.outputCostPer1kTokens,
2251
+ unknown: false
2252
+ };
551
2253
  }
552
2254
  }
553
- return { input, output };
2255
+ return { input: 0, output: 0, unknown: true };
554
2256
  }
555
2257
  function calculateCost(inputTokens, outputTokens, model) {
556
2258
  const { input, output } = resolveModelPricing(model);
557
2259
  return inputTokens / 1e3 * input + outputTokens / 1e3 * output;
558
2260
  }
2261
+ function buildTokenUsage(inputTokens, outputTokens, model) {
2262
+ const { input, output, unknown } = resolveModelPricing(model);
2263
+ return {
2264
+ inputTokens,
2265
+ outputTokens,
2266
+ totalTokens: inputTokens + outputTokens,
2267
+ estimatedCostUsd: inputTokens / 1e3 * input + outputTokens / 1e3 * output,
2268
+ ...unknown ? { costUnknown: true } : {}
2269
+ };
2270
+ }
559
2271
  var init_cost = __esm({
560
2272
  "src/utils/cost.ts"() {
561
2273
  init_constants();
2274
+ init_pricing();
562
2275
  }
563
2276
  });
564
2277
 
@@ -584,12 +2297,7 @@ var init_base = __esm({
584
2297
  return calculateCost(inputTokens, outputTokens, this.model);
585
2298
  }
586
2299
  makeUsage(inputTokens, outputTokens) {
587
- return {
588
- inputTokens,
589
- outputTokens,
590
- totalTokens: inputTokens + outputTokens,
591
- estimatedCostUsd: this.estimateCost(inputTokens, outputTokens)
592
- };
2300
+ return buildTokenUsage(inputTokens, outputTokens, this.model);
593
2301
  }
594
2302
  };
595
2303
  }
@@ -665,6 +2373,7 @@ var init_anthropic = __esm({
665
2373
  "src/providers/anthropic.ts"() {
666
2374
  init_constants();
667
2375
  init_base();
2376
+ init_pricing();
668
2377
  init_model_filter();
669
2378
  AnthropicProvider = class extends BaseProvider {
670
2379
  client;
@@ -775,7 +2484,7 @@ var init_anthropic = __esm({
775
2484
  return data.data.filter((m) => isChatModel(m.id)).map((m) => {
776
2485
  const known = Object.values(MODELS).find((km) => km.id === m.id && km.provider === "anthropic");
777
2486
  if (known) return known;
778
- return {
2487
+ return withResolvedPricing({
779
2488
  id: m.id,
780
2489
  name: m.display_name || m.id,
781
2490
  provider: "anthropic",
@@ -786,7 +2495,7 @@ var init_anthropic = __esm({
786
2495
  maxOutputTokens: 8e3,
787
2496
  supportsStreaming: true,
788
2497
  isLocal: false
789
- };
2498
+ });
790
2499
  });
791
2500
  } catch {
792
2501
  return Object.values(MODELS).filter((m) => m.provider === "anthropic");
@@ -881,6 +2590,7 @@ var init_openai = __esm({
881
2590
  "src/providers/openai.ts"() {
882
2591
  init_constants();
883
2592
  init_base();
2593
+ init_pricing();
884
2594
  init_model_filter();
885
2595
  OpenAIProvider = class extends BaseProvider {
886
2596
  client;
@@ -1006,7 +2716,7 @@ var init_openai = __esm({
1006
2716
  return response.data.filter((m) => isChatModel(m.id)).map((m) => {
1007
2717
  const known = Object.values(MODELS).find((km) => km.id === m.id && km.provider === "openai");
1008
2718
  if (known) return known;
1009
- return {
2719
+ return withResolvedPricing({
1010
2720
  id: m.id,
1011
2721
  name: m.id,
1012
2722
  provider: "openai",
@@ -1017,7 +2727,7 @@ var init_openai = __esm({
1017
2727
  maxOutputTokens: 4e3,
1018
2728
  supportsStreaming: true,
1019
2729
  isLocal: false
1020
- };
2730
+ });
1021
2731
  });
1022
2732
  } catch {
1023
2733
  return Object.values(MODELS).filter((m) => m.provider === "openai");
@@ -1120,6 +2830,10 @@ function azureModelForDeployment(cfg) {
1120
2830
  const baseModelId = cfg.model?.trim() || inferAzureBaseModel(id) || void 0;
1121
2831
  const base = baseModelId ? MODELS[baseModelId] : void 0;
1122
2832
  if (base) {
2833
+ const azurePrice = resolvePricing(
2834
+ { id, provider: "azure", isLocal: false, baseModelId },
2835
+ { region: cfg.region }
2836
+ );
1123
2837
  return {
1124
2838
  ...base,
1125
2839
  id,
@@ -1128,7 +2842,12 @@ function azureModelForDeployment(cfg) {
1128
2842
  provider: "azure",
1129
2843
  baseModelId,
1130
2844
  // real identity for benchmark + live pricing
1131
- supportsToolUse: base.supportsToolUse ?? true
2845
+ supportsToolUse: base.supportsToolUse ?? true,
2846
+ ...azurePrice.unknown ? {} : {
2847
+ inputCostPer1kTokens: azurePrice.input,
2848
+ outputCostPer1kTokens: azurePrice.output,
2849
+ pricingUnknown: false
2850
+ }
1132
2851
  };
1133
2852
  }
1134
2853
  return {
@@ -1151,6 +2870,7 @@ var init_azure = __esm({
1151
2870
  "src/providers/azure.ts"() {
1152
2871
  init_constants();
1153
2872
  init_openai();
2873
+ init_pricing();
1154
2874
  DEFAULT_AZURE_API_VERSION = "2024-12-01-preview";
1155
2875
  AzureOpenAIProvider = class extends OpenAIProvider {
1156
2876
  constructor(config, model) {
@@ -1211,6 +2931,7 @@ var init_gemini = __esm({
1211
2931
  "src/providers/gemini.ts"() {
1212
2932
  init_constants();
1213
2933
  init_base();
2934
+ init_pricing();
1214
2935
  init_model_filter();
1215
2936
  GeminiProvider = class extends BaseProvider {
1216
2937
  client;
@@ -1311,7 +3032,7 @@ var init_gemini = __esm({
1311
3032
  (km) => km.id === id && km.provider === "gemini"
1312
3033
  );
1313
3034
  if (known) return known;
1314
- return {
3035
+ return withResolvedPricing({
1315
3036
  id,
1316
3037
  name: m.displayName || id,
1317
3038
  provider: "gemini",
@@ -1322,7 +3043,7 @@ var init_gemini = __esm({
1322
3043
  maxOutputTokens: m.outputTokenLimit || 8e3,
1323
3044
  supportsStreaming: true,
1324
3045
  isLocal: false
1325
- };
3046
+ });
1326
3047
  });
1327
3048
  } catch {
1328
3049
  return Object.values(MODELS).filter((m) => m.provider === "gemini");
@@ -1528,6 +3249,7 @@ var init_ollama = __esm({
1528
3249
  init_constants();
1529
3250
  init_net();
1530
3251
  init_base();
3252
+ init_pricing();
1531
3253
  init_model_filter();
1532
3254
  TOOL_CAPABLE_FAMILIES = [
1533
3255
  "llama3.1",
@@ -1687,9 +3409,10 @@ var init_ollama = __esm({
1687
3409
  return supportedKeywords.some((k) => name.includes(k)) && isChatModel(name);
1688
3410
  });
1689
3411
  const shows = await Promise.all(entries.map((m) => this.showModel(m.name)));
3412
+ const local = isLocalEndpoint({ ...this.config, type: "ollama" });
1690
3413
  return entries.map((m, i) => {
1691
3414
  const show = shows[i];
1692
- return {
3415
+ return withResolvedPricing({
1693
3416
  id: m.name,
1694
3417
  name: m.name,
1695
3418
  provider: "ollama",
@@ -1699,10 +3422,10 @@ var init_ollama = __esm({
1699
3422
  outputCostPer1kTokens: 0,
1700
3423
  maxOutputTokens: 4e3,
1701
3424
  supportsStreaming: true,
1702
- isLocal: true,
3425
+ isLocal: local,
1703
3426
  supportsToolUse: show?.tools ?? isToolCapable(m.name),
1704
3427
  minSizeB: this.parseSizeB(m.details?.parameter_size)
1705
- };
3428
+ });
1706
3429
  });
1707
3430
  } catch {
1708
3431
  return [];
@@ -1786,6 +3509,7 @@ var init_openai_compatible = __esm({
1786
3509
  init_openai();
1787
3510
  init_model_filter();
1788
3511
  init_net();
3512
+ init_pricing();
1789
3513
  OpenAICompatibleProvider = class extends OpenAIProvider {
1790
3514
  constructor(config, model) {
1791
3515
  super({ ...config, apiKey: config.apiKey ?? "not-required" }, model);
@@ -1819,7 +3543,8 @@ var init_openai_compatible = __esm({
1819
3543
  }).filter((x) => typeof x === "string" && x.length > 0);
1820
3544
  if (ids.length === 0) return [this.model];
1821
3545
  const chatIds = ids.filter((id) => isChatModel(id));
1822
- return (chatIds.length ? chatIds : ids).map((id) => ({
3546
+ const local = isLocalEndpoint(this.config);
3547
+ return (chatIds.length ? chatIds : ids).map((id) => withResolvedPricing({
1823
3548
  id,
1824
3549
  name: id,
1825
3550
  provider: "openai-compatible",
@@ -1829,7 +3554,7 @@ var init_openai_compatible = __esm({
1829
3554
  outputCostPer1kTokens: 0,
1830
3555
  maxOutputTokens: 4e3,
1831
3556
  supportsStreaming: true,
1832
- isLocal: false
3557
+ isLocal: local
1833
3558
  }));
1834
3559
  }
1835
3560
  async isAvailable() {
@@ -3151,7 +4876,18 @@ var ProviderConfigSchema = zod.z.object({
3151
4876
  apiVersion: zod.z.string().optional(),
3152
4877
  model: zod.z.string().optional(),
3153
4878
  authToken: zod.z.string().optional(),
3154
- credentialSource: zod.z.string().optional()
4879
+ credentialSource: zod.z.string().optional(),
4880
+ /**
4881
+ * "This endpoint is self-hosted, so inference genuinely costs $0."
4882
+ * Only meaningful for `ollama` and `openai-compatible`. Unset ⇒ inferred:
4883
+ * ollama is local, openai-compatible is local when its baseUrl is
4884
+ * loopback/LAN. Set it explicitly to override — e.g. `false` for an Ollama
4885
+ * instance you rent, `true` for a llama.cpp box on your own LAN reached by
4886
+ * hostname.
4887
+ */
4888
+ local: zod.z.boolean().optional(),
4889
+ /** Region for providers whose price varies by region (Azure: global | us | eu | …). */
4890
+ region: zod.z.string().optional()
3155
4891
  });
3156
4892
  var ModelOverridesSchema = zod.z.object({
3157
4893
  t1: zod.z.string().optional(),
@@ -4000,6 +5736,7 @@ init_openai();
4000
5736
 
4001
5737
  // src/core/router/selector.ts
4002
5738
  init_constants();
5739
+ init_pricing();
4003
5740
  function normalizeModelId(id) {
4004
5741
  return id.replace(/^models\//, "").toLowerCase();
4005
5742
  }
@@ -4201,7 +5938,7 @@ var ModelSelector = class {
4201
5938
  else if (this.availableProviders.size === 1) providerStr = Array.from(this.availableProviders)[0];
4202
5939
  }
4203
5940
  if (providerStr && this.availableProviders.has(providerStr)) {
4204
- const dynamicModel = {
5941
+ const dynamicModel = withResolvedPricing({
4205
5942
  id: actualId,
4206
5943
  name: actualId,
4207
5944
  provider: providerStr,
@@ -4212,7 +5949,7 @@ var ModelSelector = class {
4212
5949
  maxOutputTokens: 8e3,
4213
5950
  supportsStreaming: true,
4214
5951
  isLocal: providerStr === "ollama"
4215
- };
5952
+ });
4216
5953
  this.addDynamicModel(dynamicModel);
4217
5954
  return dynamicModel;
4218
5955
  }
@@ -4582,6 +6319,7 @@ function computeDelegationSavings(stats, t1Model) {
4582
6319
 
4583
6320
  // src/core/router/live-data.ts
4584
6321
  init_constants();
6322
+ init_pricing();
4585
6323
  var DEFAULT_SNAPSHOT_URL = "https://raw.githubusercontent.com/Varun-SV/Cascade-AI/main/src/core/router/benchmark-data.json";
4586
6324
  var OPENROUTER_MODELS_URL = "https://openrouter.ai/api/v1/models";
4587
6325
  var FETCH_TIMEOUT_MS = 8e3;
@@ -4599,6 +6337,8 @@ var LiveDataProvider = class {
4599
6337
  snapshot = null;
4600
6338
  prices = /* @__PURE__ */ new Map();
4601
6339
  capabilities = /* @__PURE__ */ new Map();
6340
+ /** Dataset-vs-live price mismatches, deduped by `provider:modelId`. */
6341
+ disagreements = /* @__PURE__ */ new Map();
4602
6342
  source = "bundled";
4603
6343
  fetchedAt = 0;
4604
6344
  loaded = false;
@@ -4752,14 +6492,45 @@ var LiveDataProvider = class {
4752
6492
  /**
4753
6493
  * Returns a price-corrected copy of each model when live pricing is known,
4754
6494
  * leaving the original untouched (so the shared catalog is never mutated).
6495
+ *
6496
+ * Reconciliation policy (see reconcilePrice in pricing.ts): the bundled
6497
+ * dataset is the authoritative baseline, and a live quote overrides it
6498
+ * because it is fresher by construction — but the disagreement is RECORDED,
6499
+ * not swallowed. A dataset/live mismatch is the best signal available that
6500
+ * the committed prices have gone stale, so it must be visible rather than
6501
+ * silently resolved in either direction. A live quote of $0 for a non-local
6502
+ * model is rejected outright: that is the very failure mode this change
6503
+ * exists to prevent, and a marketplace's free-tier alias must never zero out
6504
+ * the price of the paid model Cascade is actually calling.
4755
6505
  */
4756
6506
  applyLivePricing(models) {
4757
6507
  return models.map((m) => {
4758
6508
  const p = this.getLivePrice(m.baseModelId ?? m.id);
4759
6509
  if (!p) return m;
4760
- return { ...m, inputCostPer1kTokens: p.input, outputCostPer1kTokens: p.output };
6510
+ const reconciled = reconcilePrice(m, p);
6511
+ if (reconciled.disagreement) this.recordDisagreement(reconciled.disagreement);
6512
+ if (!reconciled.accepted) return m;
6513
+ return {
6514
+ ...m,
6515
+ inputCostPer1kTokens: reconciled.input,
6516
+ outputCostPer1kTokens: reconciled.output,
6517
+ pricingUnknown: false
6518
+ };
4761
6519
  });
4762
6520
  }
6521
+ recordDisagreement(d) {
6522
+ const key = `${d.provider}:${d.modelId}`;
6523
+ if (this.disagreements.has(key)) return;
6524
+ this.disagreements.set(key, d);
6525
+ }
6526
+ /**
6527
+ * Dataset-vs-live price mismatches seen this session, newest-model-first
6528
+ * insertion order. Surfaced by `cascade models --verbose`; a non-empty list
6529
+ * means src/core/router/pricing-data.json is probably due a refresh.
6530
+ */
6531
+ getPriceDisagreements() {
6532
+ return [...this.disagreements.values()];
6533
+ }
4763
6534
  /** Current capability facts for a model id, or null when unknown. */
4764
6535
  getCapability(modelId) {
4765
6536
  return this.capabilities.get(normalizeModelId2(modelId)) ?? null;
@@ -4956,7 +6727,9 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter__default.default {
4956
6727
  tokensByTier: {},
4957
6728
  inputTokensByTier: {},
4958
6729
  outputTokensByTier: {},
4959
- costByFeature: {}
6730
+ costByFeature: {},
6731
+ untrackedCostCalls: 0,
6732
+ untrackedCostModels: []
4960
6733
  };
4961
6734
  tierModels = /* @__PURE__ */ new Map();
4962
6735
  /**
@@ -5306,7 +7079,7 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter__default.default {
5306
7079
  `Model ${model.id} inference timed out after ${cloudTimeoutMs}ms`
5307
7080
  );
5308
7081
  }
5309
- const correctedCost = calculateCost(
7082
+ const corrected = buildTokenUsage(
5310
7083
  result.usage.inputTokens,
5311
7084
  result.usage.outputTokens,
5312
7085
  model
@@ -5315,7 +7088,8 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter__default.default {
5315
7088
  ...result,
5316
7089
  usage: {
5317
7090
  ...result.usage,
5318
- estimatedCostUsd: correctedCost
7091
+ estimatedCostUsd: corrected.estimatedCostUsd,
7092
+ ...corrected.costUnknown ? { costUnknown: true } : { costUnknown: void 0 }
5319
7093
  }
5320
7094
  };
5321
7095
  if (!result || typeof result.content !== "string" || !result.usage) {
@@ -5502,7 +7276,9 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter__default.default {
5502
7276
  tokensByTier: { ...this.stats.tokensByTier },
5503
7277
  inputTokensByTier: { ...this.stats.inputTokensByTier },
5504
7278
  outputTokensByTier: { ...this.stats.outputTokensByTier },
5505
- costByFeature: { ...this.stats.costByFeature }
7279
+ costByFeature: { ...this.stats.costByFeature },
7280
+ untrackedCostCalls: this.stats.untrackedCostCalls,
7281
+ untrackedCostModels: [...this.stats.untrackedCostModels]
5506
7282
  };
5507
7283
  }
5508
7284
  /**
@@ -5553,7 +7329,9 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter__default.default {
5553
7329
  tokensByTier: {},
5554
7330
  inputTokensByTier: {},
5555
7331
  outputTokensByTier: {},
5556
- costByFeature: {}
7332
+ costByFeature: {},
7333
+ untrackedCostCalls: 0,
7334
+ untrackedCostModels: []
5557
7335
  };
5558
7336
  this.sessionCostUsd = 0;
5559
7337
  this.budgetState = "ok";
@@ -5738,6 +7516,18 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter__default.default {
5738
7516
  if (featureTag) {
5739
7517
  this.stats.costByFeature[featureTag] = (this.stats.costByFeature[featureTag] ?? 0) + usage.estimatedCostUsd;
5740
7518
  }
7519
+ if (usage.costUnknown) {
7520
+ this.stats.untrackedCostCalls += 1;
7521
+ if (!this.stats.untrackedCostModels.includes(model.id)) {
7522
+ this.stats.untrackedCostModels.push(model.id);
7523
+ const capped = this.config?.budget?.maxCostPerRunUsd != null || this.config?.budget?.sessionBudgetUsd != null;
7524
+ this.emit("cost:untracked", {
7525
+ modelId: model.id,
7526
+ provider: model.provider,
7527
+ 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.`
7528
+ });
7529
+ }
7530
+ }
5741
7531
  this.runTokens += usage.totalTokens;
5742
7532
  this.runCostUsd += usage.estimatedCostUsd;
5743
7533
  this.updateBudgetState();
@@ -11268,6 +13058,7 @@ var noopTelemetry = {
11268
13058
  };
11269
13059
 
11270
13060
  // src/core/router/task-analyzer.ts
13061
+ init_pricing();
11271
13062
  var CODE_SIGNALS = [
11272
13063
  /\b(?:function|class|interface|async|await|import|export|const|let|var|def|return|if|else|for|while|try|catch)\b/,
11273
13064
  /\b(?:typescript|javascript|python|rust|go|java|c\+\+|sql|bash|shell|dockerfile|kubernetes|terraform)\b/i,
@@ -11444,8 +13235,8 @@ var TaskAnalyzer = class {
11444
13235
  }
11445
13236
  costEfficiency(model, complexity) {
11446
13237
  if (this.tracker) return this.tracker.costEfficiencyScore(model, complexity);
11447
- const blended = model.inputCostPer1kTokens + model.outputCostPer1kTokens * 2;
11448
- const normalised = Math.min(1, blended / 0.05);
13238
+ const blended = blendedCostPer1k(model);
13239
+ const normalised = Math.min(1, blended / BLENDED_COST_CEILING);
11449
13240
  const complexityWeight = (6 - complexity) / 5;
11450
13241
  return Math.max(0.1, 1 - normalised * complexityWeight);
11451
13242
  }
@@ -11460,6 +13251,9 @@ var TaskAnalyzer = class {
11460
13251
  analysisCache.clear();
11461
13252
  }
11462
13253
  };
13254
+
13255
+ // src/core/router/model-performance-tracker.ts
13256
+ init_pricing();
11463
13257
  var DEFAULT_STATS_FILE = path32__default.default.join(os10__default.default.homedir(), ".cascade", "model-perf.json");
11464
13258
  var ModelPerformanceTracker = class {
11465
13259
  stats = /* @__PURE__ */ new Map();
@@ -11580,8 +13374,8 @@ var ModelPerformanceTracker = class {
11580
13374
  * normalised over $0.05 blended as the "expensive" ceiling.
11581
13375
  */
11582
13376
  costEfficiencyScore(model, complexity) {
11583
- const blended = model.inputCostPer1kTokens + model.outputCostPer1kTokens * 2;
11584
- const normalised = Math.min(1, blended / 0.05);
13377
+ const blended = blendedCostPer1k(model);
13378
+ const normalised = Math.min(1, blended / BLENDED_COST_CEILING);
11585
13379
  const complexityWeight = (6 - complexity) / 5;
11586
13380
  return Math.max(0.1, 1 - normalised * complexityWeight);
11587
13381
  }
@@ -14385,7 +16179,11 @@ _(incomplete: ${reasons.join("; ")})_` : partial;
14385
16179
  inputTokens: 0,
14386
16180
  outputTokens: 0,
14387
16181
  totalTokens: stats.totalTokens,
14388
- estimatedCostUsd: stats.totalCostUsd
16182
+ estimatedCostUsd: stats.totalCostUsd,
16183
+ // At least one call ran on a model with no known price, so its spend is
16184
+ // missing from the total above. Say so rather than letting the caller
16185
+ // present an undercount as the final figure.
16186
+ ...stats.untrackedCostCalls > 0 ? { costUnknown: true } : {}
14389
16187
  },
14390
16188
  t2Results,
14391
16189
  durationMs,
@@ -14455,7 +16253,8 @@ _(incomplete: ${reasons.join("; ")})_` : partial;
14455
16253
  inputTokens: 0,
14456
16254
  outputTokens: 0,
14457
16255
  totalTokens: stats2.totalTokens,
14458
- estimatedCostUsd: stats2.totalCostUsd
16256
+ estimatedCostUsd: stats2.totalCostUsd,
16257
+ ...stats2.untrackedCostCalls > 0 ? { costUnknown: true } : {}
14459
16258
  },
14460
16259
  t2Results: [],
14461
16260
  durationMs: Date.now() - startMs,
@@ -14479,7 +16278,8 @@ _(incomplete: ${reasons.join("; ")})_` : partial;
14479
16278
  inputTokens: result.usage?.inputTokens ?? 0,
14480
16279
  outputTokens: result.usage?.outputTokens ?? 0,
14481
16280
  totalTokens: stats.totalTokens,
14482
- estimatedCostUsd: stats.totalCostUsd
16281
+ estimatedCostUsd: stats.totalCostUsd,
16282
+ ...stats.untrackedCostCalls > 0 ? { costUnknown: true } : {}
14483
16283
  },
14484
16284
  t2Results: [],
14485
16285
  durationMs: Date.now() - startMs,
@@ -14669,12 +16469,19 @@ var CloudClient = class _CloudClient {
14669
16469
  );
14670
16470
  await openUrl(authorizeUrl);
14671
16471
  const code = await listener.waitForCode;
14672
- const res = await fetch(this.url("/api/native/token"), {
14673
- method: "POST",
14674
- headers: { "Content-Type": "application/json" },
14675
- body: JSON.stringify({ code, code_verifier: verifier })
14676
- });
14677
- if (!res.ok) throw new Error("Sign-in could not be completed. Please try again.");
16472
+ let res;
16473
+ try {
16474
+ res = await fetch(this.url("/api/native/token"), {
16475
+ method: "POST",
16476
+ headers: { "Content-Type": "application/json" },
16477
+ body: JSON.stringify({ code, code_verifier: verifier })
16478
+ });
16479
+ } catch (err) {
16480
+ throw new Error(
16481
+ `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)})`
16482
+ );
16483
+ }
16484
+ if (!res.ok) throw new Error(await loginFailureMessage(res, this.serverUrl));
14678
16485
  const tokens = await res.json();
14679
16486
  return await this.finishLogin(tokens);
14680
16487
  } finally {
@@ -14848,6 +16655,22 @@ function sleep(ms, signal) {
14848
16655
  }, { once: true });
14849
16656
  });
14850
16657
  }
16658
+ async function loginFailureMessage(res, serverUrl) {
16659
+ const body = await res.text().catch(() => "");
16660
+ let apiError = "";
16661
+ try {
16662
+ apiError = String(JSON.parse(body).error ?? "");
16663
+ } catch {
16664
+ }
16665
+ if (apiError === "invalid_grant") {
16666
+ 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.";
16667
+ }
16668
+ if (apiError) return `Sign-in failed: ${apiError} (HTTP ${res.status}).`;
16669
+ if (res.status === 404 || /<html/i.test(body)) {
16670
+ 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.`;
16671
+ }
16672
+ return `Sign-in could not be completed (HTTP ${res.status}). Please try again.`;
16673
+ }
14851
16674
  function base64url(buf) {
14852
16675
  return buf.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
14853
16676
  }
@@ -19673,7 +21496,10 @@ var DashboardServer = class {
19673
21496
  this.socket.broadcast("cost:update", {
19674
21497
  sessionId,
19675
21498
  totalTokens: result.usage.totalTokens,
19676
- totalCostUsd: result.usage.estimatedCostUsd
21499
+ totalCostUsd: result.usage.estimatedCostUsd,
21500
+ // True when a model with no known price was used: the total above is
21501
+ // an undercount, and the UI must not present it as the full spend.
21502
+ costUnknown: result.usage.costUnknown === true
19677
21503
  });
19678
21504
  this.throttledBroadcast("workspace");
19679
21505
  } catch (err) {
@@ -19986,7 +21812,8 @@ var DashboardServer = class {
19986
21812
  this.socket.broadcast("cost:update", {
19987
21813
  sessionId,
19988
21814
  totalTokens: result.usage.totalTokens,
19989
- totalCostUsd: result.usage.estimatedCostUsd
21815
+ totalCostUsd: result.usage.estimatedCostUsd,
21816
+ costUnknown: result.usage.costUnknown === true
19990
21817
  });
19991
21818
  this.throttledBroadcast("workspace");
19992
21819
  } catch (err) {
@@ -20528,7 +22355,8 @@ ${prompt}`;
20528
22355
  this.socket.broadcast("cost:update", {
20529
22356
  sessionId,
20530
22357
  totalTokens: result.usage.totalTokens,
20531
- totalCostUsd: result.usage.estimatedCostUsd
22358
+ totalCostUsd: result.usage.estimatedCostUsd,
22359
+ costUnknown: result.usage.costUnknown === true
20532
22360
  });
20533
22361
  this.socket.broadcastToRoom(`session:${sessionId}`, "session:complete", { sessionId, result });
20534
22362
  this.throttledBroadcast("workspace");
@@ -20924,6 +22752,7 @@ function makeIdentityCommand(workspacePath = process.cwd()) {
20924
22752
  });
20925
22753
  return identity;
20926
22754
  }
22755
+ init_pricing();
20927
22756
  async function modelsCommand(options = {}) {
20928
22757
  console.log(chalk7__default.default.magenta("\n \u25C8 Cascade Models\n"));
20929
22758
  const cm = new ConfigManager(process.cwd());
@@ -20945,17 +22774,20 @@ async function modelsCommand(options = {}) {
20945
22774
  { tier: "T3", label: "T3 Worker", color: chalk7__default.default.hex("#2DD4BF") }
20946
22775
  ];
20947
22776
  let anyMissing = false;
22777
+ let anyUnpriced = false;
20948
22778
  for (const { tier, label, color } of tiers) {
20949
22779
  const model = router.getTierModel(tier);
20950
22780
  if (model) {
20951
- const costIn = model.inputCostPer1kTokens === 0 ? "free" : `$${model.inputCostPer1kTokens.toFixed(4)}/1K in`;
20952
- const costOut = model.outputCostPer1kTokens === 0 ? "free" : `$${model.outputCostPer1kTokens.toFixed(4)}/1K out`;
22781
+ const unpriced = isPricingUnknown(model);
22782
+ if (unpriced) anyUnpriced = true;
22783
+ const costIn = unpriced ? "cost not tracked" : model.inputCostPer1kTokens === 0 ? "free" : `$${model.inputCostPer1kTokens.toFixed(4)}/1K in`;
22784
+ const costOut = unpriced ? "" : model.outputCostPer1kTokens === 0 ? "free" : `, $${model.outputCostPer1kTokens.toFixed(4)}/1K out`;
20953
22785
  const ctx = model.contextWindow >= 1e6 ? `${(model.contextWindow / 1e6).toFixed(1)}M ctx` : `${(model.contextWindow / 1e3).toFixed(0)}K ctx`;
20954
22786
  const local = model.isLocal ? chalk7__default.default.gray(" [local]") : "";
20955
22787
  const vision = model.isVisionCapable ? chalk7__default.default.gray(" \u{1F441}") : "";
20956
22788
  const bench = Math.round(benchmarkScore01(model, "mixed") * 100);
20957
22789
  console.log(
20958
- ` ${color.bold(tier)} ${chalk7__default.default.white(col(model.name, 24))}${chalk7__default.default.gray(col(model.provider, 16))}` + (options.verbose ? `${chalk7__default.default.gray(col(ctx, 12))}${chalk7__default.default.gray(col(`bench ${bench}/100`, 14))}${chalk7__default.default.gray(`${costIn}, ${costOut}`)}` : `${chalk7__default.default.gray(col(ctx, 10))}${chalk7__default.default.gray(`bench ${bench}/100`)}`) + local + vision
22790
+ ` ${color.bold(tier)} ${chalk7__default.default.white(col(model.name, 24))}${chalk7__default.default.gray(col(model.provider, 16))}` + (options.verbose ? `${chalk7__default.default.gray(col(ctx, 12))}${chalk7__default.default.gray(col(`bench ${bench}/100`, 14))}${chalk7__default.default.gray(`${costIn}${costOut}`)}` : `${chalk7__default.default.gray(col(ctx, 10))}${chalk7__default.default.gray(`bench ${bench}/100`)}`) + local + vision
20959
22791
  );
20960
22792
  } else {
20961
22793
  console.log(` ${color.bold(tier)} ${chalk7__default.default.red("No model available")} ${chalk7__default.default.gray(`(check provider config for ${label})`)}`);
@@ -20969,8 +22801,25 @@ async function modelsCommand(options = {}) {
20969
22801
  const src = liveData.getDataSource();
20970
22802
  const gen = liveData.getGeneratedAt();
20971
22803
  const srcLabel = src === "live" ? "live (just fetched)" : src === "cache" ? "cached" : "bundled";
22804
+ const pricingMeta = pricingDatasetMeta();
20972
22805
  console.log(chalk7__default.default.gray(
20973
- ` Benchmark data: ${srcLabel}` + (gen ? ` \xB7 updated ${gen.slice(0, 10)}` : "") + ` \xB7 pricing: ${liveData.hasLivePricing() ? "live (OpenRouter)" : "catalog"}`
22806
+ ` Benchmark data: ${srcLabel}` + (gen ? ` \xB7 updated ${gen.slice(0, 10)}` : "") + ` \xB7 pricing: ${liveData.hasLivePricing() ? "live (OpenRouter)" : "dataset"} (baseline ${pricingMeta.generatedAt})`
22807
+ ));
22808
+ const drift = liveData.getPriceDisagreements();
22809
+ if (drift.length) {
22810
+ console.log(chalk7__default.default.yellow(`
22811
+ ${drift.length} model${drift.length === 1 ? "" : "s"} priced differently by the live source than by the bundled dataset:`));
22812
+ for (const d of drift.slice(0, 10)) {
22813
+ console.log(chalk7__default.default.gray(
22814
+ ` ${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)`
22815
+ ));
22816
+ }
22817
+ console.log(chalk7__default.default.gray(" Live pricing is used. Refresh src/core/router/pricing-data.json to clear this."));
22818
+ }
22819
+ }
22820
+ if (anyUnpriced) {
22821
+ console.log(chalk7__default.default.yellow(
22822
+ '\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.'
20974
22823
  ));
20975
22824
  }
20976
22825
  if (options.verbose) {