1mod claude;
21mod cohere;
22mod deepseek;
23mod glm;
24mod google;
25mod kimi;
26mod llama;
27mod minimax;
28mod mistral;
29mod nova;
30mod qwen;
31
32pub use claude::*;
34pub use cohere::*;
35pub use deepseek::*;
36pub use glm::*;
37pub use google::*;
38pub use kimi::*;
39pub use llama::*;
40pub use minimax::*;
41pub use mistral::*;
42pub use nova::*;
43pub use qwen::*;
44
45macro_rules! define_model {
56 (
57 $(#[$meta:meta])*
58 $name:ident {
59 display_name: $display_name:expr,
60 bedrock_id: $bedrock_id:expr,
61 context_tokens: $context_tokens:expr,
62 output_tokens: $output_tokens:expr
63 $(, anthropic_id: $anthropic_id:expr)?
64 $(, default_inference_profile: $profile:expr)?
65 }
66 ) => {
67 $(#[$meta])*
68 #[derive(Debug, Clone, Copy, Default)]
69 pub struct $name;
70
71 impl $crate::model::Model for $name {
72 fn name(&self) -> &'static str {
73 $display_name
74 }
75
76 fn max_context_tokens(&self) -> usize {
77 $context_tokens
78 }
79
80 fn max_output_tokens(&self) -> usize {
81 $output_tokens
82 }
83
84 fn estimate_token_count(&self, text: &str) -> usize {
85 text.len().div_ceil(4)
87 }
88 }
89
90 impl $crate::model::BedrockModel for $name {
91 fn bedrock_id(&self) -> &'static str {
92 $bedrock_id
93 }
94
95 $crate::models::define_model!(@inference_profile $($profile)?);
96 }
97
98 $(
99 impl $crate::model::AnthropicModel for $name {
100 fn anthropic_id(&self) -> &'static str {
101 $anthropic_id
102 }
103 }
104 )?
105 };
106
107 (@inference_profile $profile:expr) => {
109 fn default_inference_profile(&self) -> $crate::model::InferenceProfile {
110 $profile
111 }
112 };
113
114 (@inference_profile) => {};
116}
117
118pub(crate) use define_model;
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124 use crate::model::{AnthropicModel, BedrockModel, InferenceProfile, Model};
125
126 #[test]
127 fn test_claude_implements_both_traits() {
128 let model = ClaudeSonnet4_5;
129
130 assert_eq!(model.name(), "Claude Sonnet 4.5");
132 assert_eq!(model.max_context_tokens(), 200_000);
133 assert_eq!(model.max_output_tokens(), 64_000);
134
135 assert!(model.bedrock_id().contains("claude-sonnet-4-5"));
137
138 assert!(model.anthropic_id().contains("claude-sonnet-4-5"));
140 }
141
142 #[test]
143 fn test_nova_only_implements_bedrock() {
144 let model = NovaMicro;
145
146 assert_eq!(model.name(), "Nova Micro");
148
149 assert!(model.bedrock_id().contains("nova-micro"));
151
152 }
154
155 #[test]
156 fn test_models_are_copy() {
157 let model = ClaudeSonnet4_5;
158 let copy = model;
159 assert_eq!(model.name(), copy.name());
160 }
161
162 #[test]
163 fn test_model_ids_are_valid() {
164 let models: Vec<&dyn BedrockModel> = vec![
166 &Claude3_7Sonnet,
167 &ClaudeOpus4,
168 &ClaudeSonnet4,
169 &ClaudeSonnet4_5,
170 &ClaudeSonnet4_6,
171 &ClaudeHaiku4_5,
172 &ClaudeOpus4_5,
173 &ClaudeOpus4_1,
174 &ClaudeOpus4_6,
175 &NovaMicro,
176 &NovaLite,
177 &Nova2Lite,
178 &NovaPro,
179 &NovaPremier,
180 &Nova2Sonic,
181 &MistralLarge3,
182 &MagistralSmall,
183 &Ministral3B,
184 &Ministral8B,
185 &Ministral14B,
186 &PixtralLarge,
187 &VoxtralMini3B,
188 &VoxtralSmall24B,
189 &CohereCommandRPlus,
190 &Qwen3_235B,
191 &Qwen3Coder480B,
192 &Qwen3_32B,
193 &Qwen3Coder30B,
194 &Qwen3Next80B,
195 &Qwen3VL235B,
196 &Qwen3CoderNext,
197 &GLM4_7,
198 &GLM4_7Flash,
199 &Gemma3_27B,
200 &Gemma3_12B,
201 &Gemma3_4B,
202 &DeepSeekR1,
203 &DeepSeekV3_1,
204 &DeepSeekV3_2,
205 &KimiK2Thinking,
206 &KimiK2_5,
207 &MiniMaxM2_1,
208 &Llama4Scout17B,
209 &Llama4Maverick17B,
210 &Llama3_3_70B,
211 &Llama3_2_90B,
212 &Llama3_2_11B,
213 &Llama3_2_3B,
214 &Llama3_2_1B,
215 &Llama3_1_405B,
216 &Llama3_1_70B,
217 &Llama3_1_8B,
218 ];
219
220 for model in models {
221 let id = model.bedrock_id();
222 assert!(
223 !id.contains(' '),
224 "Model ID should not contain spaces: {}",
225 id
226 );
227 assert!(
228 id.contains('.'),
229 "Model ID should contain provider prefix: {}",
230 id
231 );
232 }
233 }
234
235 #[test]
236 fn test_global_inference_profile_models() {
237 let global_models: Vec<&dyn BedrockModel> = vec![
239 &ClaudeOpus4,
240 &ClaudeOpus4_1,
241 &ClaudeOpus4_5,
242 &ClaudeOpus4_6,
243 &ClaudeSonnet4,
244 &ClaudeSonnet4_5,
245 &ClaudeSonnet4_6,
246 &ClaudeHaiku4_5,
247 &Nova2Lite,
248 &Nova2Sonic,
249 ];
250
251 for model in global_models {
252 assert_eq!(
253 model.default_inference_profile(),
254 InferenceProfile::Global,
255 "{} should have Global inference profile",
256 model.bedrock_id()
257 );
258 }
259 }
260
261 #[test]
262 fn test_default_inference_profile_models() {
263 let default_models: Vec<&dyn BedrockModel> = vec![
265 &Claude3_7Sonnet,
266 &NovaMicro,
267 &NovaLite,
268 &NovaPro,
269 &NovaPremier,
270 &MistralLarge3,
271 &Gemma3_27B,
272 &DeepSeekR1,
273 &KimiK2Thinking,
274 ];
275
276 for model in default_models {
277 assert_eq!(
278 model.default_inference_profile(),
279 InferenceProfile::None,
280 "{} should have None (default) inference profile",
281 model.bedrock_id()
282 );
283 }
284 }
285}