cascade-ai 0.48.1 → 0.50.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.
@@ -222594,8 +222594,1660 @@ Anthropic.Messages = Messages2;
222594
222594
  Anthropic.Models = Models2;
222595
222595
  Anthropic.Beta = Beta;
222596
222596
 
222597
+ // src/core/router/pricing-data.json
222598
+ var pricing_data_default = {
222599
+ entries: [
222600
+ {
222601
+ model: "claude-opus-5",
222602
+ provider: "anthropic",
222603
+ modality: "text",
222604
+ currency: "USD",
222605
+ asOf: "2026-07-27",
222606
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
222607
+ provenance: "vendor-pricing-page",
222608
+ tiers: [
222609
+ {
222610
+ inputPer1m: 5,
222611
+ outputPer1m: 25,
222612
+ cachedInputPer1m: 0.5,
222613
+ cacheWritePer1m: 6.25,
222614
+ reasoningOutputPer1m: 25
222615
+ }
222616
+ ],
222617
+ batchMultiplier: 0.5,
222618
+ contextWindow: 1e6
222619
+ },
222620
+ {
222621
+ model: "claude-opus-4-8",
222622
+ provider: "anthropic",
222623
+ modality: "text",
222624
+ currency: "USD",
222625
+ asOf: "2026-07-27",
222626
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
222627
+ provenance: "vendor-pricing-page",
222628
+ tiers: [
222629
+ {
222630
+ inputPer1m: 5,
222631
+ outputPer1m: 25,
222632
+ cachedInputPer1m: 0.5,
222633
+ cacheWritePer1m: 6.25,
222634
+ reasoningOutputPer1m: 25
222635
+ }
222636
+ ],
222637
+ batchMultiplier: 0.5,
222638
+ contextWindow: 1e6
222639
+ },
222640
+ {
222641
+ model: "claude-opus-4-7",
222642
+ provider: "anthropic",
222643
+ modality: "text",
222644
+ currency: "USD",
222645
+ asOf: "2026-07-27",
222646
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
222647
+ provenance: "vendor-pricing-page",
222648
+ tiers: [
222649
+ {
222650
+ inputPer1m: 5,
222651
+ outputPer1m: 25,
222652
+ cachedInputPer1m: 0.5,
222653
+ cacheWritePer1m: 6.25,
222654
+ reasoningOutputPer1m: 25
222655
+ }
222656
+ ],
222657
+ batchMultiplier: 0.5,
222658
+ contextWindow: 1e6
222659
+ },
222660
+ {
222661
+ model: "claude-opus-4-6",
222662
+ provider: "anthropic",
222663
+ modality: "text",
222664
+ currency: "USD",
222665
+ asOf: "2026-07-27",
222666
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
222667
+ provenance: "vendor-pricing-page",
222668
+ tiers: [
222669
+ {
222670
+ inputPer1m: 5,
222671
+ outputPer1m: 25,
222672
+ cachedInputPer1m: 0.5,
222673
+ cacheWritePer1m: 6.25,
222674
+ reasoningOutputPer1m: 25
222675
+ }
222676
+ ],
222677
+ batchMultiplier: 0.5,
222678
+ contextWindow: 1e6
222679
+ },
222680
+ {
222681
+ model: "claude-opus-4-5",
222682
+ provider: "anthropic",
222683
+ modality: "text",
222684
+ currency: "USD",
222685
+ asOf: "2026-07-27",
222686
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
222687
+ provenance: "vendor-pricing-page",
222688
+ tiers: [
222689
+ {
222690
+ inputPer1m: 5,
222691
+ outputPer1m: 25,
222692
+ cachedInputPer1m: 0.5,
222693
+ cacheWritePer1m: 6.25,
222694
+ reasoningOutputPer1m: 25
222695
+ }
222696
+ ],
222697
+ batchMultiplier: 0.5,
222698
+ contextWindow: 2e5
222699
+ },
222700
+ {
222701
+ model: "claude-opus-4-1",
222702
+ provider: "anthropic",
222703
+ modality: "text",
222704
+ currency: "USD",
222705
+ asOf: "2026-07-27",
222706
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
222707
+ provenance: "vendor-pricing-page",
222708
+ tiers: [
222709
+ {
222710
+ inputPer1m: 15,
222711
+ outputPer1m: 75,
222712
+ cachedInputPer1m: 1.5,
222713
+ cacheWritePer1m: 18.75,
222714
+ reasoningOutputPer1m: 75
222715
+ }
222716
+ ],
222717
+ batchMultiplier: 0.5,
222718
+ contextWindow: 2e5,
222719
+ notes: "Deprecated by Anthropic; priced for historical/cost-reporting accuracy."
222720
+ },
222721
+ {
222722
+ model: "claude-opus-4",
222723
+ provider: "anthropic",
222724
+ modality: "text",
222725
+ currency: "USD",
222726
+ asOf: "2026-07-27",
222727
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
222728
+ provenance: "vendor-pricing-page",
222729
+ tiers: [
222730
+ {
222731
+ inputPer1m: 15,
222732
+ outputPer1m: 75,
222733
+ cachedInputPer1m: 1.5,
222734
+ cacheWritePer1m: 18.75,
222735
+ reasoningOutputPer1m: 75
222736
+ }
222737
+ ],
222738
+ batchMultiplier: 0.5,
222739
+ contextWindow: 2e5,
222740
+ notes: "Retired except on Google Cloud; priced for historical/cost-reporting accuracy."
222741
+ },
222742
+ {
222743
+ model: "claude-sonnet-5",
222744
+ provider: "anthropic",
222745
+ modality: "text",
222746
+ currency: "USD",
222747
+ asOf: "2026-07-27",
222748
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
222749
+ provenance: "vendor-pricing-page",
222750
+ tiers: [
222751
+ {
222752
+ inputPer1m: 2,
222753
+ outputPer1m: 10,
222754
+ cachedInputPer1m: 0.2,
222755
+ cacheWritePer1m: 2.5,
222756
+ reasoningOutputPer1m: 10
222757
+ }
222758
+ ],
222759
+ batchMultiplier: 0.5,
222760
+ contextWindow: 1e6,
222761
+ 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."
222762
+ },
222763
+ {
222764
+ model: "claude-sonnet-4-6",
222765
+ provider: "anthropic",
222766
+ modality: "text",
222767
+ currency: "USD",
222768
+ asOf: "2026-07-27",
222769
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
222770
+ provenance: "vendor-pricing-page",
222771
+ tiers: [
222772
+ {
222773
+ inputPer1m: 3,
222774
+ outputPer1m: 15,
222775
+ cachedInputPer1m: 0.3,
222776
+ cacheWritePer1m: 3.75,
222777
+ reasoningOutputPer1m: 15
222778
+ }
222779
+ ],
222780
+ batchMultiplier: 0.5,
222781
+ contextWindow: 1e6
222782
+ },
222783
+ {
222784
+ model: "claude-sonnet-4-5",
222785
+ provider: "anthropic",
222786
+ modality: "text",
222787
+ currency: "USD",
222788
+ asOf: "2026-07-27",
222789
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
222790
+ provenance: "vendor-pricing-page",
222791
+ tiers: [
222792
+ {
222793
+ maxInputTokens: 2e5,
222794
+ inputPer1m: 3,
222795
+ outputPer1m: 15,
222796
+ cachedInputPer1m: 0.3,
222797
+ cacheWritePer1m: 3.75,
222798
+ reasoningOutputPer1m: 15
222799
+ },
222800
+ {
222801
+ inputPer1m: 6,
222802
+ outputPer1m: 22.5,
222803
+ cachedInputPer1m: 0.6,
222804
+ cacheWritePer1m: 7.5,
222805
+ reasoningOutputPer1m: 22.5
222806
+ }
222807
+ ],
222808
+ batchMultiplier: 0.5,
222809
+ contextWindow: 2e5,
222810
+ 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)."
222811
+ },
222812
+ {
222813
+ model: "claude-sonnet-4",
222814
+ provider: "anthropic",
222815
+ modality: "text",
222816
+ currency: "USD",
222817
+ asOf: "2026-07-27",
222818
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
222819
+ provenance: "vendor-pricing-page",
222820
+ tiers: [
222821
+ {
222822
+ inputPer1m: 3,
222823
+ outputPer1m: 15,
222824
+ cachedInputPer1m: 0.3,
222825
+ cacheWritePer1m: 3.75,
222826
+ reasoningOutputPer1m: 15
222827
+ }
222828
+ ],
222829
+ batchMultiplier: 0.5,
222830
+ contextWindow: 2e5
222831
+ },
222832
+ {
222833
+ model: "claude-haiku-4-5",
222834
+ provider: "anthropic",
222835
+ modality: "text",
222836
+ currency: "USD",
222837
+ asOf: "2026-07-27",
222838
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
222839
+ provenance: "vendor-pricing-page",
222840
+ tiers: [
222841
+ {
222842
+ inputPer1m: 1,
222843
+ outputPer1m: 5,
222844
+ cachedInputPer1m: 0.1,
222845
+ cacheWritePer1m: 1.25,
222846
+ reasoningOutputPer1m: 5
222847
+ }
222848
+ ],
222849
+ batchMultiplier: 0.5,
222850
+ contextWindow: 2e5
222851
+ },
222852
+ {
222853
+ model: "claude-haiku-3-5",
222854
+ provider: "anthropic",
222855
+ modality: "text",
222856
+ currency: "USD",
222857
+ asOf: "2026-07-27",
222858
+ source: "https://platform.claude.com/docs/en/about-claude/pricing",
222859
+ provenance: "vendor-pricing-page",
222860
+ tiers: [
222861
+ {
222862
+ inputPer1m: 0.8,
222863
+ outputPer1m: 4,
222864
+ cachedInputPer1m: 0.08,
222865
+ cacheWritePer1m: 1,
222866
+ reasoningOutputPer1m: 4
222867
+ }
222868
+ ],
222869
+ batchMultiplier: 0.5,
222870
+ contextWindow: 2e5
222871
+ },
222872
+ {
222873
+ model: "gpt-5.6-sol",
222874
+ provider: "openai",
222875
+ aliases: [
222876
+ "gpt-5.6"
222877
+ ],
222878
+ modality: "text",
222879
+ currency: "USD",
222880
+ asOf: "2026-07-27",
222881
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
222882
+ provenance: "litellm-catalog",
222883
+ tiers: [
222884
+ {
222885
+ maxInputTokens: 272e3,
222886
+ inputPer1m: 5,
222887
+ outputPer1m: 30,
222888
+ cachedInputPer1m: 0.5,
222889
+ cacheWritePer1m: 6.25
222890
+ },
222891
+ {
222892
+ inputPer1m: 10,
222893
+ outputPer1m: 45,
222894
+ cachedInputPer1m: 1,
222895
+ cacheWritePer1m: 12.5
222896
+ }
222897
+ ],
222898
+ batchMultiplier: 0.5,
222899
+ contextWindow: 105e4
222900
+ },
222901
+ {
222902
+ model: "gpt-5.6-terra",
222903
+ provider: "openai",
222904
+ modality: "text",
222905
+ currency: "USD",
222906
+ asOf: "2026-07-27",
222907
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
222908
+ provenance: "litellm-catalog",
222909
+ tiers: [
222910
+ {
222911
+ maxInputTokens: 272e3,
222912
+ inputPer1m: 2.5,
222913
+ outputPer1m: 15,
222914
+ cachedInputPer1m: 0.25,
222915
+ cacheWritePer1m: 3.125
222916
+ },
222917
+ {
222918
+ inputPer1m: 5,
222919
+ outputPer1m: 22.5,
222920
+ cachedInputPer1m: 0.5,
222921
+ cacheWritePer1m: 6.25
222922
+ }
222923
+ ],
222924
+ batchMultiplier: 0.5,
222925
+ contextWindow: 105e4
222926
+ },
222927
+ {
222928
+ model: "gpt-5.6-luna",
222929
+ provider: "openai",
222930
+ modality: "text",
222931
+ currency: "USD",
222932
+ asOf: "2026-07-27",
222933
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
222934
+ provenance: "litellm-catalog",
222935
+ tiers: [
222936
+ {
222937
+ maxInputTokens: 272e3,
222938
+ inputPer1m: 1,
222939
+ outputPer1m: 6,
222940
+ cachedInputPer1m: 0.1,
222941
+ cacheWritePer1m: 1.25
222942
+ },
222943
+ {
222944
+ inputPer1m: 2,
222945
+ outputPer1m: 9,
222946
+ cachedInputPer1m: 0.2,
222947
+ cacheWritePer1m: 2.5
222948
+ }
222949
+ ],
222950
+ batchMultiplier: 0.5,
222951
+ contextWindow: 105e4
222952
+ },
222953
+ {
222954
+ model: "gpt-5.5",
222955
+ provider: "openai",
222956
+ modality: "text",
222957
+ currency: "USD",
222958
+ asOf: "2026-07-27",
222959
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
222960
+ provenance: "litellm-catalog",
222961
+ tiers: [
222962
+ {
222963
+ maxInputTokens: 272e3,
222964
+ inputPer1m: 5,
222965
+ outputPer1m: 30,
222966
+ cachedInputPer1m: 0.5
222967
+ },
222968
+ {
222969
+ inputPer1m: 10,
222970
+ outputPer1m: 45,
222971
+ cachedInputPer1m: 1
222972
+ }
222973
+ ],
222974
+ batchMultiplier: 0.5,
222975
+ contextWindow: 105e4
222976
+ },
222977
+ {
222978
+ model: "gpt-5.4",
222979
+ provider: "openai",
222980
+ modality: "text",
222981
+ currency: "USD",
222982
+ asOf: "2026-07-27",
222983
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
222984
+ provenance: "litellm-catalog",
222985
+ tiers: [
222986
+ {
222987
+ maxInputTokens: 272e3,
222988
+ inputPer1m: 2.5,
222989
+ outputPer1m: 15,
222990
+ cachedInputPer1m: 0.25
222991
+ },
222992
+ {
222993
+ inputPer1m: 5,
222994
+ outputPer1m: 22.5,
222995
+ cachedInputPer1m: 0.5
222996
+ }
222997
+ ],
222998
+ batchMultiplier: 0.5,
222999
+ contextWindow: 105e4
223000
+ },
223001
+ {
223002
+ model: "gpt-5.4-mini",
223003
+ provider: "openai",
223004
+ modality: "text",
223005
+ currency: "USD",
223006
+ asOf: "2026-07-27",
223007
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
223008
+ provenance: "litellm-catalog",
223009
+ tiers: [
223010
+ {
223011
+ inputPer1m: 0.75,
223012
+ outputPer1m: 4.5,
223013
+ cachedInputPer1m: 0.075
223014
+ }
223015
+ ],
223016
+ batchMultiplier: 0.5,
223017
+ contextWindow: 105e4
223018
+ },
223019
+ {
223020
+ model: "gpt-5",
223021
+ provider: "openai",
223022
+ modality: "text",
223023
+ currency: "USD",
223024
+ asOf: "2026-07-27",
223025
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
223026
+ provenance: "litellm-catalog",
223027
+ tiers: [
223028
+ {
223029
+ inputPer1m: 1.25,
223030
+ outputPer1m: 10,
223031
+ cachedInputPer1m: 0.125
223032
+ }
223033
+ ],
223034
+ contextWindow: 272e3
223035
+ },
223036
+ {
223037
+ model: "gpt-5-mini",
223038
+ provider: "openai",
223039
+ modality: "text",
223040
+ currency: "USD",
223041
+ asOf: "2026-07-27",
223042
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
223043
+ provenance: "litellm-catalog",
223044
+ tiers: [
223045
+ {
223046
+ inputPer1m: 0.25,
223047
+ outputPer1m: 2,
223048
+ cachedInputPer1m: 0.025
223049
+ }
223050
+ ],
223051
+ contextWindow: 272e3
223052
+ },
223053
+ {
223054
+ model: "gpt-5-nano",
223055
+ provider: "openai",
223056
+ modality: "text",
223057
+ currency: "USD",
223058
+ asOf: "2026-07-27",
223059
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
223060
+ provenance: "litellm-catalog",
223061
+ tiers: [
223062
+ {
223063
+ inputPer1m: 0.05,
223064
+ outputPer1m: 0.4,
223065
+ cachedInputPer1m: 5e-3
223066
+ }
223067
+ ],
223068
+ contextWindow: 272e3
223069
+ },
223070
+ {
223071
+ model: "gpt-4.1",
223072
+ provider: "openai",
223073
+ modality: "text",
223074
+ currency: "USD",
223075
+ asOf: "2026-07-27",
223076
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
223077
+ provenance: "litellm-catalog",
223078
+ tiers: [
223079
+ {
223080
+ inputPer1m: 2,
223081
+ outputPer1m: 8,
223082
+ cachedInputPer1m: 0.5
223083
+ }
223084
+ ],
223085
+ batchMultiplier: 0.5,
223086
+ contextWindow: 1047576
223087
+ },
223088
+ {
223089
+ model: "gpt-4.1-mini",
223090
+ provider: "openai",
223091
+ modality: "text",
223092
+ currency: "USD",
223093
+ asOf: "2026-07-27",
223094
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
223095
+ provenance: "litellm-catalog",
223096
+ tiers: [
223097
+ {
223098
+ inputPer1m: 0.4,
223099
+ outputPer1m: 1.6,
223100
+ cachedInputPer1m: 0.1
223101
+ }
223102
+ ],
223103
+ batchMultiplier: 0.5,
223104
+ contextWindow: 1047576
223105
+ },
223106
+ {
223107
+ model: "gpt-4.1-nano",
223108
+ provider: "openai",
223109
+ modality: "text",
223110
+ currency: "USD",
223111
+ asOf: "2026-07-27",
223112
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
223113
+ provenance: "litellm-catalog",
223114
+ tiers: [
223115
+ {
223116
+ inputPer1m: 0.1,
223117
+ outputPer1m: 0.4,
223118
+ cachedInputPer1m: 0.025
223119
+ }
223120
+ ],
223121
+ batchMultiplier: 0.5,
223122
+ contextWindow: 1047576
223123
+ },
223124
+ {
223125
+ model: "gpt-4o",
223126
+ provider: "openai",
223127
+ modality: "text",
223128
+ currency: "USD",
223129
+ asOf: "2026-07-27",
223130
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
223131
+ provenance: "litellm-catalog",
223132
+ tiers: [
223133
+ {
223134
+ inputPer1m: 2.5,
223135
+ outputPer1m: 10,
223136
+ cachedInputPer1m: 1.25
223137
+ }
223138
+ ],
223139
+ batchMultiplier: 0.5,
223140
+ contextWindow: 128e3
223141
+ },
223142
+ {
223143
+ model: "gpt-4o-mini",
223144
+ provider: "openai",
223145
+ modality: "text",
223146
+ currency: "USD",
223147
+ asOf: "2026-07-27",
223148
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
223149
+ provenance: "litellm-catalog",
223150
+ tiers: [
223151
+ {
223152
+ inputPer1m: 0.15,
223153
+ outputPer1m: 0.6,
223154
+ cachedInputPer1m: 0.075
223155
+ }
223156
+ ],
223157
+ batchMultiplier: 0.5,
223158
+ contextWindow: 128e3
223159
+ },
223160
+ {
223161
+ model: "gpt-5.5",
223162
+ provider: "azure",
223163
+ region: "global",
223164
+ modality: "text",
223165
+ currency: "USD",
223166
+ asOf: "2026-07-27",
223167
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
223168
+ provenance: "litellm-catalog",
223169
+ tiers: [
223170
+ {
223171
+ maxInputTokens: 272e3,
223172
+ inputPer1m: 5,
223173
+ outputPer1m: 30,
223174
+ cachedInputPer1m: 0.5
223175
+ },
223176
+ {
223177
+ inputPer1m: 10,
223178
+ outputPer1m: 45,
223179
+ cachedInputPer1m: 1
223180
+ }
223181
+ ],
223182
+ contextWindow: 105e4
223183
+ },
223184
+ {
223185
+ model: "gpt-5.5",
223186
+ provider: "azure",
223187
+ region: "us",
223188
+ modality: "text",
223189
+ currency: "USD",
223190
+ asOf: "2026-07-27",
223191
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
223192
+ provenance: "litellm-catalog",
223193
+ tiers: [
223194
+ {
223195
+ maxInputTokens: 272e3,
223196
+ inputPer1m: 5.5,
223197
+ outputPer1m: 33,
223198
+ cachedInputPer1m: 0.55
223199
+ },
223200
+ {
223201
+ inputPer1m: 11,
223202
+ outputPer1m: 49.5,
223203
+ cachedInputPer1m: 1.1
223204
+ }
223205
+ ],
223206
+ contextWindow: 105e4
223207
+ },
223208
+ {
223209
+ model: "gpt-5.5",
223210
+ provider: "azure",
223211
+ region: "eu",
223212
+ modality: "text",
223213
+ currency: "USD",
223214
+ asOf: "2026-07-27",
223215
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
223216
+ provenance: "litellm-catalog",
223217
+ tiers: [
223218
+ {
223219
+ maxInputTokens: 272e3,
223220
+ inputPer1m: 5.5,
223221
+ outputPer1m: 33,
223222
+ cachedInputPer1m: 0.55
223223
+ },
223224
+ {
223225
+ inputPer1m: 11,
223226
+ outputPer1m: 49.5,
223227
+ cachedInputPer1m: 1.1
223228
+ }
223229
+ ],
223230
+ contextWindow: 105e4
223231
+ },
223232
+ {
223233
+ model: "gpt-5.4",
223234
+ provider: "azure",
223235
+ region: "global",
223236
+ modality: "text",
223237
+ currency: "USD",
223238
+ asOf: "2026-07-27",
223239
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
223240
+ provenance: "litellm-catalog",
223241
+ tiers: [
223242
+ {
223243
+ maxInputTokens: 272e3,
223244
+ inputPer1m: 2.5,
223245
+ outputPer1m: 15,
223246
+ cachedInputPer1m: 0.25
223247
+ },
223248
+ {
223249
+ inputPer1m: 5,
223250
+ outputPer1m: 22.5,
223251
+ cachedInputPer1m: 0.5
223252
+ }
223253
+ ],
223254
+ contextWindow: 105e4
223255
+ },
223256
+ {
223257
+ model: "gpt-5.4",
223258
+ provider: "azure",
223259
+ region: "us",
223260
+ modality: "text",
223261
+ currency: "USD",
223262
+ asOf: "2026-07-27",
223263
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
223264
+ provenance: "litellm-catalog",
223265
+ tiers: [
223266
+ {
223267
+ inputPer1m: 2.75,
223268
+ outputPer1m: 16.5,
223269
+ cachedInputPer1m: 0.28
223270
+ }
223271
+ ],
223272
+ contextWindow: 105e4
223273
+ },
223274
+ {
223275
+ model: "gpt-5.4",
223276
+ provider: "azure",
223277
+ region: "eu",
223278
+ modality: "text",
223279
+ currency: "USD",
223280
+ asOf: "2026-07-27",
223281
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
223282
+ provenance: "litellm-catalog",
223283
+ tiers: [
223284
+ {
223285
+ inputPer1m: 2.75,
223286
+ outputPer1m: 16.5,
223287
+ cachedInputPer1m: 0.28
223288
+ }
223289
+ ],
223290
+ contextWindow: 105e4
223291
+ },
223292
+ {
223293
+ model: "gpt-5.6-terra",
223294
+ provider: "azure",
223295
+ region: "global",
223296
+ modality: "text",
223297
+ currency: "USD",
223298
+ asOf: "2026-07-27",
223299
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
223300
+ provenance: "litellm-catalog",
223301
+ tiers: [
223302
+ {
223303
+ maxInputTokens: 272e3,
223304
+ inputPer1m: 2.5,
223305
+ outputPer1m: 15,
223306
+ cachedInputPer1m: 0.25
223307
+ },
223308
+ {
223309
+ inputPer1m: 5,
223310
+ outputPer1m: 22.5,
223311
+ cachedInputPer1m: 0.5
223312
+ }
223313
+ ],
223314
+ contextWindow: 105e4
223315
+ },
223316
+ {
223317
+ model: "gpt-5.6-terra",
223318
+ provider: "azure",
223319
+ region: "eu",
223320
+ modality: "text",
223321
+ currency: "USD",
223322
+ asOf: "2026-07-27",
223323
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
223324
+ provenance: "litellm-catalog",
223325
+ tiers: [
223326
+ {
223327
+ maxInputTokens: 272e3,
223328
+ inputPer1m: 2.75,
223329
+ outputPer1m: 16.5,
223330
+ cachedInputPer1m: 0.275
223331
+ },
223332
+ {
223333
+ inputPer1m: 5.5,
223334
+ outputPer1m: 24.75,
223335
+ cachedInputPer1m: 0.55
223336
+ }
223337
+ ],
223338
+ contextWindow: 105e4
223339
+ },
223340
+ {
223341
+ model: "gpt-5",
223342
+ provider: "azure",
223343
+ region: "global",
223344
+ modality: "text",
223345
+ currency: "USD",
223346
+ asOf: "2026-07-27",
223347
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
223348
+ provenance: "litellm-catalog",
223349
+ tiers: [
223350
+ {
223351
+ inputPer1m: 1.25,
223352
+ outputPer1m: 10,
223353
+ cachedInputPer1m: 0.125
223354
+ }
223355
+ ],
223356
+ contextWindow: 272e3
223357
+ },
223358
+ {
223359
+ model: "gpt-5-mini",
223360
+ provider: "azure",
223361
+ region: "global",
223362
+ modality: "text",
223363
+ currency: "USD",
223364
+ asOf: "2026-07-27",
223365
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
223366
+ provenance: "litellm-catalog",
223367
+ tiers: [
223368
+ {
223369
+ inputPer1m: 0.25,
223370
+ outputPer1m: 2,
223371
+ cachedInputPer1m: 0.025
223372
+ }
223373
+ ],
223374
+ contextWindow: 272e3
223375
+ },
223376
+ {
223377
+ model: "gpt-5-nano",
223378
+ provider: "azure",
223379
+ region: "global",
223380
+ modality: "text",
223381
+ currency: "USD",
223382
+ asOf: "2026-07-27",
223383
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
223384
+ provenance: "litellm-catalog",
223385
+ tiers: [
223386
+ {
223387
+ inputPer1m: 0.05,
223388
+ outputPer1m: 0.4,
223389
+ cachedInputPer1m: 5e-3
223390
+ }
223391
+ ],
223392
+ contextWindow: 272e3
223393
+ },
223394
+ {
223395
+ model: "gpt-4.1",
223396
+ provider: "azure",
223397
+ region: "global",
223398
+ modality: "text",
223399
+ currency: "USD",
223400
+ asOf: "2026-07-27",
223401
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
223402
+ provenance: "litellm-catalog",
223403
+ tiers: [
223404
+ {
223405
+ inputPer1m: 2,
223406
+ outputPer1m: 8,
223407
+ cachedInputPer1m: 0.5
223408
+ }
223409
+ ],
223410
+ batchMultiplier: 0.5,
223411
+ contextWindow: 1047576
223412
+ },
223413
+ {
223414
+ model: "gpt-4o",
223415
+ provider: "azure",
223416
+ region: "global",
223417
+ modality: "text",
223418
+ currency: "USD",
223419
+ asOf: "2026-07-27",
223420
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
223421
+ provenance: "litellm-catalog",
223422
+ tiers: [
223423
+ {
223424
+ inputPer1m: 2.5,
223425
+ outputPer1m: 10,
223426
+ cachedInputPer1m: 1.25
223427
+ }
223428
+ ],
223429
+ contextWindow: 128e3
223430
+ },
223431
+ {
223432
+ model: "gpt-4o-mini",
223433
+ provider: "azure",
223434
+ region: "global",
223435
+ modality: "text",
223436
+ currency: "USD",
223437
+ asOf: "2026-07-27",
223438
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
223439
+ provenance: "litellm-catalog",
223440
+ tiers: [
223441
+ {
223442
+ inputPer1m: 0.165,
223443
+ outputPer1m: 0.66,
223444
+ cachedInputPer1m: 0.075
223445
+ }
223446
+ ],
223447
+ contextWindow: 128e3,
223448
+ 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."
223449
+ },
223450
+ {
223451
+ model: "gemini-3.1-pro",
223452
+ provider: "gemini",
223453
+ aliases: [
223454
+ "gemini-3.1-pro-preview"
223455
+ ],
223456
+ modality: "text",
223457
+ currency: "USD",
223458
+ asOf: "2026-07-27",
223459
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
223460
+ provenance: "vendor-pricing-page",
223461
+ tiers: [
223462
+ {
223463
+ maxInputTokens: 2e5,
223464
+ inputPer1m: 2,
223465
+ outputPer1m: 12,
223466
+ cachedInputPer1m: 0.2,
223467
+ reasoningOutputPer1m: 12
223468
+ },
223469
+ {
223470
+ inputPer1m: 4,
223471
+ outputPer1m: 18,
223472
+ cachedInputPer1m: 0.4,
223473
+ reasoningOutputPer1m: 18
223474
+ }
223475
+ ],
223476
+ batchMultiplier: 0.5,
223477
+ contextWindow: 1048576,
223478
+ notes: "Long-context tier: $2/$12 per 1M up to 200K prompt tokens, $4/$18 above it."
223479
+ },
223480
+ {
223481
+ model: "gemini-3-pro",
223482
+ provider: "gemini",
223483
+ aliases: [
223484
+ "gemini-3-pro-preview"
223485
+ ],
223486
+ modality: "text",
223487
+ currency: "USD",
223488
+ asOf: "2026-07-27",
223489
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
223490
+ provenance: "vendor-pricing-page",
223491
+ tiers: [
223492
+ {
223493
+ maxInputTokens: 2e5,
223494
+ inputPer1m: 2,
223495
+ outputPer1m: 12,
223496
+ cachedInputPer1m: 0.2,
223497
+ reasoningOutputPer1m: 12
223498
+ },
223499
+ {
223500
+ inputPer1m: 4,
223501
+ outputPer1m: 18,
223502
+ cachedInputPer1m: 0.4,
223503
+ reasoningOutputPer1m: 18
223504
+ }
223505
+ ],
223506
+ batchMultiplier: 0.5,
223507
+ contextWindow: 1048576
223508
+ },
223509
+ {
223510
+ model: "gemini-3.6-flash",
223511
+ provider: "gemini",
223512
+ modality: "text",
223513
+ currency: "USD",
223514
+ asOf: "2026-07-27",
223515
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
223516
+ provenance: "vendor-pricing-page",
223517
+ tiers: [
223518
+ {
223519
+ inputPer1m: 1.5,
223520
+ outputPer1m: 7.5,
223521
+ cachedInputPer1m: 0.15,
223522
+ reasoningOutputPer1m: 7.5
223523
+ }
223524
+ ],
223525
+ batchMultiplier: 0.5,
223526
+ contextWindow: 1048576,
223527
+ notes: "Released 2026-07-21. Output pricing dropped ~17% from Gemini 3.5 Flash ($9.00 -> $7.50 per 1M); input unchanged."
223528
+ },
223529
+ {
223530
+ model: "gemini-3.5-flash",
223531
+ provider: "gemini",
223532
+ modality: "text",
223533
+ currency: "USD",
223534
+ asOf: "2026-07-27",
223535
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
223536
+ provenance: "vendor-pricing-page",
223537
+ tiers: [
223538
+ {
223539
+ inputPer1m: 1.5,
223540
+ outputPer1m: 9,
223541
+ cachedInputPer1m: 0.15,
223542
+ reasoningOutputPer1m: 9
223543
+ }
223544
+ ],
223545
+ batchMultiplier: 0.5,
223546
+ contextWindow: 1048576
223547
+ },
223548
+ {
223549
+ model: "gemini-3.5-flash-lite",
223550
+ provider: "gemini",
223551
+ modality: "text",
223552
+ currency: "USD",
223553
+ asOf: "2026-07-27",
223554
+ source: "https://ai.google.dev/gemini-api/docs/pricing",
223555
+ provenance: "litellm-catalog",
223556
+ tiers: [
223557
+ {
223558
+ inputPer1m: 0.3,
223559
+ outputPer1m: 2.5,
223560
+ cachedInputPer1m: 0.03,
223561
+ reasoningOutputPer1m: 2.5
223562
+ }
223563
+ ],
223564
+ batchMultiplier: 0.5,
223565
+ contextWindow: 1048576
223566
+ },
223567
+ {
223568
+ model: "gemini-3.1-flash-lite",
223569
+ provider: "gemini",
223570
+ modality: "text",
223571
+ currency: "USD",
223572
+ asOf: "2026-07-27",
223573
+ source: "https://ai.google.dev/gemini-api/docs/pricing#gemini-3.1-flash-lite",
223574
+ provenance: "litellm-catalog",
223575
+ tiers: [
223576
+ {
223577
+ inputPer1m: 0.25,
223578
+ outputPer1m: 1.5,
223579
+ cachedInputPer1m: 0.025,
223580
+ reasoningOutputPer1m: 1.5
223581
+ }
223582
+ ],
223583
+ batchMultiplier: 0.5,
223584
+ contextWindow: 1048576
223585
+ },
223586
+ {
223587
+ model: "gemini-3-flash",
223588
+ provider: "gemini",
223589
+ aliases: [
223590
+ "gemini-3-flash-preview"
223591
+ ],
223592
+ modality: "text",
223593
+ currency: "USD",
223594
+ asOf: "2026-07-27",
223595
+ source: "https://ai.google.dev/pricing/gemini-3",
223596
+ provenance: "litellm-catalog",
223597
+ tiers: [
223598
+ {
223599
+ inputPer1m: 0.5,
223600
+ outputPer1m: 3,
223601
+ cachedInputPer1m: 0.05,
223602
+ reasoningOutputPer1m: 3
223603
+ }
223604
+ ],
223605
+ contextWindow: 1048576
223606
+ },
223607
+ {
223608
+ model: "gemini-2.5-pro",
223609
+ provider: "gemini",
223610
+ modality: "text",
223611
+ currency: "USD",
223612
+ asOf: "2026-07-27",
223613
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
223614
+ provenance: "litellm-catalog",
223615
+ tiers: [
223616
+ {
223617
+ maxInputTokens: 2e5,
223618
+ inputPer1m: 1.25,
223619
+ outputPer1m: 10,
223620
+ cachedInputPer1m: 0.125
223621
+ },
223622
+ {
223623
+ inputPer1m: 2.5,
223624
+ outputPer1m: 15,
223625
+ cachedInputPer1m: 0.25
223626
+ }
223627
+ ],
223628
+ contextWindow: 1048576
223629
+ },
223630
+ {
223631
+ model: "gemini-2.5-flash",
223632
+ provider: "gemini",
223633
+ modality: "text",
223634
+ currency: "USD",
223635
+ asOf: "2026-07-27",
223636
+ source: "https://ai.google.dev/gemini-api/docs/models#gemini-2.5-flash-preview",
223637
+ provenance: "litellm-catalog",
223638
+ tiers: [
223639
+ {
223640
+ inputPer1m: 0.3,
223641
+ outputPer1m: 2.5,
223642
+ cachedInputPer1m: 0.03,
223643
+ reasoningOutputPer1m: 2.5
223644
+ }
223645
+ ],
223646
+ contextWindow: 1048576
223647
+ },
223648
+ {
223649
+ model: "gemini-2.5-flash-lite",
223650
+ provider: "gemini",
223651
+ modality: "text",
223652
+ currency: "USD",
223653
+ asOf: "2026-07-27",
223654
+ source: "https://ai.google.dev/gemini-api/docs/models#gemini-2.5-flash-lite",
223655
+ provenance: "litellm-catalog",
223656
+ tiers: [
223657
+ {
223658
+ inputPer1m: 0.1,
223659
+ outputPer1m: 0.4,
223660
+ cachedInputPer1m: 0.01,
223661
+ reasoningOutputPer1m: 0.4
223662
+ }
223663
+ ],
223664
+ contextWindow: 1048576
223665
+ },
223666
+ {
223667
+ model: "gemini-2.0-flash",
223668
+ provider: "gemini",
223669
+ modality: "text",
223670
+ currency: "USD",
223671
+ asOf: "2026-07-27",
223672
+ source: "https://ai.google.dev/pricing#2_0flash",
223673
+ provenance: "litellm-catalog",
223674
+ tiers: [
223675
+ {
223676
+ inputPer1m: 0.1,
223677
+ outputPer1m: 0.4,
223678
+ cachedInputPer1m: 0.025
223679
+ }
223680
+ ],
223681
+ contextWindow: 1048576,
223682
+ notes: "Gemini Developer API price. Vertex AI lists $0.15/$0.60 per 1M for the same model \u2014 see the vertex entry."
223683
+ },
223684
+ {
223685
+ model: "gemini-2.0-flash-lite",
223686
+ provider: "gemini",
223687
+ modality: "text",
223688
+ currency: "USD",
223689
+ asOf: "2026-07-27",
223690
+ source: "https://ai.google.dev/gemini-api/docs/pricing#gemini-2.0-flash-lite",
223691
+ provenance: "litellm-catalog",
223692
+ tiers: [
223693
+ {
223694
+ inputPer1m: 0.075,
223695
+ outputPer1m: 0.3,
223696
+ cachedInputPer1m: 0.01875
223697
+ }
223698
+ ],
223699
+ contextWindow: 1048576
223700
+ },
223701
+ {
223702
+ model: "gemini-2.0-flash",
223703
+ provider: "vertex",
223704
+ modality: "text",
223705
+ currency: "USD",
223706
+ asOf: "2026-07-27",
223707
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
223708
+ provenance: "vendor-pricing-page",
223709
+ tiers: [
223710
+ {
223711
+ inputPer1m: 0.15,
223712
+ outputPer1m: 0.6
223713
+ }
223714
+ ],
223715
+ batchMultiplier: 0.5,
223716
+ notes: "Vertex AI lists $0.15/$0.60 per 1M; the Gemini Developer API lists $0.10/$0.40 for the same model."
223717
+ },
223718
+ {
223719
+ model: "gemini-3.1-pro",
223720
+ provider: "vertex",
223721
+ aliases: [
223722
+ "gemini-3.1-pro-preview"
223723
+ ],
223724
+ modality: "text",
223725
+ currency: "USD",
223726
+ asOf: "2026-07-27",
223727
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
223728
+ provenance: "vendor-pricing-page",
223729
+ tiers: [
223730
+ {
223731
+ maxInputTokens: 2e5,
223732
+ inputPer1m: 2,
223733
+ outputPer1m: 12,
223734
+ cachedInputPer1m: 0.2,
223735
+ reasoningOutputPer1m: 12
223736
+ },
223737
+ {
223738
+ inputPer1m: 4,
223739
+ outputPer1m: 18,
223740
+ cachedInputPer1m: 0.4,
223741
+ reasoningOutputPer1m: 18
223742
+ }
223743
+ ],
223744
+ batchMultiplier: 0.5,
223745
+ contextWindow: 1048576
223746
+ },
223747
+ {
223748
+ model: "gemini-3.6-flash",
223749
+ provider: "vertex",
223750
+ modality: "text",
223751
+ currency: "USD",
223752
+ asOf: "2026-07-27",
223753
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
223754
+ provenance: "vendor-pricing-page",
223755
+ tiers: [
223756
+ {
223757
+ inputPer1m: 1.5,
223758
+ outputPer1m: 7.5,
223759
+ cachedInputPer1m: 0.15,
223760
+ reasoningOutputPer1m: 7.5
223761
+ }
223762
+ ],
223763
+ batchMultiplier: 0.5,
223764
+ contextWindow: 1048576
223765
+ },
223766
+ {
223767
+ model: "gemini-2.5-pro",
223768
+ provider: "vertex",
223769
+ modality: "text",
223770
+ currency: "USD",
223771
+ asOf: "2026-07-27",
223772
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
223773
+ provenance: "vendor-pricing-page",
223774
+ tiers: [
223775
+ {
223776
+ maxInputTokens: 2e5,
223777
+ inputPer1m: 1.25,
223778
+ outputPer1m: 10,
223779
+ cachedInputPer1m: 0.13
223780
+ },
223781
+ {
223782
+ inputPer1m: 2.5,
223783
+ outputPer1m: 15,
223784
+ cachedInputPer1m: 0.25
223785
+ }
223786
+ ],
223787
+ batchMultiplier: 0.5,
223788
+ contextWindow: 1048576
223789
+ },
223790
+ {
223791
+ model: "gemini-2.5-flash",
223792
+ provider: "vertex",
223793
+ modality: "text",
223794
+ currency: "USD",
223795
+ asOf: "2026-07-27",
223796
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
223797
+ provenance: "vendor-pricing-page",
223798
+ tiers: [
223799
+ {
223800
+ inputPer1m: 0.3,
223801
+ outputPer1m: 2.5,
223802
+ cachedInputPer1m: 0.03,
223803
+ reasoningOutputPer1m: 2.5
223804
+ }
223805
+ ],
223806
+ batchMultiplier: 0.5,
223807
+ contextWindow: 1048576
223808
+ },
223809
+ {
223810
+ model: "claude-sonnet-4-6",
223811
+ provider: "openrouter",
223812
+ modality: "text",
223813
+ currency: "USD",
223814
+ asOf: "2026-07-27",
223815
+ source: "https://openrouter.ai/anthropic/claude-sonnet-4.6",
223816
+ provenance: "litellm-catalog",
223817
+ tiers: [
223818
+ {
223819
+ maxInputTokens: 2e5,
223820
+ inputPer1m: 3,
223821
+ outputPer1m: 15,
223822
+ cachedInputPer1m: 0.3,
223823
+ cacheWritePer1m: 3.75
223824
+ },
223825
+ {
223826
+ inputPer1m: 6,
223827
+ outputPer1m: 22.5,
223828
+ cachedInputPer1m: 0.6,
223829
+ cacheWritePer1m: 7.5
223830
+ }
223831
+ ],
223832
+ contextWindow: 1e6
223833
+ },
223834
+ {
223835
+ model: "claude-haiku-4-5",
223836
+ provider: "openrouter",
223837
+ modality: "text",
223838
+ currency: "USD",
223839
+ asOf: "2026-07-27",
223840
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
223841
+ provenance: "litellm-catalog",
223842
+ tiers: [
223843
+ {
223844
+ inputPer1m: 1,
223845
+ outputPer1m: 5,
223846
+ cachedInputPer1m: 0.1,
223847
+ cacheWritePer1m: 1.25
223848
+ }
223849
+ ],
223850
+ contextWindow: 2e5
223851
+ },
223852
+ {
223853
+ model: "gpt-5",
223854
+ provider: "openrouter",
223855
+ modality: "text",
223856
+ currency: "USD",
223857
+ asOf: "2026-07-27",
223858
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
223859
+ provenance: "litellm-catalog",
223860
+ tiers: [
223861
+ {
223862
+ inputPer1m: 1.25,
223863
+ outputPer1m: 10,
223864
+ cachedInputPer1m: 0.125
223865
+ }
223866
+ ],
223867
+ contextWindow: 272e3
223868
+ },
223869
+ {
223870
+ model: "gpt-5-mini",
223871
+ provider: "openrouter",
223872
+ modality: "text",
223873
+ currency: "USD",
223874
+ asOf: "2026-07-27",
223875
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
223876
+ provenance: "litellm-catalog",
223877
+ tiers: [
223878
+ {
223879
+ inputPer1m: 0.25,
223880
+ outputPer1m: 2,
223881
+ cachedInputPer1m: 0.025
223882
+ }
223883
+ ],
223884
+ contextWindow: 272e3
223885
+ },
223886
+ {
223887
+ model: "gemini-3.1-pro",
223888
+ provider: "openrouter",
223889
+ aliases: [
223890
+ "gemini-3.1-pro-preview"
223891
+ ],
223892
+ modality: "text",
223893
+ currency: "USD",
223894
+ asOf: "2026-07-27",
223895
+ source: "https://openrouter.ai/google/gemini-3.1-pro-preview",
223896
+ provenance: "litellm-catalog",
223897
+ tiers: [
223898
+ {
223899
+ maxInputTokens: 2e5,
223900
+ inputPer1m: 2,
223901
+ outputPer1m: 12,
223902
+ cachedInputPer1m: 0.2
223903
+ },
223904
+ {
223905
+ inputPer1m: 4,
223906
+ outputPer1m: 18,
223907
+ cachedInputPer1m: 0.4,
223908
+ cacheWritePer1m: 0.25
223909
+ }
223910
+ ],
223911
+ contextWindow: 1048576
223912
+ },
223913
+ {
223914
+ model: "text-embedding-3-small",
223915
+ provider: "openai",
223916
+ modality: "embedding",
223917
+ currency: "USD",
223918
+ asOf: "2026-07-27",
223919
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
223920
+ provenance: "litellm-catalog",
223921
+ tiers: [
223922
+ {
223923
+ inputPer1m: 0.02,
223924
+ outputPer1m: 0
223925
+ }
223926
+ ],
223927
+ batchMultiplier: 0.5,
223928
+ contextWindow: 8191
223929
+ },
223930
+ {
223931
+ model: "text-embedding-3-large",
223932
+ provider: "openai",
223933
+ modality: "embedding",
223934
+ currency: "USD",
223935
+ asOf: "2026-07-27",
223936
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
223937
+ provenance: "litellm-catalog",
223938
+ tiers: [
223939
+ {
223940
+ inputPer1m: 0.13,
223941
+ outputPer1m: 0
223942
+ }
223943
+ ],
223944
+ batchMultiplier: 0.5,
223945
+ contextWindow: 8191
223946
+ },
223947
+ {
223948
+ model: "gemini-embedding-001",
223949
+ provider: "gemini",
223950
+ modality: "embedding",
223951
+ currency: "USD",
223952
+ asOf: "2026-07-27",
223953
+ source: "https://ai.google.dev/gemini-api/docs/embeddings#model-versions",
223954
+ provenance: "litellm-catalog",
223955
+ tiers: [
223956
+ {
223957
+ inputPer1m: 0.15,
223958
+ outputPer1m: 0
223959
+ }
223960
+ ],
223961
+ contextWindow: 2048
223962
+ },
223963
+ {
223964
+ model: "dall-e-3",
223965
+ provider: "openai",
223966
+ modality: "image",
223967
+ currency: "USD",
223968
+ asOf: "2026-07-27",
223969
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
223970
+ provenance: "litellm-catalog",
223971
+ rates: [
223972
+ {
223973
+ unit: "per_image",
223974
+ amount: 0.04,
223975
+ variant: "1024x1024 standard"
223976
+ }
223977
+ ]
223978
+ },
223979
+ {
223980
+ model: "gemini-3-pro-image",
223981
+ provider: "gemini",
223982
+ modality: "image",
223983
+ currency: "USD",
223984
+ asOf: "2026-07-27",
223985
+ source: "https://ai.google.dev/gemini-api/docs/pricing",
223986
+ provenance: "litellm-catalog",
223987
+ rates: [
223988
+ {
223989
+ unit: "per_image",
223990
+ amount: 0.134,
223991
+ variant: "default output resolution"
223992
+ }
223993
+ ],
223994
+ 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."
223995
+ },
223996
+ {
223997
+ model: "imagen-4.0-generate-001",
223998
+ provider: "vertex",
223999
+ modality: "image",
224000
+ currency: "USD",
224001
+ asOf: "2026-07-27",
224002
+ source: "https://cloud.google.com/vertex-ai/generative-ai/pricing",
224003
+ provenance: "litellm-catalog",
224004
+ rates: [
224005
+ {
224006
+ unit: "per_image",
224007
+ amount: 0.04
224008
+ }
224009
+ ]
224010
+ },
224011
+ {
224012
+ model: "veo-3.1-generate-001",
224013
+ provider: "gemini",
224014
+ modality: "video",
224015
+ currency: "USD",
224016
+ asOf: "2026-07-27",
224017
+ source: "https://ai.google.dev/gemini-api/docs/video",
224018
+ provenance: "litellm-catalog",
224019
+ rates: [
224020
+ {
224021
+ unit: "per_second",
224022
+ amount: 0.4
224023
+ }
224024
+ ]
224025
+ },
224026
+ {
224027
+ model: "veo-3.1-generate-001",
224028
+ provider: "vertex",
224029
+ modality: "video",
224030
+ currency: "USD",
224031
+ asOf: "2026-07-27",
224032
+ source: "https://cloud.google.com/vertex-ai/generative-ai/docs/model-reference/veo",
224033
+ provenance: "litellm-catalog",
224034
+ rates: [
224035
+ {
224036
+ unit: "per_second",
224037
+ amount: 0.4
224038
+ }
224039
+ ]
224040
+ },
224041
+ {
224042
+ model: "tts-1",
224043
+ provider: "openai",
224044
+ modality: "speech",
224045
+ currency: "USD",
224046
+ asOf: "2026-07-27",
224047
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
224048
+ provenance: "litellm-catalog",
224049
+ rates: [
224050
+ {
224051
+ unit: "per_character",
224052
+ amount: 15e-6
224053
+ }
224054
+ ],
224055
+ notes: "$15 per 1M characters."
224056
+ },
224057
+ {
224058
+ model: "tts-1-hd",
224059
+ provider: "openai",
224060
+ modality: "speech",
224061
+ currency: "USD",
224062
+ asOf: "2026-07-27",
224063
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
224064
+ provenance: "litellm-catalog",
224065
+ rates: [
224066
+ {
224067
+ unit: "per_character",
224068
+ amount: 3e-5
224069
+ }
224070
+ ],
224071
+ notes: "$30 per 1M characters."
224072
+ },
224073
+ {
224074
+ model: "whisper-1",
224075
+ provider: "openai",
224076
+ modality: "transcription",
224077
+ currency: "USD",
224078
+ asOf: "2026-07-27",
224079
+ source: "https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json",
224080
+ provenance: "litellm-catalog",
224081
+ rates: [
224082
+ {
224083
+ unit: "per_audio_minute",
224084
+ amount: 6e-3
224085
+ }
224086
+ ],
224087
+ notes: "litellm records $0.0001 per audio second; $0.006/minute is that rate x 60."
224088
+ }
224089
+ ]
224090
+ };
224091
+
224092
+ // src/core/router/pricing.ts
224093
+ var DATASET = pricing_data_default;
224094
+ function normalizeForPricing(id) {
224095
+ let s3 = id.trim().toLowerCase();
224096
+ s3 = s3.replace(/^models\//, "");
224097
+ const slash = s3.lastIndexOf("/");
224098
+ if (slash !== -1) s3 = s3.slice(slash + 1);
224099
+ const tag = s3.search(/[:@]/);
224100
+ if (tag !== -1) s3 = s3.slice(0, tag);
224101
+ s3 = s3.replace(/-latest$/, "");
224102
+ s3 = s3.replace(/-preview(?:-\d{2}-\d{2})?$/, "");
224103
+ s3 = s3.replace(/-\d{4}-\d{2}-\d{2}$/, "");
224104
+ s3 = s3.replace(/-\d{8}$/, "");
224105
+ s3 = s3.replace(/-preview$/, "");
224106
+ return s3;
224107
+ }
224108
+ function indexKey(model, provider, region) {
224109
+ return `${provider}|${normalizeForPricing(model)}|${region ?? ""}`;
224110
+ }
224111
+ var INDEX = /* @__PURE__ */ new Map();
224112
+ for (const entry of DATASET.entries) {
224113
+ for (const name of [entry.model, ...entry.aliases ?? []]) {
224114
+ const withRegion = indexKey(name, entry.provider, entry.region);
224115
+ if (!INDEX.has(withRegion)) INDEX.set(withRegion, entry);
224116
+ const bare = indexKey(name, entry.provider);
224117
+ const existing = INDEX.get(bare);
224118
+ if (!existing || existing.region && existing.region !== "global" && entry.region === "global") {
224119
+ INDEX.set(bare, entry);
224120
+ }
224121
+ }
224122
+ }
224123
+ function findPricing(modelId, provider, opts = {}) {
224124
+ const ids = [modelId, opts.baseModelId].filter((x5) => !!x5);
224125
+ const providers = [provider, ...opts.fallbackProviders ?? []];
224126
+ for (const p3 of providers) {
224127
+ for (const id of ids) {
224128
+ const hit = (opts.region ? INDEX.get(indexKey(id, p3, opts.region)) : void 0) ?? INDEX.get(indexKey(id, p3));
224129
+ if (hit) return { entry: hit, matchedProvider: p3, viaFallback: p3 !== provider };
224130
+ }
224131
+ }
224132
+ return null;
224133
+ }
224134
+ function tierFor(entry, inputTokens = 0) {
224135
+ const tiers = entry.tiers;
224136
+ if (!tiers?.length) return null;
224137
+ for (const t4 of tiers) {
224138
+ if (t4.maxInputTokens === void 0 || inputTokens <= t4.maxInputTokens) return t4;
224139
+ }
224140
+ return tiers[tiers.length - 1] ?? null;
224141
+ }
224142
+ var PER_1M_TO_PER_1K = 1 / 1e3;
224143
+ function tokenRatesPer1k(entry, opts = {}) {
224144
+ const tier = tierFor(entry, opts.inputTokens ?? 0);
224145
+ if (!tier) return null;
224146
+ const mult = (opts.batch ? entry.batchMultiplier ?? 1 : 1) * PER_1M_TO_PER_1K;
224147
+ const out = {
224148
+ input: tier.inputPer1m * mult,
224149
+ output: tier.outputPer1m * mult
224150
+ };
224151
+ if (tier.cachedInputPer1m !== void 0) out.cachedInput = tier.cachedInputPer1m * mult;
224152
+ if (tier.cacheWritePer1m !== void 0) out.cacheWrite = tier.cacheWritePer1m * mult;
224153
+ if (tier.reasoningOutputPer1m !== void 0) out.reasoningOutput = tier.reasoningOutputPer1m * mult;
224154
+ return out;
224155
+ }
224156
+ var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "0.0.0.0", "::1", "[::1]"]);
224157
+ function isLoopbackOrPrivateHost(url2) {
224158
+ if (!url2) return false;
224159
+ try {
224160
+ const host = new URL(url2).hostname.toLowerCase().replace(/^\[|\]$/g, "");
224161
+ if (LOOPBACK_HOSTS.has(host) || LOOPBACK_HOSTS.has(`[${host}]`)) return true;
224162
+ if (host.endsWith(".local")) return true;
224163
+ if (/^127\./.test(host)) return true;
224164
+ if (/^10\./.test(host)) return true;
224165
+ if (/^192\.168\./.test(host)) return true;
224166
+ if (/^172\.(1[6-9]|2\d|3[01])\./.test(host)) return true;
224167
+ return false;
224168
+ } catch {
224169
+ return false;
224170
+ }
224171
+ }
224172
+ function isLocalEndpoint(cfg) {
224173
+ if (typeof cfg.local === "boolean") return cfg.local;
224174
+ if (cfg.type === "ollama") return true;
224175
+ if (cfg.type === "openai-compatible") return isLoopbackOrPrivateHost(cfg.baseUrl);
224176
+ return false;
224177
+ }
224178
+ var UNKNOWN = { input: 0, output: 0, unknown: true, free: false };
224179
+ var FREE = { input: 0, output: 0, unknown: false, free: true };
224180
+ function resolvePricing(model, opts = {}) {
224181
+ if (model.isLocal) return FREE;
224182
+ const fallbackProviders = model.provider === "azure" ? ["openai"] : model.provider === "gemini" ? ["vertex"] : [];
224183
+ const match = findPricing(model.id, model.provider, {
224184
+ region: opts.region,
224185
+ baseModelId: model.baseModelId,
224186
+ fallbackProviders
224187
+ });
224188
+ if (!match) return UNKNOWN;
224189
+ const rates = tokenRatesPer1k(match.entry, { inputTokens: opts.inputTokens, batch: opts.batch });
224190
+ if (!rates) return UNKNOWN;
224191
+ return {
224192
+ input: rates.input,
224193
+ output: rates.output,
224194
+ unknown: false,
224195
+ free: false,
224196
+ entry: match.entry,
224197
+ ...match.viaFallback ? { estimatedFromProvider: match.matchedProvider } : {}
224198
+ };
224199
+ }
224200
+ function withResolvedPricing(model, opts = {}) {
224201
+ const p3 = resolvePricing(model, opts);
224202
+ return {
224203
+ ...model,
224204
+ inputCostPer1kTokens: p3.input,
224205
+ outputCostPer1kTokens: p3.output,
224206
+ ...p3.unknown ? { pricingUnknown: true } : { pricingUnknown: false }
224207
+ };
224208
+ }
224209
+ function isPricingUnknown(model) {
224210
+ return model.pricingUnknown === true && !model.isLocal;
224211
+ }
224212
+ var BLENDED_COST_CEILING = 0.05;
224213
+ function blendedCostPer1k(model) {
224214
+ if (isPricingUnknown(model)) return BLENDED_COST_CEILING;
224215
+ return model.inputCostPer1kTokens + model.outputCostPer1kTokens * 2;
224216
+ }
224217
+ var DISAGREEMENT_THRESHOLD = 0.02;
224218
+ function reconcilePrice(model, live) {
224219
+ const baseline = resolvePricing(model);
224220
+ const liveIsZero = !(live.input > 0) && !(live.output > 0);
224221
+ if (liveIsZero && !model.isLocal) {
224222
+ return { input: baseline.input, output: baseline.output, accepted: false };
224223
+ }
224224
+ if (baseline.unknown || !baseline.entry) {
224225
+ return { input: live.input, output: live.output, accepted: true };
224226
+ }
224227
+ const dsBlend = baseline.input + baseline.output * 2;
224228
+ const liveBlend = live.input + live.output * 2;
224229
+ const ratio = dsBlend > 0 ? liveBlend / dsBlend : Number.POSITIVE_INFINITY;
224230
+ const material = dsBlend > 0 && Math.abs(ratio - 1) > DISAGREEMENT_THRESHOLD;
224231
+ return {
224232
+ input: live.input,
224233
+ output: live.output,
224234
+ accepted: true,
224235
+ ...material ? {
224236
+ disagreement: {
224237
+ modelId: model.id,
224238
+ provider: model.provider,
224239
+ dataset: { input: baseline.input, output: baseline.output },
224240
+ live: { input: live.input, output: live.output },
224241
+ ratio: Math.round(ratio * 1e3) / 1e3,
224242
+ datasetAsOf: baseline.entry.asOf,
224243
+ datasetSource: baseline.entry.source
224244
+ }
224245
+ } : {}
224246
+ };
224247
+ }
224248
+
222597
224249
  // src/constants.ts
