paladin_llm/
provider_factory.rs1use std::sync::Arc;
8
9use paladin_ports::output::llm_port::LlmPort;
10use thiserror::Error;
11
12#[derive(Debug, Error)]
14pub enum ProviderFactoryError {
15 #[error("Unknown provider: {0}. Supported providers: openai, deepseek, anthropic")]
17 UnknownProvider(String),
18
19 #[error("Provider configuration missing: {0}")]
21 ConfigurationMissing(String),
22
23 #[error("Failed to create provider adapter: {0}")]
25 AdapterCreationFailed(String),
26}
27
28pub struct LlmProviderFactory;
45
46impl LlmProviderFactory {
47 pub fn new() -> Self {
49 Self
50 }
51
52 pub fn create(&self, provider_name: &str) -> Result<Arc<dyn LlmPort>, ProviderFactoryError> {
63 match provider_name.to_lowercase().as_str() {
64 #[cfg(feature = "openai")]
65 "openai" => {
66 use crate::openai::{OpenAIAdapter, OpenAIConfig};
67 let config = OpenAIConfig::from_env().map_err(|e| {
68 ProviderFactoryError::ConfigurationMissing(format!(
69 "OpenAI configuration error: {}. Ensure OPENAI_API_KEY is set.",
70 e
71 ))
72 })?;
73 let adapter = OpenAIAdapter::new(config).map_err(|e| {
74 ProviderFactoryError::AdapterCreationFailed(format!(
75 "Failed to create OpenAI adapter: {}",
76 e
77 ))
78 })?;
79 Ok(Arc::new(adapter))
80 }
81 #[cfg(feature = "deepseek")]
82 "deepseek" => {
83 use crate::deepseek::{DeepSeekAdapter, DeepSeekConfig};
84 let config = DeepSeekConfig::from_env().map_err(|e| {
85 ProviderFactoryError::ConfigurationMissing(format!(
86 "DeepSeek configuration error: {}. Ensure DEEPSEEK_API_KEY is set.",
87 e
88 ))
89 })?;
90 let adapter = DeepSeekAdapter::new(config).map_err(|e| {
91 ProviderFactoryError::AdapterCreationFailed(format!(
92 "Failed to create DeepSeek adapter: {}",
93 e
94 ))
95 })?;
96 Ok(Arc::new(adapter))
97 }
98 #[cfg(feature = "anthropic")]
99 "anthropic" => {
100 use crate::anthropic::{AnthropicAdapter, AnthropicConfig};
101 let config = AnthropicConfig::from_env().map_err(|e| {
102 ProviderFactoryError::ConfigurationMissing(format!(
103 "Anthropic configuration error: {}. Ensure ANTHROPIC_API_KEY is set.",
104 e
105 ))
106 })?;
107 let adapter = AnthropicAdapter::new(config).map_err(|e| {
108 ProviderFactoryError::AdapterCreationFailed(format!(
109 "Failed to create Anthropic adapter: {}",
110 e
111 ))
112 })?;
113 Ok(Arc::new(adapter))
114 }
115 other => Err(ProviderFactoryError::UnknownProvider(other.to_string())),
116 }
117 }
118
119 pub fn get_default_provider() -> Option<String> {
124 if std::env::var("OPENAI_API_KEY").is_ok() {
125 return Some("openai".to_string());
126 }
127 if std::env::var("DEEPSEEK_API_KEY").is_ok() {
128 return Some("deepseek".to_string());
129 }
130 if std::env::var("ANTHROPIC_API_KEY").is_ok() {
131 return Some("anthropic".to_string());
132 }
133 None
134 }
135
136 pub fn list_available_providers() -> Vec<String> {
138 let mut providers = Vec::new();
139 if std::env::var("OPENAI_API_KEY").is_ok() {
140 providers.push("openai".to_string());
141 }
142 if std::env::var("DEEPSEEK_API_KEY").is_ok() {
143 providers.push("deepseek".to_string());
144 }
145 if std::env::var("ANTHROPIC_API_KEY").is_ok() {
146 providers.push("anthropic".to_string());
147 }
148 providers
149 }
150}
151
152impl Default for LlmProviderFactory {
153 fn default() -> Self {
154 Self::new()
155 }
156}
157
158#[cfg(test)]
159mod tests {
160 use super::*;
161
162 #[test]
163 fn test_factory_creation() {
164 let factory = LlmProviderFactory::new();
165 assert_eq!(std::mem::size_of_val(&factory), 0);
166 }
167
168 #[test]
169 fn test_unknown_provider_returns_error() {
170 let factory = LlmProviderFactory::new();
171 let result = factory.create("bogus_provider");
172 assert!(result.is_err());
173 if let Err(ProviderFactoryError::UnknownProvider(name)) = result {
174 assert_eq!(name, "bogus_provider");
175 } else {
176 panic!("Expected UnknownProvider error");
177 }
178 }
179
180 #[test]
181 fn test_list_available_providers_returns_vec() {
182 let _ = LlmProviderFactory::list_available_providers();
184 }
185}