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/index.js CHANGED
@@ -192,8 +192,1660 @@ var init_audit_logger = __esm({
192
192
  }
193
193
  });
194
194
 
195
+ // src/core/router/pricing-data.json
196
+ var pricing_data_default = {
197
+ entries: [
198
+ {
199
+ model: "claude-opus-5",
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: 5,
209
+ outputPer1m: 25,
210
+ cachedInputPer1m: 0.5,
211
+ cacheWritePer1m: 6.25,
212
+ reasoningOutputPer1m: 25
213
+ }
214
+ ],
215
+ batchMultiplier: 0.5,
216
+ contextWindow: 1e6
217
+ },
218
+ {
219
+ model: "claude-opus-4-8",
220
+ provider: "anthropic",
221
+ modality: "text",
222
+ currency: "USD",
223
+ asOf: "2026-07-27",
224
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
225
+ provenance: "vendor-pricing-page",
226
+ tiers: [
227
+ {
228
+ inputPer1m: 5,
229
+ outputPer1m: 25,
230
+ cachedInputPer1m: 0.5,
231
+ cacheWritePer1m: 6.25,
232
+ reasoningOutputPer1m: 25
233
+ }
234
+ ],
235
+ batchMultiplier: 0.5,
236
+ contextWindow: 1e6
237
+ },
238
+ {
239
+ model: "claude-opus-4-7",
240
+ provider: "anthropic",
241
+ modality: "text",
242
+ currency: "USD",
243
+ asOf: "2026-07-27",
244
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
245
+ provenance: "vendor-pricing-page",
246
+ tiers: [
247
+ {
248
+ inputPer1m: 5,
249
+ outputPer1m: 25,
250
+ cachedInputPer1m: 0.5,
251
+ cacheWritePer1m: 6.25,
252
+ reasoningOutputPer1m: 25
253
+ }
254
+ ],
255
+ batchMultiplier: 0.5,
256
+ contextWindow: 1e6
257
+ },
258
+ {
259
+ model: "claude-opus-4-6",
260
+ provider: "anthropic",
261
+ modality: "text",
262
+ currency: "USD",
263
+ asOf: "2026-07-27",
264
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
265
+ provenance: "vendor-pricing-page",
266
+ tiers: [
267
+ {
268
+ inputPer1m: 5,
269
+ outputPer1m: 25,
270
+ cachedInputPer1m: 0.5,
271
+ cacheWritePer1m: 6.25,
272
+ reasoningOutputPer1m: 25
273
+ }
274
+ ],
275
+ batchMultiplier: 0.5,
276
+ contextWindow: 1e6
277
+ },
278
+ {
279
+ model: "claude-opus-4-5",
280
+ provider: "anthropic",
281
+ modality: "text",
282
+ currency: "USD",
283
+ asOf: "2026-07-27",
284
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
285
+ provenance: "vendor-pricing-page",
286
+ tiers: [
287
+ {
288
+ inputPer1m: 5,
289
+ outputPer1m: 25,
290
+ cachedInputPer1m: 0.5,
291
+ cacheWritePer1m: 6.25,
292
+ reasoningOutputPer1m: 25
293
+ }
294
+ ],
295
+ batchMultiplier: 0.5,
296
+ contextWindow: 2e5
297
+ },
298
+ {
299
+ model: "claude-opus-4-1",
300
+ provider: "anthropic",
301
+ modality: "text",
302
+ currency: "USD",
303
+ asOf: "2026-07-27",
304
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
305
+ provenance: "vendor-pricing-page",
306
+ tiers: [
307
+ {
308
+ inputPer1m: 15,
309
+ outputPer1m: 75,
310
+ cachedInputPer1m: 1.5,
311
+ cacheWritePer1m: 18.75,
312
+ reasoningOutputPer1m: 75
313
+ }
314
+ ],
315
+ batchMultiplier: 0.5,
316
+ contextWindow: 2e5,
317
+ notes: "Deprecated by Anthropic; priced for historical/cost-reporting accuracy."
318
+ },
319
+ {
320
+ model: "claude-opus-4",
321
+ provider: "anthropic",
322
+ modality: "text",
323
+ currency: "USD",
324
+ asOf: "2026-07-27",
325
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
326
+ provenance: "vendor-pricing-page",
327
+ tiers: [
328
+ {
329
+ inputPer1m: 15,
330
+ outputPer1m: 75,
331
+ cachedInputPer1m: 1.5,
332
+ cacheWritePer1m: 18.75,
333
+ reasoningOutputPer1m: 75
334
+ }
335
+ ],
336
+ batchMultiplier: 0.5,
337
+ contextWindow: 2e5,
338
+ notes: "Retired except on Google Cloud; priced for historical/cost-reporting accuracy."
339
+ },
340
+ {
341
+ model: "claude-sonnet-5",
342
+ provider: "anthropic",
343
+ modality: "text",
344
+ currency: "USD",
345
+ asOf: "2026-07-27",
346
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
347
+ provenance: "vendor-pricing-page",
348
+ tiers: [
349
+ {
350
+ inputPer1m: 2,
351
+ outputPer1m: 10,
352
+ cachedInputPer1m: 0.2,
353
+ cacheWritePer1m: 2.5,
354
+ reasoningOutputPer1m: 10
355
+ }
356
+ ],
357
+ batchMultiplier: 0.5,
358
+ contextWindow: 1e6,
359
+ 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."
360
+ },
361
+ {
362
+ model: "claude-sonnet-4-6",
363
+ provider: "anthropic",
364
+ modality: "text",
365
+ currency: "USD",
366
+ asOf: "2026-07-27",
367
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
368
+ provenance: "vendor-pricing-page",
369
+ tiers: [
370
+ {
371
+ inputPer1m: 3,
372
+ outputPer1m: 15,
373
+ cachedInputPer1m: 0.3,
374
+ cacheWritePer1m: 3.75,
375
+ reasoningOutputPer1m: 15
376
+ }
377
+ ],
378
+ batchMultiplier: 0.5,
379
+ contextWindow: 1e6
380
+ },
381
+ {
382
+ model: "claude-sonnet-4-5",
383
+ provider: "anthropic",
384
+ modality: "text",
385
+ currency: "USD",
386
+ asOf: "2026-07-27",
387
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
388
+ provenance: "vendor-pricing-page",
389
+ tiers: [
390
+ {
391
+ maxInputTokens: 2e5,
392
+ inputPer1m: 3,
393
+ outputPer1m: 15,
394
+ cachedInputPer1m: 0.3,
395
+ cacheWritePer1m: 3.75,
396
+ reasoningOutputPer1m: 15
397
+ },
398
+ {
399
+ inputPer1m: 6,
400
+ outputPer1m: 22.5,
401
+ cachedInputPer1m: 0.6,
402
+ cacheWritePer1m: 7.5,
403
+ reasoningOutputPer1m: 22.5
404
+ }
405
+ ],
406
+ batchMultiplier: 0.5,
407
+ contextWindow: 2e5,
408
+ 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)."
409
+ },
410
+ {
411
+ model: "claude-sonnet-4",
412
+ provider: "anthropic",
413
+ modality: "text",
414
+ currency: "USD",
415
+ asOf: "2026-07-27",
416
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
417
+ provenance: "vendor-pricing-page",
418
+ tiers: [
419
+ {
420
+ inputPer1m: 3,
421
+ outputPer1m: 15,
422
+ cachedInputPer1m: 0.3,
423
+ cacheWritePer1m: 3.75,
424
+ reasoningOutputPer1m: 15
425
+ }
426
+ ],
427
+ batchMultiplier: 0.5,
428
+ contextWindow: 2e5
429
+ },
430
+ {
431
+ model: "claude-haiku-4-5",
432
+ provider: "anthropic",
433
+ modality: "text",
434
+ currency: "USD",
435
+ asOf: "2026-07-27",
436
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
437
+ provenance: "vendor-pricing-page",
438
+ tiers: [
439
+ {
440
+ inputPer1m: 1,
441
+ outputPer1m: 5,
442
+ cachedInputPer1m: 0.1,
443
+ cacheWritePer1m: 1.25,
444
+ reasoningOutputPer1m: 5
445
+ }
446
+ ],
447
+ batchMultiplier: 0.5,
448
+ contextWindow: 2e5
449
+ },
450
+ {
451
+ model: "claude-haiku-3-5",
452
+ provider: "anthropic",
453
+ modality: "text",
454
+ currency: "USD",
455
+ asOf: "2026-07-27",
456
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
457
+ provenance: "vendor-pricing-page",
458
+ tiers: [
459
+ {
460
+ inputPer1m: 0.8,
461
+ outputPer1m: 4,
462
+ cachedInputPer1m: 0.08,
463
+ cacheWritePer1m: 1,
464
+ reasoningOutputPer1m: 4
465
+ }
466
+ ],
467
+ batchMultiplier: 0.5,
468
+ contextWindow: 2e5
469
+ },
470
+ {
471
+ model: "gpt-5.6-sol",
472
+ provider: "openai",
473
+ aliases: [
474
+ "gpt-5.6"
475
+ ],
476
+ modality: "text",
477
+ currency: "USD",
478
+ asOf: "2026-07-27",
479
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
480
+ provenance: "litellm-catalog",
481
+ tiers: [
482
+ {
483
+ maxInputTokens: 272e3,
484
+ inputPer1m: 5,
485
+ outputPer1m: 30,
486
+ cachedInputPer1m: 0.5,
487
+ cacheWritePer1m: 6.25
488
+ },
489
+ {
490
+ inputPer1m: 10,
491
+ outputPer1m: 45,
492
+ cachedInputPer1m: 1,
493
+ cacheWritePer1m: 12.5
494
+ }
495
+ ],
496
+ batchMultiplier: 0.5,
497
+ contextWindow: 105e4
498
+ },
499
+ {
500
+ model: "gpt-5.6-terra",
501
+ provider: "openai",
502
+ modality: "text",
503
+ currency: "USD",
504
+ asOf: "2026-07-27",
505
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
506
+ provenance: "litellm-catalog",
507
+ tiers: [
508
+ {
509
+ maxInputTokens: 272e3,
510
+ inputPer1m: 2.5,
511
+ outputPer1m: 15,
512
+ cachedInputPer1m: 0.25,
513
+ cacheWritePer1m: 3.125
514
+ },
515
+ {
516
+ inputPer1m: 5,
517
+ outputPer1m: 22.5,
518
+ cachedInputPer1m: 0.5,
519
+ cacheWritePer1m: 6.25
520
+ }
521
+ ],
522
+ batchMultiplier: 0.5,
523
+ contextWindow: 105e4
524
+ },
525
+ {
526
+ model: "gpt-5.6-luna",
527
+ provider: "openai",
528
+ modality: "text",
529
+ currency: "USD",
530
+ asOf: "2026-07-27",
531
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
532
+ provenance: "litellm-catalog",
533
+ tiers: [
534
+ {
535
+ maxInputTokens: 272e3,
536
+ inputPer1m: 1,
537
+ outputPer1m: 6,
538
+ cachedInputPer1m: 0.1,
539
+ cacheWritePer1m: 1.25
540
+ },
541
+ {
542
+ inputPer1m: 2,
543
+ outputPer1m: 9,
544
+ cachedInputPer1m: 0.2,
545
+ cacheWritePer1m: 2.5
546
+ }
547
+ ],
548
+ batchMultiplier: 0.5,
549
+ contextWindow: 105e4
550
+ },
551
+ {
552
+ model: "gpt-5.5",
553
+ provider: "openai",
554
+ modality: "text",
555
+ currency: "USD",
556
+ asOf: "2026-07-27",
557
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
558
+ provenance: "litellm-catalog",
559
+ tiers: [
560
+ {
561
+ maxInputTokens: 272e3,
562
+ inputPer1m: 5,
563
+ outputPer1m: 30,
564
+ cachedInputPer1m: 0.5
565
+ },
566
+ {
567
+ inputPer1m: 10,
568
+ outputPer1m: 45,
569
+ cachedInputPer1m: 1
570
+ }
571
+ ],
572
+ batchMultiplier: 0.5,
573
+ contextWindow: 105e4
574
+ },
575
+ {
576
+ model: "gpt-5.4",
577
+ provider: "openai",
578
+ modality: "text",
579
+ currency: "USD",
580
+ asOf: "2026-07-27",
581
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
582
+ provenance: "litellm-catalog",
583
+ tiers: [
584
+ {
585
+ maxInputTokens: 272e3,
586
+ inputPer1m: 2.5,
587
+ outputPer1m: 15,
588
+ cachedInputPer1m: 0.25
589
+ },
590
+ {
591
+ inputPer1m: 5,
592
+ outputPer1m: 22.5,
593
+ cachedInputPer1m: 0.5
594
+ }
595
+ ],
596
+ batchMultiplier: 0.5,
597
+ contextWindow: 105e4
598
+ },
599
+ {
600
+ model: "gpt-5.4-mini",
601
+ provider: "openai",
602
+ modality: "text",
603
+ currency: "USD",
604
+ asOf: "2026-07-27",
605
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
606
+ provenance: "litellm-catalog",
607
+ tiers: [
608
+ {
609
+ inputPer1m: 0.75,
610
+ outputPer1m: 4.5,
611
+ cachedInputPer1m: 0.075
612
+ }
613
+ ],
614
+ batchMultiplier: 0.5,
615
+ contextWindow: 105e4
616
+ },
617
+ {
618
+ model: "gpt-5",
619
+ provider: "openai",
620
+ modality: "text",
621
+ currency: "USD",
622
+ asOf: "2026-07-27",
623
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
624
+ provenance: "litellm-catalog",
625
+ tiers: [
626
+ {
627
+ inputPer1m: 1.25,
628
+ outputPer1m: 10,
629
+ cachedInputPer1m: 0.125
630
+ }
631
+ ],
632
+ contextWindow: 272e3
633
+ },
634
+ {
635
+ model: "gpt-5-mini",
636
+ provider: "openai",
637
+ modality: "text",
638
+ currency: "USD",
639
+ asOf: "2026-07-27",
640
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
641
+ provenance: "litellm-catalog",
642
+ tiers: [
643
+ {
644
+ inputPer1m: 0.25,
645
+ outputPer1m: 2,
646
+ cachedInputPer1m: 0.025
647
+ }
648
+ ],
649
+ contextWindow: 272e3
650
+ },
651
+ {
652
+ model: "gpt-5-nano",
653
+ provider: "openai",
654
+ modality: "text",
655
+ currency: "USD",
656
+ asOf: "2026-07-27",
657
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
658
+ provenance: "litellm-catalog",
659
+ tiers: [
660
+ {
661
+ inputPer1m: 0.05,
662
+ outputPer1m: 0.4,
663
+ cachedInputPer1m: 5e-3
664
+ }
665
+ ],
666
+ contextWindow: 272e3
667
+ },
668
+ {
669
+ model: "gpt-4.1",
670
+ provider: "openai",
671
+ modality: "text",
672
+ currency: "USD",
673
+ asOf: "2026-07-27",
674
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
675
+ provenance: "litellm-catalog",
676
+ tiers: [
677
+ {
678
+ inputPer1m: 2,
679
+ outputPer1m: 8,
680
+ cachedInputPer1m: 0.5
681
+ }
682
+ ],
683
+ batchMultiplier: 0.5,
684
+ contextWindow: 1047576
685
+ },
686
+ {
687
+ model: "gpt-4.1-mini",
688
+ provider: "openai",
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
+ inputPer1m: 0.4,
697
+ outputPer1m: 1.6,
698
+ cachedInputPer1m: 0.1
699
+ }
700
+ ],
701
+ batchMultiplier: 0.5,
702
+ contextWindow: 1047576
703
+ },
704
+ {
705
+ model: "gpt-4.1-nano",
706
+ provider: "openai",
707
+ modality: "text",
708
+ currency: "USD",
709
+ asOf: "2026-07-27",
710
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
711
+ provenance: "litellm-catalog",
712
+ tiers: [
713
+ {
714
+ inputPer1m: 0.1,
715
+ outputPer1m: 0.4,
716
+ cachedInputPer1m: 0.025
717
+ }
718
+ ],
719
+ batchMultiplier: 0.5,
720
+ contextWindow: 1047576
721
+ },
722
+ {
723
+ model: "gpt-4o",
724
+ provider: "openai",
725
+ modality: "text",
726
+ currency: "USD",
727
+ asOf: "2026-07-27",
728
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
729
+ provenance: "litellm-catalog",
730
+ tiers: [
731
+ {
732
+ inputPer1m: 2.5,
733
+ outputPer1m: 10,
734
+ cachedInputPer1m: 1.25
735
+ }
736
+ ],
737
+ batchMultiplier: 0.5,
738
+ contextWindow: 128e3
739
+ },
740
+ {
741
+ model: "gpt-4o-mini",
742
+ provider: "openai",
743
+ modality: "text",
744
+ currency: "USD",
745
+ asOf: "2026-07-27",
746
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
747
+ provenance: "litellm-catalog",
748
+ tiers: [
749
+ {
750
+ inputPer1m: 0.15,
751
+ outputPer1m: 0.6,
752
+ cachedInputPer1m: 0.075
753
+ }
754
+ ],
755
+ batchMultiplier: 0.5,
756
+ contextWindow: 128e3
757
+ },
758
+ {
759
+ model: "gpt-5.5",
760
+ provider: "azure",
761
+ region: "global",
762
+ modality: "text",
763
+ currency: "USD",
764
+ asOf: "2026-07-27",
765
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
766
+ provenance: "litellm-catalog",
767
+ tiers: [
768
+ {
769
+ maxInputTokens: 272e3,
770
+ inputPer1m: 5,
771
+ outputPer1m: 30,
772
+ cachedInputPer1m: 0.5
773
+ },
774
+ {
775
+ inputPer1m: 10,
776
+ outputPer1m: 45,
777
+ cachedInputPer1m: 1
778
+ }
779
+ ],
780
+ contextWindow: 105e4
781
+ },
782
+ {
783
+ model: "gpt-5.5",
784
+ provider: "azure",
785
+ region: "us",
786
+ modality: "text",
787
+ currency: "USD",
788
+ asOf: "2026-07-27",
789
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
790
+ provenance: "litellm-catalog",
791
+ tiers: [
792
+ {
793
+ maxInputTokens: 272e3,
794
+ inputPer1m: 5.5,
795
+ outputPer1m: 33,
796
+ cachedInputPer1m: 0.55
797
+ },
798
+ {
799
+ inputPer1m: 11,
800
+ outputPer1m: 49.5,
801
+ cachedInputPer1m: 1.1
802
+ }
803
+ ],
804
+ contextWindow: 105e4
805
+ },
806
+ {
807
+ model: "gpt-5.5",
808
+ provider: "azure",
809
+ region: "eu",
810
+ modality: "text",
811
+ currency: "USD",
812
+ asOf: "2026-07-27",
813
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
814
+ provenance: "litellm-catalog",
815
+ tiers: [
816
+ {
817
+ maxInputTokens: 272e3,
818
+ inputPer1m: 5.5,
819
+ outputPer1m: 33,
820
+ cachedInputPer1m: 0.55
821
+ },
822
+ {
823
+ inputPer1m: 11,
824
+ outputPer1m: 49.5,
825
+ cachedInputPer1m: 1.1
826
+ }
827
+ ],
828
+ contextWindow: 105e4
829
+ },
830
+ {
831
+ model: "gpt-5.4",
832
+ provider: "azure",
833
+ region: "global",
834
+ modality: "text",
835
+ currency: "USD",
836
+ asOf: "2026-07-27",
837
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
838
+ provenance: "litellm-catalog",
839
+ tiers: [
840
+ {
841
+ maxInputTokens: 272e3,
842
+ inputPer1m: 2.5,
843
+ outputPer1m: 15,
844
+ cachedInputPer1m: 0.25
845
+ },
846
+ {
847
+ inputPer1m: 5,
848
+ outputPer1m: 22.5,
849
+ cachedInputPer1m: 0.5
850
+ }
851
+ ],
852
+ contextWindow: 105e4
853
+ },
854
+ {
855
+ model: "gpt-5.4",
856
+ provider: "azure",
857
+ region: "us",
858
+ modality: "text",
859
+ currency: "USD",
860
+ asOf: "2026-07-27",
861
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
862
+ provenance: "litellm-catalog",
863
+ tiers: [
864
+ {
865
+ inputPer1m: 2.75,
866
+ outputPer1m: 16.5,
867
+ cachedInputPer1m: 0.28
868
+ }
869
+ ],
870
+ contextWindow: 105e4
871
+ },
872
+ {
873
+ model: "gpt-5.4",
874
+ provider: "azure",
875
+ region: "eu",
876
+ modality: "text",
877
+ currency: "USD",
878
+ asOf: "2026-07-27",
879
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
880
+ provenance: "litellm-catalog",
881
+ tiers: [
882
+ {
883
+ inputPer1m: 2.75,
884
+ outputPer1m: 16.5,
885
+ cachedInputPer1m: 0.28
886
+ }
887
+ ],
888
+ contextWindow: 105e4
889
+ },
890
+ {
891
+ model: "gpt-5.6-terra",
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
+ maxInputTokens: 272e3,
902
+ inputPer1m: 2.5,
903
+ outputPer1m: 15,
904
+ cachedInputPer1m: 0.25
905
+ },
906
+ {
907
+ inputPer1m: 5,
908
+ outputPer1m: 22.5,
909
+ cachedInputPer1m: 0.5
910
+ }
911
+ ],
912
+ contextWindow: 105e4
913
+ },
914
+ {
915
+ model: "gpt-5.6-terra",
916
+ provider: "azure",
917
+ region: "eu",
918
+ modality: "text",
919
+ currency: "USD",
920
+ asOf: "2026-07-27",
921
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
922
+ provenance: "litellm-catalog",
923
+ tiers: [
924
+ {
925
+ maxInputTokens: 272e3,
926
+ inputPer1m: 2.75,
927
+ outputPer1m: 16.5,
928
+ cachedInputPer1m: 0.275
929
+ },
930
+ {
931
+ inputPer1m: 5.5,
932
+ outputPer1m: 24.75,
933
+ cachedInputPer1m: 0.55
934
+ }
935
+ ],
936
+ contextWindow: 105e4
937
+ },
938
+ {
939
+ model: "gpt-5",
940
+ provider: "azure",
941
+ region: "global",
942
+ modality: "text",
943
+ currency: "USD",
944
+ asOf: "2026-07-27",
945
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
946
+ provenance: "litellm-catalog",
947
+ tiers: [
948
+ {
949
+ inputPer1m: 1.25,
950
+ outputPer1m: 10,
951
+ cachedInputPer1m: 0.125
952
+ }
953
+ ],
954
+ contextWindow: 272e3
955
+ },
956
+ {
957
+ model: "gpt-5-mini",
958
+ provider: "azure",
959
+ region: "global",
960
+ modality: "text",
961
+ currency: "USD",
962
+ asOf: "2026-07-27",
963
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
964
+ provenance: "litellm-catalog",
965
+ tiers: [
966
+ {
967
+ inputPer1m: 0.25,
968
+ outputPer1m: 2,
969
+ cachedInputPer1m: 0.025
970
+ }
971
+ ],
972
+ contextWindow: 272e3
973
+ },
974
+ {
975
+ model: "gpt-5-nano",
976
+ provider: "azure",
977
+ region: "global",
978
+ modality: "text",
979
+ currency: "USD",
980
+ asOf: "2026-07-27",
981
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
982
+ provenance: "litellm-catalog",
983
+ tiers: [
984
+ {
985
+ inputPer1m: 0.05,
986
+ outputPer1m: 0.4,
987
+ cachedInputPer1m: 5e-3
988
+ }
989
+ ],
990
+ contextWindow: 272e3
991
+ },
992
+ {
993
+ model: "gpt-4.1",
994
+ provider: "azure",
995
+ region: "global",
996
+ modality: "text",
997
+ currency: "USD",
998
+ asOf: "2026-07-27",
999
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1000
+ provenance: "litellm-catalog",
1001
+ tiers: [
1002
+ {
1003
+ inputPer1m: 2,
1004
+ outputPer1m: 8,
1005
+ cachedInputPer1m: 0.5
1006
+ }
1007
+ ],
1008
+ batchMultiplier: 0.5,
1009
+ contextWindow: 1047576
1010
+ },
1011
+ {
1012
+ model: "gpt-4o",
1013
+ provider: "azure",
1014
+ region: "global",
1015
+ modality: "text",
1016
+ currency: "USD",
1017
+ asOf: "2026-07-27",
1018
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1019
+ provenance: "litellm-catalog",
1020
+ tiers: [
1021
+ {
1022
+ inputPer1m: 2.5,
1023
+ outputPer1m: 10,
1024
+ cachedInputPer1m: 1.25
1025
+ }
1026
+ ],
1027
+ contextWindow: 128e3
1028
+ },
1029
+ {
1030
+ model: "gpt-4o-mini",
1031
+ provider: "azure",
1032
+ region: "global",
1033
+ modality: "text",
1034
+ currency: "USD",
1035
+ asOf: "2026-07-27",
1036
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1037
+ provenance: "litellm-catalog",
1038
+ tiers: [
1039
+ {
1040
+ inputPer1m: 0.165,
1041
+ outputPer1m: 0.66,
1042
+ cachedInputPer1m: 0.075
1043
+ }
1044
+ ],
1045
+ contextWindow: 128e3,
1046
+ 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."
1047
+ },
1048
+ {
1049
+ model: "gemini-3.1-pro",
1050
+ provider: "gemini",
1051
+ aliases: [
1052
+ "gemini-3.1-pro-preview"
1053
+ ],
1054
+ modality: "text",
1055
+ currency: "USD",
1056
+ asOf: "2026-07-27",
1057
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1058
+ provenance: "vendor-pricing-page",
1059
+ tiers: [
1060
+ {
1061
+ maxInputTokens: 2e5,
1062
+ inputPer1m: 2,
1063
+ outputPer1m: 12,
1064
+ cachedInputPer1m: 0.2,
1065
+ reasoningOutputPer1m: 12
1066
+ },
1067
+ {
1068
+ inputPer1m: 4,
1069
+ outputPer1m: 18,
1070
+ cachedInputPer1m: 0.4,
1071
+ reasoningOutputPer1m: 18
1072
+ }
1073
+ ],
1074
+ batchMultiplier: 0.5,
1075
+ contextWindow: 1048576,
1076
+ notes: "Long-context tier: $2/$12 per 1M up to 200K prompt tokens, $4/$18 above it."
1077
+ },
1078
+ {
1079
+ model: "gemini-3-pro",
1080
+ provider: "gemini",
1081
+ aliases: [
1082
+ "gemini-3-pro-preview"
1083
+ ],
1084
+ modality: "text",
1085
+ currency: "USD",
1086
+ asOf: "2026-07-27",
1087
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1088
+ provenance: "vendor-pricing-page",
1089
+ tiers: [
1090
+ {
1091
+ maxInputTokens: 2e5,
1092
+ inputPer1m: 2,
1093
+ outputPer1m: 12,
1094
+ cachedInputPer1m: 0.2,
1095
+ reasoningOutputPer1m: 12
1096
+ },
1097
+ {
1098
+ inputPer1m: 4,
1099
+ outputPer1m: 18,
1100
+ cachedInputPer1m: 0.4,
1101
+ reasoningOutputPer1m: 18
1102
+ }
1103
+ ],
1104
+ batchMultiplier: 0.5,
1105
+ contextWindow: 1048576
1106
+ },
1107
+ {
1108
+ model: "gemini-3.6-flash",
1109
+ provider: "gemini",
1110
+ modality: "text",
1111
+ currency: "USD",
1112
+ asOf: "2026-07-27",
1113
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1114
+ provenance: "vendor-pricing-page",
1115
+ tiers: [
1116
+ {
1117
+ inputPer1m: 1.5,
1118
+ outputPer1m: 7.5,
1119
+ cachedInputPer1m: 0.15,
1120
+ reasoningOutputPer1m: 7.5
1121
+ }
1122
+ ],
1123
+ batchMultiplier: 0.5,
1124
+ contextWindow: 1048576,
1125
+ notes: "Released 2026-07-21. Output pricing dropped ~17% from Gemini 3.5 Flash ($9.00 -> $7.50 per 1M); input unchanged."
1126
+ },
1127
+ {
1128
+ model: "gemini-3.5-flash",
1129
+ provider: "gemini",
1130
+ modality: "text",
1131
+ currency: "USD",
1132
+ asOf: "2026-07-27",
1133
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1134
+ provenance: "vendor-pricing-page",
1135
+ tiers: [
1136
+ {
1137
+ inputPer1m: 1.5,
1138
+ outputPer1m: 9,
1139
+ cachedInputPer1m: 0.15,
1140
+ reasoningOutputPer1m: 9
1141
+ }
1142
+ ],
1143
+ batchMultiplier: 0.5,
1144
+ contextWindow: 1048576
1145
+ },
1146
+ {
1147
+ model: "gemini-3.5-flash-lite",
1148
+ provider: "gemini",
1149
+ modality: "text",
1150
+ currency: "USD",
1151
+ asOf: "2026-07-27",
1152
+ source: "https://ai.google.dev/gemini-api/docs/pricing",
1153
+ provenance: "litellm-catalog",
1154
+ tiers: [
1155
+ {
1156
+ inputPer1m: 0.3,
1157
+ outputPer1m: 2.5,
1158
+ cachedInputPer1m: 0.03,
1159
+ reasoningOutputPer1m: 2.5
1160
+ }
1161
+ ],
1162
+ batchMultiplier: 0.5,
1163
+ contextWindow: 1048576
1164
+ },
1165
+ {
1166
+ model: "gemini-3.1-flash-lite",
1167
+ provider: "gemini",
1168
+ modality: "text",
1169
+ currency: "USD",
1170
+ asOf: "2026-07-27",
1171
+ source: "https://ai.google.dev/gemini-api/docs/pricing#gemini-3.1-flash-lite",
1172
+ provenance: "litellm-catalog",
1173
+ tiers: [
1174
+ {
1175
+ inputPer1m: 0.25,
1176
+ outputPer1m: 1.5,
1177
+ cachedInputPer1m: 0.025,
1178
+ reasoningOutputPer1m: 1.5
1179
+ }
1180
+ ],
1181
+ batchMultiplier: 0.5,
1182
+ contextWindow: 1048576
1183
+ },
1184
+ {
1185
+ model: "gemini-3-flash",
1186
+ provider: "gemini",
1187
+ aliases: [
1188
+ "gemini-3-flash-preview"
1189
+ ],
1190
+ modality: "text",
1191
+ currency: "USD",
1192
+ asOf: "2026-07-27",
1193
+ source: "https://ai.google.dev/pricing/gemini-3",
1194
+ provenance: "litellm-catalog",
1195
+ tiers: [
1196
+ {
1197
+ inputPer1m: 0.5,
1198
+ outputPer1m: 3,
1199
+ cachedInputPer1m: 0.05,
1200
+ reasoningOutputPer1m: 3
1201
+ }
1202
+ ],
1203
+ contextWindow: 1048576
1204
+ },
1205
+ {
1206
+ model: "gemini-2.5-pro",
1207
+ provider: "gemini",
1208
+ modality: "text",
1209
+ currency: "USD",
1210
+ asOf: "2026-07-27",
1211
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1212
+ provenance: "litellm-catalog",
1213
+ tiers: [
1214
+ {
1215
+ maxInputTokens: 2e5,
1216
+ inputPer1m: 1.25,
1217
+ outputPer1m: 10,
1218
+ cachedInputPer1m: 0.125
1219
+ },
1220
+ {
1221
+ inputPer1m: 2.5,
1222
+ outputPer1m: 15,
1223
+ cachedInputPer1m: 0.25
1224
+ }
1225
+ ],
1226
+ contextWindow: 1048576
1227
+ },
1228
+ {
1229
+ model: "gemini-2.5-flash",
1230
+ provider: "gemini",
1231
+ modality: "text",
1232
+ currency: "USD",
1233
+ asOf: "2026-07-27",
1234
+ source: "https://ai.google.dev/gemini-api/docs/models#gemini-2.5-flash-preview",
1235
+ provenance: "litellm-catalog",
1236
+ tiers: [
1237
+ {
1238
+ inputPer1m: 0.3,
1239
+ outputPer1m: 2.5,
1240
+ cachedInputPer1m: 0.03,
1241
+ reasoningOutputPer1m: 2.5
1242
+ }
1243
+ ],
1244
+ contextWindow: 1048576
1245
+ },
1246
+ {
1247
+ model: "gemini-2.5-flash-lite",
1248
+ provider: "gemini",
1249
+ modality: "text",
1250
+ currency: "USD",
1251
+ asOf: "2026-07-27",
1252
+ source: "https://ai.google.dev/gemini-api/docs/models#gemini-2.5-flash-lite",
1253
+ provenance: "litellm-catalog",
1254
+ tiers: [
1255
+ {
1256
+ inputPer1m: 0.1,
1257
+ outputPer1m: 0.4,
1258
+ cachedInputPer1m: 0.01,
1259
+ reasoningOutputPer1m: 0.4
1260
+ }
1261
+ ],
1262
+ contextWindow: 1048576
1263
+ },
1264
+ {
1265
+ model: "gemini-2.0-flash",
1266
+ provider: "gemini",
1267
+ modality: "text",
1268
+ currency: "USD",
1269
+ asOf: "2026-07-27",
1270
+ source: "https://ai.google.dev/pricing#2_0flash",
1271
+ provenance: "litellm-catalog",
1272
+ tiers: [
1273
+ {
1274
+ inputPer1m: 0.1,
1275
+ outputPer1m: 0.4,
1276
+ cachedInputPer1m: 0.025
1277
+ }
1278
+ ],
1279
+ contextWindow: 1048576,
1280
+ notes: "Gemini Developer API price. Vertex AI lists $0.15/$0.60 per 1M for the same model \u2014 see the vertex entry."
1281
+ },
1282
+ {
1283
+ model: "gemini-2.0-flash-lite",
1284
+ provider: "gemini",
1285
+ modality: "text",
1286
+ currency: "USD",
1287
+ asOf: "2026-07-27",
1288
+ source: "https://ai.google.dev/gemini-api/docs/pricing#gemini-2.0-flash-lite",
1289
+ provenance: "litellm-catalog",
1290
+ tiers: [
1291
+ {
1292
+ inputPer1m: 0.075,
1293
+ outputPer1m: 0.3,
1294
+ cachedInputPer1m: 0.01875
1295
+ }
1296
+ ],
1297
+ contextWindow: 1048576
1298
+ },
1299
+ {
1300
+ model: "gemini-2.0-flash",
1301
+ provider: "vertex",
1302
+ modality: "text",
1303
+ currency: "USD",
1304
+ asOf: "2026-07-27",
1305
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1306
+ provenance: "vendor-pricing-page",
1307
+ tiers: [
1308
+ {
1309
+ inputPer1m: 0.15,
1310
+ outputPer1m: 0.6
1311
+ }
1312
+ ],
1313
+ batchMultiplier: 0.5,
1314
+ notes: "Vertex AI lists $0.15/$0.60 per 1M; the Gemini Developer API lists $0.10/$0.40 for the same model."
1315
+ },
1316
+ {
1317
+ model: "gemini-3.1-pro",
1318
+ provider: "vertex",
1319
+ aliases: [
1320
+ "gemini-3.1-pro-preview"
1321
+ ],
1322
+ modality: "text",
1323
+ currency: "USD",
1324
+ asOf: "2026-07-27",
1325
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1326
+ provenance: "vendor-pricing-page",
1327
+ tiers: [
1328
+ {
1329
+ maxInputTokens: 2e5,
1330
+ inputPer1m: 2,
1331
+ outputPer1m: 12,
1332
+ cachedInputPer1m: 0.2,
1333
+ reasoningOutputPer1m: 12
1334
+ },
1335
+ {
1336
+ inputPer1m: 4,
1337
+ outputPer1m: 18,
1338
+ cachedInputPer1m: 0.4,
1339
+ reasoningOutputPer1m: 18
1340
+ }
1341
+ ],
1342
+ batchMultiplier: 0.5,
1343
+ contextWindow: 1048576
1344
+ },
1345
+ {
1346
+ model: "gemini-3.6-flash",
1347
+ provider: "vertex",
1348
+ modality: "text",
1349
+ currency: "USD",
1350
+ asOf: "2026-07-27",
1351
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1352
+ provenance: "vendor-pricing-page",
1353
+ tiers: [
1354
+ {
1355
+ inputPer1m: 1.5,
1356
+ outputPer1m: 7.5,
1357
+ cachedInputPer1m: 0.15,
1358
+ reasoningOutputPer1m: 7.5
1359
+ }
1360
+ ],
1361
+ batchMultiplier: 0.5,
1362
+ contextWindow: 1048576
1363
+ },
1364
+ {
1365
+ model: "gemini-2.5-pro",
1366
+ provider: "vertex",
1367
+ modality: "text",
1368
+ currency: "USD",
1369
+ asOf: "2026-07-27",
1370
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1371
+ provenance: "vendor-pricing-page",
1372
+ tiers: [
1373
+ {
1374
+ maxInputTokens: 2e5,
1375
+ inputPer1m: 1.25,
1376
+ outputPer1m: 10,
1377
+ cachedInputPer1m: 0.13
1378
+ },
1379
+ {
1380
+ inputPer1m: 2.5,
1381
+ outputPer1m: 15,
1382
+ cachedInputPer1m: 0.25
1383
+ }
1384
+ ],
1385
+ batchMultiplier: 0.5,
1386
+ contextWindow: 1048576
1387
+ },
1388
+ {
1389
+ model: "gemini-2.5-flash",
1390
+ provider: "vertex",
1391
+ modality: "text",
1392
+ currency: "USD",
1393
+ asOf: "2026-07-27",
1394
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1395
+ provenance: "vendor-pricing-page",
1396
+ tiers: [
1397
+ {
1398
+ inputPer1m: 0.3,
1399
+ outputPer1m: 2.5,
1400
+ cachedInputPer1m: 0.03,
1401
+ reasoningOutputPer1m: 2.5
1402
+ }
1403
+ ],
1404
+ batchMultiplier: 0.5,
1405
+ contextWindow: 1048576
1406
+ },
1407
+ {
1408
+ model: "claude-sonnet-4-6",
1409
+ provider: "openrouter",
1410
+ modality: "text",
1411
+ currency: "USD",
1412
+ asOf: "2026-07-27",
1413
+ source: "https://openrouter.ai/anthropic/claude-sonnet-4.6",
1414
+ provenance: "litellm-catalog",
1415
+ tiers: [
1416
+ {
1417
+ maxInputTokens: 2e5,
1418
+ inputPer1m: 3,
1419
+ outputPer1m: 15,
1420
+ cachedInputPer1m: 0.3,
1421
+ cacheWritePer1m: 3.75
1422
+ },
1423
+ {
1424
+ inputPer1m: 6,
1425
+ outputPer1m: 22.5,
1426
+ cachedInputPer1m: 0.6,
1427
+ cacheWritePer1m: 7.5
1428
+ }
1429
+ ],
1430
+ contextWindow: 1e6
1431
+ },
1432
+ {
1433
+ model: "claude-haiku-4-5",
1434
+ provider: "openrouter",
1435
+ modality: "text",
1436
+ currency: "USD",
1437
+ asOf: "2026-07-27",
1438
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1439
+ provenance: "litellm-catalog",
1440
+ tiers: [
1441
+ {
1442
+ inputPer1m: 1,
1443
+ outputPer1m: 5,
1444
+ cachedInputPer1m: 0.1,
1445
+ cacheWritePer1m: 1.25
1446
+ }
1447
+ ],
1448
+ contextWindow: 2e5
1449
+ },
1450
+ {
1451
+ model: "gpt-5",
1452
+ provider: "openrouter",
1453
+ modality: "text",
1454
+ currency: "USD",
1455
+ asOf: "2026-07-27",
1456
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1457
+ provenance: "litellm-catalog",
1458
+ tiers: [
1459
+ {
1460
+ inputPer1m: 1.25,
1461
+ outputPer1m: 10,
1462
+ cachedInputPer1m: 0.125
1463
+ }
1464
+ ],
1465
+ contextWindow: 272e3
1466
+ },
1467
+ {
1468
+ model: "gpt-5-mini",
1469
+ provider: "openrouter",
1470
+ modality: "text",
1471
+ currency: "USD",
1472
+ asOf: "2026-07-27",
1473
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1474
+ provenance: "litellm-catalog",
1475
+ tiers: [
1476
+ {
1477
+ inputPer1m: 0.25,
1478
+ outputPer1m: 2,
1479
+ cachedInputPer1m: 0.025
1480
+ }
1481
+ ],
1482
+ contextWindow: 272e3
1483
+ },
1484
+ {
1485
+ model: "gemini-3.1-pro",
1486
+ provider: "openrouter",
1487
+ aliases: [
1488
+ "gemini-3.1-pro-preview"
1489
+ ],
1490
+ modality: "text",
1491
+ currency: "USD",
1492
+ asOf: "2026-07-27",
1493
+ source: "https://openrouter.ai/google/gemini-3.1-pro-preview",
1494
+ provenance: "litellm-catalog",
1495
+ tiers: [
1496
+ {
1497
+ maxInputTokens: 2e5,
1498
+ inputPer1m: 2,
1499
+ outputPer1m: 12,
1500
+ cachedInputPer1m: 0.2
1501
+ },
1502
+ {
1503
+ inputPer1m: 4,
1504
+ outputPer1m: 18,
1505
+ cachedInputPer1m: 0.4,
1506
+ cacheWritePer1m: 0.25
1507
+ }
1508
+ ],
1509
+ contextWindow: 1048576
1510
+ },
1511
+ {
1512
+ model: "text-embedding-3-small",
1513
+ provider: "openai",
1514
+ modality: "embedding",
1515
+ currency: "USD",
1516
+ asOf: "2026-07-27",
1517
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1518
+ provenance: "litellm-catalog",
1519
+ tiers: [
1520
+ {
1521
+ inputPer1m: 0.02,
1522
+ outputPer1m: 0
1523
+ }
1524
+ ],
1525
+ batchMultiplier: 0.5,
1526
+ contextWindow: 8191
1527
+ },
1528
+ {
1529
+ model: "text-embedding-3-large",
1530
+ provider: "openai",
1531
+ modality: "embedding",
1532
+ currency: "USD",
1533
+ asOf: "2026-07-27",
1534
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1535
+ provenance: "litellm-catalog",
1536
+ tiers: [
1537
+ {
1538
+ inputPer1m: 0.13,
1539
+ outputPer1m: 0
1540
+ }
1541
+ ],
1542
+ batchMultiplier: 0.5,
1543
+ contextWindow: 8191
1544
+ },
1545
+ {
1546
+ model: "gemini-embedding-001",
1547
+ provider: "gemini",
1548
+ modality: "embedding",
1549
+ currency: "USD",
1550
+ asOf: "2026-07-27",
1551
+ source: "https://ai.google.dev/gemini-api/docs/embeddings#model-versions",
1552
+ provenance: "litellm-catalog",
1553
+ tiers: [
1554
+ {
1555
+ inputPer1m: 0.15,
1556
+ outputPer1m: 0
1557
+ }
1558
+ ],
1559
+ contextWindow: 2048
1560
+ },
1561
+ {
1562
+ model: "dall-e-3",
1563
+ provider: "openai",
1564
+ modality: "image",
1565
+ currency: "USD",
1566
+ asOf: "2026-07-27",
1567
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1568
+ provenance: "litellm-catalog",
1569
+ rates: [
1570
+ {
1571
+ unit: "per_image",
1572
+ amount: 0.04,
1573
+ variant: "1024x1024 standard"
1574
+ }
1575
+ ]
1576
+ },
1577
+ {
1578
+ model: "gemini-3-pro-image",
1579
+ provider: "gemini",
1580
+ modality: "image",
1581
+ currency: "USD",
1582
+ asOf: "2026-07-27",
1583
+ source: "https://ai.google.dev/gemini-api/docs/pricing",
1584
+ provenance: "litellm-catalog",
1585
+ rates: [
1586
+ {
1587
+ unit: "per_image",
1588
+ amount: 0.134,
1589
+ variant: "default output resolution"
1590
+ }
1591
+ ],
1592
+ 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."
1593
+ },
1594
+ {
1595
+ model: "imagen-4.0-generate-001",
1596
+ provider: "vertex",
1597
+ modality: "image",
1598
+ currency: "USD",
1599
+ asOf: "2026-07-27",
1600
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1601
+ provenance: "litellm-catalog",
1602
+ rates: [
1603
+ {
1604
+ unit: "per_image",
1605
+ amount: 0.04
1606
+ }
1607
+ ]
1608
+ },
1609
+ {
1610
+ model: "veo-3.1-generate-001",
1611
+ provider: "gemini",
1612
+ modality: "video",
1613
+ currency: "USD",
1614
+ asOf: "2026-07-27",
1615
+ source: "https://ai.google.dev/gemini-api/docs/video",
1616
+ provenance: "litellm-catalog",
1617
+ rates: [
1618
+ {
1619
+ unit: "per_second",
1620
+ amount: 0.4
1621
+ }
1622
+ ]
1623
+ },
1624
+ {
1625
+ model: "veo-3.1-generate-001",
1626
+ provider: "vertex",
1627
+ modality: "video",
1628
+ currency: "USD",
1629
+ asOf: "2026-07-27",
1630
+ source: "https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/veo",
1631
+ provenance: "litellm-catalog",
1632
+ rates: [
1633
+ {
1634
+ unit: "per_second",
1635
+ amount: 0.4
1636
+ }
1637
+ ]
1638
+ },
1639
+ {
1640
+ model: "tts-1",
1641
+ provider: "openai",
1642
+ modality: "speech",
1643
+ currency: "USD",
1644
+ asOf: "2026-07-27",
1645
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1646
+ provenance: "litellm-catalog",
1647
+ rates: [
1648
+ {
1649
+ unit: "per_character",
1650
+ amount: 15e-6
1651
+ }
1652
+ ],
1653
+ notes: "$15 per 1M characters."
1654
+ },
1655
+ {
1656
+ model: "tts-1-hd",
1657
+ provider: "openai",
1658
+ modality: "speech",
1659
+ currency: "USD",
1660
+ asOf: "2026-07-27",
1661
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1662
+ provenance: "litellm-catalog",
1663
+ rates: [
1664
+ {
1665
+ unit: "per_character",
1666
+ amount: 3e-5
1667
+ }
1668
+ ],
1669
+ notes: "$30 per 1M characters."
1670
+ },
1671
+ {
1672
+ model: "whisper-1",
1673
+ provider: "openai",
1674
+ modality: "transcription",
1675
+ currency: "USD",
1676
+ asOf: "2026-07-27",
1677
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1678
+ provenance: "litellm-catalog",
1679
+ rates: [
1680
+ {
1681
+ unit: "per_audio_minute",
1682
+ amount: 6e-3
1683
+ }
1684
+ ],
1685
+ notes: "litellm records $0.0001 per audio second; $0.006/minute is that rate x 60."
1686
+ }
1687
+ ]
1688
+ };
1689
+
1690
+ // src/core/router/pricing.ts
1691
+ var DATASET = pricing_data_default;
1692
+ function normalizeForPricing(id) {
1693
+ let s = id.trim().toLowerCase();
1694
+ s = s.replace(/^models\//, "");
1695
+ const slash = s.lastIndexOf("/");
1696
+ if (slash !== -1) s = s.slice(slash + 1);
1697
+ const tag = s.search(/[:@]/);
1698
+ if (tag !== -1) s = s.slice(0, tag);
1699
+ s = s.replace(/-latest$/, "");
1700
+ s = s.replace(/-preview(?:-\d{2}-\d{2})?$/, "");
1701
+ s = s.replace(/-\d{4}-\d{2}-\d{2}$/, "");
1702
+ s = s.replace(/-\d{8}$/, "");
1703
+ s = s.replace(/-preview$/, "");
1704
+ return s;
1705
+ }
1706
+ function indexKey(model, provider, region) {
1707
+ return `${provider}|${normalizeForPricing(model)}|${region ?? ""}`;
1708
+ }
1709
+ var INDEX = /* @__PURE__ */ new Map();
1710
+ for (const entry of DATASET.entries) {
1711
+ for (const name of [entry.model, ...entry.aliases ?? []]) {
1712
+ const withRegion = indexKey(name, entry.provider, entry.region);
1713
+ if (!INDEX.has(withRegion)) INDEX.set(withRegion, entry);
1714
+ const bare = indexKey(name, entry.provider);
1715
+ const existing = INDEX.get(bare);
1716
+ if (!existing || existing.region && existing.region !== "global" && entry.region === "global") {
1717
+ INDEX.set(bare, entry);
1718
+ }
1719
+ }
1720
+ }
1721
+ function findPricing(modelId, provider, opts = {}) {
1722
+ const ids = [modelId, opts.baseModelId].filter((x) => !!x);
1723
+ const providers = [provider, ...opts.fallbackProviders ?? []];
1724
+ for (const p of providers) {
1725
+ for (const id of ids) {
1726
+ const hit = (opts.region ? INDEX.get(indexKey(id, p, opts.region)) : void 0) ?? INDEX.get(indexKey(id, p));
1727
+ if (hit) return { entry: hit, matchedProvider: p, viaFallback: p !== provider };
1728
+ }
1729
+ }
1730
+ return null;
1731
+ }
1732
+ function tierFor(entry, inputTokens = 0) {
1733
+ const tiers = entry.tiers;
1734
+ if (!tiers?.length) return null;
1735
+ for (const t of tiers) {
1736
+ if (t.maxInputTokens === void 0 || inputTokens <= t.maxInputTokens) return t;
1737
+ }
1738
+ return tiers[tiers.length - 1] ?? null;
1739
+ }
1740
+ var PER_1M_TO_PER_1K = 1 / 1e3;
1741
+ function tokenRatesPer1k(entry, opts = {}) {
1742
+ const tier = tierFor(entry, opts.inputTokens ?? 0);
1743
+ if (!tier) return null;
1744
+ const mult = (opts.batch ? entry.batchMultiplier ?? 1 : 1) * PER_1M_TO_PER_1K;
1745
+ const out = {
1746
+ input: tier.inputPer1m * mult,
1747
+ output: tier.outputPer1m * mult
1748
+ };
1749
+ if (tier.cachedInputPer1m !== void 0) out.cachedInput = tier.cachedInputPer1m * mult;
1750
+ if (tier.cacheWritePer1m !== void 0) out.cacheWrite = tier.cacheWritePer1m * mult;
1751
+ if (tier.reasoningOutputPer1m !== void 0) out.reasoningOutput = tier.reasoningOutputPer1m * mult;
1752
+ return out;
1753
+ }
1754
+ var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "0.0.0.0", "::1", "[::1]"]);
1755
+ function isLoopbackOrPrivateHost(url) {
1756
+ if (!url) return false;
1757
+ try {
1758
+ const host = new URL(url).hostname.toLowerCase().replace(/^\[|\]$/g, "");
1759
+ if (LOOPBACK_HOSTS.has(host) || LOOPBACK_HOSTS.has(`[${host}]`)) return true;
1760
+ if (host.endsWith(".local")) return true;
1761
+ if (/^127\./.test(host)) return true;
1762
+ if (/^10\./.test(host)) return true;
1763
+ if (/^192\.168\./.test(host)) return true;
1764
+ if (/^172\.(1[6-9]|2\d|3[01])\./.test(host)) return true;
1765
+ return false;
1766
+ } catch {
1767
+ return false;
1768
+ }
1769
+ }
1770
+ function isLocalEndpoint(cfg) {
1771
+ if (typeof cfg.local === "boolean") return cfg.local;
1772
+ if (cfg.type === "ollama") return true;
1773
+ if (cfg.type === "openai-compatible") return isLoopbackOrPrivateHost(cfg.baseUrl);
1774
+ return false;
1775
+ }
1776
+ var UNKNOWN = { input: 0, output: 0, unknown: true, free: false };
1777
+ var FREE = { input: 0, output: 0, unknown: false, free: true };
1778
+ function resolvePricing(model, opts = {}) {
1779
+ if (model.isLocal) return FREE;
1780
+ const fallbackProviders = model.provider === "azure" ? ["openai"] : model.provider === "gemini" ? ["vertex"] : [];
1781
+ const match = findPricing(model.id, model.provider, {
1782
+ region: opts.region,
1783
+ baseModelId: model.baseModelId,
1784
+ fallbackProviders
1785
+ });
1786
+ if (!match) return UNKNOWN;
1787
+ const rates = tokenRatesPer1k(match.entry, { inputTokens: opts.inputTokens, batch: opts.batch });
1788
+ if (!rates) return UNKNOWN;
1789
+ return {
1790
+ input: rates.input,
1791
+ output: rates.output,
1792
+ unknown: false,
1793
+ free: false,
1794
+ entry: match.entry,
1795
+ ...match.viaFallback ? { estimatedFromProvider: match.matchedProvider } : {}
1796
+ };
1797
+ }
1798
+ function withResolvedPricing(model, opts = {}) {
1799
+ const p = resolvePricing(model, opts);
1800
+ return {
1801
+ ...model,
1802
+ inputCostPer1kTokens: p.input,
1803
+ outputCostPer1kTokens: p.output,
1804
+ ...p.unknown ? { pricingUnknown: true } : { pricingUnknown: false }
1805
+ };
1806
+ }
1807
+ function isPricingUnknown(model) {
1808
+ return model.pricingUnknown === true && !model.isLocal;
1809
+ }
1810
+ var BLENDED_COST_CEILING = 0.05;
1811
+ function blendedCostPer1k(model) {
1812
+ if (isPricingUnknown(model)) return BLENDED_COST_CEILING;
1813
+ return model.inputCostPer1kTokens + model.outputCostPer1kTokens * 2;
1814
+ }
1815
+ var DISAGREEMENT_THRESHOLD = 0.02;
1816
+ function reconcilePrice(model, live) {
1817
+ const baseline = resolvePricing(model);
1818
+ const liveIsZero = !(live.input > 0) && !(live.output > 0);
1819
+ if (liveIsZero && !model.isLocal) {
1820
+ return { input: baseline.input, output: baseline.output, accepted: false };
1821
+ }
1822
+ if (baseline.unknown || !baseline.entry) {
1823
+ return { input: live.input, output: live.output, accepted: true };
1824
+ }
1825
+ const dsBlend = baseline.input + baseline.output * 2;
1826
+ const liveBlend = live.input + live.output * 2;
1827
+ const ratio = dsBlend > 0 ? liveBlend / dsBlend : Number.POSITIVE_INFINITY;
1828
+ const material = dsBlend > 0 && Math.abs(ratio - 1) > DISAGREEMENT_THRESHOLD;
1829
+ return {
1830
+ input: live.input,
1831
+ output: live.output,
1832
+ accepted: true,
1833
+ ...material ? {
1834
+ disagreement: {
1835
+ modelId: model.id,
1836
+ provider: model.provider,
1837
+ dataset: { input: baseline.input, output: baseline.output },
1838
+ live: { input: live.input, output: live.output },
1839
+ ratio: Math.round(ratio * 1e3) / 1e3,
1840
+ datasetAsOf: baseline.entry.asOf,
1841
+ datasetSource: baseline.entry.source
1842
+ }
1843
+ } : {}
1844
+ };
1845
+ }
1846
+
195
1847
  // src/constants.ts