222598
- var CASCADE_VERSION = "0.48.1";
224250
+ var CASCADE_VERSION = "0.50.0";
222599
224251
  var CASCADE_CONFIG_DIR = ".cascade";
222600
224252
  var CASCADE_MD_FILE = "CASCADE.md";
222601
224253
  var CASCADE_IGNORE_FILE = ".cascadeignore";
@@ -222944,6 +224596,13 @@ var MODELS = {
222944
224596
  for (const _m of Object.values(MODELS)) {
222945
224597
  if (_m.supportsToolUse === void 0) _m.supportsToolUse = !_m.isLocal;
222946
224598
  }
224599
+ for (const _m of Object.values(MODELS)) {
224600
+ const priced = resolvePricing(_m);
224601
+ if (priced.unknown || priced.free || priced.estimatedFromProvider) continue;
224602
+ _m.inputCostPer1kTokens = priced.input;
224603
+ _m.outputCostPer1kTokens = priced.output;
224604
+ _m.pricingUnknown = false;
224605
+ }
222947
224606
  var T1_MODEL_PRIORITY = [
222948
224607
  "gpt-5.5",
222949
224608
  "gpt-5.4",
@@ -223034,21 +224693,49 @@ var PROVIDER_DISPLAY_NAMES = {
223034
224693
 
223035
224694
  // src/utils/cost.ts
223036
224695
  function resolveModelPricing(model) {
223037
- let input = model.inputCostPer1kTokens;
223038
- let output = model.outputCostPer1kTokens;
223039
- if (input === 0 && output === 0 && model.id && !model.isLocal) {
224696
+ if (model.isLocal) return { input: 0, output: 0, unknown: false };
224697
+ if (model.inputCostPer1kTokens > 0 || model.outputCostPer1kTokens > 0) {
224698
+ return {
224699
+ input: model.inputCostPer1kTokens,
224700
+ output: model.outputCostPer1kTokens,
224701
+ unknown: false
224702
+ };
224703
+ }
224704
+ const fromDataset = resolvePricing(model);
224705
+ if (!fromDataset.unknown) {
224706
+ return {
224707
+ input: fromDataset.input,
224708
+ output: fromDataset.output,
224709
+ unknown: false,
224710
+ ...fromDataset.estimatedFromProvider ? { estimatedFromProvider: fromDataset.estimatedFromProvider } : {}
224711
+ };
224712
+ }
224713
+ if (model.id) {
223040
224714
  const known = Object.values(MODELS).find((m3) => m3.id === model.id && !m3.isLocal);
223041
- if (known) {
223042
- input = known.inputCostPer1kTokens;
223043
- output = known.outputCostPer1kTokens;
224715
+ if (known && (known.inputCostPer1kTokens > 0 || known.outputCostPer1kTokens > 0)) {
224716
+ return {
224717
+ input: known.inputCostPer1kTokens,
224718
+ output: known.outputCostPer1kTokens,
224719
+ unknown: false
224720
+ };
223044
224721
  }
223045
224722
  }
223046
- return { input, output };
224723
+ return { input: 0, output: 0, unknown: true };
223047
224724
  }
223048
224725
  function calculateCost(inputTokens, outputTokens, model) {
223049
224726
  const { input, output } = resolveModelPricing(model);
223050
224727
  return inputTokens / 1e3 * input + outputTokens / 1e3 * output;
223051
224728
  }
224729
+ function buildTokenUsage(inputTokens, outputTokens, model) {
224730
+ const { input, output, unknown: unknown2 } = resolveModelPricing(model);
224731
+ return {
224732
+ inputTokens,
224733
+ outputTokens,
224734
+ totalTokens: inputTokens + outputTokens,
224735
+ estimatedCostUsd: inputTokens / 1e3 * input + outputTokens / 1e3 * output,
224736
+ ...unknown2 ? { costUnknown: true } : {}
224737
+ };
224738
+ }
223052
224739
 
223053
224740
  // src/providers/base.ts
223054
224741
  var BaseProvider = class {
@@ -223068,12 +224755,7 @@ var BaseProvider = class {
223068
224755
  return calculateCost(inputTokens, outputTokens, this.model);
223069
224756
  }
223070
224757
  makeUsage(inputTokens, outputTokens) {
223071
- return {
223072
- inputTokens,
223073
- outputTokens,
223074
- totalTokens: inputTokens + outputTokens,
223075
- estimatedCostUsd: this.estimateCost(inputTokens, outputTokens)
223076
- };
224758
+ return buildTokenUsage(inputTokens, outputTokens, this.model);
223077
224759
  }
223078
224760
  };
223079
224761
 
@@ -223242,7 +224924,7 @@ var AnthropicProvider = class extends BaseProvider {
223242
224924
  return data.data.filter((m3) => isChatModel(m3.id)).map((m3) => {
223243
224925
  const known = Object.values(MODELS).find((km) => km.id === m3.id && km.provider === "anthropic");
223244
224926
  if (known) return known;
223245
- return {
224927
+ return withResolvedPricing({
223246
224928
  id: m3.id,
223247
224929
  name: m3.display_name || m3.id,
223248
224930
  provider: "anthropic",
@@ -223253,7 +224935,7 @@ var AnthropicProvider = class extends BaseProvider {
223253
224935
  maxOutputTokens: 8e3,
223254
224936
  supportsStreaming: true,
223255
224937
  isLocal: false
223256
- };
224938
+ });
223257
224939
  });
223258
224940
  } catch {
223259
224941
  return Object.values(MODELS).filter((m3) => m3.provider === "anthropic");
@@ -231330,7 +233012,7 @@ var OpenAIProvider = class extends BaseProvider {
231330
233012
  return response.data.filter((m3) => isChatModel(m3.id)).map((m3) => {
231331
233013
  const known = Object.values(MODELS).find((km) => km.id === m3.id && km.provider === "openai");
231332
233014
  if (known) return known;
231333
- return {
233015
+ return withResolvedPricing({
231334
233016
  id: m3.id,
231335
233017
  name: m3.id,
231336
233018
  provider: "openai",
@@ -231341,7 +233023,7 @@ var OpenAIProvider = class extends BaseProvider {
231341
233023
  maxOutputTokens: 4e3,
231342
233024
  supportsStreaming: true,
231343
233025
  isLocal: false
231344
- };
233026
+ });
231345
233027
  });
231346
233028
  } catch {
231347
233029
  return Object.values(MODELS).filter((m3) => m3.provider === "openai");
@@ -231437,6 +233119,10 @@ function azureModelForDeployment(cfg) {
231437
233119
  const baseModelId = cfg.model?.trim() || inferAzureBaseModel(id) || void 0;
231438
233120
  const base = baseModelId ? MODELS[baseModelId] : void 0;
231439
233121
  if (base) {
233122
+ const azurePrice = resolvePricing(
233123
+ { id, provider: "azure", isLocal: false, baseModelId },
233124
+ { region: cfg.region }
233125
+ );
231440
233126
  return {
231441
233127
  ...base,
231442
233128
  id,
@@ -231445,7 +233131,12 @@ function azureModelForDeployment(cfg) {
231445
233131
  provider: "azure",
231446
233132
  baseModelId,
231447
233133
  // real identity for benchmark + live pricing
231448
- supportsToolUse: base.supportsToolUse ?? true
233134
+ supportsToolUse: base.supportsToolUse ?? true,
233135
+ ...azurePrice.unknown ? {} : {
233136
+ inputCostPer1kTokens: azurePrice.input,
233137
+ outputCostPer1kTokens: azurePrice.output,
233138
+ pricingUnknown: false
233139
+ }
231449
233140
  };
231450
233141
  }
231451
233142
  return {
@@ -249638,7 +251329,7 @@ var GeminiProvider = class extends BaseProvider {
249638
251329
  (km) => km.id === id && km.provider === "gemini"
249639
251330
  );
249640
251331
  if (known) return known;
249641
- return {
251332
+ return withResolvedPricing({
249642
251333
  id,
249643
251334
  name: m3.displayName || id,
249644
251335
  provider: "gemini",
@@ -249649,7 +251340,7 @@ var GeminiProvider = class extends BaseProvider {
249649
251340
  maxOutputTokens: m3.outputTokenLimit || 8e3,
249650
251341
  supportsStreaming: true,
249651
251342
  isLocal: false
249652
- };
251343
+ });
249653
251344
  });
249654
251345
  } catch {
249655
251346
  return Object.values(MODELS).filter((m3) => m3.provider === "gemini");
@@ -249996,9 +251687,10 @@ var OllamaProvider = class extends BaseProvider {
249996
251687
  return supportedKeywords.some((k4) => name.includes(k4)) && isChatModel(name);
249997
251688
  });
249998
251689
  const shows = await Promise.all(entries.map((m3) => this.showModel(m3.name)));
251690
+ const local = isLocalEndpoint({ ...this.config, type: "ollama" });
249999
251691
  return entries.map((m3, i4) => {
250000
251692
  const show = shows[i4];
250001
- return {
251693
+ return withResolvedPricing({
250002
251694
  id: m3.name,
250003
251695
  name: m3.name,
250004
251696
  provider: "ollama",
@@ -250008,10 +251700,10 @@ var OllamaProvider = class extends BaseProvider {
250008
251700
  outputCostPer1kTokens: 0,
250009
251701
  maxOutputTokens: 4e3,
250010
251702
  supportsStreaming: true,
250011
- isLocal: true,
251703
+ isLocal: local,
250012
251704
  supportsToolUse: show?.tools ?? isToolCapable(m3.name),
250013
251705
  minSizeB: this.parseSizeB(m3.details?.parameter_size)
250014
- };
251706
+ });
250015
251707
  });
250016
251708
  } catch {
250017
251709
  return [];
@@ -250116,7 +251808,8 @@ var OpenAICompatibleProvider = class extends OpenAIProvider {
250116
251808
  }).filter((x5) => typeof x5 === "string" && x5.length > 0);
250117
251809
  if (ids.length === 0) return [this.model];
250118
251810
  const chatIds = ids.filter((id) => isChatModel(id));
250119
- return (chatIds.length ? chatIds : ids).map((id) => ({
251811
+ const local = isLocalEndpoint(this.config);
251812
+ return (chatIds.length ? chatIds : ids).map((id) => withResolvedPricing({
250120
251813
  id,
250121
251814
  name: id,
250122
251815
  provider: "openai-compatible",
@@ -250126,7 +251819,7 @@ var OpenAICompatibleProvider = class extends OpenAIProvider {
250126
251819
  outputCostPer1kTokens: 0,
250127
251820
  maxOutputTokens: 4e3,
250128
251821
  supportsStreaming: true,
250129
- isLocal: false
251822
+ isLocal: local
250130
251823
  }));
250131
251824
  }
250132
251825
  async isAvailable() {
@@ -250341,7 +252034,7 @@ var ModelSelector = class {
250341
252034
  else if (this.availableProviders.size === 1) providerStr = Array.from(this.availableProviders)[0];
250342
252035
  }
250343
252036
  if (providerStr && this.availableProviders.has(providerStr)) {
250344
- const dynamicModel = {
252037
+ const dynamicModel = withResolvedPricing({
250345
252038
  id: actualId,
250346
252039
  name: actualId,
250347
252040
  provider: providerStr,
@@ -250352,7 +252045,7 @@ var ModelSelector = class {
250352
252045
  maxOutputTokens: 8e3,
250353
252046
  supportsStreaming: true,
250354
252047
  isLocal: providerStr === "ollama"
250355
- };
252048
+ });
250356
252049
  this.addDynamicModel(dynamicModel);
250357
252050
  return dynamicModel;
250358
252051
  }
@@ -250744,6 +252437,8 @@ var LiveDataProvider = class {
250744
252437
  snapshot = null;
250745
252438
  prices = /* @__PURE__ */ new Map();
250746
252439
  capabilities = /* @__PURE__ */ new Map();
252440
+ /** Dataset-vs-live price mismatches, deduped by `provider:modelId`. */
252441
+ disagreements = /* @__PURE__ */ new Map();
250747
252442
  source = "bundled";
250748
252443
  fetchedAt = 0;
250749
252444
  loaded = false;
@@ -250897,14 +252592,45 @@ var LiveDataProvider = class {
250897
252592
  /**
250898
252593
  * Returns a price-corrected copy of each model when live pricing is known,
250899
252594
  * leaving the original untouched (so the shared catalog is never mutated).
252595
+ *
252596
+ * Reconciliation policy (see reconcilePrice in pricing.ts): the bundled
252597
+ * dataset is the authoritative baseline, and a live quote overrides it
252598
+ * because it is fresher by construction — but the disagreement is RECORDED,
252599
+ * not swallowed. A dataset/live mismatch is the best signal available that
252600
+ * the committed prices have gone stale, so it must be visible rather than
252601
+ * silently resolved in either direction. A live quote of $0 for a non-local
252602
+ * model is rejected outright: that is the very failure mode this change
252603
+ * exists to prevent, and a marketplace's free-tier alias must never zero out
252604
+ * the price of the paid model Cascade is actually calling.
250900
252605
  */
250901
252606
  applyLivePricing(models) {
250902
252607
  return models.map((m3) => {
250903
252608
  const p3 = this.getLivePrice(m3.baseModelId ?? m3.id);
250904
252609
  if (!p3) return m3;
250905
- return { ...m3, inputCostPer1kTokens: p3.input, outputCostPer1kTokens: p3.output };
252610
+ const reconciled = reconcilePrice(m3, p3);
252611
+ if (reconciled.disagreement) this.recordDisagreement(reconciled.disagreement);
252612
+ if (!reconciled.accepted) return m3;
252613
+ return {
252614
+ ...m3,
252615
+ inputCostPer1kTokens: reconciled.input,
252616
+ outputCostPer1kTokens: reconciled.output,
252617
+ pricingUnknown: false
252618
+ };
250906
252619
  });
250907
252620
  }
252621
+ recordDisagreement(d2) {
252622
+ const key = `${d2.provider}:${d2.modelId}`;
252623
+ if (this.disagreements.has(key)) return;
252624
+ this.disagreements.set(key, d2);
252625
+ }
252626
+ /**
252627
+ * Dataset-vs-live price mismatches seen this session, newest-model-first
252628
+ * insertion order. Surfaced by `cascade models --verbose`; a non-empty list
252629
+ * means src/core/router/pricing-data.json is probably due a refresh.
252630
+ */
252631
+ getPriceDisagreements() {
252632
+ return [...this.disagreements.values()];
252633
+ }
250908
252634
  /** Current capability facts for a model id, or null when unknown. */
250909
252635
  getCapability(modelId) {
250910
252636
  return this.capabilities.get(normalizeModelId2(modelId)) ?? null;
@@ -251101,7 +252827,9 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter__default.default {
251101
252827
  tokensByTier: {},
251102
252828
  inputTokensByTier: {},
251103
252829
  outputTokensByTier: {},
251104
- costByFeature: {}
252830
+ costByFeature: {},
252831
+ untrackedCostCalls: 0,
252832
+ untrackedCostModels: []
251105
252833
  };
251106
252834
  tierModels = /* @__PURE__ */ new Map();
251107
252835
  /**
@@ -251451,7 +253179,7 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter__default.default {
251451
253179
  `Model ${model.id} inference timed out after ${cloudTimeoutMs}ms`
251452
253180
  );
251453
253181
  }
251454
- const correctedCost = calculateCost(
253182
+ const corrected = buildTokenUsage(
251455
253183
  result.usage.inputTokens,
251456
253184
  result.usage.outputTokens,
251457
253185
  model
@@ -251460,7 +253188,8 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter__default.default {
251460
253188
  ...result,
251461
253189
  usage: {
251462
253190
  ...result.usage,
251463
- estimatedCostUsd: correctedCost
253191
+ estimatedCostUsd: corrected.estimatedCostUsd,
253192
+ ...corrected.costUnknown ? { costUnknown: true } : { costUnknown: void 0 }
251464
253193
  }
251465
253194
  };
251466
253195
  if (!result || typeof result.content !== "string" || !result.usage) {
@@ -251647,7 +253376,9 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter__default.default {
251647
253376
  tokensByTier: { ...this.stats.tokensByTier },
251648
253377
  inputTokensByTier: { ...this.stats.inputTokensByTier },
251649
253378
  outputTokensByTier: { ...this.stats.outputTokensByTier },
251650
- costByFeature: { ...this.stats.costByFeature }
253379
+ costByFeature: { ...this.stats.costByFeature },
253380
+ untrackedCostCalls: this.stats.untrackedCostCalls,
253381
+ untrackedCostModels: [...this.stats.untrackedCostModels]
251651
253382
  };
251652
253383
  }
251653
253384
  /**
@@ -251698,7 +253429,9 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter__default.default {
251698
253429
  tokensByTier: {},
251699
253430
  inputTokensByTier: {},
251700
253431
  outputTokensByTier: {},
251701
- costByFeature: {}
253432
+ costByFeature: {},
253433
+ untrackedCostCalls: 0,
253434
+ untrackedCostModels: []
251702
253435
  };
251703
253436
  this.sessionCostUsd = 0;
251704
253437
  this.budgetState = "ok";
@@ -251883,6 +253616,18 @@ var CascadeRouter = class _CascadeRouter extends EventEmitter__default.default {
251883
253616
  if (featureTag) {
251884
253617
  this.stats.costByFeature[featureTag] = (this.stats.costByFeature[featureTag] ?? 0) + usage.estimatedCostUsd;
251885
253618
  }
253619
+ if (usage.costUnknown) {
253620
+ this.stats.untrackedCostCalls += 1;
253621
+ if (!this.stats.untrackedCostModels.includes(model.id)) {
253622
+ this.stats.untrackedCostModels.push(model.id);
253623
+ const capped = this.config?.budget?.maxCostPerRunUsd != null || this.config?.budget?.sessionBudgetUsd != null;
253624
+ this.emit("cost:untracked", {
253625
+ modelId: model.id,
253626
+ provider: model.provider,
253627
+ 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.`
253628
+ });
253629
+ }
253630
+ }
251886
253631
  this.runTokens += usage.totalTokens;
251887
253632
  this.runCostUsd += usage.estimatedCostUsd;
251888
253633
  this.updateBudgetState();
@@ -252023,6 +253768,14 @@ var BaseTier = class extends EventEmitter__default.default {
252023
253768
  this.emit("tier:status", event);
252024
253769
  }
252025
253770
  /** Record the model serving this tier; future status events carry it. */
253771
+ /**
253772
+ * The model actually serving this tier ("provider:id"), once one has been
253773
+ * chosen. The run breaker reads it to attribute a failure to a model rather
253774
+ * than to the subtask that happened to hit it.
253775
+ */
253776
+ getServingModel() {
253777
+ return this.servingModel;
253778
+ }
252026
253779
  setServingModel(model) {
252027
253780
  this.servingModel = model || void 0;
252028
253781
  }
@@ -253758,6 +255511,7 @@ var T2Manager = class extends BaseTier {
253758
255511
  escalations = [];
253759
255512
  peerSyncBuffer = [];
253760
255513
  store;
255514
+ runBreaker;
253761
255515
  t3PeerBus = new PeerBus();
253762
255516
  // ← T3↔T3 bus (local to this T2)
253763
255517
  t2PeerBus;
@@ -253788,6 +255542,15 @@ var T2Manager = class extends BaseTier {
253788
255542
  this.router = router;
253789
255543
  this.toolRegistry = toolRegistry;
253790
255544
  }
255545
+ /**
255546
+ * Share the run-wide circuit breaker. Every T2 in a run gets the SAME
255547
+ * instance: three sections each failing once against a dead model is the
255548
+ * same fact as one section failing three times, and a per-section breaker
255549
+ * would never see it.
255550
+ */
255551
+ setRunBreaker(breaker) {
255552
+ this.runBreaker = breaker;
255553
+ }
253791
255554
  setStore(store) {
253792
255555
  this.store = store;
253793
255556
  }
@@ -253911,7 +255674,8 @@ Guidance (must be followed): ${decision.note}`
253911
255674
  const overallStatus = this.determineStatus(t3Results);
253912
255675
  const isOk = overallStatus === "COMPLETED" || overallStatus === "PARTIAL";
253913
255676
  this.setStatus(isOk ? "COMPLETED" : "FAILED", summary);
253914
- this.sendStatusUpdate({ progressPct: 100, currentAction: "Section complete", status: "IN_PROGRESS", output: summary });
255677
+ const sectionAction = overallStatus === "COMPLETED" ? "Section complete" : overallStatus === "PARTIAL" ? "Section partially complete \u2014 some subtasks failed" : overallStatus === "ESCALATED" ? "Section escalated \u2014 needs a decision" : "Section failed \u2014 no subtask completed";
255678
+ this.sendStatusUpdate({ progressPct: 100, currentAction: sectionAction, status: "IN_PROGRESS", output: summary });
253915
255679
  const result = {
253916
255680
  sectionId: assignment.sectionId,
253917
255681
  sectionTitle: assignment.sectionTitle,
@@ -254081,6 +255845,24 @@ HIERARCHY CONTEXT: ${this.hierarchyContext}` : ""),
254081
255845
  const reinforceCfg = this.router.getReinforcementsConfig?.() ?? { enabled: false, maxPerSection: 4 };
254082
255846
  let reinforcementsAdded = 0;
254083
255847
  while (remaining.size > 0) {
255848
+ if (this.runBreaker?.isOpen()) {
255849
+ const why = this.runBreaker.skipMessage();
255850
+ this.log(`Run breaker open \u2014 skipping ${remaining.size} remaining subtask(s)`);
255851
+ for (const id of remaining) {
255852
+ this.t3PeerBus.publish(this.id, id, why, "FAILED");
255853
+ resultMap.set(id, {
255854
+ subtaskId: id,
255855
+ status: "FAILED",
255856
+ output: why,
255857
+ testResults: { checksRun: [], passed: [], failed: [] },
255858
+ issues: [why],
255859
+ peerSyncsUsed: [],
255860
+ correctionAttempts: 0
255861
+ });
255862
+ }
255863
+ remaining.clear();
255864
+ break;
255865
+ }
254084
255866
  const runnableIds = [...remaining].filter((id) => (inDegree.get(id) ?? 0) === 0);
254085
255867
  if (runnableIds.length === 0) {
254086
255868
  const fallbackId = [...remaining].sort(
@@ -254183,8 +255965,32 @@ HIERARCHY CONTEXT: ${this.hierarchyContext}` : ""),
254183
255965
  remaining.delete(id);
254184
255966
  const r4 = waveResults[i4];
254185
255967
  if (r4.status === "rejected") {
254186
- this.log(`T3 worker ${id} failed: ${r4.reason instanceof Error ? r4.reason.message : String(r4.reason)} \u2014 retrying once`);
254187
255968
  const assignment = sanitizedAssignments.find((a2) => a2.subtaskId === id);
255969
+ const failedModel = workerMap.get(id)?.getServingModel();
255970
+ const tripped = this.runBreaker?.record(r4.reason, failedModel);
255971
+ if (tripped) {
255972
+ this.log(`Run breaker opened: ${tripped.failures} consecutive ${tripped.kind} failures on ${tripped.modelId} \u2014 stopping`);
255973
+ this.emit("run:breaker", tripped);
255974
+ }
255975
+ if (this.runBreaker?.isOpen()) {
255976
+ const why = this.runBreaker.skipMessage();
255977
+ this.log(`T3 worker ${id} failed and the run breaker is open \u2014 not retrying`);
255978
+ this.t3PeerBus.publish(this.id, id, why, "FAILED");
255979
+ resultMap.set(id, {
255980
+ subtaskId: id,
255981
+ status: "FAILED",
255982
+ output: why,
255983
+ testResults: { checksRun: [], passed: [], failed: [] },
255984
+ issues: [why],
255985
+ peerSyncsUsed: [],
255986
+ correctionAttempts: 0
255987
+ });
255988
+ for (const dependent of adj.get(id) ?? []) {
255989
+ inDegree.set(dependent, Math.max(0, (inDegree.get(dependent) ?? 0) - 1));
255990
+ }
255991
+ continue;
255992
+ }
255993
+ this.log(`T3 worker ${id} failed: ${r4.reason instanceof Error ? r4.reason.message : String(r4.reason)} \u2014 retrying once`);
254188
255994
  try {
254189
255995
  const retried = await this.retryT3(assignment, taskId);
254190
255996
  resultMap.set(id, retried);
@@ -254516,6 +256322,7 @@ var T1Administrator = class extends BaseTier {
254516
256322
  t2Managers = /* @__PURE__ */ new Map();
254517
256323
  escalations = [];
254518
256324
  store;
256325
+ runBreaker;
254519
256326
  t2PeerBus = new PeerBus();
254520
256327
  permissionEscalator;
254521
256328
  toolCreator;
@@ -254530,6 +256337,10 @@ var T1Administrator = class extends BaseTier {
254530
256337
  this.toolRegistry = toolRegistry;
254531
256338
  this.config = config2;
254532
256339
  }
256340
+ /** Share the run-wide circuit breaker with every section manager. */
256341
+ setRunBreaker(breaker) {
256342
+ this.runBreaker = breaker;
256343
+ }
254533
256344
  setStore(store) {
254534
256345
  this.store = store;
254535
256346
  }
@@ -254892,6 +256703,7 @@ SPEC RULES \u2014 each subtask is a self-contained spec slice (workers execute f
254892
256703
  };
254893
256704
  const managers = sections.map((section) => {
254894
256705
  const manager = new T2Manager(this.router, this.toolRegistry, this.id);
256706
+ if (this.runBreaker) manager.setRunBreaker(this.runBreaker);
254895
256707
  manager.setHierarchyContext(`You are a T2 Manager for the section "${section.sectionTitle}". You are part of a COMPLEX task overseen by T1 Administrator.`);
254896
256708
  if (this.store) {
254897
256709
  manager.setStore(this.store);
@@ -255177,6 +256989,158 @@ Reply with exactly one word: YES, NO, or UNSURE.
255177
256989
  }
255178
256990
  };
255179
256991
 
256992
+ // src/core/router/provider-errors.ts
256993
+ var SYSTEMIC = /* @__PURE__ */ new Set([
256994
+ "rate_limit",
256995
+ "quota_exhausted",
256996
+ "auth",
256997
+ "model_unavailable"
256998
+ ]);
256999
+ function isSystemicKind(kind2) {
257000
+ return SYSTEMIC.has(kind2);
257001
+ }
257002
+ function statusOf(err) {
257003
+ if (!err || typeof err !== "object") return void 0;
257004
+ const e3 = err;
257005
+ for (const key of ["status", "statusCode", "code"]) {
257006
+ const v6 = e3[key];
257007
+ if (typeof v6 === "number" && v6 >= 100 && v6 < 600) return v6;
257008
+ }
257009
+ const resp = e3["response"];
257010
+ if (resp && typeof resp["status"] === "number") return resp["status"];
257011
+ const inner = e3["error"];
257012
+ if (inner && typeof inner["code"] === "number") return inner["code"];
257013
+ return void 0;
257014
+ }
257015
+ function messageOf(err) {
257016
+ if (err instanceof Error) return err.message;
257017
+ if (typeof err === "string") return err;
257018
+ if (err && typeof err === "object") {
257019
+ const e3 = err;
257020
+ if (typeof e3["message"] === "string") return e3["message"];
257021
+ const inner = e3["error"];
257022
+ if (inner && typeof inner["message"] === "string") return inner["message"];
257023
+ try {
257024
+ return JSON.stringify(err);
257025
+ } catch {
257026
+ }
257027
+ }
257028
+ return String(err);
257029
+ }
257030
+ function classifyProviderError(err) {
257031
+ const raw = messageOf(err).trim();
257032
+ const status = statusOf(err);
257033
+ const m3 = raw.toLowerCase();
257034
+ const kind2 = (() => {
257035
+ if (status === 429) {
257036
+ return /quota|billing|credit|exceeded your current quota|insufficient/.test(m3) ? "quota_exhausted" : "rate_limit";
257037
+ }
257038
+ if (status === 401 || status === 403) return "auth";
257039
+ if (status === 404) return "model_unavailable";
257040
+ if (/rate limit|too many requests|resource_exhausted/.test(m3)) {
257041
+ return /quota|billing|credit|insufficient/.test(m3) ? "quota_exhausted" : "rate_limit";
257042
+ }
257043
+ if (/quota|billing|insufficient_quota|insufficient credit|payment required/.test(m3)) return "quota_exhausted";
257044
+ if (/api key|unauthorized|authentication|permission denied|invalid[_ ]api/.test(m3)) return "auth";
257045
+ if (/model .*(not found|does not exist|unavailable)|no such model|unknown model|not supported for/.test(m3)) {
257046
+ return "model_unavailable";
257047
+ }
257048
+ if (/context length|too many tokens|maximum context|prompt is too long|input too long/.test(m3)) return "context_length";
257049
+ if (/safety|content filter|blocked|recitation|prohibited/.test(m3)) return "content_filter";
257050
+ if (/econnreset|etimedout|enotfound|socket hang up|network|fetch failed|aborted/.test(m3)) return "network";
257051
+ return "unknown";
257052
+ })();
257053
+ return { kind: kind2, systemic: isSystemicKind(kind2), status, raw };
257054
+ }
257055
+ function describeProviderError(c4, modelId) {
257056
+ const on = ` on ${modelId}` ;
257057
+ const detail = c4.raw ? ` Provider said: ${c4.raw}` : "";
257058
+ switch (c4.kind) {
257059
+ case "rate_limit":
257060
+ return `Rate limit hit${on}. The provider is throttling requests \u2014 lower the number of parallel workers, or use a model with a higher requests-per-minute allowance.${detail}`;
257061
+ case "quota_exhausted":
257062
+ return `Quota or billing limit reached${on}. This will not recover on its own \u2014 check the provider's billing page, or switch this tier to a different provider.${detail}`;
257063
+ case "auth":
257064
+ return `Authentication failed${on}. The API key is missing, expired, or lacks access to this model \u2014 re-check the key in Settings > Providers.${detail}`;
257065
+ case "model_unavailable":
257066
+ return `Model unavailable${on}. The id may be wrong, retired, or not enabled for this API key \u2014 pick a different model for this tier.${detail}`;
257067
+ case "context_length":
257068
+ return `The prompt was too long${on}. Reduce the attached context, or use a model with a larger context window for this tier.${detail}`;
257069
+ case "content_filter":
257070
+ return `The provider's safety filter refused this request${on}.${detail}`;
257071
+ case "network":
257072
+ return `Network error reaching the provider${on}. This is usually transient.${detail}`;
257073
+ default:
257074
+ return `The model call failed${on}.${detail}`;
257075
+ }
257076
+ }
257077
+
257078
+ // src/core/run-breaker.ts
257079
+ var DEFAULT_FAILURE_THRESHOLD = 3;
257080
+ var RunBreaker = class {
257081
+ threshold;
257082
+ /** modelId → consecutive systemic failures of the SAME kind. */
257083
+ counts = /* @__PURE__ */ new Map();
257084
+ trip = null;
257085
+ constructor(threshold = DEFAULT_FAILURE_THRESHOLD) {
257086
+ this.threshold = Math.max(1, threshold);
257087
+ }
257088
+ /**
257089
+ * Record a failed model call. Returns the trip if this failure is the one
257090
+ * that opened the breaker, otherwise null.
257091
+ *
257092
+ * A non-systemic failure RESETS the model's counter: it is evidence the model
257093
+ * is reachable and answering, which is exactly what a systemic streak claims
257094
+ * it is not.
257095
+ */
257096
+ record(err, modelId) {
257097
+ if (this.trip) return null;
257098
+ const id = modelId?.trim() || "unknown-model";
257099
+ const c4 = classifyProviderError(err);
257100
+ if (!c4.systemic) {
257101
+ this.counts.delete(id);
257102
+ return null;
257103
+ }
257104
+ const prev = this.counts.get(id);
257105
+ const n8 = prev && prev.kind === c4.kind ? prev.n + 1 : 1;
257106
+ this.counts.set(id, { kind: c4.kind, n: n8, last: c4 });
257107
+ if (n8 >= this.threshold) {
257108
+ this.trip = {
257109
+ modelId: id,
257110
+ kind: c4.kind,
257111
+ failures: n8,
257112
+ message: describeProviderError(c4, id)
257113
+ };
257114
+ return this.trip;
257115
+ }
257116
+ return null;
257117
+ }
257118
+ /** True once the run should stop launching work that would fail identically. */
257119
+ isOpen() {
257120
+ return this.trip !== null;
257121
+ }
257122
+ /** Why the breaker opened, or null while it is closed. */
257123
+ reason() {
257124
+ return this.trip;
257125
+ }
257126
+ /**
257127
+ * One line for a worker/section that never ran because the breaker was
257128
+ * already open. Says the work was skipped deliberately — not that it failed
257129
+ * on its own merits, which is what an empty FAILED status would imply.
257130
+ */
257131
+ skipMessage() {
257132
+ const t4 = this.trip;
257133
+ if (!t4) return "Skipped.";
257134
+ return `Skipped \u2014 the run stopped after ${t4.failures} consecutive failures on ${t4.modelId}. ${t4.message}`;
257135
+ }
257136
+ /** Test/diagnostic view of the per-model streaks. */
257137
+ streaks() {
257138
+ const out = {};
257139
+ for (const [k4, v6] of this.counts) out[k4] = { kind: v6.kind, n: v6.n };
257140
+ return out;
257141
+ }
257142
+ };
257143
+
255180
257144
  // src/tools/registry.ts
255181
257145
  var import_ignore = __toESM(require_ignore(), 1);
255182
257146
 
@@ -297684,7 +299648,18 @@ var ProviderConfigSchema = external_exports.object({
297684
299648
  apiVersion: external_exports.string().optional(),
297685
299649
  model: external_exports.string().optional(),
297686
299650
  authToken: external_exports.string().optional(),
297687
- credentialSource: external_exports.string().optional()
299651
+ credentialSource: external_exports.string().optional(),
299652
+ /**
299653
+ * "This endpoint is self-hosted, so inference genuinely costs $0."
299654
+ * Only meaningful for `ollama` and `openai-compatible`. Unset ⇒ inferred:
299655
+ * ollama is local, openai-compatible is local when its baseUrl is
299656
+ * loopback/LAN. Set it explicitly to override — e.g. `false` for an Ollama
299657
+ * instance you rent, `true` for a llama.cpp box on your own LAN reached by
299658
+ * hostname.
299659
+ */
299660
+ local: external_exports.boolean().optional(),
299661
+ /** Region for providers whose price varies by region (Azure: global | us | eu | …). */
299662
+ region: external_exports.string().optional()
297688
299663
  });
297689
299664
  var ModelOverridesSchema = external_exports.object({
297690
299665
  t1: external_exports.string().optional(),
@@ -298270,8 +300245,8 @@ var TaskAnalyzer = class {
298270
300245
  }
298271
300246
  costEfficiency(model, complexity) {
298272
300247
  if (this.tracker) return this.tracker.costEfficiencyScore(model, complexity);
298273
- const blended = model.inputCostPer1kTokens + model.outputCostPer1kTokens * 2;
298274
- const normalised = Math.min(1, blended / 0.05);
300248
+ const blended = blendedCostPer1k(model);
300249
+ const normalised = Math.min(1, blended / BLENDED_COST_CEILING);
298275
300250
  const complexityWeight = (6 - complexity) / 5;
298276
300251
  return Math.max(0.1, 1 - normalised * complexityWeight);
298277
300252
  }
@@ -298406,8 +300381,8 @@ var ModelPerformanceTracker = class {
298406
300381
  * normalised over $0.05 blended as the "expensive" ceiling.
298407
300382
  */
298408
300383
  costEfficiencyScore(model, complexity) {
298409
- const blended = model.inputCostPer1kTokens + model.outputCostPer1kTokens * 2;
298410
- const normalised = Math.min(1, blended / 0.05);
300384
+ const blended = blendedCostPer1k(model);
300385
+ const normalised = Math.min(1, blended / BLENDED_COST_CEILING);
298411
300386
  const complexityWeight = (6 - complexity) / 5;
298412
300387
  return Math.max(0.1, 1 - normalised * complexityWeight);
298413
300388
  }
@@ -301042,6 +303017,7 @@ ${prompt}` : prompt;
301042
303017
  if (toolCreator) toolCreator.setPermissionEscalator(escalator);
301043
303018
  const rootPrompt = buildContextualPrompt(options.prompt, options.conversationHistory);
301044
303019
  let finalOutput = "";
303020
+ const runBreaker = new RunBreaker();
301045
303021
  let t2Results = [];
301046
303022
  let runError = null;
301047
303023
  let identityPrompt = "";
@@ -301110,6 +303086,7 @@ ${prompt}` : prompt;
301110
303086
  this.emit("tier:status", { tierId: "t3-root", status: "COMPLETED", role: "T3" });
301111
303087
  } else if (complexity === "Moderate") {
301112
303088
  const t22 = new T2Manager(this.router, this.toolRegistry, "root");
303089
+ t22.setRunBreaker(runBreaker);
301113
303090
  t22.setPresenter(true);
301114
303091
  t22.setHierarchyContext("You are the ROOT Manager for this task. There is no T1 Administrator involved in this run. You are responsible for decomposing the task and managing T3 workers directly.");
301115
303092
  if (identityPrompt) {
@@ -301170,6 +303147,7 @@ _(incomplete: ${reasons.join("; ")})_` : partial2;
301170
303147
  }
301171
303148
  } else {
301172
303149
  const t1 = new T1Administrator(this.router, this.toolRegistry, this.config);
303150
+ t1.setRunBreaker(runBreaker);
301173
303151
  t1.setPresenter(true);
301174
303152
  t1.setHierarchyContext("You are the top-level Administrator. You are responsible for the overall plan and supervising multiple T2 Managers.");
301175
303153
  if (identityPrompt) {
@@ -301194,6 +303172,20 @@ _(incomplete: ${reasons.join("; ")})_` : partial2;
301194
303172
  finalOutput = result.output;
301195
303173
  t2Results = result.t2Results;
301196
303174
  }
303175
+ const trip = runBreaker.reason();
303176
+ if (trip) {
303177
+ finalOutput = [
303178
+ `\u26A0 **Run stopped early \u2014 ${trip.modelId} was failing every request.**`,
303179
+ "",
303180
+ trip.message,
303181
+ "",
303182
+ `Cascade stopped after ${trip.failures} consecutive failures rather than retrying every remaining subtask against the same model, which would have cost more and produced the same result.`,
303183
+ finalOutput ? `
303184
+ ---
303185
+
303186
+ ${finalOutput}` : ""
303187
+ ].join("\n").trimEnd();
303188
+ }
301197
303189
  } catch (err) {
301198
303190
  if (err instanceof CascadeCancelledError || err instanceof Error && err.name === "AbortError" || options.signal?.aborted) {
301199
303191
  this.emit("run:cancelled", {
@@ -301260,7 +303252,11 @@ _(incomplete: ${reasons.join("; ")})_` : partial2;
301260
303252
  inputTokens: 0,
301261
303253
  outputTokens: 0,
301262
303254
  totalTokens: stats.totalTokens,
301263
- estimatedCostUsd: stats.totalCostUsd
303255
+ estimatedCostUsd: stats.totalCostUsd,
303256
+ // At least one call ran on a model with no known price, so its spend is
303257
+ // missing from the total above. Say so rather than letting the caller
303258
+ // present an undercount as the final figure.
303259
+ ...stats.untrackedCostCalls > 0 ? { costUnknown: true } : {}
301264
303260
  },
301265
303261
  t2Results,
301266
303262
  durationMs,
@@ -301330,7 +303326,8 @@ _(incomplete: ${reasons.join("; ")})_` : partial2;
301330
303326
  inputTokens: 0,
301331
303327
  outputTokens: 0,
301332
303328
  totalTokens: stats2.totalTokens,
301333
- estimatedCostUsd: stats2.totalCostUsd
303329
+ estimatedCostUsd: stats2.totalCostUsd,
303330
+ ...stats2.untrackedCostCalls > 0 ? { costUnknown: true } : {}
301334
303331
  },
301335
303332
  t2Results: [],
301336
303333
  durationMs: Date.now() - startMs,
@@ -301354,7 +303351,8 @@ _(incomplete: ${reasons.join("; ")})_` : partial2;
301354
303351
  inputTokens: result.usage?.inputTokens ?? 0,
301355
303352
  outputTokens: result.usage?.outputTokens ?? 0,
301356
303353
  totalTokens: stats.totalTokens,
301357
- estimatedCostUsd: stats.totalCostUsd
303354
+ estimatedCostUsd: stats.totalCostUsd,
303355
+ ...stats.untrackedCostCalls > 0 ? { costUnknown: true } : {}
301358
303356
  },
301359
303357
  t2Results: [],
301360
303358
  durationMs: Date.now() - startMs,
@@ -303922,7 +305920,10 @@ var DashboardServer = class {
303922
305920
  this.socket.broadcast("cost:update", {
303923
305921
  sessionId,
303924
305922
  totalTokens: result.usage.totalTokens,
303925
- totalCostUsd: result.usage.estimatedCostUsd
305923
+ totalCostUsd: result.usage.estimatedCostUsd,
305924
+ // True when a model with no known price was used: the total above is
305925
+ // an undercount, and the UI must not present it as the full spend.
305926
+ costUnknown: result.usage.costUnknown === true
303926
305927
  });
303927
305928
  this.throttledBroadcast("workspace");
303928
305929
  } catch (err) {
@@ -304235,7 +306236,8 @@ var DashboardServer = class {
304235
306236
  this.socket.broadcast("cost:update", {
304236
306237
  sessionId,
304237
306238
  totalTokens: result.usage.totalTokens,
304238
- totalCostUsd: result.usage.estimatedCostUsd
306239
+ totalCostUsd: result.usage.estimatedCostUsd,
306240
+ costUnknown: result.usage.costUnknown === true
304239
306241
  });
304240
306242
  this.throttledBroadcast("workspace");
304241
306243
  } catch (err) {
@@ -304777,7 +306779,8 @@ ${prompt}`;
304777
306779
  this.socket.broadcast("cost:update", {
304778
306780
  sessionId,
304779
306781
  totalTokens: result.usage.totalTokens,
304780
- totalCostUsd: result.usage.estimatedCostUsd
306782
+ totalCostUsd: result.usage.estimatedCostUsd,
306783
+ costUnknown: result.usage.costUnknown === true
304781
306784
  });
304782
306785
  this.socket.broadcastToRoom(`session:${sessionId}`, "session:complete", { sessionId, result });
304783
306786
  this.throttledBroadcast("workspace");