"""Persistent store for agent observability records. Stores sanitized execution metrics for OpenClaw/Hermes/sub-agents. No prompts, secrets, or private message contents are persisted here; only metrics and routing metadata are stored for Web UI statistics and audit. """ from __future__ import annotations import json from pathlib import Path from typing import Any from .agent_observability import AgentExecutionRecord, AgentObservability class AgentObservabilityStore: def __init__(self, root: str = "runtime/agent-observability"): self.root = Path(root) self.records_dir = self.root / "records" self.records_dir.mkdir(parents=True, exist_ok=True) def append(self, record: AgentExecutionRecord) -> dict[str, Any]: path = self.records_dir / f"{record.execution_id}.json" data = record.to_dict() path.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8") return data def load(self) -> AgentObservability: observability = AgentObservability() for path in sorted(self.records_dir.glob("*.json")): raw = json.loads(path.read_text(encoding="utf-8")) observability.records.append(AgentExecutionRecord(**raw)) return observability def query(self, user_id: str | None = None, group_id: str | None = None, role: str = "user") -> list[dict[str, Any]]: records = [record.to_dict() for record in self.load().records] if role == "owner": return records if role == "group_admin" and group_id: return [r for r in records if r.get("visible_scope") == group_id or r.get("user_id") == user_id] return [r for r in records if r.get("user_id") == user_id] __all__ = ["AgentObservabilityStore"]