use crate::infer::InferBackend;
use cuttlefish_core::spec::ModelRef;
use std::collections::BTreeMap;
use std::sync::Arc;
pub trait BackendFactory: Send + Sync {
fn provider(&self) -> &'static str;
fn describe(&self) -> &'static str;
fn build(&self, target: &str) -> anyhow::Result<Arc<dyn InferBackend>>;
}
#[derive(Default)]
pub struct Registry {
factories: BTreeMap<&'static str, Box<dyn BackendFactory>>,
}
impl Registry {
pub fn new() -> Self {
Self::default()
}
pub fn with_builtins() -> Self {
let mut registry = Self::new();
registry.register(Box::new(crate::infer::StubFactory));
registry.register(Box::new(crate::ollama::OllamaFactory));
#[cfg(feature = "llamacpp")]
registry.register(Box::new(crate::llamacpp::LlamaCppFactory));
registry
}
pub fn register(&mut self, factory: Box<dyn BackendFactory>) {
self.factories.insert(factory.provider(), factory);
}
pub fn providers(&self) -> Vec<&'static str> {
self.factories.keys().copied().collect()
}
pub fn resolve(&self, model: &ModelRef) -> anyhow::Result<Arc<dyn InferBackend>> {
let factory = self.factories.get(model.provider.as_str()).ok_or_else(|| {
let available = self
.factories
.values()
.map(|f| format!(" {} — {}", f.provider(), f.describe()))
.collect::<Vec<_>>()
.join("\n");
anyhow::anyhow!(
"unknown model provider `{}`. Available providers:\n{available}",
model.provider
)
})?;
factory.build(&model.target).map_err(|e| {
anyhow::anyhow!(
"provider `{}` could not serve `{}`: {e}",
model.provider,
model.target
)
})
}
}