multi-agent-lab / src /ui /render.py
agharsallah
Refactor code structure for improved readability and maintainability
5424fe6
Raw
History Blame Contribute Delete
3.55 kB
from __future__ import annotations
from collections import Counter
from src.core.events import Event, event_summary
from src.core.governor import Governor
from src.core.projections import StageProjection
from src.scenarios.base import Scenario
def render_stage(projection: StageProjection) -> str:
goal = f"> **Goal:** {projection.goal}\n\n" if projection.goal else ""
artifacts = "\n".join(f"- {item}" for item in projection.user_artifacts) or "- No visitor artifacts yet."
notes = "\n".join(f"- {item}" for item in projection.agent_notes) or "- Agents are waiting."
verdicts = "\n".join(f"- {item}" for item in projection.judge_notes) or "- No verdict yet."
return f"""## Current Clearing
{goal}{projection.current_scene}
### Visitor Disturbances
{artifacts}
### Agent Activity
{notes}
### Judge Notes
{verdicts}
"""
def render_event_log(events: tuple[Event, ...]) -> str:
if not events:
return "(ledger is empty)"
return "\n".join(event_summary(event) for event in events)
def render_stats(events: tuple[Event, ...], governor: Governor | None = None) -> str:
by_kind = Counter(event.kind for event in events)
by_actor = Counter(event.actor for event in events)
lines = ["Events by kind:"]
lines.extend(f" {key}: {value}" for key, value in sorted(by_kind.items()))
lines.append("")
lines.append("Events by actor:")
lines.extend(f" {key}: {value}" for key, value in sorted(by_actor.items()))
# Structured-output health: how often the parser had to fall back to raw text.
content = [e for e in events if e.actor not in ("conductor", "visitor")]
fallbacks = sum(1 for e in content if e.payload.get("_raw_fallback"))
if content:
lines.append("")
lines.append(f"Structured output: {len(content) - fallbacks}/{len(content)} clean JSON "
f"({fallbacks} raw fallback)")
lines.append("")
lines.append("Hackathon constraints:")
lines.append(" runtime model cap: <=32B")
lines.append(" tiny mode target: <=4B")
lines.append(" UI target: custom Gradio")
if governor is not None:
lines.append("")
lines.append("Governor:")
for k, v in governor.stats.items():
lines.append(f" {k}: {v}")
return "\n".join(lines)
def render_config(scenario: Scenario, profile_models: dict[str, str] | None = None) -> str:
"""The 'config as data' panel β€” the live, declarative makeup of the run.
Everything shown here comes from YAML (config/), not code: the cast that
participates, each agent's model tier, what it may emit, and its tool grants.
"""
rows = ["| agent | role | model | emits | tools |", "|---|---|---|---|---|"]
for agent in scenario.agents:
manifest = getattr(agent, "manifest", None)
if manifest is None:
rows.append(f"| {agent.name} | (legacy) | β€” | β€” | β€” |")
continue
emits = ", ".join(manifest.may_emit) or "β€”"
tools = ", ".join(manifest.tools) or "β€”"
rows.append(
f"| `{manifest.name}` | {manifest.role} | `{manifest.model_profile}` | {emits} | {tools} |"
)
table = "\n".join(rows)
profile_block = ""
if profile_models:
profile_lines = "\n".join(f"- `{p}` β†’ `{m}`" for p, m in profile_models.items())
profile_block = f"\n\n**Model profiles**\n{profile_lines}"
goal = f"\n\n**Goal**\n{scenario.goal}" if scenario.goal else ""
return f"### Cast (from `config/`)\n\n{table}{profile_block}{goal}"