1use std::collections::HashMap;
9
10#[cfg(feature = "serde")]
11use serde::{Deserialize, Serialize};
12
13#[derive(Debug, Clone, Copy, PartialEq)]
18#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
19pub struct ModelPrice {
20 pub input_per_million_usd: f64,
21 pub output_per_million_usd: f64,
22 pub cached_input_per_million_usd: Option<f64>,
23}
24
25impl ModelPrice {
26 pub const fn new(input_per_million_usd: f64, output_per_million_usd: f64) -> Self {
27 Self {
28 input_per_million_usd,
29 output_per_million_usd,
30 cached_input_per_million_usd: None,
31 }
32 }
33
34 pub const fn with_cached(
35 input_per_million_usd: f64,
36 output_per_million_usd: f64,
37 cached_input_per_million_usd: f64,
38 ) -> Self {
39 Self {
40 input_per_million_usd,
41 output_per_million_usd,
42 cached_input_per_million_usd: Some(cached_input_per_million_usd),
43 }
44 }
45}
46
47const BUILTIN: &[(&str, ModelPrice)] = &[
49 ("claude-opus-4-7", ModelPrice::with_cached(15.00, 75.00, 1.50)),
51 ("claude-opus-4-6", ModelPrice::with_cached(15.00, 75.00, 1.50)),
52 ("claude-opus-4-5", ModelPrice::with_cached(15.00, 75.00, 1.50)),
53 ("claude-sonnet-4-6", ModelPrice::with_cached(3.00, 15.00, 0.30)),
54 ("claude-sonnet-4-5", ModelPrice::with_cached(3.00, 15.00, 0.30)),
55 ("claude-haiku-4-5", ModelPrice::with_cached(0.80, 4.00, 0.08)),
56 ("gpt-5.4", ModelPrice::new(1.25, 10.00)),
58 ("gpt-5", ModelPrice::new(1.25, 10.00)),
59 ("gpt-5-mini", ModelPrice::new(0.25, 2.00)),
60 ("gpt-5-nano", ModelPrice::new(0.05, 0.40)),
61 ("gemini-2.5-pro", ModelPrice::new(1.25, 10.00)),
63 ("gemini-2.5-flash", ModelPrice::new(0.30, 2.50)),
64 ("anthropic.claude-opus-4-7-v1:0", ModelPrice::with_cached(15.00, 75.00, 1.50)),
66 ("anthropic.claude-sonnet-4-6-v1:0", ModelPrice::with_cached(3.00, 15.00, 0.30)),
67 ("anthropic.claude-haiku-4-5-v1:0", ModelPrice::with_cached(0.80, 4.00, 0.08)),
68 ("meta.llama3-1-70b-instruct-v1:0", ModelPrice::new(2.65, 3.50)),
70];
71
72const ALIASES: &[(&str, &str)] = &[
73 ("opus", "claude-opus-4-7"),
74 ("sonnet", "claude-sonnet-4-6"),
75 ("haiku", "claude-haiku-4-5"),
76 ("gpt5", "gpt-5"),
77 ("gemini-pro", "gemini-2.5-pro"),
78 ("gemini-flash", "gemini-2.5-flash"),
79];
80
81pub const MODEL_PRICES: &[(&str, f64, f64)] = &[
85 ("claude-opus-4-7", 15.00, 75.00),
86 ("claude-opus-4-6", 15.00, 75.00),
87 ("claude-opus-4-5", 15.00, 75.00),
88 ("claude-sonnet-4-6", 3.00, 15.00),
89 ("claude-sonnet-4-5", 3.00, 15.00),
90 ("claude-haiku-4-5", 0.80, 4.00),
91 ("gpt-5.4", 1.25, 10.00),
92 ("gpt-5", 1.25, 10.00),
93 ("gpt-5-mini", 0.25, 2.00),
94 ("gpt-5-nano", 0.05, 0.40),
95 ("gemini-2.5-pro", 1.25, 10.00),
96 ("gemini-2.5-flash", 0.30, 2.50),
97 ("anthropic.claude-opus-4-7-v1:0", 15.00, 75.00),
98 ("anthropic.claude-sonnet-4-6-v1:0", 3.00, 15.00),
99 ("anthropic.claude-haiku-4-5-v1:0", 0.80, 4.00),
100 ("meta.llama3-1-70b-instruct-v1:0", 2.65, 3.50),
101];
102
103pub fn builtin_prices() -> HashMap<String, ModelPrice> {
107 let mut table: HashMap<String, ModelPrice> = BUILTIN
108 .iter()
109 .map(|(id, p)| ((*id).to_string(), *p))
110 .collect();
111 for (alias, canonical) in ALIASES {
112 if let Some(price) = table.get(*canonical).copied() {
113 table.insert((*alias).to_string(), price);
114 }
115 }
116 table
117}
118
119pub fn known_models() -> Vec<String> {
121 let mut ids: Vec<String> = BUILTIN.iter().map(|(id, _)| (*id).to_string()).collect();
122 for (alias, _) in ALIASES {
123 ids.push((*alias).to_string());
124 }
125 ids.sort();
126 ids.dedup();
127 ids
128}