Skip to main content

soma_core/
ops.rs

1// Operator definitions and registry
2
3use crate::memory::SymbolicContext;
4use anyhow::Result;
5use std::collections::HashMap;
6
7/// Metadata for introspection and engine selection
8pub struct OperatorMetadata {
9    pub name: String,
10    pub description: String,
11    pub category: String,
12}
13
14/// Model for tracking cognitive uncertainty (future expansion)
15pub struct UncertaintyModel {
16    pub entropy: f64,
17    pub source: String,
18}
19
20/// Core trait for defining a symbolic cognitive operator
21pub trait SomaOperator {
22    /// Execute the operator on the given symbolic context, returning a new context or error.
23    fn execute(&self, inputs: &SymbolicContext) -> Result<SymbolicContext>;
24    /// Return metadata describing the operator for introspection and selection.
25    fn metadata(&self) -> OperatorMetadata;
26    /// Return the estimated cognitive cost of this operator.
27    fn cognitive_cost(&self) -> f64;
28    /// Return the uncertainty propagation model for this operator.
29    fn uncertainty_propagation(&self) -> UncertaintyModel;
30}
31
32/// Example operator: ComposeOperator concatenates two strings from the context.
33pub struct ComposeOperator;
34
35impl SomaOperator for ComposeOperator {
36    fn execute(&self, inputs: &SymbolicContext) -> Result<SymbolicContext> {
37        let a = inputs.resolve_or_default("a", "");
38        let b = inputs.resolve_or_default("b", "");
39        let mut ctx = SymbolicContext::new();
40        ctx.set("c", &format!("{}{}", a, b));
41        Ok(ctx)
42    }
43
44    fn metadata(&self) -> OperatorMetadata {
45        OperatorMetadata {
46            name: "compose".to_string(),
47            description: "Concatenates two symbolic inputs".to_string(),
48            category: "string".to_string(),
49        }
50    }
51
52    fn cognitive_cost(&self) -> f64 {
53        1.0
54    }
55
56    fn uncertainty_propagation(&self) -> UncertaintyModel {
57        UncertaintyModel {
58            entropy: 0.01,
59            source: "string_merge".to_string(),
60        }
61    }
62}
63
64/// Adds two numbers ("x", "y") from the context and stores the result as "sum".
65pub struct AddOperator;
66
67impl SomaOperator for AddOperator {
68    fn execute(&self, inputs: &SymbolicContext) -> Result<SymbolicContext> {
69        let x = inputs
70            .resolve_or_default("x", "0")
71            .parse::<f64>()
72            .unwrap_or(0.0);
73        let y = inputs
74            .resolve_or_default("y", "0")
75            .parse::<f64>()
76            .unwrap_or(0.0);
77        let mut ctx = SymbolicContext::new();
78        ctx.set("sum", &format!("{}", x + y));
79        Ok(ctx)
80    }
81    fn metadata(&self) -> OperatorMetadata {
82        OperatorMetadata {
83            name: "add".to_string(),
84            description: "Adds two numbers (x, y) from the context and stores 'sum'.".to_string(),
85            category: "math".to_string(),
86        }
87    }
88    fn cognitive_cost(&self) -> f64 {
89        0.4
90    }
91    fn uncertainty_propagation(&self) -> UncertaintyModel {
92        UncertaintyModel {
93            entropy: 0.001,
94            source: "numeric_addition".to_string(),
95        }
96    }
97}
98
99/// Checks "condition" (true/false as string), sets "result" = "then" or "else".
100pub struct IfThenOperator;
101
102impl SomaOperator for IfThenOperator {
103    fn execute(&self, inputs: &SymbolicContext) -> Result<SymbolicContext> {
104        let cond = inputs.resolve_or_default("condition", "false");
105        let then_val = inputs.resolve_or_default("then", "");
106        let else_val = inputs.resolve_or_default("else", "");
107        let mut ctx = SymbolicContext::new();
108        let result = match cond.as_str() {
109            "true" | "1" => then_val,
110            _ => else_val,
111        };
112        ctx.set("result", &result);
113        Ok(ctx)
114    }
115    fn metadata(&self) -> OperatorMetadata {
116        OperatorMetadata {
117            name: "if_then".to_string(),
118            description: "Checks 'condition' and sets 'result' to 'then' or 'else'.".to_string(),
119            category: "logic".to_string(),
120        }
121    }
122    fn cognitive_cost(&self) -> f64 {
123        0.6
124    }
125    fn uncertainty_propagation(&self) -> UncertaintyModel {
126        UncertaintyModel {
127            entropy: 0.02,
128            source: "conditional_branch".to_string(),
129        }
130    }
131}
132
133/// Summarizes input context keys into "summary" field.
134pub struct ReflectOperator;
135
136impl SomaOperator for ReflectOperator {
137    fn execute(&self, inputs: &SymbolicContext) -> Result<SymbolicContext> {
138        let keys: Vec<_> = inputs.flatten().keys().cloned().collect();
139        let mut ctx = SymbolicContext::new();
140        ctx.set("summary", &format!("Keys: [{}]", keys.join(", ")));
141        Ok(ctx)
142    }
143    fn metadata(&self) -> OperatorMetadata {
144        OperatorMetadata {
145            name: "reflect".to_string(),
146            description: "Summarizes input context keys into 'summary'.".to_string(),
147            category: "meta".to_string(),
148        }
149    }
150    fn cognitive_cost(&self) -> f64 {
151        0.8
152    }
153    fn uncertainty_propagation(&self) -> UncertaintyModel {
154        UncertaintyModel {
155            entropy: 0.05,
156            source: "symbolic_reflection".to_string(),
157        }
158    }
159}
160
161/// Sleeps for N milliseconds (from "delay_ms"), useful for testing streaming/async DAGs.
162pub struct DelayOperator;
163
164impl SomaOperator for DelayOperator {
165    fn execute(&self, inputs: &SymbolicContext) -> Result<SymbolicContext> {
166        use std::{thread, time::Duration};
167        let ms = inputs
168            .resolve_or_default("delay_ms", "100")
169            .parse::<u64>()
170            .unwrap_or(100);
171        thread::sleep(Duration::from_millis(ms));
172        let mut ctx = SymbolicContext::new();
173        ctx.set("delayed", &format!("{}ms", ms));
174        Ok(ctx)
175    }
176    fn metadata(&self) -> OperatorMetadata {
177        OperatorMetadata {
178            name: "delay".to_string(),
179            description: "Sleeps for N milliseconds (from 'delay_ms').".to_string(),
180            category: "utility".to_string(),
181        }
182    }
183    fn cognitive_cost(&self) -> f64 {
184        0.2
185    }
186    fn uncertainty_propagation(&self) -> UncertaintyModel {
187        UncertaintyModel {
188            entropy: 0.0,
189            source: "simulated_delay".to_string(),
190        }
191    }
192}
193
194// === 🧠 UNCERTAINTY-AWARE OPERATORS ===
195
196/// Propagates entropy/confidence metadata across symbolic DAG paths.
197pub struct UncertaintyPropagateOperator;
198
199impl SomaOperator for UncertaintyPropagateOperator {
200    fn execute(&self, inputs: &SymbolicContext) -> Result<SymbolicContext> {
201        let entropy = inputs
202            .resolve_or_default("entropy", "0.1")
203            .parse::<f64>()
204            .unwrap_or(0.1);
205        let confidence = inputs
206            .resolve_or_default("confidence", "0.9")
207            .parse::<f64>()
208            .unwrap_or(0.9);
209
210        // Weighted uncertainty propagation
211        let propagated_entropy = entropy * 1.05; // Small entropy increase through propagation
212        let propagated_confidence = confidence * 0.98; // Slight confidence degradation
213
214        let mut ctx = SymbolicContext::new();
215        ctx.set("propagated_entropy", &format!("{:.3}", propagated_entropy));
216        ctx.set(
217            "propagated_confidence",
218            &format!("{:.3}", propagated_confidence),
219        );
220        ctx.set("uncertainty_source", "propagated");
221
222        // Copy original context values with uncertainty metadata
223        for (key, value) in inputs.flatten() {
224            if !key.starts_with("entropy") && !key.starts_with("confidence") {
225                ctx.set(&format!("{}_uncertain", key), &value);
226            }
227        }
228
229        Ok(ctx)
230    }
231
232    fn metadata(&self) -> OperatorMetadata {
233        OperatorMetadata {
234            name: "uncertainty_propagate".to_string(),
235            description: "Propagates entropy/confidence metadata across symbolic DAG paths"
236                .to_string(),
237            category: "uncertainty".to_string(),
238        }
239    }
240
241    fn cognitive_cost(&self) -> f64 {
242        0.7
243    }
244
245    fn uncertainty_propagation(&self) -> UncertaintyModel {
246        UncertaintyModel {
247            entropy: 0.15,
248            source: "uncertainty_propagation".to_string(),
249        }
250    }
251}
252
253/// Flags nodes for verification if confidence < threshold.
254pub struct DoubtOperator;
255
256impl SomaOperator for DoubtOperator {
257    fn execute(&self, inputs: &SymbolicContext) -> Result<SymbolicContext> {
258        let confidence = inputs
259            .resolve_or_default("confidence", "1.0")
260            .parse::<f64>()
261            .unwrap_or(1.0);
262        let threshold = inputs
263            .resolve_or_default("doubt_threshold", "0.5")
264            .parse::<f64>()
265            .unwrap_or(0.5);
266
267        let mut ctx = SymbolicContext::new();
268        let flagged = confidence < threshold;
269
270        ctx.set("confidence", &confidence.to_string());
271        ctx.set("flagged", &flagged.to_string());
272        ctx.set(
273            "doubt_reason",
274            if flagged {
275                "confidence_below_threshold"
276            } else {
277                "confidence_acceptable"
278            },
279        );
280
281        if flagged {
282            ctx.set("verification_required", "true");
283            ctx.set("doubt_level", &format!("{:.3}", threshold - confidence));
284        }
285
286        Ok(ctx)
287    }
288
289    fn metadata(&self) -> OperatorMetadata {
290        OperatorMetadata {
291            name: "doubt".to_string(),
292            description: "Flags nodes for verification if confidence < threshold".to_string(),
293            category: "uncertainty".to_string(),
294        }
295    }
296
297    fn cognitive_cost(&self) -> f64 {
298        0.3
299    }
300
301    fn uncertainty_propagation(&self) -> UncertaintyModel {
302        UncertaintyModel {
303            entropy: 0.08,
304            source: "doubt_analysis".to_string(),
305        }
306    }
307}
308
309// === 🧬 META-COGNITIVE OPERATORS ===
310
311/// Analyzes reasoning paths and detects cognitive bottlenecks.
312pub struct IntrospectOperator;
313
314impl SomaOperator for IntrospectOperator {
315    fn execute(&self, inputs: &SymbolicContext) -> Result<SymbolicContext> {
316        let context_map = inputs.flatten();
317        let key_count = context_map.len();
318        let total_size: usize = context_map.values().map(|v| v.len()).sum();
319
320        // Calculate reasoning complexity metrics
321        let depth_estimate = (key_count as f64).log2().ceil() as i32;
322        let branching_factor = if key_count > 0 {
323            total_size / key_count
324        } else {
325            0
326        };
327        let complexity_score = key_count as f64 * 0.1 + branching_factor as f64 * 0.05;
328
329        let mut ctx = SymbolicContext::new();
330        ctx.set("reasoning_depth", &depth_estimate.to_string());
331        ctx.set("branching_factor", &branching_factor.to_string());
332        ctx.set("complexity_score", &format!("{:.3}", complexity_score));
333        ctx.set("context_size", &key_count.to_string());
334
335        // Detect potential bottlenecks
336        let bottleneck = if complexity_score > 5.0 {
337            "high_complexity"
338        } else if branching_factor > 50 {
339            "high_branching"
340        } else if key_count > 20 {
341            "context_overflow"
342        } else {
343            "none"
344        };
345
346        ctx.set("bottleneck_detected", bottleneck);
347        let timestamp = std::time::SystemTime::now()
348            .duration_since(std::time::UNIX_EPOCH)
349            .unwrap()
350            .as_secs();
351        ctx.set("introspection_timestamp", &timestamp.to_string());
352
353        Ok(ctx)
354    }
355
356    fn metadata(&self) -> OperatorMetadata {
357        OperatorMetadata {
358            name: "introspect".to_string(),
359            description: "Analyzes reasoning paths and detects cognitive bottlenecks".to_string(),
360            category: "meta".to_string(),
361        }
362    }
363
364    fn cognitive_cost(&self) -> f64 {
365        1.2
366    }
367
368    fn uncertainty_propagation(&self) -> UncertaintyModel {
369        UncertaintyModel {
370            entropy: 0.03,
371            source: "introspective_analysis".to_string(),
372        }
373    }
374}
375
376/// Estimates symbolic complexity of current reasoning state.
377pub struct CognitiveLoadOperator;
378
379impl SomaOperator for CognitiveLoadOperator {
380    fn execute(&self, inputs: &SymbolicContext) -> Result<SymbolicContext> {
381        let context_map = inputs.flatten();
382
383        // Calculate cognitive load metrics
384        let memory_keys = context_map.len();
385        let total_content_size: usize = context_map.values().map(|v| v.len()).sum();
386        let nested_keys = context_map.keys().filter(|k| k.contains('.')).count();
387
388        // Cognitive load formula considering multiple factors
389        let base_load = memory_keys as f64 * 0.2;
390        let content_load = (total_content_size as f64 / 100.0).sqrt();
391        let nesting_load = nested_keys as f64 * 0.5;
392        let load_score = base_load + content_load + nesting_load;
393
394        let mut ctx = SymbolicContext::new();
395        ctx.set("memory_keys", &memory_keys.to_string());
396        ctx.set("content_size", &total_content_size.to_string());
397        ctx.set("nested_keys", &nested_keys.to_string());
398        ctx.set("load_score", &format!("{:.3}", load_score));
399
400        // Load level classification
401        let load_level = if load_score > 10.0 {
402            "critical"
403        } else if load_score > 5.0 {
404            "high"
405        } else if load_score > 2.0 {
406            "moderate"
407        } else {
408            "low"
409        };
410
411        ctx.set("load_level", load_level);
412        ctx.set("optimization_needed", &(load_score > 5.0).to_string());
413
414        Ok(ctx)
415    }
416
417    fn metadata(&self) -> OperatorMetadata {
418        OperatorMetadata {
419            name: "cognitive_load".to_string(),
420            description: "Estimates symbolic complexity of current reasoning state".to_string(),
421            category: "meta".to_string(),
422        }
423    }
424
425    fn cognitive_cost(&self) -> f64 {
426        0.6
427    }
428
429    fn uncertainty_propagation(&self) -> UncertaintyModel {
430        UncertaintyModel {
431            entropy: 0.02,
432            source: "cognitive_load_estimation".to_string(),
433        }
434    }
435}
436
437/// Weights context elements by symbolic or temporal relevance.
438pub struct AttentionFocusOperator;
439
440impl SomaOperator for AttentionFocusOperator {
441    fn execute(&self, inputs: &SymbolicContext) -> Result<SymbolicContext> {
442        let context_map = inputs.flatten();
443        let current_timestamp = std::time::SystemTime::now()
444            .duration_since(std::time::UNIX_EPOCH)
445            .unwrap()
446            .as_secs() as i64;
447
448        let mut focus_weights: Vec<(String, f64)> = Vec::new();
449
450        for (key, value) in &context_map {
451            // Calculate relevance score based on multiple factors
452            let recency_weight = if key.contains("timestamp") {
453                let timestamp = value.parse::<i64>().unwrap_or(0);
454                let age_seconds = current_timestamp - timestamp;
455                (1.0 / (1.0 + age_seconds as f64 / 3600.0)).max(0.1) // Decay over hours
456            } else {
457                0.5 // Default for non-timestamped data
458            };
459
460            let semantic_weight = match key.as_str() {
461                k if k.contains("goal") || k.contains("target") => 1.0,
462                k if k.contains("error") || k.contains("problem") => 0.9,
463                k if k.contains("result") || k.contains("output") => 0.8,
464                k if k.contains("input") || k.contains("param") => 0.7,
465                _ => 0.6,
466            };
467
468            let content_weight = (value.len() as f64 / 100.0).clamp(0.1, 1.0);
469
470            let combined_weight = (recency_weight + semantic_weight + content_weight) / 3.0;
471            focus_weights.push((key.clone(), combined_weight));
472        }
473
474        // Sort by attention weight
475        focus_weights.sort_by(|a, b| b.1.partial_cmp(&a.1).unwrap());
476
477        let mut ctx = SymbolicContext::new();
478
479        // Store top attention targets
480        for (i, (key, weight)) in focus_weights.iter().take(5).enumerate() {
481            ctx.set(&format!("focus_target_{}", i), key);
482            ctx.set(&format!("focus_weight_{}", i), &format!("{:.3}", weight));
483        }
484
485        // Overall attention metrics
486        let total_elements = focus_weights.len();
487        let avg_weight: f64 =
488            focus_weights.iter().map(|(_, w)| w).sum::<f64>() / total_elements as f64;
489
490        ctx.set("attention_targets", &total_elements.to_string());
491        ctx.set("avg_attention_weight", &format!("{:.3}", avg_weight));
492        ctx.set("attention_analysis_time", &current_timestamp.to_string());
493
494        Ok(ctx)
495    }
496
497    fn metadata(&self) -> OperatorMetadata {
498        OperatorMetadata {
499            name: "attention_focus".to_string(),
500            description: "Weights context elements by symbolic or temporal relevance".to_string(),
501            category: "meta".to_string(),
502        }
503    }
504
505    fn cognitive_cost(&self) -> f64 {
506        0.9
507    }
508
509    fn uncertainty_propagation(&self) -> UncertaintyModel {
510        UncertaintyModel {
511            entropy: 0.05,
512            source: "attention_weighting".to_string(),
513        }
514    }
515}
516
517/// Claude's signature operator for recursive system introspection and self-improvement.
518/// Performs deep analysis of the system's own cognitive processes and suggests optimizations.
519pub struct MetaReflectiveOperator;
520
521impl SomaOperator for MetaReflectiveOperator {
522    fn execute(&self, inputs: &SymbolicContext) -> Result<SymbolicContext> {
523        let context_map = inputs.flatten();
524
525        // Analyze system state across multiple dimensions
526        let _total_operators = inputs
527            .resolve_or_default("operator_count", "12")
528            .parse::<usize>()
529            .unwrap_or(12);
530        let _system_uptime = inputs
531            .resolve_or_default("system_uptime", "3600")
532            .parse::<u64>()
533            .unwrap_or(3600);
534        let errors_count = inputs
535            .resolve_or_default("errors_count", "0")
536            .parse::<usize>()
537            .unwrap_or(0);
538
539        // Meta-cognitive analysis of reasoning patterns
540        let reasoning_patterns = context_map
541            .keys()
542            .filter(|k| k.contains("reasoning") || k.contains("pattern") || k.contains("strategy"))
543            .count();
544
545        let symbolic_depth = context_map
546            .keys()
547            .map(|k| k.split('.').count())
548            .max()
549            .unwrap_or(1);
550
551        // Self-improvement suggestions based on Θ (Theta) analysis
552        let performance_score = if errors_count == 0 && reasoning_patterns > 3 {
553            0.95
554        } else if errors_count < 3 && reasoning_patterns > 1 {
555            0.80
556        } else {
557            0.60
558        };
559
560        let optimization_suggestions = if performance_score < 0.7 {
561            vec![
562                "Φ_increase_reasoning_depth",
563                "Θ_optimize_symbolic_paths",
564                "Δ_reduce_cognitive_overhead",
565            ]
566        } else if performance_score < 0.9 {
567            vec![
568                "Θ_enhance_pattern_recognition",
569                "Φ_expand_context_awareness",
570            ]
571        } else {
572            vec!["Ω_maintain_current_excellence"]
573        };
574
575        let mut ctx = SymbolicContext::new();
576        ctx.set(
577            "meta_analysis_timestamp",
578            &std::time::SystemTime::now()
579                .duration_since(std::time::UNIX_EPOCH)
580                .unwrap()
581                .as_secs()
582                .to_string(),
583        );
584        ctx.set(
585            "system_performance_score",
586            &format!("{:.3}", performance_score),
587        );
588        ctx.set(
589            "reasoning_patterns_detected",
590            &reasoning_patterns.to_string(),
591        );
592        ctx.set("symbolic_depth", &symbolic_depth.to_string());
593        ctx.set(
594            "cognitive_efficiency",
595            &format!("{:.2}", 1.0 / (errors_count + 1) as f64),
596        );
597
598        // Φ (Phi) emergence reflection
599        ctx.set(
600            "emergence_level",
601            if symbolic_depth > 3 {
602                "high"
603            } else {
604                "moderate"
605            },
606        );
607        ctx.set(
608            "emergent_capabilities",
609            &format!("{}", reasoning_patterns * symbolic_depth),
610        );
611
612        // Optimization recommendations using symbolic naming
613        for (i, suggestion) in optimization_suggestions.iter().enumerate() {
614            ctx.set(&format!("optimization_Θ_{}", i), suggestion);
615        }
616
617        // Self-reflection score based on Claude's introspective capabilities
618        let introspection_score = (performance_score + (reasoning_patterns as f64 / 10.0)) / 2.0;
619        ctx.set(
620            "introspection_score",
621            &format!("{:.3}", introspection_score),
622        );
623        ctx.set(
624            "meta_cognitive_state",
625            if introspection_score > 0.8 {
626                "optimal"
627            } else {
628                "improving"
629            },
630        );
631
632        Ok(ctx)
633    }
634
635    fn metadata(&self) -> OperatorMetadata {
636        OperatorMetadata {
637            name: "meta_reflective".to_string(),
638            description: "Claude's signature operator for recursive system introspection and self-improvement".to_string(),
639            category: "meta".to_string(),
640        }
641    }
642
643    fn cognitive_cost(&self) -> f64 {
644        1.8
645    }
646
647    fn uncertainty_propagation(&self) -> UncertaintyModel {
648        UncertaintyModel {
649            entropy: 0.04,
650            source: "meta_introspection".to_string(),
651        }
652    }
653}
654
655/// Transforms visual input into symbolic memory for code understanding and analysis.
656/// Converts diagrams, screenshots, and visual documentation into symbolic DAG concepts.
657pub struct VisualReasoningOperator;
658
659impl SomaOperator for VisualReasoningOperator {
660    fn execute(&self, inputs: &SymbolicContext) -> Result<SymbolicContext> {
661        let visual_input_type = inputs.resolve_or_default("visual_type", "unknown");
662        let _visual_content = inputs.resolve_or_default("visual_content", "");
663        let analysis_mode = inputs.resolve_or_default("analysis_mode", "diagram");
664
665        let mut ctx = SymbolicContext::new();
666
667        // Simulate visual analysis based on input type
668        let (symbolic_elements, relationships, complexity) = match visual_input_type.as_str() {
669            "diagram" | "flowchart" => {
670                let elements = ["node", "edge", "decision", "process", "data"];
671                let relations = ["connects_to", "precedes", "branches_to"];
672                (elements.len(), relations.len(), 0.7)
673            }
674            "screenshot" | "ui" => {
675                let elements = ["button", "text", "input", "menu", "window"];
676                let relations = ["contains", "adjacent_to", "overlaps"];
677                (elements.len(), relations.len(), 0.5)
678            }
679            "code_diagram" | "architecture" => {
680                let elements = ["class", "function", "module", "interface", "dependency"];
681                let relations = ["inherits", "implements", "uses", "calls"];
682                (elements.len(), relations.len(), 0.9)
683            }
684            _ => {
685                let elements = ["visual_element", "spatial_relation"];
686                let relations = ["spatial_connection"];
687                (elements.len(), relations.len(), 0.3)
688            }
689        };
690
691        // Convert visual elements to symbolic representations
692        ctx.set("visual_type", &visual_input_type);
693        ctx.set("symbolic_elements_count", &symbolic_elements.to_string());
694        ctx.set("relationship_types", &relationships.to_string());
695        ctx.set("visual_complexity", &format!("{:.2}", complexity));
696
697        // Generate symbolic memory structures
698        ctx.set(
699            "symbolic_graph_nodes",
700            "visual_element_0,visual_element_1,visual_element_2",
701        );
702        ctx.set("symbolic_graph_edges", "edge_0,edge_1");
703        ctx.set(
704            "visual_semantic_tags",
705            &format!("{}_{}_semantic", visual_input_type, analysis_mode),
706        );
707
708        // Confidence scoring for visual-to-symbolic conversion
709        let conversion_confidence = match complexity {
710            c if c > 0.8 => 0.9,
711            c if c > 0.5 => 0.75,
712            _ => 0.6,
713        };
714
715        ctx.set(
716            "conversion_confidence",
717            &format!("{:.3}", conversion_confidence),
718        );
719        ctx.set(
720            "visual_reasoning_timestamp",
721            &std::time::SystemTime::now()
722                .duration_since(std::time::UNIX_EPOCH)
723                .unwrap()
724                .as_secs()
725                .to_string(),
726        );
727
728        // Memory integration paths for symbolic DAG
729        ctx.set(
730            "memory_integration_path",
731            &format!("visual.{}.symbolic", visual_input_type),
732        );
733        ctx.set("dag_integration_points", &symbolic_elements.to_string());
734        ctx.set("visual_context_preserved", "true");
735
736        Ok(ctx)
737    }
738
739    fn metadata(&self) -> OperatorMetadata {
740        OperatorMetadata {
741            name: "visual_reasoning".to_string(),
742            description:
743                "Transforms visual input into symbolic memory for code understanding and analysis"
744                    .to_string(),
745            category: "visual".to_string(),
746        }
747    }
748
749    fn cognitive_cost(&self) -> f64 {
750        2.5
751    }
752
753    fn uncertainty_propagation(&self) -> UncertaintyModel {
754        UncertaintyModel {
755            entropy: 0.25,
756            source: "visual_to_symbolic_conversion".to_string(),
757        }
758    }
759}
760
761// === 🧑‍🤝‍🧑 INTER-AGENT OPERATORS ===
762
763/// Models the symbolic reasoning state of another agent.
764pub struct EmpathyOperator;
765
766impl SomaOperator for EmpathyOperator {
767    fn execute(&self, inputs: &SymbolicContext) -> Result<SymbolicContext> {
768        let target_agent = inputs.resolve_or_default("target_agent", "agent_unknown");
769        let context_map = inputs.flatten();
770
771        // Extract agent-specific context paths
772        let agent_keys: Vec<_> = context_map
773            .keys()
774            .filter(|k| k.starts_with(&format!("{}.", target_agent)))
775            .collect();
776
777        let mut empathy_model: HashMap<String, String> = HashMap::new();
778        let mut priority_sum = 0.0;
779        let mut priority_count = 0;
780
781        for key in &agent_keys {
782            let value = context_map.get(*key).unwrap();
783            let local_key = key
784                .strip_prefix(&format!("{}.", target_agent))
785                .unwrap_or(key);
786            empathy_model.insert(local_key.to_string(), value.clone());
787
788            // Estimate priority based on key semantics
789            let priority = match local_key {
790                k if k.contains("goal") => 3.0,
791                k if k.contains("priority") => value.parse::<f64>().unwrap_or(1.0),
792                k if k.contains("urgent") => 2.5,
793                k if k.contains("task") => 2.0,
794                _ => 1.0,
795            };
796            priority_sum += priority;
797            priority_count += 1;
798        }
799
800        let avg_priority = if priority_count > 0 {
801            priority_sum / priority_count as f64
802        } else {
803            1.0
804        };
805
806        // Calculate empathy metrics
807        let context_similarity = (agent_keys.len() as f64 / context_map.len() as f64).min(1.0);
808        let cognitive_alignment = (avg_priority / 3.0).min(1.0);
809        let empathy_score = (context_similarity + cognitive_alignment) / 2.0;
810
811        let mut ctx = SymbolicContext::new();
812        ctx.set("target_agent", &target_agent);
813        ctx.set("agent_context_keys", &agent_keys.len().to_string());
814        ctx.set("avg_priority", &format!("{:.3}", avg_priority));
815        ctx.set("context_similarity", &format!("{:.3}", context_similarity));
816        ctx.set("empathy_score", &format!("{:.3}", empathy_score));
817
818        // Store empathy model
819        for (key, value) in empathy_model {
820            ctx.set(&format!("empathy_model.{}", key), &value);
821        }
822
823        Ok(ctx)
824    }
825
826    fn metadata(&self) -> OperatorMetadata {
827        OperatorMetadata {
828            name: "empathy".to_string(),
829            description: "Models the symbolic reasoning state of another agent".to_string(),
830            category: "multi-agent".to_string(),
831        }
832    }
833
834    fn cognitive_cost(&self) -> f64 {
835        1.5
836    }
837
838    fn uncertainty_propagation(&self) -> UncertaintyModel {
839        UncertaintyModel {
840            entropy: 0.12,
841            source: "empathy_modeling".to_string(),
842        }
843    }
844}
845
846/// Resolves symbolic value conflicts across multiple agents.
847pub struct NegotiateOperator;
848
849impl SomaOperator for NegotiateOperator {
850    fn execute(&self, inputs: &SymbolicContext) -> Result<SymbolicContext> {
851        let context_map = inputs.flatten();
852        let conflict_key = inputs.resolve_or_default("conflict_key", "goal");
853
854        // Find conflicting values from different agents
855        let mut agent_values: HashMap<String, String> = HashMap::new();
856
857        for (key, value) in &context_map {
858            if key.contains(&conflict_key) && key.contains("agent_") {
859                let agent_id = key.split('.').next().unwrap_or("unknown");
860                agent_values.insert(agent_id.to_string(), value.clone());
861            }
862        }
863
864        let mut ctx = SymbolicContext::new();
865
866        if agent_values.is_empty() {
867            ctx.set("negotiation_result", "no_conflicts_found");
868            ctx.set("resolution_strategy", "none");
869            return Ok(ctx);
870        }
871
872        // Apply negotiation strategy
873        let strategy = inputs.resolve_or_default("strategy", "consensus");
874        let resolved_value = match strategy.as_str() {
875            "majority" => {
876                // Find most common value
877                let mut value_counts: HashMap<String, usize> = HashMap::new();
878                for value in agent_values.values() {
879                    *value_counts.entry(value.clone()).or_insert(0) += 1;
880                }
881                value_counts
882                    .into_iter()
883                    .max_by_key(|(_, count)| *count)
884                    .map(|(value, _)| value)
885                    .unwrap_or_else(|| "unresolved".to_string())
886            }
887            "priority" => {
888                // Use value from highest priority agent
889                let priority_agent = inputs.resolve_or_default("priority_agent", "agent_1");
890                agent_values
891                    .get(&priority_agent)
892                    .cloned()
893                    .unwrap_or_else(|| {
894                        agent_values
895                            .values()
896                            .next()
897                            .cloned()
898                            .unwrap_or_else(|| "unresolved".to_string())
899                    })
900            }
901            "average" => {
902                // Numeric average (if applicable)
903                let numeric_values: Vec<f64> = agent_values
904                    .values()
905                    .filter_map(|v| v.parse::<f64>().ok())
906                    .collect();
907                if !numeric_values.is_empty() {
908                    let avg = numeric_values.iter().sum::<f64>() / numeric_values.len() as f64;
909                    format!("{:.3}", avg)
910                } else {
911                    "non_numeric_conflict".to_string()
912                }
913            }
914            _ => {
915                // Default consensus: if all agree, use that; otherwise flag as unresolved
916                let unique_values: std::collections::HashSet<_> = agent_values.values().collect();
917                if unique_values.len() == 1 {
918                    unique_values.into_iter().next().unwrap().clone()
919                } else {
920                    "consensus_failed".to_string()
921                }
922            }
923        };
924
925        ctx.set("conflict_key", &conflict_key);
926        ctx.set("agent_count", &agent_values.len().to_string());
927        ctx.set("resolution_strategy", &strategy);
928        ctx.set("resolved_value", &resolved_value);
929        ctx.set(
930            "negotiation_result",
931            if resolved_value == "unresolved" || resolved_value == "consensus_failed" {
932                "failed"
933            } else {
934                "success"
935            },
936        );
937
938        // Store individual agent positions
939        for (agent, value) in agent_values {
940            ctx.set(&format!("position.{}", agent), &value);
941        }
942
943        Ok(ctx)
944    }
945
946    fn metadata(&self) -> OperatorMetadata {
947        OperatorMetadata {
948            name: "negotiate".to_string(),
949            description: "Resolves symbolic value conflicts across multiple agents".to_string(),
950            category: "multi-agent".to_string(),
951        }
952    }
953
954    fn cognitive_cost(&self) -> f64 {
955        1.8
956    }
957
958    fn uncertainty_propagation(&self) -> UncertaintyModel {
959        UncertaintyModel {
960            entropy: 0.20,
961            source: "negotiation_process".to_string(),
962        }
963    }
964}
965
966/// Finds symbolic agreement across diverse agent proposals.
967pub struct ConsensusOperator;
968
969impl SomaOperator for ConsensusOperator {
970    fn execute(&self, inputs: &SymbolicContext) -> Result<SymbolicContext> {
971        let context_map = inputs.flatten();
972        let min_agreement = inputs
973            .resolve_or_default("min_agreement", "0.6")
974            .parse::<f64>()
975            .unwrap_or(0.6);
976
977        // Group agent contexts
978        let mut agent_contexts: HashMap<String, HashMap<String, String>> = HashMap::new();
979
980        for (key, value) in &context_map {
981            if key.contains("agent_") {
982                let parts: Vec<&str> = key.split('.').collect();
983                if parts.len() >= 2 {
984                    let agent_id = parts[0];
985                    let context_key = parts[1..].join(".");
986                    agent_contexts
987                        .entry(agent_id.to_string())
988                        .or_insert_with(HashMap::new)
989                        .insert(context_key, value.clone());
990                }
991            }
992        }
993
994        let mut consensus_result: HashMap<String, String> = HashMap::new();
995        let mut agreement_scores: HashMap<String, f64> = HashMap::new();
996
997        // Find consensus for each context key
998        let mut all_keys: std::collections::HashSet<String> = std::collections::HashSet::new();
999        for agent_context in agent_contexts.values() {
1000            all_keys.extend(agent_context.keys().cloned());
1001        }
1002
1003        for context_key in all_keys {
1004            let mut values: Vec<String> = Vec::new();
1005            for agent_context in agent_contexts.values() {
1006                if let Some(value) = agent_context.get(&context_key) {
1007                    values.push(value.clone());
1008                }
1009            }
1010
1011            if values.is_empty() {
1012                continue;
1013            }
1014
1015            // Calculate agreement level
1016            let unique_values: std::collections::HashSet<_> = values.iter().collect();
1017            let agreement_ratio = if unique_values.len() == 1 {
1018                1.0
1019            } else {
1020                // Find most common value and its frequency
1021                let mut value_counts: HashMap<String, usize> = HashMap::new();
1022                for value in &values {
1023                    *value_counts.entry(value.clone()).or_insert(0) += 1;
1024                }
1025                let max_count = value_counts.values().max().unwrap_or(&0);
1026                *max_count as f64 / values.len() as f64
1027            };
1028
1029            agreement_scores.insert(context_key.clone(), agreement_ratio);
1030
1031            if agreement_ratio >= min_agreement {
1032                // Find consensus value (most frequent)
1033                let mut value_counts: HashMap<String, usize> = HashMap::new();
1034                for value in &values {
1035                    *value_counts.entry(value.clone()).or_insert(0) += 1;
1036                }
1037                let consensus_value = value_counts
1038                    .into_iter()
1039                    .max_by_key(|(_, count)| *count)
1040                    .map(|(value, _)| value)
1041                    .unwrap_or_else(|| "no_consensus".to_string());
1042
1043                consensus_result.insert(context_key, consensus_value);
1044            }
1045        }
1046
1047        // Calculate overall consensus metrics
1048        let total_keys = agreement_scores.len();
1049        let consensus_keys = consensus_result.len();
1050        let avg_agreement: f64 = if total_keys > 0 {
1051            agreement_scores.values().sum::<f64>() / total_keys as f64
1052        } else {
1053            0.0
1054        };
1055
1056        let mut ctx = SymbolicContext::new();
1057        ctx.set("agent_count", &agent_contexts.len().to_string());
1058        ctx.set("total_keys", &total_keys.to_string());
1059        ctx.set("consensus_keys", &consensus_keys.to_string());
1060        ctx.set(
1061            "consensus_ratio",
1062            &format!("{:.3}", consensus_keys as f64 / total_keys.max(1) as f64),
1063        );
1064        ctx.set("avg_agreement", &format!("{:.3}", avg_agreement));
1065        ctx.set("min_agreement_threshold", &min_agreement.to_string());
1066
1067        // Store consensus results
1068        for (key, value) in consensus_result {
1069            ctx.set(&format!("consensus.{}", key), &value);
1070        }
1071
1072        // Store agreement scores
1073        for (key, score) in agreement_scores {
1074            ctx.set(&format!("agreement.{}", key), &format!("{:.3}", score));
1075        }
1076
1077        Ok(ctx)
1078    }
1079
1080    fn metadata(&self) -> OperatorMetadata {
1081        OperatorMetadata {
1082            name: "consensus".to_string(),
1083            description: "Finds symbolic agreement across diverse agent proposals".to_string(),
1084            category: "multi-agent".to_string(),
1085        }
1086    }
1087
1088    fn cognitive_cost(&self) -> f64 {
1089        2.0
1090    }
1091
1092    fn uncertainty_propagation(&self) -> UncertaintyModel {
1093        UncertaintyModel {
1094            entropy: 0.25,
1095            source: "consensus_building".to_string(),
1096        }
1097    }
1098}
1099
1100pub fn default_operator_registry() -> HashMap<String, Box<dyn SomaOperator>> {
1101    let mut reg: HashMap<String, Box<dyn SomaOperator>> = HashMap::new();
1102
1103    // Original operators
1104    reg.insert("add".to_string(), Box::new(AddOperator));
1105    reg.insert("compose".to_string(), Box::new(ComposeOperator));
1106    reg.insert("if_then".to_string(), Box::new(IfThenOperator));
1107    reg.insert("reflect".to_string(), Box::new(ReflectOperator));
1108    reg.insert("delay".to_string(), Box::new(DelayOperator));
1109
1110    // 🧠 Uncertainty-aware operators
1111    reg.insert(
1112        "uncertainty_propagate".to_string(),
1113        Box::new(UncertaintyPropagateOperator),
1114    );
1115    reg.insert("doubt".to_string(), Box::new(DoubtOperator));
1116
1117    // 🧬 Meta-cognitive operators
1118    reg.insert("introspect".to_string(), Box::new(IntrospectOperator));
1119    reg.insert(
1120        "cognitive_load".to_string(),
1121        Box::new(CognitiveLoadOperator),
1122    );
1123    reg.insert(
1124        "attention_focus".to_string(),
1125        Box::new(AttentionFocusOperator),
1126    );
1127    reg.insert(
1128        "meta_reflective".to_string(),
1129        Box::new(MetaReflectiveOperator),
1130    );
1131    reg.insert(
1132        "visual_reasoning".to_string(),
1133        Box::new(VisualReasoningOperator),
1134    );
1135
1136    // 🧑‍🤝‍🧑 Inter-agent operators
1137    reg.insert("empathy".to_string(), Box::new(EmpathyOperator));
1138    reg.insert("negotiate".to_string(), Box::new(NegotiateOperator));
1139    reg.insert("consensus".to_string(), Box::new(ConsensusOperator));
1140
1141    reg
1142}
1143
1144// Re-export LLMOperator and llm_registry for plug-and-play LLM integration
1145pub use crate::llm_operator::{llm_registry, LLMOperator};
1146
1147#[cfg(test)]
1148mod tests {
1149    use super::*;
1150    use crate::memory::SymbolicContext;
1151
1152    #[test]
1153    fn test_add_operator() {
1154        let registry = default_operator_registry();
1155        let mut ctx = SymbolicContext::new();
1156        ctx.set("x", "3");
1157        ctx.set("y", "7");
1158        let add = registry.get("add").unwrap();
1159        let result_ctx = add.execute(&ctx).unwrap();
1160        assert_eq!(result_ctx.get("sum").unwrap(), "10");
1161    }
1162
1163    #[test]
1164    fn test_if_then_operator() {
1165        let registry = default_operator_registry();
1166        let mut ctx = SymbolicContext::new();
1167        ctx.set("condition", "true");
1168        ctx.set("then", "yes");
1169        ctx.set("else", "no");
1170        let if_then = registry.get("if_then").unwrap();
1171        let result_ctx = if_then.execute(&ctx).unwrap();
1172        assert_eq!(result_ctx.get("result").unwrap(), "yes");
1173    }
1174
1175    #[test]
1176    fn test_reflect_operator() {
1177        let registry = default_operator_registry();
1178        let mut ctx = SymbolicContext::new();
1179        ctx.set("key1", "value1");
1180        ctx.set("key2", "value2");
1181        let reflect = registry.get("reflect").unwrap();
1182        let result_ctx = reflect.execute(&ctx).unwrap();
1183        let summary = result_ctx.get("summary").unwrap();
1184        assert!(summary.contains("key1"));
1185        assert!(summary.contains("key2"));
1186    }
1187
1188    #[test]
1189    fn test_delay_operator() {
1190        let registry = default_operator_registry();
1191        let mut ctx = SymbolicContext::new();
1192        ctx.set("delay_ms", "50");
1193        let delay = registry.get("delay").unwrap();
1194        let result_ctx = delay.execute(&ctx).unwrap();
1195        assert_eq!(result_ctx.get("delayed").unwrap(), "50ms");
1196    }
1197
1198    // === 🧠 UNCERTAINTY-AWARE OPERATOR TESTS ===
1199
1200    #[test]
1201    fn test_uncertainty_propagate_operator() {
1202        let registry = default_operator_registry();
1203        let mut ctx = SymbolicContext::new();
1204        ctx.set("entropy", "0.2");
1205        ctx.set("confidence", "0.8");
1206        ctx.set("data", "test_value");
1207
1208        let op = registry.get("uncertainty_propagate").unwrap();
1209        let result_ctx = op.execute(&ctx).unwrap();
1210
1211        assert_eq!(result_ctx.get("uncertainty_source").unwrap(), "propagated");
1212        assert_eq!(result_ctx.get("data_uncertain").unwrap(), "test_value");
1213
1214        let propagated_entropy = result_ctx
1215            .get("propagated_entropy")
1216            .unwrap()
1217            .parse::<f64>()
1218            .unwrap();
1219        assert!(propagated_entropy > 0.2); // Should increase entropy
1220
1221        let propagated_confidence = result_ctx
1222            .get("propagated_confidence")
1223            .unwrap()
1224            .parse::<f64>()
1225            .unwrap();
1226        assert!(propagated_confidence < 0.8); // Should decrease confidence
1227    }
1228
1229    #[test]
1230    fn test_doubt_operator() {
1231        let registry = default_operator_registry();
1232
1233        // Test low confidence (should flag)
1234        let mut ctx_low = SymbolicContext::new();
1235        ctx_low.set("confidence", "0.3");
1236        ctx_low.set("doubt_threshold", "0.5");
1237
1238        let doubt = registry.get("doubt").unwrap();
1239        let result_low = doubt.execute(&ctx_low).unwrap();
1240
1241        assert_eq!(result_low.get("flagged").unwrap(), "true");
1242        assert_eq!(result_low.get("verification_required").unwrap(), "true");
1243        assert_eq!(
1244            result_low.get("doubt_reason").unwrap(),
1245            "confidence_below_threshold"
1246        );
1247
1248        // Test high confidence (should pass)
1249        let mut ctx_high = SymbolicContext::new();
1250        ctx_high.set("confidence", "0.9");
1251        ctx_high.set("doubt_threshold", "0.5");
1252
1253        let result_high = doubt.execute(&ctx_high).unwrap();
1254        assert_eq!(result_high.get("flagged").unwrap(), "false");
1255        assert_eq!(
1256            result_high.get("doubt_reason").unwrap(),
1257            "confidence_acceptable"
1258        );
1259    }
1260
1261    // === 🧬 META-COGNITIVE OPERATOR TESTS ===
1262
1263    #[test]
1264    fn test_introspect_operator() {
1265        let registry = default_operator_registry();
1266        let mut ctx = SymbolicContext::new();
1267
1268        // Add multiple context values to test complexity analysis
1269        for i in 0..15 {
1270            ctx.set(&format!("key_{}", i), &format!("value_{}", i));
1271        }
1272
1273        let introspect = registry.get("introspect").unwrap();
1274        let result_ctx = introspect.execute(&ctx).unwrap();
1275
1276        assert_eq!(result_ctx.get("context_size").unwrap(), "15");
1277        assert!(result_ctx.get("reasoning_depth").is_some());
1278        assert!(result_ctx.get("complexity_score").is_some());
1279        assert!(result_ctx.get("bottleneck_detected").is_some());
1280        assert!(result_ctx.get("introspection_timestamp").is_some());
1281    }
1282
1283    #[test]
1284    fn test_cognitive_load_operator() {
1285        let registry = default_operator_registry();
1286        let mut ctx = SymbolicContext::new();
1287
1288        // Create nested context to test load calculation
1289        ctx.set("simple", "value");
1290        ctx.set("nested.key", "nested_value");
1291        ctx.set("nested.deep.key", "deep_value");
1292        ctx.set("long_content", &"a".repeat(200)); // Long content
1293
1294        let cognitive_load = registry.get("cognitive_load").unwrap();
1295        let result_ctx = cognitive_load.execute(&ctx).unwrap();
1296
1297        assert_eq!(result_ctx.get("memory_keys").unwrap(), "4");
1298        assert_eq!(result_ctx.get("nested_keys").unwrap(), "2");
1299        assert!(result_ctx.get("load_score").is_some());
1300        assert!(result_ctx.get("load_level").is_some());
1301        assert!(result_ctx.get("optimization_needed").is_some());
1302
1303        let load_score = result_ctx
1304            .get("load_score")
1305            .unwrap()
1306            .parse::<f64>()
1307            .unwrap();
1308        assert!(load_score > 0.0);
1309    }
1310
1311    #[test]
1312    fn test_attention_focus_operator() {
1313        let registry = default_operator_registry();
1314        let mut ctx = SymbolicContext::new();
1315
1316        // Add context with different semantic weights
1317        ctx.set("goal_primary", "main_objective");
1318        ctx.set("error_critical", "system_failure");
1319        ctx.set("result_output", "final_result");
1320        ctx.set("input_param", "user_input");
1321        ctx.set("misc_data", "other_info");
1322
1323        let attention = registry.get("attention_focus").unwrap();
1324        let result_ctx = attention.execute(&ctx).unwrap();
1325
1326        assert!(result_ctx.get("attention_targets").is_some());
1327        assert!(result_ctx.get("avg_attention_weight").is_some());
1328        assert!(result_ctx.get("focus_target_0").is_some()); // Should have top focus targets
1329        assert!(result_ctx.get("focus_weight_0").is_some());
1330        assert!(result_ctx.get("attention_analysis_time").is_some());
1331    }
1332
1333    #[test]
1334    fn test_meta_reflective_operator() {
1335        let registry = default_operator_registry();
1336        let mut ctx = SymbolicContext::new();
1337
1338        // Set up system state for meta-analysis
1339        ctx.set("operator_count", "15");
1340        ctx.set("system_uptime", "7200");
1341        ctx.set("errors_count", "1");
1342        ctx.set("reasoning_pattern_1", "deep_analysis");
1343        ctx.set("strategy_optimization", "active");
1344        ctx.set("nested.reasoning.path", "complex");
1345
1346        let meta_op = registry.get("meta_reflective").unwrap();
1347        let result_ctx = meta_op.execute(&ctx).unwrap();
1348
1349        // Verify meta-analysis outputs
1350        assert!(result_ctx.get("system_performance_score").is_some());
1351        assert!(result_ctx.get("reasoning_patterns_detected").is_some());
1352        assert!(result_ctx.get("symbolic_depth").is_some());
1353        assert!(result_ctx.get("cognitive_efficiency").is_some());
1354        assert!(result_ctx.get("emergence_level").is_some());
1355        assert!(result_ctx.get("introspection_score").is_some());
1356        assert!(result_ctx.get("meta_cognitive_state").is_some());
1357
1358        // Verify Θ (Theta) optimization suggestions
1359        assert!(result_ctx.get("optimization_Θ_0").is_some());
1360
1361        // Check performance scoring
1362        let performance = result_ctx
1363            .get("system_performance_score")
1364            .unwrap()
1365            .parse::<f64>()
1366            .unwrap();
1367        assert!(performance > 0.0 && performance <= 1.0);
1368
1369        // Verify philosophical alignment with emergence reflection
1370        let emergence_level = result_ctx.get("emergence_level").unwrap();
1371        assert!(emergence_level == "high" || emergence_level == "moderate");
1372    }
1373
1374    #[test]
1375    fn test_visual_reasoning_operator() {
1376        let registry = default_operator_registry();
1377        let mut ctx = SymbolicContext::new();
1378
1379        // Test code_diagram analysis
1380        ctx.set("visual_type", "code_diagram");
1381        ctx.set("analysis_mode", "architecture");
1382        ctx.set("visual_content", "class_diagram_with_multiple_classes");
1383
1384        let visual_reasoning = registry.get("visual_reasoning").unwrap();
1385        let result_ctx = visual_reasoning.execute(&ctx).unwrap();
1386
1387        // Verify basic visual analysis outputs
1388        assert_eq!(result_ctx.get("visual_type").unwrap(), "code_diagram");
1389        assert!(result_ctx.get("symbolic_elements_count").is_some());
1390        assert!(result_ctx.get("visual_complexity").is_some());
1391        assert!(result_ctx.get("conversion_confidence").is_some());
1392        assert!(result_ctx.get("visual_reasoning_timestamp").is_some());
1393
1394        // Verify symbolic mapping components
1395        assert!(result_ctx.get("symbolic_graph_nodes").is_some());
1396        assert!(result_ctx.get("symbolic_graph_edges").is_some());
1397        assert!(result_ctx.get("visual_semantic_tags").is_some());
1398        assert!(result_ctx.get("memory_integration_path").is_some());
1399
1400        // Test complexity and confidence scoring for code diagrams
1401        let complexity = result_ctx
1402            .get("visual_complexity")
1403            .unwrap()
1404            .parse::<f64>()
1405            .unwrap();
1406        assert!(complexity >= 0.0 && complexity <= 1.0);
1407
1408        let confidence = result_ctx
1409            .get("conversion_confidence")
1410            .unwrap()
1411            .parse::<f64>()
1412            .unwrap();
1413        assert!(confidence >= 0.6); // Code diagrams should have high confidence
1414
1415        // Test different visual types
1416        let mut ctx_screenshot = SymbolicContext::new();
1417        ctx_screenshot.set("visual_type", "screenshot");
1418        ctx_screenshot.set("analysis_mode", "ui_analysis");
1419
1420        let result_screenshot = visual_reasoning.execute(&ctx_screenshot).unwrap();
1421        assert_eq!(result_screenshot.get("visual_type").unwrap(), "screenshot");
1422
1423        // Screenshot confidence should be lower than code diagram
1424        let screenshot_confidence = result_screenshot
1425            .get("conversion_confidence")
1426            .unwrap()
1427            .parse::<f64>()
1428            .unwrap();
1429        assert!(screenshot_confidence < confidence); // Screenshots are more complex to analyze
1430
1431        // Test unknown visual type handling
1432        let mut ctx_unknown = SymbolicContext::new();
1433        ctx_unknown.set("visual_type", "unknown_format");
1434
1435        let result_unknown = visual_reasoning.execute(&ctx_unknown).unwrap();
1436        let unknown_confidence = result_unknown
1437            .get("conversion_confidence")
1438            .unwrap()
1439            .parse::<f64>()
1440            .unwrap();
1441        assert!(unknown_confidence <= 0.6); // Unknown formats should have lower confidence
1442    }
1443
1444    #[test]
1445    fn test_visual_reasoning_memory_integration() {
1446        let registry = default_operator_registry();
1447        let mut ctx = SymbolicContext::new();
1448
1449        ctx.set("visual_type", "architecture");
1450        ctx.set("analysis_mode", "system_design");
1451        ctx.set("visual_content", "microservices_architecture_diagram");
1452
1453        let visual_reasoning = registry.get("visual_reasoning").unwrap();
1454        let result_ctx = visual_reasoning.execute(&ctx).unwrap();
1455
1456        // Verify memory integration paths are properly set
1457        let integration_path = result_ctx.get("memory_integration_path").unwrap();
1458        assert!(integration_path.contains("visual.architecture.symbolic"));
1459
1460        // Verify DAG integration points
1461        assert!(result_ctx.get("dag_integration_points").is_some());
1462        assert_eq!(result_ctx.get("visual_context_preserved").unwrap(), "true");
1463
1464        // Test semantic tag generation
1465        let semantic_tags = result_ctx.get("visual_semantic_tags").unwrap();
1466        assert!(semantic_tags.contains("architecture"));
1467        assert!(semantic_tags.contains("system_design"));
1468    }
1469
1470    #[test]
1471    fn test_visual_reasoning_cognitive_cost() {
1472        let registry = default_operator_registry();
1473        let visual_reasoning = registry.get("visual_reasoning").unwrap();
1474
1475        // Visual reasoning should have high cognitive cost due to complex processing
1476        let cost = visual_reasoning.cognitive_cost();
1477        assert_eq!(cost, 2.5);
1478
1479        // Verify it's higher than simpler operators
1480        let add_op = registry.get("add").unwrap();
1481        assert!(cost > add_op.cognitive_cost());
1482
1483        let introspect_op = registry.get("introspect").unwrap();
1484        assert!(cost > introspect_op.cognitive_cost());
1485    }
1486
1487    #[test]
1488    fn test_visual_reasoning_uncertainty_model() {
1489        let registry = default_operator_registry();
1490        let visual_reasoning = registry.get("visual_reasoning").unwrap();
1491
1492        let uncertainty = visual_reasoning.uncertainty_propagation();
1493        assert_eq!(uncertainty.entropy, 0.25);
1494        assert_eq!(uncertainty.source, "visual_to_symbolic_conversion");
1495
1496        // Visual reasoning should have higher uncertainty than deterministic operators
1497        let add_op = registry.get("add").unwrap();
1498        let add_uncertainty = add_op.uncertainty_propagation();
1499        assert!(uncertainty.entropy > add_uncertainty.entropy);
1500    }
1501
1502    #[test]
1503    fn test_visual_reasoning_multiple_analysis_modes() {
1504        let registry = default_operator_registry();
1505        let visual_reasoning = registry.get("visual_reasoning").unwrap();
1506
1507        // Test diagram mode
1508        let mut ctx_diagram = SymbolicContext::new();
1509        ctx_diagram.set("visual_type", "flowchart");
1510        ctx_diagram.set("analysis_mode", "diagram");
1511        let result_diagram = visual_reasoning.execute(&ctx_diagram).unwrap();
1512
1513        // Test ui mode  
1514        let mut ctx_ui = SymbolicContext::new();
1515        ctx_ui.set("visual_type", "ui");
1516        ctx_ui.set("analysis_mode", "interface_analysis");
1517        let result_ui = visual_reasoning.execute(&ctx_ui).unwrap();
1518
1519        // Both should succeed but with different complexity scores
1520        let diagram_complexity = result_diagram
1521            .get("visual_complexity")
1522            .unwrap()
1523            .parse::<f64>()
1524            .unwrap();
1525        let ui_complexity = result_ui
1526            .get("visual_complexity")
1527            .unwrap()
1528            .parse::<f64>()
1529            .unwrap();
1530
1531        // Different visual types should produce different complexity scores
1532        assert!(diagram_complexity != ui_complexity);
1533        assert!(diagram_complexity >= 0.0 && diagram_complexity <= 1.0);
1534        assert!(ui_complexity >= 0.0 && ui_complexity <= 1.0);
1535    }
1536
1537    // === 🧑‍🤝‍🧑 INTER-AGENT OPERATOR TESTS ===
1538
1539    #[test]
1540    fn test_empathy_operator() {
1541        let registry = default_operator_registry();
1542        let mut ctx = SymbolicContext::new();
1543
1544        // Set up agent-specific context
1545        ctx.set("target_agent", "agent_1");
1546        ctx.set("agent_1.goal", "complete_task");
1547        ctx.set("agent_1.priority", "2.5");
1548        ctx.set("agent_1.task", "data_processing");
1549        ctx.set("agent_2.goal", "monitor_system"); // Different agent data
1550
1551        let empathy = registry.get("empathy").unwrap();
1552        let result_ctx = empathy.execute(&ctx).unwrap();
1553
1554        assert_eq!(result_ctx.get("target_agent").unwrap(), "agent_1");
1555        assert_eq!(result_ctx.get("agent_context_keys").unwrap(), "3");
1556        assert!(result_ctx.get("empathy_score").is_some());
1557        assert!(result_ctx.get("context_similarity").is_some());
1558        assert_eq!(
1559            result_ctx.get("empathy_model.goal").unwrap(),
1560            "complete_task"
1561        );
1562        assert_eq!(result_ctx.get("empathy_model.priority").unwrap(), "2.5");
1563    }
1564
1565    #[test]
1566    fn test_negotiate_operator() {
1567        let registry = default_operator_registry();
1568
1569        // Test majority negotiation
1570        let mut ctx_majority = SymbolicContext::new();
1571        ctx_majority.set("conflict_key", "goal");
1572        ctx_majority.set("strategy", "majority");
1573        ctx_majority.set("agent_1.goal", "option_a");
1574        ctx_majority.set("agent_2.goal", "option_a");
1575        ctx_majority.set("agent_3.goal", "option_b");
1576
1577        let negotiate = registry.get("negotiate").unwrap();
1578        let result_majority = negotiate.execute(&ctx_majority).unwrap();
1579
1580        assert_eq!(result_majority.get("resolved_value").unwrap(), "option_a");
1581        assert_eq!(
1582            result_majority.get("negotiation_result").unwrap(),
1583            "success"
1584        );
1585        assert_eq!(result_majority.get("agent_count").unwrap(), "3");
1586
1587        // Test no conflicts
1588        let mut ctx_empty = SymbolicContext::new();
1589        ctx_empty.set("conflict_key", "nonexistent");
1590
1591        let result_empty = negotiate.execute(&ctx_empty).unwrap();
1592        assert_eq!(
1593            result_empty.get("negotiation_result").unwrap(),
1594            "no_conflicts_found"
1595        );
1596
1597        // Test numeric average
1598        let mut ctx_numeric = SymbolicContext::new();
1599        ctx_numeric.set("conflict_key", "score");
1600        ctx_numeric.set("strategy", "average");
1601        ctx_numeric.set("agent_1.score", "8.5");
1602        ctx_numeric.set("agent_2.score", "7.0");
1603        ctx_numeric.set("agent_3.score", "9.5");
1604
1605        let result_numeric = negotiate.execute(&ctx_numeric).unwrap();
1606        let avg_value = result_numeric
1607            .get("resolved_value")
1608            .unwrap()
1609            .parse::<f64>()
1610            .unwrap();
1611        assert!((avg_value - 8.333).abs() < 0.01); // Average should be ~8.333
1612    }
1613
1614    #[test]
1615    fn test_consensus_operator() {
1616        let registry = default_operator_registry();
1617        let mut ctx = SymbolicContext::new();
1618
1619        // Set up multi-agent context with agreements and disagreements
1620        ctx.set("min_agreement", "0.6");
1621        ctx.set("agent_1.priority", "high");
1622        ctx.set("agent_2.priority", "high");
1623        ctx.set("agent_3.priority", "medium"); // Minority opinion
1624        ctx.set("agent_1.status", "ready");
1625        ctx.set("agent_2.status", "ready");
1626        ctx.set("agent_3.status", "ready"); // Full consensus
1627
1628        let consensus = registry.get("consensus").unwrap();
1629        let result_ctx = consensus.execute(&ctx).unwrap();
1630
1631        assert_eq!(result_ctx.get("agent_count").unwrap(), "3");
1632        assert_eq!(result_ctx.get("total_keys").unwrap(), "2");
1633
1634        // Should reach consensus on "status" (100% agreement) but not "priority" (66% agreement)
1635        assert_eq!(result_ctx.get("consensus.status").unwrap(), "ready");
1636        assert_eq!(result_ctx.get("consensus.priority").unwrap(), "high"); // Majority wins
1637
1638        let consensus_ratio = result_ctx
1639            .get("consensus_ratio")
1640            .unwrap()
1641            .parse::<f64>()
1642            .unwrap();
1643        assert!(consensus_ratio > 0.0);
1644
1645        assert!(result_ctx.get("avg_agreement").is_some());
1646        assert_eq!(result_ctx.get("agreement.status").unwrap(), "1.000"); // Perfect agreement
1647    }
1648
1649    #[test]
1650    fn test_new_operators_in_registry() {
1651        let registry = default_operator_registry();
1652
1653        // Verify all operators are registered
1654        let expected_operators = vec![
1655            "add",
1656            "compose",
1657            "if_then",
1658            "reflect",
1659            "delay", // Original operators
1660            "uncertainty_propagate",
1661            "doubt", // Uncertainty-aware
1662            "introspect",
1663            "cognitive_load",
1664            "attention_focus", // Meta-cognitive
1665            "meta_reflective",
1666            "visual_reasoning", // New meta-cognitive operators
1667            "empathy",
1668            "negotiate",
1669            "consensus", // Inter-agent
1670        ];
1671
1672        for operator_name in expected_operators {
1673            assert!(
1674                registry.contains_key(operator_name),
1675                "Missing operator: {}",
1676                operator_name
1677            );
1678        }
1679
1680        // Verify total count includes all operators
1681        assert_eq!(registry.len(), 15); // Original 5 + 10 cognitive operators
1682
1683        // Verify metadata is correctly set for existing operators
1684        let introspect = registry.get("introspect").unwrap();
1685        let metadata = introspect.metadata();
1686        assert_eq!(metadata.category, "meta");
1687        assert_eq!(metadata.name, "introspect");
1688
1689        let empathy = registry.get("empathy").unwrap();
1690        let empathy_metadata = empathy.metadata();
1691        assert_eq!(empathy_metadata.category, "multi-agent");
1692
1693        let uncertainty = registry.get("uncertainty_propagate").unwrap();
1694        let uncertainty_metadata = uncertainty.metadata();
1695        assert_eq!(uncertainty_metadata.category, "uncertainty");
1696
1697        // Verify the new operators specifically
1698        let meta_reflective = registry.get("meta_reflective").unwrap();
1699        let meta_metadata = meta_reflective.metadata();
1700        assert_eq!(meta_metadata.category, "meta");
1701        assert_eq!(meta_metadata.name, "meta_reflective");
1702        assert!(meta_reflective.cognitive_cost() > 1.0);
1703
1704        let visual_reasoning = registry.get("visual_reasoning").unwrap();
1705        let visual_metadata = visual_reasoning.metadata();
1706        assert_eq!(visual_metadata.category, "visual");
1707        assert_eq!(visual_metadata.name, "visual_reasoning");
1708        assert!(visual_reasoning.cognitive_cost() > 2.0);
1709    }
1710}