76 lines
2.3 KiB
Python
76 lines
2.3 KiB
Python
|
|
"""SQLite — geheugen van de agent (dedupe, incidenten)."""
|
||
|
|
import json
|
||
|
|
import sqlite3
|
||
|
|
from datetime import datetime, timedelta
|
||
|
|
from pathlib import Path
|
||
|
|
|
||
|
|
DB_PATH = Path(__file__).resolve().parent.parent / "data" / "agent.db"
|
||
|
|
|
||
|
|
|
||
|
|
def connect():
|
||
|
|
DB_PATH.parent.mkdir(parents=True, exist_ok=True)
|
||
|
|
conn = sqlite3.connect(DB_PATH)
|
||
|
|
conn.row_factory = sqlite3.Row
|
||
|
|
conn.executescript(
|
||
|
|
"""
|
||
|
|
CREATE TABLE IF NOT EXISTS incidents (
|
||
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
|
|
fingerprint TEXT NOT NULL,
|
||
|
|
severity TEXT NOT NULL,
|
||
|
|
title TEXT NOT NULL,
|
||
|
|
body TEXT NOT NULL,
|
||
|
|
created_at TEXT NOT NULL,
|
||
|
|
notified INTEGER DEFAULT 0
|
||
|
|
);
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_fp ON incidents(fingerprint);
|
||
|
|
CREATE TABLE IF NOT EXISTS runs (
|
||
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
|
|
started_at TEXT NOT NULL,
|
||
|
|
summary TEXT,
|
||
|
|
raw_observations TEXT
|
||
|
|
);
|
||
|
|
"""
|
||
|
|
)
|
||
|
|
return conn
|
||
|
|
|
||
|
|
|
||
|
|
def was_notified_recently(fingerprint: str, minutes: int) -> bool:
|
||
|
|
since = (datetime.utcnow() - timedelta(minutes=minutes)).isoformat()
|
||
|
|
conn = connect()
|
||
|
|
row = conn.execute(
|
||
|
|
"SELECT 1 FROM incidents WHERE fingerprint=? AND notified=1 AND created_at>?",
|
||
|
|
(fingerprint, since),
|
||
|
|
).fetchone()
|
||
|
|
conn.close()
|
||
|
|
return row is not None
|
||
|
|
|
||
|
|
|
||
|
|
def record_incident(fingerprint: str, severity: str, title: str, body: str, notified: bool):
|
||
|
|
conn = connect()
|
||
|
|
conn.execute(
|
||
|
|
"INSERT INTO incidents (fingerprint, severity, title, body, created_at, notified) VALUES (?,?,?,?,?,?)",
|
||
|
|
(fingerprint, severity, title, body, datetime.utcnow().isoformat(), 1 if notified else 0),
|
||
|
|
)
|
||
|
|
conn.commit()
|
||
|
|
conn.close()
|
||
|
|
|
||
|
|
|
||
|
|
def recent_incidents(limit: int = 10) -> list[dict]:
|
||
|
|
conn = connect()
|
||
|
|
rows = conn.execute(
|
||
|
|
"SELECT severity, title, body, created_at FROM incidents ORDER BY id DESC LIMIT ?",
|
||
|
|
(limit,),
|
||
|
|
).fetchall()
|
||
|
|
conn.close()
|
||
|
|
return [dict(r) for r in rows]
|
||
|
|
|
||
|
|
|
||
|
|
def log_run(summary: str, observations: dict):
|
||
|
|
conn = connect()
|
||
|
|
conn.execute(
|
||
|
|
"INSERT INTO runs (started_at, summary, raw_observations) VALUES (?,?,?)",
|
||
|
|
(datetime.utcnow().isoformat(), summary, json.dumps(observations, default=str)),
|
||
|
|
)
|
||
|
|
conn.commit()
|
||
|
|
conn.close()
|