1mod qudag_stubs;
8
9use std::collections::HashMap;
10use serde::{Deserialize, Serialize};
11use thiserror::Error;
12use uuid::Uuid;
13
14pub 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#[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#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct AIConfig {
65 pub claude: claude::ClaudeConfig,
67
68 pub mcp: MCPClientConfig,
70
71 pub agents: AgentConfig,
73
74 pub memory: MemoryConfig,
76
77 #[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#[derive(Debug, Clone, Serialize, Deserialize)]
97pub struct MCPClientConfig {
98 pub server_url: String,
100
101 pub timeout: u64,
103
104 pub max_connections: usize,
106
107 pub retry_attempts: u32,
109
110 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#[derive(Debug, Clone, Serialize, Deserialize)]
133pub struct AgentConfig {
134 pub max_agents: usize,
136
137 pub default_capabilities: Vec<String>,
139
140 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#[derive(Debug, Clone, Serialize, Deserialize)]
161pub struct SpawnConfig {
162 pub default_model: String,
164
165 pub default_system_prompt: String,
167
168 pub default_temperature: f32,
170
171 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#[derive(Debug, Clone, Serialize, Deserialize)]
188pub struct MemoryConfig {
189 pub max_entries_per_agent: usize,
191
192 pub retention_hours: u64,
194
195 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, persistent: true,
205 }
206 }
207}
208
209pub struct AISystem {
211 config: AIConfig,
213
214 mcp_client: MCPClient,
216
217 claude_client: claude::ClaudeClient,
219
220 agent_manager: agents::AgentManager,
222
223 task_manager: tasks::TaskManager,
225
226 tool_registry: tools::ToolRegistry,
228
229 memory: memory::MemorySystem,
231
232 #[cfg(feature = "database")]
234 database: Option<database::DatabaseManager>,
235}
236
237impl AISystem {
238 pub async fn new(config: AIConfig) -> Result<Self> {
240 let mcp_client = MCPClient::new(&config.mcp.server_url).await
242 .map_err(AIError::MCP)?;
243
244 let claude_client = claude::ClaudeClient::new(config.claude.clone()).await?;
246
247 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 #[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 pub async fn initialize(&mut self) -> Result<()> {
276 tracing::info!("Initializing DAA AI System");
277
278 self.mcp_client.connect().await.map_err(AIError::MCP)?;
280
281 self.register_default_tools().await?;
283
284 self.memory.initialize().await?;
286
287 #[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 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 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 pub async fn execute_task(
319 &mut self,
320 agent_id: &str,
321 task: tasks::Task,
322 ) -> Result<tasks::TaskResult> {
323 let agent = self.agent_manager.get_agent(agent_id).await?;
325
326 let result = self.claude_client.execute_task(&agent, &task).await?;
328
329 self.memory.store_task_result(agent_id, &task.id, &result).await?;
331
332 #[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 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 let tool_call = ToolCall {
351 id: Uuid::new_v4().to_string(),
352 name: tool_name.to_string(),
353 parameters,
354 };
355
356 let result = self.mcp_client.call_tool(tool_call).await
358 .map_err(AIError::MCP)?;
359
360 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 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 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 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, }
392 }
393
394 async fn register_default_tools(&mut self) -> Result<()> {
396 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#[derive(Debug, Clone, Serialize, Deserialize)]
408pub struct AIStatistics {
409 pub total_agents: u64,
411
412 pub active_tasks: u64,
414
415 pub total_tools: u64,
417
418 pub memory_entries: u64,
420
421 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 assert!(true); }
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}