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.cjs CHANGED
@@ -238,8 +238,1660 @@ var init_audit_logger = __esm({
238
238
  }
239
239
  });
240
240
 
241
+ // src/core/router/pricing-data.json
242
+ var pricing_data_default = {
243
+ entries: [
244
+ {
245
+ model: "claude-opus-5",
246
+ provider: "anthropic",
247
+ modality: "text",
248
+ currency: "USD",
249
+ asOf: "2026-07-27",
250
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
251
+ provenance: "vendor-pricing-page",
252
+ tiers: [
253
+ {
254
+ inputPer1m: 5,
255
+ outputPer1m: 25,
256
+ cachedInputPer1m: 0.5,
257
+ cacheWritePer1m: 6.25,
258
+ reasoningOutputPer1m: 25
259
+ }
260
+ ],
261
+ batchMultiplier: 0.5,
262
+ contextWindow: 1e6
263
+ },
264
+ {
265
+ model: "claude-opus-4-8",
266
+ provider: "anthropic",
267
+ modality: "text",
268
+ currency: "USD",
269
+ asOf: "2026-07-27",
270
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
271
+ provenance: "vendor-pricing-page",
272
+ tiers: [
273
+ {
274
+ inputPer1m: 5,
275
+ outputPer1m: 25,
276
+ cachedInputPer1m: 0.5,
277
+ cacheWritePer1m: 6.25,
278
+ reasoningOutputPer1m: 25
279
+ }
280
+ ],
281
+ batchMultiplier: 0.5,
282
+ contextWindow: 1e6
283
+ },
284
+ {
285
+ model: "claude-opus-4-7",
286
+ provider: "anthropic",
287
+ modality: "text",
288
+ currency: "USD",
289
+ asOf: "2026-07-27",
290
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
291
+ provenance: "vendor-pricing-page",
292
+ tiers: [
293
+ {
294
+ inputPer1m: 5,
295
+ outputPer1m: 25,
296
+ cachedInputPer1m: 0.5,
297
+ cacheWritePer1m: 6.25,
298
+ reasoningOutputPer1m: 25
299
+ }
300
+ ],
301
+ batchMultiplier: 0.5,
302
+ contextWindow: 1e6
303
+ },
304
+ {
305
+ model: "claude-opus-4-6",
306
+ provider: "anthropic",
307
+ modality: "text",
308
+ currency: "USD",
309
+ asOf: "2026-07-27",
310
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
311
+ provenance: "vendor-pricing-page",
312
+ tiers: [
313
+ {
314
+ inputPer1m: 5,
315
+ outputPer1m: 25,
316
+ cachedInputPer1m: 0.5,
317
+ cacheWritePer1m: 6.25,
318
+ reasoningOutputPer1m: 25
319
+ }
320
+ ],
321
+ batchMultiplier: 0.5,
322
+ contextWindow: 1e6
323
+ },
324
+ {
325
+ model: "claude-opus-4-5",
326
+ provider: "anthropic",
327
+ modality: "text",
328
+ currency: "USD",
329
+ asOf: "2026-07-27",
330
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
331
+ provenance: "vendor-pricing-page",
332
+ tiers: [
333
+ {
334
+ inputPer1m: 5,
335
+ outputPer1m: 25,
336
+ cachedInputPer1m: 0.5,
337
+ cacheWritePer1m: 6.25,
338
+ reasoningOutputPer1m: 25
339
+ }
340
+ ],
341
+ batchMultiplier: 0.5,
342
+ contextWindow: 2e5
343
+ },
344
+ {
345
+ model: "claude-opus-4-1",
346
+ provider: "anthropic",
347
+ modality: "text",
348
+ currency: "USD",
349
+ asOf: "2026-07-27",
350
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
351
+ provenance: "vendor-pricing-page",
352
+ tiers: [
353
+ {
354
+ inputPer1m: 15,
355
+ outputPer1m: 75,
356
+ cachedInputPer1m: 1.5,
357
+ cacheWritePer1m: 18.75,
358
+ reasoningOutputPer1m: 75
359
+ }
360
+ ],
361
+ batchMultiplier: 0.5,
362
+ contextWindow: 2e5,
363
+ notes: "Deprecated by Anthropic; priced for historical/cost-reporting accuracy."
364
+ },
365
+ {
366
+ model: "claude-opus-4",
367
+ provider: "anthropic",
368
+ modality: "text",
369
+ currency: "USD",
370
+ asOf: "2026-07-27",
371
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
372
+ provenance: "vendor-pricing-page",
373
+ tiers: [
374
+ {
375
+ inputPer1m: 15,
376
+ outputPer1m: 75,
377
+ cachedInputPer1m: 1.5,
378
+ cacheWritePer1m: 18.75,
379
+ reasoningOutputPer1m: 75
380
+ }
381
+ ],
382
+ batchMultiplier: 0.5,
383
+ contextWindow: 2e5,
384
+ notes: "Retired except on Google Cloud; priced for historical/cost-reporting accuracy."
385
+ },
386
+ {
387
+ model: "claude-sonnet-5",
388
+ provider: "anthropic",
389
+ modality: "text",
390
+ currency: "USD",
391
+ asOf: "2026-07-27",
392
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
393
+ provenance: "vendor-pricing-page",
394
+ tiers: [
395
+ {
396
+ inputPer1m: 2,
397
+ outputPer1m: 10,
398
+ cachedInputPer1m: 0.2,
399
+ cacheWritePer1m: 2.5,
400
+ reasoningOutputPer1m: 10
401
+ }
402
+ ],
403
+ batchMultiplier: 0.5,
404
+ contextWindow: 1e6,
405
+ 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."
406
+ },
407
+ {
408
+ model: "claude-sonnet-4-6",
409
+ provider: "anthropic",
410
+ modality: "text",
411
+ currency: "USD",
412
+ asOf: "2026-07-27",
413
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
414
+ provenance: "vendor-pricing-page",
415
+ tiers: [
416
+ {
417
+ inputPer1m: 3,
418
+ outputPer1m: 15,
419
+ cachedInputPer1m: 0.3,
420
+ cacheWritePer1m: 3.75,
421
+ reasoningOutputPer1m: 15
422
+ }
423
+ ],
424
+ batchMultiplier: 0.5,
425
+ contextWindow: 1e6
426
+ },
427
+ {
428
+ model: "claude-sonnet-4-5",
429
+ provider: "anthropic",
430
+ modality: "text",
431
+ currency: "USD",
432
+ asOf: "2026-07-27",
433
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
434
+ provenance: "vendor-pricing-page",
435
+ tiers: [
436
+ {
437
+ maxInputTokens: 2e5,
438
+ inputPer1m: 3,
439
+ outputPer1m: 15,
440
+ cachedInputPer1m: 0.3,
441
+ cacheWritePer1m: 3.75,
442
+ reasoningOutputPer1m: 15
443
+ },
444
+ {
445
+ inputPer1m: 6,
446
+ outputPer1m: 22.5,
447
+ cachedInputPer1m: 0.6,
448
+ cacheWritePer1m: 7.5,
449
+ reasoningOutputPer1m: 22.5
450
+ }
451
+ ],
452
+ batchMultiplier: 0.5,
453
+ contextWindow: 2e5,
454
+ 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)."
455
+ },
456
+ {
457
+ model: "claude-sonnet-4",
458
+ provider: "anthropic",
459
+ modality: "text",
460
+ currency: "USD",
461
+ asOf: "2026-07-27",
462
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
463
+ provenance: "vendor-pricing-page",
464
+ tiers: [
465
+ {
466
+ inputPer1m: 3,
467
+ outputPer1m: 15,
468
+ cachedInputPer1m: 0.3,
469
+ cacheWritePer1m: 3.75,
470
+ reasoningOutputPer1m: 15
471
+ }
472
+ ],
473
+ batchMultiplier: 0.5,
474
+ contextWindow: 2e5
475
+ },
476
+ {
477
+ model: "claude-haiku-4-5",
478
+ provider: "anthropic",
479
+ modality: "text",
480
+ currency: "USD",
481
+ asOf: "2026-07-27",
482
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
483
+ provenance: "vendor-pricing-page",
484
+ tiers: [
485
+ {
486
+ inputPer1m: 1,
487
+ outputPer1m: 5,
488
+ cachedInputPer1m: 0.1,
489
+ cacheWritePer1m: 1.25,
490
+ reasoningOutputPer1m: 5
491
+ }
492
+ ],
493
+ batchMultiplier: 0.5,
494
+ contextWindow: 2e5
495
+ },
496
+ {
497
+ model: "claude-haiku-3-5",
498
+ provider: "anthropic",
499
+ modality: "text",
500
+ currency: "USD",
501
+ asOf: "2026-07-27",
502
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
503
+ provenance: "vendor-pricing-page",
504
+ tiers: [
505
+ {
506
+ inputPer1m: 0.8,
507
+ outputPer1m: 4,
508
+ cachedInputPer1m: 0.08,
509
+ cacheWritePer1m: 1,
510
+ reasoningOutputPer1m: 4
511
+ }
512
+ ],
513
+ batchMultiplier: 0.5,
514
+ contextWindow: 2e5
515
+ },
516
+ {
517
+ model: "gpt-5.6-sol",
518
+ provider: "openai",
519
+ aliases: [
520
+ "gpt-5.6"
521
+ ],
522
+ modality: "text",
523
+ currency: "USD",
524
+ asOf: "2026-07-27",
525
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
526
+ provenance: "litellm-catalog",
527
+ tiers: [
528
+ {
529
+ maxInputTokens: 272e3,
530
+ inputPer1m: 5,
531
+ outputPer1m: 30,
532
+ cachedInputPer1m: 0.5,
533
+ cacheWritePer1m: 6.25
534
+ },
535
+ {
536
+ inputPer1m: 10,
537
+ outputPer1m: 45,
538
+ cachedInputPer1m: 1,
539
+ cacheWritePer1m: 12.5
540
+ }
541
+ ],
542
+ batchMultiplier: 0.5,
543
+ contextWindow: 105e4
544
+ },
545
+ {
546
+ model: "gpt-5.6-terra",
547
+ provider: "openai",
548
+ modality: "text",
549
+ currency: "USD",
550
+ asOf: "2026-07-27",
551
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
552
+ provenance: "litellm-catalog",
553
+ tiers: [
554
+ {
555
+ maxInputTokens: 272e3,
556
+ inputPer1m: 2.5,
557
+ outputPer1m: 15,
558
+ cachedInputPer1m: 0.25,
559
+ cacheWritePer1m: 3.125
560
+ },
561
+ {
562
+ inputPer1m: 5,
563
+ outputPer1m: 22.5,
564
+ cachedInputPer1m: 0.5,
565
+ cacheWritePer1m: 6.25
566
+ }
567
+ ],
568
+ batchMultiplier: 0.5,
569
+ contextWindow: 105e4
570
+ },
571
+ {
572
+ model: "gpt-5.6-luna",
573
+ provider: "openai",
574
+ modality: "text",
575
+ currency: "USD",
576
+ asOf: "2026-07-27",
577
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
578
+ provenance: "litellm-catalog",
579
+ tiers: [
580
+ {
581
+ maxInputTokens: 272e3,
582
+ inputPer1m: 1,
583
+ outputPer1m: 6,
584
+ cachedInputPer1m: 0.1,
585
+ cacheWritePer1m: 1.25
586
+ },
587
+ {
588
+ inputPer1m: 2,
589
+ outputPer1m: 9,
590
+ cachedInputPer1m: 0.2,
591
+ cacheWritePer1m: 2.5
592
+ }
593
+ ],
594
+ batchMultiplier: 0.5,
595
+ contextWindow: 105e4
596
+ },
597
+ {
598
+ model: "gpt-5.5",
599
+ provider: "openai",
600
+ modality: "text",
601
+ currency: "USD",
602
+ asOf: "2026-07-27",
603
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
604
+ provenance: "litellm-catalog",
605
+ tiers: [
606
+ {
607
+ maxInputTokens: 272e3,
608
+ inputPer1m: 5,
609
+ outputPer1m: 30,
610
+ cachedInputPer1m: 0.5
611
+ },
612
+ {
613
+ inputPer1m: 10,
614
+ outputPer1m: 45,
615
+ cachedInputPer1m: 1
616
+ }
617
+ ],
618
+ batchMultiplier: 0.5,
619
+ contextWindow: 105e4
620
+ },
621
+ {
622
+ model: "gpt-5.4",
623
+ provider: "openai",
624
+ modality: "text",
625
+ currency: "USD",
626
+ asOf: "2026-07-27",
627
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
628
+ provenance: "litellm-catalog",
629
+ tiers: [
630
+ {
631
+ maxInputTokens: 272e3,
632
+ inputPer1m: 2.5,
633
+ outputPer1m: 15,
634
+ cachedInputPer1m: 0.25
635
+ },
636
+ {
637
+ inputPer1m: 5,
638
+ outputPer1m: 22.5,
639
+ cachedInputPer1m: 0.5
640
+ }
641
+ ],
642
+ batchMultiplier: 0.5,
643
+ contextWindow: 105e4
644
+ },
645
+ {
646
+ model: "gpt-5.4-mini",
647
+ provider: "openai",
648
+ modality: "text",
649
+ currency: "USD",
650
+ asOf: "2026-07-27",
651
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
652
+ provenance: "litellm-catalog",
653
+ tiers: [
654
+ {
655
+ inputPer1m: 0.75,
656
+ outputPer1m: 4.5,
657
+ cachedInputPer1m: 0.075
658
+ }
659
+ ],
660
+ batchMultiplier: 0.5,
661
+ contextWindow: 105e4
662
+ },
663
+ {
664
+ model: "gpt-5",
665
+ provider: "openai",
666
+ modality: "text",
667
+ currency: "USD",
668
+ asOf: "2026-07-27",
669
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
670
+ provenance: "litellm-catalog",
671
+ tiers: [
672
+ {
673
+ inputPer1m: 1.25,
674
+ outputPer1m: 10,
675
+ cachedInputPer1m: 0.125
676
+ }
677
+ ],
678
+ contextWindow: 272e3
679
+ },
680
+ {
681
+ model: "gpt-5-mini",
682
+ provider: "openai",
683
+ modality: "text",
684
+ currency: "USD",
685
+ asOf: "2026-07-27",
686
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
687
+ provenance: "litellm-catalog",
688
+ tiers: [
689
+ {
690
+ inputPer1m: 0.25,
691
+ outputPer1m: 2,
692
+ cachedInputPer1m: 0.025
693
+ }
694
+ ],
695
+ contextWindow: 272e3
696
+ },
697
+ {
698
+ model: "gpt-5-nano",
699
+ provider: "openai",
700
+ modality: "text",
701
+ currency: "USD",
702
+ asOf: "2026-07-27",
703
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
704
+ provenance: "litellm-catalog",
705
+ tiers: [
706
+ {
707
+ inputPer1m: 0.05,
708
+ outputPer1m: 0.4,
709
+ cachedInputPer1m: 5e-3
710
+ }
711
+ ],
712
+ contextWindow: 272e3
713
+ },
714
+ {
715
+ model: "gpt-4.1",
716
+ provider: "openai",
717
+ modality: "text",
718
+ currency: "USD",
719
+ asOf: "2026-07-27",
720
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
721
+ provenance: "litellm-catalog",
722
+ tiers: [
723
+ {
724
+ inputPer1m: 2,
725
+ outputPer1m: 8,
726
+ cachedInputPer1m: 0.5
727
+ }
728
+ ],
729
+ batchMultiplier: 0.5,
730
+ contextWindow: 1047576
731
+ },
732
+ {
733
+ model: "gpt-4.1-mini",
734
+ provider: "openai",
735
+ modality: "text",
736
+ currency: "USD",
737
+ asOf: "2026-07-27",
738
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
739
+ provenance: "litellm-catalog",
740
+ tiers: [
741
+ {
742
+ inputPer1m: 0.4,
743
+ outputPer1m: 1.6,
744
+ cachedInputPer1m: 0.1
745
+ }
746
+ ],
747
+ batchMultiplier: 0.5,
748
+ contextWindow: 1047576
749
+ },
750
+ {
751
+ model: "gpt-4.1-nano",
752
+ provider: "openai",
753
+ modality: "text",
754
+ currency: "USD",
755
+ asOf: "2026-07-27",
756
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
757
+ provenance: "litellm-catalog",
758
+ tiers: [
759
+ {
760
+ inputPer1m: 0.1,
761
+ outputPer1m: 0.4,
762
+ cachedInputPer1m: 0.025
763
+ }
764
+ ],
765
+ batchMultiplier: 0.5,
766
+ contextWindow: 1047576
767
+ },
768
+ {
769
+ model: "gpt-4o",
770
+ provider: "openai",
771
+ modality: "text",
772
+ currency: "USD",
773
+ asOf: "2026-07-27",
774
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
775
+ provenance: "litellm-catalog",
776
+ tiers: [
777
+ {
778
+ inputPer1m: 2.5,
779
+ outputPer1m: 10,
780
+ cachedInputPer1m: 1.25
781
+ }
782
+ ],
783
+ batchMultiplier: 0.5,
784
+ contextWindow: 128e3
785
+ },
786
+ {
787
+ model: "gpt-4o-mini",
788
+ provider: "openai",
789
+ modality: "text",
790
+ currency: "USD",
791
+ asOf: "2026-07-27",
792
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
793
+ provenance: "litellm-catalog",
794
+ tiers: [
795
+ {
796
+ inputPer1m: 0.15,
797
+ outputPer1m: 0.6,
798
+ cachedInputPer1m: 0.075
799
+ }
800
+ ],
801
+ batchMultiplier: 0.5,
802
+ contextWindow: 128e3
803
+ },
804
+ {
805
+ model: "gpt-5.5",
806
+ provider: "azure",
807
+ region: "global",
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
+ maxInputTokens: 272e3,
816
+ inputPer1m: 5,
817
+ outputPer1m: 30,
818
+ cachedInputPer1m: 0.5
819
+ },
820
+ {
821
+ inputPer1m: 10,
822
+ outputPer1m: 45,
823
+ cachedInputPer1m: 1
824
+ }
825
+ ],
826
+ contextWindow: 105e4
827
+ },
828
+ {
829
+ model: "gpt-5.5",
830
+ provider: "azure",
831
+ region: "us",
832
+ modality: "text",
833
+ currency: "USD",
834
+ asOf: "2026-07-27",
835
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
836
+ provenance: "litellm-catalog",
837
+ tiers: [
838
+ {
839
+ maxInputTokens: 272e3,
840
+ inputPer1m: 5.5,
841
+ outputPer1m: 33,
842
+ cachedInputPer1m: 0.55
843
+ },
844
+ {
845
+ inputPer1m: 11,
846
+ outputPer1m: 49.5,
847
+ cachedInputPer1m: 1.1
848
+ }
849
+ ],
850
+ contextWindow: 105e4
851
+ },
852
+ {
853
+ model: "gpt-5.5",
854
+ provider: "azure",
855
+ region: "eu",
856
+ modality: "text",
857
+ currency: "USD",
858
+ asOf: "2026-07-27",
859
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
860
+ provenance: "litellm-catalog",
861
+ tiers: [
862
+ {
863
+ maxInputTokens: 272e3,
864
+ inputPer1m: 5.5,
865
+ outputPer1m: 33,
866
+ cachedInputPer1m: 0.55
867
+ },
868
+ {
869
+ inputPer1m: 11,
870
+ outputPer1m: 49.5,
871
+ cachedInputPer1m: 1.1
872
+ }
873
+ ],
874
+ contextWindow: 105e4
875
+ },
876
+ {
877
+ model: "gpt-5.4",
878
+ provider: "azure",
879
+ region: "global",
880
+ modality: "text",
881
+ currency: "USD",
882
+ asOf: "2026-07-27",
883
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
884
+ provenance: "litellm-catalog",
885
+ tiers: [
886
+ {
887
+ maxInputTokens: 272e3,
888
+ inputPer1m: 2.5,
889
+ outputPer1m: 15,
890
+ cachedInputPer1m: 0.25
891
+ },
892
+ {
893
+ inputPer1m: 5,
894
+ outputPer1m: 22.5,
895
+ cachedInputPer1m: 0.5
896
+ }
897
+ ],
898
+ contextWindow: 105e4
899
+ },
900
+ {
901
+ model: "gpt-5.4",
902
+ provider: "azure",
903
+ region: "us",
904
+ modality: "text",
905
+ currency: "USD",
906
+ asOf: "2026-07-27",
907
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
908
+ provenance: "litellm-catalog",
909
+ tiers: [
910
+ {
911
+ inputPer1m: 2.75,
912
+ outputPer1m: 16.5,
913
+ cachedInputPer1m: 0.28
914
+ }
915
+ ],
916
+ contextWindow: 105e4
917
+ },
918
+ {
919
+ model: "gpt-5.4",
920
+ provider: "azure",
921
+ region: "eu",
922
+ modality: "text",
923
+ currency: "USD",
924
+ asOf: "2026-07-27",
925
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
926
+ provenance: "litellm-catalog",
927
+ tiers: [
928
+ {
929
+ inputPer1m: 2.75,
930
+ outputPer1m: 16.5,
931
+ cachedInputPer1m: 0.28
932
+ }
933
+ ],
934
+ contextWindow: 105e4
935
+ },
936
+ {
937
+ model: "gpt-5.6-terra",
938
+ provider: "azure",
939
+ region: "global",
940
+ modality: "text",
941
+ currency: "USD",
942
+ asOf: "2026-07-27",
943
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
944
+ provenance: "litellm-catalog",
945
+ tiers: [
946
+ {
947
+ maxInputTokens: 272e3,
948
+ inputPer1m: 2.5,
949
+ outputPer1m: 15,
950
+ cachedInputPer1m: 0.25
951
+ },
952
+ {
953
+ inputPer1m: 5,
954
+ outputPer1m: 22.5,
955
+ cachedInputPer1m: 0.5
956
+ }
957
+ ],
958
+ contextWindow: 105e4
959
+ },
960
+ {
961
+ model: "gpt-5.6-terra",
962
+ provider: "azure",
963
+ region: "eu",
964
+ modality: "text",
965
+ currency: "USD",
966
+ asOf: "2026-07-27",
967
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
968
+ provenance: "litellm-catalog",
969
+ tiers: [
970
+ {
971
+ maxInputTokens: 272e3,
972
+ inputPer1m: 2.75,
973
+ outputPer1m: 16.5,
974
+ cachedInputPer1m: 0.275
975
+ },
976
+ {
977
+ inputPer1m: 5.5,
978
+ outputPer1m: 24.75,
979
+ cachedInputPer1m: 0.55
980
+ }
981
+ ],
982
+ contextWindow: 105e4
983
+ },
984
+ {
985
+ model: "gpt-5",
986
+ provider: "azure",
987
+ region: "global",
988
+ modality: "text",
989
+ currency: "USD",
990
+ asOf: "2026-07-27",
991
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
992
+ provenance: "litellm-catalog",
993
+ tiers: [
994
+ {
995
+ inputPer1m: 1.25,
996
+ outputPer1m: 10,
997
+ cachedInputPer1m: 0.125
998
+ }
999
+ ],
1000
+ contextWindow: 272e3
1001
+ },
1002
+ {
1003
+ model: "gpt-5-mini",
1004
+ provider: "azure",
1005
+ region: "global",
1006
+ modality: "text",
1007
+ currency: "USD",
1008
+ asOf: "2026-07-27",
1009
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1010
+ provenance: "litellm-catalog",
1011
+ tiers: [
1012
+ {
1013
+ inputPer1m: 0.25,
1014
+ outputPer1m: 2,
1015
+ cachedInputPer1m: 0.025
1016
+ }
1017
+ ],
1018
+ contextWindow: 272e3
1019
+ },
1020
+ {
1021
+ model: "gpt-5-nano",
1022
+ provider: "azure",
1023
+ region: "global",
1024
+ modality: "text",
1025
+ currency: "USD",
1026
+ asOf: "2026-07-27",
1027
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1028
+ provenance: "litellm-catalog",
1029
+ tiers: [
1030
+ {
1031
+ inputPer1m: 0.05,
1032
+ outputPer1m: 0.4,
1033
+ cachedInputPer1m: 5e-3
1034
+ }
1035
+ ],
1036
+ contextWindow: 272e3
1037
+ },
1038
+ {
1039
+ model: "gpt-4.1",
1040
+ provider: "azure",
1041
+ region: "global",
1042
+ modality: "text",
1043
+ currency: "USD",
1044
+ asOf: "2026-07-27",
1045
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1046
+ provenance: "litellm-catalog",
1047
+ tiers: [
1048
+ {
1049
+ inputPer1m: 2,
1050
+ outputPer1m: 8,
1051
+ cachedInputPer1m: 0.5
1052
+ }
1053
+ ],
1054
+ batchMultiplier: 0.5,
1055
+ contextWindow: 1047576
1056
+ },
1057
+ {
1058
+ model: "gpt-4o",
1059
+ provider: "azure",
1060
+ region: "global",
1061
+ modality: "text",
1062
+ currency: "USD",
1063
+ asOf: "2026-07-27",
1064
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1065
+ provenance: "litellm-catalog",
1066
+ tiers: [
1067
+ {
1068
+ inputPer1m: 2.5,
1069
+ outputPer1m: 10,
1070
+ cachedInputPer1m: 1.25
1071
+ }
1072
+ ],
1073
+ contextWindow: 128e3
1074
+ },
1075
+ {
1076
+ model: "gpt-4o-mini",
1077
+ provider: "azure",
1078
+ region: "global",
1079
+ modality: "text",
1080
+ currency: "USD",
1081
+ asOf: "2026-07-27",
1082
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1083
+ provenance: "litellm-catalog",
1084
+ tiers: [
1085
+ {
1086
+ inputPer1m: 0.165,
1087
+ outputPer1m: 0.66,
1088
+ cachedInputPer1m: 0.075
1089
+ }
1090
+ ],
1091
+ contextWindow: 128e3,
1092
+ 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."
1093
+ },
1094
+ {
1095
+ model: "gemini-3.1-pro",
1096
+ provider: "gemini",
1097
+ aliases: [
1098
+ "gemini-3.1-pro-preview"
1099
+ ],
1100
+ modality: "text",
1101
+ currency: "USD",
1102
+ asOf: "2026-07-27",
1103
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1104
+ provenance: "vendor-pricing-page",
1105
+ tiers: [
1106
+ {
1107
+ maxInputTokens: 2e5,
1108
+ inputPer1m: 2,
1109
+ outputPer1m: 12,
1110
+ cachedInputPer1m: 0.2,
1111
+ reasoningOutputPer1m: 12
1112
+ },
1113
+ {
1114
+ inputPer1m: 4,
1115
+ outputPer1m: 18,
1116
+ cachedInputPer1m: 0.4,
1117
+ reasoningOutputPer1m: 18
1118
+ }
1119
+ ],
1120
+ batchMultiplier: 0.5,
1121
+ contextWindow: 1048576,
1122
+ notes: "Long-context tier: $2/$12 per 1M up to 200K prompt tokens, $4/$18 above it."
1123
+ },
1124
+ {
1125
+ model: "gemini-3-pro",
1126
+ provider: "gemini",
1127
+ aliases: [
1128
+ "gemini-3-pro-preview"
1129
+ ],
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
+ maxInputTokens: 2e5,
1138
+ inputPer1m: 2,
1139
+ outputPer1m: 12,
1140
+ cachedInputPer1m: 0.2,
1141
+ reasoningOutputPer1m: 12
1142
+ },
1143
+ {
1144
+ inputPer1m: 4,
1145
+ outputPer1m: 18,
1146
+ cachedInputPer1m: 0.4,
1147
+ reasoningOutputPer1m: 18
1148
+ }
1149
+ ],
1150
+ batchMultiplier: 0.5,
1151
+ contextWindow: 1048576
1152
+ },
1153
+ {
1154
+ model: "gemini-3.6-flash",
1155
+ provider: "gemini",
1156
+ modality: "text",
1157
+ currency: "USD",
1158
+ asOf: "2026-07-27",
1159
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1160
+ provenance: "vendor-pricing-page",
1161
+ tiers: [
1162
+ {
1163
+ inputPer1m: 1.5,
1164
+ outputPer1m: 7.5,
1165
+ cachedInputPer1m: 0.15,
1166
+ reasoningOutputPer1m: 7.5
1167
+ }
1168
+ ],
1169
+ batchMultiplier: 0.5,
1170
+ contextWindow: 1048576,
1171
+ notes: "Released 2026-07-21. Output pricing dropped ~17% from Gemini 3.5 Flash ($9.00 -> $7.50 per 1M); input unchanged."
1172
+ },
1173
+ {
1174
+ model: "gemini-3.5-flash",
1175
+ provider: "gemini",
1176
+ modality: "text",
1177
+ currency: "USD",
1178
+ asOf: "2026-07-27",
1179
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1180
+ provenance: "vendor-pricing-page",
1181
+ tiers: [
1182
+ {
1183
+ inputPer1m: 1.5,
1184
+ outputPer1m: 9,
1185
+ cachedInputPer1m: 0.15,
1186
+ reasoningOutputPer1m: 9
1187
+ }
1188
+ ],
1189
+ batchMultiplier: 0.5,
1190
+ contextWindow: 1048576
1191
+ },
1192
+ {
1193
+ model: "gemini-3.5-flash-lite",
1194
+ provider: "gemini",
1195
+ modality: "text",
1196
+ currency: "USD",
1197
+ asOf: "2026-07-27",
1198
+ source: "https://ai.google.dev/gemini-api/docs/pricing",
1199
+ provenance: "litellm-catalog",
1200
+ tiers: [
1201
+ {
1202
+ inputPer1m: 0.3,
1203
+ outputPer1m: 2.5,
1204
+ cachedInputPer1m: 0.03,
1205
+ reasoningOutputPer1m: 2.5
1206
+ }
1207
+ ],
1208
+ batchMultiplier: 0.5,
1209
+ contextWindow: 1048576
1210
+ },
1211
+ {
1212
+ model: "gemini-3.1-flash-lite",
1213
+ provider: "gemini",
1214
+ modality: "text",
1215
+ currency: "USD",
1216
+ asOf: "2026-07-27",
1217
+ source: "https://ai.google.dev/gemini-api/docs/pricing#gemini-3.1-flash-lite",
1218
+ provenance: "litellm-catalog",
1219
+ tiers: [
1220
+ {
1221
+ inputPer1m: 0.25,
1222
+ outputPer1m: 1.5,
1223
+ cachedInputPer1m: 0.025,
1224
+ reasoningOutputPer1m: 1.5
1225
+ }
1226
+ ],
1227
+ batchMultiplier: 0.5,
1228
+ contextWindow: 1048576
1229
+ },
1230
+ {
1231
+ model: "gemini-3-flash",
1232
+ provider: "gemini",
1233
+ aliases: [
1234
+ "gemini-3-flash-preview"
1235
+ ],
1236
+ modality: "text",
1237
+ currency: "USD",
1238
+ asOf: "2026-07-27",
1239
+ source: "https://ai.google.dev/pricing/gemini-3",
1240
+ provenance: "litellm-catalog",
1241
+ tiers: [
1242
+ {
1243
+ inputPer1m: 0.5,
1244
+ outputPer1m: 3,
1245
+ cachedInputPer1m: 0.05,
1246
+ reasoningOutputPer1m: 3
1247
+ }
1248
+ ],
1249
+ contextWindow: 1048576
1250
+ },
1251
+ {
1252
+ model: "gemini-2.5-pro",
1253
+ provider: "gemini",
1254
+ modality: "text",
1255
+ currency: "USD",
1256
+ asOf: "2026-07-27",
1257
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1258
+ provenance: "litellm-catalog",
1259
+ tiers: [
1260
+ {
1261
+ maxInputTokens: 2e5,
1262
+ inputPer1m: 1.25,
1263
+ outputPer1m: 10,
1264
+ cachedInputPer1m: 0.125
1265
+ },
1266
+ {
1267
+ inputPer1m: 2.5,
1268
+ outputPer1m: 15,
1269
+ cachedInputPer1m: 0.25
1270
+ }
1271
+ ],
1272
+ contextWindow: 1048576
1273
+ },
1274
+ {
1275
+ model: "gemini-2.5-flash",
1276
+ provider: "gemini",
1277
+ modality: "text",
1278
+ currency: "USD",
1279
+ asOf: "2026-07-27",
1280
+ source: "https://ai.google.dev/gemini-api/docs/models#gemini-2.5-flash-preview",
1281
+ provenance: "litellm-catalog",
1282
+ tiers: [
1283
+ {
1284
+ inputPer1m: 0.3,
1285
+ outputPer1m: 2.5,
1286
+ cachedInputPer1m: 0.03,
1287
+ reasoningOutputPer1m: 2.5
1288
+ }
1289
+ ],
1290
+ contextWindow: 1048576
1291
+ },
1292
+ {
1293
+ model: "gemini-2.5-flash-lite",
1294
+ provider: "gemini",
1295
+ modality: "text",
1296
+ currency: "USD",
1297
+ asOf: "2026-07-27",
1298
+ source: "https://ai.google.dev/gemini-api/docs/models#gemini-2.5-flash-lite",
1299
+ provenance: "litellm-catalog",
1300
+ tiers: [
1301
+ {
1302
+ inputPer1m: 0.1,
1303
+ outputPer1m: 0.4,
1304
+ cachedInputPer1m: 0.01,
1305
+ reasoningOutputPer1m: 0.4
1306
+ }
1307
+ ],
1308
+ contextWindow: 1048576
1309
+ },
1310
+ {
1311
+ model: "gemini-2.0-flash",
1312
+ provider: "gemini",
1313
+ modality: "text",
1314
+ currency: "USD",
1315
+ asOf: "2026-07-27",
1316
+ source: "https://ai.google.dev/pricing#2_0flash",
1317
+ provenance: "litellm-catalog",
1318
+ tiers: [
1319
+ {
1320
+ inputPer1m: 0.1,
1321
+ outputPer1m: 0.4,
1322
+ cachedInputPer1m: 0.025
1323
+ }
1324
+ ],
1325
+ contextWindow: 1048576,
1326
+ notes: "Gemini Developer API price. Vertex AI lists $0.15/$0.60 per 1M for the same model \u2014 see the vertex entry."
1327
+ },
1328
+ {
1329
+ model: "gemini-2.0-flash-lite",
1330
+ provider: "gemini",
1331
+ modality: "text",
1332
+ currency: "USD",
1333
+ asOf: "2026-07-27",
1334
+ source: "https://ai.google.dev/gemini-api/docs/pricing#gemini-2.0-flash-lite",
1335
+ provenance: "litellm-catalog",
1336
+ tiers: [
1337
+ {
1338
+ inputPer1m: 0.075,
1339
+ outputPer1m: 0.3,
1340
+ cachedInputPer1m: 0.01875
1341
+ }
1342
+ ],
1343
+ contextWindow: 1048576
1344
+ },
1345
+ {
1346
+ model: "gemini-2.0-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: 0.15,
1356
+ outputPer1m: 0.6
1357
+ }
1358
+ ],
1359
+ batchMultiplier: 0.5,
1360
+ notes: "Vertex AI lists $0.15/$0.60 per 1M; the Gemini Developer API lists $0.10/$0.40 for the same model."
1361
+ },
1362
+ {
1363
+ model: "gemini-3.1-pro",
1364
+ provider: "vertex",
1365
+ aliases: [
1366
+ "gemini-3.1-pro-preview"
1367
+ ],
1368
+ modality: "text",
1369
+ currency: "USD",
1370
+ asOf: "2026-07-27",
1371
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1372
+ provenance: "vendor-pricing-page",
1373
+ tiers: [
1374
+ {
1375
+ maxInputTokens: 2e5,
1376
+ inputPer1m: 2,
1377
+ outputPer1m: 12,
1378
+ cachedInputPer1m: 0.2,
1379
+ reasoningOutputPer1m: 12
1380
+ },
1381
+ {
1382
+ inputPer1m: 4,
1383
+ outputPer1m: 18,
1384
+ cachedInputPer1m: 0.4,
1385
+ reasoningOutputPer1m: 18
1386
+ }
1387
+ ],
1388
+ batchMultiplier: 0.5,
1389
+ contextWindow: 1048576
1390
+ },
1391
+ {
1392
+ model: "gemini-3.6-flash",
1393
+ provider: "vertex",
1394
+ modality: "text",
1395
+ currency: "USD",
1396
+ asOf: "2026-07-27",
1397
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1398
+ provenance: "vendor-pricing-page",
1399
+ tiers: [
1400
+ {
1401
+ inputPer1m: 1.5,
1402
+ outputPer1m: 7.5,
1403
+ cachedInputPer1m: 0.15,
1404
+ reasoningOutputPer1m: 7.5
1405
+ }
1406
+ ],
1407
+ batchMultiplier: 0.5,
1408
+ contextWindow: 1048576
1409
+ },
1410
+ {
1411
+ model: "gemini-2.5-pro",
1412
+ provider: "vertex",
1413
+ modality: "text",
1414
+ currency: "USD",
1415
+ asOf: "2026-07-27",
1416
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1417
+ provenance: "vendor-pricing-page",
1418
+ tiers: [
1419
+ {
1420
+ maxInputTokens: 2e5,
1421
+ inputPer1m: 1.25,
1422
+ outputPer1m: 10,
1423
+ cachedInputPer1m: 0.13
1424
+ },
1425
+ {
1426
+ inputPer1m: 2.5,
1427
+ outputPer1m: 15,
1428
+ cachedInputPer1m: 0.25
1429
+ }
1430
+ ],
1431
+ batchMultiplier: 0.5,
1432
+ contextWindow: 1048576
1433
+ },
1434
+ {
1435
+ model: "gemini-2.5-flash",
1436
+ provider: "vertex",
1437
+ modality: "text",
1438
+ currency: "USD",
1439
+ asOf: "2026-07-27",
1440
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1441
+ provenance: "vendor-pricing-page",
1442
+ tiers: [
1443
+ {
1444
+ inputPer1m: 0.3,
1445
+ outputPer1m: 2.5,
1446
+ cachedInputPer1m: 0.03,
1447
+ reasoningOutputPer1m: 2.5
1448
+ }
1449
+ ],
1450
+ batchMultiplier: 0.5,
1451
+ contextWindow: 1048576
1452
+ },
1453
+ {
1454
+ model: "claude-sonnet-4-6",
1455
+ provider: "openrouter",
1456
+ modality: "text",
1457
+ currency: "USD",
1458
+ asOf: "2026-07-27",
1459
+ source: "https://openrouter.ai/anthropic/claude-sonnet-4.6",
1460
+ provenance: "litellm-catalog",
1461
+ tiers: [
1462
+ {
1463
+ maxInputTokens: 2e5,
1464
+ inputPer1m: 3,
1465
+ outputPer1m: 15,
1466
+ cachedInputPer1m: 0.3,
1467
+ cacheWritePer1m: 3.75
1468
+ },
1469
+ {
1470
+ inputPer1m: 6,
1471
+ outputPer1m: 22.5,
1472
+ cachedInputPer1m: 0.6,
1473
+ cacheWritePer1m: 7.5
1474
+ }
1475
+ ],
1476
+ contextWindow: 1e6
1477
+ },
1478
+ {
1479
+ model: "claude-haiku-4-5",
1480
+ provider: "openrouter",
1481
+ modality: "text",
1482
+ currency: "USD",
1483
+ asOf: "2026-07-27",
1484
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1485
+ provenance: "litellm-catalog",
1486
+ tiers: [
1487
+ {
1488
+ inputPer1m: 1,
1489
+ outputPer1m: 5,
1490
+ cachedInputPer1m: 0.1,
1491
+ cacheWritePer1m: 1.25
1492
+ }
1493
+ ],
1494
+ contextWindow: 2e5
1495
+ },
1496
+ {
1497
+ model: "gpt-5",
1498
+ provider: "openrouter",
1499
+ modality: "text",
1500
+ currency: "USD",
1501
+ asOf: "2026-07-27",
1502
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1503
+ provenance: "litellm-catalog",
1504
+ tiers: [
1505
+ {
1506
+ inputPer1m: 1.25,
1507
+ outputPer1m: 10,
1508
+ cachedInputPer1m: 0.125
1509
+ }
1510
+ ],
1511
+ contextWindow: 272e3
1512
+ },
1513
+ {
1514
+ model: "gpt-5-mini",
1515
+ provider: "openrouter",
1516
+ modality: "text",
1517
+ currency: "USD",
1518
+ asOf: "2026-07-27",
1519
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1520
+ provenance: "litellm-catalog",
1521
+ tiers: [
1522
+ {
1523
+ inputPer1m: 0.25,
1524
+ outputPer1m: 2,
1525
+ cachedInputPer1m: 0.025
1526
+ }
1527
+ ],
1528
+ contextWindow: 272e3
1529
+ },
1530
+ {
1531
+ model: "gemini-3.1-pro",
1532
+ provider: "openrouter",
1533
+ aliases: [
1534
+ "gemini-3.1-pro-preview"
1535
+ ],
1536
+ modality: "text",
1537
+ currency: "USD",
1538
+ asOf: "2026-07-27",
1539
+ source: "https://openrouter.ai/google/gemini-3.1-pro-preview",
1540
+ provenance: "litellm-catalog",
1541
+ tiers: [
1542
+ {
1543
+ maxInputTokens: 2e5,
1544
+ inputPer1m: 2,
1545
+ outputPer1m: 12,
1546
+ cachedInputPer1m: 0.2
1547
+ },
1548
+ {
1549
+ inputPer1m: 4,
1550
+ outputPer1m: 18,
1551
+ cachedInputPer1m: 0.4,
1552
+ cacheWritePer1m: 0.25
1553
+ }
1554
+ ],
1555
+ contextWindow: 1048576
1556
+ },
1557
+ {
1558
+ model: "text-embedding-3-small",
1559
+ provider: "openai",
1560
+ modality: "embedding",
1561
+ currency: "USD",
1562
+ asOf: "2026-07-27",
1563
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1564
+ provenance: "litellm-catalog",
1565
+ tiers: [
1566
+ {
1567
+ inputPer1m: 0.02,
1568
+ outputPer1m: 0
1569
+ }
1570
+ ],
1571
+ batchMultiplier: 0.5,
1572
+ contextWindow: 8191
1573
+ },
1574
+ {
1575
+ model: "text-embedding-3-large",
1576
+ provider: "openai",
1577
+ modality: "embedding",
1578
+ currency: "USD",
1579
+ asOf: "2026-07-27",
1580
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1581
+ provenance: "litellm-catalog",
1582
+ tiers: [
1583
+ {
1584
+ inputPer1m: 0.13,
1585
+ outputPer1m: 0
1586
+ }
1587
+ ],
1588
+ batchMultiplier: 0.5,
1589
+ contextWindow: 8191
1590
+ },
1591
+ {
1592
+ model: "gemini-embedding-001",
1593
+ provider: "gemini",
1594
+ modality: "embedding",
1595
+ currency: "USD",
1596
+ asOf: "2026-07-27",
1597
+ source: "https://ai.google.dev/gemini-api/docs/embeddings#model-versions",
1598
+ provenance: "litellm-catalog",
1599
+ tiers: [
1600
+ {
1601
+ inputPer1m: 0.15,
1602
+ outputPer1m: 0
1603
+ }
1604
+ ],
1605
+ contextWindow: 2048
1606
+ },
1607
+ {
1608
+ model: "dall-e-3",
1609
+ provider: "openai",
1610
+ modality: "image",
1611
+ currency: "USD",
1612
+ asOf: "2026-07-27",
1613
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1614
+ provenance: "litellm-catalog",
1615
+ rates: [
1616
+ {
1617
+ unit: "per_image",
1618
+ amount: 0.04,
1619
+ variant: "1024x1024 standard"
1620
+ }
1621
+ ]
1622
+ },
1623
+ {
1624
+ model: "gemini-3-pro-image",
1625
+ provider: "gemini",
1626
+ modality: "image",
1627
+ currency: "USD",
1628
+ asOf: "2026-07-27",
1629
+ source: "https://ai.google.dev/gemini-api/docs/pricing",
1630
+ provenance: "litellm-catalog",
1631
+ rates: [
1632
+ {
1633
+ unit: "per_image",
1634
+ amount: 0.134,
1635
+ variant: "default output resolution"
1636
+ }
1637
+ ],
1638
+ 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."
1639
+ },
1640
+ {
1641
+ model: "imagen-4.0-generate-001",
1642
+ provider: "vertex",
1643
+ modality: "image",
1644
+ currency: "USD",
1645
+ asOf: "2026-07-27",
1646
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
1647
+ provenance: "litellm-catalog",
1648
+ rates: [
1649
+ {
1650
+ unit: "per_image",
1651
+ amount: 0.04
1652
+ }
1653
+ ]
1654
+ },
1655
+ {
1656
+ model: "veo-3.1-generate-001",
1657
+ provider: "gemini",
1658
+ modality: "video",
1659
+ currency: "USD",
1660
+ asOf: "2026-07-27",
1661
+ source: "https://ai.google.dev/gemini-api/docs/video",
1662
+ provenance: "litellm-catalog",
1663
+ rates: [
1664
+ {
1665
+ unit: "per_second",
1666
+ amount: 0.4
1667
+ }
1668
+ ]
1669
+ },
1670
+ {
1671
+ model: "veo-3.1-generate-001",
1672
+ provider: "vertex",
1673
+ modality: "video",
1674
+ currency: "USD",
1675
+ asOf: "2026-07-27",
1676
+ source: "https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/veo",
1677
+ provenance: "litellm-catalog",
1678
+ rates: [
1679
+ {
1680
+ unit: "per_second",
1681
+ amount: 0.4
1682
+ }
1683
+ ]
1684
+ },
1685
+ {
1686
+ model: "tts-1",
1687
+ provider: "openai",
1688
+ modality: "speech",
1689
+ currency: "USD",
1690
+ asOf: "2026-07-27",
1691
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1692
+ provenance: "litellm-catalog",
1693
+ rates: [
1694
+ {
1695
+ unit: "per_character",
1696
+ amount: 15e-6
1697
+ }
1698
+ ],
1699
+ notes: "$15 per 1M characters."
1700
+ },
1701
+ {
1702
+ model: "tts-1-hd",
1703
+ provider: "openai",
1704
+ modality: "speech",
1705
+ currency: "USD",
1706
+ asOf: "2026-07-27",
1707
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1708
+ provenance: "litellm-catalog",
1709
+ rates: [
1710
+ {
1711
+ unit: "per_character",
1712
+ amount: 3e-5
1713
+ }
1714
+ ],
1715
+ notes: "$30 per 1M characters."
1716
+ },
1717
+ {
1718
+ model: "whisper-1",
1719
+ provider: "openai",
1720
+ modality: "transcription",
1721
+ currency: "USD",
1722
+ asOf: "2026-07-27",
1723
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
1724
+ provenance: "litellm-catalog",
1725
+ rates: [
1726
+ {
1727
+ unit: "per_audio_minute",
1728
+ amount: 6e-3
1729
+ }
1730
+ ],
1731
+ notes: "litellm records $0.0001 per audio second; $0.006/minute is that rate x 60."
1732
+ }
1733
+ ]
1734
+ };
1735
+
1736
+ // src/core/router/pricing.ts
1737
+ var DATASET = pricing_data_default;
1738
+ function normalizeForPricing(id) {
1739
+ let s = id.trim().toLowerCase();
1740
+ s = s.replace(/^models\//, "");
1741
+ const slash = s.lastIndexOf("/");
1742
+ if (slash !== -1) s = s.slice(slash + 1);
1743
+ const tag = s.search(/[:@]/);
1744
+ if (tag !== -1) s = s.slice(0, tag);
1745
+ s = s.replace(/-latest$/, "");
1746
+ s = s.replace(/-preview(?:-\d{2}-\d{2})?$/, "");
1747
+ s = s.replace(/-\d{4}-\d{2}-\d{2}$/, "");
1748
+ s = s.replace(/-\d{8}$/, "");
1749
+ s = s.replace(/-preview$/, "");
1750
+ return s;
1751
+ }
1752
+ function indexKey(model, provider, region) {
1753
+ return `${provider}|${normalizeForPricing(model)}|${region ?? ""}`;
1754
+ }
1755
+ var INDEX = /* @__PURE__ */ new Map();
1756
+ for (const entry of DATASET.entries) {
1757
+ for (const name of [entry.model, ...entry.aliases ?? []]) {
1758
+ const withRegion = indexKey(name, entry.provider, entry.region);
1759
+ if (!INDEX.has(withRegion)) INDEX.set(withRegion, entry);
1760
+ const bare = indexKey(name, entry.provider);
1761
+ const existing = INDEX.get(bare);
1762
+ if (!existing || existing.region && existing.region !== "global" && entry.region === "global") {
1763
+ INDEX.set(bare, entry);
1764
+ }
1765
+ }
1766
+ }
1767
+ function findPricing(modelId, provider, opts = {}) {
1768
+ const ids = [modelId, opts.baseModelId].filter((x) => !!x);
1769
+ const providers = [provider, ...opts.fallbackProviders ?? []];
1770
+ for (const p of providers) {
1771
+ for (const id of ids) {
1772
+ const hit = (opts.region ? INDEX.get(indexKey(id, p, opts.region)) : void 0) ?? INDEX.get(indexKey(id, p));
1773
+ if (hit) return { entry: hit, matchedProvider: p, viaFallback: p !== provider };
1774
+ }
1775
+ }
1776
+ return null;
1777
+ }
1778
+ function tierFor(entry, inputTokens = 0) {
1779
+ const tiers = entry.tiers;
1780
+ if (!tiers?.length) return null;
1781
+ for (const t of tiers) {
1782
+ if (t.maxInputTokens === void 0 || inputTokens <= t.maxInputTokens) return t;
1783
+ }
1784
+ return tiers[tiers.length - 1] ?? null;
1785
+ }
1786
+ var PER_1M_TO_PER_1K = 1 / 1e3;
1787
+ function tokenRatesPer1k(entry, opts = {}) {
1788
+ const tier = tierFor(entry, opts.inputTokens ?? 0);
1789
+ if (!tier) return null;
1790
+ const mult = (opts.batch ? entry.batchMultiplier ?? 1 : 1) * PER_1M_TO_PER_1K;
1791
+ const out = {
1792
+ input: tier.inputPer1m * mult,
1793
+ output: tier.outputPer1m * mult
1794
+ };
1795
+ if (tier.cachedInputPer1m !== void 0) out.cachedInput = tier.cachedInputPer1m * mult;
1796
+ if (tier.cacheWritePer1m !== void 0) out.cacheWrite = tier.cacheWritePer1m * mult;
1797
+ if (tier.reasoningOutputPer1m !== void 0) out.reasoningOutput = tier.reasoningOutputPer1m * mult;
1798
+ return out;
1799
+ }
1800
+ var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "0.0.0.0", "::1", "[::1]"]);
1801
+ function isLoopbackOrPrivateHost(url) {
1802
+ if (!url) return false;
1803
+ try {
1804
+ const host = new URL(url).hostname.toLowerCase().replace(/^\[|\]$/g, "");
1805
+ if (LOOPBACK_HOSTS.has(host) || LOOPBACK_HOSTS.has(`[${host}]`)) return true;
1806
+ if (host.endsWith(".local")) return true;
1807
+ if (/^127\./.test(host)) return true;
1808
+ if (/^10\./.test(host)) return true;
1809
+ if (/^192\.168\./.test(host)) return true;
1810
+ if (/^172\.(1[6-9]|2\d|3[01])\./.test(host)) return true;
1811
+ return false;
1812
+ } catch {
1813
+ return false;
1814
+ }
1815
+ }
1816
+ function isLocalEndpoint(cfg) {
1817
+ if (typeof cfg.local === "boolean") return cfg.local;
1818
+ if (cfg.type === "ollama") return true;
1819
+ if (cfg.type === "openai-compatible") return isLoopbackOrPrivateHost(cfg.baseUrl);
1820
+ return false;
1821
+ }
1822
+ var UNKNOWN = { input: 0, output: 0, unknown: true, free: false };
1823
+ var FREE = { input: 0, output: 0, unknown: false, free: true };
1824
+ function resolvePricing(model, opts = {}) {
1825
+ if (model.isLocal) return FREE;
1826
+ const fallbackProviders = model.provider === "azure" ? ["openai"] : model.provider === "gemini" ? ["vertex"] : [];
1827
+ const match = findPricing(model.id, model.provider, {
1828
+ region: opts.region,
1829
+ baseModelId: model.baseModelId,
1830
+ fallbackProviders
1831
+ });
1832
+ if (!match) return UNKNOWN;
1833
+ const rates = tokenRatesPer1k(match.entry, { inputTokens: opts.inputTokens, batch: opts.batch });
1834
+ if (!rates) return UNKNOWN;
1835
+ return {
1836
+ input: rates.input,
1837
+ output: rates.output,
1838
+ unknown: false,
1839
+ free: false,
1840
+ entry: match.entry,
1841
+ ...match.viaFallback ? { estimatedFromProvider: match.matchedProvider } : {}
1842
+ };
1843
+ }
1844
+ function withResolvedPricing(model, opts = {}) {
1845
+ const p = resolvePricing(model, opts);
1846
+ return {
1847
+ ...model,
1848
+ inputCostPer1kTokens: p.input,
1849
+ outputCostPer1kTokens: p.output,
1850
+ ...p.unknown ? { pricingUnknown: true } : { pricingUnknown: false }
1851
+ };
1852
+ }
1853
+ function isPricingUnknown(model) {
1854
+ return model.pricingUnknown === true && !model.isLocal;
1855
+ }
1856
+ var BLENDED_COST_CEILING = 0.05;
1857
+ function blendedCostPer1k(model) {
1858
+ if (isPricingUnknown(model)) return BLENDED_COST_CEILING;
1859
+ return model.inputCostPer1kTokens + model.outputCostPer1kTokens * 2;
1860
+ }
1861
+ var DISAGREEMENT_THRESHOLD = 0.02;
1862
+ function reconcilePrice(model, live) {
1863
+ const baseline = resolvePricing(model);
1864
+ const liveIsZero = !(live.input > 0) && !(live.output > 0);
1865
+ if (liveIsZero && !model.isLocal) {
1866
+ return { input: baseline.input, output: baseline.output, accepted: false };
1867
+ }
1868
+ if (baseline.unknown || !baseline.entry) {
1869
+ return { input: live.input, output: live.output, accepted: true };
1870
+ }
1871
+ const dsBlend = baseline.input + baseline.output * 2;
1872
+ const liveBlend = live.input + live.output * 2;
1873
+ const ratio = dsBlend > 0 ? liveBlend / dsBlend : Number.POSITIVE_INFINITY;
1874
+ const material = dsBlend > 0 && Math.abs(ratio - 1) > DISAGREEMENT_THRESHOLD;
1875
+ return {
1876
+ input: live.input,
1877
+ output: live.output,
1878
+ accepted: true,
1879
+ ...material ? {
1880
+ disagreement: {
1881
+ modelId: model.id,
1882
+ provider: model.provider,
1883
+ dataset: { input: baseline.input, output: baseline.output },
1884
+ live: { input: live.input, output: live.output },
1885
+ ratio: Math.round(ratio * 1e3) / 1e3,
1886
+ datasetAsOf: baseline.entry.asOf,
1887
+ datasetSource: baseline.entry.source
1888
+ }
1889
+ } : {}
1890
+ };
1891
+ }
1892
+
241
1893
  // src/constants.ts
