anya_core/ml/agents/
system_map.rs

1// System Map and Index for Agent Operations
2//
3// This module provides the system mapping and indexing capabilities
4// that enable the "read first always" principle. It maintains global
5// state about the system that agents can read before taking actions.
6
7use async_trait::async_trait;
8use blake3;
9use dashmap::{DashMap, DashSet};
10use once_cell::sync::Lazy;
11use rayon::iter::{ParallelBridge, ParallelIterator};
12use serde::{Deserialize, Serialize};
13use std::collections::HashMap;
14use std::sync::{
15    atomic::{AtomicU32, AtomicU64, Ordering},
16    Arc, RwLock,
17};
18use std::time::{SystemTime, UNIX_EPOCH};
19use walkdir::WalkDir;
20
21use super::AgentError;
22
23/// System-wide index of resources and components
24#[derive(Debug)]
25pub struct SystemIndex {
26    /// Available agent IDs
27    pub agent_ids: DashSet<String>,
28    /// Available component paths with content hash
29    pub component_paths: DashMap<String, (String, [u8; 32])>,
30    /// Available model paths with versioning
31    pub model_paths: DashMap<String, semver::Version>,
32    /// Documentation links with hash verification
33    pub documentation_links: DashMap<String, (LinkStatus, [u8; 32])>,
34    /// Last update timestamp (nanoseconds since epoch)
35    pub last_updated: AtomicU64,
36    /// Version of the index
37    pub version: AtomicU32,
38    /// Rust-specific metrics
39    pub rust_metrics: DashMap<String, RustCodeMetrics>,
40}
41
42impl Default for SystemIndex {
43    fn default() -> Self {
44        Self {
45            agent_ids: DashSet::new(),
46            component_paths: DashMap::new(),
47            model_paths: DashMap::new(),
48            documentation_links: DashMap::new(),
49            last_updated: AtomicU64::new(0),
50            version: AtomicU32::new(0),
51            rust_metrics: DashMap::new(),
52        }
53    }
54}
55
56/// System-wide mapping of relationships and states
57#[derive(Debug, Default, Clone)]
58pub struct SystemMap {
59    /// Agent relationships (dependencies)
60    pub agent_relationships: HashMap<String, Vec<String>>,
61
62    /// Component states
63    pub component_states: HashMap<String, ComponentState>,
64
65    /// Model states
66    pub model_states: HashMap<String, ModelState>,
67
68    /// System health metrics
69    pub health_metrics: HashMap<String, f64>,
70
71    /// Last update timestamp
72    pub last_updated: u64,
73
74    /// Version of the map
75    pub version: u32,
76}
77
78/// State of a system component
79#[derive(Debug, Clone, Serialize, Deserialize)]
80pub struct ComponentState {
81    /// Component ID
82    pub id: String,
83
84    /// Current status
85    pub status: ComponentStatus,
86
87    /// Health score (0.0 to 1.0)
88    pub health: f32,
89
90    /// Last update timestamp
91    pub last_updated: u64,
92
93    /// Additional properties
94    pub properties: HashMap<String, serde_json::Value>,
95}
96
97/// Status of a component
98#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
99pub enum ComponentStatus {
100    /// Component is active and working properly
101    Active,
102
103    /// Component is initializing
104    Initializing,
105
106    /// Component is degraded but still functioning
107    Degraded,
108
109    /// Component is offline or not functioning
110    Offline,
111
112    /// Component is in maintenance mode
113    Maintenance,
114
115    /// Component status is unknown
116    Unknown,
117}
118
119impl Default for ComponentStatus {
120    fn default() -> Self {
121        Self::Unknown
122    }
123}
124
125/// State of a machine learning model
126#[derive(Debug, Clone, Serialize, Deserialize)]
127pub struct ModelState {
128    /// Model ID
129    pub id: String,
130
131    /// Model version
132    pub version: String,
133
134    /// Current status
135    pub status: ModelStatus,
136
137    /// Model accuracy or other primary metric
138    pub accuracy: f32,
139
140    /// Last update timestamp
141    pub last_updated: u64,
142
143    /// Model metadata
144    pub metadata: HashMap<String, serde_json::Value>,
145}
146
147/// Status of a model
148#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
149pub enum ModelStatus {
150    /// Model is available and ready for inference
151    Ready,
152
153    /// Model is being trained
154    Training,
155
156    /// Model is being validated
157    Validating,
158
159    /// Model failed validation
160    Failed,
161
162    /// Model is being updated
163    Updating,
164
165    /// Model is deprecated
166    Deprecated,
167}
168
169/// Link status for documentation
170#[derive(Debug, Clone, Serialize, Deserialize)]
171pub enum LinkStatus {
172    Valid,
173    Broken,
174    Deprecated(String), // Deprecation timestamp
175    External,
176}
177
178/// Rust-specific metrics
179#[derive(Debug, Clone, Default, Serialize, Deserialize)]
180pub struct RustCodeMetrics {
181    pub cyclomatic_complexity: f32,
182    pub unsafe_usage_count: u32,
183    pub test_coverage: f32,
184    pub dependency_graph: HashMap<String, Vec<String>>,
185    pub clippy_lints: HashMap<String, u32>,
186    pub security_audit_flags: Vec<String>,
187    pub bitcoin_protocol_adherence: f32,
188}
189
190// Global instance of the system index
191static GLOBAL_INDEX: Lazy<Arc<SystemIndexManager>> =
192    Lazy::new(|| Arc::new(SystemIndexManager::new()));
193
194// Global instance of the system map
195static GLOBAL_MAP: Lazy<Arc<SystemMapManager>> = Lazy::new(|| Arc::new(SystemMapManager::new()));
196
197/// Manager for the system index
198pub struct SystemIndexManager {
199    index: RwLock<SystemIndex>,
200}
201
202impl Default for SystemIndexManager {
203    fn default() -> Self {
204        Self::new()
205    }
206}
207
208impl SystemIndexManager {
209    /// Create a new system index manager
210    pub fn new() -> Self {
211        Self {
212            index: RwLock::new(SystemIndex::default()),
213        }
214    }
215
216    /// Get the current index (returns a reference to avoid cloning atomic types)
217    pub async fn read_index(&self) -> Result<(), AgentError> {
218        let _index = self.index.read().map_err(|_| {
219            AgentError::InternalError("Failed to acquire read lock on system index".to_string())
220        })?;
221        // Return success if we can read the index
222        Ok(())
223    }
224
225    /// Get a clone of the SystemIndex for reading component paths
226    async fn get_index_for_reading(&self) -> Result<SystemIndex, AgentError> {
227        let index = self.index.read().map_err(|_| {
228            AgentError::InternalError("Failed to acquire read lock on system index".to_string())
229        })?;
230
231        // Create a new SystemIndex with the current data
232        let new_index = SystemIndex::default();
233        for entry in index.component_paths.iter() {
234            new_index
235                .component_paths
236                .insert(entry.key().clone(), entry.value().clone());
237        }
238        for entry in index.agent_ids.iter() {
239            new_index.agent_ids.insert(entry.clone());
240        }
241        for entry in index.model_paths.iter() {
242            new_index
243                .model_paths
244                .insert(entry.key().clone(), entry.value().clone());
245        }
246        Ok(new_index)
247    }
248
249    /// Get agent IDs from the index
250    pub async fn get_agent_ids(&self) -> Result<Vec<String>, AgentError> {
251        let index = self.index.read().map_err(|_| {
252            AgentError::InternalError("Failed to acquire read lock on system index".to_string())
253        })?;
254        let agents: Vec<String> = index.agent_ids.iter().map(|id| id.clone()).collect();
255        Ok(agents)
256    }
257
258    /// Update the index version
259    pub async fn increment_version(&self) -> Result<(), AgentError> {
260        let index = self.index.read().map_err(|_| {
261            AgentError::InternalError("Failed to acquire read lock on system index".to_string())
262        })?;
263
264        index
265            .version
266            .store(index.version.load(Ordering::SeqCst) + 1, Ordering::SeqCst);
267        index.last_updated.store(
268            SystemTime::now()
269                .duration_since(UNIX_EPOCH)
270                .map_err(AgentError::SystemTimeError)?
271                .as_nanos() as u64,
272            Ordering::SeqCst,
273        );
274
275        Ok(())
276    }
277
278    /// Register an agent in the index
279    pub async fn register_agent(&self, agent_id: String) -> Result<(), AgentError> {
280        let index = self.index.read().map_err(|_| {
281            AgentError::InternalError("Failed to acquire read lock on system index".to_string())
282        })?;
283        index.agent_ids.insert(agent_id);
284
285        // Update metadata
286        index.last_updated.store(
287            SystemTime::now()
288                .duration_since(UNIX_EPOCH)
289                .map_err(AgentError::SystemTimeError)?
290                .as_nanos() as u64,
291            Ordering::SeqCst,
292        );
293        index
294            .version
295            .store(index.version.load(Ordering::SeqCst) + 1, Ordering::SeqCst);
296
297        Ok(())
298    }
299
300    /// Register a component in the index
301    pub async fn register_component(
302        &self,
303        component_id: String,
304        path: String,
305    ) -> Result<(), AgentError> {
306        let index = self.index.read().map_err(|_| {
307            AgentError::InternalError("Failed to acquire read lock on system index".to_string())
308        })?;
309
310        index.component_paths.insert(
311            component_id,
312            (path.clone(), blake3::hash(path.as_bytes()).into()),
313        );
314
315        // Update metadata
316        index.last_updated.store(
317            SystemTime::now()
318                .duration_since(UNIX_EPOCH)
319                .map_err(AgentError::SystemTimeError)?
320                .as_nanos() as u64,
321            Ordering::SeqCst,
322        );
323        index
324            .version
325            .store(index.version.load(Ordering::SeqCst) + 1, Ordering::SeqCst);
326
327        Ok(())
328    }
329
330    /// Register a model in the index
331    pub async fn register_model(&self, model_id: String, path: String) -> Result<(), AgentError> {
332        let index = self.index.read().map_err(|_| {
333            AgentError::InternalError("Failed to acquire read lock on system index".to_string())
334        })?;
335
336        // Extract version from path or default to 0.0.0
337        let version_str = path.split('.').next_back().unwrap_or("0.0.0");
338        let version =
339            semver::Version::parse(version_str).unwrap_or_else(|_| semver::Version::new(0, 0, 0));
340
341        index.model_paths.insert(model_id, version);
342
343        // Update metadata
344        index.last_updated.store(
345            SystemTime::now()
346                .duration_since(UNIX_EPOCH)
347                .map_err(AgentError::SystemTimeError)?
348                .as_nanos() as u64,
349            Ordering::SeqCst,
350        );
351        index
352            .version
353            .store(index.version.load(Ordering::SeqCst) + 1, Ordering::SeqCst);
354
355        Ok(())
356    }
357
358    /// Parallel directory crawler using rayon
359    pub async fn crawl_and_update(&self) -> Result<(), AgentError> {
360        let update_data: HashMap<String, (String, [u8; 32])> = WalkDir::new(".")
361            .into_iter()
362            .filter_map(|e| e.ok())
363            .par_bridge()
364            .map(|entry| {
365                let path = entry.path().to_string_lossy().into_owned();
366                let hash = if entry.file_type().is_file() {
367                    let data = std::fs::read(&path).unwrap_or_default();
368                    blake3::hash(&data).to_hex().to_string()
369                } else {
370                    String::new()
371                };
372
373                let file_type = if path.ends_with(".md") {
374                    "Documentation"
375                } else if path.ends_with(".rs") {
376                    "Rust Source"
377                } else {
378                    "Asset"
379                };
380
381                let hash_bytes: [u8; 32] = blake3::hash(hash.as_bytes()).into();
382                (path, (file_type.to_string(), hash_bytes))
383            })
384            .collect();
385
386        // Update the index with collected data
387        {
388            let index = self.index.write().map_err(|_| {
389                AgentError::InternalError(
390                    "Failed to acquire write lock on system index".to_string(),
391                )
392            })?;
393
394            for (path, (file_type, hash)) in update_data {
395                index.component_paths.insert(path, (file_type, hash));
396            }
397
398            index.last_updated.store(
399                SystemTime::now()
400                    .duration_since(UNIX_EPOCH)
401                    .map_err(AgentError::SystemTimeError)?
402                    .as_nanos() as u64,
403                Ordering::SeqCst,
404            );
405        }
406
407        Ok(())
408    }
409
410    fn analyze_rust_file(&self, path: &str) -> RustCodeMetrics {
411        let content = std::fs::read_to_string(path).unwrap_or_default();
412        if let Ok(syntax) = syn::parse_file(&content) {
413            let mut metrics = RustCodeMetrics {
414                cyclomatic_complexity: calculate_cyclomatic_complexity(&syntax),
415                unsafe_usage_count: count_unsafe_blocks(&syntax),
416                test_coverage: get_test_coverage(path),
417                dependency_graph: analyze_dependencies(&content),
418                clippy_lints: run_clippy_checks(path),
419                security_audit_flags: check_bitcoin_security(&content),
420                bitcoin_protocol_adherence: calculate_protocol_adherence(&content),
421            };
422
423            // Apply Bitcoin protocol rules
424            if metrics.bitcoin_protocol_adherence < 0.9 {
425                metrics
426                    .security_audit_flags
427                    .push("Low Bitcoin protocol adherence - review BIP-341/342 compliance".into());
428            }
429
430            metrics
431        } else {
432            RustCodeMetrics::default()
433        }
434    }
435    pub fn enhanced_crawl(&self) -> Result<(), AgentError> {
436        let index = self.index.read().map_err(|_| {
437            AgentError::InternalError("Failed to acquire read lock on system index".to_string())
438        })?;
439
440        let walker = WalkDir::new(".")
441            .into_iter()
442            .filter_map(|e| e.ok())
443            .par_bridge()
444            .filter(|e| e.path().extension().map(|ext| ext == "rs").unwrap_or(false))
445            .map(|entry| {
446                let path = entry.path().to_string_lossy().into_owned();
447                let metrics = self.analyze_rust_file(&path);
448                (path, metrics)
449            });
450
451        walker.for_each(|(path, metrics)| {
452            index.rust_metrics.insert(path, metrics);
453        });
454
455        Ok(())
456    }
457
458    pub async fn bitcoin_health_check(&self) -> Result<f32, AgentError> {
459        let index = self.get_index_for_reading().await?;
460        let total = index.component_paths.len() as f32;
461        let compliant = index
462            .component_paths
463            .iter()
464            .filter(|entry| Self::is_bitcoin_related(std::path::Path::new(entry.key())))
465            .filter(|entry| entry.value().1.len() == 32) // Simple validation
466            .count() as f32;
467
468        Ok(compliant / total.max(1.0))
469    }
470
471    /// Check if a path is related to Bitcoin functionality
472    pub fn is_bitcoin_related(path: &std::path::Path) -> bool {
473        let path_str = path.to_string_lossy().to_lowercase();
474        path_str.contains("bitcoin")
475            || path_str.contains("bip")
476            || path_str.contains("address")
477            || path_str.contains("transaction")
478            || path_str.contains("wallet")
479            || path_str.contains("script")
480            || path_str.contains("secp256k1")
481            || path_str.contains("hash")
482            || path_str.contains("merkle")
483            || path_str.contains("block")
484    }
485}
486
487/// Manager for the system map
488pub struct SystemMapManager {
489    map: RwLock<SystemMap>,
490}
491
492impl Default for SystemMapManager {
493    fn default() -> Self {
494        Self::new()
495    }
496}
497
498impl SystemMapManager {
499    /// Create a new system map manager
500    pub fn new() -> Self {
501        Self {
502            map: RwLock::new(SystemMap::default()),
503        }
504    }
505
506    /// Get the current map status
507    pub async fn read_map(&self) -> Result<(), AgentError> {
508        let _map = self.map.read().map_err(|_| {
509            AgentError::InternalError("Failed to acquire read lock on system map".to_string())
510        })?;
511        Ok(())
512    }
513
514    /// Update the map
515    pub async fn update_map(&self) -> Result<(), AgentError> {
516        let mut map = self.map.write().map_err(|_| {
517            AgentError::InternalError("Failed to acquire write lock on system map".to_string())
518        })?;
519
520        // Update the timestamp
521        map.last_updated = std::time::SystemTime::now()
522            .duration_since(std::time::UNIX_EPOCH)
523            .unwrap_or_default()
524            .as_secs();
525
526        // Increment the version
527        map.version += 1;
528
529        // TODO: Actual map update logic
530
531        Ok(())
532    }
533
534    /// Update component state
535    pub async fn update_component_state(
536        &self,
537        component_id: String,
538        state: ComponentState,
539    ) -> Result<(), AgentError> {
540        let mut map = self.map.write().map_err(|_| {
541            AgentError::InternalError("Failed to acquire write lock on system map".to_string())
542        })?;
543
544        map.component_states.insert(component_id, state);
545
546        // Update metadata
547        map.last_updated = std::time::SystemTime::now()
548            .duration_since(std::time::UNIX_EPOCH)
549            .unwrap_or_default()
550            .as_secs();
551        map.version += 1;
552
553        Ok(())
554    }
555
556    /// Update model state
557    pub async fn update_model_state(
558        &self,
559        model_id: String,
560        state: ModelState,
561    ) -> Result<(), AgentError> {
562        let mut map = self.map.write().map_err(|_| {
563            AgentError::InternalError("Failed to acquire write lock on system map".to_string())
564        })?;
565
566        map.model_states.insert(model_id, state);
567
568        // Update metadata
569        map.last_updated = std::time::SystemTime::now()
570            .duration_since(std::time::UNIX_EPOCH)
571            .unwrap_or_default()
572            .as_secs();
573        map.version += 1;
574
575        Ok(())
576    }
577
578    /// Update agent relationships
579    pub async fn update_agent_relationships(
580        &self,
581        agent_id: String,
582        relationships: Vec<String>,
583    ) -> Result<(), AgentError> {
584        let mut map = self.map.write().map_err(|_| {
585            AgentError::InternalError("Failed to acquire write lock on system map".to_string())
586        })?;
587
588        map.agent_relationships.insert(agent_id, relationships);
589
590        // Update metadata
591        map.last_updated = std::time::SystemTime::now()
592            .duration_since(std::time::UNIX_EPOCH)
593            .unwrap_or_default()
594            .as_secs();
595        map.version += 1;
596
597        Ok(())
598    }
599
600    /// Update system health metrics
601    pub async fn update_health_metrics(
602        &self,
603        metrics: HashMap<String, f64>,
604    ) -> Result<(), AgentError> {
605        let mut map = self.map.write().map_err(|_| {
606            AgentError::InternalError("Failed to acquire write lock on system map".to_string())
607        })?;
608
609        // Update or insert each metric
610        for (key, value) in metrics {
611            map.health_metrics.insert(key, value);
612        }
613
614        // Update metadata
615        map.last_updated = std::time::SystemTime::now()
616            .duration_since(std::time::UNIX_EPOCH)
617            .unwrap_or_default()
618            .as_secs();
619        map.version += 1;
620
621        Ok(())
622    }
623}
624
625/// Get the global instance of the system index manager
626pub fn system_index() -> Arc<SystemIndexManager> {
627    GLOBAL_INDEX.clone()
628}
629
630/// Get the global instance of the system map manager
631pub fn system_map() -> Arc<SystemMapManager> {
632    GLOBAL_MAP.clone()
633}
634
635/// Implementation of the IndexProvider trait for the system index
636#[async_trait]
637pub trait IndexProvider {
638    /// Get the global system index
639    fn global() -> Arc<SystemIndexManager>;
640
641    /// Read the current index
642    async fn read_index(&self) -> Result<(), AgentError>;
643
644    /// Update the index
645    async fn increment_version(&self) -> Result<(), AgentError>;
646}
647
648/// Implementation of the MapProvider trait for the system map
649#[async_trait]
650pub trait MapProvider {
651    /// Get the global system map
652    fn global() -> Arc<SystemMapManager>;
653
654    /// Read the current map
655    async fn read_map(&self) -> Result<(), AgentError>;
656
657    /// Update the map
658    async fn update_map(&self) -> Result<(), AgentError>;
659}
660
661#[async_trait]
662impl IndexProvider for SystemIndexManager {
663    fn global() -> Arc<SystemIndexManager> {
664        GLOBAL_INDEX.clone()
665    }
666
667    async fn read_index(&self) -> Result<(), AgentError> {
668        self.read_index().await
669    }
670
671    async fn increment_version(&self) -> Result<(), AgentError> {
672        self.increment_version().await
673    }
674}
675
676#[async_trait]
677impl MapProvider for SystemMapManager {
678    fn global() -> Arc<SystemMapManager> {
679        GLOBAL_MAP.clone()
680    }
681
682    async fn read_map(&self) -> Result<(), AgentError> {
683        self.read_map().await
684    }
685
686    async fn update_map(&self) -> Result<(), AgentError> {
687        self.update_map().await
688    }
689}
690
691// Stub implementations for missing analysis functions
692fn calculate_cyclomatic_complexity(_syntax: &syn::File) -> f32 {
693    1.0 // Default complexity
694}
695fn count_unsafe_blocks(_syntax: &syn::File) -> u32 {
696    0
697}
698fn get_test_coverage(_path: &str) -> f32 {
699    0.0
700}
701fn analyze_dependencies(_content: &str) -> HashMap<String, Vec<String>> {
702    HashMap::new()
703}
704fn run_clippy_checks(_path: &str) -> HashMap<String, u32> {
705    HashMap::new()
706}
707fn check_bitcoin_security(_content: &str) -> Vec<String> {
708    vec![]
709}
710fn calculate_protocol_adherence(_content: &str) -> f32 {
711    0.0
712}
713
714#[cfg(test)]
715mod tests {
716
717    #[tokio::test]
718    async fn test_system_index_operations() {
719        // Test index operations
720    }
721
722    #[tokio::test]
723    async fn test_system_map_operations() {
724        // Test map operations
725    }
726}