1use async_trait::async_trait;
4use core::fmt;
5use serde::{Deserialize, Serialize};
6
7#[cfg(not(feature = "std"))]
8use alloc::{
9 boxed::Box,
10 string::{String, ToString},
11 vec::Vec,
12};
13
14use crate::error::Result;
15
16pub type AgentId = String;
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
21pub enum AgentStatus {
22 Idle,
24 Running,
26 Busy,
28 Offline,
30 Error,
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct AgentConfig {
37 pub id: AgentId,
39 pub capabilities: Vec<String>,
41 pub max_concurrent_tasks: usize,
43 pub resource_limits: Option<ResourceRequirements>,
45}
46
47#[async_trait]
49pub trait Agent: Send + Sync {
50 type Input: Send;
52
53 type Output: Send;
55
56 type Error: fmt::Debug + Send;
58
59 async fn process(
61 &mut self,
62 input: Self::Input,
63 ) -> core::result::Result<Self::Output, Self::Error>;
64
65 fn capabilities(&self) -> &[String];
67
68 fn id(&self) -> &str;
70
71 fn metadata(&self) -> AgentMetadata {
73 AgentMetadata::default()
74 }
75
76 fn has_capability(&self, capability: &str) -> bool {
78 self.capabilities().iter().any(|c| c == capability)
79 }
80
81 async fn health_check(&self) -> Result<HealthStatus> {
83 Ok(HealthStatus::Healthy)
84 }
85
86 fn status(&self) -> AgentStatus {
88 AgentStatus::Running
89 }
90
91 fn can_handle(&self, task: &crate::task::Task) -> bool {
93 task.required_capabilities
94 .iter()
95 .all(|cap| self.has_capability(cap))
96 }
97
98 async fn start(&mut self) -> Result<()> {
100 self.initialize().await
101 }
102
103 async fn initialize(&mut self) -> Result<()> {
105 Ok(())
106 }
107
108 async fn shutdown(&mut self) -> Result<()> {
110 Ok(())
111 }
112}
113
114#[derive(Debug, Clone, Serialize, Deserialize)]
116pub struct AgentMetadata {
117 pub name: String,
119
120 pub version: String,
122
123 pub description: String,
125
126 pub cognitive_pattern: CognitivePattern,
128
129 pub resources: ResourceRequirements,
131
132 pub metrics: AgentMetrics,
134}
135
136impl Default for AgentMetadata {
137 fn default() -> Self {
138 AgentMetadata {
139 name: "Unknown".to_string(),
140 version: "0.0.0".to_string(),
141 description: "No description".to_string(),
142 cognitive_pattern: CognitivePattern::Convergent,
143 resources: ResourceRequirements::default(),
144 metrics: AgentMetrics::default(),
145 }
146 }
147}
148
149#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
151pub enum CognitivePattern {
152 Convergent,
154 Divergent,
156 Lateral,
158 Systems,
160 Critical,
162 Abstract,
164}
165
166impl CognitivePattern {
167 pub fn all() -> &'static [CognitivePattern] {
169 &[
170 CognitivePattern::Convergent,
171 CognitivePattern::Divergent,
172 CognitivePattern::Lateral,
173 CognitivePattern::Systems,
174 CognitivePattern::Critical,
175 CognitivePattern::Abstract,
176 ]
177 }
178
179 #[must_use]
181 pub fn complement(&self) -> CognitivePattern {
182 match self {
183 CognitivePattern::Convergent => CognitivePattern::Divergent,
184 CognitivePattern::Divergent => CognitivePattern::Convergent,
185 CognitivePattern::Lateral => CognitivePattern::Systems,
186 CognitivePattern::Systems => CognitivePattern::Lateral,
187 CognitivePattern::Critical => CognitivePattern::Abstract,
188 CognitivePattern::Abstract => CognitivePattern::Critical,
189 }
190 }
191}
192
193#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
195pub enum HealthStatus {
196 Healthy,
198 Degraded,
200 Unhealthy,
202 Stopping,
204}
205
206#[derive(Debug, Clone, Serialize, Deserialize)]
208pub struct ResourceRequirements {
209 pub min_memory_mb: u32,
211
212 pub max_memory_mb: u32,
214
215 pub cpu_cores: f32,
217
218 pub requires_gpu: bool,
220
221 pub network_bandwidth_mbps: u32,
223}
224
225impl Default for ResourceRequirements {
226 fn default() -> Self {
227 ResourceRequirements {
228 min_memory_mb: 128,
229 max_memory_mb: 512,
230 cpu_cores: 0.5,
231 requires_gpu: false,
232 network_bandwidth_mbps: 10,
233 }
234 }
235}
236
237#[derive(Debug, Clone, Serialize, Deserialize)]
239pub struct AgentMetrics {
240 pub tasks_processed: u64,
242
243 pub tasks_succeeded: u64,
245
246 pub tasks_failed: u64,
248
249 pub avg_processing_time_ms: f64,
251
252 pub queue_size: usize,
254
255 #[cfg(feature = "std")]
257 pub uptime_seconds: u64,
258}
259
260impl Default for AgentMetrics {
261 fn default() -> Self {
262 AgentMetrics {
263 tasks_processed: 0,
264 tasks_succeeded: 0,
265 tasks_failed: 0,
266 avg_processing_time_ms: 0.0,
267 queue_size: 0,
268 #[cfg(feature = "std")]
269 uptime_seconds: 0,
270 }
271 }
272}
273
274pub type BoxedAgent<I, O, E> = Box<dyn Agent<Input = I, Output = O, Error = E>>;
276
277#[async_trait]
279pub trait ErasedAgent: Send + Sync {
280 fn id(&self) -> &str;
282
283 fn capabilities(&self) -> &[String];
285
286 #[inline]
288 fn has_capability(&self, capability: &str) -> bool {
289 self.capabilities().iter().any(|c| c == capability)
290 }
291
292 fn status(&self) -> AgentStatus;
294
295 fn can_handle(&self, task: &crate::task::Task) -> bool {
297 task.required_capabilities
298 .iter()
299 .all(|cap| self.has_capability(cap))
300 }
301
302 fn metadata(&self) -> AgentMetadata {
304 AgentMetadata::default()
305 }
306
307 async fn health_check(&self) -> Result<HealthStatus> {
309 Ok(HealthStatus::Healthy)
310 }
311
312 async fn start(&mut self) -> Result<()> {
314 Ok(())
315 }
316
317 async fn shutdown(&mut self) -> Result<()> {
319 Ok(())
320 }
321
322 async fn process_json(&mut self, input: serde_json::Value) -> Result<serde_json::Value>;
324}
325
326pub struct DynamicAgent {
328 id: String,
329 capabilities: Vec<String>,
330 metadata: AgentMetadata,
331 status: AgentStatus,
332 processor: Box<dyn AgentProcessor>,
333}
334
335impl DynamicAgent {
336 pub fn new(id: impl Into<String>, capabilities: Vec<String>) -> Self {
338 DynamicAgent {
339 id: id.into(),
340 capabilities,
341 metadata: AgentMetadata::default(),
342 status: AgentStatus::Running,
343 processor: Box::new(DefaultProcessor),
344 }
345 }
346
347 pub fn id(&self) -> &str {
349 &self.id
350 }
351
352 pub fn capabilities(&self) -> &[String] {
354 &self.capabilities
355 }
356
357 pub fn status(&self) -> AgentStatus {
359 self.status
360 }
361
362 pub fn set_status(&mut self, status: AgentStatus) {
364 self.status = status;
365 }
366
367 pub fn can_handle(&self, task: &crate::task::Task) -> bool {
369 task.required_capabilities
370 .iter()
371 .all(|cap| self.capabilities.contains(cap))
372 }
373
374 pub fn has_capability(&self, capability: &str) -> bool {
376 self.capabilities.iter().any(|c| c == capability)
377 }
378
379 #[allow(clippy::unused_async)]
385 pub async fn start(&mut self) -> crate::error::Result<()> {
386 self.status = AgentStatus::Running;
387 Ok(())
388 }
389
390 #[allow(clippy::unused_async)]
396 pub async fn shutdown(&mut self) -> crate::error::Result<()> {
397 self.status = AgentStatus::Offline;
398 Ok(())
399 }
400}
401
402struct DefaultProcessor;
404
405#[async_trait]
406impl AgentProcessor for DefaultProcessor {
407 async fn process_dynamic(
408 &mut self,
409 input: serde_json::Value,
410 ) -> crate::error::Result<serde_json::Value> {
411 Ok(input)
412 }
413}
414
415#[async_trait]
417trait AgentProcessor: Send + Sync {
418 async fn process_dynamic(&mut self, input: serde_json::Value) -> Result<serde_json::Value>;
419}
420
421#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
423pub struct Capability {
424 pub name: String,
426 pub version: String,
428}
429
430impl Capability {
431 pub fn new(name: impl Into<String>, version: impl Into<String>) -> Self {
433 Self {
434 name: name.into(),
435 version: version.into(),
436 }
437 }
438}
439
440#[cfg(test)]
441pub struct MockAgent {
443 id: String,
444 status: AgentStatus,
445 capabilities: Vec<Capability>,
446 process_result: Option<crate::error::Result<crate::task::TaskResult>>,
447}
448
449#[cfg(test)]
450impl MockAgent {
451 pub fn new(id: impl Into<String>) -> Self {
453 Self {
454 id: id.into(),
455 status: AgentStatus::Idle,
456 capabilities: Vec::new(),
457 process_result: None,
458 }
459 }
460
461 #[must_use]
463 pub fn with_capabilities(mut self, capabilities: Vec<Capability>) -> Self {
464 self.capabilities = capabilities;
465 self
466 }
467
468 #[must_use]
470 pub fn with_process_result(mut self, result: crate::error::Result<crate::task::TaskResult>) -> Self {
471 self.process_result = Some(result);
472 self
473 }
474
475 pub fn id(&self) -> &str {
477 &self.id
478 }
479
480 pub fn status(&self) -> AgentStatus {
482 self.status
483 }
484
485 pub fn capabilities(&self) -> &[Capability] {
487 &self.capabilities
488 }
489
490 pub fn can_handle(&self, task: &crate::task::Task) -> bool {
492 task.required_capabilities
493 .iter()
494 .all(|cap| self.capabilities.iter().any(|c| &c.name == cap))
495 }
496
497 #[allow(clippy::unused_async)]
503 pub async fn start(&mut self) -> crate::error::Result<()> {
504 self.status = AgentStatus::Running;
505 Ok(())
506 }
507
508 #[allow(clippy::unused_async)]
514 pub async fn shutdown(&mut self) -> crate::error::Result<()> {
515 self.status = AgentStatus::Offline;
516 Ok(())
517 }
518
519 #[allow(clippy::unused_async)]
525 pub async fn process(&mut self, _task: crate::task::Task) -> crate::error::Result<crate::task::TaskResult> {
526 if let Some(result) = &self.process_result {
527 result.clone()
528 } else {
529 Ok(crate::task::TaskResult::success("Mock processing complete"))
530 }
531 }
532
533 pub fn metrics(&self) -> AgentMetrics {
535 AgentMetrics::default()
536 }
537
538 #[allow(clippy::unused_async)]
544 pub async fn health_check(&self) -> crate::error::Result<HealthStatus> {
545 Ok(HealthStatus::Healthy)
546 }
547
548 pub fn metadata(&self) -> AgentMetadata {
550 AgentMetadata::default()
551 }
552}
553
554#[derive(Debug, Clone, Serialize, Deserialize)]
556pub struct AgentMessage<T> {
557 pub from: String,
559
560 pub to: String,
562
563 pub payload: T,
565
566 pub msg_type: MessageType,
568
569 pub correlation_id: Option<String>,
571}
572
573#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
575pub enum MessageType {
576 TaskAssignment,
578 TaskResult,
580 StatusUpdate,
582 Coordination,
584 Error,
586}
587
588#[cfg(test)]
589mod tests {
590 use super::*;
591
592 #[test]
593 fn test_cognitive_pattern_complement() {
594 assert_eq!(
595 CognitivePattern::Convergent.complement(),
596 CognitivePattern::Divergent
597 );
598 assert_eq!(
599 CognitivePattern::Divergent.complement(),
600 CognitivePattern::Convergent
601 );
602 assert_eq!(
603 CognitivePattern::Lateral.complement(),
604 CognitivePattern::Systems
605 );
606 }
607
608 #[test]
609 fn test_agent_metadata_default() {
610 let metadata = AgentMetadata::default();
611 assert_eq!(metadata.name, "Unknown");
612 assert_eq!(metadata.cognitive_pattern, CognitivePattern::Convergent);
613 }
614}