use super::{AnthropicProvider, MistralProvider, OpenAiProvider};
#[derive(Debug, Clone)]
pub struct Model {
pub name: String,
pub context_window: Option<u64>,
}
impl Model {
pub fn from_name(name: impl Into<String>) -> Self {
let name = name.into();
let context_window = AnthropicProvider::lookup_context_window_size(&name)
.or_else(|| OpenAiProvider::lookup_context_window_size(&name))
.or_else(|| MistralProvider::lookup_context_window_size(&name));
Self {
name,
context_window,
}
}
pub fn context_window(mut self, size: u64) -> Self {
self.context_window = Some(size);
self
}
}
impl From<&str> for Model {
fn from(name: &str) -> Self {
Self::from_name(name)
}
}
impl From<String> for Model {
fn from(name: String) -> Self {
Self::from_name(name)
}
}
impl From<&String> for Model {
fn from(name: &String) -> Self {
Self::from_name(name.as_str())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn from_name_resolves_claude_models() {
assert_eq!(
Model::from_name("claude-sonnet-4-20250514").context_window,
Some(200_000)
);
}
#[test]
fn from_name_resolves_openai_models() {
assert_eq!(Model::from_name("gpt-5").context_window, Some(400_000));
assert_eq!(Model::from_name("gpt-4o").context_window, Some(128_000));
}
#[test]
fn from_name_resolves_mistral_models() {
assert_eq!(
Model::from_name("mistral-large-2411").context_window,
Some(131_072)
);
}
#[test]
fn from_name_unknown_has_no_context_window() {
assert_eq!(Model::from_name("unknown").context_window, None);
assert_eq!(Model::from_name("mock").context_window, None);
}
#[test]
fn context_window_overrides() {
let m = Model::from_name("unknown").context_window(50_000);
assert_eq!(m.context_window, Some(50_000));
}
}