mod claude;
mod cohere;
mod deepseek;
mod glm;
mod google;
mod kimi;
mod llama;
mod minimax;
mod mistral;
mod nova;
mod qwen;
pub use claude::*;
pub use cohere::*;
pub use deepseek::*;
pub use glm::*;
pub use google::*;
pub use kimi::*;
pub use llama::*;
pub use minimax::*;
pub use mistral::*;
pub use nova::*;
pub use qwen::*;
macro_rules! define_model {
(
$(#[$meta:meta])*
$name:ident {
display_name: $display_name:expr,
bedrock_id: $bedrock_id:expr,
context_tokens: $context_tokens:expr,
output_tokens: $output_tokens:expr
$(, anthropic_id: $anthropic_id:expr)?
$(, default_inference_profile: $profile:expr)?
}
) => {
$(#[$meta])*
#[derive(Debug, Clone, Copy, Default)]
pub struct $name;
impl $crate::model::Model for $name {
fn name(&self) -> &'static str {
$display_name
}
fn max_context_tokens(&self) -> usize {
$context_tokens
}
fn max_output_tokens(&self) -> usize {
$output_tokens
}
fn estimate_token_count(&self, text: &str) -> usize {
text.len().div_ceil(4)
}
}
impl $crate::model::BedrockModel for $name {
fn bedrock_id(&self) -> &'static str {
$bedrock_id
}
$crate::models::define_model!(@inference_profile $($profile)?);
}
$(
impl $crate::model::AnthropicModel for $name {
fn anthropic_id(&self) -> &'static str {
$anthropic_id
}
}
)?
};
(@inference_profile $profile:expr) => {
fn default_inference_profile(&self) -> $crate::model::InferenceProfile {
$profile
}
};
(@inference_profile) => {};
}
pub(crate) use define_model;
#[cfg(test)]
mod tests {
use super::*;
use crate::model::{AnthropicModel, BedrockModel, InferenceProfile, Model};
#[test]
fn test_claude_implements_both_traits() {
let model = ClaudeSonnet4_5;
assert_eq!(model.name(), "Claude Sonnet 4.5");
assert_eq!(model.max_context_tokens(), 200_000);
assert_eq!(model.max_output_tokens(), 64_000);
assert!(model.bedrock_id().contains("claude-sonnet-4-5"));
assert!(model.anthropic_id().contains("claude-sonnet-4-5"));
}
#[test]
fn test_nova_only_implements_bedrock() {
let model = NovaMicro;
assert_eq!(model.name(), "Nova Micro");
assert!(model.bedrock_id().contains("nova-micro"));
}
#[test]
fn test_models_are_copy() {
let model = ClaudeSonnet4_5;
let copy = model;
assert_eq!(model.name(), copy.name());
}
#[test]
fn test_model_ids_are_valid() {
let models: Vec<&dyn BedrockModel> = vec![
&Claude3_7Sonnet,
&ClaudeOpus4,
&ClaudeSonnet4,
&ClaudeSonnet4_5,
&ClaudeSonnet4_6,
&ClaudeHaiku4_5,
&ClaudeOpus4_5,
&ClaudeOpus4_1,
&ClaudeOpus4_6,
&NovaMicro,
&NovaLite,
&Nova2Lite,
&NovaPro,
&NovaPremier,
&Nova2Sonic,
&MistralLarge3,
&MagistralSmall,
&Ministral3B,
&Ministral8B,
&Ministral14B,
&PixtralLarge,
&VoxtralMini3B,
&VoxtralSmall24B,
&CohereCommandRPlus,
&Qwen3_235B,
&Qwen3Coder480B,
&Qwen3_32B,
&Qwen3Coder30B,
&Qwen3Next80B,
&Qwen3VL235B,
&Qwen3CoderNext,
&GLM4_7,
&GLM4_7Flash,
&Gemma3_27B,
&Gemma3_12B,
&Gemma3_4B,
&DeepSeekR1,
&DeepSeekV3_1,
&DeepSeekV3_2,
&KimiK2Thinking,
&KimiK2_5,
&MiniMaxM2_1,
&Llama4Scout17B,
&Llama4Maverick17B,
&Llama3_3_70B,
&Llama3_2_90B,
&Llama3_2_11B,
&Llama3_2_3B,
&Llama3_2_1B,
&Llama3_1_405B,
&Llama3_1_70B,
&Llama3_1_8B,
];
for model in models {
let id = model.bedrock_id();
assert!(
!id.contains(' '),
"Model ID should not contain spaces: {}",
id
);
assert!(
id.contains('.'),
"Model ID should contain provider prefix: {}",
id
);
}
}
#[test]
fn test_global_inference_profile_models() {
let global_models: Vec<&dyn BedrockModel> = vec![
&ClaudeOpus4,
&ClaudeOpus4_1,
&ClaudeOpus4_5,
&ClaudeOpus4_6,
&ClaudeSonnet4,
&ClaudeSonnet4_5,
&ClaudeSonnet4_6,
&ClaudeHaiku4_5,
&Nova2Lite,
&Nova2Sonic,
];
for model in global_models {
assert_eq!(
model.default_inference_profile(),
InferenceProfile::Global,
"{} should have Global inference profile",
model.bedrock_id()
);
}
}
#[test]
fn test_default_inference_profile_models() {
let default_models: Vec<&dyn BedrockModel> = vec![
&Claude3_7Sonnet,
&NovaMicro,
&NovaLite,
&NovaPro,
&NovaPremier,
&MistralLarge3,
&Gemma3_27B,
&DeepSeekR1,
&KimiK2Thinking,
];
for model in default_models {
assert_eq!(
model.default_inference_profile(),
InferenceProfile::None,
"{} should have None (default) inference profile",
model.bedrock_id()
);
}
}
}