import sqlite3 import uuid import logging from datetime import datetime, timezone from pydantic import BaseModel from typing import Optional from backend.services.usb_monitor import get_db_path from backend.services.usb_vault import KeyDomain from backend.ws.agent_ws import ws_manager class OmegaEvent(BaseModel): domain: KeyDomain event_type: str description: str persona: Optional[str] = None timestamp: datetime = None def __init__(self, **data): super().__init__(**data) if self.timestamp is None: self.timestamp = datetime.now(timezone.utc) def event_type_warrants_speech(event_type: str) -> bool: """Determine if an event is critical enough to trigger Voice TTS.""" critical_events = {"game_won", "bug_found", "feature_implemented", "research_alert"} return event_type in critical_events def describe_event_for_speech(event: OmegaEvent) -> str: """Format the event description for the TTS engine.""" return f"Attention. {event.description}" async def sqlite_insert_omega_event(event: OmegaEvent): try: db_path = get_db_path() with sqlite3.connect(db_path) as conn: conn.execute('PRAGMA journal_mode=WAL') conn.execute( "INSERT INTO omega_events (id, domain, event_type, description, persona, timestamp) VALUES (?, ?, ?, ?, ?, ?)", (str(uuid.uuid4()), event.domain.value, event.event_type, event.description, event.persona, event.timestamp.isoformat()) ) # Enforce 30-day retention policy to prevent unbounded growth conn.execute("DELETE FROM omega_events WHERE timestamp < datetime('now', '-30 days')") conn.commit() except Exception as e: logging.error(f"Failed to insert OmegaEvent: {e}") async def publish_omega_event(event: OmegaEvent): """Publish an event to the Omega Event Bus.""" # 1. shared history table await sqlite_insert_omega_event(event) # 2. broadcast to EXE + APK regardless of source domain payload = event.model_dump() payload['timestamp'] = payload['timestamp'].isoformat() await ws_manager.broadcast({ "event": "omega:event", "payload": payload }) # 3. routes through existing ยง0.4 voice (stubbed for now if kokoro_engine not fully connected here, # but requested by user spec to synthesize_tts) if event_type_warrants_speech(event.event_type): try: from backend.voice.engines.kokoro_engine import synthesize_kokoro as synthesize_tts persona = event.persona or "jarvis" # Context stub if ResponseContext does not exist natively class StubContext: type = "automation_status" await synthesize_tts( describe_event_for_speech(event), persona=persona, context=StubContext() ) except ImportError as e: logging.warning(f"Could not import TTS engine for omega event speech: {e}") except Exception as e: logging.error(f"Error during TTS synthesis for omega event: {e}") # 4. Trigger vault auto-refresh try: from backend.security.vault_auto_refresh import maybe_trigger_vault_refresh import asyncio # Run it asynchronously so it doesn't block the event bus asyncio.create_task(maybe_trigger_vault_refresh(event.event_type)) except ImportError as e: logging.warning(f"Could not import vault_auto_refresh: {e}") except Exception as e: logging.error(f"Error triggering vault auto-refresh: {e}")