1use crate::error::Result;
4use crate::models::{DomainAgentConfig, DomainAgentMetadata};
5use async_trait::async_trait;
6use serde::{Deserialize, Serialize};
7use std::collections::HashMap;
8use tracing::debug;
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct DomainAgentInput {
13 pub domain: String,
15 pub task: String,
17 pub context: String,
19 pub parameters: HashMap<String, serde_json::Value>,
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
25pub struct DomainAgentOutput {
26 pub domain: String,
28 pub response: String,
30 pub suggestions: Vec<String>,
32 pub confidence: f32,
34 pub metadata: HashMap<String, serde_json::Value>,
36}
37
38#[async_trait]
40pub trait DomainAgent: Send + Sync {
41 fn metadata(&self) -> &DomainAgentMetadata;
43
44 fn config(&self) -> &DomainAgentConfig;
46
47 async fn execute(&self, input: DomainAgentInput) -> Result<DomainAgentOutput>;
49
50 fn validate_input(&self, input: &DomainAgentInput) -> Result<()>;
52}
53
54pub struct FrontendAgent {
56 metadata: DomainAgentMetadata,
57 config: DomainAgentConfig,
58}
59
60impl FrontendAgent {
61 pub fn new() -> Self {
63 Self {
64 metadata: DomainAgentMetadata {
65 domain: "frontend".to_string(),
66 name: "Frontend Agent".to_string(),
67 version: "1.0.0".to_string(),
68 capabilities: vec![
69 "component-design".to_string(),
70 "state-management".to_string(),
71 "performance-optimization".to_string(),
72 "accessibility".to_string(),
73 ],
74 required_tools: vec!["code-analysis".to_string()],
75 optional_tools: vec!["performance-profiling".to_string()],
76 },
77 config: DomainAgentConfig {
78 domain: "frontend".to_string(),
79 name: "Frontend Agent".to_string(),
80 description: "Specialized agent for frontend development".to_string(),
81 system_prompt: "You are an expert frontend developer specializing in React, Vue, and Angular. Provide best practices for component design, state management, and performance optimization.".to_string(),
82 tools: vec!["code-analysis".to_string(), "performance-profiling".to_string()],
83 model: None,
84 temperature: Some(0.7),
85 max_tokens: Some(2000),
86 custom_config: HashMap::new(),
87 },
88 }
89 }
90}
91
92impl Default for FrontendAgent {
93 fn default() -> Self {
94 Self::new()
95 }
96}
97
98#[async_trait]
99impl DomainAgent for FrontendAgent {
100 fn metadata(&self) -> &DomainAgentMetadata {
101 &self.metadata
102 }
103
104 fn config(&self) -> &DomainAgentConfig {
105 &self.config
106 }
107
108 async fn execute(&self, input: DomainAgentInput) -> Result<DomainAgentOutput> {
109 debug!("Frontend agent executing task: {}", input.task);
110
111 self.validate_input(&input)?;
112
113 Ok(DomainAgentOutput {
114 domain: "frontend".to_string(),
115 response: format!("Frontend analysis for: {}", input.task),
116 suggestions: vec![
117 "Consider using React hooks for state management".to_string(),
118 "Implement proper error boundaries".to_string(),
119 "Optimize component re-renders".to_string(),
120 ],
121 confidence: 0.85,
122 metadata: HashMap::new(),
123 })
124 }
125
126 fn validate_input(&self, input: &DomainAgentInput) -> Result<()> {
127 if input.domain != "frontend" {
128 return Err(crate::error::DomainAgentError::InvalidConfiguration(
129 "Domain mismatch".to_string(),
130 ));
131 }
132 Ok(())
133 }
134}
135
136pub struct BackendAgent {
138 metadata: DomainAgentMetadata,
139 config: DomainAgentConfig,
140}
141
142impl BackendAgent {
143 pub fn new() -> Self {
145 Self {
146 metadata: DomainAgentMetadata {
147 domain: "backend".to_string(),
148 name: "Backend Agent".to_string(),
149 version: "1.0.0".to_string(),
150 capabilities: vec![
151 "api-design".to_string(),
152 "database-optimization".to_string(),
153 "security".to_string(),
154 "scalability".to_string(),
155 ],
156 required_tools: vec!["code-analysis".to_string()],
157 optional_tools: vec!["performance-profiling".to_string()],
158 },
159 config: DomainAgentConfig {
160 domain: "backend".to_string(),
161 name: "Backend Agent".to_string(),
162 description: "Specialized agent for backend development".to_string(),
163 system_prompt: "You are an expert backend developer specializing in Node.js, Python, and Go. Provide best practices for API design, database optimization, and security.".to_string(),
164 tools: vec!["code-analysis".to_string(), "performance-profiling".to_string()],
165 model: None,
166 temperature: Some(0.7),
167 max_tokens: Some(2000),
168 custom_config: HashMap::new(),
169 },
170 }
171 }
172}
173
174impl Default for BackendAgent {
175 fn default() -> Self {
176 Self::new()
177 }
178}
179
180#[async_trait]
181impl DomainAgent for BackendAgent {
182 fn metadata(&self) -> &DomainAgentMetadata {
183 &self.metadata
184 }
185
186 fn config(&self) -> &DomainAgentConfig {
187 &self.config
188 }
189
190 async fn execute(&self, input: DomainAgentInput) -> Result<DomainAgentOutput> {
191 debug!("Backend agent executing task: {}", input.task);
192
193 self.validate_input(&input)?;
194
195 Ok(DomainAgentOutput {
196 domain: "backend".to_string(),
197 response: format!("Backend analysis for: {}", input.task),
198 suggestions: vec![
199 "Implement proper error handling".to_string(),
200 "Add database indexing for performance".to_string(),
201 "Use connection pooling".to_string(),
202 ],
203 confidence: 0.88,
204 metadata: HashMap::new(),
205 })
206 }
207
208 fn validate_input(&self, input: &DomainAgentInput) -> Result<()> {
209 if input.domain != "backend" {
210 return Err(crate::error::DomainAgentError::InvalidConfiguration(
211 "Domain mismatch".to_string(),
212 ));
213 }
214 Ok(())
215 }
216}
217
218pub struct DevOpsAgent {
220 metadata: DomainAgentMetadata,
221 config: DomainAgentConfig,
222}
223
224impl DevOpsAgent {
225 pub fn new() -> Self {
227 Self {
228 metadata: DomainAgentMetadata {
229 domain: "devops".to_string(),
230 name: "DevOps Agent".to_string(),
231 version: "1.0.0".to_string(),
232 capabilities: vec![
233 "infrastructure-design".to_string(),
234 "deployment".to_string(),
235 "monitoring".to_string(),
236 "security".to_string(),
237 ],
238 required_tools: vec!["infrastructure-analysis".to_string()],
239 optional_tools: vec!["monitoring-setup".to_string()],
240 },
241 config: DomainAgentConfig {
242 domain: "devops".to_string(),
243 name: "DevOps Agent".to_string(),
244 description: "Specialized agent for DevOps and infrastructure".to_string(),
245 system_prompt: "You are an expert DevOps engineer specializing in Kubernetes, Docker, and cloud infrastructure. Provide best practices for deployment, monitoring, and security.".to_string(),
246 tools: vec!["infrastructure-analysis".to_string(), "monitoring-setup".to_string()],
247 model: None,
248 temperature: Some(0.7),
249 max_tokens: Some(2000),
250 custom_config: HashMap::new(),
251 },
252 }
253 }
254}
255
256impl Default for DevOpsAgent {
257 fn default() -> Self {
258 Self::new()
259 }
260}
261
262#[async_trait]
263impl DomainAgent for DevOpsAgent {
264 fn metadata(&self) -> &DomainAgentMetadata {
265 &self.metadata
266 }
267
268 fn config(&self) -> &DomainAgentConfig {
269 &self.config
270 }
271
272 async fn execute(&self, input: DomainAgentInput) -> Result<DomainAgentOutput> {
273 debug!("DevOps agent executing task: {}", input.task);
274
275 self.validate_input(&input)?;
276
277 Ok(DomainAgentOutput {
278 domain: "devops".to_string(),
279 response: format!("DevOps analysis for: {}", input.task),
280 suggestions: vec![
281 "Implement infrastructure as code".to_string(),
282 "Set up proper monitoring and alerting".to_string(),
283 "Use container orchestration".to_string(),
284 ],
285 confidence: 0.82,
286 metadata: HashMap::new(),
287 })
288 }
289
290 fn validate_input(&self, input: &DomainAgentInput) -> Result<()> {
291 if input.domain != "devops" {
292 return Err(crate::error::DomainAgentError::InvalidConfiguration(
293 "Domain mismatch".to_string(),
294 ));
295 }
296 Ok(())
297 }
298}
299
300#[cfg(test)]
301mod tests {
302 use super::*;
303
304 #[tokio::test]
305 async fn test_frontend_agent_creation() {
306 let agent = FrontendAgent::new();
307 assert_eq!(agent.metadata().domain, "frontend");
308 assert_eq!(agent.config().domain, "frontend");
309 }
310
311 #[tokio::test]
312 async fn test_backend_agent_creation() {
313 let agent = BackendAgent::new();
314 assert_eq!(agent.metadata().domain, "backend");
315 assert_eq!(agent.config().domain, "backend");
316 }
317
318 #[tokio::test]
319 async fn test_devops_agent_creation() {
320 let agent = DevOpsAgent::new();
321 assert_eq!(agent.metadata().domain, "devops");
322 assert_eq!(agent.config().domain, "devops");
323 }
324
325 #[tokio::test]
326 async fn test_frontend_agent_execution() {
327 let agent = FrontendAgent::new();
328 let input = DomainAgentInput {
329 domain: "frontend".to_string(),
330 task: "Design a React component".to_string(),
331 context: "Component for user profile".to_string(),
332 parameters: HashMap::new(),
333 };
334
335 let output = agent.execute(input).await.unwrap();
336 assert_eq!(output.domain, "frontend");
337 assert!(!output.suggestions.is_empty());
338 }
339
340 #[tokio::test]
341 async fn test_backend_agent_execution() {
342 let agent = BackendAgent::new();
343 let input = DomainAgentInput {
344 domain: "backend".to_string(),
345 task: "Design an API endpoint".to_string(),
346 context: "User management API".to_string(),
347 parameters: HashMap::new(),
348 };
349
350 let output = agent.execute(input).await.unwrap();
351 assert_eq!(output.domain, "backend");
352 assert!(!output.suggestions.is_empty());
353 }
354
355 #[tokio::test]
356 async fn test_devops_agent_execution() {
357 let agent = DevOpsAgent::new();
358 let input = DomainAgentInput {
359 domain: "devops".to_string(),
360 task: "Set up deployment pipeline".to_string(),
361 context: "Kubernetes cluster".to_string(),
362 parameters: HashMap::new(),
363 };
364
365 let output = agent.execute(input).await.unwrap();
366 assert_eq!(output.domain, "devops");
367 assert!(!output.suggestions.is_empty());
368 }
369
370 #[tokio::test]
371 async fn test_domain_mismatch_validation() {
372 let agent = FrontendAgent::new();
373 let input = DomainAgentInput {
374 domain: "backend".to_string(),
375 task: "Design a React component".to_string(),
376 context: "Component for user profile".to_string(),
377 parameters: HashMap::new(),
378 };
379
380 let result = agent.execute(input).await;
381 assert!(result.is_err());
382 }
383}