1use std::collections::HashMap;
6use std::pin::Pin;
7use std::sync::Arc;
8
9use async_trait::async_trait;
10use futures::Stream;
11use tokio::time::sleep;
12
13use crate::audio::{
14 SpeechProvider, SpeechRequest, SpeechResponse, TranscriptionProvider, TranscriptionRequest,
15 TranscriptionResponse,
16};
17use crate::embedding::{EmbeddingProvider, EmbeddingRequest, EmbeddingResponse};
18use crate::error::{Error, Result};
19use crate::image::{ImageGenerationRequest, ImageGenerationResponse, ImageProvider};
20use crate::provider::{Provider, ProviderConfig};
21use crate::retry::RetryConfig;
22use crate::specialized::{
23 ClassificationProvider, ClassificationRequest, ClassificationResponse, ModerationProvider,
24 ModerationRequest, ModerationResponse, RankingProvider, RankingRequest, RankingResponse,
25};
26use crate::types::{
27 BatchJob, BatchRequest, BatchResult, CompletionRequest, CompletionResponse, StreamChunk,
28 TokenCountRequest, TokenCountResult,
29};
30use crate::video::{
31 VideoGenerationRequest, VideoGenerationResponse, VideoJobStatus, VideoProvider,
32};
33
34struct DynamicRetryingProvider {
39 inner: Arc<dyn Provider>,
40 config: RetryConfig,
41}
42
43impl DynamicRetryingProvider {
44 async fn execute_with_retry<T, F, Fut>(&self, operation_name: &str, mut f: F) -> Result<T>
46 where
47 F: FnMut() -> Fut,
48 Fut: std::future::Future<Output = Result<T>>,
49 {
50 let mut last_error: Option<Error> = None;
51
52 for attempt in 0..=self.config.max_retries {
53 match f().await {
54 Ok(result) => {
55 if attempt > 0 {
56 tracing::info!(
57 provider = %self.inner.name(),
58 operation = %operation_name,
59 attempt = attempt + 1,
60 "Operation succeeded after retry"
61 );
62 }
63 return Ok(result);
64 }
65 Err(e) => {
66 if !e.is_retryable() {
67 tracing::debug!(
68 provider = %self.inner.name(),
69 operation = %operation_name,
70 error = %e,
71 "Non-retryable error, failing immediately"
72 );
73 return Err(e);
74 }
75
76 if attempt < self.config.max_retries {
77 let delay = e
79 .retry_after()
80 .unwrap_or_else(|| self.config.delay_for_attempt(attempt));
81
82 tracing::warn!(
83 provider = %self.inner.name(),
84 operation = %operation_name,
85 attempt = attempt + 1,
86 max_retries = self.config.max_retries,
87 delay_ms = delay.as_millis(),
88 error = %e,
89 "Retryable error, will retry after delay"
90 );
91
92 sleep(delay).await;
93 }
94
95 last_error = Some(e);
96 }
97 }
98 }
99
100 tracing::error!(
101 provider = %self.inner.name(),
102 operation = %operation_name,
103 max_retries = self.config.max_retries,
104 "All retry attempts exhausted"
105 );
106
107 Err(last_error.unwrap_or_else(|| Error::other("Unknown retry failure")))
108 }
109}
110
111#[async_trait]
112impl Provider for DynamicRetryingProvider {
113 fn name(&self) -> &str {
114 self.inner.name()
115 }
116
117 async fn complete(&self, request: CompletionRequest) -> Result<CompletionResponse> {
118 let request = Arc::new(request);
119 self.execute_with_retry("complete", || {
120 let request = (*request).clone();
121 let inner = Arc::clone(&self.inner);
122 async move { inner.complete(request).await }
123 })
124 .await
125 }
126
127 async fn complete_stream(
128 &self,
129 request: CompletionRequest,
130 ) -> Result<Pin<Box<dyn Stream<Item = Result<StreamChunk>> + Send>>> {
131 let request = Arc::new(request);
132 self.execute_with_retry("complete_stream", || {
133 let request = (*request).clone();
134 let inner = Arc::clone(&self.inner);
135 async move { inner.complete_stream(request).await }
136 })
137 .await
138 }
139
140 fn supports_tools(&self) -> bool {
141 self.inner.supports_tools()
142 }
143
144 fn supports_vision(&self) -> bool {
145 self.inner.supports_vision()
146 }
147
148 fn supports_streaming(&self) -> bool {
149 self.inner.supports_streaming()
150 }
151
152 async fn count_tokens(&self, request: TokenCountRequest) -> Result<TokenCountResult> {
153 let request = Arc::new(request);
154 self.execute_with_retry("count_tokens", || {
155 let request = (*request).clone();
156 let inner = Arc::clone(&self.inner);
157 async move { inner.count_tokens(request).await }
158 })
159 .await
160 }
161
162 fn supports_token_counting(&self) -> bool {
163 self.inner.supports_token_counting()
164 }
165
166 async fn create_batch(&self, requests: Vec<BatchRequest>) -> Result<BatchJob> {
167 self.inner.create_batch(requests).await
168 }
169
170 async fn get_batch(&self, batch_id: &str) -> Result<BatchJob> {
171 self.inner.get_batch(batch_id).await
172 }
173
174 async fn get_batch_results(&self, batch_id: &str) -> Result<Vec<BatchResult>> {
175 self.inner.get_batch_results(batch_id).await
176 }
177
178 async fn cancel_batch(&self, batch_id: &str) -> Result<BatchJob> {
179 self.inner.cancel_batch(batch_id).await
180 }
181
182 async fn list_batches(&self, limit: Option<u32>) -> Result<Vec<BatchJob>> {
183 self.inner.list_batches(limit).await
184 }
185
186 fn supports_batch(&self) -> bool {
187 self.inner.supports_batch()
188 }
189}
190
191fn parse_model_identifier(model: &str) -> Result<(&str, &str)> {
208 if let Some(idx) = model.find('/') {
209 let provider = &model[..idx];
210 let model_name = &model[idx + 1..];
211 if !provider.is_empty()
213 && !provider.contains('-')
214 && !provider.contains('.')
215 && !provider.contains(':')
216 {
217 return Ok((provider, model_name));
218 }
219 }
220 Err(Error::InvalidRequest(format!(
221 "Model must be in 'provider/model' format (e.g., 'openai/gpt-4o'), got: {}",
222 model
223 )))
224}
225
226pub struct LLMKitClient {
257 providers: HashMap<String, Arc<dyn Provider>>,
258 embedding_providers: HashMap<String, Arc<dyn EmbeddingProvider>>,
259 speech_providers: HashMap<String, Arc<dyn SpeechProvider>>,
260 transcription_providers: HashMap<String, Arc<dyn TranscriptionProvider>>,
261 image_providers: HashMap<String, Arc<dyn ImageProvider>>,
262 video_providers: HashMap<String, Arc<dyn VideoProvider>>,
263 ranking_providers: HashMap<String, Arc<dyn RankingProvider>>,
264 moderation_providers: HashMap<String, Arc<dyn ModerationProvider>>,
265 classification_providers: HashMap<String, Arc<dyn ClassificationProvider>>,
266 default_provider: Option<String>,
267}
268
269impl LLMKitClient {
270 pub fn builder() -> ClientBuilder {
272 ClientBuilder::new()
273 }
274
275 pub fn provider(&self, name: &str) -> Option<Arc<dyn Provider>> {
277 self.providers.get(name).cloned()
278 }
279
280 pub fn default_provider(&self) -> Option<Arc<dyn Provider>> {
282 self.default_provider
283 .as_ref()
284 .and_then(|name| self.providers.get(name).cloned())
285 }
286
287 pub fn providers(&self) -> Vec<&str> {
289 self.providers.keys().map(|s| s.as_str()).collect()
290 }
291
292 pub async fn complete(&self, mut request: CompletionRequest) -> Result<CompletionResponse> {
299 let (provider, model_name) = self.resolve_provider(&request.model)?;
300 request.model = model_name;
301 provider.complete(request).await
302 }
303
304 pub async fn complete_stream(
308 &self,
309 mut request: CompletionRequest,
310 ) -> Result<Pin<Box<dyn Stream<Item = Result<StreamChunk>> + Send>>> {
311 let (provider, model_name) = self.resolve_provider(&request.model)?;
312 request.model = model_name;
313 provider.complete_stream(request).await
314 }
315
316 pub async fn complete_with_provider(
318 &self,
319 provider_name: &str,
320 request: CompletionRequest,
321 ) -> Result<CompletionResponse> {
322 let provider = self
323 .providers
324 .get(provider_name)
325 .ok_or_else(|| Error::ProviderNotFound(provider_name.to_string()))?;
326 provider.complete(request).await
327 }
328
329 pub async fn complete_stream_with_provider(
331 &self,
332 provider_name: &str,
333 request: CompletionRequest,
334 ) -> Result<Pin<Box<dyn Stream<Item = Result<StreamChunk>> + Send>>> {
335 let provider = self
336 .providers
337 .get(provider_name)
338 .ok_or_else(|| Error::ProviderNotFound(provider_name.to_string()))?;
339 provider.complete_stream(request).await
340 }
341
342 pub async fn count_tokens(&self, mut request: TokenCountRequest) -> Result<TokenCountResult> {
352 let (provider, model_name) = self.resolve_provider(&request.model)?;
353 request.model = model_name;
354 provider.count_tokens(request).await
355 }
356
357 pub async fn count_tokens_with_provider(
359 &self,
360 provider_name: &str,
361 request: TokenCountRequest,
362 ) -> Result<TokenCountResult> {
363 let provider = self
364 .providers
365 .get(provider_name)
366 .ok_or_else(|| Error::ProviderNotFound(provider_name.to_string()))?;
367 provider.count_tokens(request).await
368 }
369
370 pub async fn create_batch(&self, mut requests: Vec<BatchRequest>) -> Result<BatchJob> {
380 if requests.is_empty() {
381 return Err(Error::invalid_request(
382 "Batch must contain at least one request",
383 ));
384 }
385 let (provider, model_name) = self.resolve_provider(&requests[0].request.model)?;
386 for req in &mut requests {
388 let (_, req_model) = parse_model_identifier(&req.request.model)?;
389 req.request.model = req_model.to_string();
390 }
391 requests[0].request.model = model_name;
393 provider.create_batch(requests).await
394 }
395
396 pub async fn create_batch_with_provider(
398 &self,
399 provider_name: &str,
400 requests: Vec<BatchRequest>,
401 ) -> Result<BatchJob> {
402 let provider = self
403 .providers
404 .get(provider_name)
405 .ok_or_else(|| Error::ProviderNotFound(provider_name.to_string()))?;
406 provider.create_batch(requests).await
407 }
408
409 pub async fn get_batch(&self, provider_name: &str, batch_id: &str) -> Result<BatchJob> {
411 let provider = self
412 .providers
413 .get(provider_name)
414 .ok_or_else(|| Error::ProviderNotFound(provider_name.to_string()))?;
415 provider.get_batch(batch_id).await
416 }
417
418 pub async fn get_batch_results(
420 &self,
421 provider_name: &str,
422 batch_id: &str,
423 ) -> Result<Vec<BatchResult>> {
424 let provider = self
425 .providers
426 .get(provider_name)
427 .ok_or_else(|| Error::ProviderNotFound(provider_name.to_string()))?;
428 provider.get_batch_results(batch_id).await
429 }
430
431 pub async fn cancel_batch(&self, provider_name: &str, batch_id: &str) -> Result<BatchJob> {
433 let provider = self
434 .providers
435 .get(provider_name)
436 .ok_or_else(|| Error::ProviderNotFound(provider_name.to_string()))?;
437 provider.cancel_batch(batch_id).await
438 }
439
440 pub async fn list_batches(
442 &self,
443 provider_name: &str,
444 limit: Option<u32>,
445 ) -> Result<Vec<BatchJob>> {
446 let provider = self
447 .providers
448 .get(provider_name)
449 .ok_or_else(|| Error::ProviderNotFound(provider_name.to_string()))?;
450 provider.list_batches(limit).await
451 }
452
453 pub async fn embed(&self, mut request: EmbeddingRequest) -> Result<EmbeddingResponse> {
481 let (provider, model_name) = self.resolve_embedding_provider(&request.model)?;
482 request.model = model_name;
483 provider.embed(request).await
484 }
485
486 pub async fn embed_with_provider(
488 &self,
489 provider_name: &str,
490 request: EmbeddingRequest,
491 ) -> Result<EmbeddingResponse> {
492 let provider = self
493 .embedding_providers
494 .get(provider_name)
495 .ok_or_else(|| Error::ProviderNotFound(provider_name.to_string()))?;
496 provider.embed(request).await
497 }
498
499 pub fn embedding_providers(&self) -> Vec<&str> {
501 self.embedding_providers
502 .keys()
503 .map(|s| s.as_str())
504 .collect()
505 }
506
507 pub fn supports_embeddings(&self, provider_name: &str) -> bool {
509 self.embedding_providers.contains_key(provider_name)
510 }
511
512 pub async fn speech(&self, mut request: SpeechRequest) -> Result<SpeechResponse> {
532 let (provider, model_name) = self.resolve_speech_provider(&request.model)?;
533 request.model = model_name;
534 provider.speech(request).await
535 }
536
537 pub async fn speech_with_provider(
539 &self,
540 provider_name: &str,
541 request: SpeechRequest,
542 ) -> Result<SpeechResponse> {
543 let provider = self
544 .speech_providers
545 .get(provider_name)
546 .ok_or_else(|| Error::ProviderNotFound(provider_name.to_string()))?;
547 provider.speech(request).await
548 }
549
550 pub fn speech_providers(&self) -> Vec<&str> {
552 self.speech_providers.keys().map(|s| s.as_str()).collect()
553 }
554
555 pub async fn transcribe(
578 &self,
579 mut request: TranscriptionRequest,
580 ) -> Result<TranscriptionResponse> {
581 let (provider, model_name) = self.resolve_transcription_provider(&request.model)?;
582 request.model = model_name;
583 provider.transcribe(request).await
584 }
585
586 pub async fn transcribe_with_provider(
588 &self,
589 provider_name: &str,
590 request: TranscriptionRequest,
591 ) -> Result<TranscriptionResponse> {
592 let provider = self
593 .transcription_providers
594 .get(provider_name)
595 .ok_or_else(|| Error::ProviderNotFound(provider_name.to_string()))?;
596 provider.transcribe(request).await
597 }
598
599 pub fn transcription_providers(&self) -> Vec<&str> {
601 self.transcription_providers
602 .keys()
603 .map(|s| s.as_str())
604 .collect()
605 }
606
607 pub async fn generate_image(
630 &self,
631 mut request: ImageGenerationRequest,
632 ) -> Result<ImageGenerationResponse> {
633 let (provider, model_name) = self.resolve_image_provider(&request.model)?;
634 request.model = model_name;
635 provider.generate_image(request).await
636 }
637
638 pub async fn generate_image_with_provider(
640 &self,
641 provider_name: &str,
642 request: ImageGenerationRequest,
643 ) -> Result<ImageGenerationResponse> {
644 let provider = self
645 .image_providers
646 .get(provider_name)
647 .ok_or_else(|| Error::ProviderNotFound(provider_name.to_string()))?;
648 provider.generate_image(request).await
649 }
650
651 pub fn image_providers(&self) -> Vec<&str> {
653 self.image_providers.keys().map(|s| s.as_str()).collect()
654 }
655
656 pub async fn generate_video(
680 &self,
681 mut request: VideoGenerationRequest,
682 ) -> Result<VideoGenerationResponse> {
683 let (provider, model_name) = self.resolve_video_provider(&request.model)?;
684 request.model = model_name;
685 provider.generate_video(request).await
686 }
687
688 pub async fn generate_video_with_provider(
690 &self,
691 provider_name: &str,
692 request: VideoGenerationRequest,
693 ) -> Result<VideoGenerationResponse> {
694 let provider = self
695 .video_providers
696 .get(provider_name)
697 .ok_or_else(|| Error::ProviderNotFound(provider_name.to_string()))?;
698 provider.generate_video(request).await
699 }
700
701 pub async fn get_video_status(
703 &self,
704 provider_name: &str,
705 job_id: &str,
706 ) -> Result<VideoJobStatus> {
707 let provider = self
708 .video_providers
709 .get(provider_name)
710 .ok_or_else(|| Error::ProviderNotFound(provider_name.to_string()))?;
711 provider.get_video_status(job_id).await
712 }
713
714 pub fn video_providers(&self) -> Vec<&str> {
716 self.video_providers.keys().map(|s| s.as_str()).collect()
717 }
718
719 pub async fn rank(&self, mut request: RankingRequest) -> Result<RankingResponse> {
741 let (provider, model_name) = self.resolve_ranking_provider(&request.model)?;
742 request.model = model_name;
743 provider.rank(request).await
744 }
745
746 pub async fn rank_with_provider(
748 &self,
749 provider_name: &str,
750 request: RankingRequest,
751 ) -> Result<RankingResponse> {
752 let provider = self
753 .ranking_providers
754 .get(provider_name)
755 .ok_or_else(|| Error::ProviderNotFound(provider_name.to_string()))?;
756 provider.rank(request).await
757 }
758
759 pub fn ranking_providers(&self) -> Vec<&str> {
761 self.ranking_providers.keys().map(|s| s.as_str()).collect()
762 }
763
764 pub async fn moderate(&self, mut request: ModerationRequest) -> Result<ModerationResponse> {
787 let (provider, model_name) = self.resolve_moderation_provider(&request.model)?;
788 request.model = model_name;
789 provider.moderate(request).await
790 }
791
792 pub async fn moderate_with_provider(
794 &self,
795 provider_name: &str,
796 request: ModerationRequest,
797 ) -> Result<ModerationResponse> {
798 let provider = self
799 .moderation_providers
800 .get(provider_name)
801 .ok_or_else(|| Error::ProviderNotFound(provider_name.to_string()))?;
802 provider.moderate(request).await
803 }
804
805 pub fn moderation_providers(&self) -> Vec<&str> {
807 self.moderation_providers
808 .keys()
809 .map(|s| s.as_str())
810 .collect()
811 }
812
813 pub async fn classify(
835 &self,
836 mut request: ClassificationRequest,
837 ) -> Result<ClassificationResponse> {
838 let (provider, model_name) = self.resolve_classification_provider(&request.model)?;
839 request.model = model_name;
840 provider.classify(request).await
841 }
842
843 pub async fn classify_with_provider(
845 &self,
846 provider_name: &str,
847 request: ClassificationRequest,
848 ) -> Result<ClassificationResponse> {
849 let provider = self
850 .classification_providers
851 .get(provider_name)
852 .ok_or_else(|| Error::ProviderNotFound(provider_name.to_string()))?;
853 provider.classify(request).await
854 }
855
856 pub fn classification_providers(&self) -> Vec<&str> {
858 self.classification_providers
859 .keys()
860 .map(|s| s.as_str())
861 .collect()
862 }
863
864 fn resolve_embedding_provider(
869 &self,
870 model: &str,
871 ) -> Result<(Arc<dyn EmbeddingProvider>, String)> {
872 let (provider_name, model_name) = parse_model_identifier(model)?;
873
874 self.embedding_providers
875 .get(provider_name)
876 .cloned()
877 .map(|p| (p, model_name.to_string()))
878 .ok_or_else(|| {
879 Error::ProviderNotFound(format!(
880 "Embedding provider '{}' not configured. Available providers: {:?}",
881 provider_name,
882 self.embedding_providers.keys().collect::<Vec<_>>()
883 ))
884 })
885 }
886
887 fn resolve_provider(&self, model: &str) -> Result<(Arc<dyn Provider>, String)> {
892 let (provider_name, model_name) = parse_model_identifier(model)?;
893
894 self.providers
895 .get(provider_name)
896 .cloned()
897 .map(|p| (p, model_name.to_string()))
898 .ok_or_else(|| {
899 Error::ProviderNotFound(format!(
900 "Provider '{}' not configured. Available providers: {:?}",
901 provider_name,
902 self.providers.keys().collect::<Vec<_>>()
903 ))
904 })
905 }
906
907 fn resolve_speech_provider(&self, model: &str) -> Result<(Arc<dyn SpeechProvider>, String)> {
909 let (provider_name, model_name) = parse_model_identifier(model)?;
910
911 self.speech_providers
912 .get(provider_name)
913 .cloned()
914 .map(|p| (p, model_name.to_string()))
915 .ok_or_else(|| {
916 Error::ProviderNotFound(format!(
917 "Speech provider '{}' not configured. Available providers: {:?}",
918 provider_name,
919 self.speech_providers.keys().collect::<Vec<_>>()
920 ))
921 })
922 }
923
924 fn resolve_transcription_provider(
926 &self,
927 model: &str,
928 ) -> Result<(Arc<dyn TranscriptionProvider>, String)> {
929 let (provider_name, model_name) = parse_model_identifier(model)?;
930
931 self.transcription_providers
932 .get(provider_name)
933 .cloned()
934 .map(|p| (p, model_name.to_string()))
935 .ok_or_else(|| {
936 Error::ProviderNotFound(format!(
937 "Transcription provider '{}' not configured. Available providers: {:?}",
938 provider_name,
939 self.transcription_providers.keys().collect::<Vec<_>>()
940 ))
941 })
942 }
943
944 fn resolve_image_provider(&self, model: &str) -> Result<(Arc<dyn ImageProvider>, String)> {
946 let (provider_name, model_name) = parse_model_identifier(model)?;
947
948 self.image_providers
949 .get(provider_name)
950 .cloned()
951 .map(|p| (p, model_name.to_string()))
952 .ok_or_else(|| {
953 Error::ProviderNotFound(format!(
954 "Image provider '{}' not configured. Available providers: {:?}",
955 provider_name,
956 self.image_providers.keys().collect::<Vec<_>>()
957 ))
958 })
959 }
960
961 fn resolve_video_provider(&self, model: &str) -> Result<(Arc<dyn VideoProvider>, String)> {
963 let (provider_name, model_name) = parse_model_identifier(model)?;
964
965 self.video_providers
966 .get(provider_name)
967 .cloned()
968 .map(|p| (p, model_name.to_string()))
969 .ok_or_else(|| {
970 Error::ProviderNotFound(format!(
971 "Video provider '{}' not configured. Available providers: {:?}",
972 provider_name,
973 self.video_providers.keys().collect::<Vec<_>>()
974 ))
975 })
976 }
977
978 fn resolve_ranking_provider(&self, model: &str) -> Result<(Arc<dyn RankingProvider>, String)> {
980 let (provider_name, model_name) = parse_model_identifier(model)?;
981
982 self.ranking_providers
983 .get(provider_name)
984 .cloned()
985 .map(|p| (p, model_name.to_string()))
986 .ok_or_else(|| {
987 Error::ProviderNotFound(format!(
988 "Ranking provider '{}' not configured. Available providers: {:?}",
989 provider_name,
990 self.ranking_providers.keys().collect::<Vec<_>>()
991 ))
992 })
993 }
994
995 fn resolve_moderation_provider(
997 &self,
998 model: &str,
999 ) -> Result<(Arc<dyn ModerationProvider>, String)> {
1000 let (provider_name, model_name) = parse_model_identifier(model)?;
1001
1002 self.moderation_providers
1003 .get(provider_name)
1004 .cloned()
1005 .map(|p| (p, model_name.to_string()))
1006 .ok_or_else(|| {
1007 Error::ProviderNotFound(format!(
1008 "Moderation provider '{}' not configured. Available providers: {:?}",
1009 provider_name,
1010 self.moderation_providers.keys().collect::<Vec<_>>()
1011 ))
1012 })
1013 }
1014
1015 fn resolve_classification_provider(
1017 &self,
1018 model: &str,
1019 ) -> Result<(Arc<dyn ClassificationProvider>, String)> {
1020 let (provider_name, model_name) = parse_model_identifier(model)?;
1021
1022 self.classification_providers
1023 .get(provider_name)
1024 .cloned()
1025 .map(|p| (p, model_name.to_string()))
1026 .ok_or_else(|| {
1027 Error::ProviderNotFound(format!(
1028 "Classification provider '{}' not configured. Available providers: {:?}",
1029 provider_name,
1030 self.classification_providers.keys().collect::<Vec<_>>()
1031 ))
1032 })
1033 }
1034}
1035
1036#[cfg(feature = "vertex")]
1043#[derive(Clone)]
1044enum PendingVertexConfig {
1045 FromEnv,
1047 ServiceAccount {
1049 path: std::path::PathBuf,
1050 project_id: String,
1051 location: String,
1052 },
1053 WithPublisher { publisher: String },
1055}
1056
1057#[cfg(feature = "bedrock")]
1060#[derive(Clone)]
1061enum PendingBedrockConfig {
1062 FromEnv,
1064 WithRegion { region: String },
1066}
1067
1068pub struct ClientBuilder {
1070 providers: HashMap<String, Arc<dyn Provider>>,
1071 embedding_providers: HashMap<String, Arc<dyn EmbeddingProvider>>,
1072 speech_providers: HashMap<String, Arc<dyn SpeechProvider>>,
1073 transcription_providers: HashMap<String, Arc<dyn TranscriptionProvider>>,
1074 image_providers: HashMap<String, Arc<dyn ImageProvider>>,
1075 video_providers: HashMap<String, Arc<dyn VideoProvider>>,
1076 ranking_providers: HashMap<String, Arc<dyn RankingProvider>>,
1077 moderation_providers: HashMap<String, Arc<dyn ModerationProvider>>,
1078 classification_providers: HashMap<String, Arc<dyn ClassificationProvider>>,
1079 default_provider: Option<String>,
1080 retry_config: Option<RetryConfig>,
1081
1082 #[cfg(feature = "vertex")]
1084 pending_vertex: Vec<(String, PendingVertexConfig)>,
1085 #[cfg(feature = "bedrock")]
1086 pending_bedrock: Vec<(String, PendingBedrockConfig)>,
1087}
1088
1089impl ClientBuilder {
1090 pub fn new() -> Self {
1092 Self {
1093 providers: HashMap::new(),
1094 embedding_providers: HashMap::new(),
1095 speech_providers: HashMap::new(),
1096 transcription_providers: HashMap::new(),
1097 image_providers: HashMap::new(),
1098 video_providers: HashMap::new(),
1099 ranking_providers: HashMap::new(),
1100 moderation_providers: HashMap::new(),
1101 classification_providers: HashMap::new(),
1102 default_provider: None,
1103 retry_config: None,
1104 #[cfg(feature = "vertex")]
1105 pending_vertex: Vec::new(),
1106 #[cfg(feature = "bedrock")]
1107 pending_bedrock: Vec::new(),
1108 }
1109 }
1110
1111 pub fn with_embedding_provider(
1113 mut self,
1114 name: impl Into<String>,
1115 provider: Arc<dyn EmbeddingProvider>,
1116 ) -> Self {
1117 self.embedding_providers.insert(name.into(), provider);
1118 self
1119 }
1120
1121 pub fn with_speech_provider(
1123 mut self,
1124 name: impl Into<String>,
1125 provider: Arc<dyn SpeechProvider>,
1126 ) -> Self {
1127 self.speech_providers.insert(name.into(), provider);
1128 self
1129 }
1130
1131 pub fn with_transcription_provider(
1133 mut self,
1134 name: impl Into<String>,
1135 provider: Arc<dyn TranscriptionProvider>,
1136 ) -> Self {
1137 self.transcription_providers.insert(name.into(), provider);
1138 self
1139 }
1140
1141 pub fn with_image_provider(
1143 mut self,
1144 name: impl Into<String>,
1145 provider: Arc<dyn ImageProvider>,
1146 ) -> Self {
1147 self.image_providers.insert(name.into(), provider);
1148 self
1149 }
1150
1151 pub fn with_video_provider(
1153 mut self,
1154 name: impl Into<String>,
1155 provider: Arc<dyn VideoProvider>,
1156 ) -> Self {
1157 self.video_providers.insert(name.into(), provider);
1158 self
1159 }
1160
1161 pub fn with_ranking_provider(
1163 mut self,
1164 name: impl Into<String>,
1165 provider: Arc<dyn RankingProvider>,
1166 ) -> Self {
1167 self.ranking_providers.insert(name.into(), provider);
1168 self
1169 }
1170
1171 pub fn with_moderation_provider(
1173 mut self,
1174 name: impl Into<String>,
1175 provider: Arc<dyn ModerationProvider>,
1176 ) -> Self {
1177 self.moderation_providers.insert(name.into(), provider);
1178 self
1179 }
1180
1181 pub fn with_classification_provider(
1183 mut self,
1184 name: impl Into<String>,
1185 provider: Arc<dyn ClassificationProvider>,
1186 ) -> Self {
1187 self.classification_providers.insert(name.into(), provider);
1188 self
1189 }
1190
1191 pub fn with_retry(mut self, config: RetryConfig) -> Self {
1204 self.retry_config = Some(config);
1205 self
1206 }
1207
1208 pub fn with_default_retry(mut self) -> Self {
1215 self.retry_config = Some(RetryConfig::default());
1216 self
1217 }
1218
1219 pub fn with_provider(mut self, name: impl Into<String>, provider: Arc<dyn Provider>) -> Self {
1221 let name = name.into();
1222 if self.default_provider.is_none() {
1223 self.default_provider = Some(name.clone());
1224 }
1225 self.providers.insert(name, provider);
1226 self
1227 }
1228
1229 pub fn with_default(mut self, name: impl Into<String>) -> Self {
1231 self.default_provider = Some(name.into());
1232 self
1233 }
1234
1235 #[cfg(feature = "anthropic")]
1237 pub fn with_anthropic_from_env(self) -> Self {
1238 match crate::providers::chat::anthropic::AnthropicProvider::from_env() {
1239 Ok(provider) => self.with_provider("anthropic", Arc::new(provider)),
1240 Err(_) => self, }
1242 }
1243
1244 #[cfg(feature = "anthropic")]
1246 pub fn with_anthropic(self, api_key: impl Into<String>) -> Result<Self> {
1247 let provider = crate::providers::chat::anthropic::AnthropicProvider::with_api_key(api_key)?;
1248 Ok(self.with_provider("anthropic", Arc::new(provider)))
1249 }
1250
1251 #[cfg(feature = "anthropic")]
1253 pub fn with_anthropic_config(self, config: ProviderConfig) -> Result<Self> {
1254 let provider = crate::providers::chat::anthropic::AnthropicProvider::new(config)?;
1255 Ok(self.with_provider("anthropic", Arc::new(provider)))
1256 }
1257
1258 #[cfg(feature = "openai")]
1262 pub fn with_openai_from_env(mut self) -> Self {
1263 match crate::providers::chat::openai::OpenAIProvider::from_env() {
1264 Ok(provider) => {
1265 let provider = Arc::new(provider);
1266 self.embedding_providers.insert(
1267 "openai".to_string(),
1268 Arc::clone(&provider) as Arc<dyn EmbeddingProvider>,
1269 );
1270 self.with_provider("openai", provider)
1271 }
1272 Err(_) => self, }
1274 }
1275
1276 #[cfg(feature = "openai")]
1280 pub fn with_openai(mut self, api_key: impl Into<String>) -> Result<Self> {
1281 let provider =
1282 Arc::new(crate::providers::chat::openai::OpenAIProvider::with_api_key(api_key)?);
1283 self.embedding_providers.insert(
1284 "openai".to_string(),
1285 Arc::clone(&provider) as Arc<dyn EmbeddingProvider>,
1286 );
1287 Ok(self.with_provider("openai", provider))
1288 }
1289
1290 #[cfg(feature = "openai")]
1294 pub fn with_openai_config(mut self, config: ProviderConfig) -> Result<Self> {
1295 let provider = Arc::new(crate::providers::chat::openai::OpenAIProvider::new(config)?);
1296 self.embedding_providers.insert(
1297 "openai".to_string(),
1298 Arc::clone(&provider) as Arc<dyn EmbeddingProvider>,
1299 );
1300 Ok(self.with_provider("openai", provider))
1301 }
1302
1303 #[cfg(feature = "groq")]
1305 pub fn with_groq_from_env(self) -> Self {
1306 match crate::providers::chat::groq::GroqProvider::from_env() {
1307 Ok(provider) => self.with_provider("groq", Arc::new(provider)),
1308 Err(_) => self, }
1310 }
1311
1312 #[cfg(feature = "groq")]
1314 pub fn with_groq(self, api_key: impl Into<String>) -> Result<Self> {
1315 let provider = crate::providers::chat::groq::GroqProvider::with_api_key(api_key)?;
1316 Ok(self.with_provider("groq", Arc::new(provider)))
1317 }
1318
1319 #[cfg(feature = "groq")]
1321 pub fn with_groq_config(self, config: ProviderConfig) -> Result<Self> {
1322 let provider = crate::providers::chat::groq::GroqProvider::new(config)?;
1323 Ok(self.with_provider("groq", Arc::new(provider)))
1324 }
1325
1326 #[cfg(feature = "mistral")]
1328 pub fn with_mistral_from_env(self) -> Self {
1329 match crate::providers::chat::mistral::MistralProvider::from_env() {
1330 Ok(provider) => self.with_provider("mistral", Arc::new(provider)),
1331 Err(_) => self, }
1333 }
1334
1335 #[cfg(feature = "mistral")]
1337 pub fn with_mistral(self, api_key: impl Into<String>) -> Result<Self> {
1338 let provider = crate::providers::chat::mistral::MistralProvider::with_api_key(api_key)?;
1339 Ok(self.with_provider("mistral", Arc::new(provider)))
1340 }
1341
1342 #[cfg(feature = "mistral")]
1344 pub fn with_mistral_config(self, _config: ProviderConfig) -> Result<Self> {
1345 let provider = crate::providers::chat::mistral::MistralProvider::from_env()?;
1346 Ok(self.with_provider("mistral", Arc::new(provider)))
1347 }
1348
1349 #[cfg(feature = "azure")]
1357 pub fn with_azure_from_env(self) -> Self {
1358 match crate::providers::chat::azure::AzureOpenAIProvider::from_env() {
1359 Ok(provider) => self.with_provider("azure", Arc::new(provider)),
1360 Err(_) => self, }
1362 }
1363
1364 #[cfg(feature = "azure")]
1366 pub fn with_azure(self, config: crate::providers::chat::azure::AzureConfig) -> Result<Self> {
1367 let provider = crate::providers::chat::azure::AzureOpenAIProvider::new(config)?;
1368 Ok(self.with_provider("azure", Arc::new(provider)))
1369 }
1370
1371 #[cfg(feature = "bedrock")]
1379 pub fn with_bedrock_from_env(mut self) -> Self {
1380 self.pending_bedrock
1381 .push(("bedrock".to_string(), PendingBedrockConfig::FromEnv));
1382 self
1383 }
1384
1385 #[cfg(feature = "bedrock")]
1389 pub fn with_bedrock_region(mut self, region: impl Into<String>) -> Self {
1390 self.pending_bedrock.push((
1391 "bedrock".to_string(),
1392 PendingBedrockConfig::WithRegion {
1393 region: region.into(),
1394 },
1395 ));
1396 self
1397 }
1398
1399 #[cfg(feature = "bedrock")]
1404 pub async fn with_bedrock(
1405 self,
1406 builder: crate::providers::chat::bedrock::BedrockBuilder,
1407 ) -> Result<Self> {
1408 let provider = builder.build().await?;
1409 Ok(self.with_provider("bedrock", Arc::new(provider)))
1410 }
1411
1412 #[cfg(feature = "openai-compatible")]
1416 pub fn with_together_from_env(self) -> Self {
1417 match crate::providers::chat::openai_compatible::OpenAICompatibleProvider::together_from_env(
1418 ) {
1419 Ok(provider) => self.with_provider("together", Arc::new(provider)),
1420 Err(_) => self,
1421 }
1422 }
1423
1424 #[cfg(feature = "openai-compatible")]
1426 pub fn with_together(self, api_key: impl Into<String>) -> Result<Self> {
1427 let provider =
1428 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::together(api_key)?;
1429 Ok(self.with_provider("together", Arc::new(provider)))
1430 }
1431
1432 #[cfg(all(feature = "openai-compatible", not(feature = "fireworks")))]
1434 pub fn with_fireworks_from_env(self) -> Self {
1435 match crate::providers::chat::openai_compatible::OpenAICompatibleProvider::fireworks_from_env() {
1436 Ok(provider) => self.with_provider("fireworks", Arc::new(provider)),
1437 Err(_) => self,
1438 }
1439 }
1440
1441 #[cfg(all(feature = "openai-compatible", not(feature = "fireworks")))]
1443 pub fn with_fireworks(self, api_key: impl Into<String>) -> Result<Self> {
1444 let provider =
1445 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::fireworks(
1446 api_key,
1447 )?;
1448 Ok(self.with_provider("fireworks", Arc::new(provider)))
1449 }
1450
1451 #[cfg(feature = "fireworks")]
1453 pub fn with_fireworks_from_env(self) -> Self {
1454 match crate::providers::chat::fireworks::FireworksProvider::from_env() {
1455 Ok(provider) => self.with_provider("fireworks", Arc::new(provider)),
1456 Err(_) => self,
1457 }
1458 }
1459
1460 #[cfg(feature = "fireworks")]
1462 pub fn with_fireworks(self, api_key: impl Into<String>) -> Result<Self> {
1463 let provider = crate::providers::chat::fireworks::FireworksProvider::with_api_key(api_key)?;
1464 Ok(self.with_provider("fireworks", Arc::new(provider)))
1465 }
1466
1467 #[cfg(all(feature = "openai-compatible", not(feature = "deepseek")))]
1469 pub fn with_deepseek_from_env(self) -> Self {
1470 match crate::providers::chat::openai_compatible::OpenAICompatibleProvider::deepseek_from_env(
1471 ) {
1472 Ok(provider) => self.with_provider("deepseek", Arc::new(provider)),
1473 Err(_) => self,
1474 }
1475 }
1476
1477 #[cfg(all(feature = "openai-compatible", not(feature = "deepseek")))]
1479 pub fn with_deepseek(self, api_key: impl Into<String>) -> Result<Self> {
1480 let provider =
1481 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::deepseek(api_key)?;
1482 Ok(self.with_provider("deepseek", Arc::new(provider)))
1483 }
1484
1485 #[cfg(feature = "deepseek")]
1487 pub fn with_deepseek_from_env(self) -> Self {
1488 match crate::providers::chat::deepseek::DeepSeekProvider::from_env() {
1489 Ok(provider) => self.with_provider("deepseek", Arc::new(provider)),
1490 Err(_) => self,
1491 }
1492 }
1493
1494 #[cfg(feature = "deepseek")]
1496 pub fn with_deepseek(self, api_key: impl Into<String>) -> Result<Self> {
1497 let provider = crate::providers::chat::deepseek::DeepSeekProvider::with_api_key(api_key)?;
1498 Ok(self.with_provider("deepseek", Arc::new(provider)))
1499 }
1500
1501 #[cfg(feature = "openai-compatible")]
1503 pub fn with_perplexity_from_env(self) -> Self {
1504 match crate::providers::chat::openai_compatible::OpenAICompatibleProvider::perplexity_from_env() {
1505 Ok(provider) => self.with_provider("perplexity", Arc::new(provider)),
1506 Err(_) => self,
1507 }
1508 }
1509
1510 #[cfg(feature = "openai-compatible")]
1512 pub fn with_perplexity(self, api_key: impl Into<String>) -> Result<Self> {
1513 let provider =
1514 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::perplexity(
1515 api_key,
1516 )?;
1517 Ok(self.with_provider("perplexity", Arc::new(provider)))
1518 }
1519
1520 #[cfg(feature = "openai-compatible")]
1522 pub fn with_anyscale_from_env(self) -> Self {
1523 match crate::providers::chat::openai_compatible::OpenAICompatibleProvider::anyscale_from_env(
1524 ) {
1525 Ok(provider) => self.with_provider("anyscale", Arc::new(provider)),
1526 Err(_) => self,
1527 }
1528 }
1529
1530 #[cfg(feature = "openai-compatible")]
1532 pub fn with_anyscale(self, api_key: impl Into<String>) -> Result<Self> {
1533 let provider =
1534 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::anyscale(api_key)?;
1535 Ok(self.with_provider("anyscale", Arc::new(provider)))
1536 }
1537
1538 #[cfg(feature = "openai-compatible")]
1540 pub fn with_deepinfra_from_env(self) -> Self {
1541 match crate::providers::chat::openai_compatible::OpenAICompatibleProvider::deepinfra_from_env() {
1542 Ok(provider) => self.with_provider("deepinfra", Arc::new(provider)),
1543 Err(_) => self,
1544 }
1545 }
1546
1547 #[cfg(feature = "openai-compatible")]
1549 pub fn with_deepinfra(self, api_key: impl Into<String>) -> Result<Self> {
1550 let provider =
1551 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::deepinfra(
1552 api_key,
1553 )?;
1554 Ok(self.with_provider("deepinfra", Arc::new(provider)))
1555 }
1556
1557 #[cfg(feature = "openai-compatible")]
1559 pub fn with_novita_from_env(self) -> Self {
1560 match crate::providers::chat::openai_compatible::OpenAICompatibleProvider::novita_from_env()
1561 {
1562 Ok(provider) => self.with_provider("novita", Arc::new(provider)),
1563 Err(_) => self,
1564 }
1565 }
1566
1567 #[cfg(feature = "openai-compatible")]
1569 pub fn with_novita(self, api_key: impl Into<String>) -> Result<Self> {
1570 let provider =
1571 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::novita(api_key)?;
1572 Ok(self.with_provider("novita", Arc::new(provider)))
1573 }
1574
1575 #[cfg(feature = "openai-compatible")]
1577 pub fn with_hyperbolic_from_env(self) -> Self {
1578 match crate::providers::chat::openai_compatible::OpenAICompatibleProvider::hyperbolic_from_env() {
1579 Ok(provider) => self.with_provider("hyperbolic", Arc::new(provider)),
1580 Err(_) => self,
1581 }
1582 }
1583
1584 #[cfg(feature = "openai-compatible")]
1586 pub fn with_hyperbolic(self, api_key: impl Into<String>) -> Result<Self> {
1587 let provider =
1588 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::hyperbolic(
1589 api_key,
1590 )?;
1591 Ok(self.with_provider("hyperbolic", Arc::new(provider)))
1592 }
1593
1594 #[cfg(all(feature = "openai-compatible", not(feature = "cerebras")))]
1596 pub fn with_cerebras_from_env(self) -> Self {
1597 match crate::providers::chat::openai_compatible::OpenAICompatibleProvider::cerebras_from_env(
1598 ) {
1599 Ok(provider) => self.with_provider("cerebras", Arc::new(provider)),
1600 Err(_) => self,
1601 }
1602 }
1603
1604 #[cfg(all(feature = "openai-compatible", not(feature = "cerebras")))]
1606 pub fn with_cerebras(self, api_key: impl Into<String>) -> Result<Self> {
1607 let provider =
1608 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::cerebras(api_key)?;
1609 Ok(self.with_provider("cerebras", Arc::new(provider)))
1610 }
1611
1612 #[cfg(feature = "cerebras")]
1614 pub fn with_cerebras_from_env(self) -> Self {
1615 match crate::providers::chat::cerebras::CerebrasProvider::from_env() {
1616 Ok(provider) => self.with_provider("cerebras", Arc::new(provider)),
1617 Err(_) => self,
1618 }
1619 }
1620
1621 #[cfg(feature = "cerebras")]
1623 pub fn with_cerebras(self, api_key: impl Into<String>) -> Result<Self> {
1624 let provider = crate::providers::chat::cerebras::CerebrasProvider::with_api_key(api_key)?;
1625 Ok(self.with_provider("cerebras", Arc::new(provider)))
1626 }
1627
1628 #[cfg(feature = "reka")]
1632 pub fn with_reka_from_env(self) -> Self {
1633 match crate::providers::chat::openai_compatible::OpenAICompatibleProvider::reka_from_env() {
1634 Ok(provider) => self.with_provider("reka", Arc::new(provider)),
1635 Err(_) => self,
1636 }
1637 }
1638
1639 #[cfg(feature = "reka")]
1641 pub fn with_reka(self, api_key: impl Into<String>) -> Result<Self> {
1642 let provider =
1643 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::reka(api_key)?;
1644 Ok(self.with_provider("reka", Arc::new(provider)))
1645 }
1646
1647 #[cfg(feature = "reka")]
1649 pub fn with_reka_config(self, config: crate::provider::ProviderConfig) -> Result<Self> {
1650 let provider =
1651 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::reka_config(
1652 config,
1653 )?;
1654 Ok(self.with_provider("reka", Arc::new(provider)))
1655 }
1656
1657 #[cfg(feature = "nvidia-nim")]
1659 pub fn with_nvidia_nim_from_env(self) -> Self {
1660 match crate::providers::chat::openai_compatible::OpenAICompatibleProvider::nvidia_nim_from_env() {
1661 Ok(provider) => self.with_provider("nvidia_nim", Arc::new(provider)),
1662 Err(_) => self,
1663 }
1664 }
1665
1666 #[cfg(feature = "nvidia-nim")]
1668 pub fn with_nvidia_nim(self, api_key: impl Into<String>) -> Result<Self> {
1669 let provider =
1670 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::nvidia_nim(
1671 api_key,
1672 )?;
1673 Ok(self.with_provider("nvidia_nim", Arc::new(provider)))
1674 }
1675
1676 #[cfg(feature = "nvidia-nim")]
1678 pub fn with_nvidia_nim_config(self, config: crate::provider::ProviderConfig) -> Result<Self> {
1679 let provider =
1680 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::nvidia_nim_config(
1681 config,
1682 )?;
1683 Ok(self.with_provider("nvidia_nim", Arc::new(provider)))
1684 }
1685
1686 #[cfg(feature = "xinference")]
1688 pub fn with_xinference_from_env(self) -> Self {
1689 match crate::providers::chat::openai_compatible::OpenAICompatibleProvider::xinference_from_env() {
1690 Ok(provider) => self.with_provider("xinference", Arc::new(provider)),
1691 Err(_) => self,
1692 }
1693 }
1694
1695 #[cfg(feature = "xinference")]
1697 pub fn with_xinference(self, api_key: impl Into<String>) -> Result<Self> {
1698 let provider =
1699 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::xinference(
1700 api_key,
1701 )?;
1702 Ok(self.with_provider("xinference", Arc::new(provider)))
1703 }
1704
1705 #[cfg(feature = "xinference")]
1707 pub fn with_xinference_config(self, config: crate::provider::ProviderConfig) -> Result<Self> {
1708 let provider =
1709 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::xinference_config(
1710 config,
1711 )?;
1712 Ok(self.with_provider("xinference", Arc::new(provider)))
1713 }
1714
1715 #[cfg(feature = "public-ai")]
1717 pub fn with_public_ai_from_env(self) -> Self {
1718 match crate::providers::chat::openai_compatible::OpenAICompatibleProvider::public_ai_from_env() {
1719 Ok(provider) => self.with_provider("public_ai", Arc::new(provider)),
1720 Err(_) => self,
1721 }
1722 }
1723
1724 #[cfg(feature = "public-ai")]
1726 pub fn with_public_ai(self, api_key: impl Into<String>) -> Result<Self> {
1727 let provider =
1728 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::public_ai(
1729 api_key,
1730 )?;
1731 Ok(self.with_provider("public_ai", Arc::new(provider)))
1732 }
1733
1734 #[cfg(feature = "public-ai")]
1736 pub fn with_public_ai_config(self, config: crate::provider::ProviderConfig) -> Result<Self> {
1737 let provider =
1738 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::public_ai_config(
1739 config,
1740 )?;
1741 Ok(self.with_provider("public_ai", Arc::new(provider)))
1742 }
1743
1744 #[cfg(feature = "bytez")]
1748 pub fn with_bytez_from_env(self) -> Self {
1749 match crate::providers::chat::openai_compatible::OpenAICompatibleProvider::bytez_from_env()
1750 {
1751 Ok(provider) => self.with_provider("bytez", Arc::new(provider)),
1752 Err(_) => self,
1753 }
1754 }
1755
1756 #[cfg(feature = "bytez")]
1758 pub fn with_bytez(self, api_key: impl Into<String>) -> Result<Self> {
1759 let provider =
1760 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::bytez(api_key)?;
1761 Ok(self.with_provider("bytez", Arc::new(provider)))
1762 }
1763
1764 #[cfg(feature = "bytez")]
1766 pub fn with_bytez_config(self, config: crate::provider::ProviderConfig) -> Result<Self> {
1767 let provider =
1768 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::bytez_config(
1769 config,
1770 )?;
1771 Ok(self.with_provider("bytez", Arc::new(provider)))
1772 }
1773
1774 #[cfg(feature = "chutes")]
1776 pub fn with_chutes_from_env(self) -> Self {
1777 match crate::providers::chat::openai_compatible::OpenAICompatibleProvider::chutes_from_env()
1778 {
1779 Ok(provider) => self.with_provider("chutes", Arc::new(provider)),
1780 Err(_) => self,
1781 }
1782 }
1783
1784 #[cfg(feature = "chutes")]
1786 pub fn with_chutes(self, api_key: impl Into<String>) -> Result<Self> {
1787 let provider =
1788 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::chutes(api_key)?;
1789 Ok(self.with_provider("chutes", Arc::new(provider)))
1790 }
1791
1792 #[cfg(feature = "chutes")]
1794 pub fn with_chutes_config(self, config: crate::provider::ProviderConfig) -> Result<Self> {
1795 let provider =
1796 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::chutes_config(
1797 config,
1798 )?;
1799 Ok(self.with_provider("chutes", Arc::new(provider)))
1800 }
1801
1802 #[cfg(feature = "comet-api")]
1804 pub fn with_comet_api_from_env(self) -> Self {
1805 match crate::providers::chat::openai_compatible::OpenAICompatibleProvider::comet_api_from_env() {
1806 Ok(provider) => self.with_provider("comet_api", Arc::new(provider)),
1807 Err(_) => self,
1808 }
1809 }
1810
1811 #[cfg(feature = "comet-api")]
1813 pub fn with_comet_api(self, api_key: impl Into<String>) -> Result<Self> {
1814 let provider =
1815 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::comet_api(
1816 api_key,
1817 )?;
1818 Ok(self.with_provider("comet_api", Arc::new(provider)))
1819 }
1820
1821 #[cfg(feature = "comet-api")]
1823 pub fn with_comet_api_config(self, config: crate::provider::ProviderConfig) -> Result<Self> {
1824 let provider =
1825 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::comet_api_config(
1826 config,
1827 )?;
1828 Ok(self.with_provider("comet_api", Arc::new(provider)))
1829 }
1830
1831 #[cfg(feature = "compactifai")]
1833 pub fn with_compactifai_from_env(self) -> Self {
1834 match crate::providers::chat::openai_compatible::OpenAICompatibleProvider::compactifai_from_env()
1835 {
1836 Ok(provider) => self.with_provider("compactifai", Arc::new(provider)),
1837 Err(_) => self,
1838 }
1839 }
1840
1841 #[cfg(feature = "compactifai")]
1843 pub fn with_compactifai(self, api_key: impl Into<String>) -> Result<Self> {
1844 let provider =
1845 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::compactifai(
1846 api_key,
1847 )?;
1848 Ok(self.with_provider("compactifai", Arc::new(provider)))
1849 }
1850
1851 #[cfg(feature = "compactifai")]
1853 pub fn with_compactifai_config(self, config: crate::provider::ProviderConfig) -> Result<Self> {
1854 let provider =
1855 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::compactifai_config(
1856 config,
1857 )?;
1858 Ok(self.with_provider("compactifai", Arc::new(provider)))
1859 }
1860
1861 #[cfg(feature = "synthetic")]
1863 pub fn with_synthetic_from_env(self) -> Self {
1864 match crate::providers::chat::openai_compatible::OpenAICompatibleProvider::synthetic_from_env() {
1865 Ok(provider) => self.with_provider("synthetic", Arc::new(provider)),
1866 Err(_) => self,
1867 }
1868 }
1869
1870 #[cfg(feature = "synthetic")]
1872 pub fn with_synthetic(self, api_key: impl Into<String>) -> Result<Self> {
1873 let provider =
1874 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::synthetic(
1875 api_key,
1876 )?;
1877 Ok(self.with_provider("synthetic", Arc::new(provider)))
1878 }
1879
1880 #[cfg(feature = "synthetic")]
1882 pub fn with_synthetic_config(self, config: crate::provider::ProviderConfig) -> Result<Self> {
1883 let provider =
1884 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::synthetic_config(
1885 config,
1886 )?;
1887 Ok(self.with_provider("synthetic", Arc::new(provider)))
1888 }
1889
1890 #[cfg(feature = "morph")]
1892 pub fn with_morph_from_env(self) -> Self {
1893 match crate::providers::chat::openai_compatible::OpenAICompatibleProvider::morph_from_env()
1894 {
1895 Ok(provider) => self.with_provider("morph", Arc::new(provider)),
1896 Err(_) => self,
1897 }
1898 }
1899
1900 #[cfg(feature = "morph")]
1902 pub fn with_morph(self, api_key: impl Into<String>) -> Result<Self> {
1903 let provider =
1904 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::morph(api_key)?;
1905 Ok(self.with_provider("morph", Arc::new(provider)))
1906 }
1907
1908 #[cfg(feature = "morph")]
1910 pub fn with_morph_config(self, config: crate::provider::ProviderConfig) -> Result<Self> {
1911 let provider =
1912 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::morph_config(
1913 config,
1914 )?;
1915 Ok(self.with_provider("morph", Arc::new(provider)))
1916 }
1917
1918 #[cfg(feature = "heroku-ai")]
1920 pub fn with_heroku_ai_from_env(self) -> Self {
1921 match crate::providers::chat::openai_compatible::OpenAICompatibleProvider::heroku_ai_from_env() {
1922 Ok(provider) => self.with_provider("heroku_ai", Arc::new(provider)),
1923 Err(_) => self,
1924 }
1925 }
1926
1927 #[cfg(feature = "heroku-ai")]
1929 pub fn with_heroku_ai(self, api_key: impl Into<String>) -> Result<Self> {
1930 let provider =
1931 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::heroku_ai(
1932 api_key,
1933 )?;
1934 Ok(self.with_provider("heroku_ai", Arc::new(provider)))
1935 }
1936
1937 #[cfg(feature = "heroku-ai")]
1939 pub fn with_heroku_ai_config(self, config: crate::provider::ProviderConfig) -> Result<Self> {
1940 let provider =
1941 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::heroku_ai_config(
1942 config,
1943 )?;
1944 Ok(self.with_provider("heroku_ai", Arc::new(provider)))
1945 }
1946
1947 #[cfg(feature = "v0")]
1949 pub fn with_v0_from_env(self) -> Self {
1950 match crate::providers::chat::openai_compatible::OpenAICompatibleProvider::v0_from_env() {
1951 Ok(provider) => self.with_provider("v0", Arc::new(provider)),
1952 Err(_) => self,
1953 }
1954 }
1955
1956 #[cfg(feature = "v0")]
1958 pub fn with_v0(self, api_key: impl Into<String>) -> Result<Self> {
1959 let provider =
1960 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::v0(api_key)?;
1961 Ok(self.with_provider("v0", Arc::new(provider)))
1962 }
1963
1964 #[cfg(feature = "v0")]
1966 pub fn with_v0_config(self, config: crate::provider::ProviderConfig) -> Result<Self> {
1967 let provider =
1968 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::v0_config(config)?;
1969 Ok(self.with_provider("v0", Arc::new(provider)))
1970 }
1971
1972 #[cfg(feature = "openai-compatible")]
1982 pub fn with_openai_compatible(
1983 self,
1984 name: impl Into<String>,
1985 base_url: impl Into<String>,
1986 api_key: Option<String>,
1987 ) -> Result<Self> {
1988 let name_str = name.into();
1989 let provider = crate::providers::chat::openai_compatible::OpenAICompatibleProvider::custom(
1990 name_str.clone(),
1991 base_url,
1992 api_key,
1993 )?;
1994 Ok(self.with_provider(name_str, Arc::new(provider)))
1995 }
1996
1997 #[cfg(feature = "google")]
2003 pub fn with_google_from_env(self) -> Self {
2004 match crate::providers::chat::google::GoogleProvider::from_env() {
2005 Ok(provider) => self.with_provider("google", Arc::new(provider)),
2006 Err(_) => self,
2007 }
2008 }
2009
2010 #[cfg(feature = "google")]
2012 pub fn with_google(self, api_key: impl Into<String>) -> Result<Self> {
2013 let provider = crate::providers::chat::google::GoogleProvider::with_api_key(api_key)?;
2014 Ok(self.with_provider("google", Arc::new(provider)))
2015 }
2016
2017 #[cfg(feature = "google")]
2019 pub fn with_google_config(self, config: ProviderConfig) -> Result<Self> {
2020 let provider = crate::providers::chat::google::GoogleProvider::new(config)?;
2021 Ok(self.with_provider("google", Arc::new(provider)))
2022 }
2023
2024 #[cfg(feature = "vertex")]
2038 pub fn with_vertex_from_env(mut self) -> Self {
2039 self.pending_vertex
2040 .push(("vertex".to_string(), PendingVertexConfig::FromEnv));
2041 self
2042 }
2043
2044 #[cfg(feature = "vertex")]
2048 pub fn with_vertex_service_account(
2049 mut self,
2050 path: impl AsRef<std::path::Path>,
2051 project_id: impl Into<String>,
2052 location: impl Into<String>,
2053 ) -> Self {
2054 self.pending_vertex.push((
2055 "vertex".to_string(),
2056 PendingVertexConfig::ServiceAccount {
2057 path: path.as_ref().to_path_buf(),
2058 project_id: project_id.into(),
2059 location: location.into(),
2060 },
2061 ));
2062 self
2063 }
2064
2065 #[cfg(feature = "vertex")]
2070 pub fn with_vertex_config(
2071 self,
2072 config: crate::providers::chat::vertex::VertexConfig,
2073 ) -> Result<Self> {
2074 let provider = crate::providers::chat::vertex::VertexProvider::with_config(config)?;
2075 Ok(self.with_provider("vertex", Arc::new(provider)))
2076 }
2077
2078 #[cfg(feature = "vertex")]
2084 pub fn with_vertex_anthropic_from_env(mut self) -> Self {
2085 self.pending_vertex.push((
2086 "vertex-anthropic".to_string(),
2087 PendingVertexConfig::WithPublisher {
2088 publisher: "anthropic".to_string(),
2089 },
2090 ));
2091 self
2092 }
2093
2094 #[cfg(feature = "vertex")]
2096 pub fn with_vertex_anthropic_config(
2097 self,
2098 mut config: crate::providers::chat::vertex::VertexConfig,
2099 ) -> Result<Self> {
2100 config.set_publisher("anthropic");
2101 let provider = crate::providers::chat::vertex::VertexProvider::with_config(config)?;
2102 Ok(self.with_provider("vertex-anthropic", Arc::new(provider)))
2103 }
2104
2105 #[cfg(feature = "vertex")]
2109 pub fn with_vertex_deepseek_from_env(mut self) -> Self {
2110 self.pending_vertex.push((
2111 "vertex-deepseek".to_string(),
2112 PendingVertexConfig::WithPublisher {
2113 publisher: "deepseek".to_string(),
2114 },
2115 ));
2116 self
2117 }
2118
2119 #[cfg(feature = "vertex")]
2121 pub fn with_vertex_deepseek_config(
2122 self,
2123 mut config: crate::providers::chat::vertex::VertexConfig,
2124 ) -> Result<Self> {
2125 config.set_publisher("deepseek");
2126 let provider = crate::providers::chat::vertex::VertexProvider::with_config(config)?;
2127 Ok(self.with_provider("vertex-deepseek", Arc::new(provider)))
2128 }
2129
2130 #[cfg(feature = "vertex")]
2134 pub fn with_vertex_llama_from_env(mut self) -> Self {
2135 self.pending_vertex.push((
2136 "vertex-llama".to_string(),
2137 PendingVertexConfig::WithPublisher {
2138 publisher: "meta".to_string(),
2139 },
2140 ));
2141 self
2142 }
2143
2144 #[cfg(feature = "vertex")]
2146 pub fn with_vertex_llama_config(
2147 self,
2148 mut config: crate::providers::chat::vertex::VertexConfig,
2149 ) -> Result<Self> {
2150 config.set_publisher("meta");
2151 let provider = crate::providers::chat::vertex::VertexProvider::with_config(config)?;
2152 Ok(self.with_provider("vertex-llama", Arc::new(provider)))
2153 }
2154
2155 #[cfg(feature = "vertex")]
2159 pub fn with_vertex_mistral_from_env(mut self) -> Self {
2160 self.pending_vertex.push((
2161 "vertex-mistral".to_string(),
2162 PendingVertexConfig::WithPublisher {
2163 publisher: "mistralai".to_string(),
2164 },
2165 ));
2166 self
2167 }
2168
2169 #[cfg(feature = "vertex")]
2171 pub fn with_vertex_mistral_config(
2172 self,
2173 mut config: crate::providers::chat::vertex::VertexConfig,
2174 ) -> Result<Self> {
2175 config.set_publisher("mistralai");
2176 let provider = crate::providers::chat::vertex::VertexProvider::with_config(config)?;
2177 Ok(self.with_provider("vertex-mistral", Arc::new(provider)))
2178 }
2179
2180 #[cfg(feature = "vertex")]
2185 pub fn with_vertex_ai21_from_env(mut self) -> Self {
2186 self.pending_vertex.push((
2187 "vertex-ai21".to_string(),
2188 PendingVertexConfig::WithPublisher {
2189 publisher: "ai21labs".to_string(),
2190 },
2191 ));
2192 self
2193 }
2194
2195 #[cfg(feature = "vertex")]
2197 pub fn with_vertex_ai21_config(
2198 self,
2199 mut config: crate::providers::chat::vertex::VertexConfig,
2200 ) -> Result<Self> {
2201 config.set_publisher("ai21labs");
2202 let provider = crate::providers::chat::vertex::VertexProvider::with_config(config)?;
2203 Ok(self.with_provider("vertex-ai21", Arc::new(provider)))
2204 }
2205
2206 #[cfg(feature = "cohere")]
2214 pub fn with_cohere_from_env(mut self) -> Self {
2215 match crate::providers::chat::cohere::CohereProvider::from_env() {
2216 Ok(provider) => {
2217 let provider = Arc::new(provider);
2218 self.embedding_providers.insert(
2219 "cohere".to_string(),
2220 Arc::clone(&provider) as Arc<dyn EmbeddingProvider>,
2221 );
2222 self.with_provider("cohere", provider)
2223 }
2224 Err(_) => self,
2225 }
2226 }
2227
2228 #[cfg(feature = "cohere")]
2232 pub fn with_cohere(mut self, api_key: impl Into<String>) -> Result<Self> {
2233 let provider =
2234 Arc::new(crate::providers::chat::cohere::CohereProvider::with_api_key(api_key)?);
2235 self.embedding_providers.insert(
2236 "cohere".to_string(),
2237 Arc::clone(&provider) as Arc<dyn EmbeddingProvider>,
2238 );
2239 Ok(self.with_provider("cohere", provider))
2240 }
2241
2242 #[cfg(feature = "cohere")]
2246 pub fn with_cohere_config(mut self, config: ProviderConfig) -> Result<Self> {
2247 let provider = Arc::new(crate::providers::chat::cohere::CohereProvider::new(config)?);
2248 self.embedding_providers.insert(
2249 "cohere".to_string(),
2250 Arc::clone(&provider) as Arc<dyn EmbeddingProvider>,
2251 );
2252 Ok(self.with_provider("cohere", provider))
2253 }
2254
2255 #[cfg(feature = "ai21")]
2259 pub fn with_ai21_from_env(self) -> Self {
2260 match crate::providers::chat::ai21::AI21Provider::from_env() {
2261 Ok(provider) => self.with_provider("ai21", Arc::new(provider)),
2262 Err(_) => self,
2263 }
2264 }
2265
2266 #[cfg(feature = "ai21")]
2268 pub fn with_ai21(self, api_key: impl Into<String>) -> Result<Self> {
2269 let provider = crate::providers::chat::ai21::AI21Provider::with_api_key(api_key)?;
2270 Ok(self.with_provider("ai21", Arc::new(provider)))
2271 }
2272
2273 #[cfg(feature = "ai21")]
2275 pub fn with_ai21_config(self, config: ProviderConfig) -> Result<Self> {
2276 let provider = crate::providers::chat::ai21::AI21Provider::new(config)?;
2277 Ok(self.with_provider("ai21", Arc::new(provider)))
2278 }
2279
2280 #[cfg(feature = "huggingface")]
2286 pub fn with_huggingface_from_env(self) -> Self {
2287 match crate::providers::chat::huggingface::HuggingFaceProvider::from_env() {
2288 Ok(provider) => self.with_provider("huggingface", Arc::new(provider)),
2289 Err(_) => self,
2290 }
2291 }
2292
2293 #[cfg(feature = "huggingface")]
2295 pub fn with_huggingface(self, api_key: impl Into<String>) -> Result<Self> {
2296 let provider =
2297 crate::providers::chat::huggingface::HuggingFaceProvider::with_api_key(api_key)?;
2298 Ok(self.with_provider("huggingface", Arc::new(provider)))
2299 }
2300
2301 #[cfg(feature = "huggingface")]
2303 pub fn with_huggingface_endpoint(
2304 self,
2305 endpoint_url: impl Into<String>,
2306 api_key: impl Into<String>,
2307 ) -> Result<Self> {
2308 let provider = crate::providers::chat::huggingface::HuggingFaceProvider::endpoint(
2309 endpoint_url,
2310 api_key,
2311 )?;
2312 Ok(self.with_provider("huggingface", Arc::new(provider)))
2313 }
2314
2315 #[cfg(feature = "huggingface")]
2317 pub fn with_huggingface_config(self, config: ProviderConfig) -> Result<Self> {
2318 let provider = crate::providers::chat::huggingface::HuggingFaceProvider::new(config)?;
2319 Ok(self.with_provider("huggingface", Arc::new(provider)))
2320 }
2321
2322 #[cfg(feature = "replicate")]
2326 pub fn with_replicate_from_env(self) -> Self {
2327 match crate::providers::chat::replicate::ReplicateProvider::from_env() {
2328 Ok(provider) => self.with_provider("replicate", Arc::new(provider)),
2329 Err(_) => self,
2330 }
2331 }
2332
2333 #[cfg(feature = "replicate")]
2335 pub fn with_replicate(self, api_key: impl Into<String>) -> Result<Self> {
2336 let provider = crate::providers::chat::replicate::ReplicateProvider::with_api_key(api_key)?;
2337 Ok(self.with_provider("replicate", Arc::new(provider)))
2338 }
2339
2340 #[cfg(feature = "replicate")]
2342 pub fn with_replicate_config(self, config: ProviderConfig) -> Result<Self> {
2343 let provider = crate::providers::chat::replicate::ReplicateProvider::new(config)?;
2344 Ok(self.with_provider("replicate", Arc::new(provider)))
2345 }
2346
2347 #[cfg(feature = "baseten")]
2351 pub fn with_baseten_from_env(self) -> Self {
2352 match crate::providers::chat::baseten::BasetenProvider::from_env() {
2353 Ok(provider) => self.with_provider("baseten", Arc::new(provider)),
2354 Err(_) => self,
2355 }
2356 }
2357
2358 #[cfg(feature = "baseten")]
2360 pub fn with_baseten(self, api_key: impl Into<String>) -> Result<Self> {
2361 let provider = crate::providers::chat::baseten::BasetenProvider::with_api_key(api_key)?;
2362 Ok(self.with_provider("baseten", Arc::new(provider)))
2363 }
2364
2365 #[cfg(feature = "baseten")]
2367 pub fn with_baseten_model(
2368 self,
2369 model_id: impl Into<String>,
2370 api_key: impl Into<String>,
2371 ) -> Result<Self> {
2372 let provider =
2373 crate::providers::chat::baseten::BasetenProvider::with_model(model_id, api_key)?;
2374 Ok(self.with_provider("baseten", Arc::new(provider)))
2375 }
2376
2377 #[cfg(feature = "baseten")]
2379 pub fn with_baseten_config(self, config: ProviderConfig) -> Result<Self> {
2380 let provider = crate::providers::chat::baseten::BasetenProvider::new(config)?;
2381 Ok(self.with_provider("baseten", Arc::new(provider)))
2382 }
2383
2384 #[cfg(feature = "runpod")]
2388 pub fn with_runpod_from_env(self) -> Self {
2389 match crate::providers::chat::runpod::RunPodProvider::from_env() {
2390 Ok(provider) => self.with_provider("runpod", Arc::new(provider)),
2391 Err(_) => self,
2392 }
2393 }
2394
2395 #[cfg(feature = "runpod")]
2397 pub fn with_runpod(
2398 self,
2399 endpoint_id: impl Into<String>,
2400 api_key: impl Into<String>,
2401 ) -> Result<Self> {
2402 let provider = crate::providers::chat::runpod::RunPodProvider::new(endpoint_id, api_key)?;
2403 Ok(self.with_provider("runpod", Arc::new(provider)))
2404 }
2405
2406 #[cfg(feature = "cloudflare")]
2412 pub fn with_cloudflare_from_env(self) -> Self {
2413 match crate::providers::chat::cloudflare::CloudflareProvider::from_env() {
2414 Ok(provider) => self.with_provider("cloudflare", Arc::new(provider)),
2415 Err(_) => self,
2416 }
2417 }
2418
2419 #[cfg(feature = "cloudflare")]
2421 pub fn with_cloudflare(
2422 self,
2423 account_id: impl Into<String>,
2424 api_token: impl Into<String>,
2425 ) -> Result<Self> {
2426 let provider =
2427 crate::providers::chat::cloudflare::CloudflareProvider::new(account_id, api_token)?;
2428 Ok(self.with_provider("cloudflare", Arc::new(provider)))
2429 }
2430
2431 #[cfg(feature = "watsonx")]
2435 pub fn with_watsonx_from_env(self) -> Self {
2436 match crate::providers::chat::watsonx::WatsonxProvider::from_env() {
2437 Ok(provider) => self.with_provider("watsonx", Arc::new(provider)),
2438 Err(_) => self,
2439 }
2440 }
2441
2442 #[cfg(feature = "watsonx")]
2444 pub fn with_watsonx(
2445 self,
2446 api_key: impl Into<String>,
2447 project_id: impl Into<String>,
2448 ) -> Result<Self> {
2449 let provider = crate::providers::chat::watsonx::WatsonxProvider::new(api_key, project_id)?;
2450 Ok(self.with_provider("watsonx", Arc::new(provider)))
2451 }
2452
2453 #[cfg(feature = "databricks")]
2457 pub fn with_databricks_from_env(self) -> Self {
2458 match crate::providers::chat::databricks::DatabricksProvider::from_env() {
2459 Ok(provider) => self.with_provider("databricks", Arc::new(provider)),
2460 Err(_) => self,
2461 }
2462 }
2463
2464 #[cfg(feature = "databricks")]
2466 pub fn with_databricks(
2467 self,
2468 host: impl Into<String>,
2469 token: impl Into<String>,
2470 ) -> Result<Self> {
2471 let provider = crate::providers::chat::databricks::DatabricksProvider::new(host, token)?;
2472 Ok(self.with_provider("databricks", Arc::new(provider)))
2473 }
2474
2475 #[cfg(feature = "sambanova")]
2481 pub fn with_sambanova_from_env(self) -> Self {
2482 match crate::providers::chat::sambanova::SambaNovaProvider::from_env() {
2483 Ok(provider) => self.with_provider("sambanova", Arc::new(provider)),
2484 Err(_) => self,
2485 }
2486 }
2487
2488 #[cfg(feature = "sambanova")]
2490 pub fn with_sambanova(self, api_key: impl Into<String>) -> Result<Self> {
2491 let provider = crate::providers::chat::sambanova::SambaNovaProvider::with_api_key(api_key)?;
2492 Ok(self.with_provider("sambanova", Arc::new(provider)))
2493 }
2494
2495 #[cfg(feature = "openai-compatible")]
2499 pub fn with_xai_from_env(self) -> Self {
2500 match crate::providers::chat::openai_compatible::OpenAICompatibleProvider::xai_from_env() {
2501 Ok(provider) => self.with_provider("xai", Arc::new(provider)),
2502 Err(_) => self,
2503 }
2504 }
2505
2506 #[cfg(feature = "openai-compatible")]
2508 pub fn with_xai(self, api_key: impl Into<String>) -> Result<Self> {
2509 let provider =
2510 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::xai(api_key)?;
2511 Ok(self.with_provider("xai", Arc::new(provider)))
2512 }
2513
2514 #[cfg(feature = "openai-compatible")]
2516 pub fn with_lambda_from_env(self) -> Self {
2517 match crate::providers::chat::openai_compatible::OpenAICompatibleProvider::lambda_from_env()
2518 {
2519 Ok(provider) => self.with_provider("lambda", Arc::new(provider)),
2520 Err(_) => self,
2521 }
2522 }
2523
2524 #[cfg(feature = "openai-compatible")]
2526 pub fn with_lambda(self, api_key: impl Into<String>) -> Result<Self> {
2527 let provider =
2528 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::lambda(api_key)?;
2529 Ok(self.with_provider("lambda", Arc::new(provider)))
2530 }
2531
2532 #[cfg(feature = "openai-compatible")]
2534 pub fn with_friendli_from_env(self) -> Self {
2535 match crate::providers::chat::openai_compatible::OpenAICompatibleProvider::friendli_from_env(
2536 ) {
2537 Ok(provider) => self.with_provider("friendli", Arc::new(provider)),
2538 Err(_) => self,
2539 }
2540 }
2541
2542 #[cfg(feature = "openai-compatible")]
2544 pub fn with_friendli(self, api_key: impl Into<String>) -> Result<Self> {
2545 let provider =
2546 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::friendli(api_key)?;
2547 Ok(self.with_provider("friendli", Arc::new(provider)))
2548 }
2549
2550 #[cfg(feature = "openai-compatible")]
2552 pub fn with_volcengine_from_env(self) -> Self {
2553 match crate::providers::chat::openai_compatible::OpenAICompatibleProvider::volcengine_from_env() {
2554 Ok(provider) => self.with_provider("volcengine", Arc::new(provider)),
2555 Err(_) => self,
2556 }
2557 }
2558
2559 #[cfg(feature = "openai-compatible")]
2561 pub fn with_volcengine(self, api_key: impl Into<String>) -> Result<Self> {
2562 let provider =
2563 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::volcengine(
2564 api_key,
2565 )?;
2566 Ok(self.with_provider("volcengine", Arc::new(provider)))
2567 }
2568
2569 #[cfg(feature = "openai-compatible")]
2571 pub fn with_meta_llama_from_env(self) -> Self {
2572 match crate::providers::chat::openai_compatible::OpenAICompatibleProvider::meta_llama_from_env() {
2573 Ok(provider) => self.with_provider("meta_llama", Arc::new(provider)),
2574 Err(_) => self,
2575 }
2576 }
2577
2578 #[cfg(feature = "openai-compatible")]
2580 pub fn with_meta_llama(self, api_key: impl Into<String>) -> Result<Self> {
2581 let provider =
2582 crate::providers::chat::openai_compatible::OpenAICompatibleProvider::meta_llama(
2583 api_key,
2584 )?;
2585 Ok(self.with_provider("meta_llama", Arc::new(provider)))
2586 }
2587
2588 #[cfg(feature = "datarobot")]
2592 pub fn with_datarobot_from_env(self) -> Self {
2593 match crate::providers::DataRobotProvider::from_env() {
2594 Ok(provider) => self.with_provider("datarobot", Arc::new(provider)),
2595 Err(_) => self,
2596 }
2597 }
2598
2599 #[cfg(feature = "datarobot")]
2601 pub fn with_datarobot(self, api_key: impl Into<String>) -> Result<Self> {
2602 let provider = crate::providers::DataRobotProvider::with_api_key(api_key)?;
2603 Ok(self.with_provider("datarobot", Arc::new(provider)))
2604 }
2605
2606 #[cfg(feature = "stability")]
2608 pub fn with_stability_from_env(self) -> Self {
2609 match crate::providers::StabilityProvider::from_env() {
2610 Ok(provider) => self.with_provider("stability", Arc::new(provider)),
2611 Err(_) => self,
2612 }
2613 }
2614
2615 #[cfg(feature = "stability")]
2617 pub fn with_stability(self, api_key: impl Into<String>) -> Result<Self> {
2618 let provider = crate::providers::StabilityProvider::with_api_key(api_key)?;
2619 Ok(self.with_provider("stability", Arc::new(provider)))
2620 }
2621
2622 #[cfg(feature = "runwayml")]
2626 pub fn with_runwayml_from_env(self) -> Self {
2627 match crate::providers::RunwayMLProvider::from_env() {
2628 Ok(provider) => self.with_provider("runwayml", Arc::new(provider)),
2629 Err(_) => self,
2630 }
2631 }
2632
2633 #[cfg(feature = "runwayml")]
2635 pub fn with_runwayml(self, api_key: impl Into<String>) -> Result<Self> {
2636 let provider = crate::providers::RunwayMLProvider::with_api_key(api_key)?;
2637 Ok(self.with_provider("runwayml", Arc::new(provider)))
2638 }
2639
2640 #[cfg(feature = "recraft")]
2642 pub fn with_recraft_from_env(self) -> Self {
2643 match crate::providers::RecraftProvider::from_env() {
2644 Ok(provider) => self.with_provider("recraft", Arc::new(provider)),
2645 Err(_) => self,
2646 }
2647 }
2648
2649 #[cfg(feature = "recraft")]
2651 pub fn with_recraft(self, api_key: impl Into<String>) -> Result<Self> {
2652 let provider = crate::providers::RecraftProvider::with_api_key(api_key)?;
2653 Ok(self.with_provider("recraft", Arc::new(provider)))
2654 }
2655
2656 #[cfg(feature = "voyage")]
2660 pub fn with_voyage_from_env(self) -> Self {
2661 match crate::providers::VoyageProvider::from_env() {
2662 Ok(provider) => self.with_provider("voyage", Arc::new(provider)),
2663 Err(_) => self,
2664 }
2665 }
2666
2667 #[cfg(feature = "voyage")]
2669 pub fn with_voyage(self, api_key: impl Into<String>) -> Result<Self> {
2670 let provider = crate::providers::VoyageProvider::with_api_key(api_key)?;
2671 Ok(self.with_provider("voyage", Arc::new(provider)))
2672 }
2673
2674 #[cfg(feature = "jina")]
2676 pub fn with_jina_from_env(self) -> Self {
2677 match crate::providers::JinaProvider::from_env() {
2678 Ok(provider) => self.with_provider("jina", Arc::new(provider)),
2679 Err(_) => self,
2680 }
2681 }
2682
2683 #[cfg(feature = "jina")]
2685 pub fn with_jina(self, api_key: impl Into<String>) -> Result<Self> {
2686 let provider = crate::providers::JinaProvider::with_api_key(api_key)?;
2687 Ok(self.with_provider("jina", Arc::new(provider)))
2688 }
2689
2690 #[cfg(feature = "sagemaker")]
2694 pub async fn with_sagemaker_from_env(self) -> Result<Self> {
2695 let provider = crate::providers::SageMakerProvider::from_env().await?;
2696 Ok(self.with_provider("sagemaker", Arc::new(provider)))
2697 }
2698
2699 #[cfg(feature = "sagemaker")]
2701 pub async fn with_sagemaker(self, region: &str, endpoint_name: &str) -> Result<Self> {
2702 let provider = crate::providers::SageMakerProvider::new(region, endpoint_name).await?;
2703 Ok(self.with_provider("sagemaker", Arc::new(provider)))
2704 }
2705
2706 #[cfg(feature = "snowflake")]
2708 pub async fn with_snowflake_from_env(self) -> Result<Self> {
2709 let provider = crate::providers::SnowflakeProvider::from_env().await?;
2710 Ok(self.with_provider("snowflake", Arc::new(provider)))
2711 }
2712
2713 #[cfg(feature = "snowflake")]
2715 pub async fn with_snowflake(
2716 self,
2717 account: &str,
2718 user: &str,
2719 password: &str,
2720 database: &str,
2721 schema: &str,
2722 warehouse: &str,
2723 ) -> Result<Self> {
2724 let provider = crate::providers::SnowflakeProvider::new(
2725 account, user, password, database, schema, warehouse,
2726 )
2727 .await?;
2728 Ok(self.with_provider("snowflake", Arc::new(provider)))
2729 }
2730
2731 #[cfg(feature = "openai-realtime")]
2735 pub fn openai_realtime_from_env(&self) -> Result<crate::providers::RealtimeProvider> {
2736 crate::providers::RealtimeProvider::from_env()
2737 }
2738
2739 #[cfg(feature = "openai-realtime")]
2741 pub fn openai_realtime(&self, api_key: &str) -> crate::providers::RealtimeProvider {
2742 crate::providers::RealtimeProvider::new(api_key, "gpt-4o-realtime-preview")
2743 }
2744
2745 #[cfg(feature = "openai-realtime")]
2747 pub fn openai_realtime_with_model(
2748 &self,
2749 api_key: &str,
2750 model: &str,
2751 ) -> crate::providers::RealtimeProvider {
2752 crate::providers::RealtimeProvider::new(api_key, model)
2753 }
2754
2755 #[cfg(feature = "baidu")]
2761 pub fn with_baidu_from_env(self) -> Self {
2762 match crate::providers::BaiduProvider::from_env() {
2763 Ok(provider) => self.with_provider("baidu", Arc::new(provider)),
2764 Err(_) => self,
2765 }
2766 }
2767
2768 #[cfg(feature = "baidu")]
2770 pub fn with_baidu(
2771 self,
2772 api_key: impl Into<String>,
2773 secret_key: impl Into<String>,
2774 ) -> Result<Self> {
2775 let provider = crate::providers::BaiduProvider::new(&api_key.into(), &secret_key.into())?;
2776 Ok(self.with_provider("baidu", Arc::new(provider)))
2777 }
2778
2779 #[cfg(feature = "alibaba")]
2784 pub fn with_alibaba_from_env(self) -> Self {
2785 match crate::providers::AlibabaProvider::from_env() {
2786 Ok(provider) => self.with_provider("alibaba", Arc::new(provider)),
2787 Err(_) => self,
2788 }
2789 }
2790
2791 #[cfg(feature = "alibaba")]
2794 pub fn with_alibaba(self, api_key: impl Into<String>) -> Result<Self> {
2795 let provider = crate::providers::AlibabaProvider::new(&api_key.into())?;
2796 Ok(self.with_provider("alibaba", Arc::new(provider)))
2797 }
2798
2799 #[cfg(feature = "openrouter")]
2804 pub fn with_openrouter_from_env(self) -> Self {
2805 match crate::providers::chat::openrouter::OpenRouterProvider::from_env() {
2806 Ok(provider) => self.with_provider("openrouter", Arc::new(provider)),
2807 Err(_) => self,
2808 }
2809 }
2810
2811 #[cfg(feature = "openrouter")]
2813 pub fn with_openrouter(self, api_key: impl Into<String>) -> Result<Self> {
2814 let provider =
2815 crate::providers::chat::openrouter::OpenRouterProvider::with_api_key(api_key)?;
2816 Ok(self.with_provider("openrouter", Arc::new(provider)))
2817 }
2818
2819 #[cfg(feature = "ollama")]
2821 pub fn with_ollama(self) -> Result<Self> {
2822 let provider = crate::providers::chat::ollama::OllamaProvider::new(Default::default())?;
2823 Ok(self.with_provider("ollama", Arc::new(provider)))
2824 }
2825
2826 #[cfg(feature = "ollama")]
2828 pub fn with_ollama_url(self, base_url: impl Into<String>) -> Result<Self> {
2829 let config = crate::provider::ProviderConfig {
2830 base_url: Some(base_url.into()),
2831 ..Default::default()
2832 };
2833 let provider = crate::providers::chat::ollama::OllamaProvider::new(config)?;
2834 Ok(self.with_provider("ollama", Arc::new(provider)))
2835 }
2836
2837 #[cfg(feature = "maritaca")]
2840 pub fn with_maritaca_from_env(self) -> Self {
2841 match crate::providers::chat::maritaca::MaritacaProvider::from_env() {
2842 Ok(provider) => self.with_provider("maritaca", Arc::new(provider)),
2843 Err(_) => self,
2844 }
2845 }
2846
2847 #[cfg(feature = "maritaca")]
2849 pub fn with_maritaca(self, api_key: impl Into<String>) -> Result<Self> {
2850 let provider = crate::providers::chat::maritaca::MaritacaProvider::with_api_key(api_key)?;
2851 Ok(self.with_provider("maritaca", Arc::new(provider)))
2852 }
2853
2854 #[cfg(feature = "lighton")]
2857 pub fn with_lighton_from_env(self) -> Self {
2858 match crate::providers::chat::lighton::LightOnProvider::from_env() {
2859 Ok(provider) => self.with_provider("lighton", Arc::new(provider)),
2860 Err(_) => self,
2861 }
2862 }
2863
2864 #[cfg(feature = "lighton")]
2866 pub fn with_lighton(self, api_key: impl Into<String>) -> Result<Self> {
2867 let provider = crate::providers::chat::lighton::LightOnProvider::with_api_key(api_key)?;
2868 Ok(self.with_provider("lighton", Arc::new(provider)))
2869 }
2870
2871 #[allow(unused_mut)] pub async fn build(mut self) -> Result<LLMKitClient> {
2880 #[cfg(feature = "vertex")]
2882 {
2883 for (name, config) in self.pending_vertex {
2884 let result = match config {
2885 PendingVertexConfig::FromEnv => {
2886 match crate::providers::chat::vertex::VertexConfig::from_env().await {
2887 Ok(cfg) => {
2888 crate::providers::chat::vertex::VertexProvider::with_config(cfg)
2889 }
2890 Err(_) => continue, }
2892 }
2893 PendingVertexConfig::ServiceAccount {
2894 path,
2895 project_id,
2896 location,
2897 } => {
2898 match crate::providers::chat::vertex::VertexConfig::from_service_account_file(
2899 &path,
2900 &project_id,
2901 &location,
2902 )
2903 .await
2904 {
2905 Ok(cfg) => {
2906 crate::providers::chat::vertex::VertexProvider::with_config(cfg)
2907 }
2908 Err(_) => continue, }
2910 }
2911 PendingVertexConfig::WithPublisher { publisher } => {
2912 match crate::providers::chat::vertex::VertexConfig::from_env_with_publisher(
2913 &publisher,
2914 )
2915 .await
2916 {
2917 Ok(cfg) => {
2918 crate::providers::chat::vertex::VertexProvider::with_config(cfg)
2919 }
2920 Err(_) => continue, }
2922 }
2923 };
2924
2925 if let Ok(provider) = result {
2926 self.providers.insert(name, Arc::new(provider));
2927 }
2928 }
2929 }
2930
2931 #[cfg(feature = "bedrock")]
2933 {
2934 for (name, config) in self.pending_bedrock {
2935 let result = match config {
2936 PendingBedrockConfig::FromEnv => {
2937 crate::providers::chat::bedrock::BedrockProvider::from_env_region().await
2938 }
2939 PendingBedrockConfig::WithRegion { region } => {
2940 crate::providers::chat::bedrock::BedrockProvider::from_env(®ion).await
2941 }
2942 };
2943
2944 if let Ok(provider) = result {
2945 self.providers.insert(name, Arc::new(provider));
2946 }
2947 }
2948 }
2949
2950 if self.providers.is_empty() {
2951 return Err(Error::config("No providers configured"));
2952 }
2953
2954 let providers = if let Some(retry_config) = self.retry_config {
2956 self.providers
2957 .into_iter()
2958 .map(|(name, provider)| {
2959 let retrying = DynamicRetryingProvider {
2960 inner: provider,
2961 config: retry_config.clone(),
2962 };
2963 (name, Arc::new(retrying) as Arc<dyn Provider>)
2964 })
2965 .collect()
2966 } else {
2967 self.providers
2968 };
2969
2970 Ok(LLMKitClient {
2971 providers,
2972 embedding_providers: self.embedding_providers,
2973 speech_providers: self.speech_providers,
2974 transcription_providers: self.transcription_providers,
2975 image_providers: self.image_providers,
2976 video_providers: self.video_providers,
2977 ranking_providers: self.ranking_providers,
2978 moderation_providers: self.moderation_providers,
2979 classification_providers: self.classification_providers,
2980 default_provider: self.default_provider,
2981 })
2982 }
2983}
2984
2985impl Default for ClientBuilder {
2986 fn default() -> Self {
2987 Self::new()
2988 }
2989}
2990
2991#[cfg(test)]
2992mod tests {
2993 use super::*;
2994
2995 #[test]
2996 fn test_model_parsing_valid_format() {
2997 let (provider, model) =
2999 parse_model_identifier("anthropic/claude-sonnet-4-20250514").unwrap();
3000 assert_eq!(provider, "anthropic");
3001 assert_eq!(model, "claude-sonnet-4-20250514");
3002
3003 let (provider, model) = parse_model_identifier("openai/gpt-4o").unwrap();
3004 assert_eq!(provider, "openai");
3005 assert_eq!(model, "gpt-4o");
3006
3007 let (provider, model) = parse_model_identifier("groq/llama-3.3-70b-versatile").unwrap();
3008 assert_eq!(provider, "groq");
3009 assert_eq!(model, "llama-3.3-70b-versatile");
3010
3011 let (provider, model) = parse_model_identifier("vertex/gemini-pro").unwrap();
3012 assert_eq!(provider, "vertex");
3013 assert_eq!(model, "gemini-pro");
3014
3015 let (provider, model) = parse_model_identifier("mistral/mistral-large-latest").unwrap();
3016 assert_eq!(provider, "mistral");
3017 assert_eq!(model, "mistral-large-latest");
3018
3019 let (provider, model) = parse_model_identifier("baidu/ERNIE-Bot-Ultra").unwrap();
3021 assert_eq!(provider, "baidu");
3022 assert_eq!(model, "ERNIE-Bot-Ultra");
3023
3024 let (provider, model) = parse_model_identifier("alibaba/qwen-max").unwrap();
3025 assert_eq!(provider, "alibaba");
3026 assert_eq!(model, "qwen-max");
3027
3028 let (provider, model) = parse_model_identifier("runwayml/gen4_turbo").unwrap();
3029 assert_eq!(provider, "runwayml");
3030 assert_eq!(model, "gen4_turbo");
3031
3032 let (provider, model) = parse_model_identifier("recraft/recraft-v3").unwrap();
3033 assert_eq!(provider, "recraft");
3034 assert_eq!(model, "recraft-v3");
3035 }
3036
3037 #[test]
3038 fn test_model_parsing_requires_provider() {
3039 assert!(parse_model_identifier("claude-sonnet-4-20250514").is_err());
3041 assert!(parse_model_identifier("gpt-4o").is_err());
3042 assert!(parse_model_identifier("mistral-large").is_err());
3043 assert!(parse_model_identifier("model").is_err());
3044 assert!(parse_model_identifier("").is_err());
3045 }
3046
3047 #[test]
3048 fn test_model_parsing_invalid_provider_format() {
3049 assert!(parse_model_identifier("meta-llama/Llama-3.2-3B-Instruct").is_err());
3052
3053 assert!(parse_model_identifier("v1.2.3/model").is_err());
3055
3056 assert!(parse_model_identifier("namespace:tag/model").is_err());
3058 }
3059
3060 #[test]
3061 fn test_model_parsing_valid_provider_like_names() {
3062 let (provider, model) = parse_model_identifier("mistralai/Mistral-7B-v0.1").unwrap();
3065 assert_eq!(provider, "mistralai");
3066 assert_eq!(model, "Mistral-7B-v0.1");
3067 }
3068}