use std::path::PathBuf;
use anyhow::Result;
use tracing::info;
use super::model::ModelRegistry;
const LITELLM_URL: &str =
"https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json";
fn cache_path() -> Option<PathBuf> {
dirs::home_dir().map(|home| home.join(".collet").join("cache").join("models.json"))
}
pub fn load_cached() -> ModelRegistry {
let Some(path) = cache_path() else {
return ModelRegistry::empty();
};
match std::fs::read(&path) {
Ok(data) => ModelRegistry::parse(&data),
Err(_) => ModelRegistry::empty(),
}
}
pub fn load_or_fetch_blocking() -> ModelRegistry {
if let Some(path) = cache_path()
&& let Ok(meta) = std::fs::metadata(&path)
{
let age = meta
.modified()
.ok()
.and_then(|m| m.elapsed().ok())
.unwrap_or(std::time::Duration::MAX);
if age < std::time::Duration::from_secs(24 * 3600)
&& let Ok(data) = std::fs::read(&path)
{
let reg = ModelRegistry::parse(&data);
if !reg.is_empty() {
return reg;
}
}
}
fetch_and_cache_blocking().unwrap_or_else(|_| load_cached())
}
pub fn fetch_and_cache_blocking() -> Result<ModelRegistry> {
info!("fetching model registry from {LITELLM_URL}");
let bytes = std::thread::spawn(|| -> Result<Vec<u8>> {
Ok(reqwest::blocking::get(LITELLM_URL)?.bytes()?.to_vec())
})
.join()
.map_err(|_| anyhow::anyhow!("registry fetch thread panicked"))??;
if let Some(path) = cache_path() {
if let Some(parent) = path.parent() {
std::fs::create_dir_all(parent)?;
}
std::fs::write(&path, &bytes)?;
info!("cached model registry to {}", path.display());
}
Ok(ModelRegistry::parse(&bytes))
}