1use std::collections::{HashMap, VecDeque};
6use std::sync::{Arc, RwLock};
7use std::time::{SystemTime, UNIX_EPOCH};
8
9#[derive(Debug, Clone, PartialEq)]
10pub enum ModuleState {
11 Idle,
12 Running,
13 Blocked(String),
14 Error(String),
15 Exhausted,
16}
17#[derive(Debug, Clone)]
18pub struct CognitiveModule {
19 pub id: String,
20 pub name: String,
21 pub priority: u8,
22 pub energy_cost: f64,
23 pub state: ModuleState,
24 pub last_run_ms: u64,
25 pub run_count: u64,
26 pub avg_duration_ms: f64,
27 pub tags: Vec<String>,
28}
29
30#[derive(Debug, Clone)]
31pub struct CognitiveResources {
32 pub attention_budget: f64,
33 pub energy_level: f64,
34 pub time_budget_ms: u64,
35 pub working_memory_load: f64,
36 pub context_switches: u64,
37}
38
39#[derive(Debug, Clone)]
40pub struct ExecutionPlan {
41 pub module_order: Vec<String>,
42 pub total_energy: f64,
43 pub estimated_duration_ms: u64,
44 pub priority: u8,
45 pub reason: String,
46}
47
48#[derive(Debug, Clone)]
49pub struct ExecutionLogEntry {
50 pub timestamp_ms: u64,
51 pub module_id: String,
52 pub action: String,
53 pub duration_ms: u64,
54 pub energy_used: f64,
55 pub success: bool,
56 pub detail: String,
57}
58
59#[derive(Debug, Clone)]
60pub struct ExecutiveConfig {
61 pub max_modules_per_cycle: usize,
62 pub min_energy_for_execution: f64,
63 pub energy_regen_rate: f64,
64 pub critical_energy_threshold: f64,
65 pub attention_decay_rate: f64,
66 pub log_retention: usize,
67}
68
69impl Default for ExecutiveConfig {
70 fn default() -> Self {
71 Self {
72 max_modules_per_cycle: 5,
73 min_energy_for_execution: 0.1,
74 energy_regen_rate: 0.02,
75 critical_energy_threshold: 0.15,
76 attention_decay_rate: 0.05,
77 log_retention: 500,
78 }
79 }
80}
81pub struct Executive {
82 modules: Arc<RwLock<HashMap<String, CognitiveModule>>>,
83 resources: Arc<RwLock<CognitiveResources>>,
84 log: Arc<RwLock<VecDeque<ExecutionLogEntry>>>,
85 config: Arc<RwLock<ExecutiveConfig>>,
86 current_plan: Arc<RwLock<Option<ExecutionPlan>>>,
87 module_queue: Arc<RwLock<VecDeque<String>>>,
88}
89
90impl Default for Executive {
91 fn default() -> Self {
92 Self::new()
93 }
94}
95
96impl Executive {
97 pub fn new() -> Self {
98 Self {
99 modules: Arc::new(RwLock::new(HashMap::new())),
100 resources: Arc::new(RwLock::new(CognitiveResources {
101 attention_budget: 1.0,
102 energy_level: 1.0,
103 time_budget_ms: 1000,
104 working_memory_load: 0.0,
105 context_switches: 0,
106 })),
107 log: Arc::new(RwLock::new(VecDeque::with_capacity(500))),
108 config: Arc::new(RwLock::new(ExecutiveConfig::default())),
109 current_plan: Arc::new(RwLock::new(None)),
110 module_queue: Arc::new(RwLock::new(VecDeque::new())),
111 }
112 }
113
114 fn now_ms(&self) -> u64 {
115 SystemTime::now()
116 .duration_since(UNIX_EPOCH)
117 .unwrap_or_default()
118 .as_millis() as u64
119 }
120
121 pub fn register_module(
122 &self,
123 id: &str,
124 name: &str,
125 priority: u8,
126 energy_cost: f64,
127 tags: Vec<String>,
128 ) {
129 crate::sync_guard::write_lock(&self.modules).insert(
130 id.to_string(),
131 CognitiveModule {
132 id: id.to_string(),
133 name: name.to_string(),
134 priority,
135 energy_cost,
136 state: ModuleState::Idle,
137 last_run_ms: 0,
138 run_count: 0,
139 avg_duration_ms: 0.0,
140 tags,
141 },
142 );
143 }
144
145 pub fn module_state(&self, id: &str) -> Option<ModuleState> {
146 crate::sync_guard::read_lock(&self.modules)
147 .get(id)
148 .map(|m| m.state.clone())
149 }
150
151 pub fn set_module_state(&self, id: &str, state: ModuleState) -> bool {
152 crate::sync_guard::write_lock(&self.modules)
153 .get_mut(id)
154 .map(|m| {
155 m.state = state;
156 true
157 })
158 .unwrap_or(false)
159 }
160
161 pub fn list_modules(&self) -> Vec<CognitiveModule> {
162 crate::sync_guard::read_lock(&self.modules)
163 .values()
164 .cloned()
165 .collect()
166 }
167
168 pub fn set_priority(&self, id: &str, priority: u8) -> bool {
169 crate::sync_guard::write_lock(&self.modules)
170 .get_mut(id)
171 .map(|m| {
172 m.priority = priority;
173 true
174 })
175 .unwrap_or(false)
176 }
177
178 pub fn resources(&self) -> CognitiveResources {
179 crate::sync_guard::read_lock(&self.resources).clone()
180 }
181
182 pub fn update_resources(&self, f: impl Fn(&mut CognitiveResources)) {
183 f(&mut crate::sync_guard::write_lock(&self.resources));
184 }
185
186 pub fn schedule(&self) -> ExecutionPlan {
187 let modules = crate::sync_guard::read_lock(&self.modules);
188 let mut sorted: Vec<&CognitiveModule> = modules
189 .values()
190 .filter(|m| m.state == ModuleState::Idle || m.state == ModuleState::Running)
191 .collect();
192 sorted.sort_by_key(|b| std::cmp::Reverse(b.priority));
193 let order: Vec<String> = sorted.iter().map(|m| m.id.clone()).collect();
194 let energy: f64 = sorted.iter().map(|m| m.energy_cost).sum();
195 let plan = ExecutionPlan {
196 module_order: order.clone(),
197 total_energy: energy,
198 estimated_duration_ms: sorted.len() as u64 * 100,
199 priority: sorted.first().map(|m| m.priority).unwrap_or(0),
200 reason: format!("{} modules, {:.2} energy", sorted.len(), energy),
201 };
202 let mut queue = crate::sync_guard::write_lock(&self.module_queue);
203 queue.clear();
204 for id in &order {
205 queue.push_back(id.clone());
206 }
207 *crate::sync_guard::write_lock(&self.current_plan) = Some(plan.clone());
208 plan
209 }
210
211 pub fn execute_next(&self) -> Option<String> {
212 let next = crate::sync_guard::write_lock(&self.module_queue).pop_front()?;
213 {
214 let mut res = crate::sync_guard::write_lock(&self.resources);
215 if let Some(m) = crate::sync_guard::read_lock(&self.modules).get(&next) {
216 res.energy_level = (res.energy_level - m.energy_cost * 0.01).max(0.0);
217 res.context_switches += 1;
218 }
219 }
220 let now = self.now_ms();
221 crate::sync_guard::write_lock(&self.log).push_back(ExecutionLogEntry {
222 timestamp_ms: now,
223 module_id: next.clone(),
224 action: "execute".to_string(),
225 duration_ms: 100,
226 energy_used: 0.01,
227 success: true,
228 detail: "Scheduled by executive".to_string(),
229 });
230 if let Some(m) = crate::sync_guard::write_lock(&self.modules).get_mut(&next) {
231 m.last_run_ms = now;
232 m.run_count += 1;
233 m.state = ModuleState::Running;
234 }
235 Some(next)
236 }
237}
238impl Executive {
239 pub fn cycle(&self) -> Vec<String> {
240 let config = crate::sync_guard::read_lock(&self.config).clone();
241 let mut executed = Vec::new();
242 self.schedule();
243 if crate::sync_guard::read_lock(&self.resources).energy_level
244 < config.min_energy_for_execution
245 {
246 return vec!["__low_energy__".to_string()];
247 }
248 for _ in 0..config.max_modules_per_cycle {
249 if let Some(id) = self.execute_next() {
250 executed.push(id);
251 } else {
252 break;
253 }
254 }
255 self.update_resources(|r| {
256 r.energy_level = (r.energy_level + config.energy_regen_rate).min(1.0);
257 if r.energy_level > 0.9 {
258 r.attention_budget = 1.0;
259 }
260 });
261 executed
262 }
263
264 pub fn homeostasis(&self) -> Vec<String> {
265 let mut actions = Vec::new();
266 let res = crate::sync_guard::read_lock(&self.resources).clone();
267 let config = crate::sync_guard::read_lock(&self.config).clone();
268 if res.energy_level < config.critical_energy_threshold {
269 let mut modules = crate::sync_guard::write_lock(&self.modules);
270 for m in modules.values_mut() {
271 if m.priority < 100 && m.state == ModuleState::Running {
272 m.state = ModuleState::Exhausted;
273 actions.push(format!("suspended_{}", m.id));
274 }
275 }
276 actions.push("energy_conservation".to_string());
277 }
278 if res.context_switches > 1000 {
279 self.update_resources(|r| r.context_switches = 0);
280 actions.push("context_switch_throttle".to_string());
281 }
282 actions
283 }
284
285 pub fn stats(&self) -> (usize, usize, f64, f64) {
286 let m = crate::sync_guard::read_lock(&self.modules);
287 let r = crate::sync_guard::read_lock(&self.resources);
288 (
289 m.len(),
290 m.values()
291 .filter(|m| m.state == ModuleState::Running)
292 .count(),
293 r.energy_level,
294 r.attention_budget,
295 )
296 }
297
298 pub fn recent_log(&self, k: usize) -> Vec<ExecutionLogEntry> {
299 crate::sync_guard::read_lock(&self.log)
300 .iter()
301 .rev()
302 .take(k)
303 .cloned()
304 .collect()
305 }
306
307 pub fn recommend_module(&self, vagus_tone: Option<f64>) -> Option<String> {
308 let modules = crate::sync_guard::read_lock(&self.modules);
309 let res = crate::sync_guard::read_lock(&self.resources);
310 let mut candidates: Vec<&CognitiveModule> = modules
311 .values()
312 .filter(|m| m.state == ModuleState::Idle && m.energy_cost <= res.energy_level)
313 .collect();
314 if candidates.is_empty() {
315 return None;
316 }
317 if let Some(tone) = vagus_tone {
318 if tone < 0.4 {
319 candidates.sort_by(|a, b| {
320 let a_stress = a.tags.contains(&"stress".to_string()) as u8;
321 let b_stress = b.tags.contains(&"stress".to_string()) as u8;
322 b_stress
323 .cmp(&a_stress)
324 .then_with(|| b.priority.cmp(&a.priority))
325 });
326 } else {
327 candidates.sort_by_key(|b| std::cmp::Reverse(b.priority));
328 }
329 } else {
330 candidates.sort_by_key(|b| std::cmp::Reverse(b.priority));
331 }
332 Some(candidates[0].id.clone())
333 }
334}