llm_stack_anthropic/
factory.rs1use llm_stack::registry::{ProviderConfig, ProviderFactory};
4use llm_stack::{DynProvider, LlmError};
5
6use crate::{AnthropicConfig, AnthropicProvider};
7
8#[derive(Debug, Clone, Copy, Default)]
32pub struct AnthropicFactory;
33
34impl ProviderFactory for AnthropicFactory {
35 fn name(&self) -> &'static str {
36 "anthropic"
37 }
38
39 fn build(&self, config: &ProviderConfig) -> Result<Box<dyn DynProvider>, LlmError> {
40 let api_key = config.api_key.clone().ok_or_else(|| {
41 LlmError::InvalidRequest("anthropic provider requires api_key".into())
42 })?;
43
44 if config.model.is_empty() {
45 return Err(LlmError::InvalidRequest(
46 "anthropic provider requires model".into(),
47 ));
48 }
49
50 let mut anthropic_config = AnthropicConfig {
51 api_key,
52 model: config.model.clone(),
53 client: config.client.clone(),
54 ..Default::default()
55 };
56
57 if let Some(base_url) = &config.base_url {
58 anthropic_config.base_url.clone_from(base_url);
59 }
60
61 if let Some(timeout) = config.timeout {
62 anthropic_config.timeout = Some(timeout);
63 }
64
65 if let Some(max_tokens) = config.get_extra_i64("max_tokens") {
66 anthropic_config.max_tokens =
67 u32::try_from(max_tokens).unwrap_or(anthropic_config.max_tokens);
68 }
69
70 if let Some(api_version) = config.get_extra_str("api_version") {
71 anthropic_config.api_version = api_version.to_string();
72 }
73
74 Ok(Box::new(AnthropicProvider::new(anthropic_config)))
75 }
76}
77
78pub fn register_global() {
83 llm_stack::ProviderRegistry::global().register(Box::new(AnthropicFactory));
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89 use std::time::Duration;
90
91 #[test]
92 fn test_factory_name() {
93 let factory = AnthropicFactory;
94 assert_eq!(factory.name(), "anthropic");
95 }
96
97 #[test]
98 fn test_factory_build_success() {
99 let factory = AnthropicFactory;
100 let config = ProviderConfig::new("anthropic", "claude-3")
101 .api_key("sk-test")
102 .timeout(Duration::from_secs(30))
103 .extra("max_tokens", 2048i64);
104
105 let provider = factory.build(&config).unwrap();
106 assert_eq!(provider.metadata().name, "anthropic");
107 assert_eq!(provider.metadata().model, "claude-3");
108 }
109
110 #[test]
111 fn test_factory_missing_api_key() {
112 let factory = AnthropicFactory;
113 let config = ProviderConfig::new("anthropic", "claude-3");
114
115 let err = factory.build(&config).err().unwrap();
116 assert!(matches!(err, LlmError::InvalidRequest(_)));
117 }
118
119 #[test]
120 fn test_factory_empty_model() {
121 let factory = AnthropicFactory;
122 let config = ProviderConfig::new("anthropic", "").api_key("sk-test");
123
124 let err = factory.build(&config).err().unwrap();
125 assert!(matches!(err, LlmError::InvalidRequest(_)));
126 }
127}