Fix 3 arc reactor bugs: metrics_json→metric_data, system nesting, message→content in conversations

- guardian_loop + sitrep: SELECT metric_data (not metrics_json which does not exist)
- guardian_loop: metrics are flat (cpu_percent at top level), not nested under system key
- guardian_loop + sitrep: filter metric_type=system to avoid parsing proxmox blobs
- guardian_loop: disk.mount key (not mountpoint) + fallback for both key names
- sitrep: same metric_data + root-level key fixes
- _guardian_inject_chat (x2): INSERT into conversations.content (not message)
- /guardian/chat endpoint (x2): SELECT content (not message) from conversations

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-12 01:59:58 +00:00
parent 7dc457562b
commit 04bd412b65
+13 -13
View File
@@ -945,10 +945,11 @@ async def guardian_loop() -> None:
# ── 2. Metrics analysis ───────────────────────────────────────────
# Get latest metric per online agent
metrics_rows = await db_fetchall(
"""SELECT m.agent_id, r.hostname, m.metrics_json
"""SELECT m.agent_id, r.hostname, m.metric_data
FROM agent_metrics m
JOIN registered_agents r ON r.agent_id = m.agent_id
WHERE r.status = 'online'
AND m.metric_type = 'system'
AND m.recorded_at > DATE_SUB(NOW(), INTERVAL 5 MINUTE)
ORDER BY m.recorded_at DESC"""
)
@@ -961,8 +962,7 @@ async def guardian_loop() -> None:
hostname = row["hostname"]
try:
m = json.loads(row["metrics_json"]) if isinstance(row["metrics_json"], str) else row["metrics_json"]
sys_data = m.get("system", {})
sys_data = json.loads(row["metric_data"]) if isinstance(row["metric_data"], str) else row["metric_data"]
cpu = sys_data.get("cpu_percent")
if cpu is not None and float(cpu) >= cpu_thresh:
@@ -988,7 +988,7 @@ async def guardian_loop() -> None:
for disk in disks:
dpct = disk.get("percent", 0)
if dpct and float(str(dpct).rstrip("%")) >= disk_thresh:
mount = disk.get("mountpoint", "/")
mount = disk.get("mount", disk.get("mountpoint", "/"))
key = f"disk_{mount}"
if await _guardian_cooldown_ok(aid, key):
msg = f"{hostname}: Disk {mount} at {dpct}% (threshold: {disk_thresh}%)"
@@ -1051,7 +1051,7 @@ async def _guardian_inject_chat(message: str) -> None:
"""Write a proactive JARVIS message into the conversations table so the HUD picks it up."""
try:
await db_execute(
"""INSERT INTO conversations (session_id, role, message, created_at)
"""INSERT INTO conversations (session_id, role, content, created_at)
VALUES ('guardian', 'assistant', %s, NOW())""",
(message,)
)
@@ -1079,16 +1079,16 @@ async def handle_sitrep(payload: dict) -> dict:
# 2. Get latest metrics per agent
metrics_map = {}
metrics_rows = await db_fetchall(
"""SELECT m.agent_id, m.metrics_json, m.recorded_at
"""SELECT m.agent_id, m.metric_data, m.recorded_at
FROM agent_metrics m
WHERE m.recorded_at > DATE_SUB(NOW(), INTERVAL 10 MINUTE)
WHERE m.metric_type = 'system'
AND m.recorded_at > DATE_SUB(NOW(), INTERVAL 10 MINUTE)
ORDER BY m.recorded_at DESC"""
)
for row in metrics_rows:
if row["agent_id"] not in metrics_map:
try:
m = json.loads(row["metrics_json"]) if isinstance(row["metrics_json"], str) else row["metrics_json"]
metrics_map[row["agent_id"]] = m
metrics_map[row["agent_id"]] = json.loads(row["metric_data"]) if isinstance(row["metric_data"], str) else row["metric_data"]
except Exception:
pass
@@ -1117,7 +1117,7 @@ async def handle_sitrep(payload: dict) -> dict:
sys = m.get("system", {}) if m else {}
cpu = sys.get("cpu_percent", "?")
mem = sys.get("memory", {}).get("percent", "?") if isinstance(sys.get("memory"), dict) else "?"
disk = next((d.get("percent","?") for d in (sys.get("disk") or []) if d.get("mountpoint") == "/"), "?")
disk = next((d.get("percent","?") for d in (sys.get("disk") or []) if d.get("mount","").rstrip("/") == "" or d.get("mountpoint","") == "/"), "?")
line = (f" {ag['hostname']} ({ag['status'].upper()}) — "
f"CPU:{cpu}% MEM:{mem}% DISK:{disk}%")
agent_lines.append(line)
@@ -1806,7 +1806,7 @@ Keep the tone confident and action-oriented. Format with clear sections. Under 4
# Store in conversations so HUD can surface it
await db_execute(
"INSERT INTO conversations (session_id, role, message, created_at) VALUES ('guardian','assistant',%s,NOW())",
"INSERT INTO conversations (session_id, role, content, created_at) VALUES ('guardian','assistant',%s,NOW())",
(review_text,)
)
@@ -2728,13 +2728,13 @@ async def guardian_chat_events(since: str = ""):
"""Return proactive guardian messages injected into conversations."""
if since:
rows = await db_fetchall(
"SELECT id, message, created_at FROM conversations "
"SELECT id, content, created_at FROM conversations"
"WHERE session_id='guardian' AND created_at > %s ORDER BY created_at ASC",
(since,)
)
else:
rows = await db_fetchall(
"SELECT id, message, created_at FROM conversations "
"SELECT id, content, created_at FROM conversations"
"WHERE session_id='guardian' ORDER BY created_at DESC LIMIT 10"
)
return rows or []