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::memory::ConcurrencyLimiter;
use super::runtime::{AgentConfig, AgentRuntime};
use crate::provider::LlmProvider;
use anyhow::Result;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;

/// Agent manager for multi-agent scheduling.
pub struct AgentManager {
    agents: Arc<RwLock<HashMap<Arc<str>, Arc<AgentRuntime>>>>,
    limiter: ConcurrencyLimiter,
    provider: Option<Arc<dyn LlmProvider>>,
}

impl AgentManager {
    /// Create a new agent manager.
    pub fn new(max_concurrent: u32) -> Self {
        Self {
            agents: Arc::new(RwLock::new(HashMap::new())),
            limiter: ConcurrencyLimiter::new(max_concurrent),
            provider: None,
        }
    }

    /// Set the LLM provider.
    pub fn set_provider(&mut self, provider: Arc<dyn LlmProvider>) {
        self.provider = Some(provider);
    }

    /// Get the LLM provider.
    pub fn provider(&self) -> Option<Arc<dyn LlmProvider>> {
        self.provider.clone()
    }

    /// Create an agent.
    pub async fn create(&self, config: AgentConfig) -> Result<Arc<str>> {
        if !self.limiter.try_acquire() {
            anyhow::bail!(
                "Cannot create agent: concurrency limit reached ({}/{})",
                self.limiter.current(),
                self.limiter.max()
            );
        }

        let name = config.name.clone();
        let agent = Arc::new(AgentRuntime::new(config));

        {
            let mut agents = self.agents.write().await;
            agents.insert(name.clone(), agent);
        }

        tracing::info!("Agent '{}' created", name);
        Ok(name)
    }

    /// Get an agent by name.
    pub async fn get(&self, name: &str) -> Option<Arc<AgentRuntime>> {
        let agents = self.agents.read().await;
        agents.get(name).cloned()
    }

    /// List all agents.
    pub async fn list(&self) -> Vec<Arc<AgentRuntime>> {
        let agents = self.agents.read().await;
        agents.values().cloned().collect()
    }

    /// Destroy an agent.
    pub async fn destroy(&self, name: &str) -> Result<bool> {
        let mut agents = self.agents.write().await;
        if agents.remove(name).is_some() {
            self.limiter.release();
            tracing::info!("Agent '{}' destroyed", name);
            Ok(true)
        } else {
            Ok(false)
        }
    }

    /// Send message to an agent.
    pub async fn chat(&self, agent_name: &str, message: &str) -> Result<String> {
        let agent = self.get(agent_name).await
            .ok_or_else(|| anyhow::anyhow!("Agent '{}' not found", agent_name))?;

        let provider = self.provider.clone()
            .ok_or_else(|| anyhow::anyhow!("No LLM provider configured"))?;

        agent.chat(message, provider).await
    }

    /// Get agent count.
    pub async fn count(&self) -> usize {
        let agents = self.agents.read().await;
        agents.len()
    }

    /// Check if at capacity.
    pub fn is_at_capacity(&self) -> bool {
        self.limiter.is_at_capacity()
    }

    /// Get current concurrency.
    pub fn current_concurrency(&self) -> u64 {
        self.limiter.current()
    }

    /// Get max concurrency.
    pub fn max_concurrency(&self) -> u64 {
        self.limiter.max()
    }
}

impl Default for AgentManager {
    fn default() -> Self {
        Self::new(3)
    }
}