Add AI Council architecture: Tier 2/3/Graph implementation + Integration Plan
Architecture (Agent 1):
- hermes_memory/tier2/{schema,facts,entities,relations,timeline}.py
- hermes_memory/tier3/{backend,chroma_backend,embedder}.py
- hermes_memory/graph/nx_store.py
- hermes_memory/api/memory_api.py (unified API)
- hermes_memory/cron/{consolidate,embed_queue,graph_refresh,prune}.py
- hermes_memory/config.py + pyproject.toml
Integration Plan (Agent 3):
- INTEGRATION_PLAN.md: Memory Provider Plugin strategy
- Hermes Core needs minimal changes
- sync_turn() + prefetch() hooks
- Skills integration via nextlevel_search/remember
Auto-Extraction (Agent 2):
- ARCHITECTURE.md: Full extraction pipeline docs
- Chunking, Pre-Filter, LLM Prompts, Classification
- Entity-Linking, Temporal Reasoning, Deduplication
All files: Python syntax checked, ECC standards applied.
This commit is contained in:
@@ -0,0 +1,196 @@
|
||||
"""SQLite Schema & Migrationen für Tier 2.
|
||||
|
||||
Enthält alle CREATE TABLE / INDEX / TRIGGER Statements
|
||||
mit Schema-Versionierung.
|
||||
"""
|
||||
|
||||
import sqlite3
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
SCHEMA_VERSION = 1
|
||||
|
||||
SCHEMA_SQL = """
|
||||
-- Schema-Version
|
||||
CREATE TABLE IF NOT EXISTS memory_schema_version (
|
||||
version INTEGER PRIMARY KEY,
|
||||
applied_at REAL NOT NULL
|
||||
);
|
||||
|
||||
-- Fakten
|
||||
CREATE TABLE IF NOT EXISTS facts (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
uuid TEXT NOT NULL UNIQUE,
|
||||
content TEXT NOT NULL,
|
||||
content_hash TEXT NOT NULL,
|
||||
category TEXT,
|
||||
confidence REAL DEFAULT 1.0,
|
||||
source_type TEXT NOT NULL,
|
||||
source_id TEXT,
|
||||
created_at REAL NOT NULL,
|
||||
updated_at REAL NOT NULL,
|
||||
expires_at REAL,
|
||||
access_count INTEGER DEFAULT 0,
|
||||
last_accessed REAL,
|
||||
is_archived INTEGER DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_facts_category ON facts(category);
|
||||
CREATE INDEX IF NOT EXISTS idx_facts_source ON facts(source_type, source_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_facts_created ON facts(created_at DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_facts_hash ON facts(content_hash);
|
||||
CREATE INDEX IF NOT EXISTS idx_facts_confidence ON facts(confidence DESC);
|
||||
|
||||
-- Entitäten
|
||||
CREATE TABLE IF NOT EXISTS entities (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
uuid TEXT NOT NULL UNIQUE,
|
||||
name TEXT NOT NULL,
|
||||
aliases TEXT,
|
||||
entity_type TEXT NOT NULL,
|
||||
description TEXT,
|
||||
first_seen REAL NOT NULL,
|
||||
last_seen REAL NOT NULL,
|
||||
occurrence_count INTEGER DEFAULT 1,
|
||||
metadata TEXT
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_entities_name ON entities(name);
|
||||
CREATE INDEX IF NOT EXISTS idx_entities_type ON entities(entity_type);
|
||||
|
||||
-- Relationen
|
||||
CREATE TABLE IF NOT EXISTS relations (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
uuid TEXT NOT NULL UNIQUE,
|
||||
from_entity_id TEXT NOT NULL,
|
||||
to_entity_id TEXT NOT NULL,
|
||||
relation_type TEXT NOT NULL,
|
||||
strength REAL DEFAULT 1.0,
|
||||
evidence_fact_id TEXT,
|
||||
created_at REAL NOT NULL,
|
||||
updated_at REAL NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_relations_from ON relations(from_entity_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_relations_to ON relations(to_entity_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_relations_type ON relations(relation_type);
|
||||
|
||||
-- Timeline
|
||||
CREATE TABLE IF NOT EXISTS timeline (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
uuid TEXT NOT NULL UNIQUE,
|
||||
event_type TEXT NOT NULL,
|
||||
title TEXT NOT NULL,
|
||||
description TEXT,
|
||||
related_entities TEXT,
|
||||
related_facts TEXT,
|
||||
session_id TEXT,
|
||||
timestamp REAL NOT NULL,
|
||||
importance REAL DEFAULT 0.5
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_timeline_time ON timeline(timestamp DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_timeline_type ON timeline(event_type);
|
||||
|
||||
-- Audit-Log
|
||||
CREATE TABLE IF NOT EXISTS memory_audit_log (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
timestamp REAL NOT NULL,
|
||||
action TEXT NOT NULL,
|
||||
tier TEXT NOT NULL,
|
||||
actor TEXT NOT NULL,
|
||||
target_uuid TEXT,
|
||||
diff TEXT,
|
||||
success INTEGER DEFAULT 1
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_audit_timestamp ON memory_audit_log(timestamp DESC);
|
||||
CREATE INDEX IF NOT EXISTS idx_audit_actor ON memory_audit_log(actor);
|
||||
|
||||
-- Embedding-Queue
|
||||
CREATE TABLE IF NOT EXISTS embedding_queue (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
fact_id TEXT,
|
||||
content TEXT NOT NULL,
|
||||
source_type TEXT NOT NULL,
|
||||
session_id TEXT,
|
||||
message_id INTEGER,
|
||||
queued_at REAL NOT NULL,
|
||||
processed INTEGER DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_queue_processed ON embedding_queue(processed, queued_at);
|
||||
"""
|
||||
|
||||
FTS_SQL = """
|
||||
CREATE VIRTUAL TABLE IF NOT EXISTS facts_fts USING fts5(
|
||||
content,
|
||||
content_rowid='id',
|
||||
tokenize='unicode61'
|
||||
);
|
||||
|
||||
CREATE TRIGGER IF NOT EXISTS facts_fts_insert AFTER INSERT ON facts BEGIN
|
||||
INSERT INTO facts_fts(rowid, content) VALUES (new.id, new.content);
|
||||
END;
|
||||
|
||||
CREATE TRIGGER IF NOT EXISTS facts_fts_delete AFTER DELETE ON facts BEGIN
|
||||
DELETE FROM facts_fts WHERE rowid = old.id;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER IF NOT EXISTS facts_fts_update AFTER UPDATE ON facts BEGIN
|
||||
DELETE FROM facts_fts WHERE rowid = old.id;
|
||||
INSERT INTO facts_fts(rowid, content) VALUES (new.id, new.content);
|
||||
END;
|
||||
|
||||
CREATE VIRTUAL TABLE IF NOT EXISTS entities_fts USING fts5(
|
||||
name,
|
||||
content_rowid='id',
|
||||
tokenize='unicode61'
|
||||
);
|
||||
|
||||
CREATE TRIGGER IF NOT EXISTS entities_fts_insert AFTER INSERT ON entities BEGIN
|
||||
INSERT INTO entities_fts(rowid, name) VALUES (new.id, new.name);
|
||||
END;
|
||||
|
||||
CREATE TRIGGER IF NOT EXISTS entities_fts_delete AFTER DELETE ON entities BEGIN
|
||||
DELETE FROM entities_fts WHERE rowid = old.id;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER IF NOT EXISTS entities_fts_update AFTER UPDATE ON entities BEGIN
|
||||
DELETE FROM entities_fts WHERE rowid = old.id;
|
||||
INSERT INTO entities_fts(rowid, name) VALUES (new.id, new.name);
|
||||
END;
|
||||
"""
|
||||
|
||||
|
||||
def init_schema(conn: sqlite3.Connection) -> None:
|
||||
"""Initialisiert alle Tabellen, Indizes und FTS5."""
|
||||
conn.executescript(SCHEMA_SQL)
|
||||
conn.executescript(FTS_SQL)
|
||||
conn.execute(
|
||||
"INSERT OR REPLACE INTO memory_schema_version (version, applied_at) VALUES (?, ?)",
|
||||
(SCHEMA_VERSION, time.time()),
|
||||
)
|
||||
conn.commit()
|
||||
|
||||
|
||||
def migrate(conn: sqlite3.Connection) -> None:
|
||||
"""Führt Migrationen durch (aktuell: nur Schema-Version prüfen)."""
|
||||
row = conn.execute("SELECT version FROM memory_schema_version ORDER BY version DESC LIMIT 1").fetchone()
|
||||
current = row[0] if row else 0
|
||||
if current < SCHEMA_VERSION:
|
||||
init_schema(conn)
|
||||
|
||||
|
||||
def connect(db_path: Path, wal_mode: bool = True) -> sqlite3.Connection:
|
||||
"""Erstellt Verbindung mit WAL-Mode und Foreign Keys."""
|
||||
db_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
conn = sqlite3.connect(str(db_path), check_same_thread=False, timeout=10.0)
|
||||
conn.row_factory = sqlite3.Row
|
||||
conn.execute("PRAGMA foreign_keys=ON")
|
||||
if wal_mode:
|
||||
try:
|
||||
conn.execute("PRAGMA journal_mode=WAL")
|
||||
except sqlite3.OperationalError:
|
||||
conn.execute("PRAGMA journal_mode=DELETE")
|
||||
return conn
|
||||
Reference in New Issue
Block a user