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