pub fn infer_provider(model: &str) -> Option<&'static str> {
if model.is_empty() {
return None;
}
if model.starts_with("gpt-") || model.starts_with("chatgpt-") {
return Some("openai");
}
if model == "o3" || model.starts_with("o3-") {
return Some("openai");
}
if model.starts_with("o4-") || model.starts_with("o5-") {
return Some("openai");
}
if model.starts_with("claude-") {
return Some("anthropic");
}
if model.starts_with("gemini-") {
return Some("gemini");
}
if model.starts_with("mistral-")
|| model.starts_with("mixtral-")
|| model.starts_with("pixtral-")
|| model.starts_with("codestral-")
|| model.starts_with("ministral-")
{
return Some("mistral");
}
None
}
pub fn known_to_differ(a: &str, b: &str) -> bool {
match (infer_provider(a), infer_provider(b)) {
(Some(x), Some(y)) => x != y,
_ => false,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn openai_prefixes() {
assert_eq!(infer_provider("gpt-4o"), Some("openai"));
assert_eq!(infer_provider("gpt-4o-mini"), Some("openai"));
assert_eq!(infer_provider("gpt-5.5"), Some("openai"));
assert_eq!(infer_provider("chatgpt-4o-latest"), Some("openai"));
assert_eq!(infer_provider("o3"), Some("openai"));
assert_eq!(infer_provider("o3-mini"), Some("openai"));
assert_eq!(infer_provider("o4-mini"), Some("openai"));
}
#[test]
fn anthropic_prefix() {
assert_eq!(infer_provider("claude-opus-4-7"), Some("anthropic"));
assert_eq!(infer_provider("claude-sonnet-4-6"), Some("anthropic"));
assert_eq!(infer_provider("claude-haiku-4-5"), Some("anthropic"));
}
#[test]
fn gemini_prefix() {
assert_eq!(infer_provider("gemini-2.5-pro"), Some("gemini"));
assert_eq!(infer_provider("gemini-1.5-flash"), Some("gemini"));
}
#[test]
fn mistral_family_prefixes() {
assert_eq!(infer_provider("mistral-large-2407"), Some("mistral"));
assert_eq!(infer_provider("mixtral-8x22b"), Some("mistral"));
assert_eq!(infer_provider("pixtral-12b"), Some("mistral"));
assert_eq!(infer_provider("codestral-22b"), Some("mistral"));
assert_eq!(infer_provider("ministral-8b"), Some("mistral"));
}
#[test]
fn unknown_returns_none() {
assert_eq!(infer_provider("llama-3.3-70b"), None);
assert_eq!(infer_provider("qwen2.5-72b"), None);
assert_eq!(infer_provider("deepseek-r1"), None);
assert_eq!(infer_provider("totally-custom-model"), None);
assert_eq!(infer_provider(""), None);
}
#[test]
fn known_to_differ_only_blocks_known_pairs() {
assert!(!known_to_differ("gpt-4o", "gpt-4o-mini"));
assert!(!known_to_differ("claude-sonnet-4-6", "claude-haiku-4-5"));
assert!(known_to_differ("gpt-4o", "claude-sonnet-4-6"));
assert!(known_to_differ("claude-haiku-4-5", "gemini-2.5-pro"));
assert!(!known_to_differ("gpt-4o", "llama-3.3-70b"));
assert!(!known_to_differ("custom-1", "custom-2"));
assert!(!known_to_differ("custom-1", "gpt-4o"));
}
}