62 lines
2.9 KiB
Python
62 lines
2.9 KiB
Python
"""Agent orchestration — Spec 029."""
|
|
from __future__ import annotations
|
|
import os
|
|
from pathlib import Path
|
|
from app.agents import checks, llm_client, notify, registry, store
|
|
|
|
SPECS = Path(os.getenv("AGENTIC_SPECS_ROOT", "/opt/ligbox-ops-platform/specs"))
|
|
OPS_API = os.getenv("OPS_API_URL", "http://api:8080")
|
|
TOKEN = os.getenv("OPS_INTERNAL_TOKEN", "")
|
|
|
|
def sync_registry(conn):
|
|
for sc in registry.load_registry():
|
|
store.upsert_scenario(conn, sc)
|
|
return len(registry.load_registry())
|
|
|
|
def index_specs_kb(conn):
|
|
if not SPECS.exists(): return 0
|
|
n = 0
|
|
for p in sorted(SPECS.glob("**/*.md")):
|
|
try:
|
|
txt = p.read_text(encoding="utf-8", errors="ignore")
|
|
if len(txt) > 100:
|
|
store.index_kb_file(conn, str(p.relative_to(SPECS)), txt)
|
|
n += 1
|
|
except OSError:
|
|
pass
|
|
return n
|
|
|
|
def run_scenario(conn, scenario_id, *, trigger="cron"):
|
|
sc = store.get_scenario(conn, scenario_id)
|
|
if not sc: return {"ok": False, "error": "not found"}
|
|
fn = checks.SCENARIO_RUNNERS.get(scenario_id)
|
|
if not fn: return {"ok": False, "error": "no runner"}
|
|
run_id = store.create_run(conn, scenario_id, trigger)
|
|
store.log_event(conn, event_type="run.start", message=scenario_id, run_id=run_id)
|
|
raw = fn(conn, ops_api_url=OPS_API, internal_token=TOKEN)
|
|
fids = []
|
|
for f in raw:
|
|
kb = store.search_kb(conn, f.get("title", ""))
|
|
human = f.get("human_action") or ""
|
|
if f.get("severity") in ("high", "critical", "warn"):
|
|
advice, model = llm_client.advise_human_action(
|
|
finding_title=f.get("title",""), finding_detail=f.get("detail_md",""),
|
|
kb_snippets=[k["snippet"] for k in kb],
|
|
)
|
|
if advice and not human: human = advice
|
|
fid = store.add_finding(conn, run_id, severity=f.get("severity", sc.get("severity_default","warn")),
|
|
category=f.get("category","api"), title=f.get("title","Finding"), detail_md=f.get("detail_md",""),
|
|
evidence=f.get("evidence"), human_action=human, kb_refs=[k["source"] for k in kb])
|
|
fids.append(fid)
|
|
if f.get("severity") in ("high", "critical"):
|
|
notify.notify_finding({**f, "suggested_human_action": human})
|
|
store.log_event(conn, event_type="finding.created", message=f.get("title",""), run_id=run_id, payload={"id": fid})
|
|
status = "ok" if not raw else "degraded"
|
|
store.finish_run(conn, run_id, status=status, summary=f"{len(raw)} finding(s)" if raw else "healthy")
|
|
store.log_event(conn, event_type="run.finish", message=status, run_id=run_id)
|
|
return {"ok": True, "run_id": run_id, "scenario_id": scenario_id, "status": status, "findings_count": len(raw), "finding_ids": fids}
|
|
|
|
def run_all_enabled(conn, trigger="cron"):
|
|
sync_registry(conn)
|
|
return {"runs": [run_scenario(conn, s["id"], trigger=trigger) for s in store.list_scenarios(conn)],
|
|
"total": len(store.list_scenarios(conn))}
|