mirror of
http://100.103.83.12:3003/fegger/pv-agent.git
synced 2026-09-17 16:06:23 +00:00
feat(agent): add odoo review mode with plausibility verdict
This commit is contained in:
+28
-4
@@ -25,7 +25,8 @@ CREATE TABLE IF NOT EXISTS interactions (
|
||||
model TEXT NOT NULL,
|
||||
latency_ms INTEGER NOT NULL,
|
||||
n_context INTEGER NOT NULL,
|
||||
regenerations INTEGER NOT NULL
|
||||
regenerations INTEGER NOT NULL,
|
||||
context_json TEXT
|
||||
);
|
||||
CREATE TABLE IF NOT EXISTS ratings (
|
||||
request_id TEXT PRIMARY KEY,
|
||||
@@ -62,12 +63,25 @@ class AuditStore:
|
||||
self._con.execute("PRAGMA foreign_keys = ON")
|
||||
self._con.execute("PRAGMA journal_mode = WAL")
|
||||
self._con.executescript(SCHEMA)
|
||||
self._migrate()
|
||||
self._delete_expired()
|
||||
|
||||
def close(self) -> None:
|
||||
with self._lock:
|
||||
self._con.close()
|
||||
|
||||
def _migrate(self) -> None:
|
||||
"""Idempotente Spalten-Migration für bestehende audit.db-Dateien."""
|
||||
cols = {
|
||||
row[1]
|
||||
for row in self._con.execute("PRAGMA table_info(interactions)").fetchall()
|
||||
}
|
||||
if "context_json" not in cols:
|
||||
self._con.execute(
|
||||
"ALTER TABLE interactions ADD COLUMN context_json TEXT"
|
||||
)
|
||||
self._con.commit()
|
||||
|
||||
def _delete_expired(self) -> None:
|
||||
if self.cfg.audit_retention_days <= 0:
|
||||
return
|
||||
@@ -76,7 +90,7 @@ class AuditStore:
|
||||
self._con.execute("DELETE FROM interactions WHERE created_at < ?", (cutoff,))
|
||||
self._con.commit()
|
||||
|
||||
def record_interaction(self, payload: dict) -> None:
|
||||
def record_interaction(self, payload: dict, context: dict | None = None) -> None:
|
||||
now = int(time.time())
|
||||
include_content = self.cfg.audit_log_content
|
||||
question = payload.get("question") if include_content else None
|
||||
@@ -84,6 +98,11 @@ class AuditStore:
|
||||
sources = payload.get("sources", []) if include_content else []
|
||||
conflicts = payload.get("conflicts", []) if include_content else []
|
||||
planned_queries = payload.get("planned_queries", []) if include_content else []
|
||||
context_json = (
|
||||
json.dumps(context, ensure_ascii=False)
|
||||
if include_content and context
|
||||
else None
|
||||
)
|
||||
values = (
|
||||
payload["request_id"],
|
||||
now,
|
||||
@@ -100,14 +119,15 @@ class AuditStore:
|
||||
int(payload.get("latency_ms", 0)),
|
||||
int(payload.get("n_context", 0)),
|
||||
int(payload.get("regenerations", 0)),
|
||||
context_json,
|
||||
)
|
||||
with self._lock:
|
||||
self._con.execute(
|
||||
"INSERT INTO interactions("
|
||||
"request_id, created_at, question, answer, status, verified, refused, "
|
||||
"citations_json, sources_json, conflicts_json, planned_queries_json, "
|
||||
"model, latency_ms, n_context, regenerations"
|
||||
") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) "
|
||||
"model, latency_ms, n_context, regenerations, context_json"
|
||||
") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) "
|
||||
"ON CONFLICT(request_id) DO UPDATE SET "
|
||||
"created_at=excluded.created_at, question=excluded.question, "
|
||||
"answer=excluded.answer, status=excluded.status, "
|
||||
@@ -123,6 +143,8 @@ class AuditStore:
|
||||
if self.cfg.audit_stdout:
|
||||
if include_content:
|
||||
event = {"event": "agent_interaction", "created_at": now, **payload}
|
||||
if context:
|
||||
event["context"] = context
|
||||
else:
|
||||
event = {
|
||||
"event": "agent_interaction",
|
||||
@@ -237,6 +259,8 @@ class AuditStore:
|
||||
item[field.removesuffix("_json")] = json.loads(item.pop(field))
|
||||
item["verified"] = bool(item["verified"])
|
||||
item["refused"] = bool(item["refused"])
|
||||
raw_context = item.pop("context_json", None)
|
||||
item["context"] = json.loads(raw_context) if raw_context else None
|
||||
item["comments"] = comments_by_request[item["request_id"]]
|
||||
out.append(item)
|
||||
return out
|
||||
|
||||
Reference in New Issue
Block a user