ricecoder_agents/domain/
registry.rs

1//! Domain registry for discovering and managing domain agents
2
3use crate::domain::error::{DomainError, DomainResult};
4use crate::domain::models::{DomainAgent, DomainCapability};
5use std::collections::HashMap;
6use std::sync::{Arc, RwLock};
7
8/// Registry for domain agents
9///
10/// This struct manages the registration and discovery of domain agents.
11/// It supports auto-discovery of domains from configuration files and
12/// provides agent lookup by domain type.
13///
14/// # Examples
15///
16/// ```ignore
17/// use ricecoder_agents::domain::DomainRegistry;
18///
19/// let registry = DomainRegistry::new();
20/// registry.register_agent("web", agent);
21/// let agent = registry.get_agent("web")?;
22/// ```
23#[derive(Debug, Clone)]
24pub struct DomainRegistry {
25    agents: Arc<RwLock<HashMap<String, DomainAgent>>>,
26}
27
28impl DomainRegistry {
29    /// Create a new domain registry
30    pub fn new() -> Self {
31        Self {
32            agents: Arc::new(RwLock::new(HashMap::new())),
33        }
34    }
35
36    /// Register a domain agent
37    ///
38    /// # Arguments
39    ///
40    /// * `domain` - Domain identifier (e.g., "web", "backend", "devops")
41    /// * `agent` - Domain agent to register
42    ///
43    /// # Examples
44    ///
45    /// ```ignore
46    /// registry.register_agent("web", web_agent);
47    /// ```
48    pub fn register_agent(&self, domain: &str, agent: DomainAgent) -> DomainResult<()> {
49        let mut agents = self
50            .agents
51            .write()
52            .map_err(|e| DomainError::internal(format!("Failed to acquire write lock: {}", e)))?;
53
54        agents.insert(domain.to_string(), agent);
55        Ok(())
56    }
57
58    /// Get a domain agent by domain type
59    ///
60    /// # Arguments
61    ///
62    /// * `domain` - Domain identifier
63    ///
64    /// # Returns
65    ///
66    /// Returns the domain agent if found, otherwise returns an error
67    ///
68    /// # Examples
69    ///
70    /// ```ignore
71    /// let agent = registry.get_agent("web")?;
72    /// ```
73    pub fn get_agent(&self, domain: &str) -> DomainResult<DomainAgent> {
74        let agents = self
75            .agents
76            .read()
77            .map_err(|e| DomainError::internal(format!("Failed to acquire read lock: {}", e)))?;
78
79        agents
80            .get(domain)
81            .cloned()
82            .ok_or_else(|| DomainError::agent_not_found(domain))
83    }
84
85    /// Discover all registered domains
86    ///
87    /// # Returns
88    ///
89    /// Returns a vector of all registered domain identifiers
90    ///
91    /// # Examples
92    ///
93    /// ```ignore
94    /// let domains = registry.discover_domains()?;
95    /// ```
96    pub fn discover_domains(&self) -> DomainResult<Vec<String>> {
97        let agents = self
98            .agents
99            .read()
100            .map_err(|e| DomainError::internal(format!("Failed to acquire read lock: {}", e)))?;
101
102        Ok(agents.keys().cloned().collect())
103    }
104
105    /// List capabilities for a domain
106    ///
107    /// # Arguments
108    ///
109    /// * `domain` - Domain identifier
110    ///
111    /// # Returns
112    ///
113    /// Returns a vector of capabilities for the domain
114    ///
115    /// # Examples
116    ///
117    /// ```ignore
118    /// let capabilities = registry.list_capabilities("web")?;
119    /// ```
120    pub fn list_capabilities(&self, domain: &str) -> DomainResult<Vec<DomainCapability>> {
121        let agent = self.get_agent(domain)?;
122        Ok(agent.capabilities)
123    }
124
125    /// Check if a domain is registered
126    ///
127    /// # Arguments
128    ///
129    /// * `domain` - Domain identifier
130    ///
131    /// # Returns
132    ///
133    /// Returns true if the domain is registered, false otherwise
134    pub fn has_domain(&self, domain: &str) -> DomainResult<bool> {
135        let agents = self
136            .agents
137            .read()
138            .map_err(|e| DomainError::internal(format!("Failed to acquire read lock: {}", e)))?;
139
140        Ok(agents.contains_key(domain))
141    }
142
143    /// Get all registered agents
144    ///
145    /// # Returns
146    ///
147    /// Returns a vector of all registered domain agents
148    pub fn get_all_agents(&self) -> DomainResult<Vec<DomainAgent>> {
149        let agents = self
150            .agents
151            .read()
152            .map_err(|e| DomainError::internal(format!("Failed to acquire read lock: {}", e)))?;
153
154        Ok(agents.values().cloned().collect())
155    }
156
157    /// Clear all registered agents
158    pub fn clear(&self) -> DomainResult<()> {
159        let mut agents = self
160            .agents
161            .write()
162            .map_err(|e| DomainError::internal(format!("Failed to acquire write lock: {}", e)))?;
163
164        agents.clear();
165        Ok(())
166    }
167
168    /// Get the number of registered domains
169    pub fn domain_count(&self) -> DomainResult<usize> {
170        let agents = self
171            .agents
172            .read()
173            .map_err(|e| DomainError::internal(format!("Failed to acquire read lock: {}", e)))?;
174
175        Ok(agents.len())
176    }
177}
178
179impl Default for DomainRegistry {
180    fn default() -> Self {
181        Self::new()
182    }
183}
184
185#[cfg(test)]
186mod tests {
187    use super::*;
188    use crate::domain::models::{DomainKnowledge, DomainAgent};
189
190    fn create_test_agent(domain: &str) -> DomainAgent {
191        DomainAgent {
192            id: format!("{}-agent", domain),
193            domain: domain.to_string(),
194            capabilities: vec![],
195            knowledge: DomainKnowledge::default(),
196        }
197    }
198
199    #[test]
200    fn test_registry_creation() {
201        let registry = DomainRegistry::new();
202        assert!(registry.discover_domains().unwrap().is_empty());
203    }
204
205    #[test]
206    fn test_register_agent() {
207        let registry = DomainRegistry::new();
208        let agent = create_test_agent("web");
209
210        registry.register_agent("web", agent).unwrap();
211        assert!(registry.has_domain("web").unwrap());
212    }
213
214    #[test]
215    fn test_get_agent() {
216        let registry = DomainRegistry::new();
217        let agent = create_test_agent("web");
218
219        registry.register_agent("web", agent.clone()).unwrap();
220        let retrieved = registry.get_agent("web").unwrap();
221
222        assert_eq!(retrieved.id, agent.id);
223        assert_eq!(retrieved.domain, agent.domain);
224    }
225
226    #[test]
227    fn test_get_nonexistent_agent() {
228        let registry = DomainRegistry::new();
229        let result = registry.get_agent("nonexistent");
230
231        assert!(result.is_err());
232        assert!(matches!(result.unwrap_err(), DomainError::AgentNotFound(_)));
233    }
234
235    #[test]
236    fn test_discover_domains() {
237        let registry = DomainRegistry::new();
238
239        registry.register_agent("web", create_test_agent("web")).unwrap();
240        registry.register_agent("backend", create_test_agent("backend")).unwrap();
241        registry.register_agent("devops", create_test_agent("devops")).unwrap();
242
243        let domains = registry.discover_domains().unwrap();
244        assert_eq!(domains.len(), 3);
245        assert!(domains.contains(&"web".to_string()));
246        assert!(domains.contains(&"backend".to_string()));
247        assert!(domains.contains(&"devops".to_string()));
248    }
249
250    #[test]
251    fn test_list_capabilities() {
252        let registry = DomainRegistry::new();
253        let agent = create_test_agent("web");
254
255        registry.register_agent("web", agent).unwrap();
256        let capabilities = registry.list_capabilities("web").unwrap();
257
258        assert!(capabilities.is_empty());
259    }
260
261    #[test]
262    fn test_has_domain() {
263        let registry = DomainRegistry::new();
264
265        registry.register_agent("web", create_test_agent("web")).unwrap();
266
267        assert!(registry.has_domain("web").unwrap());
268        assert!(!registry.has_domain("backend").unwrap());
269    }
270
271    #[test]
272    fn test_get_all_agents() {
273        let registry = DomainRegistry::new();
274
275        registry.register_agent("web", create_test_agent("web")).unwrap();
276        registry.register_agent("backend", create_test_agent("backend")).unwrap();
277
278        let agents = registry.get_all_agents().unwrap();
279        assert_eq!(agents.len(), 2);
280    }
281
282    #[test]
283    fn test_clear() {
284        let registry = DomainRegistry::new();
285
286        registry.register_agent("web", create_test_agent("web")).unwrap();
287        registry.register_agent("backend", create_test_agent("backend")).unwrap();
288
289        assert_eq!(registry.domain_count().unwrap(), 2);
290
291        registry.clear().unwrap();
292        assert_eq!(registry.domain_count().unwrap(), 0);
293    }
294
295    #[test]
296    fn test_domain_count() {
297        let registry = DomainRegistry::new();
298
299        assert_eq!(registry.domain_count().unwrap(), 0);
300
301        registry.register_agent("web", create_test_agent("web")).unwrap();
302        assert_eq!(registry.domain_count().unwrap(), 1);
303
304        registry.register_agent("backend", create_test_agent("backend")).unwrap();
305        assert_eq!(registry.domain_count().unwrap(), 2);
306    }
307
308    #[test]
309    fn test_register_multiple_agents() {
310        let registry = DomainRegistry::new();
311
312        registry.register_agent("web", create_test_agent("web")).unwrap();
313        registry.register_agent("backend", create_test_agent("backend")).unwrap();
314        registry.register_agent("devops", create_test_agent("devops")).unwrap();
315
316        assert_eq!(registry.domain_count().unwrap(), 3);
317    }
318
319    #[test]
320    fn test_overwrite_agent() {
321        let registry = DomainRegistry::new();
322
323        let agent1 = create_test_agent("web");
324        registry.register_agent("web", agent1).unwrap();
325
326        let mut agent2 = create_test_agent("web");
327        agent2.id = "web-agent-v2".to_string();
328        registry.register_agent("web", agent2).unwrap();
329
330        let retrieved = registry.get_agent("web").unwrap();
331        assert_eq!(retrieved.id, "web-agent-v2");
332    }
333
334    #[test]
335    fn test_default_registry() {
336        let registry = DomainRegistry::default();
337        assert_eq!(registry.domain_count().unwrap(), 0);
338    }
339}