rsclaw 0.0.1-alpha.1

rsclaw: High-performance AI agent (BETA). Optimized for M4 Max and 2GB VPS. 100% compatible with openclaw
Documentation
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;

/// LLM provider registry for managing multiple providers.
pub struct ProviderRegistry {
    providers: HashMap<String, Arc<dyn LlmProvider>>,
}

impl ProviderRegistry {
    /// Create a new provider registry.
    pub fn new() -> Self {
        Self {
            providers: HashMap::new(),
        }
    }

    /// Register a provider.
    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);
    }

    /// Get a provider by name.
    pub fn get(&self, name: &str) -> Option<Arc<dyn LlmProvider>> {
        self.providers.get(name).cloned()
    }

    /// List all registered provider names.
    pub fn list(&self) -> Vec<&str> {
        self.providers.keys().map(|k| k.as_str()).collect()
    }

    /// Build registry from config.
    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()
    }
}