196
- var CASCADE_VERSION = "0.48.0";
1848
+ var CASCADE_VERSION = "0.49.0";
197
1849
  var CASCADE_CONFIG_DIR = ".cascade";
198
1850
  var CASCADE_MD_FILE = "CASCADE.md";
199
1851
  var CASCADE_IGNORE_FILE = ".cascadeignore";
@@ -542,6 +2194,13 @@ var MODELS = {
542
2194
  for (const _m of Object.values(MODELS)) {
543
2195
  if (_m.supportsToolUse === void 0) _m.supportsToolUse = !_m.isLocal;
544
2196
  }
2197
+ for (const _m of Object.values(MODELS)) {
2198
+ const priced = resolvePricing(_m);
2199
+ if (priced.unknown || priced.free || priced.estimatedFromProvider) continue;
2200
+ _m.inputCostPer1kTokens = priced.input;
2201
+ _m.outputCostPer1kTokens = priced.output;
2202
+ _m.pricingUnknown = false;
2203
+ }
545
2204
  var T1_MODEL_PRIORITY = [
546
2205
  "gpt-5.5",
547
2206
  "gpt-5.4",
@@ -632,21 +2291,49 @@ var PROVIDER_DISPLAY_NAMES = {
632
2291
 
633
2292
  // src/utils/cost.ts
634
2293
  function resolveModelPricing(model) {
635
- let input = model.inputCostPer1kTokens;
636
- let output = model.outputCostPer1kTokens;
637
- if (input === 0 && output === 0 && model.id && !model.isLocal) {
2294
+ if (model.isLocal) return { input: 0, output: 0, unknown: false };
2295
+ if (model.inputCostPer1kTokens > 0 || model.outputCostPer1kTokens > 0) {
2296
+ return {
2297
+ input: model.inputCostPer1kTokens,
2298
+ output: model.outputCostPer1kTokens,
2299
+ unknown: false
2300
+ };
2301
+ }
2302
+ const fromDataset = resolvePricing(model);
2303
+ if (!fromDataset.unknown) {
2304
+ return {
2305
+ input: fromDataset.input,
2306
+ output: fromDataset.output,
2307
+ unknown: false,
2308
+ ...fromDataset.estimatedFromProvider ? { estimatedFromProvider: fromDataset.estimatedFromProvider } : {}
2309
+ };
2310
+ }
2311
+ if (model.id) {
638
2312
  const known = Object.values(MODELS).find((m) => m.id === model.id && !m.isLocal);
639
- if (known) {
640
- input = known.inputCostPer1kTokens;
641
- output = known.outputCostPer1kTokens;
2313
+ if (known && (known.inputCostPer1kTokens > 0 || known.outputCostPer1kTokens > 0)) {
2314
+ return {
2315
+ input: known.inputCostPer1kTokens,
2316
+ output: known.outputCostPer1kTokens,
2317
+ unknown: false
2318
+ };
642
2319
  }
643
2320
  }
644
- return { input, output };
2321
+ return { input: 0, output: 0, unknown: true };
645
2322
  }
646
2323
  function calculateCost(inputTokens, outputTokens, model) {
647
2324
  const { input, output } = resolveModelPricing(model);
648
2325
  return inputTokens / 1e3 * input + outputTokens / 1e3 * output;
649
2326
  }
2327
+ function buildTokenUsage(inputTokens, outputTokens, model) {
2328
+ const { input, output, unknown } = resolveModelPricing(model);
2329
+ return {
2330
+ inputTokens,
2331
+ outputTokens,
2332
+ totalTokens: inputTokens + outputTokens,
2333
+ estimatedCostUsd: inputTokens / 1e3 * input + outputTokens / 1e3 * output,
2334
+ ...unknown ? { costUnknown: true } : {}
2335
+ };
2336
+ }
650
2337
 
651
2338
  // src/providers/base.ts
652
2339
  var BaseProvider = class {
@@ -666,12 +2353,7 @@ var BaseProvider = class {
666
2353
  return calculateCost(inputTokens, outputTokens, this.model);
667
2354
  }
668
2355
  makeUsage(inputTokens, outputTokens) {
669
- return {
670
- inputTokens,
671
- outputTokens,
672
- totalTokens: inputTokens + outputTokens,
673
- estimatedCostUsd: this.estimateCost(inputTokens, outputTokens)
674
- };
2356
+ return buildTokenUsage(inputTokens, outputTokens, this.model);
675
2357
  }
676
2358
  };
677
2359
 
@@ -840,7 +2522,7 @@ var AnthropicProvider = class extends BaseProvider {
840
2522
  return data.data.filter((m) => isChatModel(m.id)).map((m) => {
841
2523
  const known = Object.values(MODELS).find((km) => km.id === m.id && km.provider === "anthropic");
842
2524
  if (known) return known;
843
- return {
2525
+ return withResolvedPricing({
844
2526
  id: m.id,
845
2527
  name: m.display_name || m.id,
846
2528
  provider: "anthropic",
@@ -851,7 +2533,7 @@ var AnthropicProvider = class extends BaseProvider {
851
2533
  maxOutputTokens: 8e3,
852
2534
  supportsStreaming: true,
853
2535
  isLocal: false
854
- };
2536
+ });
855
2537
  });
856
2538
  } catch {
857
2539
  return Object.values(MODELS).filter((m) => m.provider === "anthropic");
@@ -1055,7 +2737,7 @@ var OpenAIProvider = class extends BaseProvider {
1055
2737
  return response.data.filter((m) => isChatModel(m.id)).map((m) => {
1056
2738
  const known = Object.values(MODELS).find((km) => km.id === m.id && km.provider === "openai");
1057
2739
  if (known) return known;
1058
- return {
2740
+ return withResolvedPricing({
1059
2741
  id: m.id,
1060
2742
  name: m.id,
1061
2743
  provider: "openai",
@@ -1066,7 +2748,7 @@ var OpenAIProvider = class extends BaseProvider {
1066
2748
  maxOutputTokens: 4e3,
1067
2749
  supportsStreaming: true,
1068
2750
  isLocal: false
1069
- };
2751
+ });
1070
2752
  });
1071
2753
  } catch {
1072
2754
  return Object.values(MODELS).filter((m) => m.provider === "openai");
@@ -1162,6 +2844,10 @@ function azureModelForDeployment(cfg) {
1162
2844
  const baseModelId = cfg.model?.trim() || inferAzureBaseModel(id) || void 0;
1163
2845
  const base = baseModelId ? MODELS[baseModelId] : void 0;
1164
2846
  if (base) {
2847
+ const azurePrice = resolvePricing(
2848
+ { id, provider: "azure", isLocal: false, baseModelId },
2849
+ { region: cfg.region }
2850
+ );
1165
2851
  return {
1166
2852
  ...base,
1167
2853
  id,
@@ -1170,7 +2856,12 @@ function azureModelForDeployment(cfg) {
1170
2856
  provider: "azure",
1171
2857
  baseModelId,
1172
2858
  // real identity for benchmark + live pricing
1173
- supportsToolUse: base.supportsToolUse ?? true
2859
+ supportsToolUse: base.supportsToolUse ?? true,
2860
+ ...azurePrice.unknown ? {} : {
2861
+ inputCostPer1kTokens: azurePrice.input,
2862
+ outputCostPer1kTokens: azurePrice.output,
2863
+ pricingUnknown: false
2864
+ }
1174
2865
  };
1175
2866
  }
1176
2867
  return {
@@ -1333,7 +3024,7 @@ var GeminiProvider = class extends BaseProvider {
1333
3024
  (km) => km.id === id && km.provider === "gemini"
1334
3025
  );
1335
3026
  if (known) return known;
1336
- return {
3027
+ return withResolvedPricing({
1337
3028
  id,
1338
3029
  name: m.displayName || id,
1339
3030
  provider: "gemini",
@@ -1344,7 +3035,7 @@ var GeminiProvider = class extends BaseProvider {
1344
3035
  maxOutputTokens: m.outputTokenLimit || 8e3,
1345
3036
  supportsStreaming: true,
1346
3037
  isLocal: false
1347
- };
3038
+ });
1348
3039
  });
1349
3040
  } catch {
1350
3041
  return Object.values(MODELS).filter((m) => m.provider === "gemini");
@@ -1691,9 +3382,10 @@ var OllamaProvider = class extends BaseProvider {
1691
3382
  return supportedKeywords.some((k) => name.includes(k)) && isChatModel(name);
1692
3383
  });
1693
3384
  const shows = await Promise.all(entries.map((m) => this.showModel(m.name)));
3385
+ const local = isLocalEndpoint({ ...this.config, type: "ollama" });
1694
3386
  return entries.map((m, i) => {
1695
3387
  const show = shows[i];
1696
- return {
3388
+ return withResolvedPricing({
1697
3389
  id: m.name,
1698
3390
  name: m.name,
1699
3391
  provider: "ollama",
@@ -1703,10 +3395,10 @@ var OllamaProvider = class extends BaseProvider {
1703
3395
  outputCostPer1kTokens: 0,
1704
3396
  maxOutputTokens: 4e3,
1705
3397
  supportsStreaming: true,
1706
- isLocal: true,
3398
+ isLocal: local,
1707
3399
  supportsToolUse: show?.tools ?? isToolCapable(m.name),
1708
3400
  minSizeB: this.parseSizeB(m.details?.parameter_size)
1709
- };
3401
+ });
1710
3402
  });
1711
3403
  } catch {
1712
3404
  return [];
@@ -1809,7 +3501,8 @@ var OpenAICompatibleProvider = class extends OpenAIProvider {
1809
3501
  }).filter((x) => typeof x === "string" && x.length > 0);
1810
3502
  if (ids.length === 0) return [this.model];
1811
3503
  const chatIds = ids.filter((id) => isChatModel(id));
1812
- return (chatIds.length ? chatIds : ids).map((id) => ({
3504
+ const local = isLocalEndpoint(this.config);
3505
+ return (chatIds.length ? chatIds : ids).map((id) => withResolvedPricing({
1813
3506
  id,
1814
3507
  name: id,
1815
3508
  provider: "openai-compatible",
@@ -1819,7 +3512,7 @@ var OpenAICompatibleProvider = class extends OpenAIProvider {
1819
3512
  outputCostPer1kTokens: 0,
1820
3513
  maxOutputTokens: 4e3,
1821
3514
  supportsStreaming: true,
1822
- isLocal: false
3515
+ isLocal: local
1823
3516
  }));
1824
3517
  }
1825
3518
  async isAvailable() {
@@ -2034,7 +3727,7 @@ var ModelSelector = class {
2034
3727
  else if (this.availableProviders.size === 1) providerStr = Array.from(this.availableProviders)[0];
2035
3728
  }
2036
3729
  if (providerStr && this.availableProviders.has(providerStr)) {
2037
- const dynamicModel = {
3730
+ const dynamicModel = withResolvedPricing({
2038
3731
  id: actualId,
2039
3732
  name: actualId,
2040
3733
  provider: providerStr,
@@ -2045,7 +3738,7 @@ var ModelSelector = class {
2045
3738
  maxOutputTokens: 8e3,
2046
3739
  supportsStreaming: true,
2047
3740
  isLocal: providerStr === "ollama"
2048
- };
3741
+ });
2049
3742
  this.addDynamicModel(dynamicModel);
2050
3743
  return dynamicModel;
2051
3744
  }
@@ -2437,6 +4130,8 @@ var LiveDataProvider = class {
2437
4130
  snapshot = null;
2438
4131
  prices = /* @__PURE__ */ new Map();
2439
4132
  capabilities = /* @__PURE__ */ new Map();
4133
+ /** Dataset-vs-live price mismatches, deduped by `provider:modelId`. */
4134
+ disagreements = /* @__PURE__ */ new Map();
2440
4135
  source = "bundled";
2441
4136
  fetchedAt = 0;
2442
4137
  loaded = false;
@@ -2590,14 +4285,45 @@ var LiveDataProvider = class {
2590
4285
  /**
2591
4286
  * Returns a price-corrected copy of each model when live pricing is known,
2592
4287
  * leaving the original untouched (so the shared catalog is never mutated).
4288
+ *
4289
+ * Reconciliation policy (see reconcilePrice in pricing.ts): the bundled
4290
+ * dataset is the authoritative baseline, and a live quote overrides it
4291
+ * because it is fresher by construction — but the disagreement is RECORDED,
4292
+ * not swallowed. A dataset/live mismatch is the best signal available that
4293
+ * the committed prices have gone stale, so it must be visible rather than
4294
+ * silently resolved in either direction. A live quote of $0 for a non-local
4295
+ * model is rejected outright: that is the very failure mode this change
4296
+ * exists to prevent, and a marketplace's free-tier alias must never zero out
4297
+ * the price of the paid model Cascade is actually calling.
2593
4298
  */
2594
4299
  applyLivePricing(models) {
2595
4300
  return models.map((m) => {
2596
4301
  const p = this.getLivePrice(m.baseModelId ?? m.id);
2597
4302
  if (!p) return m;
2598
- return { ...m, inputCostPer1kTokens: p.input, outputCostPer1kTokens: p.output };
4303
+ const reconciled = reconcilePrice(m, p);
4304
+ if (reconciled.disagreement) this.recordDisagreement(reconciled.disagreement);
4305
+ if (!reconciled.accepted) return m;
4306
+ return {
4307
+ ...m,
4308
+ inputCostPer1kTokens: reconciled.input,
4309
+ outputCostPer1kTokens: reconciled.output,
4310
+ pricingUnknown: false
4311
+ };
2599
4312
  });
2600
4313
  }
4314
+ recordDisagreement(d) {
4315
+ const key = `${d.provider}:${d.modelId}`;
4316
+ if (this.disagreements.has(key)) return;
4317
+ this.disagreements.set(key, d);
4318
+ }
4319
+ /**
4320
+ * Dataset-vs-live price mismatches seen this session, newest-model-first
4321
+ * insertion order. Surfaced by `cascade models --verbose`; a non-empty list
4322
+ * means src/core/router/pricing-data.json is probably due a refresh.
4323
+ */
4324
+ getPriceDisagreements() {
4325
+ return [...this.disagreements.values()];
4326
+ }
2601
4327
  /** Current capability facts for a model id, or null when unknown. */
2602
4328
  getCapability(modelId) {
2603
4329
  return this.capabilities.get(normalizeModelId2(modelId)) ?? null;
@@ -2794,7 +4520,9 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter {
2794
4520
  tokensByTier: {},
2795
4521
  inputTokensByTier: {},
2796
4522
  outputTokensByTier: {},
2797
- costByFeature: {}
4523
+ costByFeature: {},
4524
+ untrackedCostCalls: 0,
4525
+ untrackedCostModels: []
2798
4526
  };
2799
4527
  tierModels = /* @__PURE__ */ new Map();
2800
4528
  /**
@@ -3144,7 +4872,7 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter {
3144
4872
  `Model ${model.id} inference timed out after ${cloudTimeoutMs}ms`
3145
4873
  );
3146
4874
  }
3147
- const correctedCost = calculateCost(
4875
+ const corrected = buildTokenUsage(
3148
4876
  result.usage.inputTokens,
3149
4877
  result.usage.outputTokens,
3150
4878
  model
@@ -3153,7 +4881,8 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter {
3153
4881
  ...result,
3154
4882
  usage: {
3155
4883
  ...result.usage,
3156
- estimatedCostUsd: correctedCost
4884
+ estimatedCostUsd: corrected.estimatedCostUsd,
4885
+ ...corrected.costUnknown ? { costUnknown: true } : { costUnknown: void 0 }
3157
4886
  }
3158
4887
  };
3159
4888
  if (!result || typeof result.content !== "string" || !result.usage) {
@@ -3340,7 +5069,9 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter {
3340
5069
  tokensByTier: { ...this.stats.tokensByTier },
3341
5070
  inputTokensByTier: { ...this.stats.inputTokensByTier },
3342
5071
  outputTokensByTier: { ...this.stats.outputTokensByTier },
3343
- costByFeature: { ...this.stats.costByFeature }
5072
+ costByFeature: { ...this.stats.costByFeature },
5073
+ untrackedCostCalls: this.stats.untrackedCostCalls,
5074
+ untrackedCostModels: [...this.stats.untrackedCostModels]
3344
5075
  };
3345
5076
  }
3346
5077
  /**
@@ -3391,7 +5122,9 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter {
3391
5122
  tokensByTier: {},
3392
5123
  inputTokensByTier: {},
3393
5124
  outputTokensByTier: {},
3394
- costByFeature: {}
5125
+ costByFeature: {},
5126
+ untrackedCostCalls: 0,
5127
+ untrackedCostModels: []
3395
5128
  };
3396
5129
  this.sessionCostUsd = 0;
3397
5130
  this.budgetState = "ok";
@@ -3576,6 +5309,18 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter {
3576
5309
  if (featureTag) {
3577
5310
  this.stats.costByFeature[featureTag] = (this.stats.costByFeature[featureTag] ?? 0) + usage.estimatedCostUsd;
3578
5311
  }
5312
+ if (usage.costUnknown) {
5313
+ this.stats.untrackedCostCalls += 1;
5314
+ if (!this.stats.untrackedCostModels.includes(model.id)) {
5315
+ this.stats.untrackedCostModels.push(model.id);
5316
+ const capped = this.config?.budget?.maxCostPerRunUsd != null || this.config?.budget?.sessionBudgetUsd != null;
5317
+ this.emit("cost:untracked", {
5318
+ modelId: model.id,
5319
+ provider: model.provider,
5320
+ 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.`
5321
+ });
5322
+ }
5323
+ }
3579
5324
  this.runTokens += usage.totalTokens;
3580
5325
  this.runCostUsd += usage.estimatedCostUsd;
3581
5326
  this.updateBudgetState();
@@ -9083,7 +10828,18 @@ var ProviderConfigSchema = z.object({
9083
10828
  apiVersion: z.string().optional(),
9084
10829
  model: z.string().optional(),
9085
10830
  authToken: z.string().optional(),
9086
- credentialSource: z.string().optional()
10831
+ credentialSource: z.string().optional(),
10832
+ /**
10833
+ * "This endpoint is self-hosted, so inference genuinely costs $0."
10834
+ * Only meaningful for `ollama` and `openai-compatible`. Unset ⇒ inferred:
10835
+ * ollama is local, openai-compatible is local when its baseUrl is
10836
+ * loopback/LAN. Set it explicitly to override — e.g. `false` for an Ollama
10837
+ * instance you rent, `true` for a llama.cpp box on your own LAN reached by
10838
+ * hostname.
10839
+ */
10840
+ local: z.boolean().optional(),
10841
+ /** Region for providers whose price varies by region (Azure: global | us | eu | …). */
10842
+ region: z.string().optional()
9087
10843
  });
9088
10844
  var ModelOverridesSchema = z.object({
9089
10845
  t1: z.string().optional(),
@@ -9669,8 +11425,8 @@ var TaskAnalyzer = class {
9669
11425
  }
9670
11426
  costEfficiency(model, complexity) {
9671
11427
  if (this.tracker) return this.tracker.costEfficiencyScore(model, complexity);
9672
- const blended = model.inputCostPer1kTokens + model.outputCostPer1kTokens * 2;
9673
- const normalised = Math.min(1, blended / 0.05);
11428
+ const blended = blendedCostPer1k(model);
11429
+ const normalised = Math.min(1, blended / BLENDED_COST_CEILING);
9674
11430
  const complexityWeight = (6 - complexity) / 5;
9675
11431
  return Math.max(0.1, 1 - normalised * complexityWeight);
9676
11432
  }
@@ -9805,8 +11561,8 @@ var ModelPerformanceTracker = class {
9805
11561
  * normalised over $0.05 blended as the "expensive" ceiling.
9806
11562
  */
9807
11563
  costEfficiencyScore(model, complexity) {
9808
- const blended = model.inputCostPer1kTokens + model.outputCostPer1kTokens * 2;
9809
- const normalised = Math.min(1, blended / 0.05);
11564
+ const blended = blendedCostPer1k(model);
11565
+ const normalised = Math.min(1, blended / BLENDED_COST_CEILING);
9810
11566
  const complexityWeight = (6 - complexity) / 5;
9811
11567
  return Math.max(0.1, 1 - normalised * complexityWeight);
9812
11568
  }
@@ -12649,7 +14405,11 @@ _(incomplete: ${reasons.join("; ")})_` : partial;
12649
14405
  inputTokens: 0,
12650
14406
  outputTokens: 0,
12651
14407
  totalTokens: stats.totalTokens,
12652
- estimatedCostUsd: stats.totalCostUsd
14408
+ estimatedCostUsd: stats.totalCostUsd,
14409
+ // At least one call ran on a model with no known price, so its spend is
14410
+ // missing from the total above. Say so rather than letting the caller
14411
+ // present an undercount as the final figure.
14412
+ ...stats.untrackedCostCalls > 0 ? { costUnknown: true } : {}
12653
14413
  },
12654
14414
  t2Results,
12655
14415
  durationMs,
@@ -12719,7 +14479,8 @@ _(incomplete: ${reasons.join("; ")})_` : partial;
12719
14479
  inputTokens: 0,
12720
14480
  outputTokens: 0,
12721
14481
  totalTokens: stats2.totalTokens,
12722
- estimatedCostUsd: stats2.totalCostUsd
14482
+ estimatedCostUsd: stats2.totalCostUsd,
14483
+ ...stats2.untrackedCostCalls > 0 ? { costUnknown: true } : {}
12723
14484
  },
12724
14485
  t2Results: [],
12725
14486
  durationMs: Date.now() - startMs,
@@ -12743,7 +14504,8 @@ _(incomplete: ${reasons.join("; ")})_` : partial;
12743
14504
  inputTokens: result.usage?.inputTokens ?? 0,
12744
14505
  outputTokens: result.usage?.outputTokens ?? 0,
12745
14506
  totalTokens: stats.totalTokens,
12746
- estimatedCostUsd: stats.totalCostUsd
14507
+ estimatedCostUsd: stats.totalCostUsd,
14508
+ ...stats.untrackedCostCalls > 0 ? { costUnknown: true } : {}
12747
14509
  },
12748
14510
  t2Results: [],
12749
14511
  durationMs: Date.now() - startMs,
@@ -14527,7 +16289,10 @@ var DashboardServer = class {
14527
16289
  this.socket.broadcast("cost:update", {
14528
16290
  sessionId,
14529
16291
  totalTokens: result.usage.totalTokens,
14530
- totalCostUsd: result.usage.estimatedCostUsd
16292
+ totalCostUsd: result.usage.estimatedCostUsd,
16293
+ // True when a model with no known price was used: the total above is
16294
+ // an undercount, and the UI must not present it as the full spend.
16295
+ costUnknown: result.usage.costUnknown === true
14531
16296
  });
14532
16297
  this.throttledBroadcast("workspace");
14533
16298
  } catch (err) {
@@ -14840,7 +16605,8 @@ var DashboardServer = class {
14840
16605
  this.socket.broadcast("cost:update", {
14841
16606
  sessionId,
14842
16607
  totalTokens: result.usage.totalTokens,
14843
- totalCostUsd: result.usage.estimatedCostUsd
16608
+ totalCostUsd: result.usage.estimatedCostUsd,
16609
+ costUnknown: result.usage.costUnknown === true
14844
16610
  });
14845
16611
  this.throttledBroadcast("workspace");
14846
16612
  } catch (err) {
@@ -15382,7 +17148,8 @@ ${prompt}`;
15382
17148
  this.socket.broadcast("cost:update", {
15383
17149
  sessionId,
15384
17150
  totalTokens: result.usage.totalTokens,
15385
- totalCostUsd: result.usage.estimatedCostUsd
17151
+ totalCostUsd: result.usage.estimatedCostUsd,
17152
+ costUnknown: result.usage.costUnknown === true
15386
17153
  });
15387
17154
  this.socket.broadcastToRoom(`session:${sessionId}`, "session:complete", { sessionId, result });
15388
17155
  this.throttledBroadcast("workspace");
@@ -15938,12 +17705,19 @@ var CloudClient = class _CloudClient {
15938
17705
  );
15939
17706
  await openUrl(authorizeUrl);
15940
17707
  const code = await listener.waitForCode;
15941
- const res = await fetch(this.url("/api/native/token"), {
15942
- method: "POST",
15943
- headers: { "Content-Type": "application/json" },
15944
- body: JSON.stringify({ code, code_verifier: verifier })
15945
- });
15946
- if (!res.ok) throw new Error("Sign-in could not be completed. Please try again.");
17708
+ let res;
17709
+ try {
17710
+ res = await fetch(this.url("/api/native/token"), {
17711
+ method: "POST",
17712
+ headers: { "Content-Type": "application/json" },
17713
+ body: JSON.stringify({ code, code_verifier: verifier })
17714
+ });
17715
+ } catch (err) {
17716
+ throw new Error(
17717
+ `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)})`
17718
+ );
17719
+ }
17720
+ if (!res.ok) throw new Error(await loginFailureMessage(res, this.serverUrl));
15947
17721
  const tokens = await res.json();
15948
17722
  return await this.finishLogin(tokens);
15949
17723
  } finally {
@@ -16117,6 +17891,22 @@ function sleep(ms, signal) {
16117
17891
  }, { once: true });
16118
17892
  });
16119
17893
  }
17894
+ async function loginFailureMessage(res, serverUrl) {
17895
+ const body = await res.text().catch(() => "");
17896
+ let apiError = "";
17897
+ try {
17898
+ apiError = String(JSON.parse(body).error ?? "");
17899
+ } catch {
17900
+ }
17901
+ if (apiError === "invalid_grant") {
17902
+ 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.";
17903
+ }
17904
+ if (apiError) return `Sign-in failed: ${apiError} (HTTP ${res.status}).`;
17905
+ if (res.status === 404 || /<html/i.test(body)) {
17906
+ 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.`;
17907
+ }
17908
+ return `Sign-in could not be completed (HTTP ${res.status}). Please try again.`;
17909
+ }
16120
17910
  function base64url(buf) {
16121
17911
  return buf.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
16122
17912
  }