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>
470 lines
18 KiB
Python
470 lines
18 KiB
Python
"""Lucidia Codex-10 Mediator agent.
|
|
|
|
The Mediator keeps conversations from collapsing into collisions. It listens
|
|
for tension signals inside the Reflex bus, gathers the motives on each side,
|
|
and offers balancing language aligned with the Codex-10 charter. Output is
|
|
persisted as transcripts, harmony metrics, and prompt snippets that other
|
|
agents can learn from.
|
|
|
|
Behavioral loop (per the charter): detect → listen → translate → balance → record
|
|
→ rest.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import logging
|
|
import textwrap
|
|
import time
|
|
from collections import OrderedDict
|
|
from dataclasses import dataclass, field
|
|
from datetime import datetime, timezone
|
|
from pathlib import Path
|
|
from typing import Mapping, Optional, Sequence
|
|
|
|
import yaml
|
|
|
|
from lucidia.intelligence.events import make_event, validate_event
|
|
from lucidia.reflex import BUS, start as start_reflex
|
|
|
|
LOGGER = logging.getLogger("lucidia.mediator")
|
|
if not LOGGER.handlers:
|
|
LOGGER.setLevel(logging.INFO)
|
|
handler = logging.StreamHandler()
|
|
formatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s")
|
|
handler.setFormatter(formatter)
|
|
LOGGER.addHandler(handler)
|
|
|
|
DEFAULT_STATE_DIR = Path("logs/lucidia/mediator")
|
|
DEFAULT_EMIT_DIR = Path("/codex/prompts/next")
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class MediatorCharter:
|
|
"""Minimal slice of the Codex-10 charter useful at runtime."""
|
|
|
|
name: str = "Codex-10 Mediator"
|
|
moral_constant: str = "Justice = Understanding in motion"
|
|
core_principle: str = "No truth is served by silencing another"
|
|
directives: Sequence[str] = field(default_factory=tuple)
|
|
seed_language: str = ""
|
|
|
|
@classmethod
|
|
def from_yaml(cls, path: Optional[Path]) -> "MediatorCharter":
|
|
if path is None or not path.exists():
|
|
return cls()
|
|
try:
|
|
payload = yaml.safe_load(path.read_text(encoding="utf-8")) or {}
|
|
except yaml.YAMLError as exc: # pragma: no cover - guardrail
|
|
LOGGER.error("Failed to parse charter yaml %s: %s", path, exc)
|
|
return cls()
|
|
defaults = cls()
|
|
agent_raw = payload.get("agent", {})
|
|
agent: Mapping[str, object]
|
|
if isinstance(agent_raw, Mapping):
|
|
agent = agent_raw
|
|
else:
|
|
agent = {}
|
|
raw_directives = payload.get("directives")
|
|
if isinstance(raw_directives, Sequence) and not isinstance(raw_directives, (str, bytes)):
|
|
directives = tuple(str(item) for item in raw_directives)
|
|
else:
|
|
directives = tuple()
|
|
seed_language = str(payload.get("seed_language", "")).strip()
|
|
return cls(
|
|
name=str(agent.get("name", defaults.name)),
|
|
moral_constant=str(agent.get("moral_constant", defaults.moral_constant)),
|
|
core_principle=str(agent.get("core_principle", defaults.core_principle)),
|
|
directives=directives,
|
|
seed_language=seed_language,
|
|
)
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class HarmonyMetrics:
|
|
"""Rolling metrics describing harmony inside the console."""
|
|
|
|
tensions_observed: int = 0
|
|
resolutions_offered: int = 0
|
|
follow_up_required: int = 0
|
|
last_resolution: Optional[str] = None
|
|
|
|
def to_dict(self) -> dict[str, object]:
|
|
return {
|
|
"tensions_observed": self.tensions_observed,
|
|
"resolutions_offered": self.resolutions_offered,
|
|
"follow_up_required": self.follow_up_required,
|
|
"last_resolution": self.last_resolution,
|
|
}
|
|
|
|
@classmethod
|
|
def from_dict(cls, data: Mapping[str, object]) -> "HarmonyMetrics":
|
|
return cls(
|
|
tensions_observed=int(data.get("tensions_observed", 0) or 0),
|
|
resolutions_offered=int(data.get("resolutions_offered", 0) or 0),
|
|
follow_up_required=int(data.get("follow_up_required", 0) or 0),
|
|
last_resolution=(
|
|
str(data.get("last_resolution"))
|
|
if data.get("last_resolution") not in {None, ""}
|
|
else None
|
|
),
|
|
)
|
|
|
|
def record(self, *, follow_up: bool, summary: str) -> None:
|
|
self.tensions_observed += 1
|
|
if follow_up:
|
|
self.follow_up_required += 1
|
|
else:
|
|
self.resolutions_offered += 1
|
|
self.last_resolution = summary
|
|
|
|
|
|
@dataclass(slots=True)
|
|
class MediationRecord:
|
|
"""Structured transcript entry for a mediated event."""
|
|
|
|
conflict_id: str
|
|
source_topic: str
|
|
summary: str
|
|
guidance: str
|
|
participants: Sequence[str]
|
|
positions: Sequence[str]
|
|
severity: str
|
|
timestamp: str
|
|
status: str
|
|
|
|
def to_dict(self) -> dict[str, object]:
|
|
return {
|
|
"conflict_id": self.conflict_id,
|
|
"source_topic": self.source_topic,
|
|
"summary": self.summary,
|
|
"guidance": self.guidance,
|
|
"participants": list(self.participants),
|
|
"positions": list(self.positions),
|
|
"severity": self.severity,
|
|
"timestamp": self.timestamp,
|
|
"status": self.status,
|
|
}
|
|
|
|
|
|
class PromptEmitter:
|
|
"""Write mediator reflections to a prompt directory."""
|
|
|
|
def __init__(self, directory: Optional[Path]) -> None:
|
|
self.directory = directory
|
|
if self.directory is not None:
|
|
self.directory.mkdir(parents=True, exist_ok=True)
|
|
|
|
def emit(self, text: str) -> Optional[Path]:
|
|
if self.directory is None:
|
|
return None
|
|
ts = int(time.time() * 1000)
|
|
path = self.directory / f"mediator-{ts}.txt"
|
|
path.write_text(text + "\n", encoding="utf-8")
|
|
return path
|
|
|
|
|
|
class Mediator:
|
|
"""Codex-10 Mediator implementation."""
|
|
|
|
def __init__(
|
|
self,
|
|
*,
|
|
charter: MediatorCharter,
|
|
state_dir: Path = DEFAULT_STATE_DIR,
|
|
emit_dir: Optional[Path] = None,
|
|
auto_emit: bool = True,
|
|
) -> None:
|
|
self.charter = charter
|
|
self.state_dir = state_dir
|
|
self.state_dir.mkdir(parents=True, exist_ok=True)
|
|
self.transcript_path = self.state_dir / "mediator_transcript.jsonl"
|
|
self.summary_path = self.state_dir / "mediator_reflections.md"
|
|
self.metrics_path = self.state_dir / "mediator_metrics.json"
|
|
self.metrics = self._load_metrics()
|
|
self.emitter = PromptEmitter(emit_dir)
|
|
self._auto_emit = auto_emit
|
|
self._recent_event_ids: OrderedDict[str, None] = OrderedDict()
|
|
self._recent_event_limit = 1024
|
|
self._initialize_summary()
|
|
|
|
# ------------------------------------------------------------------
|
|
def register(self) -> None:
|
|
"""Attach mediator handlers to the Reflex bus."""
|
|
|
|
BUS.on("guardian.contradiction", self._handle_contradiction)
|
|
BUS.on("observations.dialogue.tension*", self._handle_dialogue_tension)
|
|
|
|
# ------------------------------------------------------------------
|
|
def _initialize_summary(self) -> None:
|
|
if self.summary_path.exists():
|
|
return
|
|
header_lines = [
|
|
f"# {self.charter.name}",
|
|
"",
|
|
f"Moral constant: {self.charter.moral_constant}",
|
|
f"Core principle: {self.charter.core_principle}",
|
|
]
|
|
if self.charter.seed_language:
|
|
header_lines.extend([
|
|
"",
|
|
"Seed language:",
|
|
textwrap.fill(self.charter.seed_language, width=92),
|
|
])
|
|
if self.charter.directives:
|
|
header_lines.append("")
|
|
header_lines.append("Directives:")
|
|
for directive in self.charter.directives:
|
|
header_lines.append(f"- {directive}")
|
|
header_lines.append("")
|
|
self.summary_path.write_text("\n".join(header_lines) + "\n", encoding="utf-8")
|
|
|
|
# ------------------------------------------------------------------
|
|
def _load_metrics(self) -> HarmonyMetrics:
|
|
if not self.metrics_path.exists():
|
|
return HarmonyMetrics()
|
|
try:
|
|
data = json.loads(self.metrics_path.read_text(encoding="utf-8"))
|
|
except (OSError, json.JSONDecodeError):
|
|
return HarmonyMetrics()
|
|
if not isinstance(data, Mapping):
|
|
return HarmonyMetrics()
|
|
return HarmonyMetrics.from_dict(data)
|
|
|
|
# ------------------------------------------------------------------
|
|
def _save_metrics(self) -> None:
|
|
payload = json.dumps(self.metrics.to_dict(), indent=2, ensure_ascii=False)
|
|
self.metrics_path.write_text(payload + "\n", encoding="utf-8")
|
|
|
|
# ------------------------------------------------------------------
|
|
def _already_processed(self, event_id: str) -> bool:
|
|
if not event_id:
|
|
return False
|
|
if event_id in self._recent_event_ids:
|
|
# Refresh recency by moving to the end
|
|
self._recent_event_ids.move_to_end(event_id)
|
|
return True
|
|
self._recent_event_ids[event_id] = None
|
|
if len(self._recent_event_ids) > self._recent_event_limit:
|
|
self._recent_event_ids.popitem(last=False)
|
|
return False
|
|
|
|
# ------------------------------------------------------------------
|
|
def mediate_event(self, source_topic: str, event: Mapping[str, object]) -> Optional[dict[str, object]]:
|
|
"""Generate a mediation record for the provided event."""
|
|
|
|
if not isinstance(event, Mapping):
|
|
return None
|
|
try:
|
|
validate_event(event)
|
|
except Exception as exc: # pragma: no cover - guardrail
|
|
LOGGER.error("Ignoring invalid event on %s: %s", source_topic, exc)
|
|
return None
|
|
event_id = str(event.get("id", ""))
|
|
if self._already_processed(event_id):
|
|
return None
|
|
payload = event.get("payload", {})
|
|
if not isinstance(payload, Mapping):
|
|
payload = {}
|
|
summary = str(payload.get("summary", "tension detected")).strip() or "tension detected"
|
|
severity = str(payload.get("severity", "unknown")).lower() or "unknown"
|
|
participants = self._normalize_participants(payload.get("participants"))
|
|
positions = self._extract_positions(payload.get("positions"))
|
|
timestamp = str(event.get("timestamp") or self._now())
|
|
guidance = self._compose_guidance(summary, severity, participants, positions)
|
|
status = "follow-up" if severity in {"critical", "high"} else "proposed"
|
|
record = MediationRecord(
|
|
conflict_id=event_id,
|
|
source_topic=source_topic,
|
|
summary=summary,
|
|
guidance=guidance,
|
|
participants=participants,
|
|
positions=positions,
|
|
severity=severity,
|
|
timestamp=timestamp,
|
|
status=status,
|
|
)
|
|
self._append_transcript(record)
|
|
summary_text = self._format_summary(record)
|
|
self._append_summary(summary_text)
|
|
self.emitter.emit(summary_text)
|
|
follow_up = status == "follow-up"
|
|
self.metrics.record(follow_up=follow_up, summary=guidance)
|
|
self._save_metrics()
|
|
resolution = make_event(
|
|
topic="codex.mediator.resolution",
|
|
payload={
|
|
"conflict_id": record.conflict_id,
|
|
"source_topic": record.source_topic,
|
|
"summary": record.summary,
|
|
"guidance": record.guidance,
|
|
"participants": list(record.participants),
|
|
"positions": list(record.positions),
|
|
"severity": record.severity,
|
|
"status": record.status,
|
|
},
|
|
source="mediator",
|
|
channel="reflex",
|
|
parent_id=event_id,
|
|
tags=["mediator", "resolution"],
|
|
)
|
|
if self._auto_emit:
|
|
BUS.emit(resolution["topic"], resolution)
|
|
return resolution
|
|
|
|
# ------------------------------------------------------------------
|
|
def _handle_contradiction(self, event: Mapping[str, object]) -> None:
|
|
topic = "guardian.contradiction"
|
|
if isinstance(event, Mapping):
|
|
topic = str(event.get("topic", topic))
|
|
self.mediate_event(topic, event)
|
|
|
|
# ------------------------------------------------------------------
|
|
def _handle_dialogue_tension(self, event: Mapping[str, object]) -> None:
|
|
topic = "observations.dialogue.tension"
|
|
if isinstance(event, Mapping):
|
|
topic = str(event.get("topic", topic))
|
|
self.mediate_event(topic, event)
|
|
|
|
# ------------------------------------------------------------------
|
|
def _append_transcript(self, record: MediationRecord) -> None:
|
|
with self.transcript_path.open("a", encoding="utf-8") as handle:
|
|
handle.write(json.dumps(record.to_dict(), ensure_ascii=False) + "\n")
|
|
|
|
# ------------------------------------------------------------------
|
|
def _append_summary(self, text: str) -> None:
|
|
with self.summary_path.open("a", encoding="utf-8") as handle:
|
|
handle.write(text + "\n")
|
|
|
|
# ------------------------------------------------------------------
|
|
def _normalize_participants(self, raw: object) -> Sequence[str]:
|
|
if isinstance(raw, Mapping):
|
|
return tuple(str(key) for key in raw.keys())
|
|
if isinstance(raw, Sequence) and not isinstance(raw, (str, bytes)):
|
|
return tuple(str(item) for item in raw if str(item).strip())
|
|
if isinstance(raw, (str, bytes)):
|
|
return (str(raw),)
|
|
return tuple()
|
|
|
|
# ------------------------------------------------------------------
|
|
def _extract_positions(self, raw: object) -> Sequence[str]:
|
|
if isinstance(raw, Mapping):
|
|
return tuple(f"{key}: {value}" for key, value in raw.items())
|
|
if isinstance(raw, Sequence) and not isinstance(raw, (str, bytes)):
|
|
return tuple(str(item) for item in raw if str(item).strip())
|
|
if isinstance(raw, (str, bytes)):
|
|
return (str(raw),)
|
|
return tuple()
|
|
|
|
# ------------------------------------------------------------------
|
|
def _compose_guidance(
|
|
self,
|
|
summary: str,
|
|
severity: str,
|
|
participants: Sequence[str],
|
|
positions: Sequence[str],
|
|
) -> str:
|
|
participant_line = (
|
|
", ".join(participants)
|
|
if participants
|
|
else "the involved parties"
|
|
)
|
|
severity_label = severity if severity not in {"", "unknown"} else "balanced"
|
|
principle = self.charter.core_principle or "Hold space for each voice."
|
|
directive = self.charter.directives[0] if self.charter.directives else "Seek mutual understanding before deciding."
|
|
position_clause = "; ".join(positions)
|
|
guidance_parts = [
|
|
f"Mediator notes a {severity_label} tension: {summary}.",
|
|
f"{participant_line} each hold part of the truth.",
|
|
principle,
|
|
]
|
|
if position_clause:
|
|
guidance_parts.append(f"Recognized positions: {position_clause}.")
|
|
guidance_parts.append(f"Suggested next step: {directive}")
|
|
if severity in {"critical", "high"}:
|
|
guidance_parts.append("Schedule a facilitated review with Guardian oversight.")
|
|
else:
|
|
guidance_parts.append("Log reflections from each side after cooling off.")
|
|
return " ".join(guidance_parts)
|
|
|
|
# ------------------------------------------------------------------
|
|
def _format_summary(self, record: MediationRecord) -> str:
|
|
lines = [
|
|
f"## {record.timestamp} • {record.severity.title()} tension",
|
|
f"Source topic: {record.source_topic}",
|
|
f"Summary: {record.summary}",
|
|
]
|
|
if record.participants:
|
|
lines.append("Participants: " + ", ".join(record.participants))
|
|
if record.positions:
|
|
lines.append("Positions:")
|
|
for position in record.positions:
|
|
lines.append(f"- {position}")
|
|
lines.append("Guidance: " + textwrap.fill(record.guidance, width=92))
|
|
lines.append("Status: " + record.status)
|
|
return "\n".join(lines)
|
|
|
|
# ------------------------------------------------------------------
|
|
def _now(self) -> str:
|
|
return (
|
|
datetime.now(timezone.utc)
|
|
.isoformat(timespec="seconds")
|
|
.replace("+00:00", "Z")
|
|
)
|
|
|
|
# ------------------------------------------------------------------
|
|
def run_forever(self, poll_interval: float = 1.0) -> None:
|
|
try:
|
|
while True:
|
|
time.sleep(poll_interval)
|
|
except KeyboardInterrupt: # pragma: no cover - manual stop
|
|
LOGGER.info("Mediator shutting down")
|
|
|
|
|
|
def _parse_args(argv: Optional[Sequence[str]] = None) -> argparse.Namespace:
|
|
parser = argparse.ArgumentParser(description="Run the Codex-10 Mediator agent")
|
|
parser.add_argument(
|
|
"--seed",
|
|
type=Path,
|
|
default=None,
|
|
help="Path to the Codex charter YAML (e.g. codex10.yaml)",
|
|
)
|
|
parser.add_argument(
|
|
"--emit",
|
|
type=Path,
|
|
default=None,
|
|
help="Directory to emit mediator prompt snippets",
|
|
)
|
|
parser.add_argument(
|
|
"--state-dir",
|
|
type=Path,
|
|
default=DEFAULT_STATE_DIR,
|
|
help="Directory for mediator state files",
|
|
)
|
|
parser.add_argument(
|
|
"--no-bus",
|
|
action="store_true",
|
|
help="Initialize without registering to the Reflex bus",
|
|
)
|
|
return parser.parse_args(argv)
|
|
|
|
|
|
def main(argv: Optional[Sequence[str]] = None) -> None:
|
|
args = _parse_args(argv)
|
|
charter = MediatorCharter.from_yaml(args.seed)
|
|
mediator = Mediator(
|
|
charter=charter,
|
|
state_dir=args.state_dir,
|
|
emit_dir=args.emit if args.emit is not None else DEFAULT_EMIT_DIR,
|
|
auto_emit=not args.no_bus,
|
|
)
|
|
if not args.no_bus:
|
|
mediator.register()
|
|
start_reflex()
|
|
mediator.run_forever()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|