242
- var CASCADE_VERSION = "0.48.0";
1894
+ var CASCADE_VERSION = "0.49.0";
243
1895
  var CASCADE_CONFIG_DIR = ".cascade";
244
1896
  var CASCADE_MD_FILE = "CASCADE.md";
245
1897
  var CASCADE_IGNORE_FILE = ".cascadeignore";
@@ -588,6 +2240,13 @@ var MODELS = {
588
2240
  for (const _m of Object.values(MODELS)) {
589
2241
  if (_m.supportsToolUse === void 0) _m.supportsToolUse = !_m.isLocal;
590
2242
  }
2243
+ for (const _m of Object.values(MODELS)) {
2244
+ const priced = resolvePricing(_m);
2245
+ if (priced.unknown || priced.free || priced.estimatedFromProvider) continue;
2246
+ _m.inputCostPer1kTokens = priced.input;
2247
+ _m.outputCostPer1kTokens = priced.output;
2248
+ _m.pricingUnknown = false;
2249
+ }
591
2250
  var T1_MODEL_PRIORITY = [
592
2251
  "gpt-5.5",
593
2252
  "gpt-5.4",
@@ -678,21 +2337,49 @@ var PROVIDER_DISPLAY_NAMES = {
678
2337
 
679
2338
  // src/utils/cost.ts
680
2339
  function resolveModelPricing(model) {
681
- let input = model.inputCostPer1kTokens;
682
- let output = model.outputCostPer1kTokens;
683
- if (input === 0 && output === 0 && model.id && !model.isLocal) {
2340
+ if (model.isLocal) return { input: 0, output: 0, unknown: false };
2341
+ if (model.inputCostPer1kTokens > 0 || model.outputCostPer1kTokens > 0) {
2342
+ return {
2343
+ input: model.inputCostPer1kTokens,
2344
+ output: model.outputCostPer1kTokens,
2345
+ unknown: false
2346
+ };
2347
+ }
2348
+ const fromDataset = resolvePricing(model);
2349
+ if (!fromDataset.unknown) {
2350
+ return {
2351
+ input: fromDataset.input,
2352
+ output: fromDataset.output,
2353
+ unknown: false,
2354
+ ...fromDataset.estimatedFromProvider ? { estimatedFromProvider: fromDataset.estimatedFromProvider } : {}
2355
+ };
2356
+ }
2357
+ if (model.id) {
684
2358
  const known = Object.values(MODELS).find((m) => m.id === model.id && !m.isLocal);
685
- if (known) {
686
- input = known.inputCostPer1kTokens;
687
- output = known.outputCostPer1kTokens;
2359
+ if (known && (known.inputCostPer1kTokens > 0 || known.outputCostPer1kTokens > 0)) {
2360
+ return {
2361
+ input: known.inputCostPer1kTokens,
2362
+ output: known.outputCostPer1kTokens,
2363
+ unknown: false
2364
+ };
688
2365
  }
689
2366
  }
690
- return { input, output };
2367
+ return { input: 0, output: 0, unknown: true };
691
2368
  }
692
2369
  function calculateCost(inputTokens, outputTokens, model) {
693
2370
  const { input, output } = resolveModelPricing(model);
694
2371
  return inputTokens / 1e3 * input + outputTokens / 1e3 * output;
695
2372
  }
2373
+ function buildTokenUsage(inputTokens, outputTokens, model) {
2374
+ const { input, output, unknown } = resolveModelPricing(model);
2375
+ return {
2376
+ inputTokens,
2377
+ outputTokens,
2378
+ totalTokens: inputTokens + outputTokens,
2379
+ estimatedCostUsd: inputTokens / 1e3 * input + outputTokens / 1e3 * output,
2380
+ ...unknown ? { costUnknown: true } : {}
2381
+ };
2382
+ }
696
2383
 
697
2384
  // src/providers/base.ts
698
2385
  var BaseProvider = class {
@@ -712,12 +2399,7 @@ var BaseProvider = class {
712
2399
  return calculateCost(inputTokens, outputTokens, this.model);
713
2400
  }
714
2401
  makeUsage(inputTokens, outputTokens) {
715
- return {
716
- inputTokens,
717
- outputTokens,
718
- totalTokens: inputTokens + outputTokens,
719
- estimatedCostUsd: this.estimateCost(inputTokens, outputTokens)
720
- };
2402
+ return buildTokenUsage(inputTokens, outputTokens, this.model);
721
2403
  }
722
2404
  };
723
2405
 
@@ -886,7 +2568,7 @@ var AnthropicProvider = class extends BaseProvider {
886
2568
  return data.data.filter((m) => isChatModel(m.id)).map((m) => {
887
2569
  const known = Object.values(MODELS).find((km) => km.id === m.id && km.provider === "anthropic");
888
2570
  if (known) return known;
889
- return {
2571
+ return withResolvedPricing({
890
2572
  id: m.id,
891
2573
  name: m.display_name || m.id,
892
2574
  provider: "anthropic",
@@ -897,7 +2579,7 @@ var AnthropicProvider = class extends BaseProvider {
897
2579
  maxOutputTokens: 8e3,
898
2580
  supportsStreaming: true,
899
2581
  isLocal: false
900
- };
2582
+ });
901
2583
  });
902
2584
  } catch {
903
2585
  return Object.values(MODELS).filter((m) => m.provider === "anthropic");
@@ -1101,7 +2783,7 @@ var OpenAIProvider = class extends BaseProvider {
1101
2783
  return response.data.filter((m) => isChatModel(m.id)).map((m) => {
1102
2784
  const known = Object.values(MODELS).find((km) => km.id === m.id && km.provider === "openai");
1103
2785
  if (known) return known;
1104
- return {
2786
+ return withResolvedPricing({
1105
2787
  id: m.id,
1106
2788
  name: m.id,
1107
2789
  provider: "openai",
@@ -1112,7 +2794,7 @@ var OpenAIProvider = class extends BaseProvider {
1112
2794
  maxOutputTokens: 4e3,
1113
2795
  supportsStreaming: true,
1114
2796
  isLocal: false
1115
- };
2797
+ });
1116
2798
  });
1117
2799
  } catch {
1118
2800
  return Object.values(MODELS).filter((m) => m.provider === "openai");
@@ -1208,6 +2890,10 @@ function azureModelForDeployment(cfg) {
1208
2890
  const baseModelId = cfg.model?.trim() || inferAzureBaseModel(id) || void 0;
1209
2891
  const base = baseModelId ? MODELS[baseModelId] : void 0;
1210
2892
  if (base) {
2893
+ const azurePrice = resolvePricing(
2894
+ { id, provider: "azure", isLocal: false, baseModelId },
2895
+ { region: cfg.region }
2896
+ );
1211
2897
  return {
1212
2898
  ...base,
1213
2899
  id,
@@ -1216,7 +2902,12 @@ function azureModelForDeployment(cfg) {
1216
2902
  provider: "azure",
1217
2903
  baseModelId,
1218
2904
  // real identity for benchmark + live pricing
1219
- supportsToolUse: base.supportsToolUse ?? true
2905
+ supportsToolUse: base.supportsToolUse ?? true,
2906
+ ...azurePrice.unknown ? {} : {
2907
+ inputCostPer1kTokens: azurePrice.input,
2908
+ outputCostPer1kTokens: azurePrice.output,
2909
+ pricingUnknown: false
2910
+ }
1220
2911
  };
1221
2912
  }
1222
2913
  return {
@@ -1379,7 +3070,7 @@ var GeminiProvider = class extends BaseProvider {
1379
3070
  (km) => km.id === id && km.provider === "gemini"
1380
3071
  );
1381
3072
  if (known) return known;
1382
- return {
3073
+ return withResolvedPricing({
1383
3074
  id,
1384
3075
  name: m.displayName || id,
1385
3076
  provider: "gemini",
@@ -1390,7 +3081,7 @@ var GeminiProvider = class extends BaseProvider {
1390
3081
  maxOutputTokens: m.outputTokenLimit || 8e3,
1391
3082
  supportsStreaming: true,
1392
3083
  isLocal: false
1393
- };
3084
+ });
1394
3085
  });
1395
3086
  } catch {
1396
3087
  return Object.values(MODELS).filter((m) => m.provider === "gemini");
@@ -1737,9 +3428,10 @@ var OllamaProvider = class extends BaseProvider {
1737
3428
  return supportedKeywords.some((k) => name.includes(k)) && isChatModel(name);
1738
3429
  });
1739
3430
  const shows = await Promise.all(entries.map((m) => this.showModel(m.name)));
3431
+ const local = isLocalEndpoint({ ...this.config, type: "ollama" });
1740
3432
  return entries.map((m, i) => {
1741
3433
  const show = shows[i];
1742
- return {
3434
+ return withResolvedPricing({
1743
3435
  id: m.name,
1744
3436
  name: m.name,
1745
3437
  provider: "ollama",
@@ -1749,10 +3441,10 @@ var OllamaProvider = class extends BaseProvider {
1749
3441
  outputCostPer1kTokens: 0,
1750
3442
  maxOutputTokens: 4e3,
1751
3443
  supportsStreaming: true,
1752
- isLocal: true,
3444
+ isLocal: local,
1753
3445
  supportsToolUse: show?.tools ?? isToolCapable(m.name),
1754
3446
  minSizeB: this.parseSizeB(m.details?.parameter_size)
1755
- };
3447
+ });
1756
3448
  });
1757
3449
  } catch {
1758
3450
  return [];
@@ -1855,7 +3547,8 @@ var OpenAICompatibleProvider = class extends OpenAIProvider {
1855
3547
  }).filter((x) => typeof x === "string" && x.length > 0);
1856
3548
  if (ids.length === 0) return [this.model];
1857
3549
  const chatIds = ids.filter((id) => isChatModel(id));
1858
- return (chatIds.length ? chatIds : ids).map((id) => ({
3550
+ const local = isLocalEndpoint(this.config);
3551
+ return (chatIds.length ? chatIds : ids).map((id) => withResolvedPricing({
1859
3552
  id,
1860
3553
  name: id,
1861
3554
  provider: "openai-compatible",
@@ -1865,7 +3558,7 @@ var OpenAICompatibleProvider = class extends OpenAIProvider {
1865
3558
  outputCostPer1kTokens: 0,
1866
3559
  maxOutputTokens: 4e3,
1867
3560
  supportsStreaming: true,
1868
- isLocal: false
3561
+ isLocal: local
1869
3562
  }));
1870
3563
  }
1871
3564
  async isAvailable() {
@@ -2080,7 +3773,7 @@ var ModelSelector = class {
2080
3773
  else if (this.availableProviders.size === 1) providerStr = Array.from(this.availableProviders)[0];
2081
3774
  }
2082
3775
  if (providerStr && this.availableProviders.has(providerStr)) {
2083
- const dynamicModel = {
3776
+ const dynamicModel = withResolvedPricing({
2084
3777
  id: actualId,
2085
3778
  name: actualId,
2086
3779
  provider: providerStr,
@@ -2091,7 +3784,7 @@ var ModelSelector = class {
2091
3784
  maxOutputTokens: 8e3,
2092
3785
  supportsStreaming: true,
2093
3786
  isLocal: providerStr === "ollama"
2094
- };
3787
+ });
2095
3788
  this.addDynamicModel(dynamicModel);
2096
3789
  return dynamicModel;
2097
3790
  }
@@ -2483,6 +4176,8 @@ var LiveDataProvider = class {
2483
4176
  snapshot = null;
2484
4177
  prices = /* @__PURE__ */ new Map();
2485
4178
  capabilities = /* @__PURE__ */ new Map();
4179
+ /** Dataset-vs-live price mismatches, deduped by `provider:modelId`. */
4180
+ disagreements = /* @__PURE__ */ new Map();
2486
4181
  source = "bundled";
2487
4182
  fetchedAt = 0;
2488
4183
  loaded = false;
@@ -2636,14 +4331,45 @@ var LiveDataProvider = class {
2636
4331
  /**
2637
4332
  * Returns a price-corrected copy of each model when live pricing is known,
2638
4333
  * leaving the original untouched (so the shared catalog is never mutated).
4334
+ *
4335
+ * Reconciliation policy (see reconcilePrice in pricing.ts): the bundled
4336
+ * dataset is the authoritative baseline, and a live quote overrides it
4337
+ * because it is fresher by construction — but the disagreement is RECORDED,
4338
+ * not swallowed. A dataset/live mismatch is the best signal available that
4339
+ * the committed prices have gone stale, so it must be visible rather than
4340
+ * silently resolved in either direction. A live quote of $0 for a non-local
4341
+ * model is rejected outright: that is the very failure mode this change
4342
+ * exists to prevent, and a marketplace's free-tier alias must never zero out
4343
+ * the price of the paid model Cascade is actually calling.
2639
4344
  */
2640
4345
  applyLivePricing(models) {
2641
4346
  return models.map((m) => {
2642
4347
  const p = this.getLivePrice(m.baseModelId ?? m.id);
2643
4348
  if (!p) return m;
2644
- return { ...m, inputCostPer1kTokens: p.input, outputCostPer1kTokens: p.output };
4349
+ const reconciled = reconcilePrice(m, p);
4350
+ if (reconciled.disagreement) this.recordDisagreement(reconciled.disagreement);
4351
+ if (!reconciled.accepted) return m;
4352
+ return {
4353
+ ...m,
4354
+ inputCostPer1kTokens: reconciled.input,
4355
+ outputCostPer1kTokens: reconciled.output,
4356
+ pricingUnknown: false
4357
+ };
2645
4358
  });
2646
4359
  }
4360
+ recordDisagreement(d) {
4361
+ const key = `${d.provider}:${d.modelId}`;
4362
+ if (this.disagreements.has(key)) return;
4363
+ this.disagreements.set(key, d);
4364
+ }
4365
+ /**
4366
+ * Dataset-vs-live price mismatches seen this session, newest-model-first
4367
+ * insertion order. Surfaced by `cascade models --verbose`; a non-empty list
4368
+ * means src/core/router/pricing-data.json is probably due a refresh.
4369
+ */
4370
+ getPriceDisagreements() {
4371
+ return [...this.disagreements.values()];
4372
+ }
2647
4373
  /** Current capability facts for a model id, or null when unknown. */
2648
4374
  getCapability(modelId) {
2649
4375
  return this.capabilities.get(normalizeModelId2(modelId)) ?? null;
@@ -2840,7 +4566,9 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter__default.default {
2840
4566
  tokensByTier: {},
2841
4567
  inputTokensByTier: {},
2842
4568
  outputTokensByTier: {},
2843
- costByFeature: {}
4569
+ costByFeature: {},
4570
+ untrackedCostCalls: 0,
4571
+ untrackedCostModels: []
2844
4572
  };
2845
4573
  tierModels = /* @__PURE__ */ new Map();
2846
4574
  /**
@@ -3190,7 +4918,7 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter__default.default {
3190
4918
  `Model ${model.id} inference timed out after ${cloudTimeoutMs}ms`
3191
4919
  );
3192
4920
  }
3193
- const correctedCost = calculateCost(
4921
+ const corrected = buildTokenUsage(
3194
4922
  result.usage.inputTokens,
3195
4923
  result.usage.outputTokens,
3196
4924
  model
@@ -3199,7 +4927,8 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter__default.default {
3199
4927
  ...result,
3200
4928
  usage: {
3201
4929
  ...result.usage,
3202
- estimatedCostUsd: correctedCost
4930
+ estimatedCostUsd: corrected.estimatedCostUsd,
4931
+ ...corrected.costUnknown ? { costUnknown: true } : { costUnknown: void 0 }
3203
4932
  }
3204
4933
  };
3205
4934
  if (!result || typeof result.content !== "string" || !result.usage) {
@@ -3386,7 +5115,9 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter__default.default {
3386
5115
  tokensByTier: { ...this.stats.tokensByTier },
3387
5116
  inputTokensByTier: { ...this.stats.inputTokensByTier },
3388
5117
  outputTokensByTier: { ...this.stats.outputTokensByTier },
3389
- costByFeature: { ...this.stats.costByFeature }
5118
+ costByFeature: { ...this.stats.costByFeature },
5119
+ untrackedCostCalls: this.stats.untrackedCostCalls,
5120
+ untrackedCostModels: [...this.stats.untrackedCostModels]
3390
5121
  };
3391
5122
  }
3392
5123
  /**
@@ -3437,7 +5168,9 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter__default.default {
3437
5168
  tokensByTier: {},
3438
5169
  inputTokensByTier: {},
3439
5170
  outputTokensByTier: {},
3440
- costByFeature: {}
5171
+ costByFeature: {},
5172
+ untrackedCostCalls: 0,
5173
+ untrackedCostModels: []
3441
5174
  };
3442
5175
  this.sessionCostUsd = 0;
3443
5176
  this.budgetState = "ok";
@@ -3622,6 +5355,18 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter__default.default {
3622
5355
  if (featureTag) {
3623
5356
  this.stats.costByFeature[featureTag] = (this.stats.costByFeature[featureTag] ?? 0) + usage.estimatedCostUsd;
3624
5357
  }
5358
+ if (usage.costUnknown) {
5359
+ this.stats.untrackedCostCalls += 1;
5360
+ if (!this.stats.untrackedCostModels.includes(model.id)) {
5361
+ this.stats.untrackedCostModels.push(model.id);
5362
+ const capped = this.config?.budget?.maxCostPerRunUsd != null || this.config?.budget?.sessionBudgetUsd != null;
5363
+ this.emit("cost:untracked", {
5364
+ modelId: model.id,
5365
+ provider: model.provider,
5366
+ 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.`
5367
+ });
5368
+ }
5369
+ }
3625
5370
  this.runTokens += usage.totalTokens;
3626
5371
  this.runCostUsd += usage.estimatedCostUsd;
3627
5372
  this.updateBudgetState();
@@ -9129,7 +10874,18 @@ var ProviderConfigSchema = zod.z.object({
9129
10874
  apiVersion: zod.z.string().optional(),
9130
10875
  model: zod.z.string().optional(),
9131
10876
  authToken: zod.z.string().optional(),
9132
- credentialSource: zod.z.string().optional()
10877
+ credentialSource: zod.z.string().optional(),
10878
+ /**
10879
+ * "This endpoint is self-hosted, so inference genuinely costs $0."
10880
+ * Only meaningful for `ollama` and `openai-compatible`. Unset ⇒ inferred:
10881
+ * ollama is local, openai-compatible is local when its baseUrl is
10882
+ * loopback/LAN. Set it explicitly to override — e.g. `false` for an Ollama
10883
+ * instance you rent, `true` for a llama.cpp box on your own LAN reached by
10884
+ * hostname.
10885
+ */
10886
+ local: zod.z.boolean().optional(),
10887
+ /** Region for providers whose price varies by region (Azure: global | us | eu | …). */
10888
+ region: zod.z.string().optional()
9133
10889
  });
9134
10890
  var ModelOverridesSchema = zod.z.object({
9135
10891
  t1: zod.z.string().optional(),
@@ -9715,8 +11471,8 @@ var TaskAnalyzer = class {
9715
11471
  }
9716
11472
  costEfficiency(model, complexity) {
9717
11473
  if (this.tracker) return this.tracker.costEfficiencyScore(model, complexity);
9718
- const blended = model.inputCostPer1kTokens + model.outputCostPer1kTokens * 2;
9719
- const normalised = Math.min(1, blended / 0.05);
11474
+ const blended = blendedCostPer1k(model);
11475
+ const normalised = Math.min(1, blended / BLENDED_COST_CEILING);
9720
11476
  const complexityWeight = (6 - complexity) / 5;
9721
11477
  return Math.max(0.1, 1 - normalised * complexityWeight);
9722
11478
  }
@@ -9851,8 +11607,8 @@ var ModelPerformanceTracker = class {
9851
11607
  * normalised over $0.05 blended as the "expensive" ceiling.
9852
11608
  */
9853
11609
  costEfficiencyScore(model, complexity) {
9854
- const blended = model.inputCostPer1kTokens + model.outputCostPer1kTokens * 2;
9855
- const normalised = Math.min(1, blended / 0.05);
11610
+ const blended = blendedCostPer1k(model);
11611
+ const normalised = Math.min(1, blended / BLENDED_COST_CEILING);
9856
11612
  const complexityWeight = (6 - complexity) / 5;
9857
11613
  return Math.max(0.1, 1 - normalised * complexityWeight);
9858
11614
  }
@@ -12695,7 +14451,11 @@ _(incomplete: ${reasons.join("; ")})_` : partial;
12695
14451
  inputTokens: 0,
12696
14452
  outputTokens: 0,
12697
14453
  totalTokens: stats.totalTokens,
12698
- estimatedCostUsd: stats.totalCostUsd
14454
+ estimatedCostUsd: stats.totalCostUsd,
14455
+ // At least one call ran on a model with no known price, so its spend is
14456
+ // missing from the total above. Say so rather than letting the caller
14457
+ // present an undercount as the final figure.
14458
+ ...stats.untrackedCostCalls > 0 ? { costUnknown: true } : {}
12699
14459
  },
12700
14460
  t2Results,
12701
14461
  durationMs,
@@ -12765,7 +14525,8 @@ _(incomplete: ${reasons.join("; ")})_` : partial;
12765
14525
  inputTokens: 0,
12766
14526
  outputTokens: 0,
12767
14527
  totalTokens: stats2.totalTokens,
12768
- estimatedCostUsd: stats2.totalCostUsd
14528
+ estimatedCostUsd: stats2.totalCostUsd,
14529
+ ...stats2.untrackedCostCalls > 0 ? { costUnknown: true } : {}
12769
14530
  },
12770
14531
  t2Results: [],
12771
14532
  durationMs: Date.now() - startMs,
@@ -12789,7 +14550,8 @@ _(incomplete: ${reasons.join("; ")})_` : partial;
12789
14550
  inputTokens: result.usage?.inputTokens ?? 0,
12790
14551
  outputTokens: result.usage?.outputTokens ?? 0,
12791
14552
  totalTokens: stats.totalTokens,
12792
- estimatedCostUsd: stats.totalCostUsd
14553
+ estimatedCostUsd: stats.totalCostUsd,
14554
+ ...stats.untrackedCostCalls > 0 ? { costUnknown: true } : {}
12793
14555
  },
12794
14556
  t2Results: [],
12795
14557
  durationMs: Date.now() - startMs,
@@ -14573,7 +16335,10 @@ var DashboardServer = class {
14573
16335
  this.socket.broadcast("cost:update", {
14574
16336
  sessionId,
14575
16337
  totalTokens: result.usage.totalTokens,
14576
- totalCostUsd: result.usage.estimatedCostUsd
16338
+ totalCostUsd: result.usage.estimatedCostUsd,
16339
+ // True when a model with no known price was used: the total above is
16340
+ // an undercount, and the UI must not present it as the full spend.
16341
+ costUnknown: result.usage.costUnknown === true
14577
16342
  });
14578
16343
  this.throttledBroadcast("workspace");
14579
16344
  } catch (err) {
@@ -14886,7 +16651,8 @@ var DashboardServer = class {
14886
16651
  this.socket.broadcast("cost:update", {
14887
16652
  sessionId,
14888
16653
  totalTokens: result.usage.totalTokens,
14889
- totalCostUsd: result.usage.estimatedCostUsd
16654
+ totalCostUsd: result.usage.estimatedCostUsd,
16655
+ costUnknown: result.usage.costUnknown === true
14890
16656
  });
14891
16657
  this.throttledBroadcast("workspace");
14892
16658
  } catch (err) {
@@ -15428,7 +17194,8 @@ ${prompt}`;
15428
17194
  this.socket.broadcast("cost:update", {
15429
17195
  sessionId,
15430
17196
  totalTokens: result.usage.totalTokens,
15431
- totalCostUsd: result.usage.estimatedCostUsd
17197
+ totalCostUsd: result.usage.estimatedCostUsd,
17198
+ costUnknown: result.usage.costUnknown === true
15432
17199
  });
15433
17200
  this.socket.broadcastToRoom(`session:${sessionId}`, "session:complete", { sessionId, result });
15434
17201
  this.throttledBroadcast("workspace");
@@ -15984,12 +17751,19 @@ var CloudClient = class _CloudClient {
15984
17751
  );
15985
17752
  await openUrl(authorizeUrl);
15986
17753
  const code = await listener.waitForCode;
15987
- const res = await fetch(this.url("/api/native/token"), {
15988
- method: "POST",
15989
- headers: { "Content-Type": "application/json" },
15990
- body: JSON.stringify({ code, code_verifier: verifier })
15991
- });
15992
- if (!res.ok) throw new Error("Sign-in could not be completed. Please try again.");
17754
+ let res;
17755
+ try {
17756
+ res = await fetch(this.url("/api/native/token"), {
17757
+ method: "POST",
17758
+ headers: { "Content-Type": "application/json" },
17759
+ body: JSON.stringify({ code, code_verifier: verifier })
17760
+ });
17761
+ } catch (err) {
17762
+ throw new Error(
17763
+ `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)})`
17764
+ );
17765
+ }
17766
+ if (!res.ok) throw new Error(await loginFailureMessage(res, this.serverUrl));
15993
17767
  const tokens = await res.json();
15994
17768
  return await this.finishLogin(tokens);
15995
17769
  } finally {
@@ -16163,6 +17937,22 @@ function sleep(ms, signal) {
16163
17937
  }, { once: true });
16164
17938
  });
16165
17939
  }
17940
+ async function loginFailureMessage(res, serverUrl) {
17941
+ const body = await res.text().catch(() => "");
17942
+ let apiError = "";
17943
+ try {
17944
+ apiError = String(JSON.parse(body).error ?? "");
17945
+ } catch {
17946
+ }
17947
+ if (apiError === "invalid_grant") {
17948
+ 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.";
17949
+ }
17950
+ if (apiError) return `Sign-in failed: ${apiError} (HTTP ${res.status}).`;
17951
+ if (res.status === 404 || /<html/i.test(body)) {
17952
+ 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.`;
17953
+ }
17954
+ return `Sign-in could not be completed (HTTP ${res.status}). Please try again.`;
17955
+ }
16166
17956
  function base64url(buf) {
16167
17957
  return buf.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
16168
17958
  }