1use crate::agents::Agent;
4use crate::error::{AgentError, Result};
5use crate::models::TaskType;
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8use std::sync::Arc;
9use tracing::{debug, info};
10
11#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct AgentMetadataInfo {
17 pub id: String,
19 pub name: String,
21 pub description: String,
23 pub supported_task_types: Vec<TaskType>,
25}
26
27pub struct AgentRegistry {
46 agents: HashMap<String, Arc<dyn Agent>>,
47 task_type_map: HashMap<TaskType, Vec<String>>,
48 metadata: HashMap<String, AgentMetadataInfo>,
49}
50
51impl AgentRegistry {
52 pub fn new() -> Self {
58 Self {
59 agents: HashMap::new(),
60 task_type_map: HashMap::new(),
61 metadata: HashMap::new(),
62 }
63 }
64
65 pub fn register(&mut self, agent: Arc<dyn Agent>) {
74 let agent_id = agent.id().to_string();
75 let agent_name = agent.name().to_string();
76
77 debug!(agent_id = %agent_id, agent_name = %agent_name, "Registering agent");
78
79 self.agents.insert(agent_id.clone(), agent.clone());
80
81 let supported_task_types: Vec<TaskType> = [
83 TaskType::CodeReview,
84 TaskType::TestGeneration,
85 TaskType::Documentation,
86 TaskType::Refactoring,
87 TaskType::SecurityAnalysis,
88 ]
89 .iter()
90 .copied()
91 .filter(|task_type| agent.supports(*task_type))
92 .collect();
93
94 debug!(
95 agent_id = %agent_id,
96 task_count = supported_task_types.len(),
97 "Agent supports task types"
98 );
99
100 for task_type in &supported_task_types {
102 self.task_type_map
103 .entry(*task_type)
104 .or_default()
105 .push(agent_id.clone());
106 }
107
108 let metadata = AgentMetadataInfo {
110 id: agent_id.clone(),
111 name: agent_name.clone(),
112 description: agent.description().to_string(),
113 supported_task_types,
114 };
115 self.metadata.insert(metadata.id.clone(), metadata);
116
117 info!(agent_id = %agent_id, agent_name = %agent_name, "Agent registered successfully");
118 }
119
120 pub fn find_agent(&self, agent_id: &str) -> Result<Arc<dyn Agent>> {
130 self.agents
131 .get(agent_id)
132 .cloned()
133 .ok_or_else(|| AgentError::not_found(agent_id))
134 }
135
136 pub fn find_agents_by_task_type(&self, task_type: TaskType) -> Vec<Arc<dyn Agent>> {
146 self.task_type_map
147 .get(&task_type)
148 .map(|agent_ids| {
149 agent_ids
150 .iter()
151 .filter_map(|id| self.agents.get(id).cloned())
152 .collect()
153 })
154 .unwrap_or_default()
155 }
156
157 pub fn all_agents(&self) -> Vec<Arc<dyn Agent>> {
163 self.agents.values().cloned().collect()
164 }
165
166 pub fn agent_count(&self) -> usize {
172 self.agents.len()
173 }
174
175 pub fn get_agent_metadata(&self, agent_id: &str) -> Option<AgentMetadataInfo> {
185 self.metadata.get(agent_id).cloned()
186 }
187
188 pub fn all_agent_metadata(&self) -> Vec<AgentMetadataInfo> {
194 self.metadata.values().cloned().collect()
195 }
196
197 pub fn has_agent(&self, agent_id: &str) -> bool {
207 self.agents.contains_key(agent_id)
208 }
209
210 pub fn agents_for_task_type(&self, task_type: TaskType) -> Vec<AgentMetadataInfo> {
220 self.task_type_map
221 .get(&task_type)
222 .map(|agent_ids| {
223 agent_ids
224 .iter()
225 .filter_map(|id| self.metadata.get(id).cloned())
226 .collect()
227 })
228 .unwrap_or_default()
229 }
230
231 pub fn discover_builtin_agents(&mut self) -> Result<()> {
237 info!("Discovering built-in agents");
238 debug!("Built-in agent discovery completed");
241 Ok(())
242 }
243
244 pub fn load_configuration(&mut self, config: HashMap<String, serde_json::Value>) -> Result<()> {
250 info!(config_count = config.len(), "Loading agent configuration");
251 debug!("Agent configuration loaded successfully");
254 Ok(())
255 }
256
257 pub fn supported_task_types(&self) -> Vec<TaskType> {
263 let mut types: Vec<TaskType> = self.task_type_map.keys().copied().collect();
264 types.sort_by_key(|t| format!("{:?}", t));
265 types
266 }
267}
268
269impl Default for AgentRegistry {
270 fn default() -> Self {
271 Self::new()
272 }
273}
274
275#[cfg(test)]
276mod tests {
277 use super::*;
278 use crate::models::{AgentInput, AgentOutput};
279
280 struct TestAgent {
281 id: String,
282 name: String,
283 description: String,
284 task_types: Vec<TaskType>,
285 }
286
287 #[async_trait::async_trait]
288 impl Agent for TestAgent {
289 fn id(&self) -> &str {
290 &self.id
291 }
292
293 fn name(&self) -> &str {
294 &self.name
295 }
296
297 fn description(&self) -> &str {
298 &self.description
299 }
300
301 fn supports(&self, task_type: TaskType) -> bool {
302 self.task_types.contains(&task_type)
303 }
304
305 async fn execute(&self, _input: AgentInput) -> Result<AgentOutput> {
306 Ok(AgentOutput::default())
307 }
308 }
309
310 #[test]
311 fn test_register_agent() {
312 let mut registry = AgentRegistry::new();
313 let agent = Arc::new(TestAgent {
314 id: "test-agent".to_string(),
315 name: "Test Agent".to_string(),
316 description: "A test agent".to_string(),
317 task_types: vec![TaskType::CodeReview],
318 });
319
320 registry.register(agent);
321 assert_eq!(registry.agent_count(), 1);
322 }
323
324 #[test]
325 fn test_find_agent_by_id() {
326 let mut registry = AgentRegistry::new();
327 let agent = Arc::new(TestAgent {
328 id: "test-agent".to_string(),
329 name: "Test Agent".to_string(),
330 description: "A test agent".to_string(),
331 task_types: vec![TaskType::CodeReview],
332 });
333
334 registry.register(agent);
335 let found = registry.find_agent("test-agent");
336 assert!(found.is_ok());
337 }
338
339 #[test]
340 fn test_find_agent_not_found() {
341 let registry = AgentRegistry::new();
342 let found = registry.find_agent("nonexistent");
343 assert!(found.is_err());
344 }
345
346 #[test]
347 fn test_find_agents_by_task_type() {
348 let mut registry = AgentRegistry::new();
349 let agent = Arc::new(TestAgent {
350 id: "test-agent".to_string(),
351 name: "Test Agent".to_string(),
352 description: "A test agent".to_string(),
353 task_types: vec![TaskType::CodeReview],
354 });
355
356 registry.register(agent);
357 let agents = registry.find_agents_by_task_type(TaskType::CodeReview);
358 assert_eq!(agents.len(), 1);
359 }
360
361 #[test]
362 fn test_get_agent_metadata() {
363 let mut registry = AgentRegistry::new();
364 let agent = Arc::new(TestAgent {
365 id: "test-agent".to_string(),
366 name: "Test Agent".to_string(),
367 description: "A test agent for metadata".to_string(),
368 task_types: vec![TaskType::CodeReview, TaskType::SecurityAnalysis],
369 });
370
371 registry.register(agent);
372 let metadata = registry.get_agent_metadata("test-agent");
373 assert!(metadata.is_some());
374
375 let meta = metadata.unwrap();
376 assert_eq!(meta.id, "test-agent");
377 assert_eq!(meta.name, "Test Agent");
378 assert_eq!(meta.description, "A test agent for metadata");
379 assert_eq!(meta.supported_task_types.len(), 2);
380 assert!(meta.supported_task_types.contains(&TaskType::CodeReview));
381 assert!(meta
382 .supported_task_types
383 .contains(&TaskType::SecurityAnalysis));
384 }
385
386 #[test]
387 fn test_all_agent_metadata() {
388 let mut registry = AgentRegistry::new();
389 let agent1 = Arc::new(TestAgent {
390 id: "agent-1".to_string(),
391 name: "Agent 1".to_string(),
392 description: "First agent".to_string(),
393 task_types: vec![TaskType::CodeReview],
394 });
395 let agent2 = Arc::new(TestAgent {
396 id: "agent-2".to_string(),
397 name: "Agent 2".to_string(),
398 description: "Second agent".to_string(),
399 task_types: vec![TaskType::TestGeneration],
400 });
401
402 registry.register(agent1);
403 registry.register(agent2);
404
405 let all_metadata = registry.all_agent_metadata();
406 assert_eq!(all_metadata.len(), 2);
407 }
408
409 #[test]
410 fn test_has_agent() {
411 let mut registry = AgentRegistry::new();
412 let agent = Arc::new(TestAgent {
413 id: "test-agent".to_string(),
414 name: "Test Agent".to_string(),
415 description: "A test agent".to_string(),
416 task_types: vec![TaskType::CodeReview],
417 });
418
419 registry.register(agent);
420 assert!(registry.has_agent("test-agent"));
421 assert!(!registry.has_agent("nonexistent"));
422 }
423
424 #[test]
425 fn test_agents_for_task_type() {
426 let mut registry = AgentRegistry::new();
427 let agent1 = Arc::new(TestAgent {
428 id: "agent-1".to_string(),
429 name: "Agent 1".to_string(),
430 description: "First agent".to_string(),
431 task_types: vec![TaskType::CodeReview],
432 });
433 let agent2 = Arc::new(TestAgent {
434 id: "agent-2".to_string(),
435 name: "Agent 2".to_string(),
436 description: "Second agent".to_string(),
437 task_types: vec![TaskType::CodeReview, TaskType::SecurityAnalysis],
438 });
439
440 registry.register(agent1);
441 registry.register(agent2);
442
443 let code_review_agents = registry.agents_for_task_type(TaskType::CodeReview);
444 assert_eq!(code_review_agents.len(), 2);
445
446 let security_agents = registry.agents_for_task_type(TaskType::SecurityAnalysis);
447 assert_eq!(security_agents.len(), 1);
448
449 let doc_agents = registry.agents_for_task_type(TaskType::Documentation);
450 assert_eq!(doc_agents.len(), 0);
451 }
452
453 #[test]
454 fn test_multiple_agents_same_task_type() {
455 let mut registry = AgentRegistry::new();
456 let agent1 = Arc::new(TestAgent {
457 id: "agent-1".to_string(),
458 name: "Agent 1".to_string(),
459 description: "First agent".to_string(),
460 task_types: vec![TaskType::CodeReview],
461 });
462 let agent2 = Arc::new(TestAgent {
463 id: "agent-2".to_string(),
464 name: "Agent 2".to_string(),
465 description: "Second agent".to_string(),
466 task_types: vec![TaskType::CodeReview],
467 });
468
469 registry.register(agent1);
470 registry.register(agent2);
471
472 let agents = registry.find_agents_by_task_type(TaskType::CodeReview);
473 assert_eq!(agents.len(), 2);
474 }
475
476 #[test]
477 fn test_agent_metadata_serialization() {
478 let metadata = AgentMetadataInfo {
479 id: "test-agent".to_string(),
480 name: "Test Agent".to_string(),
481 description: "A test agent".to_string(),
482 supported_task_types: vec![TaskType::CodeReview, TaskType::SecurityAnalysis],
483 };
484
485 let json = serde_json::to_string(&metadata).expect("serialization failed");
486 let deserialized: AgentMetadataInfo =
487 serde_json::from_str(&json).expect("deserialization failed");
488
489 assert_eq!(deserialized.id, metadata.id);
490 assert_eq!(deserialized.name, metadata.name);
491 assert_eq!(deserialized.description, metadata.description);
492 assert_eq!(
493 deserialized.supported_task_types,
494 metadata.supported_task_types
495 );
496 }
497
498 #[test]
499 fn test_discover_builtin_agents() {
500 let mut registry = AgentRegistry::new();
501 let result = registry.discover_builtin_agents();
502 assert!(result.is_ok());
503 }
504
505 #[test]
506 fn test_load_configuration() {
507 let mut registry = AgentRegistry::new();
508 let mut config = HashMap::new();
509 config.insert("agent-1".to_string(), serde_json::json!({"enabled": true}));
510
511 let result = registry.load_configuration(config);
512 assert!(result.is_ok());
513 }
514
515 #[test]
516 fn test_supported_task_types() {
517 let mut registry = AgentRegistry::new();
518 let agent1 = Arc::new(TestAgent {
519 id: "agent-1".to_string(),
520 name: "Agent 1".to_string(),
521 description: "First agent".to_string(),
522 task_types: vec![TaskType::CodeReview],
523 });
524 let agent2 = Arc::new(TestAgent {
525 id: "agent-2".to_string(),
526 name: "Agent 2".to_string(),
527 description: "Second agent".to_string(),
528 task_types: vec![TaskType::TestGeneration, TaskType::SecurityAnalysis],
529 });
530
531 registry.register(agent1);
532 registry.register(agent2);
533
534 let supported = registry.supported_task_types();
535 assert!(supported.contains(&TaskType::CodeReview));
536 assert!(supported.contains(&TaskType::TestGeneration));
537 assert!(supported.contains(&TaskType::SecurityAnalysis));
538 assert!(!supported.contains(&TaskType::Documentation));
539 }
540
541 #[test]
542 fn test_registry_empty_discovery() {
543 let registry = AgentRegistry::new();
544 assert_eq!(registry.agent_count(), 0);
545 assert!(registry.all_agent_metadata().is_empty());
546 assert!(registry.supported_task_types().is_empty());
547 }
548
549 #[test]
550 fn test_registry_with_multiple_agents() {
551 let mut registry = AgentRegistry::new();
552 let agents: Vec<Arc<dyn Agent>> = (1..=5)
553 .map(|i| {
554 Arc::new(TestAgent {
555 id: format!("agent-{}", i),
556 name: format!("Agent {}", i),
557 description: format!("Test agent {}", i),
558 task_types: vec![TaskType::CodeReview],
559 }) as Arc<dyn Agent>
560 })
561 .collect();
562
563 for agent in agents {
564 registry.register(agent);
565 }
566
567 assert_eq!(registry.agent_count(), 5);
568 assert_eq!(registry.all_agent_metadata().len(), 5);
569 }
570}