use super::anthropic::AnthropicProvider;
use super::gemini::GeminiProvider;
use super::openai::OpenAiProvider;
use super::traits::LlmProvider;
use crate::config::runtime::ProviderConfig;
use anyhow::Result;
use std::collections::HashMap;
use std::sync::Arc;
pub struct ProviderRegistry {
providers: HashMap<String, Arc<dyn LlmProvider>>,
}
impl ProviderRegistry {
pub fn new() -> Self {
Self {
providers: HashMap::new(),
}
}
pub fn register(&mut self, provider: Arc<dyn LlmProvider>) {
let name = provider.name().to_string();
tracing::info!("Registering LLM provider: {}", name);
self.providers.insert(name, provider);
}
pub fn get(&self, name: &str) -> Option<Arc<dyn LlmProvider>> {
self.providers.get(name).cloned()
}
pub fn list(&self) -> Vec<&str> {
self.providers.keys().map(|k| k.as_str()).collect()
}
pub fn from_configs(configs: &[ProviderConfig]) -> Result<Self> {
let mut registry = Self::new();
for config in configs {
let provider: Arc<dyn LlmProvider> = match config.provider_type.as_ref() {
"openai" | "ollama" => {
let api_key = config.api_key.clone().unwrap_or_else(|| {
Arc::from(std::env::var("OPENAI_API_KEY").unwrap_or_default().as_str())
});
Arc::new(OpenAiProvider::new(
config.name.clone(),
api_key,
config.base_url.clone(),
))
}
"anthropic" => {
let api_key = config.api_key.clone().unwrap_or_else(|| {
Arc::from(
std::env::var("ANTHROPIC_API_KEY")
.unwrap_or_default()
.as_str(),
)
});
Arc::new(AnthropicProvider::new(
config.name.clone(),
api_key,
config.base_url.clone(),
))
}
"gemini" => {
let api_key = config.api_key.clone().unwrap_or_else(|| {
Arc::from(std::env::var("GEMINI_API_KEY").unwrap_or_default().as_str())
});
Arc::new(GeminiProvider::new(
config.name.clone(),
api_key,
config.base_url.clone(),
))
}
other => anyhow::bail!("Unknown provider type: {}", other),
};
registry.register(provider);
}
Ok(registry)
}
}
impl Default for ProviderRegistry {
fn default() -> Self {
Self::new()
}
}