agentic_payments/agents/
mod.rs

1//! Autonomous agent implementations
2
3use crate::error::{Error, Result};
4use chrono::{DateTime, Utc};
5use serde::{Deserialize, Serialize};
6use std::time::Duration;
7use uuid::Uuid;
8
9// pub mod pool; // Deprecated - use system::AgentPool instead
10pub mod recovery;
11pub mod verification;
12
13// pub use pool::*; // Deprecated
14pub use recovery::*;
15pub use verification::*;
16
17/// Agent status
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
19pub enum AgentStatus {
20    /// Agent is healthy and ready
21    Healthy,
22    /// Agent is busy processing
23    Busy,
24    /// Agent encountered an error
25    Error,
26    /// Agent is recovering
27    Recovering,
28    /// Agent is quarantined
29    Quarantined,
30}
31
32/// Agent health metrics
33#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct AgentHealth {
35    /// Agent ID
36    pub agent_id: Uuid,
37    /// Current status
38    pub status: AgentStatus,
39    /// Total verifications performed
40    pub total_verifications: usize,
41    /// Successful verifications
42    pub successful_verifications: usize,
43    /// Failed verifications
44    pub failed_verifications: usize,
45    /// Average response time in milliseconds
46    pub avg_response_time_ms: f64,
47    /// Last heartbeat timestamp
48    pub last_heartbeat: DateTime<Utc>,
49    /// Uptime in seconds
50    pub uptime_secs: u64,
51}
52
53impl AgentHealth {
54    /// Create new agent health metrics
55    pub fn new(agent_id: Uuid) -> Self {
56        Self {
57            agent_id,
58            status: AgentStatus::Healthy,
59            total_verifications: 0,
60            successful_verifications: 0,
61            failed_verifications: 0,
62            avg_response_time_ms: 0.0,
63            last_heartbeat: Utc::now(),
64            uptime_secs: 0,
65        }
66    }
67
68    /// Update heartbeat
69    pub fn heartbeat(&mut self) {
70        self.last_heartbeat = Utc::now();
71    }
72
73    /// Record a verification
74    pub fn record_verification(&mut self, success: bool, duration: Duration) {
75        self.total_verifications += 1;
76        if success {
77            self.successful_verifications += 1;
78        } else {
79            self.failed_verifications += 1;
80        }
81
82        // Update rolling average
83        let new_time = duration.as_millis() as f64;
84        if self.total_verifications == 1 {
85            self.avg_response_time_ms = new_time;
86        } else {
87            self.avg_response_time_ms =
88                (self.avg_response_time_ms * (self.total_verifications - 1) as f64 + new_time)
89                / self.total_verifications as f64;
90        }
91    }
92
93    /// Get success rate
94    pub fn success_rate(&self) -> f64 {
95        if self.total_verifications == 0 {
96            1.0
97        } else {
98            self.successful_verifications as f64 / self.total_verifications as f64
99        }
100    }
101
102    /// Check if agent is healthy
103    pub fn is_healthy(&self) -> bool {
104        self.status == AgentStatus::Healthy && self.success_rate() >= 0.95
105    }
106}
107
108/// Trait for verification agents
109#[async_trait::async_trait]
110pub trait VerificationAgent: Send + Sync {
111    /// Get agent ID
112    fn id(&self) -> Uuid;
113
114    /// Check if agent is healthy
115    fn is_healthy(&self) -> bool;
116
117    /// Perform health check
118    async fn health_check(&self) -> Result<()> {
119        if self.is_healthy() {
120            Ok(())
121        } else {
122            Err(Error::agent_pool(format!(
123                "Agent {} is unhealthy",
124                self.id()
125            )))
126        }
127    }
128
129    /// Verify a signature
130    async fn verify(
131        &self,
132        message: &[u8],
133        signature: &[u8],
134        public_key: &ed25519_dalek::VerifyingKey,
135    ) -> Result<bool>;
136}
137
138/// Basic verification agent implementation
139#[derive(Debug)]
140pub struct BasicVerificationAgent {
141    /// Agent ID
142    pub id: Uuid,
143    /// Agent health metrics
144    pub health: std::sync::Arc<std::sync::Mutex<AgentHealth>>,
145}
146
147impl BasicVerificationAgent {
148    /// Create a new verification agent
149    pub fn new() -> Result<Self> {
150        let id = Uuid::new_v4();
151        Ok(Self {
152            id,
153            health: std::sync::Arc::new(std::sync::Mutex::new(AgentHealth::new(id))),
154        })
155    }
156}
157
158#[async_trait::async_trait]
159impl VerificationAgent for BasicVerificationAgent {
160    fn id(&self) -> Uuid {
161        self.id
162    }
163
164    fn is_healthy(&self) -> bool {
165        self.health.lock().unwrap().is_healthy()
166    }
167
168    async fn verify(
169        &self,
170        message: &[u8],
171        signature: &[u8],
172        public_key: &ed25519_dalek::VerifyingKey,
173    ) -> Result<bool> {
174        use ed25519_dalek::{Signature, Verifier};
175
176        let sig = Signature::from_bytes(signature.try_into().map_err(|_| {
177            Error::verification("Invalid signature length")
178        })?);
179
180        let start = std::time::Instant::now();
181        let result = public_key.verify(message, &sig).is_ok();
182
183        // Update health
184        let mut health = self.health.lock().unwrap();
185        health.record_verification(result, start.elapsed());
186        health.heartbeat();
187
188        Ok(result)
189    }
190}
191
192impl Default for BasicVerificationAgent {
193    fn default() -> Self {
194        Self::new().unwrap()
195    }
196}
197
198#[cfg(test)]
199mod tests {
200    use super::*;
201
202    #[test]
203    fn test_agent_creation() {
204        let agent = BasicVerificationAgent::new().unwrap();
205        assert!(agent.is_healthy());
206        // Verify agent has initialized health metrics
207        let health = agent.health.lock().unwrap();
208        assert_eq!(health.status, AgentStatus::Healthy);
209        assert_eq!(health.total_verifications, 0);
210    }
211
212    #[test]
213    fn test_health_metrics() {
214        let mut health = AgentHealth::new(Uuid::new_v4());
215
216        health.record_verification(true, Duration::from_millis(10));
217        assert_eq!(health.total_verifications, 1);
218        assert_eq!(health.successful_verifications, 1);
219        assert_eq!(health.success_rate(), 1.0);
220
221        health.record_verification(false, Duration::from_millis(20));
222        assert_eq!(health.total_verifications, 2);
223        assert_eq!(health.successful_verifications, 1);
224        assert_eq!(health.success_rate(), 0.5);
225    }
226}