feagi_services/traits/runtime_service.rs
1// Copyright 2025 Neuraville Inc.
2// SPDX-License-Identifier: Apache-2.0
3
4/*!
5Runtime control service trait.
6
7Defines the stable interface for controlling the FEAGI burst engine runtime.
8
9Copyright 2025 Neuraville Inc.
10Licensed under the Apache License, Version 2.0
11*/
12
13use crate::types::*;
14use async_trait::async_trait;
15
16/// Manual stimulation injection behavior.
17///
18/// - `Candidate`: inject into FCL candidates (normal dynamics path)
19/// - `ForceFire`: stage neurons to be emitted in next burst fire queue
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub enum ManualStimulationMode {
22 Candidate,
23 ForceFire,
24}
25
26/// Runtime control service (transport-agnostic)
27#[async_trait]
28pub trait RuntimeService: Send + Sync {
29 /// Start the burst engine
30 ///
31 /// Begins executing neural bursts at the configured frequency.
32 ///
33 /// # Errors
34 /// * `ServiceError::InvalidState` - Already running
35 /// * `ServiceError::Backend` - Failed to start burst engine
36 ///
37 async fn start(&self) -> ServiceResult<()>;
38
39 /// Stop the burst engine
40 ///
41 /// Gracefully stops burst execution.
42 ///
43 /// # Errors
44 /// * `ServiceError::Backend` - Failed to stop burst engine
45 ///
46 async fn stop(&self) -> ServiceResult<()>;
47
48 /// Pause the burst engine
49 ///
50 /// Temporarily pauses burst execution without stopping the thread.
51 ///
52 /// # Errors
53 /// * `ServiceError::InvalidState` - Not running
54 /// * `ServiceError::Backend` - Failed to pause
55 ///
56 async fn pause(&self) -> ServiceResult<()>;
57
58 /// Resume the burst engine
59 ///
60 /// Resumes burst execution after pause.
61 ///
62 /// # Errors
63 /// * `ServiceError::InvalidState` - Not paused
64 /// * `ServiceError::Backend` - Failed to resume
65 ///
66 async fn resume(&self) -> ServiceResult<()>;
67
68 /// Execute a single burst step
69 ///
70 /// Executes one burst cycle and then pauses.
71 /// Useful for debugging and step-by-step execution.
72 ///
73 /// # Errors
74 /// * `ServiceError::InvalidState` - Already running in continuous mode
75 /// * `ServiceError::Backend` - Failed to execute step
76 ///
77 async fn step(&self) -> ServiceResult<()>;
78
79 /// Get runtime status
80 ///
81 /// Returns the current state of the burst engine.
82 ///
83 /// # Returns
84 /// * `RuntimeStatus` - Current runtime status
85 ///
86 async fn get_status(&self) -> ServiceResult<RuntimeStatus>;
87
88 /// Set burst frequency
89 ///
90 /// Changes the burst execution frequency (Hz).
91 ///
92 /// # Arguments
93 /// * `frequency_hz` - New frequency in Hz (e.g., 30.0)
94 ///
95 /// # Errors
96 /// * `ServiceError::InvalidInput` - Invalid frequency (must be > 0)
97 ///
98 async fn set_frequency(&self, frequency_hz: f64) -> ServiceResult<()>;
99
100 /// Get current burst count
101 ///
102 /// Returns the total number of bursts executed since start.
103 ///
104 /// # Returns
105 /// * `u64` - Total burst count
106 ///
107 async fn get_burst_count(&self) -> ServiceResult<u64>;
108
109 /// Reset burst count
110 ///
111 /// Resets the burst counter to zero.
112 ///
113 async fn reset_burst_count(&self) -> ServiceResult<()>;
114
115 /// Get FCL (Fire Candidate List) snapshot for monitoring
116 ///
117 /// Returns vector of (neuron_id, potential) pairs from last burst
118 ///
119 /// # Returns
120 /// * `Vec<(u64, f32)>` - Neuron IDs and their membrane potentials
121 ///
122 async fn get_fcl_snapshot(&self) -> ServiceResult<Vec<(u64, f32)>>;
123
124 /// Get Fire Candidate List snapshot with cortical area information
125 ///
126 /// Returns the last FCL snapshot with cortical_idx for each neuron.
127 /// This avoids the need to query cortical_area for each neuron separately.
128 ///
129 /// # Returns
130 /// * `Vec<(u64, u32, f32)>` - (neuron_id, cortical_idx, membrane_potential) tuples
131 ///
132 async fn get_fcl_snapshot_with_cortical_idx(&self) -> ServiceResult<Vec<(u64, u32, f32)>>;
133
134 /// Get Fire Queue sample for monitoring
135 ///
136 /// Returns neurons that actually fired in the last burst, organized by cortical area
137 ///
138 /// # Returns
139 /// * `HashMap<u32, (Vec<u32>, Vec<u32>, Vec<u32>, Vec<u32>, Vec<f32>)>` - Area data
140 ///
141 async fn get_fire_queue_sample(
142 &self,
143 ) -> ServiceResult<
144 std::collections::HashMap<u32, (Vec<u32>, Vec<u32>, Vec<u32>, Vec<u32>, Vec<f32>)>,
145 >;
146
147 /// Get Fire Ledger window configurations for all cortical areas
148 ///
149 /// # Returns
150 /// * `Vec<(u32, usize)>` - (cortical_idx, window_size) pairs
151 ///
152 async fn get_fire_ledger_configs(&self) -> ServiceResult<Vec<(u32, usize)>>;
153
154 /// Configure Fire Ledger window size for a cortical area
155 ///
156 /// # Arguments
157 /// * `cortical_idx` - Cortical area index
158 /// * `window_size` - Number of bursts to retain in history
159 ///
160 async fn configure_fire_ledger_window(
161 &self,
162 cortical_idx: u32,
163 window_size: usize,
164 ) -> ServiceResult<()>;
165
166 /// Get FCL/FQ sampler configuration
167 ///
168 /// # Returns
169 /// * `(f64, u32)` - (frequency_hz, consumer_type) where consumer: 1=viz, 2=motor, 3=both
170 ///
171 async fn get_fcl_sampler_config(&self) -> ServiceResult<(f64, u32)>;
172
173 /// Set FCL/FQ sampler configuration
174 ///
175 /// # Arguments
176 /// * `frequency` - Optional sampling frequency in Hz
177 /// * `consumer` - Optional consumer type (1=viz, 2=motor, 3=both)
178 ///
179 async fn set_fcl_sampler_config(
180 &self,
181 frequency: Option<f64>,
182 consumer: Option<u32>,
183 ) -> ServiceResult<()>;
184
185 /// Get FCL sample rate for a specific cortical area
186 ///
187 /// # Arguments
188 /// * `area_id` - Cortical area ID (cortical_idx)
189 ///
190 /// # Returns
191 /// * `f64` - Sample rate in Hz
192 ///
193 async fn get_area_fcl_sample_rate(&self, area_id: u32) -> ServiceResult<f64>;
194
195 /// Set FCL sample rate for a specific cortical area
196 ///
197 /// # Arguments
198 /// * `area_id` - Cortical area ID (cortical_idx)
199 /// * `sample_rate` - Sample rate in Hz
200 ///
201 async fn set_area_fcl_sample_rate(&self, area_id: u32, sample_rate: f64) -> ServiceResult<()>;
202
203 /// Inject sensory data by cortical area ID and coordinates
204 ///
205 /// Takes cortical ID (base64 string) and coordinates with potential values,
206 /// converts coordinates to neuron IDs, and injects them into FCL.
207 ///
208 /// # Arguments
209 /// * `cortical_id` - Base64 encoded cortical area ID
210 /// * `xyzp_data` - Vector of (x, y, z, potential) tuples
211 ///
212 /// # Returns
213 /// * Number of neurons successfully injected
214 ///
215 /// # Errors
216 /// * `ServiceError::NotFound` - Cortical area not found
217 /// * `ServiceError::InvalidInput` - Invalid cortical ID format
218 ///
219 async fn inject_sensory_by_coordinates(
220 &self,
221 cortical_id: &str,
222 xyzp_data: &[(u32, u32, u32, f32)],
223 mode: ManualStimulationMode,
224 ) -> ServiceResult<usize>;
225
226 /// Register motor subscriptions with per-agent rate limits.
227 ///
228 /// # Arguments
229 /// * `agent_id` - Unique agent identifier
230 /// * `cortical_ids` - List of cortical IDs to subscribe to
231 /// * `rate_hz` - Motor publish rate (Hz)
232 ///
233 async fn register_motor_subscriptions(
234 &self,
235 agent_id: &str,
236 cortical_ids: Vec<String>,
237 rate_hz: f64,
238 ) -> ServiceResult<()>;
239
240 /// Register visualization subscriptions with per-agent rate limits.
241 ///
242 /// # Arguments
243 /// * `agent_id` - Unique agent identifier
244 /// * `rate_hz` - Visualization publish rate (Hz)
245 ///
246 async fn register_visualization_subscriptions(
247 &self,
248 agent_id: &str,
249 rate_hz: f64,
250 ) -> ServiceResult<()>;
251
252 /// Unregister motor subscriptions for a disconnected agent.
253 ///
254 /// Called when an agent is deregistered (e.g. descriptor replacement, timeout).
255 fn unregister_motor_subscriptions(&self, agent_id: &str);
256
257 /// Unregister visualization subscriptions for a disconnected agent.
258 ///
259 /// Called when an agent is deregistered (e.g. descriptor replacement, timeout).
260 fn unregister_visualization_subscriptions(&self, agent_id: &str);
261}