1use crate::memory_neuron_array::MemoryNeuronDetail;
14use crate::memory_stats_cache::MemoryStatsCache;
15use crate::service::{
16 MemoryCorticalAreaRuntimeInfo, PlasticityCommand, PlasticityConfig, PlasticityService,
17};
18use std::sync::{Arc, Mutex};
19use tracing::{debug, warn};
20
21pub trait PlasticityExecutor: Send + Sync {
27 fn notify_burst(&self, timestep: u64);
32
33 fn drain_commands(&self) -> Vec<PlasticityCommand>;
41
42 fn register_memory_area(
52 &self,
53 area_idx: u32,
54 area_name: String,
55 temporal_depth: u32,
56 upstream_areas: Vec<u32>,
57 lifecycle_config: Option<crate::MemoryNeuronLifecycleConfig>,
58 mp_learning_enabled: bool,
59 );
60
61 fn start(&mut self) {}
65
66 fn stop(&mut self) {}
70
71 fn is_running(&self) -> bool {
73 false }
75}
76
77pub struct AsyncPlasticityExecutor {
87 service: Arc<Mutex<Option<PlasticityService>>>,
89
90 memory_stats_cache: MemoryStatsCache,
92
93 _config: PlasticityConfig,
95
96 running: bool,
98}
99
100impl AsyncPlasticityExecutor {
101 pub fn new(
103 config: PlasticityConfig,
104 memory_stats_cache: MemoryStatsCache,
105 npu: Arc<feagi_npu_burst_engine::TracingMutex<feagi_npu_burst_engine::DynamicNPU>>,
106 ) -> Self {
107 let service = PlasticityService::new(config.clone(), memory_stats_cache.clone(), npu);
108
109 Self {
110 service: Arc::new(Mutex::new(Some(service))),
111 memory_stats_cache,
112 _config: config,
113 running: false,
114 }
115 }
116
117 pub fn get_memory_stats_cache(&self) -> MemoryStatsCache {
119 self.memory_stats_cache.clone()
120 }
121
122 pub fn get_service(&self) -> Option<PlasticityService> {
124 self.service.lock().ok()?.as_ref().cloned()
125 }
126
127 pub fn enqueue_commands_for_test(&self, commands: Vec<crate::PlasticityCommand>) {
128 if let Some(service) = self.service.lock().unwrap().as_ref() {
129 service.enqueue_commands_for_test(commands);
130 }
131 }
132
133 pub fn memory_cortical_area_runtime_info(
135 &self,
136 cortical_idx: u32,
137 ) -> Option<MemoryCorticalAreaRuntimeInfo> {
138 self.service
139 .lock()
140 .ok()?
141 .as_ref()
142 .map(|s| s.memory_cortical_area_runtime_info(cortical_idx))
143 }
144
145 pub fn memory_neuron_detail(&self, neuron_id: u32) -> Option<MemoryNeuronDetail> {
147 self.service
148 .lock()
149 .ok()?
150 .as_ref()
151 .and_then(|s| s.memory_neuron_detail(neuron_id))
152 }
153
154 pub fn paginated_memory_neuron_ids_in_area(
156 &self,
157 cortical_idx: u32,
158 offset: usize,
159 limit: usize,
160 ) -> Option<(Vec<u32>, usize)> {
161 let guard = self.service.lock().ok()?;
162 let service = guard.as_ref()?;
163 let array_arc = service.get_memory_neuron_array();
164 let array = array_arc.lock().ok()?;
165 Some(array.paginated_neuron_ids_in_area(cortical_idx, offset, limit))
166 }
167}
168
169impl PlasticityExecutor for AsyncPlasticityExecutor {
170 fn notify_burst(&self, timestep: u64) {
171 if let Some(service) = self.service.lock().unwrap().as_ref() {
173 service.notify_burst(timestep);
174 } else {
175 warn!("[PLASTICITY-EXEC] ⚠️ Service is None, cannot notify");
176 }
177 }
178
179 fn drain_commands(&self) -> Vec<PlasticityCommand> {
180 if let Some(service) = self.service.lock().unwrap().as_ref() {
181 let drained = service.drain_commands();
182 if !drained.is_empty() {
183 debug!(
184 target: "plasticity",
185 "[PLASTICITY-EXEC] Drained {} command(s) from executor",
186 drained.len()
187 );
188 for command in &drained {
189 match command {
190 PlasticityCommand::RegisterMemoryNeuron {
191 neuron_id,
192 area_idx,
193 ..
194 } => {
195 debug!(
196 target: "plasticity",
197 "[PLASTICITY-EXEC] RegisterMemoryNeuron area={} neuron_id={}",
198 area_idx,
199 neuron_id
200 );
201 }
202 PlasticityCommand::MemoryNeuronConvertedToLtm {
203 neuron_id,
204 area_idx,
205 ..
206 } => {
207 debug!(
208 target: "plasticity",
209 "[PLASTICITY-EXEC] MemoryNeuronConvertedToLtm area={} neuron_id={}",
210 area_idx,
211 neuron_id
212 );
213 }
214 PlasticityCommand::InjectMemoryNeuronToFCL {
215 neuron_id,
216 area_idx,
217 is_reactivation,
218 replay_frames,
219 ..
220 } => {
221 debug!(
222 target: "plasticity",
223 "[PLASTICITY-EXEC] InjectMemoryNeuronToFCL area={} neuron_id={} reactivation={} replay_frames={}",
224 area_idx,
225 neuron_id,
226 is_reactivation,
227 replay_frames.len()
228 );
229 }
230 PlasticityCommand::UpdateWeightsDelta { .. } => {}
231 PlasticityCommand::UpdateStateCounters { .. } => {}
232 PlasticityCommand::ResetMemoryNeuronsInArea { cortical_idx } => {
233 debug!(
234 target: "plasticity",
235 "[PLASTICITY-EXEC] ResetMemoryNeuronsInArea cortical_idx={}",
236 cortical_idx
237 );
238 }
239 }
240 }
241 }
242 drained
243 } else {
244 Vec::new()
245 }
246 }
247
248 fn register_memory_area(
249 &self,
250 area_idx: u32,
251 area_name: String,
252 temporal_depth: u32,
253 upstream_areas: Vec<u32>,
254 lifecycle_config: Option<crate::MemoryNeuronLifecycleConfig>,
255 mp_learning_enabled: bool,
256 ) {
257 if let Some(service) = self.service.lock().unwrap().as_mut() {
258 service.register_memory_area(
259 area_idx,
260 area_name,
261 temporal_depth,
262 upstream_areas,
263 lifecycle_config,
264 mp_learning_enabled,
265 );
266 }
267 }
268
269 fn start(&mut self) {
270 if self.running {
271 tracing::warn!(target: "plasticity", "⚠️ PlasticityExecutor already running");
272 return;
273 }
274
275 if let Some(service) = self.service.lock().unwrap().as_ref() {
276 tracing::info!(target: "plasticity", "🚀 Initializing AsyncPlasticityExecutor...");
277 service.start();
278 self.running = true;
279 tracing::info!(target: "plasticity",
280 "✅ AsyncPlasticityExecutor started successfully - ready to monitor memory areas and process STDP"
281 );
282 } else {
283 tracing::error!(target: "plasticity", "❌ Failed to start PlasticityExecutor - service not initialized");
284 }
285 }
286
287 fn stop(&mut self) {
288 if !self.running {
289 return;
290 }
291
292 if let Some(service) = self.service.lock().unwrap().as_ref() {
293 service.stop();
294 self.running = false;
295 tracing::info!("Stopped async plasticity executor");
296 }
297 }
298
299 fn is_running(&self) -> bool {
300 self.running
301 }
302}
303
304#[cfg(not(feature = "std"))]
325pub struct SyncPlasticityExecutor {
326 _marker: core::marker::PhantomData<()>,
328}
329
330#[cfg(not(feature = "std"))]
331impl PlasticityExecutor for SyncPlasticityExecutor {
332 fn notify_burst(&self, _timestep: u64) {
333 unimplemented!("SyncPlasticityExecutor not yet implemented");
334 }
335
336 fn drain_commands(&self) -> Vec<PlasticityCommand> {
337 unimplemented!("SyncPlasticityExecutor not yet implemented");
338 }
339
340 fn register_memory_area(
341 &self,
342 _area_idx: u32,
343 _area_name: String,
344 _temporal_depth: u32,
345 _upstream_areas: Vec<u32>,
346 _lifecycle_config: Option<crate::MemoryNeuronLifecycleConfig>,
347 _mp_learning_enabled: bool,
348 ) {
349 unimplemented!("SyncPlasticityExecutor not yet implemented");
350 }
351}