use std::collections::HashMap;
use std::sync::LazyLock;
use crate::provider::ModelEntry;
const CATALOG_JSON: &str = include_str!("../data/models.json");
#[derive(serde::Deserialize)]
struct RawModel {
id: String,
name: String,
context: Option<u32>,
}
static CATALOG: LazyLock<HashMap<String, Vec<ModelEntry>>> = LazyLock::new(|| {
let raw: HashMap<String, Vec<RawModel>> = serde_json::from_str(CATALOG_JSON)
.expect("embedded data/models.json is malformed — run scripts/gen-models-catalog.sh");
raw.into_iter()
.map(|(provider, models)| {
let entries = models
.into_iter()
.map(|m| ModelEntry {
id: m.id,
display: m.name,
context_length: m.context,
kind: None,
})
.collect();
(provider, entries)
})
.collect()
});
pub fn catalog_entries(provider: &str) -> Option<Vec<ModelEntry>> {
CATALOG.get(provider).cloned()
}
#[cfg(test)]
mod tests {
use super::*;
fn ids(provider: &str) -> Vec<String> {
catalog_entries(provider)
.unwrap_or_default()
.iter()
.map(|m| m.id.clone())
.collect()
}
#[test]
fn catalog_parses_and_has_expected_providers() {
for p in ["anthropic", "openai", "gemini", "openrouter"] {
assert!(
!ids(p).is_empty(),
"missing or empty baked catalog for: {p}"
);
}
}
#[test]
fn openrouter_includes_default_model() {
assert!(
ids("openrouter").contains(&"deepseek/deepseek-v4-pro".to_string()),
"default model missing from baked openrouter catalog"
);
}
#[test]
fn unbaked_provider_has_no_catalog() {
assert!(catalog_entries("ollama").is_none());
}
}