pub mod convert;
mod registry;
#[cfg(feature = "remote")]
pub mod remote;
pub(crate) mod tier;
pub mod types;
pub use aither_core::llm::model::Ability;
pub use registry::ModelRegistry;
pub use tier::ModelTier;
pub use types::{ModelEntry, ModelMode, Pricing, Provider};
#[must_use]
pub fn lookup(model_id: &str) -> Option<&'static ModelEntry> {
ModelRegistry::bundled().lookup(model_id)
}
pub fn models_for_provider(provider: &Provider) -> impl Iterator<Item = &'static ModelEntry> + '_ {
ModelRegistry::bundled().models_for_provider(provider)
}
pub fn models_with_ability(ability: Ability) -> impl Iterator<Item = &'static ModelEntry> {
ModelRegistry::bundled().models_with_ability(ability)
}
pub fn models_by_mode(mode: ModelMode) -> impl Iterator<Item = &'static ModelEntry> {
ModelRegistry::bundled().models_by_mode(mode)
}
pub fn all_models() -> impl Iterator<Item = &'static ModelEntry> {
ModelRegistry::bundled().all()
}
#[must_use]
pub fn tier(model_id: &str) -> ModelTier {
ModelRegistry::bundled().tier(model_id)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn bundled_matches_runtime_conversion_of_snapshot() {
let runtime =
ModelRegistry::from_litellm_json(include_bytes!("../data/litellm_snapshot.json"));
let bundled: Vec<_> = all_models().map(ModelEntry::litellm_id).collect();
let converted: Vec<_> = runtime.all().map(ModelEntry::litellm_id).collect();
assert_eq!(bundled, converted);
}
#[test]
fn bundled_registry_is_populated() {
let registry = ModelRegistry::bundled();
assert!(
registry.len() > 100,
"Expected 100+ models, got {}",
registry.len()
);
assert_ne!(models_by_mode(ModelMode::Chat).count(), 0);
}
#[test]
fn every_entry_is_reachable_by_its_litellm_id() {
for entry in all_models() {
assert!(
lookup(entry.litellm_id()).is_some(),
"{} is not reachable by its own key",
entry.litellm_id()
);
assert!(
entry.litellm_id().ends_with(entry.id()),
"{} does not end with its canonical id {}",
entry.litellm_id(),
entry.id()
);
}
}
#[test]
fn query_helpers_return_only_matching_entries() {
assert!(models_with_ability(Ability::Vision).all(|m| m.has_ability(Ability::Vision)));
assert!(models_by_mode(ModelMode::Chat).all(|m| m.mode() == ModelMode::Chat));
assert!(models_for_provider(&Provider::OpenAI).all(|m| *m.provider() == Provider::OpenAI));
}
#[test]
fn image_generation_entries_classify_as_image_tier() {
for entry in models_by_mode(ModelMode::ImageGeneration) {
assert!(entry.has_ability(Ability::ImageGeneration));
assert_eq!(
ModelRegistry::bundled().tier_of(entry),
ModelTier::ImageGeneration
);
}
}
}