Skip to main content

microscope_memory/
mental_sandbox.rs

1//! Mental sandbox for pre-action scenario simulation.
2//! Provides a safe environment to test different action paths before committing.
3
4use std::collections::HashMap;
5use std::sync::{Arc, RwLock};
6
7/// Represents a simulated scenario with its outcome
8#[derive(Debug, Clone)]
9pub struct Scenario {
10    pub id: String,
11    pub description: String,
12    pub actions: Vec<String>,
13    pub outcome_probability: f32,
14    pub risk_score: f32,
15    pub reward_potential: f32,
16}
17
18/// Maximum scenarios kept in memory before automatic purge of oldest.
19const MAX_SCENARIOS: usize = 100;
20
21/// Mental sandbox that simulates multiple scenarios
22pub struct MentalSandbox {
23    scenarios: Arc<RwLock<HashMap<String, Scenario>>>,
24    current_simulation: Arc<RwLock<Option<String>>>,
25    long_term_goals: Vec<String>,
26}
27
28impl Default for MentalSandbox {
29    fn default() -> Self {
30        Self::new()
31    }
32}
33
34impl MentalSandbox {
35    /// Create a new mental sandbox
36    pub fn new() -> Self {
37        Self {
38            scenarios: Arc::new(RwLock::new(HashMap::new())),
39            current_simulation: Arc::new(RwLock::new(None)),
40            long_term_goals: Vec::new(),
41        }
42    }
43
44    /// Add a long-term goal for scenario evaluation
45    pub fn add_goal(&mut self, goal: &str) {
46        self.long_term_goals.push(goal.to_string());
47    }
48
49    /// Simulate a scenario before real action
50    pub fn simulate_scenario(&self, description: &str, actions: Vec<&str>) -> Scenario {
51        let id = format!("scenario_{}", rand::random::<u32>());
52
53        // Simple heuristic scoring based on goal alignment
54        let goal_alignment = self.calculate_goal_alignment(description);
55        let complexity_factor = actions.len() as f32 * 0.1;
56
57        let scenario = Scenario {
58            id: id.clone(),
59            description: description.to_string(),
60            actions: actions.iter().map(|s| s.to_string()).collect(),
61            outcome_probability: 0.7, // base probability
62            risk_score: (1.0 - goal_alignment) * complexity_factor,
63            reward_potential: goal_alignment * (1.0 - complexity_factor.min(1.0)),
64        };
65
66        let mut scenarios = crate::sync_guard::write_lock(&self.scenarios);
67        scenarios.insert(id.clone(), scenario.clone());
68
69        // Automatic purge: if over MAX_SCENARIOS, remove oldest entries
70        if scenarios.len() > MAX_SCENARIOS {
71            let excess = scenarios.len() - MAX_SCENARIOS;
72            let keys: Vec<String> = scenarios.keys().take(excess).cloned().collect();
73            for k in keys {
74                scenarios.remove(&k);
75            }
76        }
77
78        let mut current = crate::sync_guard::write_lock(&self.current_simulation);
79        *current = Some(id);
80
81        scenario
82    }
83
84    /// Calculate how well a scenario aligns with long-term goals
85    fn calculate_goal_alignment(&self, description: &str) -> f32 {
86        if self.long_term_goals.is_empty() {
87            return 0.5; // neutral alignment
88        }
89
90        let keywords = description.to_lowercase();
91        let mut matches = 0.0;
92
93        for goal in &self.long_term_goals {
94            let goal_lower = goal.to_lowercase();
95            if keywords.contains(&goal_lower) {
96                matches += 1.0;
97            }
98        }
99
100        matches / self.long_term_goals.len() as f32
101    }
102
103    /// Get the best scenario based on risk/reward ratio
104    pub fn get_best_scenario(&self) -> Option<Scenario> {
105        let scenarios = crate::sync_guard::read_lock(&self.scenarios);
106
107        scenarios
108            .values()
109            .max_by(|a, b| {
110                let a_score = a.reward_potential / (a.risk_score + 0.01);
111                let b_score = b.reward_potential / (b.risk_score + 0.01);
112                a_score.total_cmp(&b_score)
113            })
114            .cloned()
115    }
116
117    /// Clear all simulated scenarios
118    pub fn clear(&mut self) {
119        crate::sync_guard::write_lock(&self.scenarios).clear();
120        *crate::sync_guard::write_lock(&self.current_simulation) = None;
121    }
122}
123
124/// Run multiple scenario simulations in parallel
125pub fn run_parallel_simulations(
126    sandbox: &MentalSandbox,
127    scenario_descriptions: &[(&str, Vec<&str>)],
128) -> Vec<Scenario> {
129    scenario_descriptions
130        .iter()
131        .map(|(desc, actions)| sandbox.simulate_scenario(desc, actions.clone()))
132        .collect()
133}