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