Spaces:
Sleeping
Sleeping
| """Dream environments (Mission skins) + externalized world-state. | |
| The world-state lives HERE, outside the models β small models can't hold a long | |
| coherent context, so the fleet keeps the source of truth and feeds slices to each | |
| agent. Add a new environment by appending to ENVIRONMENTS; the engine is generic. | |
| DAYDREAM β Press Your Luck, Keep Your Tiger: | |
| the state also owns the *game* β LUCIDITY (a draining clock), COURAGE (Hobbes' | |
| bond meter), MENACE (the Nightmare's pressure), and a code-owned TIER_TABLE that | |
| fixes the risk/reward math. Models never decide outcomes; code does. | |
| """ | |
| from __future__ import annotations | |
| from dataclasses import dataclass, field | |
| class Environment: | |
| id: str | |
| name: str | |
| emoji: str | |
| opening: str # scene the dreamer wakes into | |
| mission: str # the soft goal (ignorable β wandering is fine) | |
| start_location: str | |
| inhabitant: str # one-line persona seed for the local NPC voice | |
| visual: str = "" # art-direction seed for the dream-image model (vision.py) | |
| ENVIRONMENTS: dict[str, Environment] = { | |
| "candy_desert": Environment( | |
| "candy_desert", "The Candy Desert", "π", | |
| "Two pale moons hang over endless dunes of crystalline sugar. Something hums beneath the sand.", | |
| "Find what is humming under the dunes β or don't, and just wander.", | |
| "a ridge of warm sugar-glass", | |
| "a nervous gummy bear who knows too much and trusts too little", | |
| "a surreal candy desert under two pale moons, endless dunes of translucent " | |
| "crystalline sugar-glass, soft pastel pinks lilacs and mint, spun-sugar haze", | |
| ), | |
| "sunken_city": Environment( | |
| "sunken_city", "The Sunken City", "π", | |
| "You breathe water like air. Drowned bell-towers lean in the blue dark, trying to ring.", | |
| "Find the song the bells are reaching for.", | |
| "the steps of a flooded cathedral", | |
| "an old eel who used to be the city's bellringer", | |
| "a drowned dreamlike city deep underwater, leaning bell-towers and flooded " | |
| "cathedrals in deep teal gloom, drifting silt, pale godrays of light", | |
| ), | |
| "noir_alley": Environment( | |
| "noir_alley", "Rain Street", "π΅οΈ", | |
| "Neon bleeds into wet asphalt. Somebody stole the moon, and the whole city's gone dim.", | |
| "Find out who took the moon.", | |
| "under a flickering sign that says OPEN, lying", | |
| "a trench-coated cat informant who speaks only in riddles and prices", | |
| "a rain-soaked neon noir alley at night, wet asphalt mirroring magenta and " | |
| "cyan signs, deep shadows, fog, a conspicuously moonless dim sky", | |
| ), | |
| "red_planet": Environment( | |
| "red_planet", "The Red Planet", "π", | |
| "Rust-colored wind. Your tin rocket ticks as it cools. Something tall watches from the dunes.", | |
| "Get the rocket flying again before the tall thing reaches you.", | |
| "beside a cooling tin rocket", | |
| "a polite but very hungry zorch that insists it just wants to talk", | |
| "a rust-red dream planet, a small retro tin rocket cooling on ochre dunes, " | |
| "a tall watching silhouette on the horizon, dusty wind, two faint moons", | |
| ), | |
| "token_wood": Environment( | |
| "token_wood", "Thousand Token Wood", "π²", | |
| "A wood where every leaf is a word. Step wrong and the sentence changes around you.", | |
| "Reach the clearing where the wood is trying to finish a thought.", | |
| "at the wood's whispering edge", | |
| "a small fox made of footnotes who narrates itself", | |
| "an enchanted misty wood where every leaf is printed text and words, pages " | |
| "and letters as foliage, soft diffuse light, gentle storybook surrealism", | |
| ), | |
| } | |
| # --- The game's spine: CODE owns this, never the model --------------------- | |
| # Each gambit tier fixes its own risk/reward. resolver.py reads these; the | |
| # personality models only ever pick the *words* on the buttons, never the math. | |
| # Tuned for a tense-but-winnable ~3-min arc (8-12 turns). Each tier is a real | |
| # choice: safe is the patient grind (10/turn clears 100 well within a run), | |
| # reckless is a genuine gamble for speed β risky, not a death sentence. | |
| # Tuned so a balanced run lasts ~8-12 turns (long enough to live the 5-beat story | |
| # arc), reckless is a real gamble (fast but can lose), and safe is the patient, | |
| # low-drama grind. Progress always advances (see resolver); these set the pace. | |
| TIER_TABLE: dict[str, dict[str, int | float]] = { | |
| "safe": {"lucidity_cost": 1, "progress_reward": 9, "courage_gain": 0, | |
| "fail_chance": 0.05, "menace_delta": 0}, | |
| "bold": {"lucidity_cost": 2, "progress_reward": 15, "courage_gain": 1, | |
| "fail_chance": 0.25, "menace_delta": 1}, | |
| "reckless": {"lucidity_cost": 4, "progress_reward": 26, "courage_gain": 2, | |
| "fail_chance": 0.40, "menace_delta": 1}, | |
| } | |
| TIERS = ("safe", "bold", "reckless") | |
| LUCIDITY_START = 20 | |
| MENACE_THRESHOLD = 5 # at/above this, the Nightmare forces a Flee-or-Face beat | |
| COURAGE_MAX = 6 | |
| def courage_tier(courage: int) -> str: | |
| """Maps the COURAGE meter to Hobbes' mood β drives his system-prompt slice.""" | |
| if courage <= 1: | |
| return "timid" # cowering, joke-deflecting, begs you off the red button | |
| if courage <= 3: | |
| return "warming" # nervous but rallying | |
| return "brave" # loyal, steady: "do it, I've got you" | |
| class WorldState: | |
| env_id: str | |
| env_name: str | |
| emoji: str | |
| location: str | |
| mission: str | |
| inhabitant: str | |
| seed: str = "dream" | |
| inventory: list[str] = field(default_factory=list) | |
| log: list[str] = field(default_factory=list) # short memory of key beats | |
| scars: list[str] = field(default_factory=list) # failed-gamble marks (card flavor) | |
| progress: int = 0 # soft 0..100 -> WAKE WITH THE PRIZE | |
| lucidity: int = LUCIDITY_START # 0 -> LOST IN THE DREAM | |
| courage: int = 0 # Hobbes' bond, 0..COURAGE_MAX | |
| menace: int = 0 # the Nightmare's pressure | |
| peak_menace: int = 0 # high-water mark (card flavor) | |
| turn: int = 0 | |
| complete: bool = False # won | |
| lost: bool = False # lucidity ran out | |
| def from_env(cls, env: Environment, seed: str = "dream") -> "WorldState": | |
| return cls(env_id=env.id, env_name=env.name, emoji=env.emoji, | |
| location=env.start_location, mission=env.mission, | |
| inhabitant=env.inhabitant, seed=seed) | |
| # --- derived --- | |
| def over(self) -> bool: | |
| return self.complete or self.lost | |
| def mood(self) -> str: | |
| return courage_tier(self.courage) | |
| def nightmare_near(self) -> bool: | |
| return self.menace >= MENACE_THRESHOLD | |
| def context(self) -> str: | |
| """A compact slice of truth handed to each agent every turn.""" | |
| recent = " | ".join(self.log[-4:]) if self.log else "(nothing yet)" | |
| carry = ", ".join(self.inventory) if self.inventory else "nothing" | |
| return (f"WORLD: {self.env_name}. LOCATION: {self.location}. " | |
| f"MISSION: {self.mission} (progress {self.progress}%). " | |
| f"LUCIDITY: {self.lucidity}/{LUCIDITY_START}. " | |
| f"HOBBES_COURAGE: {self.courage} ({self.mood}). " | |
| f"MENACE: {self.menace}{' (NIGHTMARE CLOSE)' if self.nightmare_near else ''}. " | |
| f"CARRYING: {carry}. RECENT BEATS: {recent}.") | |