the-echo / echo /agents /verifier.py
frankyy03's picture
Deploy The Echo (MockLLM path): Gradio app + echo package
897d5bd verified
"""
echo/agents/verifier.py
-----------------------
The Verifier checks a freshly-grown child WorldState against its branch history
for contradictions (impossible age math, relationships that vanished, a dead
parent reappearing, location/era inconsistencies). If it fails, the orchestrator
regenerates.
This cheap consistency loop is the polish that turns "plausible chatbot output"
into "how is it keeping all of this straight?" — the technical aha. It also
provides the metric for the Tiny Titan experiment: regeneration rate by model
size.
"""
from __future__ import annotations
from dataclasses import dataclass
from .base import Agent
from ..core.world_state import WorldState
@dataclass
class VerdictResult:
consistent: bool
reason: str = ""
class Verifier(Agent):
SYSTEM = (
"You are the Verifier. You audit a newly written life-state against the "
"established history of its branch and decide if it is consistent. Flag "
"a contradiction only when something genuinely breaks: age that doesn't "
"match the years elapsed, a relationship or dependent that appears or "
"vanishes with no cause, a carried loss silently erased, or a "
"location/era that's impossible. Do NOT flag a change that the choice "
"taken and the passing years plausibly explain — growth, moves, new "
"love, and healing are allowed. Be strict about broken facts, generous "
"about "
"plausible change. Respond ONLY as JSON: "
'{"consistent": true/false, "reason": "<short; name the specific '
'contradiction>"}.'
)
def check(self, child: WorldState, parent: WorldState,
branch_narrative: str) -> VerdictResult:
# 1) cheap deterministic checks first (no LLM needed)
hard = self._hard_checks(child, parent)
if hard is not None:
return hard
# 2) soft semantic check via LLM
user = (
f"BRANCH HISTORY:\n{branch_narrative}\n\n"
f"PARENT: {parent.facts.constraints_text()}\n"
f"NEW STATE: {child.facts.constraints_text()}\n"
f"CHOICE TAKEN: {child.divergence} (+{child.years_elapsed}y)\n\n"
"Is the NEW STATE consistent with everything above?"
)
data = self._complete_json(user)
return VerdictResult(
consistent=bool(data.get("consistent", True)),
reason=str(data.get("reason", "")),
)
def _hard_checks(self, child: WorldState, parent: WorldState):
"""Deterministic guards that never need a model."""
expected_age = parent.facts.age + child.years_elapsed
if abs(child.facts.age - expected_age) > 1:
return VerdictResult(False,
f"age {child.facts.age} != expected {expected_age}")
if child.years_elapsed < 0:
return VerdictResult(False, "negative time")
# a carried scar from the parent should not silently disappear if it was
# a permanent loss (heuristic: parent dependents shouldn't vanish)
for dep in parent.facts.dependents:
# children don't un-exist; allow them to grow but not disappear
base = dep.split(",")[0].strip().lower()
if base and not any(base in d.lower() for d in child.facts.dependents):
# not necessarily fatal (estrangement), so soft-flag only if
# the time elapsed is small
if child.years_elapsed <= 2:
return VerdictResult(False, f"dependent '{base}' vanished")
return None