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::types::{InboundMessage, OutboundMessage};
use crate::agent::AgentManager;
use crate::config::loader::ConfigLoader;
use anyhow::Result;
use std::sync::Arc;
use tokio::sync::RwLock;

/// Message router for dispatching messages to agents.
pub struct MessageRouter {
    agent_manager: Arc<RwLock<AgentManager>>,
}

impl MessageRouter {
    /// Create a new message router.
    pub fn new(agent_manager: Arc<RwLock<AgentManager>>) -> Self {
        Self { agent_manager }
    }

    /// Route a message to the appropriate agent.
    pub async fn route(&self, message: InboundMessage) -> Result<OutboundMessage> {
        let manager = self.agent_manager.read().await;

        let agent_name = self.resolve_agent(&message).await;

        let agent = match manager.get(&agent_name).await {
            Some(agent) => agent,
            None => {
                tracing::info!("Auto-creating agent '{}'", agent_name);
                drop(manager);

                let manager = self.agent_manager.write().await;
                let config = crate::agent::AgentConfig {
                    name: agent_name.clone(),
                    model: Arc::from("gpt-4"),
                    system_prompt: Arc::from("You are a helpful assistant."),
                    max_tokens: 4096,
                    memory_limit_mb: 512,
                };

                match manager.create(config).await {
                    Ok(_) => manager.get(&agent_name).await.unwrap(),
                    Err(e) => {
                        return Ok(OutboundMessage::error(format!("Failed to create agent: {}", e)));
                    }
                }
            }
        };

        match self.process_message(&agent, &message).await {
            Ok(response) => Ok(OutboundMessage::ok(response)),
            Err(e) => Ok(OutboundMessage::error(format!("Processing error: {}", e))),
        }
    }

    /// Resolve which agent should handle this message.
    async fn resolve_agent(&self, _message: &InboundMessage) -> Arc<str> {
        let config = ConfigLoader::load().unwrap_or_default();

        config.agents.list
            .iter()
            .find(|a| a.default)
            .map(|a| a.name.clone())
            .unwrap_or_else(|| Arc::from("default"))
    }

    /// Process a message through an agent.
    async fn process_message(
        &self,
        agent: &crate::agent::AgentRuntime,
        message: &InboundMessage,
    ) -> Result<String> {
        let manager = self.agent_manager.read().await;
        if let Some(provider) = manager.provider() {
            agent.chat(&message.text, provider).await
        } else {
            Ok(format!(
                "Agent '{}' received: {} (no LLM provider configured)",
                agent.name(),
                message.text
            ))
        }
    }
}

impl Default for MessageRouter {
    fn default() -> Self {
        let config = ConfigLoader::load().unwrap_or_default();
        let manager = AgentManager::new(config.memory.max_concurrent_agents);
        Self::new(Arc::new(RwLock::new(manager)))
    }
}