multi-agent-lab / src /core /projections.py
agharsallah
feat: implement Archive feature for past session management
a2ca0e0
Raw
History Blame Contribute Delete
2.38 kB
from __future__ import annotations
from dataclasses import dataclass, field
from src import observability as obs
from src.core.events import Event
@dataclass
class StageProjection:
seed: str = ""
goal: str = ""
current_scene: str = "The curtain has not risen."
agent_notes: list[str] = field(default_factory=list)
judge_notes: list[str] = field(default_factory=list)
user_artifacts: list[str] = field(default_factory=list)
def apply(self, event: Event) -> None:
obs.log("projection.apply", level="debug", kind=event.kind, actor=event.actor, turn=event.turn)
if event.kind == "run.started":
self.seed = str(event.payload["seed"])
self.goal = str(event.payload.get("goal", "")) or self.goal
self.current_scene = f"The wood wakes around: {self.seed}"
elif event.kind == "world.observed":
self.current_scene = str(event.payload["text"])
elif event.kind == "agent.reflected":
self.agent_notes.append(f"💭 {event.actor} believes: {event.payload.get('text', '')}")
self.agent_notes = self.agent_notes[-8:]
elif event.kind in {"agent.thought", "agent.spoke"}:
self.agent_notes.append(f"{event.actor}: {event.payload['text']}")
self.agent_notes = self.agent_notes[-8:]
elif event.kind == "judge.verdict":
self.judge_notes.append(str(event.payload["text"]))
self.judge_notes = self.judge_notes[-5:]
elif event.kind == "user.injected":
self.user_artifacts.append(str(event.payload["text"]))
self.user_artifacts = self.user_artifacts[-5:]
elif "text" in event.payload:
# Generic fallback: any drop-in agent that mints its own namespaced
# kind (e.g. "clue.found", "oracle.spoke") still renders on stage with
# zero engine edits, as long as it carries a `text` payload.
self.agent_notes.append(f"{event.actor} [{event.kind}]: {event.payload['text']}")
self.agent_notes = self.agent_notes[-8:]
def rebuild_stage(events: tuple[Event, ...], run_id: str | None = None) -> StageProjection:
projection = StageProjection()
if run_id is not None:
events = tuple(e for e in events if e.run_id == run_id)
for event in events:
projection.apply(event)
return projection