omega_runtime/
runtime.rs

1//! Main runtime orchestrator for the Omega system
2
3use crate::config::OmegaConfig;
4use crate::error::{RuntimeError, RuntimeResult};
5use crate::events::{EventBus, EventHandler, OmegaEvent};
6use omega_agentdb::{AgentDB, AgentDBConfig};
7use omega_loops::LoopEngine;
8use omega_memory::CosmicMemory;
9use omega_meta_sona::MetaSONA;
10use parking_lot::RwLock;
11use std::sync::Arc;
12use tracing::{debug, info};
13
14/// Runtime state machine
15#[derive(Debug, Clone, Copy, PartialEq, Eq)]
16pub enum RuntimeState {
17    /// Runtime has not been initialized
18    Uninitialized,
19    /// Runtime is currently initializing
20    Initializing,
21    /// Runtime is running normally
22    Running,
23    /// Runtime is paused
24    Paused,
25    /// Runtime is shutting down
26    ShuttingDown,
27    /// Runtime has stopped
28    Stopped,
29}
30
31impl RuntimeState {
32    /// Check if a state transition is valid
33    pub fn can_transition_to(&self, target: RuntimeState) -> bool {
34        use RuntimeState::*;
35        matches!(
36            (self, target),
37            (Uninitialized, Initializing)
38                | (Initializing, Running)
39                | (Initializing, Stopped)
40                | (Running, Paused)
41                | (Running, ShuttingDown)
42                | (Paused, Running)
43                | (Paused, ShuttingDown)
44                | (ShuttingDown, Stopped)
45        )
46    }
47
48    /// Get a human-readable description of the state
49    pub fn description(&self) -> &'static str {
50        match self {
51            RuntimeState::Uninitialized => "uninitialized",
52            RuntimeState::Initializing => "initializing",
53            RuntimeState::Running => "running",
54            RuntimeState::Paused => "paused",
55            RuntimeState::ShuttingDown => "shutting down",
56            RuntimeState::Stopped => "stopped",
57        }
58    }
59}
60
61/// Main runtime orchestrator for the Omega system
62pub struct OmegaRuntime {
63    config: OmegaConfig,
64    agentdb: Arc<AgentDB>,
65    memory: Arc<CosmicMemory>,
66    loops: Arc<LoopEngine>,
67    meta_sona: Arc<MetaSONA>,
68    event_bus: Arc<RwLock<EventBus>>,
69    state: Arc<RwLock<RuntimeState>>,
70}
71
72impl OmegaRuntime {
73    /// Create a new OmegaRuntime instance
74    pub async fn new(config: OmegaConfig) -> RuntimeResult<Self> {
75        info!("Creating OmegaRuntime with configuration");
76
77        // Validate configuration
78        config.validate().map_err(|e| {
79            RuntimeError::Config(format!("Invalid configuration: {}", e))
80        })?;
81
82        // Create subsystems with async constructors where needed
83        let agentdb = Arc::new(
84            AgentDB::new(AgentDBConfig::default())
85                .await
86                .map_err(|e| RuntimeError::AgentDB(e.to_string()))?
87        );
88
89        let memory = Arc::new(
90            CosmicMemory::new()
91                .await
92                .map_err(|e| RuntimeError::Memory(e.to_string()))?
93        );
94
95        let loops = Arc::new(LoopEngine::new());
96        let meta_sona = Arc::new(MetaSONA::new());
97
98        let event_bus = if config.enable_event_logging {
99            Arc::new(RwLock::new(EventBus::new()))
100        } else {
101            Arc::new(RwLock::new(EventBus::with_buffer_size(0)))
102        };
103
104        Ok(Self {
105            config,
106            agentdb,
107            memory,
108            loops,
109            meta_sona,
110            event_bus,
111            state: Arc::new(RwLock::new(RuntimeState::Uninitialized)),
112        })
113    }
114
115    /// Start the runtime and all subsystems
116    pub async fn start(&self) -> RuntimeResult<()> {
117        self.transition_state(RuntimeState::Initializing)?;
118
119        info!("Starting OmegaRuntime");
120
121        // Subsystems are initialized during construction
122        // Here we just transition to running state
123        debug!("AgentDB ready");
124        debug!("Memory system ready");
125        debug!("Loop engine ready");
126        debug!("Meta-SONA ready");
127
128        self.transition_state(RuntimeState::Running)?;
129
130        self.emit_event(OmegaEvent::SystemStarted {
131            timestamp: chrono::Utc::now(),
132        });
133
134        info!("OmegaRuntime started successfully");
135        Ok(())
136    }
137
138    /// Stop the runtime and shutdown all subsystems
139    pub async fn stop(&self) -> RuntimeResult<()> {
140        self.transition_state(RuntimeState::ShuttingDown)?;
141
142        info!("Stopping OmegaRuntime");
143
144        // Subsystems will be dropped when runtime is dropped
145        // Here we just transition to stopped state
146        debug!("Meta-SONA stopping");
147        debug!("Loop engine stopping");
148        debug!("Memory system stopping");
149        debug!("AgentDB stopping");
150
151        self.transition_state(RuntimeState::Stopped)?;
152
153        self.emit_event(OmegaEvent::SystemShutdown {
154            timestamp: chrono::Utc::now(),
155        });
156
157        info!("OmegaRuntime stopped");
158        Ok(())
159    }
160
161    /// Pause the runtime
162    pub async fn pause(&self) -> RuntimeResult<()> {
163        self.transition_state(RuntimeState::Paused)?;
164
165        info!("Pausing OmegaRuntime");
166
167        self.emit_event(OmegaEvent::SystemPaused {
168            timestamp: chrono::Utc::now(),
169        });
170
171        Ok(())
172    }
173
174    /// Resume the runtime from paused state
175    pub async fn resume(&self) -> RuntimeResult<()> {
176        self.transition_state(RuntimeState::Running)?;
177
178        info!("Resuming OmegaRuntime");
179
180        self.emit_event(OmegaEvent::SystemResumed {
181            timestamp: chrono::Utc::now(),
182        });
183
184        Ok(())
185    }
186
187    /// Get reference to AgentDB
188    pub fn agentdb(&self) -> &AgentDB {
189        &self.agentdb
190    }
191
192    /// Get reference to Memory system
193    pub fn memory(&self) -> &CosmicMemory {
194        &self.memory
195    }
196
197    /// Get reference to Loop engine
198    pub fn loops(&self) -> &LoopEngine {
199        &self.loops
200    }
201
202    /// Get reference to Meta-SONA
203    pub fn meta_sona(&self) -> &MetaSONA {
204        &self.meta_sona
205    }
206
207    /// Get the current runtime configuration
208    pub fn config(&self) -> &OmegaConfig {
209        &self.config
210    }
211
212    /// Get the current runtime state
213    pub fn state(&self) -> RuntimeState {
214        *self.state.read()
215    }
216
217    /// Check if runtime is running
218    pub fn is_running(&self) -> bool {
219        *self.state.read() == RuntimeState::Running
220    }
221
222    /// Check if runtime is paused
223    pub fn is_paused(&self) -> bool {
224        *self.state.read() == RuntimeState::Paused
225    }
226
227    /// Register an event handler
228    pub fn on_event(&self, handler: EventHandler) {
229        self.event_bus.write().on(handler);
230    }
231
232    /// Get event history
233    pub fn event_history(&self) -> Vec<OmegaEvent> {
234        self.event_bus.read().history().to_vec()
235    }
236
237    /// Clear event history
238    pub fn clear_event_history(&self) {
239        self.event_bus.write().clear_history();
240    }
241
242    /// Transition to a new state
243    fn transition_state(&self, new_state: RuntimeState) -> RuntimeResult<()> {
244        let mut state = self.state.write();
245
246        if !state.can_transition_to(new_state) {
247            return Err(RuntimeError::InvalidStateTransition {
248                current: state.description().to_string(),
249                attempted: new_state.description().to_string(),
250            });
251        }
252
253        debug!("State transition: {} -> {}", state.description(), new_state.description());
254        *state = new_state;
255        Ok(())
256    }
257
258    /// Emit an event to the event bus
259    fn emit_event(&self, event: OmegaEvent) {
260        if self.config.enable_event_logging {
261            self.event_bus.write().emit(event);
262        }
263    }
264
265    /// Get runtime health status
266    pub async fn health(&self) -> RuntimeHealth {
267        RuntimeHealth {
268            state: self.state(),
269            agentdb_healthy: true, // TODO: implement health checks
270            memory_healthy: true,
271            loops_healthy: true,
272            meta_sona_healthy: true,
273        }
274    }
275}
276
277/// Runtime health status
278#[derive(Debug, Clone)]
279pub struct RuntimeHealth {
280    pub state: RuntimeState,
281    pub agentdb_healthy: bool,
282    pub memory_healthy: bool,
283    pub loops_healthy: bool,
284    pub meta_sona_healthy: bool,
285}
286
287impl RuntimeHealth {
288    /// Check if all subsystems are healthy
289    pub fn is_healthy(&self) -> bool {
290        self.agentdb_healthy
291            && self.memory_healthy
292            && self.loops_healthy
293            && self.meta_sona_healthy
294            && self.state == RuntimeState::Running
295    }
296}
297
298#[cfg(test)]
299mod tests {
300    use super::*;
301
302    #[test]
303    fn test_state_transitions() {
304        use RuntimeState::*;
305
306        assert!(Uninitialized.can_transition_to(Initializing));
307        assert!(Initializing.can_transition_to(Running));
308        assert!(Running.can_transition_to(Paused));
309        assert!(Paused.can_transition_to(Running));
310        assert!(Running.can_transition_to(ShuttingDown));
311        assert!(ShuttingDown.can_transition_to(Stopped));
312
313        assert!(!Uninitialized.can_transition_to(Running));
314        assert!(!Running.can_transition_to(Stopped));
315        assert!(!Stopped.can_transition_to(Running));
316    }
317
318    #[tokio::test]
319    async fn test_runtime_creation() {
320        let config = OmegaConfig::minimal();
321        let runtime = OmegaRuntime::new(config).await;
322        assert!(runtime.is_ok());
323    }
324
325    #[tokio::test]
326    async fn test_runtime_lifecycle() {
327        let config = OmegaConfig::minimal();
328        let runtime = OmegaRuntime::new(config).await.unwrap();
329
330        assert_eq!(runtime.state(), RuntimeState::Uninitialized);
331
332        runtime.start().await.unwrap();
333        assert_eq!(runtime.state(), RuntimeState::Running);
334        assert!(runtime.is_running());
335
336        runtime.pause().await.unwrap();
337        assert_eq!(runtime.state(), RuntimeState::Paused);
338        assert!(runtime.is_paused());
339
340        runtime.resume().await.unwrap();
341        assert_eq!(runtime.state(), RuntimeState::Running);
342
343        runtime.stop().await.unwrap();
344        assert_eq!(runtime.state(), RuntimeState::Stopped);
345    }
346
347    #[tokio::test]
348    async fn test_invalid_state_transition() {
349        let config = OmegaConfig::minimal();
350        let runtime = OmegaRuntime::new(config).await.unwrap();
351
352        // Cannot pause when not running
353        let result = runtime.pause().await;
354        assert!(result.is_err());
355    }
356
357    #[tokio::test]
358    async fn test_event_emission() {
359        let mut config = OmegaConfig::minimal();
360        config.enable_event_logging = true;  // Enable event logging for this test
361        let runtime = OmegaRuntime::new(config).await.unwrap();
362
363        runtime.start().await.unwrap();
364
365        let history = runtime.event_history();
366        assert!(history.iter().any(|e| matches!(e, OmegaEvent::SystemStarted { .. })));
367    }
368}