import asyncio from datetime import datetime, timezone import json import sqlite3 from typing import Any, Dict, List, Optional import uuid from schemas.enums import AgentState, DecisionStage, MissionStatus from schemas.models import ( AgentMessage, AgentReflectionDetail, AgentReputationModel, ApprovalRequestModel, BlackboardEntry, ConversationMessageModel, DebateSession, DiscussionEntry, EvidenceScore, KnowledgeEdge, KnowledgeNode, MissionContextModel, NotificationModel, TimelineEventModel, ) class DatabaseManager: """SQLite Database Engine for Spark Colony System State, Memory & Logs.""" def __init__(self, db_path: str = "spark_colony.db"): self.db_path = db_path self._init_db() def _get_connection(self) -> sqlite3.Connection: conn = sqlite3.connect(self.db_path, check_same_thread=False) conn.row_factory = sqlite3.Row conn.execute("PRAGMA journal_mode=WAL;") return conn def _init_db(self) -> None: with self._get_connection() as conn: cursor = conn.cursor() cursor.execute(""" CREATE TABLE IF NOT EXISTS missions ( id TEXT PRIMARY KEY, topic TEXT NOT NULL, status TEXT NOT NULL, stage TEXT NOT NULL, created_at TEXT NOT NULL, updated_at TEXT NOT NULL, summary TEXT, total_cost REAL DEFAULT 0.0 ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS agents ( id TEXT PRIMARY KEY, name TEXT NOT NULL, role TEXT NOT NULL, state TEXT NOT NULL, current_task TEXT, confidence REAL NOT NULL, last_active TEXT NOT NULL, enabled INTEGER DEFAULT 1 ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS memories ( id TEXT PRIMARY KEY, agent_id TEXT NOT NULL, mission_id TEXT NOT NULL, content TEXT NOT NULL, tags TEXT, created_at TEXT NOT NULL ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS journals ( id TEXT PRIMARY KEY, agent_id TEXT NOT NULL, mission_id TEXT NOT NULL, entry TEXT NOT NULL, timestamp TEXT NOT NULL ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS messages ( id TEXT PRIMARY KEY, sender TEXT NOT NULL, recipient TEXT NOT NULL, mission_id TEXT NOT NULL, status TEXT NOT NULL, summary TEXT NOT NULL, next_request TEXT NOT NULL, confidence REAL NOT NULL, timestamp TEXT NOT NULL ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS evidence ( id TEXT PRIMARY KEY, mission_id TEXT NOT NULL, agent_id TEXT NOT NULL, claim TEXT NOT NULL, source TEXT NOT NULL, credibility REAL NOT NULL, freshness REAL NOT NULL, authority REAL NOT NULL, agreement REAL NOT NULL, conflict REAL NOT NULL, confidence REAL NOT NULL, created_at TEXT NOT NULL ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS token_costs ( id TEXT PRIMARY KEY, mission_id TEXT NOT NULL, agent_id TEXT NOT NULL, prompt_tokens INT DEFAULT 0, completion_tokens INT DEFAULT 0, reasoning_tokens INT DEFAULT 0, vision_tokens INT DEFAULT 0, cost_usd REAL DEFAULT 0.0, timestamp TEXT NOT NULL ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS browser_cache ( id TEXT PRIMARY KEY, url TEXT UNIQUE NOT NULL, html TEXT NOT NULL, title TEXT, cached_at TEXT NOT NULL ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS plugins ( id TEXT PRIMARY KEY, name TEXT UNIQUE NOT NULL, version TEXT NOT NULL, description TEXT NOT NULL, entry_point TEXT NOT NULL, permissions TEXT, status TEXT NOT NULL, registered_at TEXT NOT NULL ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS reflections ( id TEXT PRIMARY KEY, mission_id TEXT NOT NULL, agent_id TEXT NOT NULL, lessons_learned TEXT NOT NULL, mistakes_identified TEXT, cost_usd REAL NOT NULL, confidence_achieved REAL NOT NULL, created_at TEXT NOT NULL, FOREIGN KEY (mission_id) REFERENCES missions (id) ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS website_profiles ( domain TEXT PRIMARY KEY, trust_score REAL NOT NULL, authority REAL NOT NULL, typical_layout TEXT NOT NULL, has_captcha_history INTEGER DEFAULT 0, interaction_success_rate REAL DEFAULT 100.0, last_visited TEXT NOT NULL ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS screen_memories ( id TEXT PRIMARY KEY, mission_id TEXT NOT NULL, url TEXT NOT NULL, screenshot_ref TEXT NOT NULL, layout_summary TEXT NOT NULL, timestamp TEXT NOT NULL ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS downloaded_files ( id TEXT PRIMARY KEY, mission_id TEXT NOT NULL, filename TEXT NOT NULL, mime_type TEXT NOT NULL, file_size INTEGER NOT NULL, summary TEXT, created_at TEXT NOT NULL ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS checkpoints ( id TEXT PRIMARY KEY, mission_id TEXT NOT NULL, stage TEXT NOT NULL, data_json TEXT NOT NULL, created_at TEXT NOT NULL, FOREIGN KEY (mission_id) REFERENCES missions (id) ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS knowledge_nodes ( id TEXT PRIMARY KEY, mission_id TEXT NOT NULL, label TEXT NOT NULL, entity_type TEXT NOT NULL, confidence REAL NOT NULL ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS knowledge_edges ( id TEXT PRIMARY KEY, mission_id TEXT NOT NULL, source_node_id TEXT NOT NULL, target_node_id TEXT NOT NULL, relationship TEXT NOT NULL, FOREIGN KEY (source_node_id) REFERENCES knowledge_nodes (id), FOREIGN KEY (target_node_id) REFERENCES knowledge_nodes (id) ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS blackboard ( id TEXT PRIMARY KEY, mission_id TEXT NOT NULL, agent_id TEXT NOT NULL, topic TEXT NOT NULL, data_json TEXT NOT NULL, timestamp TEXT NOT NULL ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS mission_contexts ( mission_id TEXT PRIMARY KEY, topic TEXT NOT NULL, priority INTEGER DEFAULT 5, current_phase TEXT NOT NULL, progress_percent REAL DEFAULT 0.0, owner_agent TEXT NOT NULL, resource_usage_json TEXT NOT NULL, estimated_cost REAL DEFAULT 0.0, health_status TEXT DEFAULT 'HEALTHY', retry_count INTEGER DEFAULT 0, checkpoint_state TEXT, created_at TEXT NOT NULL ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS mission_timeline ( id TEXT PRIMARY KEY, mission_id TEXT NOT NULL, agent_id TEXT NOT NULL, step_type TEXT NOT NULL, description TEXT NOT NULL, metadata_json TEXT NOT NULL, timestamp TEXT NOT NULL ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS discussions ( id TEXT PRIMARY KEY, mission_id TEXT NOT NULL, agent_id TEXT NOT NULL, agent_name TEXT NOT NULL, discussion_type TEXT NOT NULL, topic TEXT NOT NULL, content TEXT NOT NULL, evidence_ref TEXT, tags_json TEXT, confidence REAL NOT NULL, timestamp TEXT NOT NULL ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS debates ( debate_id TEXT PRIMARY KEY, mission_id TEXT NOT NULL, topic TEXT NOT NULL, status TEXT NOT NULL, participants_json TEXT NOT NULL, turns_json TEXT NOT NULL, consensus_summary TEXT, final_confidence REAL NOT NULL, created_at TEXT NOT NULL ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS agent_reputations ( agent_id TEXT PRIMARY KEY, name TEXT NOT NULL, role TEXT NOT NULL, experience_points INTEGER DEFAULT 100, trust_score REAL DEFAULT 100.0, accuracy_rate REAL DEFAULT 100.0, reliability_score REAL DEFAULT 100.0, speed_score REAL DEFAULT 100.0, cost_efficiency REAL DEFAULT 100.0, avg_confidence REAL DEFAULT 100.0, success_rate REAL DEFAULT 100.0, total_missions_participated INTEGER DEFAULT 0 ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS agent_reflections_v2 ( reflection_id TEXT PRIMARY KEY, mission_id TEXT NOT NULL, agent_id TEXT NOT NULL, agent_name TEXT NOT NULL, what_worked TEXT NOT NULL, what_failed TEXT NOT NULL, what_surprised TEXT NOT NULL, what_to_improve TEXT NOT NULL, timestamp TEXT NOT NULL ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS approval_requests ( id TEXT PRIMARY KEY, mission_id TEXT NOT NULL, agent_id TEXT NOT NULL, action_type TEXT NOT NULL, prompt_message TEXT NOT NULL, status TEXT NOT NULL, input_data_json TEXT, created_at TEXT NOT NULL ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS notifications ( id TEXT PRIMARY KEY, level TEXT NOT NULL, title TEXT NOT NULL, message TEXT NOT NULL, mission_id TEXT, acknowledged INTEGER DEFAULT 0, created_at TEXT NOT NULL ) """) cursor.execute(""" CREATE TABLE IF NOT EXISTS conversation_logs ( id TEXT PRIMARY KEY, user_id TEXT NOT NULL, sender TEXT NOT NULL, message TEXT NOT NULL, metadata_json TEXT, timestamp TEXT NOT NULL ) """) # Safe schema migration for blackboard try: cursor.execute("ALTER TABLE blackboard ADD COLUMN version INTEGER DEFAULT 1") cursor.execute("ALTER TABLE blackboard ADD COLUMN tags_json TEXT DEFAULT '[]'") cursor.execute("ALTER TABLE blackboard ADD COLUMN priority INTEGER DEFAULT 5") cursor.execute("ALTER TABLE blackboard ADD COLUMN confidence REAL DEFAULT 100.0") except sqlite3.OperationalError: pass # Columns already exist conn.commit() async def save_mission( self, mission_id: str, topic: str, status: MissionStatus, stage: DecisionStage, summary: Optional[str] = None, total_cost: float = 0.0, ) -> None: def _exec(): now = datetime.now(timezone.utc).isoformat() with self._get_connection() as conn: conn.execute( """ INSERT INTO missions (id, topic, status, stage, created_at, updated_at, summary, total_cost) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(id) DO UPDATE SET status=excluded.status, stage=excluded.stage, updated_at=excluded.updated_at, summary=COALESCE(excluded.summary, missions.summary), total_cost=missions.total_cost + excluded.total_cost """, (mission_id, topic, status.value, stage.value, now, now, summary, total_cost), ) conn.commit() await asyncio.to_thread(_exec) async def update_mission_status(self, mission_id: str, status: MissionStatus, stage: Optional[DecisionStage] = None) -> None: def _exec(): now = datetime.now(timezone.utc).isoformat() with self._get_connection() as conn: if stage: conn.execute("UPDATE missions SET status=?, stage=?, updated_at=? WHERE id=?", (status.value, stage.value, now, mission_id)) else: conn.execute("UPDATE missions SET status=?, updated_at=? WHERE id=?", (status.value, now, mission_id)) conn.commit() await asyncio.to_thread(_exec) async def delete_mission(self, mission_id: str) -> None: def _exec(): with self._get_connection() as conn: conn.execute("DELETE FROM missions WHERE id=?", (mission_id,)) conn.execute("DELETE FROM memories WHERE mission_id=?", (mission_id,)) conn.execute("DELETE FROM journals WHERE mission_id=?", (mission_id,)) conn.execute("DELETE FROM messages WHERE mission_id=?", (mission_id,)) conn.execute("DELETE FROM evidence WHERE mission_id=?", (mission_id,)) conn.execute("DELETE FROM reflections WHERE mission_id=?", (mission_id,)) conn.execute("DELETE FROM screen_memories WHERE mission_id=?", (mission_id,)) conn.execute("DELETE FROM downloaded_files WHERE mission_id=?", (mission_id,)) conn.execute("DELETE FROM checkpoints WHERE mission_id=?", (mission_id,)) conn.execute("DELETE FROM knowledge_nodes WHERE mission_id=?", (mission_id,)) conn.execute("DELETE FROM knowledge_edges WHERE mission_id=?", (mission_id,)) conn.execute("DELETE FROM blackboard WHERE mission_id=?", (mission_id,)) conn.execute("DELETE FROM mission_contexts WHERE mission_id=?", (mission_id,)) conn.execute("DELETE FROM mission_timeline WHERE mission_id=?", (mission_id,)) conn.execute("DELETE FROM discussions WHERE mission_id=?", (mission_id,)) conn.execute("DELETE FROM debates WHERE mission_id=?", (mission_id,)) conn.execute("DELETE FROM agent_reflections_v2 WHERE mission_id=?", (mission_id,)) conn.execute("DELETE FROM approval_requests WHERE mission_id=?", (mission_id,)) conn.execute("DELETE FROM notifications WHERE mission_id=?", (mission_id,)) conn.commit() await asyncio.to_thread(_exec) async def get_mission(self, mission_id: str) -> Optional[Dict[str, Any]]: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM missions WHERE id = ?", (mission_id,)) row = cursor.fetchone() return dict(row) if row else None return await asyncio.to_thread(_exec) async def get_all_missions(self) -> List[Dict[str, Any]]: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM missions ORDER BY created_at DESC") return [dict(row) for row in cursor.fetchall()] return await asyncio.to_thread(_exec) async def count_missions(self) -> int: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT COUNT(*) FROM missions") return cursor.fetchone()[0] return await asyncio.to_thread(_exec) async def upsert_agent( self, agent_id: str, name: str, role: str, state: AgentState, current_task: Optional[str], confidence: float, enabled: bool = True ) -> None: def _exec(): now = datetime.now(timezone.utc).isoformat() with self._get_connection() as conn: conn.execute( """ INSERT INTO agents (id, name, role, state, current_task, confidence, last_active, enabled) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(id) DO UPDATE SET name=excluded.name, role=excluded.role, state=excluded.state, current_task=excluded.current_task, confidence=excluded.confidence, last_active=excluded.last_active, enabled=excluded.enabled """, (agent_id, name, role, state.value, current_task, confidence, now, 1 if enabled else 0), ) conn.commit() await asyncio.to_thread(_exec) async def get_all_agents(self) -> List[Dict[str, Any]]: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM agents") return [dict(row) for row in cursor.fetchall()] return await asyncio.to_thread(_exec) async def get_agent(self, agent_id: str) -> Optional[Dict[str, Any]]: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM agents WHERE id=?", (agent_id,)) row = cursor.fetchone() return dict(row) if row else None return await asyncio.to_thread(_exec) async def save_memory(self, agent_id: str, mission_id: str, content: str, tags: List[str]) -> str: memory_id = str(uuid.uuid4()) tags_str = json.dumps(tags) now = datetime.now(timezone.utc).isoformat() def _exec(): with self._get_connection() as conn: conn.execute( "INSERT INTO memories (id, agent_id, mission_id, content, tags, created_at) VALUES (?, ?, ?, ?, ?, ?)", (memory_id, agent_id, mission_id, content, tags_str, now), ) conn.commit() await asyncio.to_thread(_exec) return memory_id async def search_memories(self, query: str, tag: Optional[str] = None) -> List[Dict[str, Any]]: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() if tag: cursor.execute("SELECT * FROM memories WHERE content LIKE ? AND tags LIKE ?", (f"%{query}%", f"%{tag}%")) else: cursor.execute("SELECT * FROM memories WHERE content LIKE ?", (f"%{query}%",)) rows = cursor.fetchall() results = [] for r in rows: item = dict(r) item["tags"] = json.loads(item["tags"]) if item["tags"] else [] results.append(item) return results return await asyncio.to_thread(_exec) async def delete_memory(self, memory_id: str) -> None: def _exec(): with self._get_connection() as conn: conn.execute("DELETE FROM memories WHERE id=?", (memory_id,)) conn.commit() await asyncio.to_thread(_exec) async def get_memories_for_mission(self, mission_id: str) -> List[Dict[str, Any]]: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM memories WHERE mission_id = ? ORDER BY created_at ASC", (mission_id,)) rows = cursor.fetchall() results = [] for row in rows: item = dict(row) item["tags"] = json.loads(item["tags"]) if item["tags"] else [] results.append(item) return results return await asyncio.to_thread(_exec) async def count_memories(self) -> int: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT COUNT(*) FROM memories") return cursor.fetchone()[0] return await asyncio.to_thread(_exec) async def save_journal(self, agent_id: str, mission_id: str, entry: str) -> str: journal_id = str(uuid.uuid4()) now = datetime.now(timezone.utc).isoformat() def _exec(): with self._get_connection() as conn: conn.execute( "INSERT INTO journals (id, agent_id, mission_id, entry, timestamp) VALUES (?, ?, ?, ?, ?)", (journal_id, agent_id, mission_id, entry, now), ) conn.commit() await asyncio.to_thread(_exec) return journal_id async def get_journals_for_mission(self, mission_id: str) -> List[Dict[str, Any]]: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM journals WHERE mission_id = ? ORDER BY timestamp ASC", (mission_id,)) return [dict(row) for row in cursor.fetchall()] return await asyncio.to_thread(_exec) async def save_message(self, message: AgentMessage) -> None: def _exec(): with self._get_connection() as conn: conn.execute( """ INSERT INTO messages (id, sender, recipient, mission_id, status, summary, next_request, confidence, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) """, ( message.id, message.sender, message.recipient, message.mission_id, message.status, message.summary, message.next_request, message.confidence, message.timestamp, ), ) conn.commit() await asyncio.to_thread(_exec) async def get_messages_for_mission(self, mission_id: str) -> List[Dict[str, Any]]: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM messages WHERE mission_id = ? ORDER BY timestamp ASC", (mission_id,)) return [dict(row) for row in cursor.fetchall()] return await asyncio.to_thread(_exec) async def count_messages(self) -> int: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT COUNT(*) FROM messages") return cursor.fetchone()[0] return await asyncio.to_thread(_exec) async def save_evidence( self, mission_id: str, agent_id: str, claim: str, source: str, score: EvidenceScore, ) -> str: evidence_id = str(uuid.uuid4()) now = datetime.now(timezone.utc).isoformat() def _exec(): with self._get_connection() as conn: conn.execute( """ INSERT INTO evidence (id, mission_id, agent_id, claim, source, credibility, freshness, authority, agreement, conflict, confidence, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """, ( evidence_id, mission_id, agent_id, claim, source, score.credibility, score.freshness, score.authority, score.agreement, score.conflict, score.overall_confidence, now, ), ) conn.commit() await asyncio.to_thread(_exec) return evidence_id async def get_evidence_for_mission(self, mission_id: str) -> List[Dict[str, Any]]: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM evidence WHERE mission_id = ? ORDER BY created_at ASC", (mission_id,)) return [dict(row) for row in cursor.fetchall()] return await asyncio.to_thread(_exec) async def record_tokens( self, mission_id: str, agent_id: str, prompt_tokens: int, completion_tokens: int, reasoning_tokens: int, vision_tokens: int, cost_usd: float, ) -> None: token_id = str(uuid.uuid4()) now = datetime.now(timezone.utc).isoformat() def _exec(): with self._get_connection() as conn: conn.execute( """ INSERT INTO token_costs (id, mission_id, agent_id, prompt_tokens, completion_tokens, reasoning_tokens, vision_tokens, cost_usd, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) """, (token_id, mission_id, agent_id, prompt_tokens, completion_tokens, reasoning_tokens, vision_tokens, cost_usd, now), ) conn.commit() await asyncio.to_thread(_exec) async def get_total_system_cost(self) -> float: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT SUM(cost_usd) FROM token_costs") res = cursor.fetchone()[0] return res if res else 0.0 return await asyncio.to_thread(_exec) async def save_browser_cache(self, url: str, html: str, title: Optional[str]) -> str: cache_id = str(uuid.uuid4()) now = datetime.now(timezone.utc).isoformat() def _exec(): with self._get_connection() as conn: conn.execute( """ INSERT INTO browser_cache (id, url, html, title, cached_at) VALUES (?, ?, ?, ?, ?) ON CONFLICT(url) DO UPDATE SET html=excluded.html, title=excluded.title, cached_at=excluded.cached_at """, (cache_id, url, html, title, now), ) conn.commit() await asyncio.to_thread(_exec) return cache_id async def clear_browser_cache(self) -> None: def _exec(): with self._get_connection() as conn: conn.execute("DELETE FROM browser_cache") conn.commit() await asyncio.to_thread(_exec) async def save_plugin(self, name: str, version: str, description: str, entry_point: str, permissions: List[str]) -> str: plugin_id = str(uuid.uuid4()) now = datetime.now(timezone.utc).isoformat() perms_str = json.dumps(permissions) def _exec(): with self._get_connection() as conn: conn.execute( """ INSERT INTO plugins (id, name, version, description, entry_point, permissions, status, registered_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(name) DO UPDATE SET version=excluded.version, status=excluded.status """, (plugin_id, name, version, description, entry_point, perms_str, "ACTIVE", now), ) conn.commit() await asyncio.to_thread(_exec) return plugin_id async def get_all_plugins(self) -> List[Dict[str, Any]]: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM plugins") rows = cursor.fetchall() results = [] for r in rows: item = dict(r) item["permissions"] = json.loads(item["permissions"]) if item["permissions"] else [] results.append(item) return results return await asyncio.to_thread(_exec) async def save_reflection( self, mission_id: str, agent_id: str, lessons_learned: str, mistakes_identified: Optional[str], cost_usd: float, confidence_achieved: float, ) -> str: ref_id = str(uuid.uuid4()) now = datetime.now(timezone.utc).isoformat() def _exec(): with self._get_connection() as conn: conn.execute( """ INSERT INTO reflections (id, mission_id, agent_id, lessons_learned, mistakes_identified, cost_usd, confidence_achieved, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?) """, (ref_id, mission_id, agent_id, lessons_learned, mistakes_identified, cost_usd, confidence_achieved, now), ) conn.commit() await asyncio.to_thread(_exec) return ref_id async def get_reflections_for_mission(self, mission_id: str) -> List[Dict[str, Any]]: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM reflections WHERE mission_id = ? ORDER BY created_at ASC", (mission_id,)) return [dict(row) for row in cursor.fetchall()] return await asyncio.to_thread(_exec) async def get_all_reflections(self) -> List[Dict[str, Any]]: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM reflections ORDER BY created_at DESC") return [dict(row) for row in cursor.fetchall()] return await asyncio.to_thread(_exec) async def upsert_website_profile( self, domain: str, trust_score: float, authority: float, typical_layout: str, has_captcha: bool = False, success_rate: float = 100.0, ) -> None: def _exec(): now = datetime.now(timezone.utc).isoformat() with self._get_connection() as conn: conn.execute( """ INSERT INTO website_profiles (domain, trust_score, authority, typical_layout, has_captcha_history, interaction_success_rate, last_visited) VALUES (?, ?, ?, ?, ?, ?, ?) ON CONFLICT(domain) DO UPDATE SET trust_score=excluded.trust_score, authority=excluded.authority, typical_layout=excluded.typical_layout, has_captcha_history=excluded.has_captcha_history, interaction_success_rate=excluded.interaction_success_rate, last_visited=excluded.last_visited """, (domain, trust_score, authority, typical_layout, 1 if has_captcha else 0, success_rate, now), ) conn.commit() await asyncio.to_thread(_exec) async def get_website_profiles(self) -> List[Dict[str, Any]]: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM website_profiles ORDER BY trust_score DESC") return [dict(row) for row in cursor.fetchall()] return await asyncio.to_thread(_exec) async def save_screen_memory(self, mission_id: str, url: str, screenshot_ref: str, layout_summary: str) -> str: mem_id = str(uuid.uuid4()) now = datetime.now(timezone.utc).isoformat() def _exec(): with self._get_connection() as conn: conn.execute( "INSERT INTO screen_memories (id, mission_id, url, screenshot_ref, layout_summary, timestamp) VALUES (?, ?, ?, ?, ?, ?)", (mem_id, mission_id, url, screenshot_ref, layout_summary, now), ) conn.commit() await asyncio.to_thread(_exec) return mem_id async def save_downloaded_file(self, mission_id: str, filename: str, mime_type: str, file_size: int, summary: str) -> str: file_id = str(uuid.uuid4()) now = datetime.now(timezone.utc).isoformat() def _exec(): with self._get_connection() as conn: conn.execute( "INSERT INTO downloaded_files (id, mission_id, filename, mime_type, file_size, summary, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)", (file_id, mission_id, filename, mime_type, file_size, summary, now), ) conn.commit() await asyncio.to_thread(_exec) return file_id async def get_downloaded_files(self) -> List[Dict[str, Any]]: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM downloaded_files ORDER BY created_at DESC") return [dict(row) for row in cursor.fetchall()] return await asyncio.to_thread(_exec) async def save_checkpoint(self, mission_id: str, stage: DecisionStage, data: Dict[str, Any]) -> str: cp_id = str(uuid.uuid4()) now = datetime.now(timezone.utc).isoformat() data_str = json.dumps(data) def _exec(): with self._get_connection() as conn: conn.execute( "INSERT INTO checkpoints (id, mission_id, stage, data_json, created_at) VALUES (?, ?, ?, ?, ?)", (cp_id, mission_id, stage.value, data_str, now), ) conn.commit() await asyncio.to_thread(_exec) return cp_id async def get_latest_checkpoint(self, mission_id: str) -> Optional[Dict[str, Any]]: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM checkpoints WHERE mission_id = ? ORDER BY created_at DESC LIMIT 1", (mission_id,)) row = cursor.fetchone() if not row: return None item = dict(row) item["data"] = json.loads(item["data_json"]) return item return await asyncio.to_thread(_exec) async def get_checkpoints_for_mission(self, mission_id: str) -> List[Dict[str, Any]]: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM checkpoints WHERE mission_id = ? ORDER BY created_at ASC", (mission_id,)) rows = cursor.fetchall() results = [] for r in rows: item = dict(r) item["data"] = json.loads(item["data_json"]) results.append(item) return results return await asyncio.to_thread(_exec) async def save_knowledge_node(self, node: KnowledgeNode) -> None: def _exec(): with self._get_connection() as conn: conn.execute( "INSERT INTO knowledge_nodes (id, mission_id, label, entity_type, confidence) VALUES (?, ?, ?, ?, ?)", (node.id, node.mission_id, node.label, node.entity_type, node.confidence), ) conn.commit() await asyncio.to_thread(_exec) async def save_knowledge_edge(self, edge: KnowledgeEdge) -> None: def _exec(): with self._get_connection() as conn: conn.execute( "INSERT INTO knowledge_edges (id, mission_id, source_node_id, target_node_id, relationship) VALUES (?, ?, ?, ?, ?)", (edge.id, edge.mission_id, edge.source_node_id, edge.target_node_id, edge.relationship), ) conn.commit() await asyncio.to_thread(_exec) async def get_knowledge_graph(self, mission_id: str) -> Dict[str, Any]: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM knowledge_nodes WHERE mission_id=?", (mission_id,)) nodes = [dict(r) for r in cursor.fetchall()] cursor.execute("SELECT * FROM knowledge_edges WHERE mission_id=?", (mission_id,)) edges = [dict(r) for r in cursor.fetchall()] return {"mission_id": mission_id, "nodes": nodes, "edges": edges} return await asyncio.to_thread(_exec) async def save_blackboard_entry(self, entry: BlackboardEntry) -> None: def _exec(): with self._get_connection() as conn: conn.execute( "INSERT INTO blackboard (id, mission_id, agent_id, topic, data_json, timestamp) VALUES (?, ?, ?, ?, ?, ?)", (entry.id, entry.mission_id, entry.agent_id, entry.topic, json.dumps(entry.data), entry.timestamp), ) conn.commit() await asyncio.to_thread(_exec) async def get_blackboard_entries(self, mission_id: str, topic: Optional[str] = None) -> List[Dict[str, Any]]: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() if topic: cursor.execute("SELECT * FROM blackboard WHERE mission_id = ? AND topic = ? ORDER BY timestamp ASC", (mission_id, topic)) else: cursor.execute("SELECT * FROM blackboard WHERE mission_id = ? ORDER BY timestamp ASC", (mission_id,)) rows = cursor.fetchall() results = [] for r in rows: item = dict(r) item["data"] = json.loads(item["data_json"]) results.append(item) return results return await asyncio.to_thread(_exec) async def save_mission_context(self, ctx: MissionContextModel) -> None: def _exec(): with self._get_connection() as conn: conn.execute( """ INSERT INTO mission_contexts (mission_id, topic, priority, current_phase, progress_percent, owner_agent, resource_usage_json, estimated_cost, health_status, retry_count, checkpoint_state, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(mission_id) DO UPDATE SET current_phase=excluded.current_phase, progress_percent=excluded.progress_percent, resource_usage_json=excluded.resource_usage_json, estimated_cost=excluded.estimated_cost, health_status=excluded.health_status, retry_count=excluded.retry_count, checkpoint_state=excluded.checkpoint_state """, ( ctx.mission_id, ctx.topic, ctx.priority, ctx.current_phase.value, ctx.progress_percent, ctx.owner_agent, json.dumps(ctx.resource_usage), ctx.estimated_cost, ctx.health_status, ctx.retry_count, ctx.checkpoint_state, ctx.created_at, ), ) conn.commit() await asyncio.to_thread(_exec) async def get_all_mission_contexts(self) -> List[Dict[str, Any]]: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM mission_contexts ORDER BY created_at DESC") rows = cursor.fetchall() results = [] for r in rows: item = dict(r) item["resource_usage"] = json.loads(item["resource_usage_json"]) results.append(item) return results return await asyncio.to_thread(_exec) async def save_timeline_event(self, event: TimelineEventModel) -> None: def _exec(): with self._get_connection() as conn: conn.execute( "INSERT INTO mission_timeline (id, mission_id, agent_id, step_type, description, metadata_json, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?)", (event.id, event.mission_id, event.agent_id, event.step_type.value, event.description, json.dumps(event.metadata), event.timestamp), ) conn.commit() await asyncio.to_thread(_exec) async def get_mission_timeline(self, mission_id: str) -> List[Dict[str, Any]]: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM mission_timeline WHERE mission_id = ? ORDER BY timestamp ASC", (mission_id,)) rows = cursor.fetchall() results = [] for r in rows: item = dict(r) item["metadata"] = json.loads(item["metadata_json"]) results.append(item) return results return await asyncio.to_thread(_exec) async def save_discussion_entry(self, entry: DiscussionEntry) -> None: def _exec(): with self._get_connection() as conn: conn.execute( """ INSERT INTO discussions (id, mission_id, agent_id, agent_name, discussion_type, topic, content, evidence_ref, tags_json, confidence, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """, ( entry.id, entry.mission_id, entry.agent_id, entry.agent_name, entry.discussion_type.value, entry.topic, entry.content, entry.evidence_ref, json.dumps(entry.tags), entry.confidence, entry.timestamp, ), ) conn.commit() await asyncio.to_thread(_exec) async def get_discussions_for_mission(self, mission_id: str, tag: Optional[str] = None) -> List[Dict[str, Any]]: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() if tag: cursor.execute("SELECT * FROM discussions WHERE mission_id = ? AND tags_json LIKE ? ORDER BY timestamp ASC", (mission_id, f"%{tag}%")) else: cursor.execute("SELECT * FROM discussions WHERE mission_id = ? ORDER BY timestamp ASC", (mission_id,)) rows = cursor.fetchall() results = [] for r in rows: item = dict(r) item["tags"] = json.loads(item["tags_json"]) if item.get("tags_json") else [] results.append(item) return results return await asyncio.to_thread(_exec) async def save_debate_session(self, debate: DebateSession) -> None: def _exec(): with self._get_connection() as conn: turns_json = json.dumps([t.model_dump() for t in debate.turns]) conn.execute( """ INSERT INTO debates (debate_id, mission_id, topic, status, participants_json, turns_json, consensus_summary, final_confidence, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(debate_id) DO UPDATE SET status=excluded.status, turns_json=excluded.turns_json, consensus_summary=excluded.consensus_summary, final_confidence=excluded.final_confidence """, ( debate.debate_id, debate.mission_id, debate.topic, debate.status, json.dumps(debate.participants), turns_json, debate.consensus_summary, debate.final_confidence, debate.created_at, ), ) conn.commit() await asyncio.to_thread(_exec) async def get_debate_session(self, debate_id: str) -> Optional[Dict[str, Any]]: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM debates WHERE debate_id = ?", (debate_id,)) row = cursor.fetchone() if not row: return None item = dict(row) item["participants"] = json.loads(item["participants_json"]) item["turns"] = json.loads(item["turns_json"]) return item return await asyncio.to_thread(_exec) async def get_debates_for_mission(self, mission_id: str) -> List[Dict[str, Any]]: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM debates WHERE mission_id = ? ORDER BY created_at ASC", (mission_id,)) rows = cursor.fetchall() results = [] for r in rows: item = dict(r) item["participants"] = json.loads(item["participants_json"]) item["turns"] = json.loads(item["turns_json"]) results.append(item) return results return await asyncio.to_thread(_exec) async def save_agent_reputation(self, rep: AgentReputationModel) -> None: def _exec(): with self._get_connection() as conn: conn.execute( """ INSERT INTO agent_reputations (agent_id, name, role, experience_points, trust_score, accuracy_rate, reliability_score, speed_score, cost_efficiency, avg_confidence, success_rate, total_missions_participated) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(agent_id) DO UPDATE SET experience_points=excluded.experience_points, trust_score=excluded.trust_score, accuracy_rate=excluded.accuracy_rate, reliability_score=excluded.reliability_score, speed_score=excluded.speed_score, cost_efficiency=excluded.cost_efficiency, avg_confidence=excluded.avg_confidence, success_rate=excluded.success_rate, total_missions_participated=excluded.total_missions_participated """, ( rep.agent_id, rep.name, rep.role, rep.experience_points, rep.trust_score, rep.accuracy_rate, rep.reliability_score, rep.speed_score, rep.cost_efficiency, rep.avg_confidence, rep.success_rate, rep.total_missions_participated, ), ) conn.commit() await asyncio.to_thread(_exec) async def get_agent_reputation(self, agent_id: str) -> Optional[Dict[str, Any]]: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM agent_reputations WHERE agent_id = ?", (agent_id,)) row = cursor.fetchone() return dict(row) if row else None return await asyncio.to_thread(_exec) async def get_all_agent_reputations(self) -> List[Dict[str, Any]]: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM agent_reputations ORDER BY trust_score DESC") return [dict(r) for r in cursor.fetchall()] return await asyncio.to_thread(_exec) async def save_agent_reflection_v2(self, refl: AgentReflectionDetail) -> None: def _exec(): with self._get_connection() as conn: conn.execute( """ INSERT INTO agent_reflections_v2 (reflection_id, mission_id, agent_id, agent_name, what_worked, what_failed, what_surprised, what_to_improve, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) """, ( refl.reflection_id, refl.mission_id, refl.agent_id, refl.agent_name, refl.what_worked, refl.what_failed, refl.what_surprised, refl.what_to_improve, refl.timestamp, ), ) conn.commit() await asyncio.to_thread(_exec) async def get_agent_reflections_for_mission(self, mission_id: str) -> List[Dict[str, Any]]: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM agent_reflections_v2 WHERE mission_id = ? ORDER BY timestamp ASC", (mission_id,)) return [dict(r) for r in cursor.fetchall()] return await asyncio.to_thread(_exec) async def save_approval_request(self, req: ApprovalRequestModel) -> None: def _exec(): with self._get_connection() as conn: conn.execute( """ INSERT INTO approval_requests (id, mission_id, agent_id, action_type, prompt_message, status, input_data_json, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT(id) DO UPDATE SET status=excluded.status, input_data_json=excluded.input_data_json """, (req.id, req.mission_id, req.agent_id, req.action_type.value, req.prompt_message, req.status.value, json.dumps(req.input_data), req.created_at), ) conn.commit() await asyncio.to_thread(_exec) async def get_approval_request(self, approval_id: str) -> Optional[Dict[str, Any]]: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM approval_requests WHERE id = ?", (approval_id,)) row = cursor.fetchone() if not row: return None item = dict(row) item["input_data"] = json.loads(item["input_data_json"]) if item.get("input_data_json") else {} return item return await asyncio.to_thread(_exec) async def get_pending_approvals(self) -> List[Dict[str, Any]]: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM approval_requests WHERE status = 'PENDING' ORDER BY created_at ASC") rows = cursor.fetchall() results = [] for r in rows: item = dict(r) item["input_data"] = json.loads(item["input_data_json"]) if item.get("input_data_json") else {} results.append(item) return results return await asyncio.to_thread(_exec) async def save_notification(self, notif: NotificationModel) -> None: def _exec(): with self._get_connection() as conn: conn.execute( "INSERT INTO notifications (id, level, title, message, mission_id, acknowledged, created_at) VALUES (?, ?, ?, ?, ?, ?, ?)", (notif.id, notif.level.value, notif.title, notif.message, notif.mission_id, 1 if notif.acknowledged else 0, notif.created_at), ) conn.commit() await asyncio.to_thread(_exec) async def get_unacknowledged_notifications(self) -> List[Dict[str, Any]]: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM notifications WHERE acknowledged = 0 ORDER BY created_at DESC") return [dict(r) for r in cursor.fetchall()] return await asyncio.to_thread(_exec) async def acknowledge_notification(self, notif_id: str) -> None: def _exec(): with self._get_connection() as conn: conn.execute("UPDATE notifications SET acknowledged = 1 WHERE id = ?", (notif_id,)) conn.commit() await asyncio.to_thread(_exec) async def save_conversation_log(self, msg: ConversationMessageModel) -> None: def _exec(): with self._get_connection() as conn: conn.execute( "INSERT INTO conversation_logs (id, user_id, sender, message, metadata_json, timestamp) VALUES (?, ?, ?, ?, ?, ?)", (msg.id, msg.user_id, msg.sender, msg.message, json.dumps(msg.metadata), msg.timestamp), ) conn.commit() await asyncio.to_thread(_exec) async def get_conversation_history(self, user_id: str = "human-operator", limit: int = 50) -> List[Dict[str, Any]]: def _exec(): with self._get_connection() as conn: cursor = conn.cursor() cursor.execute("SELECT * FROM conversation_logs WHERE user_id = ? ORDER BY timestamp ASC LIMIT ?", (user_id, limit)) rows = cursor.fetchall() results = [] for r in rows: item = dict(r) item["metadata"] = json.loads(item["metadata_json"]) if item.get("metadata_json") else {} results.append(item) return results return await asyncio.to_thread(_exec)