use std::sync::Arc;
use paladin_ports::output::llm_port::LlmPort;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum ProviderFactoryError {
#[error("Unknown provider: {0}. Supported providers: openai, deepseek, anthropic")]
UnknownProvider(String),
#[error("Provider configuration missing: {0}")]
ConfigurationMissing(String),
#[error("Failed to create provider adapter: {0}")]
AdapterCreationFailed(String),
}
pub struct LlmProviderFactory;
impl LlmProviderFactory {
pub fn new() -> Self {
Self
}
pub fn create(&self, provider_name: &str) -> Result<Arc<dyn LlmPort>, ProviderFactoryError> {
match provider_name.to_lowercase().as_str() {
#[cfg(feature = "openai")]
"openai" => {
use crate::openai::{OpenAIAdapter, OpenAIConfig};
let config = OpenAIConfig::from_env().map_err(|e| {
ProviderFactoryError::ConfigurationMissing(format!(
"OpenAI configuration error: {}. Ensure OPENAI_API_KEY is set.",
e
))
})?;
let adapter = OpenAIAdapter::new(config).map_err(|e| {
ProviderFactoryError::AdapterCreationFailed(format!(
"Failed to create OpenAI adapter: {}",
e
))
})?;
Ok(Arc::new(adapter))
}
#[cfg(feature = "deepseek")]
"deepseek" => {
use crate::deepseek::{DeepSeekAdapter, DeepSeekConfig};
let config = DeepSeekConfig::from_env().map_err(|e| {
ProviderFactoryError::ConfigurationMissing(format!(
"DeepSeek configuration error: {}. Ensure DEEPSEEK_API_KEY is set.",
e
))
})?;
let adapter = DeepSeekAdapter::new(config).map_err(|e| {
ProviderFactoryError::AdapterCreationFailed(format!(
"Failed to create DeepSeek adapter: {}",
e
))
})?;
Ok(Arc::new(adapter))
}
#[cfg(feature = "anthropic")]
"anthropic" => {
use crate::anthropic::{AnthropicAdapter, AnthropicConfig};
let config = AnthropicConfig::from_env().map_err(|e| {
ProviderFactoryError::ConfigurationMissing(format!(
"Anthropic configuration error: {}. Ensure ANTHROPIC_API_KEY is set.",
e
))
})?;
let adapter = AnthropicAdapter::new(config).map_err(|e| {
ProviderFactoryError::AdapterCreationFailed(format!(
"Failed to create Anthropic adapter: {}",
e
))
})?;
Ok(Arc::new(adapter))
}
other => Err(ProviderFactoryError::UnknownProvider(other.to_string())),
}
}
pub fn get_default_provider() -> Option<String> {
if std::env::var("OPENAI_API_KEY").is_ok() {
return Some("openai".to_string());
}
if std::env::var("DEEPSEEK_API_KEY").is_ok() {
return Some("deepseek".to_string());
}
if std::env::var("ANTHROPIC_API_KEY").is_ok() {
return Some("anthropic".to_string());
}
None
}
pub fn list_available_providers() -> Vec<String> {
let mut providers = Vec::new();
if std::env::var("OPENAI_API_KEY").is_ok() {
providers.push("openai".to_string());
}
if std::env::var("DEEPSEEK_API_KEY").is_ok() {
providers.push("deepseek".to_string());
}
if std::env::var("ANTHROPIC_API_KEY").is_ok() {
providers.push("anthropic".to_string());
}
providers
}
}
impl Default for LlmProviderFactory {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_factory_creation() {
let factory = LlmProviderFactory::new();
assert_eq!(std::mem::size_of_val(&factory), 0);
}
#[test]
fn test_unknown_provider_returns_error() {
let factory = LlmProviderFactory::new();
let result = factory.create("bogus_provider");
assert!(result.is_err());
if let Err(ProviderFactoryError::UnknownProvider(name)) = result {
assert_eq!(name, "bogus_provider");
} else {
panic!("Expected UnknownProvider error");
}
}
#[test]
fn test_list_available_providers_returns_vec() {
let _ = LlmProviderFactory::list_available_providers();
}
}