Spaces:
Sleeping
Sleeping
| """ | |
| echo/core/world_state.py | |
| ------------------------ | |
| The persistent, structured memory of a single alternate life (one node in the | |
| tree). This is what makes "the same you" recognizable across branches: every | |
| new branch is generated as a *causal consequence* of its parent's WorldState, | |
| not invented from scratch. | |
| Pure data. No LLM, no I/O. The Curator agent reads a parent WorldState and | |
| writes a child; the Verifier checks a child against its parent using these | |
| fields. | |
| """ | |
| from __future__ import annotations | |
| from dataclasses import dataclass, field, asdict | |
| from typing import Optional | |
| import uuid | |
| class LifeFacts: | |
| """The concrete, checkable facts about this version of the person.""" | |
| age: int | |
| location: str # city / country right now | |
| occupation: str | |
| relationships: list[str] = field(default_factory=list) # e.g. "married to Sofia" | |
| dependents: list[str] = field(default_factory=list) # e.g. "daughter, 4" | |
| scars: list[str] = field(default_factory=list) # losses / regrets carried | |
| triumphs: list[str] = field(default_factory=list) # what went right | |
| possessions: list[str] = field(default_factory=list) # grounding mundane detail | |
| def constraints_text(self) -> str: | |
| """A compact statement of facts the next branch must NOT contradict.""" | |
| parts = [f"age {self.age}", f"in {self.location}", f"works as {self.occupation}"] | |
| if self.relationships: | |
| parts.append("relationships: " + "; ".join(self.relationships)) | |
| if self.dependents: | |
| parts.append("dependents: " + "; ".join(self.dependents)) | |
| if self.scars: | |
| parts.append("carries: " + "; ".join(self.scars)) | |
| return " | ".join(parts) | |
| class EmotionalTone: | |
| """Where this life sits emotionally — drives the gold/dark visual + voice.""" | |
| valence: float # -1.0 (devastated) .. +1.0 (thriving) | |
| dominant_feeling: str # e.g. "restless pride", "quiet grief" | |
| voice_hint: str = "" # guidance for TTS (pace, warmth, weariness) | |
| def is_flourishing(self) -> bool: | |
| return self.valence >= 0.25 | |
| def is_struggling(self) -> bool: | |
| return self.valence <= -0.25 | |
| class WorldState: | |
| """One node: a complete snapshot of an alternate life.""" | |
| node_id: str | |
| parent_id: Optional[str] | |
| depth: int | |
| # the choice that CREATED this branch (what diverged from the parent) | |
| divergence: str | |
| # how many years passed since the parent node | |
| years_elapsed: int | |
| facts: LifeFacts | |
| tone: EmotionalTone | |
| # a short second-person summary the UI shows ("You are 34, in Lisbon...") | |
| summary: str = "" | |
| # the spoken message this echo leaves (filled by the voice tool) | |
| voice_line: str = "" | |
| voice_audio_path: Optional[str] = None | |
| # the two planned next forks (filled by the Screenwriter) | |
| pending_forks: list[str] = field(default_factory=list) | |
| def to_dict(self) -> dict: | |
| return asdict(self) | |
| def new_id() -> str: | |
| return uuid.uuid4().hex[:8] | |
| def root_state(seed_choice: str, base_age: int = 30) -> WorldState: | |
| """ | |
| Create the minimal root before the Curator fills it. The Curator will | |
| overwrite facts/tone; this just establishes the tree's origin. | |
| """ | |
| return WorldState( | |
| node_id=WorldState.new_id(), | |
| parent_id=None, | |
| depth=0, | |
| divergence=seed_choice, | |
| years_elapsed=0, | |
| facts=LifeFacts(age=base_age, location="unknown", | |
| occupation="unknown"), | |
| tone=EmotionalTone(valence=0.0, dominant_feeling="uncertain"), | |
| ) |