use std::path::PathBuf;
pub fn models_dir() -> PathBuf {
std::env::var("HOME")
.map(PathBuf::from)
.unwrap_or_else(|_| PathBuf::from("/tmp"))
.join("llm")
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Role {
Router, Specialist, General, }
impl std::fmt::Display for Role {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.pad(match self {
Self::Router => "router",
Self::Specialist => "specialist",
Self::General => "general",
})
}
}
#[derive(Debug, Clone)]
pub struct ModelSpec {
pub name: &'static str,
pub hf_repo: &'static str,
pub ollama_tag: Option<&'static str>,
pub role: Role,
pub ram_mb: u32,
pub notes: &'static str,
}
pub const MANIFEST: &[ModelSpec] = &[
ModelSpec {
name: "qwen3-0.6b-abl",
hf_repo: "Qwen/Qwen3-0.6B",
ollama_tag: Some("qwen3:0.6b"),
role: Role::Router,
ram_mb: 350,
notes: "always on, classifies queries, 300+ tok/s target",
},
ModelSpec {
name: "qwen2.5-coder-1.5b-abl",
hf_repo: "Qwen/Qwen2.5-Coder-1.5B",
ollama_tag: Some("qwen2.5-coder:1.5b"),
role: Role::Specialist,
ram_mb: 1100,
notes: "code generation small, LlamaStyle attn_bias, 100+ tok/s target",
},
ModelSpec {
name: "qwen2.5-coder-14b-abl",
hf_repo: "Qwen/Qwen2.5-Coder-14B",
ollama_tag: Some("qwen2.5-coder:14b"),
role: Role::Specialist,
ram_mb: 9000,
notes: "code generation large, fused Q4_K matmul, 25+ tok/s target",
},
ModelSpec {
name: "gemma-4-31b",
hf_repo: "google/gemma-4-31B",
ollama_tag: None, role: Role::General,
ram_mb: 18000,
notes: "multimodal LlamaStyle+, 60 layers, 30+ tok/s target",
},
];
pub fn format_size(bytes: u64) -> String {
if bytes >= 1 << 30 {
format!("{:.1}G", bytes as f64 / (1u64 << 30) as f64)
} else if bytes >= 1 << 20 {
format!("{}M", bytes >> 20)
} else if bytes >= 1 << 10 {
format!("{}K", bytes >> 10)
} else {
format!("{}B", bytes)
}
}