anya_core/ml/
agent_checker.rs

1// [AIR-3][AIS-3][BPC-3][RES-3] Removed unused import: std::error::Error
2// AIP-002: Agent Checker System Implementation
3// Priority: CRITICAL - ML-based system analyzer with in-memory auto-save
4
5use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7use std::sync::{Arc, Mutex};
8use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
9
10/// Status threshold constants for system readiness
11const DEVELOPMENT_THRESHOLD: f64 = 0.60;
12const PRODUCTION_THRESHOLD: f64 = 0.90;
13const RELEASE_THRESHOLD: f64 = 0.99;
14
15/// Environment stage enum
16#[derive(Debug, Clone, Copy, PartialEq)]
17pub enum SystemStage {
18    Development,
19    Production,
20    Release,
21    Unavailable,
22}
23
24/// Component readiness status
25#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct ComponentStatus {
27    /// Component name
28    pub name: String,
29    /// Component status (0.0 to 1.0)
30    pub status: f64,
31    /// Last check time as timestamp (u64)
32    pub last_check: u64,
33    /// Additional metrics
34    pub metrics: HashMap<String, f64>,
35    /// List of issues
36    pub issues: Vec<String>,
37}
38
39impl ComponentStatus {
40    /// Create a new component status
41    pub fn new(
42        name: String,
43        status: f64,
44        metrics: HashMap<String, f64>,
45        issues: Vec<String>,
46    ) -> Self {
47        Self {
48            name,
49            status,
50            last_check: chrono::Utc::now().timestamp() as u64,
51            metrics,
52            issues,
53        }
54    }
55}
56
57/// System health metrics
58#[derive(Debug, Clone)]
59pub struct SystemHealth {
60    overall_status: f64,
61    stage: SystemStage,
62    components: HashMap<String, ComponentStatus>,
63    last_update: Instant,
64}
65
66/// Agent Checker main system
67pub struct AgentChecker {
68    health: Arc<Mutex<SystemHealth>>,
69    input_buffer: Arc<Mutex<Vec<String>>>,
70    input_counter: Arc<Mutex<usize>>,
71    auto_save_frequency: usize,
72    last_save: Arc<Mutex<Instant>>,
73}
74
75impl AgentChecker {
76    /// Create a new agent checker with specified auto-save frequency
77    pub fn new(auto_save_frequency: usize) -> Self {
78        let health = SystemHealth {
79            overall_status: 0.0,
80            stage: SystemStage::Unavailable,
81            components: HashMap::new(),
82            last_update: Instant::now(),
83        };
84
85        Self {
86            health: Arc::new(Mutex::new(health)),
87            input_buffer: Arc::new(Mutex::new(Vec::new())),
88            input_counter: Arc::new(Mutex::new(0)),
89            auto_save_frequency,
90            last_save: Arc::new(Mutex::new(Instant::now())),
91        }
92    }
93
94    /// Process input and auto-save every Nth input
95    pub fn process_input(&self, input: &str) -> Result<(), String> {
96        // Add input to buffer
97        {
98            let mut buffer = match self.input_buffer.lock() {
99                Ok(guard) => guard,
100                Err(e) => return Err(format!("Failed to lock input buffer: {e}")),
101            };
102            buffer.push(input.to_string());
103        }
104
105        // Increment counter and check for auto-save
106        let should_save = {
107            let mut counter = match self.input_counter.lock() {
108                Ok(guard) => guard,
109                Err(e) => return Err(format!("Failed to lock input counter: {e}")),
110            };
111            *counter += 1;
112            *counter % self.auto_save_frequency == 0
113        };
114
115        // Auto-save every Nth input (e.g., every 20th input)
116        if should_save {
117            self.save_state_to_memory();
118            println!("Auto-saved state after processing input");
119        }
120
121        // Process the input for agent checking
122        self.analyze_input(input)
123    }
124
125    /// Save the current state to memory (no file writing)
126    fn save_state_to_memory(&self) {
127        // In a real implementation, this would create a checkpoint of the current state
128        match self.last_save.lock() {
129            Ok(mut last_save) => {
130                *last_save = Instant::now();
131            }
132            Err(e) => {
133                log::error!("Failed to update last save time: {e}");
134            }
135        }
136    }
137
138    /// Analyze input for agent checking
139    fn analyze_input(&self, input: &str) -> Result<(), String> {
140        // Simplified implementation for demo purposes
141        let mut health = match self.health.lock() {
142            Ok(guard) => guard,
143            Err(e) => return Err(format!("Failed to acquire health lock: {e}")),
144        };
145
146        // Update overall system health based on input
147        // This is a placeholder for actual ML-based analysis
148        if input.contains("error") {
149            health.overall_status = (health.overall_status - 0.05).max(0.0);
150        } else if input.contains("success") {
151            health.overall_status = (health.overall_status + 0.03).min(1.0);
152        }
153
154        // Update system stage based on health
155        health.stage = if health.overall_status >= RELEASE_THRESHOLD {
156            SystemStage::Release
157        } else if health.overall_status >= PRODUCTION_THRESHOLD {
158            SystemStage::Production
159        } else if health.overall_status >= DEVELOPMENT_THRESHOLD {
160            SystemStage::Development
161        } else {
162            SystemStage::Unavailable
163        };
164
165        health.last_update = Instant::now();
166        Ok(())
167    }
168
169    /// Get current system stage
170    pub fn get_system_stage(&self) -> SystemStage {
171        match self.health.lock() {
172            Ok(health) => health.stage,
173            Err(_) => SystemStage::Unavailable,
174        }
175    }
176
177    /// Get system health metrics
178    pub fn get_system_health(&self) -> SystemHealth {
179        match self.health.lock() {
180            Ok(health) => health.clone(),
181            Err(_) => SystemHealth {
182                stage: SystemStage::Unavailable,
183                components: HashMap::new(),
184                overall_status: 0.0,
185                last_update: Instant::now(),
186            },
187        }
188    }
189
190    /// Check component readiness
191    pub fn check_component_status(&self, component_name: &str) -> Option<ComponentStatus> {
192        match self.health.lock() {
193            Ok(health) => health.components.get(component_name).cloned(),
194            Err(_) => None,
195        }
196    }
197
198    /// Update component status
199    pub fn update_component_status(
200        &self,
201        component_name: &str,
202        status: f64,
203        metrics: HashMap<String, f64>,
204        issues: Vec<String>,
205    ) {
206        let mut health = match self.health.lock() {
207            Ok(health) => health,
208            Err(e) => {
209                log::error!("Failed to acquire health lock: {e}");
210                return;
211            }
212        };
213
214        let component = ComponentStatus {
215            name: component_name.to_string(),
216            status,
217            last_check: SystemTime::now()
218                .duration_since(UNIX_EPOCH)
219                .unwrap_or(Duration::ZERO)
220                .as_secs(),
221            metrics,
222            issues,
223        };
224
225        health
226            .components
227            .insert(component_name.to_string(), component);
228
229        // Recalculate overall system health
230        let component_count = health.components.len() as f64;
231        let total_status: f64 = health.components.values().map(|c| c.status).sum();
232
233        if component_count > 0.0 {
234            health.overall_status = total_status / component_count;
235
236            // Update system stage based on overall status
237            health.stage = if health.overall_status >= RELEASE_THRESHOLD {
238                SystemStage::Release
239            } else if health.overall_status >= PRODUCTION_THRESHOLD {
240                SystemStage::Production
241            } else if health.overall_status >= DEVELOPMENT_THRESHOLD {
242                SystemStage::Development
243            } else {
244                SystemStage::Unavailable
245            };
246        }
247    }
248
249    /// Validate system readiness against thresholds
250    pub fn validate_system_readiness(&self) -> (bool, SystemStage, Vec<String>) {
251        let health = match self.health.lock() {
252            Ok(health) => health,
253            Err(e) => {
254                log::error!("Failed to acquire health lock: {e}");
255                return (
256                    false,
257                    SystemStage::Unavailable,
258                    vec![format!("Failed to acquire health lock: {}", e)],
259                );
260            }
261        };
262
263        let stage = health.stage;
264        let mut issues = Vec::new();
265
266        for (name, component) in &health.components {
267            if component.status < DEVELOPMENT_THRESHOLD {
268                issues.push(format!(
269                    "Component {} is below minimum threshold: {:.2}",
270                    name, component.status
271                ));
272            }
273        }
274
275        let is_ready = match stage {
276            SystemStage::Development => health.overall_status >= DEVELOPMENT_THRESHOLD,
277            SystemStage::Production => health.overall_status >= PRODUCTION_THRESHOLD,
278            SystemStage::Release => health.overall_status >= RELEASE_THRESHOLD,
279            SystemStage::Unavailable => false,
280        };
281
282        (is_ready, stage, issues)
283    }
284
285    /// Get input buffer stats
286    pub fn get_input_stats(&self) -> (usize, usize, Duration) {
287        let buffer = match self.input_buffer.lock() {
288            Ok(guard) => guard,
289            Err(_) => return (0, 0, Duration::from_secs(0)),
290        };
291
292        let counter = match self.input_counter.lock() {
293            Ok(guard) => *guard,
294            Err(_) => return (buffer.len(), 0, Duration::from_secs(0)),
295        };
296
297        let last_save = match self.last_save.lock() {
298            Ok(guard) => guard.elapsed(),
299            Err(_) => Duration::from_secs(0),
300        };
301
302        (buffer.len(), counter, last_save)
303    }
304}
305
306// Tests for the AgentChecker
307#[cfg(test)]
308mod tests {
309    use super::*;
310
311    #[test]
312    fn test_input_processing_with_auto_save() -> Result<(), Box<dyn std::error::Error>> {
313        let checker = AgentChecker::new(20); // Auto-save every 20th input
314
315        // Process 25 inputs
316        for i in 0..25 {
317            let input = if i % 5 == 0 {
318                format!("success message {i}")
319            } else {
320                format!("normal message {i}")
321            };
322
323            checker
324                .process_input(&input)
325                .map_err(|e| format!("Failed to process input: {e}"))?;
326        }
327
328        // Check the stats
329        let (buffer_size, counter, _) = checker.get_input_stats();
330        assert_eq!(buffer_size, 25);
331        assert_eq!(counter, 25);
332
333        // Verify system state updated
334        let health = checker.get_system_health();
335        assert!(health.overall_status > 0.0);
336
337        Ok(())
338    }
339
340    #[test]
341    fn test_system_stage_transitions() -> Result<(), Box<dyn std::error::Error>> {
342        let checker = AgentChecker::new(10);
343
344        // Initially at Unavailable
345        assert_eq!(checker.get_system_stage(), SystemStage::Unavailable);
346
347        // Update component to reach Development stage
348        let mut metrics = HashMap::new();
349        metrics.insert("memory".to_string(), 0.70);
350        metrics.insert("cpu".to_string(), 0.65);
351
352        checker.update_component_status("core", 0.62, metrics, vec![]);
353
354        // Should be at Development stage now
355        assert_eq!(checker.get_system_stage(), SystemStage::Development);
356
357        Ok(())
358    }
359}