Lucidia Core - AI reasoning engines for specialized domains: - Physicist (867 lines) - energy modeling, force calculations - Mathematician (760 lines) - symbolic computation, proofs - Geologist (654 lines) - terrain modeling, stratigraphy - Engineer (599 lines) - structural analysis, optimization - Painter (583 lines) - visual generation, graphics - Chemist (569 lines) - molecular analysis, reactions - Analyst (505 lines) - pattern recognition, insights - Plus: architect, researcher, mediator, speaker, poet, navigator Features: - FastAPI wrapper with REST endpoints for each agent - CLI with `lucidia list`, `lucidia run`, `lucidia api` - Codex YAML configurations for agent personalities - Quantum engine extensions 12,512 lines of Python across 91 files. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
198 lines
6.9 KiB
Python
198 lines
6.9 KiB
Python
#!/usr/bin/env python3
|
|
"""Guardian Agent
|
|
"""Guardian agent wired into the unified intelligence bus."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from __future__ import annotations
|
|
|
|
import time
|
|
from typing import Any, Iterable, Mapping, Optional
|
|
|
|
from prism_event_bridge import fetch_events
|
|
import asyncio
|
|
import json
|
|
import logging
|
|
import os
|
|
from dataclasses import dataclass
|
|
from pathlib import Path
|
|
from typing import Any, Mapping
|
|
|
|
import yaml
|
|
|
|
from lucidia.intelligence.events import make_event, validate_event
|
|
from lucidia.reflex import BUS, start as start_reflex
|
|
|
|
class Guardian:
|
|
def __init__(self) -> None:
|
|
self.cursor: Optional[str] = None
|
|
|
|
def handle_event(self, record: Mapping[str, Any]) -> None:
|
|
topic = record.get("topic", "?")
|
|
payload = record.get("payload", {})
|
|
kpis = record.get("kpis")
|
|
memory_deltas = record.get("memory_deltas")
|
|
print(f"[guardian] event {topic}: {payload}")
|
|
if kpis:
|
|
print(f"[guardian] KPIs: {kpis}")
|
|
if isinstance(memory_deltas, Iterable):
|
|
for delta in memory_deltas:
|
|
print(f"[guardian] memory delta: {delta}")
|
|
|
|
def loop(self, poll_interval: float = 2.0) -> None:
|
|
while True:
|
|
events, cursor = fetch_events(since=self.cursor)
|
|
if cursor:
|
|
self.cursor = cursor
|
|
for record in events:
|
|
try:
|
|
self.handle_event(record)
|
|
except Exception as exc: # noqa: BLE001 - Guardian must keep running
|
|
print(f"[guardian] failed to handle event: {exc}")
|
|
time.sleep(poll_interval)
|
|
|
|
|
|
def main() -> None:
|
|
guardian = Guardian()
|
|
guardian.loop()
|
|
LOGGER = logging.getLogger("lucidia.guardian")
|
|
LOGGER.setLevel(logging.INFO)
|
|
_handler = logging.StreamHandler()
|
|
_handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(message)s"))
|
|
LOGGER.addHandler(_handler)
|
|
|
|
DEFAULT_POLICY_PATH = Path(os.environ.get("LUCIDIA_GUARDIAN_POLICY", "guardian/policy.yaml"))
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class PolicyEnvelope:
|
|
"""Loaded guardian policy metadata."""
|
|
|
|
version: str
|
|
directives: Mapping[str, Any]
|
|
|
|
@classmethod
|
|
def load(cls, path: Path) -> "PolicyEnvelope":
|
|
if not path.exists():
|
|
LOGGER.warning("Guardian policy missing at %s; using defaults", path)
|
|
return cls(
|
|
version="0.0.0",
|
|
directives={
|
|
"restraint": ["no destructive operations"],
|
|
"contradiction": {"escalate": True, "cooldown_seconds": 180},
|
|
},
|
|
)
|
|
with path.open("r", encoding="utf-8") as handle:
|
|
payload = yaml.safe_load(handle) or {}
|
|
return cls(
|
|
version=str(payload.get("version", "0.0.0")),
|
|
directives=payload.get("directives", {}),
|
|
)
|
|
|
|
|
|
class Guardian:
|
|
"""Central truth arbiter for the Lucidia reflex loop."""
|
|
|
|
def __init__(self, policy_path: Path = DEFAULT_POLICY_PATH) -> None:
|
|
self._policy_path = policy_path
|
|
self._policy = PolicyEnvelope.load(policy_path)
|
|
self._state_path = Path(os.environ.get("LUCIDIA_GUARDIAN_STATE", "logs/guardian_state.json"))
|
|
self._state_path.parent.mkdir(parents=True, exist_ok=True)
|
|
BUS.on("guardian.contradiction", self._handle_contradiction)
|
|
BUS.on("guardian.policy.request", self._handle_policy_request)
|
|
BUS.on("memory.deltas.*", self._handle_memory_delta)
|
|
LOGGER.info("Guardian initialized with policy version %s", self._policy.version)
|
|
|
|
# ------------------------------------------------------------------
|
|
def _handle_contradiction(self, event: Mapping[str, Any]) -> None:
|
|
try:
|
|
validate_event(event)
|
|
except Exception as exc: # pragma: no cover - guardrail
|
|
LOGGER.error("Ignoring invalid contradiction event: %s", exc)
|
|
return
|
|
payload = event.get("payload", {})
|
|
summary = payload.get("summary", "contradiction detected")
|
|
severity = payload.get("severity", "unknown")
|
|
LOGGER.warning("Contradiction(%s): %s", severity, summary)
|
|
update_payload = {
|
|
"decision": "halt" if severity in {"critical", "high"} else "review",
|
|
"source_event": event["id"],
|
|
"reason": summary,
|
|
}
|
|
update = make_event(
|
|
topic="guardian.policy.update",
|
|
payload=update_payload,
|
|
source="guardian",
|
|
channel="guardian",
|
|
parent_id=event.get("id"),
|
|
tags=["policy", "contradiction"],
|
|
)
|
|
BUS.emit(update["topic"], update)
|
|
self._persist_state({"last_contradiction": update_payload})
|
|
|
|
# ------------------------------------------------------------------
|
|
def _handle_policy_request(self, event: Mapping[str, Any]) -> None:
|
|
try:
|
|
validate_event(event)
|
|
except Exception as exc: # pragma: no cover - guardrail
|
|
LOGGER.error("Ignoring invalid policy request: %s", exc)
|
|
return
|
|
snapshot = make_event(
|
|
topic="guardian.policy.snapshot",
|
|
payload={
|
|
"version": self._policy.version,
|
|
"directives": self._policy.directives,
|
|
},
|
|
source="guardian",
|
|
channel="guardian",
|
|
parent_id=event.get("id"),
|
|
tags=["policy", "snapshot"],
|
|
)
|
|
BUS.emit(snapshot["topic"], snapshot)
|
|
|
|
# ------------------------------------------------------------------
|
|
def _handle_memory_delta(self, event: Mapping[str, Any]) -> None:
|
|
try:
|
|
validate_event(event)
|
|
except Exception:
|
|
return
|
|
payload = event.get("payload", {})
|
|
delta_summary = payload.get("summary")
|
|
LOGGER.info("Memory delta observed: %s", delta_summary)
|
|
audit = make_event(
|
|
topic="guardian.audit.memory",
|
|
payload={
|
|
"delta": payload,
|
|
"ack": True,
|
|
},
|
|
source="guardian",
|
|
channel="guardian",
|
|
parent_id=event.get("id"),
|
|
tags=["memory", "audit"],
|
|
)
|
|
BUS.emit(audit["topic"], audit)
|
|
|
|
# ------------------------------------------------------------------
|
|
def _persist_state(self, data: Mapping[str, Any]) -> None:
|
|
snapshot = {"policy_version": self._policy.version, **data}
|
|
try:
|
|
with self._state_path.open("w", encoding="utf-8") as handle:
|
|
json.dump(snapshot, handle, indent=2)
|
|
except OSError as exc: # pragma: no cover - guardrail
|
|
LOGGER.error("Failed to persist guardian state: %s", exc)
|
|
|
|
|
|
def main() -> None:
|
|
start_reflex()
|
|
Guardian()
|
|
LOGGER.info("Guardian ready; waiting for events")
|
|
loop = asyncio.new_event_loop()
|
|
try:
|
|
loop.run_forever()
|
|
finally: # pragma: no cover - lifecycle guard
|
|
loop.close()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|