use crate::config::OmegaConfig;
use crate::error::{RuntimeError, RuntimeResult};
use crate::events::{EventBus, EventHandler, OmegaEvent};
use omega_agentdb::{AgentDB, AgentDBConfig};
use omega_loops::LoopEngine;
use omega_memory::CosmicMemory;
use omega_meta_sona::MetaSONA;
use parking_lot::RwLock;
use std::sync::Arc;
use tracing::{debug, info};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RuntimeState {
Uninitialized,
Initializing,
Running,
Paused,
ShuttingDown,
Stopped,
}
impl RuntimeState {
pub fn can_transition_to(&self, target: RuntimeState) -> bool {
use RuntimeState::*;
matches!(
(self, target),
(Uninitialized, Initializing)
| (Initializing, Running)
| (Initializing, Stopped)
| (Running, Paused)
| (Running, ShuttingDown)
| (Paused, Running)
| (Paused, ShuttingDown)
| (ShuttingDown, Stopped)
)
}
pub fn description(&self) -> &'static str {
match self {
RuntimeState::Uninitialized => "uninitialized",
RuntimeState::Initializing => "initializing",
RuntimeState::Running => "running",
RuntimeState::Paused => "paused",
RuntimeState::ShuttingDown => "shutting down",
RuntimeState::Stopped => "stopped",
}
}
}
pub struct OmegaRuntime {
config: OmegaConfig,
agentdb: Arc<AgentDB>,
memory: Arc<CosmicMemory>,
loops: Arc<LoopEngine>,
meta_sona: Arc<MetaSONA>,
event_bus: Arc<RwLock<EventBus>>,
state: Arc<RwLock<RuntimeState>>,
}
impl OmegaRuntime {
pub async fn new(config: OmegaConfig) -> RuntimeResult<Self> {
info!("Creating OmegaRuntime with configuration");
config.validate().map_err(|e| {
RuntimeError::Config(format!("Invalid configuration: {}", e))
})?;
let agentdb = Arc::new(
AgentDB::new(AgentDBConfig::default())
.await
.map_err(|e| RuntimeError::AgentDB(e.to_string()))?
);
let memory = Arc::new(
CosmicMemory::new()
.await
.map_err(|e| RuntimeError::Memory(e.to_string()))?
);
let loops = Arc::new(LoopEngine::new());
let meta_sona = Arc::new(MetaSONA::new());
let event_bus = if config.enable_event_logging {
Arc::new(RwLock::new(EventBus::new()))
} else {
Arc::new(RwLock::new(EventBus::with_buffer_size(0)))
};
Ok(Self {
config,
agentdb,
memory,
loops,
meta_sona,
event_bus,
state: Arc::new(RwLock::new(RuntimeState::Uninitialized)),
})
}
pub async fn start(&self) -> RuntimeResult<()> {
self.transition_state(RuntimeState::Initializing)?;
info!("Starting OmegaRuntime");
debug!("AgentDB ready");
debug!("Memory system ready");
debug!("Loop engine ready");
debug!("Meta-SONA ready");
self.transition_state(RuntimeState::Running)?;
self.emit_event(OmegaEvent::SystemStarted {
timestamp: chrono::Utc::now(),
});
info!("OmegaRuntime started successfully");
Ok(())
}
pub async fn stop(&self) -> RuntimeResult<()> {
self.transition_state(RuntimeState::ShuttingDown)?;
info!("Stopping OmegaRuntime");
debug!("Meta-SONA stopping");
debug!("Loop engine stopping");
debug!("Memory system stopping");
debug!("AgentDB stopping");
self.transition_state(RuntimeState::Stopped)?;
self.emit_event(OmegaEvent::SystemShutdown {
timestamp: chrono::Utc::now(),
});
info!("OmegaRuntime stopped");
Ok(())
}
pub async fn pause(&self) -> RuntimeResult<()> {
self.transition_state(RuntimeState::Paused)?;
info!("Pausing OmegaRuntime");
self.emit_event(OmegaEvent::SystemPaused {
timestamp: chrono::Utc::now(),
});
Ok(())
}
pub async fn resume(&self) -> RuntimeResult<()> {
self.transition_state(RuntimeState::Running)?;
info!("Resuming OmegaRuntime");
self.emit_event(OmegaEvent::SystemResumed {
timestamp: chrono::Utc::now(),
});
Ok(())
}
pub fn agentdb(&self) -> &AgentDB {
&self.agentdb
}
pub fn memory(&self) -> &CosmicMemory {
&self.memory
}
pub fn loops(&self) -> &LoopEngine {
&self.loops
}
pub fn meta_sona(&self) -> &MetaSONA {
&self.meta_sona
}
pub fn config(&self) -> &OmegaConfig {
&self.config
}
pub fn state(&self) -> RuntimeState {
*self.state.read()
}
pub fn is_running(&self) -> bool {
*self.state.read() == RuntimeState::Running
}
pub fn is_paused(&self) -> bool {
*self.state.read() == RuntimeState::Paused
}
pub fn on_event(&self, handler: EventHandler) {
self.event_bus.write().on(handler);
}
pub fn event_history(&self) -> Vec<OmegaEvent> {
self.event_bus.read().history().to_vec()
}
pub fn clear_event_history(&self) {
self.event_bus.write().clear_history();
}
fn transition_state(&self, new_state: RuntimeState) -> RuntimeResult<()> {
let mut state = self.state.write();
if !state.can_transition_to(new_state) {
return Err(RuntimeError::InvalidStateTransition {
current: state.description().to_string(),
attempted: new_state.description().to_string(),
});
}
debug!("State transition: {} -> {}", state.description(), new_state.description());
*state = new_state;
Ok(())
}
fn emit_event(&self, event: OmegaEvent) {
if self.config.enable_event_logging {
self.event_bus.write().emit(event);
}
}
pub async fn health(&self) -> RuntimeHealth {
RuntimeHealth {
state: self.state(),
agentdb_healthy: true, memory_healthy: true,
loops_healthy: true,
meta_sona_healthy: true,
}
}
}
#[derive(Debug, Clone)]
pub struct RuntimeHealth {
pub state: RuntimeState,
pub agentdb_healthy: bool,
pub memory_healthy: bool,
pub loops_healthy: bool,
pub meta_sona_healthy: bool,
}
impl RuntimeHealth {
pub fn is_healthy(&self) -> bool {
self.agentdb_healthy
&& self.memory_healthy
&& self.loops_healthy
&& self.meta_sona_healthy
&& self.state == RuntimeState::Running
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_state_transitions() {
use RuntimeState::*;
assert!(Uninitialized.can_transition_to(Initializing));
assert!(Initializing.can_transition_to(Running));
assert!(Running.can_transition_to(Paused));
assert!(Paused.can_transition_to(Running));
assert!(Running.can_transition_to(ShuttingDown));
assert!(ShuttingDown.can_transition_to(Stopped));
assert!(!Uninitialized.can_transition_to(Running));
assert!(!Running.can_transition_to(Stopped));
assert!(!Stopped.can_transition_to(Running));
}
#[tokio::test]
async fn test_runtime_creation() {
let config = OmegaConfig::minimal();
let runtime = OmegaRuntime::new(config).await;
assert!(runtime.is_ok());
}
#[tokio::test]
async fn test_runtime_lifecycle() {
let config = OmegaConfig::minimal();
let runtime = OmegaRuntime::new(config).await.unwrap();
assert_eq!(runtime.state(), RuntimeState::Uninitialized);
runtime.start().await.unwrap();
assert_eq!(runtime.state(), RuntimeState::Running);
assert!(runtime.is_running());
runtime.pause().await.unwrap();
assert_eq!(runtime.state(), RuntimeState::Paused);
assert!(runtime.is_paused());
runtime.resume().await.unwrap();
assert_eq!(runtime.state(), RuntimeState::Running);
runtime.stop().await.unwrap();
assert_eq!(runtime.state(), RuntimeState::Stopped);
}
#[tokio::test]
async fn test_invalid_state_transition() {
let config = OmegaConfig::minimal();
let runtime = OmegaRuntime::new(config).await.unwrap();
let result = runtime.pause().await;
assert!(result.is_err());
}
#[tokio::test]
async fn test_event_emission() {
let mut config = OmegaConfig::minimal();
config.enable_event_logging = true; let runtime = OmegaRuntime::new(config).await.unwrap();
runtime.start().await.unwrap();
let history = runtime.event_history();
assert!(history.iter().any(|e| matches!(e, OmegaEvent::SystemStarted { .. })));
}
}