daa_ai/
lib.rs

1//! # DAA AI
2//!
3//! AI integration layer for the Decentralized Autonomous Agents (DAA) system.
4//! Provides Claude AI integration via QuDAG MCP (Model Context Protocol) for 
5//! intelligent decision making and task automation.
6
7mod qudag_stubs;
8
9use std::collections::HashMap;
10use serde::{Deserialize, Serialize};
11use thiserror::Error;
12use uuid::Uuid;
13
14// Re-export QuDAG MCP types
15pub use crate::qudag_stubs::qudag_mcp::{MCPClient, MCPMessage, MCPError, Tool, ToolCall, ToolResult};
16
17pub mod claude;
18pub mod agents;
19pub mod tools;
20pub mod tasks;
21pub mod memory;
22
23#[cfg(feature = "rules-integration")]
24pub mod rules_integration;
25
26#[cfg(feature = "database")]
27pub mod database;
28
29/// AI system error types
30#[derive(Error, Debug)]
31pub enum AIError {
32    #[error("MCP error: {0}")]
33    MCP(#[from] MCPError),
34    
35    #[error("Claude API error: {0}")]
36    Claude(String),
37    
38    #[error("Agent not found: {0}")]
39    AgentNotFound(String),
40    
41    #[error("Task execution error: {0}")]
42    TaskExecution(String),
43    
44    #[error("Tool error: {0}")]
45    Tool(String),
46    
47    #[error("Memory error: {0}")]
48    Memory(String),
49    
50    #[error("Configuration error: {0}")]
51    Configuration(String),
52    
53    #[error("Network error: {0}")]
54    Network(#[from] reqwest::Error),
55    
56    #[error("Serialization error: {0}")]
57    Serialization(#[from] serde_json::Error),
58}
59
60pub type Result<T> = std::result::Result<T, AIError>;
61
62/// Configuration for the DAA AI system
63#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct AIConfig {
65    /// Claude API configuration
66    pub claude: claude::ClaudeConfig,
67    
68    /// MCP client configuration
69    pub mcp: MCPClientConfig,
70    
71    /// Agent configuration
72    pub agents: AgentConfig,
73    
74    /// Memory configuration
75    pub memory: MemoryConfig,
76    
77    /// Database configuration
78    #[cfg(feature = "database")]
79    pub database_url: Option<String>,
80}
81
82impl Default for AIConfig {
83    fn default() -> Self {
84        Self {
85            claude: claude::ClaudeConfig::default(),
86            mcp: MCPClientConfig::default(),
87            agents: AgentConfig::default(),
88            memory: MemoryConfig::default(),
89            #[cfg(feature = "database")]
90            database_url: None,
91        }
92    }
93}
94
95/// MCP client configuration
96#[derive(Debug, Clone, Serialize, Deserialize)]
97pub struct MCPClientConfig {
98    /// MCP server endpoint
99    pub server_url: String,
100    
101    /// Connection timeout in seconds
102    pub timeout: u64,
103    
104    /// Maximum concurrent connections
105    pub max_connections: usize,
106    
107    /// Retry configuration
108    pub retry_attempts: u32,
109    
110    /// Tool registry
111    pub available_tools: Vec<String>,
112}
113
114impl Default for MCPClientConfig {
115    fn default() -> Self {
116        Self {
117            server_url: "http://localhost:3000".to_string(),
118            timeout: 30,
119            max_connections: 10,
120            retry_attempts: 3,
121            available_tools: vec![
122                "code_execution".to_string(),
123                "file_operations".to_string(),
124                "web_search".to_string(),
125                "data_analysis".to_string(),
126            ],
127        }
128    }
129}
130
131/// Agent configuration
132#[derive(Debug, Clone, Serialize, Deserialize)]
133pub struct AgentConfig {
134    /// Maximum number of agents
135    pub max_agents: usize,
136    
137    /// Default agent capabilities
138    pub default_capabilities: Vec<String>,
139    
140    /// Agent spawn configuration
141    pub spawn_config: SpawnConfig,
142}
143
144impl Default for AgentConfig {
145    fn default() -> Self {
146        Self {
147            max_agents: 100,
148            default_capabilities: vec![
149                "reasoning".to_string(),
150                "code_generation".to_string(),
151                "data_analysis".to_string(),
152                "communication".to_string(),
153            ],
154            spawn_config: SpawnConfig::default(),
155        }
156    }
157}
158
159/// Agent spawn configuration
160#[derive(Debug, Clone, Serialize, Deserialize)]
161pub struct SpawnConfig {
162    /// Default model to use for new agents
163    pub default_model: String,
164    
165    /// Default system prompt
166    pub default_system_prompt: String,
167    
168    /// Default temperature for responses
169    pub default_temperature: f32,
170    
171    /// Maximum tokens per response
172    pub max_tokens: u32,
173}
174
175impl Default for SpawnConfig {
176    fn default() -> Self {
177        Self {
178            default_model: "claude-3-opus-20240229".to_string(),
179            default_system_prompt: "You are a helpful AI agent in the DAA system. You can execute tasks, analyze data, and collaborate with other agents.".to_string(),
180            default_temperature: 0.7,
181            max_tokens: 4096,
182        }
183    }
184}
185
186/// Memory configuration
187#[derive(Debug, Clone, Serialize, Deserialize)]
188pub struct MemoryConfig {
189    /// Maximum memory entries per agent
190    pub max_entries_per_agent: usize,
191    
192    /// Memory retention period in hours
193    pub retention_hours: u64,
194    
195    /// Enable persistent memory
196    pub persistent: bool,
197}
198
199impl Default for MemoryConfig {
200    fn default() -> Self {
201        Self {
202            max_entries_per_agent: 1000,
203            retention_hours: 24 * 7, // 1 week
204            persistent: true,
205        }
206    }
207}
208
209/// Main AI system coordinating all AI operations
210pub struct AISystem {
211    /// System configuration
212    config: AIConfig,
213    
214    /// MCP client for Claude integration
215    mcp_client: MCPClient,
216    
217    /// Claude API client
218    claude_client: claude::ClaudeClient,
219    
220    /// Agent manager
221    agent_manager: agents::AgentManager,
222    
223    /// Task manager
224    task_manager: tasks::TaskManager,
225    
226    /// Tool registry
227    tool_registry: tools::ToolRegistry,
228    
229    /// Memory system
230    memory: memory::MemorySystem,
231    
232    /// Database connection
233    #[cfg(feature = "database")]
234    database: Option<database::DatabaseManager>,
235}
236
237impl AISystem {
238    /// Create a new AI system
239    pub async fn new(config: AIConfig) -> Result<Self> {
240        // Initialize MCP client
241        let mcp_client = MCPClient::new(&config.mcp.server_url).await
242            .map_err(AIError::MCP)?;
243        
244        // Initialize Claude client
245        let claude_client = claude::ClaudeClient::new(config.claude.clone()).await?;
246        
247        // Initialize managers
248        let agent_manager = agents::AgentManager::new(config.agents.clone());
249        let task_manager = tasks::TaskManager::new();
250        let tool_registry = tools::ToolRegistry::new();
251        let memory = memory::MemorySystem::new(config.memory.clone());
252        
253        // Initialize database if enabled
254        #[cfg(feature = "database")]
255        let database = if let Some(db_url) = &config.database_url {
256            Some(database::DatabaseManager::new(db_url).await?)
257        } else {
258            None
259        };
260
261        Ok(Self {
262            config,
263            mcp_client,
264            claude_client,
265            agent_manager,
266            task_manager,
267            tool_registry,
268            memory,
269            #[cfg(feature = "database")]
270            database,
271        })
272    }
273
274    /// Initialize the AI system
275    pub async fn initialize(&mut self) -> Result<()> {
276        tracing::info!("Initializing DAA AI System");
277        
278        // Initialize MCP connection
279        self.mcp_client.connect().await.map_err(AIError::MCP)?;
280        
281        // Register default tools
282        self.register_default_tools().await?;
283        
284        // Initialize memory system
285        self.memory.initialize().await?;
286        
287        // Initialize database if enabled
288        #[cfg(feature = "database")]
289        if let Some(db) = &mut self.database {
290            db.initialize().await?;
291        }
292        
293        tracing::info!("DAA AI System initialized successfully");
294        Ok(())
295    }
296
297    /// Spawn a new AI agent
298    pub async fn spawn_agent(
299        &mut self,
300        agent_type: agents::AgentType,
301        capabilities: Option<Vec<String>>,
302        custom_config: Option<HashMap<String, String>>,
303    ) -> Result<String> {
304        let agent = self.agent_manager.spawn_agent(
305            agent_type,
306            capabilities.unwrap_or_else(|| self.config.agents.default_capabilities.clone()),
307            custom_config,
308        ).await?;
309        
310        // Store agent in memory
311        self.memory.store_agent_metadata(&agent.id, &agent).await?;
312        
313        tracing::info!("Spawned new agent: {} ({})", agent.id, agent.agent_type);
314        Ok(agent.id)
315    }
316
317    /// Execute a task with an agent
318    pub async fn execute_task(
319        &mut self,
320        agent_id: &str,
321        task: tasks::Task,
322    ) -> Result<tasks::TaskResult> {
323        // Get agent
324        let agent = self.agent_manager.get_agent(agent_id).await?;
325        
326        // Execute task through Claude
327        let result = self.claude_client.execute_task(&agent, &task).await?;
328        
329        // Store task result in memory
330        self.memory.store_task_result(agent_id, &task.id, &result).await?;
331        
332        // Record in database if enabled
333        #[cfg(feature = "database")]
334        if let Some(db) = &mut self.database {
335            db.record_task_execution(agent_id, &task, &result).await?;
336        }
337        
338        tracing::info!("Task {} executed by agent {}", task.id, agent_id);
339        Ok(result)
340    }
341
342    /// Use a tool via MCP
343    pub async fn use_tool(
344        &mut self,
345        agent_id: &str,
346        tool_name: &str,
347        parameters: HashMap<String, serde_json::Value>,
348    ) -> Result<ToolResult> {
349        // Create tool call
350        let tool_call = ToolCall {
351            id: Uuid::new_v4().to_string(),
352            name: tool_name.to_string(),
353            parameters,
354        };
355        
356        // Execute via MCP
357        let result = self.mcp_client.call_tool(tool_call).await
358            .map_err(AIError::MCP)?;
359        
360        // Store in memory
361        self.memory.store_tool_usage(agent_id, tool_name, &result).await?;
362        
363        tracing::info!("Tool {} used by agent {}", tool_name, agent_id);
364        Ok(result)
365    }
366
367    /// Get agent memory
368    pub async fn get_agent_memory(&self, agent_id: &str) -> Result<Vec<memory::MemoryEntry>> {
369        self.memory.get_agent_memory(agent_id).await
370    }
371
372    /// Store information in agent memory
373    pub async fn store_memory(
374        &mut self,
375        agent_id: &str,
376        key: String,
377        data: serde_json::Value,
378        metadata: Option<HashMap<String, String>>,
379    ) -> Result<()> {
380        self.memory.store(agent_id, key, data, metadata).await
381    }
382
383    /// Get system statistics
384    pub async fn get_statistics(&self) -> AIStatistics {
385        AIStatistics {
386            total_agents: self.agent_manager.get_agent_count().await,
387            active_tasks: self.task_manager.get_active_task_count().await,
388            total_tools: self.tool_registry.get_tool_count().await,
389            memory_entries: self.memory.get_total_entries().await,
390            uptime_seconds: 0, // Would be calculated from start time
391        }
392    }
393
394    /// Register default tools
395    async fn register_default_tools(&mut self) -> Result<()> {
396        // Register built-in tools
397        for tool_name in &self.config.mcp.available_tools {
398            let tool = tools::create_default_tool(tool_name)?;
399            self.tool_registry.register_tool(tool).await?;
400        }
401        
402        Ok(())
403    }
404}
405
406/// AI system statistics
407#[derive(Debug, Clone, Serialize, Deserialize)]
408pub struct AIStatistics {
409    /// Total number of spawned agents
410    pub total_agents: u64,
411    
412    /// Number of active tasks
413    pub active_tasks: u64,
414    
415    /// Total available tools
416    pub total_tools: u64,
417    
418    /// Memory entries count
419    pub memory_entries: u64,
420    
421    /// System uptime in seconds
422    pub uptime_seconds: u64,
423}
424
425impl std::fmt::Display for AIStatistics {
426    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
427        write!(
428            f,
429            "AI Stats: Agents={}, Active Tasks={}, Tools={}, Memory={}, Uptime={}s",
430            self.total_agents,
431            self.active_tasks,
432            self.total_tools,
433            self.memory_entries,
434            self.uptime_seconds
435        )
436    }
437}
438
439#[cfg(test)]
440mod tests {
441    use super::*;
442
443    #[tokio::test]
444    async fn test_ai_system_creation() {
445        let config = AIConfig::default();
446        // Note: This would fail in real test due to missing MCP server
447        // let system = AISystem::new(config).await;
448        // In actual implementation, we'd use mock clients for testing
449        assert!(true); // Placeholder test
450    }
451
452    #[test]
453    fn test_config_defaults() {
454        let config = AIConfig::default();
455        assert_eq!(config.claude.model, "claude-3-opus-20240229");
456        assert_eq!(config.mcp.timeout, 30);
457        assert_eq!(config.agents.max_agents, 100);
458    }
459
460    #[test]
461    fn test_statistics_display() {
462        let stats = AIStatistics {
463            total_agents: 5,
464            active_tasks: 3,
465            total_tools: 10,
466            memory_entries: 100,
467            uptime_seconds: 3600,
468        };
469        
470        let display = stats.to_string();
471        assert!(display.contains("Agents=5"));
472        assert!(display.contains("Active Tasks=3"));
473        assert!(display.contains("Tools=10"));
474    }
475}