agent-parkour / app /app.py
anngo-1's picture
Deploy Agent Parkour app
386f43a verified
Raw
History Blame Contribute Delete
125 kB
from __future__ import annotations
import hashlib
import json
import os
import queue
import re
import sys
import threading
import time
import traceback
import urllib.error
import urllib.request
from dataclasses import replace
from pathlib import Path
from typing import Any, Callable
# Make the project root importable so the Space reuses the exact runner stack.
ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT))
import torch
from fastapi import Request
from fastapi.responses import FileResponse, JSONResponse, StreamingResponse
from gradio import Server
from config import V2Config
from env import FastFloatingBeaconEnv
from infer import load_model, planner_mode_for_state
from mapgen import configure_motif_mapgen, install_motif_mapgen
from replay import plain, write_json
from runtime import resolve_device, sync_device
from settings import ACTIVE_CHECKPOINT, ENV_DEFAULTS, MAPGEN_KWARGS, PHYSICS_DEFAULTS
app = Server()
try:
import spaces
except Exception:
class _SpacesFallback:
@staticmethod
def GPU(*decorator_args: Any, **_decorator_kwargs: Any) -> Callable[[Callable[..., Any]], Callable[..., Any]] | Callable[..., Any]:
if decorator_args and callable(decorator_args[0]):
return decorator_args[0]
def decorator(fn: Callable[..., Any]) -> Callable[..., Any]:
return fn
return decorator
spaces = _SpacesFallback()
def _load_env_file(path: Path) -> None:
try:
lines = path.read_text(encoding="utf-8").splitlines()
except FileNotFoundError:
return
except OSError:
return
for raw_line in lines:
line = raw_line.strip()
if not line or line.startswith("#") or "=" not in line:
continue
key, value = line.split("=", 1)
key = key.strip()
if not key or key in os.environ:
continue
value = value.strip()
if len(value) >= 2 and value[0] == value[-1] and value[0] in {"'", '"'}:
value = value[1:-1]
os.environ[key] = value
_load_env_file(ROOT / ".env")
CHECKPOINT_PATH = ROOT / os.environ.get("PARKOUR_CHECKPOINT", ACTIVE_CHECKPOINT)
DEVICE_NAME = os.environ.get("PARKOUR_DEVICE", "auto")
TRIAL_DIR = Path(__file__).resolve().parent / "trials"
TRIAL_DIR.mkdir(parents=True, exist_ok=True)
MAPS_DIR = Path(__file__).resolve().parent / "maps"
MAPS_DIR.mkdir(parents=True, exist_ok=True)
SAVED_MAPS_DIR = Path(__file__).resolve().parent / "saved_maps"
SAVED_MAPS_DIR.mkdir(parents=True, exist_ok=True)
SAVED_MAPS_CURATED_DIR = SAVED_MAPS_DIR / "curated"
SAVED_MAPS_CURATED_DIR.mkdir(parents=True, exist_ok=True)
APP_MAPGEN_VERSION = "vibe_params_sparse_long_v4"
APP_MAPGEN_LLM_LABEL = "LLM vibe knobs"
_lock = threading.Lock()
_model_cache: dict[str, Any] = {}
_trial_cache: dict[str, dict[str, Any]] = {}
_maps_cache: dict[str, dict[str, Any]] = {}
_saved_maps_cache: dict[str, dict[str, Any]] = {}
DIFFICULTIES: dict[str, dict[str, Any]] = {
"rookie": {
"route_jumps": 6,
"distractors": 3,
"attempts": 40,
"retries": 1,
"max_steps_factor": 18.0,
"label": "Rookie",
},
"standard": {
"route_jumps": 9,
"distractors": 6,
"attempts": 80,
"retries": 2,
"max_steps_factor": 20.0,
"label": "Standard",
},
"cursed": {
"route_jumps": 15,
"distractors": 8,
"attempts": 96,
"retries": 3,
"max_steps_factor": 23.0,
"label": "Cursed",
},
"nightmare": {
"route_jumps": 24,
"distractors": 20,
"attempts": 96,
"retries": 4,
"max_steps_factor": 24.0,
"label": "Nightmare",
},
}
LLM_DIRECT_BASE_SPEC: dict[str, Any] = {
"key": "llm_direct",
"label": "LLM",
"route_jumps": 10,
"distractors": 8,
"attempts": 128,
"retries": 1,
}
KNOB_DEFAULTS: dict[str, float] = {
"verticality": 0.40,
"traps": 0.20,
"loopiness": 0.24,
"precision": 0.24,
"length": 0.42,
"jump_gap": 0.40,
"platform_size": 0.58,
"decoys": 0.16,
"elevation_scale": 0.40,
"turniness": 0.32,
"tiny_platforms": 0.14,
"large_platforms": 0.30,
"unintuitive": 0.18,
}
DIFFICULTY_KNOB_FLOORS: dict[str, dict[str, float]] = {
"cursed": {
"verticality": 0.76,
"traps": 0.84,
"loopiness": 0.78,
"precision": 0.60,
"length": 0.78,
"jump_gap": 0.80,
"decoys": 0.70,
"elevation_scale": 0.78,
"turniness": 0.82,
"tiny_platforms": 0.58,
"unintuitive": 0.84,
},
"nightmare": {
"verticality": 0.92,
"traps": 0.98,
"loopiness": 0.94,
"precision": 0.76,
"length": 0.92,
"jump_gap": 0.96,
"decoys": 0.90,
"elevation_scale": 0.92,
"turniness": 0.96,
"tiny_platforms": 0.74,
"unintuitive": 0.98,
},
}
DIFFICULTY_KNOB_CAPS: dict[str, dict[str, float]] = {
"rookie": {
"traps": 0.34,
"loopiness": 0.38,
"precision": 0.38,
"jump_gap": 0.52,
"tiny_platforms": 0.34,
"unintuitive": 0.34,
},
"standard": {
"traps": 0.62,
"loopiness": 0.58,
"precision": 0.52,
"jump_gap": 0.64,
"tiny_platforms": 0.48,
"unintuitive": 0.54,
},
"cursed": {
"platform_size": 0.24,
"large_platforms": 0.14,
},
"nightmare": {
"platform_size": 0.12,
"large_platforms": 0.06,
},
}
def _device() -> torch.device:
return resolve_device(DEVICE_NAME)
def _load_checkpoint() -> tuple[dict[str, Any], Any, torch.nn.Module]:
key = f"{CHECKPOINT_PATH}:{_device()}"
cached = _model_cache.get(key)
if cached is not None:
return cached
if not CHECKPOINT_PATH.exists():
raise FileNotFoundError(f"checkpoint missing: {CHECKPOINT_PATH}")
checkpoint = torch.load(CHECKPOINT_PATH, map_location="cpu", weights_only=False)
base_cfg = checkpoint.get("stage_config") or checkpoint["config"]
cfg = replace(base_cfg, device=str(_device()))
configure_motif_mapgen(**MAPGEN_KWARGS)
install_motif_mapgen()
model = load_model(checkpoint, cfg, depth=3)
model.eval()
cached = (checkpoint, cfg, model)
_model_cache[key] = cached
return cached
def _difficulty_spec(difficulty: str) -> dict[str, Any]:
key = str(difficulty or "standard").strip().lower()
return {**DIFFICULTIES.get(key, DIFFICULTIES["standard"]), "key": key if key in DIFFICULTIES else "standard"}
def _llm_direct_spec(knobs: dict[str, float]) -> dict[str, Any]:
length = float(knobs["length"])
decoys = float(knobs["decoys"])
traps = float(knobs["traps"])
precision = float(knobs["precision"])
turniness = float(knobs["turniness"])
jump_gap = float(knobs["jump_gap"])
tiny_platforms = float(knobs["tiny_platforms"])
unintuitive = float(knobs["unintuitive"])
route_jumps = 6 + int(round(length * 3.0 + jump_gap * 1.0 + turniness * 1.0 + precision * 1.0))
distractors = 3 + int(round(decoys * 3.0 + traps * 2.0 + unintuitive * 1.0 + tiny_platforms * 1.0))
attempts = 96 + int(round((length + decoys + traps + jump_gap + unintuitive) * 18.0))
route_jumps = min(route_jumps, 9)
distractors = min(distractors, 6)
total_platforms = route_jumps + 1 + distractors
if total_platforms > 15:
distractors = max(2, 15 - (route_jumps + 1))
total_platforms = route_jumps + 1 + distractors
if total_platforms > 15:
route_jumps = max(5, 15 - distractors - 1)
return {
**LLM_DIRECT_BASE_SPEC,
"route_jumps": int(route_jumps),
"distractors": int(distractors),
"attempts": min(attempts, 160),
}
def _clamp01(value: float | int | None, default: float) -> float:
try:
number = float(value)
except (TypeError, ValueError):
number = float(default)
return max(0.0, min(1.0, number))
def _knobs(
verticality: float | int | None = None,
traps: float | int | None = None,
loopiness: float | int | None = None,
precision: float | int | None = None,
length: float | int | None = None,
jump_gap: float | int | None = None,
platform_size: float | int | None = None,
decoys: float | int | None = None,
elevation_scale: float | int | None = None,
turniness: float | int | None = None,
tiny_platforms: float | int | None = None,
large_platforms: float | int | None = None,
unintuitive: float | int | None = None,
) -> dict[str, float]:
return {
"verticality": _clamp01(verticality, KNOB_DEFAULTS["verticality"]),
"traps": _clamp01(traps, KNOB_DEFAULTS["traps"]),
"loopiness": _clamp01(loopiness, KNOB_DEFAULTS["loopiness"]),
"precision": _clamp01(precision, KNOB_DEFAULTS["precision"]),
"length": _clamp01(length, KNOB_DEFAULTS["length"]),
"jump_gap": _clamp01(jump_gap, KNOB_DEFAULTS["jump_gap"]),
"platform_size": _clamp01(platform_size, KNOB_DEFAULTS["platform_size"]),
"decoys": _clamp01(decoys, KNOB_DEFAULTS["decoys"]),
"elevation_scale": _clamp01(elevation_scale, KNOB_DEFAULTS["elevation_scale"]),
"turniness": _clamp01(turniness, KNOB_DEFAULTS["turniness"]),
"tiny_platforms": _clamp01(tiny_platforms, KNOB_DEFAULTS["tiny_platforms"]),
"large_platforms": _clamp01(large_platforms, KNOB_DEFAULTS["large_platforms"]),
"unintuitive": _clamp01(unintuitive, KNOB_DEFAULTS["unintuitive"]),
}
def _difficulty_knobs(difficulty_key: str, knobs: dict[str, float]) -> dict[str, float]:
key = str(difficulty_key or "standard").strip().lower()
tuned = dict(knobs)
for name, floor in DIFFICULTY_KNOB_FLOORS.get(key, {}).items():
tuned[name] = max(float(tuned.get(name, 0.0)), float(floor))
for name, cap in DIFFICULTY_KNOB_CAPS.get(key, {}).items():
tuned[name] = min(float(tuned.get(name, 1.0)), float(cap))
return tuned
def _difficulty_pressure(difficulty_key: str) -> float:
return {
"rookie": 0.0,
"standard": 0.25,
"cursed": 0.74,
"nightmare": 1.0,
}.get(str(difficulty_key or "standard").strip().lower(), 0.25)
def _direct_vibe(vibe: str, difficulty_key: str, knobs: dict[str, float] | None = None) -> dict[str, Any]:
"""Convert a free-form vibe string into a vibe plan.
The plan's `params` only contains keys the heuristic is willing to set.
`_build_vibe_plan` merges it on top of MAPGEN_KWARGS, so the heuristic can
push some params higher (or cap them lower for "smooth" vibes) but never
silently erase the strong MAPGEN_KWARGS defaults.
"""
text = str(vibe or "").lower()
knobs = knobs or _knobs()
params: dict[str, float | int] = {}
caps: dict[str, float] = {}
tags: list[str] = []
theme = "misty wood ruins"
mood = "cool teal fog"
if any(word in text for word in ("vertical", "tower", "climb", "mountain", "summit", "upward", "uphill")):
tags.append("vertical")
params["map_goal_vertical_bias"] = 0.45 if difficulty_key in ("cursed", "nightmare") else 0.30
params["map_false_summit_fraction"] = max(float(MAPGEN_KWARGS.get("map_false_summit_fraction", 0.14)), 0.08)
theme = "vertical ruin stacks"
if any(word in text for word in ("trap", "fake", "bait", "cursed", "evil", "dead end", "deceptive")):
tags.append("trap-heavy")
params["map_trap_jump_fraction"] = max(float(MAPGEN_KWARGS.get("map_trap_jump_fraction", 0.40)), 0.40)
params["map_trap_jump_high_fraction"] = max(float(MAPGEN_KWARGS.get("map_trap_jump_high_fraction", 0.20)), 0.20)
params["map_greedy_trap_fraction"] = max(float(MAPGEN_KWARGS.get("map_greedy_trap_fraction", 0.22)), 0.22)
params["map_false_finish_fraction"] = max(float(MAPGEN_KWARGS.get("map_false_finish_fraction", 0.16)), 0.16)
params["map_false_branch_fraction"] = max(float(MAPGEN_KWARGS.get("map_false_branch_fraction", 0.20)), 0.20)
mood = "red warning haze"
if any(word in text for word in ("loop", "spiral", "maze", "wrong way", "detour", "confusing")):
tags.append("loopback")
params["map_route_detour_period"] = min(int(MAPGEN_KWARGS.get("map_route_detour_period", 4)), 5)
params["map_route_detour_depth"] = max(float(MAPGEN_KWARGS.get("map_route_detour_depth", 0.58)), 0.58)
params["map_unintuitive_depth"] = max(float(MAPGEN_KWARGS.get("map_unintuitive_depth", 0.56)), 0.56)
params["map_backtrack_period"] = min(int(MAPGEN_KWARGS.get("map_backtrack_period", 5)), 6)
params["map_backtrack_depth"] = max(float(MAPGEN_KWARGS.get("map_backtrack_depth", 0.42)), 0.55)
params["map_hairpin_period"] = min(int(MAPGEN_KWARGS.get("map_hairpin_period", 7)), 5)
params["map_hairpin_depth"] = max(float(MAPGEN_KWARGS.get("map_hairpin_depth", 0.48)), 0.55)
theme = "loopback floating garden"
if any(word in text for word in ("tiny", "needle", "precision", "small", "narrow")):
tags.append("precision")
params["map_platform_tiny_fraction"] = max(float(MAPGEN_KWARGS.get("map_platform_tiny_fraction", 0.18)), 0.30)
params["map_route_tiny_fraction"] = max(float(MAPGEN_KWARGS.get("map_route_tiny_fraction", 0.10)), 0.18)
params["map_platform_min_scale"] = min(float(MAPGEN_KWARGS.get("map_platform_min_scale", 0.52)), 0.46)
params["map_edge_gap_min"] = max(float(MAPGEN_KWARGS.get("map_edge_gap_min", 0.95)), 1.05)
if any(word in text for word in ("wide", "chill", "easy", "smooth", "flow", "forgiving")):
tags.append("flow")
caps["map_trap_jump_fraction"] = 0.07 if difficulty_key == "rookie" else 0.10
caps["map_trap_jump_high_fraction"] = 0.03
caps["map_greedy_trap_fraction"] = 0.04
caps["map_false_finish_fraction"] = 0.04
caps["map_false_branch_fraction"] = 0.04
caps["map_route_detour_depth"] = 0.10
caps["map_hairpin_depth"] = 0.10
caps["map_backtrack_depth"] = 0.10
params["map_platform_large_fraction"] = max(float(MAPGEN_KWARGS.get("map_platform_large_fraction", 0.18)), 0.28)
params["map_platform_min_scale"] = max(float(MAPGEN_KWARGS.get("map_platform_min_scale", 0.52)), 0.66)
mood = "soft open air"
if any(word in text for word in ("hairpin", "switchback")):
params["map_hairpin_period"] = min(int(MAPGEN_KWARGS.get("map_hairpin_period", 7)), 5)
params["map_hairpin_angle"] = max(float(MAPGEN_KWARGS.get("map_hairpin_angle", 1.24)), 1.35)
params["map_hairpin_depth"] = max(float(MAPGEN_KWARGS.get("map_hairpin_depth", 0.48)), 0.65)
if any(word in text for word in ("backtrack", "backtracking", "return path")):
params["map_backtrack_period"] = min(int(MAPGEN_KWARGS.get("map_backtrack_period", 5)), 5)
params["map_backtrack_depth"] = max(float(MAPGEN_KWARGS.get("map_backtrack_depth", 0.42)), 0.65)
if any(word in text for word in ("valley", "dip", "drop first")):
params["map_valley_period"] = min(int(MAPGEN_KWARGS.get("map_valley_period", 5)), 6)
params["map_valley_depth"] = max(float(MAPGEN_KWARGS.get("map_valley_depth", 0.58)), 0.70)
if any(word in text for word in ("long", "marathon", "extended")):
params["map_goal_xy_min"] = max(float(MAPGEN_KWARGS.get("map_goal_xy_min", 28.0)), 40.0)
params["map_goal_xy_per_jump_min"] = max(float(MAPGEN_KWARGS.get("map_goal_xy_per_jump_min", 1.90)), 2.6)
if any(word in text for word in ("short", "quick", "compact")):
params["map_goal_xy_min"] = min(float(MAPGEN_KWARGS.get("map_goal_xy_min", 28.0)), 14.0)
params["map_goal_xy_per_jump_min"] = min(float(MAPGEN_KWARGS.get("map_goal_xy_per_jump_min", 1.90)), 1.0)
verticality = knobs["verticality"]
traps = knobs["traps"]
loopiness = knobs["loopiness"]
precision = knobs["precision"]
length = knobs["length"]
jump_gap = knobs["jump_gap"]
platform_size = knobs["platform_size"]
decoys = knobs["decoys"]
elevation_scale = knobs["elevation_scale"]
turniness = knobs["turniness"]
tiny_platforms = knobs["tiny_platforms"]
large_platforms = knobs["large_platforms"]
unintuitive = knobs["unintuitive"]
pressure = _difficulty_pressure(difficulty_key)
size_pressure = 1.0 - platform_size
params["map_route_gap_scale"] = max(float(params.get("map_route_gap_scale", MAPGEN_KWARGS.get("map_route_gap_scale", 1.0))), 0.92 + 0.58 * jump_gap + 0.20 * pressure)
params["map_edge_gap_min"] = max(float(params.get("map_edge_gap_min", MAPGEN_KWARGS.get("map_edge_gap_min", 0.95))), 0.76 + 0.48 * jump_gap + 0.18 * precision + 0.12 * pressure)
params["map_edge_gap_max"] = max(float(params.get("map_edge_gap_max", MAPGEN_KWARGS.get("map_edge_gap_max", 1.58))), 1.12 + 0.72 * jump_gap + 0.22 * precision + 0.18 * pressure)
params["map_route_edge_gap_floor"] = max(float(params.get("map_route_edge_gap_floor", MAPGEN_KWARGS.get("map_route_edge_gap_floor", 0.38))), 0.34 + 0.22 * pressure)
params["map_goal_xy_min"] = max(float(params.get("map_goal_xy_min", MAPGEN_KWARGS.get("map_goal_xy_min", 28.0))), 12.0 + 30.0 * length + 10.0 * jump_gap + 24.0 * pressure)
params["map_goal_xy_per_jump_min"] = max(float(params.get("map_goal_xy_per_jump_min", MAPGEN_KWARGS.get("map_goal_xy_per_jump_min", 1.90))), 0.65 + 2.35 * jump_gap + 0.35 * pressure)
params["map_direct_decoy_fraction"] = max(float(params.get("map_direct_decoy_fraction", MAPGEN_KWARGS.get("map_direct_decoy_fraction", 0.08))), 0.04 + 0.20 * decoys + 0.08 * pressure)
params["map_cluster_extra_fraction"] = max(float(params.get("map_cluster_extra_fraction", MAPGEN_KWARGS.get("map_cluster_extra_fraction", 0.10))), 0.04 + 0.22 * decoys + 0.08 * pressure)
params["map_decoy_corridor_fraction"] = max(float(params.get("map_decoy_corridor_fraction", MAPGEN_KWARGS.get("map_decoy_corridor_fraction", 0.06))), 0.03 + 0.20 * decoys + 0.08 * pressure)
params["map_false_branch_fraction"] = max(float(params.get("map_false_branch_fraction", MAPGEN_KWARGS.get("map_false_branch_fraction", 0.20))), 0.03 + 0.28 * decoys + 0.14 * unintuitive + 0.14 * pressure)
params["map_false_finish_fraction"] = max(float(params.get("map_false_finish_fraction", MAPGEN_KWARGS.get("map_false_finish_fraction", 0.16))), 0.02 + 0.18 * decoys + 0.14 * unintuitive + 0.12 * pressure)
params["map_braid_bridge_fraction"] = max(float(params.get("map_braid_bridge_fraction", MAPGEN_KWARGS.get("map_braid_bridge_fraction", 0.16))), 0.04 + 0.24 * turniness + 0.10 * decoys + 0.10 * pressure)
params["map_hairpin_period"] = min(int(params.get("map_hairpin_period", MAPGEN_KWARGS.get("map_hairpin_period", 7))), max(3, int(round(9 - 5 * turniness))))
params["map_hairpin_angle"] = max(float(params.get("map_hairpin_angle", MAPGEN_KWARGS.get("map_hairpin_angle", 1.24))), 0.92 + 0.62 * turniness + 0.12 * pressure)
params["map_hairpin_depth"] = max(float(params.get("map_hairpin_depth", MAPGEN_KWARGS.get("map_hairpin_depth", 0.48))), 0.16 + 0.64 * turniness + 0.18 * pressure)
params["map_route_detour_period"] = min(int(params.get("map_route_detour_period", MAPGEN_KWARGS.get("map_route_detour_period", 4))), max(3, int(round(8 - 4 * turniness))))
params["map_route_detour_depth"] = max(float(params.get("map_route_detour_depth", MAPGEN_KWARGS.get("map_route_detour_depth", 0.58))), 0.14 + 0.48 * turniness + 0.28 * unintuitive + 0.20 * pressure)
params["map_unintuitive_depth"] = max(float(params.get("map_unintuitive_depth", MAPGEN_KWARGS.get("map_unintuitive_depth", 0.56))), 0.12 + 0.70 * unintuitive + 0.22 * pressure)
params["map_backtrack_depth"] = max(float(params.get("map_backtrack_depth", MAPGEN_KWARGS.get("map_backtrack_depth", 0.42))), 0.08 + 0.56 * unintuitive + 0.22 * pressure)
params["map_loopback_anchor_fraction"] = max(float(params.get("map_loopback_anchor_fraction", 0.0)), 0.18 * pressure + 0.22 * unintuitive * pressure)
params["map_loopback_anchor_period"] = min(int(params.get("map_loopback_anchor_period", 6)), 4 if pressure > 0.8 else 5)
params["map_valley_depth"] = max(float(params.get("map_valley_depth", MAPGEN_KWARGS.get("map_valley_depth", 0.58))), 0.12 + 0.72 * elevation_scale + 0.16 * pressure)
params["map_vertical_scale"] = max(float(params.get("map_vertical_scale", 1.70)), 1.15 + 1.05 * elevation_scale + 0.28 * pressure)
params["map_max_height"] = max(float(params.get("map_max_height", 7.0)), 5.2 + 3.0 * elevation_scale + 0.8 * pressure)
params["map_platform_tiny_fraction"] = max(float(params.get("map_platform_tiny_fraction", MAPGEN_KWARGS.get("map_platform_tiny_fraction", 0.18))), 0.04 + 0.42 * tiny_platforms + 0.10 * size_pressure + 0.10 * pressure)
params["map_route_tiny_fraction"] = max(float(params.get("map_route_tiny_fraction", MAPGEN_KWARGS.get("map_route_tiny_fraction", 0.10))), 0.02 + 0.26 * tiny_platforms + 0.10 * precision + 0.14 * pressure)
params["map_route_tiny_min_scale"] = min(float(params.get("map_route_tiny_min_scale", 0.44)), 0.44 - 0.08 * pressure)
params["map_route_tiny_max_scale"] = min(float(params.get("map_route_tiny_max_scale", 0.68)), 0.68 - 0.10 * pressure)
params["map_platform_large_fraction"] = max(float(params.get("map_platform_large_fraction", MAPGEN_KWARGS.get("map_platform_large_fraction", 0.18))), 0.04 + 0.34 * large_platforms)
params["map_platform_min_scale"] = min(float(params.get("map_platform_min_scale", MAPGEN_KWARGS.get("map_platform_min_scale", 0.52))), 0.74 - 0.26 * size_pressure - 0.16 * tiny_platforms - 0.06 * pressure)
params["map_platform_max_scale"] = max(float(params.get("map_platform_max_scale", MAPGEN_KWARGS.get("map_platform_max_scale", 1.42))), 1.08 + 0.56 * large_platforms + 0.22 * platform_size)
if verticality > 0.05:
params["map_goal_vertical_bias"] = max(float(params.get("map_goal_vertical_bias", MAPGEN_KWARGS.get("map_goal_vertical_bias", 0.0))), 0.20 + 0.75 * verticality)
params["map_false_summit_fraction"] = max(float(params.get("map_false_summit_fraction", MAPGEN_KWARGS.get("map_false_summit_fraction", 0.14))), 0.06 + 0.14 * verticality)
params["map_max_height"] = max(float(params.get("map_max_height", 7.0)), 5.4 + 2.4 * verticality)
if "vertical" not in tags and verticality > 0.55:
tags.append("vertical")
if traps > 0.05:
params["map_trap_jump_fraction"] = max(float(params.get("map_trap_jump_fraction", MAPGEN_KWARGS.get("map_trap_jump_fraction", 0.40))), 0.10 + 0.42 * traps)
params["map_trap_jump_high_fraction"] = max(float(params.get("map_trap_jump_high_fraction", MAPGEN_KWARGS.get("map_trap_jump_high_fraction", 0.20))), 0.05 + 0.22 * traps)
params["map_greedy_trap_fraction"] = max(float(params.get("map_greedy_trap_fraction", MAPGEN_KWARGS.get("map_greedy_trap_fraction", 0.22))), 0.05 + 0.20 * traps)
params["map_false_finish_fraction"] = max(float(params.get("map_false_finish_fraction", MAPGEN_KWARGS.get("map_false_finish_fraction", 0.16))), 0.04 + 0.16 * traps)
params["map_false_branch_fraction"] = max(float(params.get("map_false_branch_fraction", MAPGEN_KWARGS.get("map_false_branch_fraction", 0.20))), 0.04 + 0.20 * traps)
if loopiness > 0.05:
params["map_route_detour_depth"] = max(float(params.get("map_route_detour_depth", MAPGEN_KWARGS.get("map_route_detour_depth", 0.58))), 0.18 + 0.50 * loopiness)
params["map_unintuitive_depth"] = max(float(params.get("map_unintuitive_depth", MAPGEN_KWARGS.get("map_unintuitive_depth", 0.56))), 0.18 + 0.45 * loopiness)
params["map_backtrack_depth"] = max(float(params.get("map_backtrack_depth", MAPGEN_KWARGS.get("map_backtrack_depth", 0.42))), 0.10 + 0.55 * loopiness)
params["map_hairpin_depth"] = max(float(params.get("map_hairpin_depth", MAPGEN_KWARGS.get("map_hairpin_depth", 0.48))), 0.10 + 0.55 * loopiness)
if loopiness > 0.50:
params["map_route_detour_period"] = min(int(params.get("map_route_detour_period", MAPGEN_KWARGS.get("map_route_detour_period", 4))), 5)
if "loopback" not in tags:
tags.append("loopback")
if precision > 0.05:
params["map_platform_tiny_fraction"] = max(float(params.get("map_platform_tiny_fraction", MAPGEN_KWARGS.get("map_platform_tiny_fraction", 0.18))), 0.08 + 0.32 * precision)
params["map_route_tiny_fraction"] = max(float(params.get("map_route_tiny_fraction", MAPGEN_KWARGS.get("map_route_tiny_fraction", 0.10))), 0.04 + 0.20 * precision)
params["map_platform_min_scale"] = min(float(params.get("map_platform_min_scale", MAPGEN_KWARGS.get("map_platform_min_scale", 0.52))), 0.66 - 0.20 * precision)
params["map_edge_gap_min"] = max(float(params.get("map_edge_gap_min", MAPGEN_KWARGS.get("map_edge_gap_min", 0.95))), 0.85 + 0.45 * precision)
params["map_edge_gap_max"] = max(float(params.get("map_edge_gap_max", MAPGEN_KWARGS.get("map_edge_gap_max", 1.58))), 1.20 + 0.60 * precision)
if precision > 0.55 and "precision" not in tags:
tags.append("precision")
if difficulty_key == "rookie":
caps.setdefault("map_trap_jump_fraction", 0.05)
caps.setdefault("map_trap_jump_high_fraction", 0.02)
caps.setdefault("map_greedy_trap_fraction", 0.04)
caps.setdefault("map_false_branch_fraction", 0.06)
caps.setdefault("map_false_finish_fraction", 0.04)
caps.setdefault("map_false_summit_fraction", 0.06)
caps.setdefault("map_braid_bridge_fraction", 0.08)
caps.setdefault("map_route_detour_depth", 0.18)
caps.setdefault("map_backtrack_depth", 0.10)
caps.setdefault("map_hairpin_depth", 0.18)
caps.setdefault("map_unintuitive_depth", 0.18)
caps.setdefault("map_loopback_anchor_fraction", 0.0)
elif difficulty_key == "standard":
caps.setdefault("map_trap_jump_fraction", 0.22)
caps.setdefault("map_trap_jump_high_fraction", 0.08)
caps.setdefault("map_greedy_trap_fraction", 0.12)
caps.setdefault("map_false_branch_fraction", 0.16)
caps.setdefault("map_false_finish_fraction", 0.10)
caps.setdefault("map_false_summit_fraction", 0.12)
caps.setdefault("map_braid_bridge_fraction", 0.16)
caps.setdefault("map_route_detour_depth", 0.44)
caps.setdefault("map_backtrack_depth", 0.30)
caps.setdefault("map_hairpin_depth", 0.40)
caps.setdefault("map_unintuitive_depth", 0.42)
caps.setdefault("map_loopback_anchor_fraction", 0.08)
elif difficulty_key == "cursed":
params["map_route_gap_scale"] = max(float(params.get("map_route_gap_scale", 1.0)), 1.24)
params["map_edge_gap_min"] = max(float(params.get("map_edge_gap_min", 0.95)), 1.00)
params["map_edge_gap_max"] = max(float(params.get("map_edge_gap_max", 1.58)), 1.78)
params["map_route_edge_gap_floor"] = max(float(params.get("map_route_edge_gap_floor", 0.38)), 0.44)
params["map_goal_xy_min"] = max(float(params.get("map_goal_xy_min", 28.0)), 38.0)
params["map_goal_xy_per_jump_min"] = max(float(params.get("map_goal_xy_per_jump_min", 1.90)), 1.92)
params["map_goal_vertical_bias"] = max(float(params.get("map_goal_vertical_bias", 0.0)), 0.66)
params["map_vertical_scale"] = max(float(params.get("map_vertical_scale", 1.70)), 1.86)
params["map_max_height"] = max(float(params.get("map_max_height", 7.0)), 7.4)
params["map_platform_min_scale"] = max(float(params.get("map_platform_min_scale", 0.52)), 0.52)
params["map_platform_max_scale"] = min(float(params.get("map_platform_max_scale", 1.42)), 1.28)
params["map_platform_tiny_fraction"] = max(float(params.get("map_platform_tiny_fraction", 0.18)), 0.18)
params["map_route_tiny_fraction"] = max(float(params.get("map_route_tiny_fraction", 0.10)), 0.12)
params["map_trap_jump_fraction"] = max(float(params.get("map_trap_jump_fraction", 0.40)), 0.18)
params["map_trap_jump_high_fraction"] = max(float(params.get("map_trap_jump_high_fraction", 0.20)), 0.10)
params["map_greedy_trap_fraction"] = max(float(params.get("map_greedy_trap_fraction", 0.22)), 0.10)
params["map_false_branch_fraction"] = max(float(params.get("map_false_branch_fraction", 0.20)), 0.14)
params["map_false_finish_fraction"] = max(float(params.get("map_false_finish_fraction", 0.16)), 0.10)
params["map_false_summit_fraction"] = max(float(params.get("map_false_summit_fraction", 0.14)), 0.16)
params["map_braid_bridge_fraction"] = max(float(params.get("map_braid_bridge_fraction", 0.16)), 0.14)
params["map_direct_decoy_fraction"] = max(float(params.get("map_direct_decoy_fraction", 0.08)), 0.06)
params["map_cluster_extra_fraction"] = max(float(params.get("map_cluster_extra_fraction", 0.10)), 0.06)
params["map_decoy_corridor_fraction"] = max(float(params.get("map_decoy_corridor_fraction", 0.06)), 0.04)
params["map_hairpin_period"] = min(int(params.get("map_hairpin_period", 7)), 3)
params["map_hairpin_angle"] = max(float(params.get("map_hairpin_angle", 1.24)), 1.34)
params["map_hairpin_depth"] = max(float(params.get("map_hairpin_depth", 0.48)), 0.82)
params["map_route_detour_period"] = min(int(params.get("map_route_detour_period", 4)), 3)
params["map_route_detour_depth"] = max(float(params.get("map_route_detour_depth", 0.58)), 0.72)
params["map_backtrack_period"] = min(int(params.get("map_backtrack_period", 5)), 4)
params["map_backtrack_depth"] = max(float(params.get("map_backtrack_depth", 0.42)), 0.58)
params["map_unintuitive_depth"] = max(float(params.get("map_unintuitive_depth", 0.56)), 0.68)
params["map_valley_depth"] = max(float(params.get("map_valley_depth", 0.58)), 0.52)
params["map_loopback_anchor_fraction"] = max(float(params.get("map_loopback_anchor_fraction", 0.0)), 0.08)
params["map_loopback_anchor_period"] = min(int(params.get("map_loopback_anchor_period", 6)), 4)
params["map_trap_jump_drop"] = max(float(params.get("map_trap_jump_drop", 0.70)), 0.94)
params["map_trap_jump_high_max_up"] = max(float(params.get("map_trap_jump_high_max_up", 0.94)), 1.26)
params["map_trap_jump_disguise"] = max(float(params.get("map_trap_jump_disguise", 0.82)), 1.06)
caps.setdefault("map_route_gap_scale", 1.30)
caps.setdefault("map_edge_gap_min", 1.08)
caps.setdefault("map_edge_gap_max", 1.86)
caps.setdefault("map_route_edge_gap_floor", 0.48)
caps.setdefault("map_goal_xy_min", 40.0)
caps.setdefault("map_goal_xy_per_jump_min", 2.00)
caps.setdefault("map_goal_vertical_bias", 0.70)
caps.setdefault("map_vertical_scale", 1.94)
caps.setdefault("map_max_height", 7.8)
caps.setdefault("map_platform_tiny_fraction", 0.22)
caps.setdefault("map_route_tiny_fraction", 0.14)
caps.setdefault("map_trap_jump_fraction", 0.24)
caps.setdefault("map_trap_jump_high_fraction", 0.12)
caps.setdefault("map_greedy_trap_fraction", 0.14)
caps.setdefault("map_false_branch_fraction", 0.18)
caps.setdefault("map_false_finish_fraction", 0.12)
caps.setdefault("map_false_summit_fraction", 0.18)
caps.setdefault("map_braid_bridge_fraction", 0.18)
caps.setdefault("map_direct_decoy_fraction", 0.08)
caps.setdefault("map_cluster_extra_fraction", 0.08)
caps.setdefault("map_decoy_corridor_fraction", 0.06)
caps.setdefault("map_hairpin_depth", 0.90)
caps.setdefault("map_route_detour_depth", 0.82)
caps.setdefault("map_backtrack_depth", 0.66)
caps.setdefault("map_unintuitive_depth", 0.76)
caps.setdefault("map_valley_depth", 0.60)
caps.setdefault("map_loopback_anchor_fraction", 0.10)
if "cursed" not in tags:
tags.append("cursed")
elif difficulty_key == "nightmare":
# Match the hardest locally deployed checkpoint instead of asking the bot
# to certify an untrained 30/38 ultra-chaos distribution.
params.update({
"map_scenic_turn_scale": 1.16,
"map_scenic_vertical_step": 0.72,
"map_route_gap_scale": 1.36,
"map_edge_gap_min": 1.06,
"map_edge_gap_max": 1.92,
"map_route_edge_gap_floor": 0.50,
"map_goal_xy_min": 38.0,
"map_goal_xy_per_jump_min": 1.92,
"map_goal_vertical_bias": 0.72,
"map_goal_vertical_bias_min": 0.16,
"map_vertical_scale": 2.12,
"map_max_height": 9.6,
"map_platform_min_scale": 0.50,
"map_platform_max_scale": 1.26,
"map_platform_tiny_fraction": 0.22,
"map_route_tiny_fraction": 0.14,
"map_route_tiny_min_scale": 0.44,
"map_route_tiny_max_scale": 0.68,
"map_trap_jump_fraction": 0.22,
"map_trap_jump_high_fraction": 0.16,
"map_greedy_trap_fraction": 0.14,
"map_false_branch_fraction": 0.18,
"map_false_finish_fraction": 0.12,
"map_false_summit_fraction": 0.20,
"map_braid_bridge_fraction": 0.18,
"map_direct_decoy_fraction": 0.06,
"map_cluster_extra_fraction": 0.08,
"map_decoy_corridor_fraction": 0.06,
"map_hairpin_period": 3,
"map_hairpin_angle": 1.36,
"map_hairpin_depth": 1.20,
"map_route_detour_period": 3,
"map_route_detour_depth": 1.10,
"map_backtrack_period": 5,
"map_backtrack_depth": 1.00,
"map_unintuitive_depth": 1.10,
"map_valley_period": 5,
"map_valley_depth": 0.36,
"map_loopback_anchor_fraction": 0.10,
"map_loopback_anchor_period": 4,
"map_loopback_turn_gate": 0.26,
"map_trap_jump_drop": 0.70,
"map_trap_jump_high_max_up": 0.94,
"map_trap_jump_disguise": 0.82,
})
if "nightmare" not in tags:
tags.append("nightmare")
if difficulty_key == "rookie":
params.update({
"map_scenic_turn_scale": 0.70,
"map_route_gap_scale": 0.96,
"map_edge_gap_min": 0.70,
"map_edge_gap_max": 1.28,
"map_route_edge_gap_floor": 0.26,
"map_goal_xy_min": 14.0,
"map_goal_xy_per_jump_min": 1.08,
"map_goal_vertical_bias": 0.24,
"map_vertical_scale": 1.34,
"map_max_height": 5.4,
"map_platform_min_scale": 0.68,
"map_platform_max_scale": 1.58,
"map_platform_tiny_fraction": 0.04,
"map_route_tiny_fraction": 0.02,
"map_trap_jump_fraction": 0.02,
"map_trap_jump_high_fraction": 0.0,
"map_greedy_trap_fraction": 0.02,
"map_false_branch_fraction": 0.02,
"map_false_finish_fraction": 0.02,
"map_false_summit_fraction": 0.02,
"map_braid_bridge_fraction": 0.05,
"map_direct_decoy_fraction": 0.02,
"map_cluster_extra_fraction": 0.04,
"map_decoy_corridor_fraction": 0.02,
"map_hairpin_depth": 0.16,
"map_route_detour_depth": 0.14,
"map_backtrack_depth": 0.06,
"map_unintuitive_depth": 0.10,
"map_valley_depth": 0.22,
"map_loopback_anchor_fraction": 0.0,
})
elif difficulty_key == "standard":
params.update({
"map_scenic_turn_scale": 0.82,
"map_route_gap_scale": 1.04,
"map_edge_gap_min": 0.76,
"map_edge_gap_max": 1.42,
"map_route_edge_gap_floor": 0.30,
"map_goal_xy_min": 18.0,
"map_goal_xy_per_jump_min": 1.28,
"map_goal_vertical_bias": 0.38,
"map_vertical_scale": 1.56,
"map_max_height": 6.4,
"map_platform_min_scale": 0.58,
"map_platform_max_scale": 1.50,
"map_platform_tiny_fraction": 0.10,
"map_route_tiny_fraction": 0.05,
"map_trap_jump_fraction": 0.10,
"map_trap_jump_high_fraction": 0.03,
"map_greedy_trap_fraction": 0.06,
"map_false_branch_fraction": 0.08,
"map_false_finish_fraction": 0.05,
"map_false_summit_fraction": 0.06,
"map_braid_bridge_fraction": 0.10,
"map_direct_decoy_fraction": 0.04,
"map_cluster_extra_fraction": 0.07,
"map_decoy_corridor_fraction": 0.04,
"map_hairpin_depth": 0.30,
"map_route_detour_depth": 0.26,
"map_backtrack_depth": 0.14,
"map_unintuitive_depth": 0.22,
"map_valley_depth": 0.30,
"map_loopback_anchor_fraction": 0.0,
})
# Apply caps last so they can only lower the result.
for key, cap in caps.items():
if key in params:
params[key] = min(float(params[key]), float(cap))
else:
params[key] = float(cap)
return {
"theme": theme,
"mood": mood,
"tags": tags or ["balanced"],
"knobs": knobs,
"params": params,
"raw_vibe": str(vibe or "").strip(),
}
# --- LLM direct platform placement ----------------------------------------
#
# This is a separate code path from the procedural vibe plan above. The LLM
# returns a list of platform specs (position + size in metres) and the
# backend sets `env.platforms` directly. The same legalizer
# (`separate_route_overlaps`, `enforce_route_reach`, ...) is applied so the
# output stays physics-consistent, but the LLM has full control over the
# layout, including the ability to make extreme OOD maps. The point of this
# path is to test whether the trained policy can generalize to maps the
# procedural generator has never seen.
DIRECT_PLATFORM_FEATURES = (
"extra",
"trap_low",
"trap_high",
"bridge",
"island",
)
DIRECT_LLM_SYSTEM_PROMPT = (
"You design floating-platform parkour maps by writing a JSON list of platforms. "
"Return one JSON object with the key 'platforms'. Each platform is an object: "
"x (float metres, -20..20), y (float metres, -12..12), z (float metres, 0..6), "
"w (float width, 0.45..2.4), d (float depth, 0.45..2.4). "
"The platforms array is the path in order: first platform is spawn, last is goal. "
"Steps should usually be 0.8..2.5 metres apart in xy, with rises of at most 1.4m "
"and drops of at most 3.0m. Adjacent route platforms must be jumpable. "
"Keep the output compact. Do not include knobs, theme, mood, tags, notes, "
"explanations, labels, markdown, is_route, feature, or extra keys. "
"Raw compact JSON only."
)
def _llm_api_key() -> str:
return os.environ.get("MAPGEN_LLM_API_KEY", "").strip() or os.environ.get("OPENROUTER_API_KEY", "").strip()
def _llm_model() -> str:
return os.environ.get("MAPGEN_LLM_MODEL", "google/gemma-4-31b-it")
def _llm_mode() -> str:
return os.environ.get("MAPGEN_LLM", "auto").strip().lower()
def _llm_timeout() -> float:
return float(os.environ.get("MAPGEN_LLM_TIMEOUT", "30.0"))
def _json_from_text(text: str) -> dict[str, Any]:
cleaned = str(text or "").strip()
cleaned = re.sub(r"^\s*```(?:json)?\s*", "", cleaned, flags=re.IGNORECASE)
cleaned = re.sub(r"\s*```\s*$", "", cleaned)
try:
value = json.loads(cleaned)
except json.JSONDecodeError:
match = re.search(r"\{.*\}", cleaned, flags=re.DOTALL)
if not match:
raise
candidate = match.group(0)
repaired = _repair_json_text(candidate)
try:
value = json.loads(repaired)
except json.JSONDecodeError:
value = _extract_platforms_object(repaired)
if not isinstance(value, dict):
raise ValueError("LLM response did not parse as a JSON object")
return value
def _repair_json_text(text: str) -> str:
repaired = str(text or "").strip()
repaired = re.sub(r",(\s*[}\]])", r"\1", repaired)
repaired = re.sub(r"}\s*{", "},{", repaired)
return repaired
def _extract_platforms_object(text: str) -> dict[str, Any]:
key_match = re.search(r'"platforms"\s*:\s*\[', text)
if not key_match:
raise ValueError("LLM response did not include a parseable platforms array")
start = key_match.end()
depth = 0
object_start: int | None = None
snippets: list[str] = []
for index in range(start, len(text)):
char = text[index]
if char == "{":
if depth == 0:
object_start = index
depth += 1
elif char == "}":
if depth > 0:
depth -= 1
if depth == 0 and object_start is not None:
snippets.append(text[object_start:index + 1])
object_start = None
elif char == "]" and depth == 0:
break
platforms: list[dict[str, Any]] = []
for snippet in snippets:
try:
value = json.loads(_repair_json_text(snippet))
except json.JSONDecodeError:
value = _loose_platform_object(snippet)
if isinstance(value, dict):
platforms.append(value)
if not platforms:
raise ValueError("LLM response did not contain any parseable platform objects")
return {"platforms": platforms}
def _loose_platform_object(text: str) -> dict[str, Any] | None:
raw = str(text or "")
def find_number(*keys: str) -> float | None:
for key in keys:
match = re.search(rf'"{re.escape(key)}"\s*:\s*(-?\d+(?:\.\d+)?)', raw)
if match:
try:
return float(match.group(1))
except ValueError:
continue
return None
x = find_number("x", "forward")
y = find_number("y", "side", "lateral")
z = find_number("z", "rise", "z_level")
w = find_number("w", "width")
d = find_number("d", "depth")
if None in {x, y, z, w, d}:
return None
is_route_match = re.search(r'"is_route"\s*:\s*(true|false)', raw, flags=re.IGNORECASE)
feature_match = re.search(r'"feature"\s*:\s*"([^"]+)"', raw)
label_match = re.search(r'"label"\s*:\s*"([^"]+)"', raw)
return {
"x": x,
"y": y,
"z": z,
"w": w,
"d": d,
"is_route": bool(is_route_match and is_route_match.group(1).lower() == "true"),
"feature": feature_match.group(1) if feature_match else "extra",
"label": label_match.group(1) if label_match else "",
}
def _clean_text(value: Any, default: str = "", limit: int = 80) -> str:
text = re.sub(r"[\x00-\x1f\x7f]+", " ", str(value or "")).strip()
text = re.sub(r"\s+", " ", text)
return (text or default)[:limit]
def _openrouter_request(api_key: str, payload: dict[str, Any]) -> urllib.request.Request:
return urllib.request.Request(
"https://openrouter.ai/api/v1/chat/completions",
data=json.dumps(payload).encode("utf-8"),
headers={
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json",
"HTTP-Referer": os.environ.get("OPENROUTER_SITE_URL", "https://agent-parkour.local"),
"X-Title": "agent-parkour-mapgen",
},
method="POST",
)
def _llm_in_use() -> bool:
if _llm_mode() in {"off", "false", "0", "none", "disabled"}:
return False
return bool(_llm_api_key())
def _sanitize_direct_platform(raw: Any, *, is_route: bool, index: int) -> dict[str, Any] | None:
if not isinstance(raw, dict):
return None
try:
x = float(raw.get("x", raw.get("forward", 0.0)))
y = float(raw.get("y", raw.get("side", raw.get("lateral", 0.0))))
z = float(raw.get("z", raw.get("rise", raw.get("z_level", 0.0))))
w = float(raw.get("w", raw.get("width", 1.0)))
d = float(raw.get("d", raw.get("depth", 1.0)))
except (TypeError, ValueError):
return None
if not (all(map(lambda v: v == v, (x, y, z, w, d)))):
return None
if abs(x) > 24.0 or abs(y) > 16.0 or z < -2.0 or z > 8.0:
return None
w = max(0.45, min(2.4, w))
d = max(0.45, min(2.4, d))
if is_route:
if index == 0 or index == -1:
w = max(w, 1.6)
d = max(d, 1.6)
feature = _clean_text(raw.get("feature"), "extra", limit=16).lower().replace(" ", "_")
if feature not in DIRECT_PLATFORM_FEATURES:
feature = "extra"
return {
"x": x,
"y": y,
"z": z,
"w": w,
"d": d,
"is_route": bool(is_route),
"feature": feature,
"label": _clean_text(raw.get("label"), f"{'route' if is_route else 'extra'} {index}", limit=36),
}
def _platforms_from_llm_response(raw: dict[str, Any], *, route_jumps: int, distractors: int) -> dict[str, Any]:
platforms_raw = raw.get("platforms")
if not isinstance(platforms_raw, list):
return {"ok": False, "reason": "missing platforms list", "platforms": []}
route_needed = max(2, int(route_jumps) + 1)
route_platforms: list[dict[str, Any]] = []
for raw_item in platforms_raw:
if len(route_platforms) >= route_needed:
break
spec = _sanitize_direct_platform(raw_item, is_route=True, index=len(route_platforms))
if spec is not None:
route_platforms.append(spec)
if len(route_platforms) < 2:
return {"ok": False, "reason": f"only {len(route_platforms)} valid route platforms", "platforms": []}
if len(route_platforms) < route_needed:
return {
"ok": False,
"reason": f"only {len(route_platforms)} valid route platforms; expected {route_needed}",
"platforms": [],
}
return {
"ok": True,
"reason": "ok",
"route": route_platforms,
"extras": [],
}
def _request_direct_platforms_with_llm(vibe: str, difficulty_key: str, route_jumps: int, distractors: int) -> dict[str, Any]:
api_key = _llm_api_key()
if not api_key:
raise RuntimeError("MAPGEN_LLM_API_KEY or OPENROUTER_API_KEY is required for LLM direct platform placement")
payload = _direct_platforms_payload(vibe, difficulty_key, route_jumps, distractors, stream=False)
request = _openrouter_request(api_key, payload)
try:
with urllib.request.urlopen(request, timeout=_llm_timeout()) as response:
data = json.loads(response.read().decode("utf-8"))
except urllib.error.HTTPError as exc:
body = exc.read().decode("utf-8", errors="replace")
raise RuntimeError(f"OpenRouter HTTP {exc.code}: {_clean_text(body, limit=180)}") from exc
content = data["choices"][0]["message"]["content"]
return _platforms_from_llm_response(
_json_from_text(content),
route_jumps=route_jumps,
distractors=distractors,
)
def _direct_platforms_payload(
vibe: str, difficulty_key: str, route_jumps: int, distractors: int, *, stream: bool
) -> dict[str, Any]:
return {
"model": _llm_model(),
"temperature": 0.25,
"max_tokens": 900,
"stream": bool(stream),
"messages": [
{"role": "system", "content": DIRECT_LLM_SYSTEM_PROMPT},
{
"role": "user",
"content": json.dumps(
{
"user_vibe": str(vibe or "")[:1500],
"platforms_needed": int(route_jumps) + 1,
"physics": {
"agent_max_xy_step_metres": 4.5,
"agent_max_rise_metres": 1.4,
"agent_max_drop_metres": 3.0,
"platform_x_extent": 24.0,
"platform_y_extent": 16.0,
"platform_z_extent": [0.0, 6.0],
},
"instructions": [
"Place platforms in metres, not in grid cells.",
"Return only one ordered path of blocks.",
"First platform is spawn. Last platform is goal.",
"Keep it short and valid: one compact JSON object, no prose, no markdown.",
"Use exactly the requested number of platforms.",
],
},
separators=(",", ":"),
),
},
],
}
def _request_direct_platforms_with_llm_stream(
vibe: str,
difficulty_key: str,
route_jumps: int,
distractors: int,
emit: Callable[[dict[str, Any]], None],
) -> dict[str, Any]:
"""Stream the LLM response. Emits `llm_text_delta` per chunk, then `llm_text_done` with the full text."""
api_key = _llm_api_key()
if not api_key:
raise RuntimeError("MAPGEN_LLM_API_KEY or OPENROUTER_API_KEY is required for LLM direct platform placement")
payload = _direct_platforms_payload(vibe, difficulty_key, route_jumps, distractors, stream=True)
request = _openrouter_request(api_key, payload)
chunks: list[str] = []
try:
with urllib.request.urlopen(request, timeout=_llm_timeout()) as response:
for raw_line in response:
line = raw_line.decode("utf-8", errors="replace").strip()
if not line or line.startswith(":"):
continue
if line.startswith("data:"):
line = line[5:].strip()
if line == "[DONE]":
break
try:
packet = json.loads(line)
except json.JSONDecodeError:
continue
choices = packet.get("choices") if isinstance(packet, dict) else None
if not choices:
continue
choice = choices[0] if isinstance(choices[0], dict) else {}
delta = ""
delta_obj = choice.get("delta")
if isinstance(delta_obj, dict):
delta = str(delta_obj.get("content") or "")
if not delta:
message_obj = choice.get("message")
if isinstance(message_obj, dict):
delta = str(message_obj.get("content") or "")
if not delta:
continue
chunks.append(delta)
emit({"type": "llm_text_delta", "delta": delta})
except urllib.error.HTTPError as exc:
body = exc.read().decode("utf-8", errors="replace")
raise RuntimeError(f"OpenRouter HTTP {exc.code}: {_clean_text(body, limit=180)}") from exc
content = "".join(chunks).strip()
if not content:
raise RuntimeError("OpenRouter returned an empty streamed response")
emit({"type": "llm_text_done", "text": content})
return _platforms_from_llm_response(
_json_from_text(content),
route_jumps=route_jumps,
distractors=distractors,
)
def _apply_direct_platforms(env: FastFloatingBeaconEnv, platforms: dict[str, Any]) -> None:
"""Set `env.platforms` and `env.sizes` from the LLM-produced list.
The route platforms are placed at the start, extras fill the rest. The
legalizer (called by the caller) fixes overlaps and unreachability.
"""
n = int(env.n)
route_len = int(env.route_len)
p = int(env.p)
route_specs = list(platforms.get("route", []))
extra_specs = list(platforms.get("extras", []))
if not route_specs:
raise RuntimeError("direct platform path got an empty route")
env.platforms.zero_()
env.sizes.fill_(0.0)
base_w, base_d = float(env.platform_x), float(env.platform_y)
min_h = float(getattr(env.cfg, "map_height_offset", 2.85)) + 0.18
max_h = max(min_h + 0.4, float(getattr(env.cfg, "map_max_height", 5.6)))
for layer in range(route_len):
spec = route_specs[min(layer, len(route_specs) - 1)]
env.platforms[:, layer, 0] = float(spec.get("x", 0.0))
env.platforms[:, layer, 1] = float(spec.get("y", 0.0))
env.platforms[:, layer, 2] = float(min(max(float(spec.get("z", 0.0)) + min_h, min_h), max_h))
env.sizes[:, layer, 0] = max(0.4, min(2.6, float(spec.get("w", 1.0))))
env.sizes[:, layer, 1] = max(0.4, min(2.6, float(spec.get("d", 1.0))))
env.sizes[:, 0] = torch.maximum(env.sizes[:, 0], torch.tensor([base_w * 1.2, base_d * 1.2], device=env.device))
env.sizes[:, route_len - 1] = torch.maximum(
env.sizes[:, route_len - 1],
torch.tensor([base_w * 1.15, base_d * 1.15], device=env.device),
)
if extra_specs:
for e in range(p - route_len):
spec = extra_specs[e % len(extra_specs)]
idx = route_len + e
feature = str(spec.get("feature", "extra"))
anchor_layer = int(spec.get("anchor", e % max(1, route_len - 1)))
anchor_layer = max(0, min(route_len - 1, anchor_layer))
env.platforms[:, idx, 0] = float(spec.get("x", 0.0))
env.platforms[:, idx, 1] = float(spec.get("y", 0.0))
rise = float(spec.get("rise", 0.0))
if feature == "trap_high":
rise = 1.6
elif feature == "trap_low":
rise = -1.4
elif feature == "bridge":
rise = 0.0
elif feature == "island":
rise = (rise if rise != 0.0 else 0.0)
env.platforms[:, idx, 2] = float(min(max(env.platforms[0, anchor_layer, 2].item() + rise, min_h), max_h))
env.sizes[:, idx, 0] = max(0.4, min(2.4, float(spec.get("w", 1.0))))
env.sizes[:, idx, 1] = max(0.4, min(2.4, float(spec.get("d", 1.0))))
from mapgen import ( # noqa: E402 (local import to avoid cycles in some envs)
enforce_route_edge_gap,
enforce_route_reach,
relocate_route_colliding_extras,
resolve_route_extra_grazes,
separate_nonroute_overlaps,
separate_route_overlaps,
)
edge_floor = max(0.22, float(getattr(env.cfg, "map_route_edge_gap_floor", 0.24)))
separate_route_overlaps(env, iterations=18, clearance=0.10)
enforce_route_edge_gap(env, floor=edge_floor, passes=2)
enforce_route_reach(env, safety=0.16, passes=4)
separate_route_overlaps(env, iterations=14, clearance=0.08)
enforce_route_reach(env, safety=0.12, passes=3)
if p > route_len:
relocate_route_colliding_extras(env, iterations=6, clearance=0.32)
separate_nonroute_overlaps(env, iterations=32)
resolve_route_extra_grazes(env, iterations=6, clearance=0.08)
from mapgen import enforce_extra_any_route_reach
enforce_extra_any_route_reach(env, safety=0.02, passes=2)
separate_nonroute_overlaps(env, iterations=18)
center = env.platforms[:, :, :2].mean(dim=1, keepdim=True)
env.platforms[:, :, :2] -= center
env.setup_platform_mechanics(env.env_i)
env.reset_state(env.env_i)
env.update_dynamic_platforms()
def _make_env(
seed: int = 7,
route_jumps: int = 12,
distractors: int = 6,
device: str = "cpu",
*,
motif_params: dict[str, Any] | None = None,
direct_platforms: dict[str, Any] | None = None,
) -> FastFloatingBeaconEnv:
if motif_params is not None:
configure_motif_mapgen(replace=True, **motif_params)
else:
configure_motif_mapgen(**MAPGEN_KWARGS)
install_motif_mapgen()
cfg = V2Config(
seed=seed,
device=device,
envs=1,
route_jumps=route_jumps,
distractors=distractors,
arena_x=32.0,
arena_y=18.0,
lava_z=-0.9,
agent_radius=0.18,
max_speed=float(PHYSICS_DEFAULTS["max_speed"]),
jump_velocity=float(PHYSICS_DEFAULTS["jump_velocity"]),
gravity=float(PHYSICS_DEFAULTS["gravity"]),
accel=float(PHYSICS_DEFAULTS["accel"]),
ground_damping=float(PHYSICS_DEFAULTS["ground_damping"]),
air_damping=float(PHYSICS_DEFAULTS["air_damping"]),
air_control=float(PHYSICS_DEFAULTS["air_control"]),
sprint_speed_mult=float(PHYSICS_DEFAULTS["sprint_speed_mult"]),
sprint_accel_mult=float(PHYSICS_DEFAULTS["sprint_accel_mult"]),
turn_speed=float(PHYSICS_DEFAULTS["turn_speed"]),
map_height_offset=2.75,
map_vertical_scale=1.25,
map_max_height=6.0,
sensor_mode="topk",
sensor_topk=16,
pillar_platforms=False,
)
env = FastFloatingBeaconEnv(cfg, envs=1, seed=seed)
if direct_platforms is not None:
_apply_direct_platforms(env, direct_platforms)
return env
def _stage_config(base_cfg: V2Config, spec: dict[str, Any], seed: int, vibe_plan: dict[str, Any]) -> V2Config:
max_steps_factor = float(spec.get("max_steps_factor", getattr(base_cfg, "max_steps_factor", 24.0)))
cfg = replace(
base_cfg,
seed=int(seed),
device=str(_device()),
eval_envs=int(spec["attempts"]),
route_jumps=int(spec["route_jumps"]),
distractors=int(spec["distractors"]),
max_steps_factor=max_steps_factor,
run_dir=str(TRIAL_DIR),
sensor_mode="topk",
sensor_topk=16,
sensor_token_range=9.5,
pillar_platforms=False,
**{key: value for key, value in ENV_DEFAULTS.items() if hasattr(base_cfg, key)},
)
for key, value in vibe_plan["params"].items():
if hasattr(cfg, key):
cfg = replace(cfg, **{key: value})
return cfg
def _sync_for_timing(device: torch.device) -> None:
try:
sync_device(device)
except Exception:
pass
def _runtime_report(model: torch.nn.Module | None = None) -> dict[str, Any]:
resolved = _device()
model_device = str(next(model.parameters()).device) if model is not None else ""
return {
"requested_device": DEVICE_NAME,
"resolved_device": str(resolved),
"model_device": model_device,
"uses_mps": model_device.startswith("mps") or (not model_device and resolved.type == "mps"),
"uses_cuda": model_device.startswith("cuda") or (not model_device and resolved.type == "cuda"),
"mps_available": bool(hasattr(torch.backends, "mps") and torch.backends.mps.is_available()),
"cuda_available": bool(torch.cuda.is_available()),
"checkpoint": str(CHECKPOINT_PATH.relative_to(ROOT)) if CHECKPOINT_PATH.is_relative_to(ROOT) else str(CHECKPOINT_PATH),
}
def _physics_parity_report(cfg: V2Config) -> dict[str, Any]:
keys = tuple(PHYSICS_DEFAULTS.keys())
actual = {key: float(getattr(cfg, key)) for key in keys if hasattr(cfg, key)}
expected = {key: float(PHYSICS_DEFAULTS[key]) for key in actual}
mismatches = {
key: {"actual": actual[key], "expected": expected[key]}
for key in actual
if abs(actual[key] - expected[key]) > 1.0e-6
}
return {
"bot_env_matches_shared_defaults": not mismatches,
"bot_env": "canonical Python FastFloatingBeaconEnv",
"human_try_mode": "browser game-feel physics port; not used for bot certification",
"actual": actual,
"expected": expected,
"mismatches": mismatches,
}
def _capture_eval_state(env: FastFloatingBeaconEnv) -> dict[str, torch.Tensor]:
return {
"pos": env.pos.detach().clone(),
"yaw": env.yaw.detach().clone(),
"grounded": env.grounded.detach().clone(),
"done": env.done.detach().clone(),
"success": env.success.detach().clone(),
"steps": env.steps.detach().clone(),
"current": env.current.detach().clone(),
"visited": env.visited.detach().clone(),
"available": env.platform_available.detach().clone(),
"progress": env.progress_tensor().detach().clone(),
}
@torch.no_grad()
def _evaluate_trial_fast(
model: torch.nn.Module,
cfg: V2Config,
*,
setup_fn: Callable[[FastFloatingBeaconEnv], None] | None = None,
) -> tuple[dict[str, float], list[dict[str, Any]], bool, int, dict[str, Any]]:
device = next(model.parameters()).device
total_start = time.perf_counter()
env = FastFloatingBeaconEnv(cfg, envs=int(cfg.eval_envs), seed=int(cfg.seed) + 300_000)
if setup_fn is not None:
setup_fn(env)
obs = env.observe().to(device=device, dtype=torch.float32)
else:
obs = env.reset().to(device=device, dtype=torch.float32)
platforms = env.platforms.detach().clone()
sizes = env.sizes.detach().clone()
lever_mask = env.lever_mask.detach().clone()
locked_by = env.locked_by.detach().clone()
fragile = env.fragile_mask.detach().clone()
launch_pad = env.launch_pad_mask.detach().clone()
moving = env.moving_mask.detach().clone()
platform_velocity = env.platform_velocity.detach().clone()
_sync_for_timing(device)
env_init_seconds = time.perf_counter() - total_start
history: list[dict[str, torch.Tensor]] = [_capture_eval_state(env)]
episode_done = torch.zeros(env.n, dtype=torch.bool, device=device)
success_seen = torch.zeros(env.n, dtype=torch.bool, device=device)
rollout_start = time.perf_counter()
for _ in range(env.max_steps):
action, _out = model.choose_action(obs, deterministic_controls=True, deterministic_buttons=True)
step = env.step(action)
done = step.done.to(device=device)
success_seen |= (~episode_done) & step.info["success"].to(device=device)
episode_done |= done
obs = step.observation.to(device=device, dtype=torch.float32)
history.append(_capture_eval_state(env))
if bool(episode_done.all().detach().cpu()):
break
_sync_for_timing(device)
rollout_seconds = time.perf_counter() - rollout_start
progress = env.progress_tensor().detach()
steps = env.steps.detach()
if bool(success_seen.any().detach().cpu()):
score = torch.where(success_seen, -steps.float(), torch.full_like(steps.float(), -1.0e9))
else:
score = progress * 1000.0 + steps.float() * 1.0e-4
selected = int(score.argmax().detach().cpu())
selected_success = bool(success_seen[selected].detach().cpu())
frame_start = time.perf_counter()
frames = _frames_from_eval_history(
cfg,
env,
history,
selected,
platforms[selected].detach().cpu(),
sizes[selected].detach().cpu(),
lever_mask[selected].detach().cpu(),
locked_by[selected].detach().cpu(),
fragile[selected].detach().cpu(),
launch_pad[selected].detach().cpu(),
moving[selected].detach().cpu(),
platform_velocity[selected].detach().cpu(),
)
frame_build_seconds = time.perf_counter() - frame_start
stats = {
"eval_success": float(success_seen.float().mean().detach().cpu()),
"eval_progress": float(progress.mean().detach().cpu()),
"eval_steps": float(steps.float().mean().detach().cpu()),
}
diagnostics = {
"eval_envs": int(env.n),
"max_steps": int(env.max_steps),
"history_frames": len(history),
"selected_attempt": int(selected),
"selected_success": bool(selected_success),
"env_init_seconds": env_init_seconds,
"rollout_seconds": rollout_seconds,
"frame_build_seconds": frame_build_seconds,
"total_seconds": time.perf_counter() - total_start,
"snapshot_strategy": "device tensor history; JSON materialized only for selected rollout",
}
return stats, frames, selected_success, selected, diagnostics
def _frames_from_eval_history(
cfg: V2Config,
env: FastFloatingBeaconEnv,
history: list[dict[str, torch.Tensor]],
selected: int,
platforms: torch.Tensor,
sizes: torch.Tensor,
lever_mask: torch.Tensor,
locked_by: torch.Tensor,
fragile: torch.Tensor,
launch_pad: torch.Tensor,
moving: torch.Tensor,
platform_velocity: torch.Tensor,
) -> list[dict[str, Any]]:
platforms_list = platforms.tolist()
sizes_list = sizes.tolist()
lever_mask_list = [bool(x) for x in lever_mask.tolist()]
locked_by_list = [int(x) for x in locked_by.tolist()]
fragile_list = [bool(x) for x in fragile.tolist()]
launch_pad_list = [bool(x) for x in launch_pad.tolist()]
moving_list = [bool(x) for x in moving.tolist()]
platform_velocity_list = platform_velocity.tolist()
goal = int(env.route_len) - 1
frames: list[dict[str, Any]] = []
for row in history:
pos = row["pos"][selected].detach().cpu()
step = int(row["steps"][selected].detach().cpu())
success = bool(row["success"][selected].detach().cpu())
done = bool(row["done"][selected].detach().cpu())
fallen = bool(float(pos[2]) < float(cfg.lava_z))
timeout = bool(done and (not success) and (not fallen))
available = [bool(x) for x in row["available"][selected].detach().cpu().tolist()]
visited = [bool(x) for x in row["visited"][selected].detach().cpu().tolist()]
outcome = "success" if success else ("fallen" if fallen else ("timeout" if timeout else "running"))
frames.append(
{
"pos": pos.tolist(),
"yaw": float(row["yaw"][selected].detach().cpu()),
"stage": float(row["progress"][selected].detach().cpu()) * max(1, goal),
"step": step,
"grounded": bool(row["grounded"][selected].detach().cpu()),
"success": success,
"done": done,
"fallen": fallen,
"burned": False,
"timeout": timeout,
"outcome": outcome,
"landed": int(row["current"][selected].detach().cpu()),
"goal": goal,
"egoReplay": True,
"physicsBackend": "torch_fast_kinematic",
"routeMode": "route_free_goal",
"plannerMode": "policy_direct_ego_sensor",
"sensorMode": str(getattr(cfg, "sensor_mode", "ray")),
"platforms": platforms_list,
"sizes": sizes_list,
"activeNodes": available,
"visited": visited,
"fireMask": [False for _ in range(env.p)],
"fireActive": [False for _ in range(env.p)],
"leverMask": lever_mask_list,
"leverUnlocked": [False for _ in range(env.p)],
"leverProgress": [0 for _ in range(env.p)],
"leverHoldSteps": int(max(1, int(getattr(cfg, "unlock_hold_steps", 1)))),
"lockedBy": locked_by_list,
"fragileMask": fragile_list,
"launchPadMask": launch_pad_list,
"movingMask": moving_list,
"platformVelocity": platform_velocity_list,
"platformOpen": available,
"platformAvailable": available,
"platformSafe": available,
}
)
if done and step > 0:
break
return frames
def _spec_with_knobs(spec: dict[str, Any], knobs: dict[str, float]) -> dict[str, Any]:
next_spec = dict(spec)
length = float(knobs["length"])
decoys = float(knobs["decoys"])
precision = float(knobs["precision"])
traps = float(knobs["traps"])
loopiness = float(knobs["loopiness"])
jump_gap = float(knobs["jump_gap"])
turniness = float(knobs["turniness"])
tiny_platforms = float(knobs["tiny_platforms"])
unintuitive = float(knobs["unintuitive"])
pressure = _difficulty_pressure(str(next_spec.get("key", "standard")))
key = str(next_spec.get("key", "standard"))
if key in {"rookie", "standard"}:
extra_jumps = int(round(length * 2.0 + jump_gap * 1.0 + turniness * 0.5 + pressure * 1.0))
extra_distractors = int(round(decoys * 3.0 + traps * 1.0 + unintuitive * 1.0 + pressure * 1.0))
else:
extra_jumps = int(round(length * 5.0 + jump_gap * 2.0 + turniness * 1.5 + pressure * 3.0))
extra_distractors = int(round(length * 4.0 + decoys * 8.0 + traps * 3.0 + unintuitive * 4.0 + pressure * 5.0))
next_spec["route_jumps"] = int(next_spec["route_jumps"]) + extra_jumps
next_spec["distractors"] = int(next_spec["distractors"]) + extra_distractors
next_spec["attempts"] = int(next_spec["attempts"]) + int(round((length + decoys + precision + traps + jump_gap + unintuitive) * 16.0 + pressure * 24.0))
next_spec["retries"] = int(next_spec["retries"]) + int(round((traps + loopiness + precision + jump_gap + unintuitive + tiny_platforms) * 1.3 + pressure * 2.0))
route_caps = {"rookie": 7, "standard": 12, "cursed": 17, "nightmare": 25}
distractor_caps = {"rookie": 5, "standard": 8, "cursed": 9, "nightmare": 20}
attempt_caps = {"rookie": 56, "standard": 80, "cursed": 96, "nightmare": 96}
retry_caps = {"rookie": 1, "standard": 2, "cursed": 3, "nightmare": 4}
next_spec["route_jumps"] = min(int(next_spec["route_jumps"]), route_caps.get(key, 16))
next_spec["distractors"] = min(int(next_spec["distractors"]), distractor_caps.get(key, 18))
next_spec["attempts"] = min(int(next_spec["attempts"]), attempt_caps.get(key, 128))
next_spec["retries"] = min(int(next_spec["retries"]), retry_caps.get(key, 6))
return next_spec
def _build_vibe_plan(vibe: str, difficulty_key: str, knobs: dict[str, float]) -> dict[str, Any]:
"""Procedural vibe plan: vibe text + UI knobs -> mapgen kwargs.
The LLM direct path bypasses this entirely and produces platforms via
`_request_direct_platforms_with_llm`.
"""
return _direct_vibe(vibe, difficulty_key, knobs)
def _generation_mode_alias(mode: str | None) -> str:
"""Map UI-facing aliases to the canonical generation mode."""
key = str(mode or "procedural").strip().lower().replace("-", "_").replace(" ", "_")
if key in {"", "procedural", "vibe_params", "vibe", "vibes", "vibe_map", "map_vibes", "params", "knobs"}:
return "procedural"
if key in {"llm_direct", "llm_vibe", "llm", "ai", "direct", "direct_blueprint", "course_architect", "architect", "blueprint"}:
return "llm_direct"
raise ValueError(f"unknown generation mode: {mode}")
def _generation_mode_labels() -> dict[str, str]:
return {
"procedural": "Procedural (knobs)",
"llm_direct": "LLM direct (out of distribution)",
}
def _stream_event(event: dict[str, Any]) -> str:
return json.dumps(event, default=plain, separators=(",", ":")) + "\n"
def _certify(
difficulty: str,
vibe: str,
seed: int | None,
*,
generation_mode: str = "procedural",
verticality: float | int | None = None,
traps: float | int | None = None,
loopiness: float | int | None = None,
precision: float | int | None = None,
length: float | int | None = None,
jump_gap: float | int | None = None,
platform_size: float | int | None = None,
decoys: float | int | None = None,
elevation_scale: float | int | None = None,
turniness: float | int | None = None,
tiny_platforms: float | int | None = None,
large_platforms: float | int | None = None,
unintuitive: float | int | None = None,
) -> dict[str, Any]:
return _certify_inner(
difficulty=difficulty,
vibe=vibe,
seed=seed,
generation_mode=generation_mode,
verticality=verticality,
traps=traps,
loopiness=loopiness,
precision=precision,
length=length,
jump_gap=jump_gap,
platform_size=platform_size,
decoys=decoys,
elevation_scale=elevation_scale,
turniness=turniness,
tiny_platforms=tiny_platforms,
large_platforms=large_platforms,
unintuitive=unintuitive,
direct_platforms=None,
)
@spaces.GPU(duration=180)
def _certify_inner(
*,
difficulty: str,
vibe: str,
seed: int | None,
generation_mode: str,
verticality: float | int | None,
traps: float | int | None,
loopiness: float | int | None,
precision: float | int | None,
length: float | int | None,
jump_gap: float | int | None,
platform_size: float | int | None,
decoys: float | int | None,
elevation_scale: float | int | None,
turniness: float | int | None,
tiny_platforms: float | int | None,
large_platforms: float | int | None,
unintuitive: float | int | None,
direct_platforms: dict[str, Any] | None,
) -> dict[str, Any]:
load_start = time.perf_counter()
checkpoint, base_cfg, model = _load_checkpoint()
_sync_for_timing(next(model.parameters()).device)
load_seconds = time.perf_counter() - load_start
requested_knobs = _knobs(
verticality,
traps,
loopiness,
precision,
length,
jump_gap,
platform_size,
decoys,
elevation_scale,
turniness,
tiny_platforms,
large_platforms,
unintuitive,
)
mode = _generation_mode_alias(generation_mode)
if mode == "llm_direct":
knob_values = requested_knobs
primary = _llm_direct_spec(knob_values)
else:
base_spec = _difficulty_spec(difficulty)
knob_values = _difficulty_knobs(str(base_spec["key"]), requested_knobs)
primary = _spec_with_knobs(base_spec, knob_values)
start_seed = int(seed if seed is not None else int.from_bytes(os.urandom(4), "little") % 1_000_000)
# One candidate still runs many parallel rollout envs; avoid the old slow
# best-of-many map-generation loop, but never allow a zero-attempt certify.
retry_count = 1 if mode == "llm_direct" else max(1, int(primary.get("retries", 1) or 1))
attempts: list[tuple[dict[str, Any], int]] = [
(primary, start_seed + i * 9973) for i in range(retry_count)
]
attempt_timings: list[dict[str, Any]] = []
candidates: list[dict[str, Any]] = []
best_uncertified: dict[str, Any] | None = None
best_stage = 0.0
stop_after_first_certified = True
def remember_uncertified(
*,
cfg: V2Config,
frames: list[dict[str, Any]],
stats: dict[str, Any],
spec: dict[str, Any],
vibe_plan: dict[str, Any],
trial_seed: int,
selected: int,
eval_diag: dict[str, Any],
selected_success: bool,
extra_diag: dict[str, Any] | None = None,
) -> None:
nonlocal best_uncertified
if not frames:
return
merged_diag = dict(eval_diag)
if extra_diag:
merged_diag.update(extra_diag)
fallback_rank = (
1.0 if selected_success else 0.0,
float(_max_stage(frames)),
float(stats.get("eval_progress", 0.0) or 0.0),
float(stats.get("eval_success", 0.0) or 0.0),
float(len(frames)),
)
current_rank = best_uncertified["rank"] if best_uncertified is not None else None
if current_rank is None or fallback_rank > current_rank:
best_uncertified = {
"rank": fallback_rank,
"checkpoint": checkpoint,
"cfg": cfg,
"frames": frames,
"stats": stats,
"difficulty": spec,
"vibe_plan": vibe_plan,
"seed": int(trial_seed),
"selected_attempt": int(selected),
"eval_diag": merged_diag,
}
for spec, trial_seed in attempts:
if mode == "llm_direct":
vibe_plan, setup_fn = _setup_llm_direct_attempt(
vibe=vibe,
difficulty_key=str(spec["key"]),
spec=spec,
trial_seed=int(trial_seed),
direct_platforms=direct_platforms,
)
else:
vibe_plan = _build_vibe_plan(vibe, str(spec["key"]), knob_values)
configure_motif_mapgen(**vibe_plan["params"])
setup_fn = None
cfg = _stage_config(base_cfg, spec, trial_seed, vibe_plan)
stats, frames, success, selected, eval_diag = _evaluate_trial_fast(model, cfg, setup_fn=setup_fn)
attempt_timings.append({
"seed": int(trial_seed),
"difficulty": str(spec["key"]),
"generation_mode": generation_mode,
**eval_diag,
})
best_stage = max(best_stage, _max_stage(frames))
if bool(success):
first_frame = frames[0] if frames else {}
platforms = first_frame.get("platforms", []) if isinstance(first_frame, dict) else []
xy_span, z_span = _platform_span(platforms if isinstance(platforms, list) else [])
max_span = _max_layout_span(str(spec["key"]))
if xy_span > max_span:
layout_diag = {
"rejected_reason": "layout_span",
"layout_xy_span": float(xy_span),
"layout_z_span": float(z_span),
"layout_xy_span_limit": float(max_span),
}
attempt_timings[-1].update(layout_diag)
remember_uncertified(
cfg=cfg,
frames=frames,
stats=stats,
spec=spec,
vibe_plan=vibe_plan,
trial_seed=int(trial_seed),
selected=int(selected),
eval_diag=eval_diag,
selected_success=True,
extra_diag=layout_diag,
)
continue
score = _trial_difficulty_score(cfg, frames, stats)
candidates.append({
"score": score,
"checkpoint": checkpoint,
"cfg": cfg,
"frames": frames,
"stats": stats,
"difficulty": spec,
"vibe_plan": vibe_plan,
"seed": int(trial_seed),
"selected_attempt": int(selected),
"eval_diag": eval_diag,
})
if stop_after_first_certified:
break
else:
remember_uncertified(
cfg=cfg,
frames=frames,
stats=stats,
spec=spec,
vibe_plan=vibe_plan,
trial_seed=int(trial_seed),
selected=int(selected),
eval_diag=eval_diag,
selected_success=False,
)
if candidates:
winner = max(candidates, key=lambda candidate: float(candidate["score"]))
diagnostics = {
"runtime": _runtime_report(model),
"model_load_seconds": load_seconds,
"attempts": attempt_timings,
"latest_attempt": winner["eval_diag"],
"certified_candidate_count": len(candidates),
"selected_seed": int(winner["seed"]),
"selection_score": float(winner["score"]),
"selection_policy": "highest certified difficulty score across requested-spec seeds",
"requested_knobs": requested_knobs,
"effective_knobs": knob_values,
}
payload = _trial_payload(
winner["checkpoint"],
winner["cfg"],
winner["frames"],
True,
winner["stats"],
difficulty=winner["difficulty"],
vibe_plan=winner["vibe_plan"],
seed=int(winner["seed"]),
certified=True,
selected_attempt=int(winner["selected_attempt"]),
diagnostics=diagnostics,
)
return payload
if best_uncertified is not None:
diagnostics = {
"runtime": _runtime_report(model),
"model_load_seconds": load_seconds,
"attempts": attempt_timings,
"latest_attempt": best_uncertified["eval_diag"],
"certified_candidate_count": 0,
"selected_seed": int(best_uncertified["seed"]),
"selection_policy": "highest progress uncertified attempt across requested-spec seeds",
"requested_knobs": requested_knobs,
"effective_knobs": knob_values,
"failure_reason": (
f"certification failed for {primary['key']} after {len(attempt_timings)} attempts; "
f"best_stage={best_stage:.2f}"
),
}
payload = _trial_payload(
best_uncertified["checkpoint"],
best_uncertified["cfg"],
best_uncertified["frames"],
False,
best_uncertified["stats"],
difficulty=best_uncertified["difficulty"],
vibe_plan=best_uncertified["vibe_plan"],
seed=int(best_uncertified["seed"]),
certified=False,
selected_attempt=int(best_uncertified["selected_attempt"]),
diagnostics=diagnostics,
)
return payload
raise RuntimeError("certification failed before producing any usable rollout frames")
def _certify_stream(
*,
difficulty: str,
vibe: str,
seed: int | None,
generation_mode: str,
verticality: float | int | None,
traps: float | int | None,
loopiness: float | int | None,
precision: float | int | None,
length: float | int | None,
jump_gap: float | int | None,
platform_size: float | int | None,
decoys: float | int | None,
elevation_scale: float | int | None,
turniness: float | int | None,
tiny_platforms: float | int | None,
large_platforms: float | int | None,
unintuitive: float | int | None,
emit: Callable[[dict[str, Any]], None],
) -> None:
"""Run _certify_inner and emit each trial payload as a `done` event."""
direct_platforms: dict[str, Any] | None = None
if generation_mode == "llm_direct":
requested_knobs = _knobs(
verticality,
traps,
loopiness,
precision,
length,
jump_gap,
platform_size,
decoys,
elevation_scale,
turniness,
tiny_platforms,
large_platforms,
unintuitive,
)
spec = _llm_direct_spec(requested_knobs)
emit({
"type": "status",
"message": "streaming llm platform json",
"generation_mode": generation_mode,
"route_jumps": int(spec["route_jumps"]),
"distractors": int(spec["distractors"]),
})
direct_platforms = _request_direct_platforms_with_llm_stream(
vibe,
str(spec["key"]),
int(spec["route_jumps"]),
int(spec["distractors"]),
emit,
)
emit({"type": "status", "message": "certifying streamed llm map", "generation_mode": generation_mode})
payload = _certify_inner(
difficulty=difficulty,
vibe=vibe,
seed=seed,
generation_mode=generation_mode,
verticality=verticality,
traps=traps,
loopiness=loopiness,
precision=precision,
length=length,
jump_gap=jump_gap,
platform_size=platform_size,
decoys=decoys,
elevation_scale=elevation_scale,
turniness=turniness,
tiny_platforms=tiny_platforms,
large_platforms=large_platforms,
unintuitive=unintuitive,
direct_platforms=direct_platforms,
)
emit({"type": "done", "trial": payload})
def _setup_llm_direct_attempt(
*,
vibe: str,
difficulty_key: str,
spec: dict[str, Any],
trial_seed: int,
direct_platforms: dict[str, Any] | None = None,
) -> tuple[dict[str, Any], Callable[[FastFloatingBeaconEnv], None]]:
"""Call the LLM to get a platform list and build a setup callback for the env."""
if not _llm_in_use():
raise RuntimeError("LLM direct path requires MAPGEN_LLM_API_KEY (or OPENROUTER_API_KEY) and MAPGEN_LLM=auto")
route_jumps = int(spec["route_jumps"])
distractors = int(spec["distractors"])
if direct_platforms is not None:
result = direct_platforms
else:
result = _request_direct_platforms_with_llm(vibe, difficulty_key, route_jumps, distractors)
if not result.get("ok"):
raise RuntimeError(f"LLM did not produce a usable platform list: {result.get('reason')}")
platforms = result
def setup_fn(env: FastFloatingBeaconEnv) -> None:
_apply_direct_platforms(env, platforms)
vibe_plan = {
"theme": "llm direct platforms",
"mood": "out of distribution",
"tags": ["llm-direct", "ood"],
"knobs": {},
"params": {},
"raw_vibe": str(vibe or "").strip(),
"direct_platforms": {
"source": "llm",
"model": _llm_model(),
"seed": int(trial_seed),
"route_count": len(platforms.get("route", [])),
"extras_count": len(platforms.get("extras", [])),
},
}
return vibe_plan, setup_fn
def _select_rollout(frames_by_env: list[list[dict[str, Any]]], successes: list[bool]) -> int:
return max(
range(len(frames_by_env)),
key=lambda i: (
1 if bool(successes[i]) else 0,
_max_stage(frames_by_env[i]),
len(frames_by_env[i]),
),
)
def _max_stage(frames: list[dict[str, Any]]) -> float:
return max((float(frame.get("stage", 0.0) or 0.0) for frame in frames), default=0.0)
def _platform_span(platforms: list[Any]) -> tuple[float, float]:
points: list[tuple[float, float, float]] = []
for platform in platforms:
if not isinstance(platform, (list, tuple)) or len(platform) < 3:
continue
try:
points.append((float(platform[0]), float(platform[1]), float(platform[2])))
except (TypeError, ValueError):
continue
if not points:
return 0.0, 0.0
xs = [point[0] for point in points]
ys = [point[1] for point in points]
zs = [point[2] for point in points]
xy_span = ((max(xs) - min(xs)) ** 2 + (max(ys) - min(ys)) ** 2) ** 0.5
return float(xy_span), float(max(zs) - min(zs))
def _max_layout_span(difficulty_key: str) -> float:
return {
"rookie": 80.0,
"standard": 110.0,
"cursed": 155.0,
"nightmare": 190.0,
}.get(str(difficulty_key or "standard"), 110.0)
def _route_turn_score(platforms: list[Any], route_len: int) -> float:
if route_len < 3:
return 0.0
route = []
for platform in platforms[:route_len]:
if not isinstance(platform, (list, tuple)) or len(platform) < 2:
continue
try:
route.append((float(platform[0]), float(platform[1])))
except (TypeError, ValueError):
continue
if len(route) < 3:
return 0.0
total = 0.0
for index in range(1, len(route) - 1):
ax = route[index][0] - route[index - 1][0]
ay = route[index][1] - route[index - 1][1]
bx = route[index + 1][0] - route[index][0]
by = route[index + 1][1] - route[index][1]
alen = (ax * ax + ay * ay) ** 0.5
blen = (bx * bx + by * by) ** 0.5
if alen <= 1.0e-6 or blen <= 1.0e-6:
continue
dot = max(-1.0, min(1.0, (ax * bx + ay * by) / (alen * blen)))
total += abs(torch.acos(torch.tensor(dot)).item())
return float(total)
def _trial_difficulty_score(cfg: V2Config, frames: list[dict[str, Any]], stats: dict[str, Any]) -> float:
first = frames[0] if frames else {}
terminal = frames[-1] if frames else {}
platforms = first.get("platforms", []) if isinstance(first, dict) else []
sizes = first.get("sizes", []) if isinstance(first, dict) else []
route_len = int(getattr(cfg, "route_jumps", 1)) + 1
route_jumps = max(1, route_len - 1)
distractors = int(getattr(cfg, "distractors", 0))
par_steps = float(terminal.get("step", max(0, len(frames) - 1)) or 0.0)
eval_success = max(0.0, min(1.0, float(stats.get("eval_success", 1.0) or 0.0)))
eval_progress = max(0.0, min(1.0, float(stats.get("eval_progress", 1.0) or 0.0)))
xy_span, z_span = _platform_span(platforms if isinstance(platforms, list) else [])
turn_score = _route_turn_score(platforms if isinstance(platforms, list) else [], route_len)
tiny_count = 0
if isinstance(sizes, list):
for size in sizes[:route_len]:
if not isinstance(size, (list, tuple)) or len(size) < 2:
continue
try:
if min(float(size[0]), float(size[1])) < 0.78:
tiny_count += 1
except (TypeError, ValueError):
continue
max_score_span = 190.0 if route_jumps >= 25 else (155.0 if route_jumps >= 20 else 110.0)
xy_span = min(xy_span, max_score_span)
return float(
par_steps * 0.55
+ route_jumps * 3.0
+ distractors * 1.15
+ xy_span * 0.32
+ z_span * 2.2
+ turn_score * 7.0
+ tiny_count * 4.5
+ (1.0 - eval_success) * 170.0
+ (1.0 - eval_progress) * 35.0
)
def _trial_payload(
checkpoint: dict[str, Any],
cfg: V2Config,
frames: list[dict[str, Any]],
success: bool,
stats: dict[str, Any],
*,
difficulty: dict[str, Any],
vibe_plan: dict[str, Any],
seed: int,
certified: bool,
selected_attempt: int,
diagnostics: dict[str, Any] | None = None,
) -> dict[str, Any]:
first = frames[0] if frames else {}
terminal = frames[-1] if frames else {}
dt = float(getattr(cfg, "dt", 0.05))
par_steps = int(terminal.get("step", max(0, len(frames) - 1)) or 0)
par_time = par_steps * dt
trial_id = _trial_id(seed, difficulty["key"], vibe_plan["raw_vibe"], certified, par_steps)
payload = {
"trial_id": trial_id,
"status": "certified" if certified else "uncertified",
"certified": bool(certified),
"seed": int(seed),
"difficulty": difficulty["key"],
"difficulty_label": difficulty["label"],
"vibe": vibe_plan["raw_vibe"],
"vibe_plan": {key: value for key, value in vibe_plan.items() if key != "params"},
"map": {
"platforms": first.get("platforms", []),
"sizes": first.get("sizes", []),
"goal": first.get("goal", int(getattr(cfg, "route_jumps", 1)) - 1),
"routeMode": first.get("routeMode", "route_free_goal"),
"theme": vibe_plan["theme"],
"mood": vibe_plan["mood"],
},
"bot": {
"name": "Tiny v37",
"success": bool(success),
"par_time": float(par_time),
"par_steps": int(par_steps),
"max_stage": float(_max_stage(frames)),
"selected_attempt": int(selected_attempt),
"eval_success": float(stats.get("eval_success", 0.0) or 0.0),
"eval_progress": float(stats.get("eval_progress", 0.0) or 0.0),
"checkpoint": str(CHECKPOINT_PATH.relative_to(ROOT)) if CHECKPOINT_PATH.is_relative_to(ROOT) else str(CHECKPOINT_PATH),
"planner_mode": planner_mode_for_state(checkpoint["model"]),
},
"replay": {
"frames": frames,
"frame_count": len(frames),
"dt": dt,
},
"config": plain(cfg),
"debug": {
"physics_parity": _physics_parity_report(cfg),
"route_observation": "none",
"certification": "policy rollout in canonical Python env; user sees recorded successful states as ghost",
"trialing": diagnostics or {},
},
}
_trial_cache[trial_id] = payload
write_json(TRIAL_DIR / f"{trial_id}.json", payload, compact=True)
return payload
def _trial_id(seed: int, difficulty: str, vibe: str, certified: bool, par_steps: int) -> str:
digest = hashlib.sha1(f"{seed}:{difficulty}:{vibe}:{certified}:{par_steps}".encode("utf-8")).hexdigest()[:10]
return f"trial_{difficulty}_{seed}_{digest}"
def _load_trial(trial_id: str) -> dict[str, Any] | None:
if trial_id in _trial_cache:
return _trial_cache[trial_id]
path = TRIAL_DIR / f"{trial_id}.json"
if not path.exists():
return None
import json
payload = json.loads(path.read_text(encoding="utf-8"))
_trial_cache[trial_id] = payload
return payload
def _safe_stem(value: Any, *, default: str = "map") -> str:
text = re.sub(r"[^a-zA-Z0-9_.-]+", "_", str(value or "").strip()).strip("._-")
return text[:96] or default
def _local_request_only(request: Request) -> None:
host = (request.client.host if request.client else "") or ""
if host in {"127.0.0.1", "::1", "localhost"}:
return
raise PermissionError("saving sample maps is local-only")
def _saved_map_path(saved_id: str) -> Path:
return SAVED_MAPS_DIR / f"{_safe_stem(saved_id, default='sample')}.json"
def _saved_map_curated_path(saved_id: str) -> Path:
return SAVED_MAPS_CURATED_DIR / f"{_safe_stem(saved_id, default='sample')}.json"
def _iter_saved_map_paths() -> list[Path]:
return [
*sorted(SAVED_MAPS_CURATED_DIR.glob("*.json")),
*sorted(SAVED_MAPS_DIR.glob("*.json")),
]
def _read_saved_map_file(path: Path) -> dict[str, Any] | None:
try:
payload = json.loads(path.read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError):
return None
return payload if isinstance(payload, dict) else None
def _saved_map_id(trial: dict[str, Any]) -> str:
trial_id = str(trial.get("trial_id") or "")
difficulty = _safe_stem(trial.get("difficulty") or "sample", default="sample")
seed = int(trial.get("seed", 0) or 0)
digest = hashlib.sha1(trial_id.encode("utf-8")).hexdigest()[:10]
return f"sample_{difficulty}_{seed}_{digest}"
def _saved_map_name(trial: dict[str, Any], name: str | None) -> str:
if name:
return _clean_text(name, default="Saved Map", limit=48)
difficulty = _clean_text(trial.get("difficulty_label") or trial.get("difficulty"), default="Sample", limit=24)
seed = int(trial.get("seed", 0) or 0)
theme = _clean_text((trial.get("map") or {}).get("theme"), default="", limit=24)
if theme and theme.lower() not in {"floating platforms", "llm direct platforms"}:
return _clean_text(f"{difficulty} {theme}", default=f"{difficulty} {seed}", limit=48)
return _clean_text(f"{difficulty} {seed}", default="Saved Map", limit=48)
def _saved_map_metadata(saved: dict[str, Any], *, path: Path | None = None) -> dict[str, Any]:
trial = saved.get("trial") if isinstance(saved.get("trial"), dict) else saved
trial_map = trial.get("map") if isinstance(trial.get("map"), dict) else {}
bot = trial.get("bot") if isinstance(trial.get("bot"), dict) else {}
replay = trial.get("replay") if isinstance(trial.get("replay"), dict) else {}
platforms = trial_map.get("platforms") if isinstance(trial_map.get("platforms"), list) else []
sizes = trial_map.get("sizes") if isinstance(trial_map.get("sizes"), list) else []
saved_id = str(saved.get("id") or _saved_map_id(trial))
load_id = _safe_stem(path.stem if path is not None else saved_id, default=saved_id or "sample")
difficulty = str(trial.get("difficulty") or "standard")
par_time = float(bot.get("par_time", 0.0) or 0.0)
goal = int(trial_map.get("goal", max(0, len(platforms) - 1)) or 0)
return {
"id": saved_id,
"load_id": load_id,
"trial_id": str(trial.get("trial_id") or ""),
"name": _clean_text(saved.get("name") or _saved_map_name(trial, None), default=saved_id, limit=48),
"difficulty": difficulty,
"difficulty_label": trial.get("difficulty_label") or difficulty.title(),
"seed": int(trial.get("seed", 0) or 0),
"certified": bool(trial.get("certified")),
"jumps": max(0, goal),
"platform_count": len(platforms),
"frame_count": int(replay.get("frame_count", len(replay.get("frames", []) or [])) or 0),
"par_time": par_time,
"tempo": "fast" if par_time and par_time < 8 else "technical" if par_time and par_time < 18 else "long",
"theme": trial_map.get("theme", ""),
"mood": trial_map.get("mood", ""),
"preview_platforms": platforms,
"preview_sizes": sizes,
"preview_goal": goal,
"preview_config": trial.get("config") if isinstance(trial.get("config"), dict) else {},
"saved_at": int(saved.get("saved_at", 0) or 0),
}
def _save_trial_as_sample(trial_id: str, *, name: str | None = None) -> dict[str, Any]:
clean_trial_id = _safe_stem(trial_id, default="")
if clean_trial_id != str(trial_id):
raise ValueError("invalid trial_id")
trial = _load_trial(clean_trial_id)
if trial is None:
raise FileNotFoundError(f"trial not found: {clean_trial_id}")
if not trial.get("replay", {}).get("frames"):
raise ValueError("trial has no replay frames")
saved_id = _saved_map_id(trial)
saved = {
"id": saved_id,
"trial_id": clean_trial_id,
"name": _saved_map_name(trial, name),
"saved_at": int(time.time()),
"source": "curated",
"trial": trial,
}
path = _saved_map_curated_path(saved_id)
write_json(path, saved, compact=True)
_saved_maps_cache[saved_id] = saved
return {
"status": "ok",
"saved_map": _saved_map_metadata(saved, path=path),
"path": str(path.relative_to(ROOT)),
}
def _load_saved_map(saved_id: str) -> dict[str, Any] | None:
clean_id = _safe_stem(saved_id, default="")
if not clean_id:
return None
cached = _saved_maps_cache.get(clean_id)
if cached is not None:
return cached
for path in (_saved_map_curated_path(clean_id), _saved_map_path(clean_id)):
if not path.exists():
continue
payload = _read_saved_map_file(path)
if payload is None:
continue
metadata = _saved_map_metadata(payload, path=path)
_saved_maps_cache[clean_id] = payload
_saved_maps_cache[str(metadata["id"])] = payload
_saved_maps_cache[str(metadata["load_id"])] = payload
_saved_maps_cache[path.stem] = payload
return payload
for path in _iter_saved_map_paths():
payload = _read_saved_map_file(path)
if payload is None:
continue
metadata = _saved_map_metadata(payload, path=path)
raw_matches = {
path.stem,
str(metadata.get("load_id") or ""),
str(metadata.get("id") or ""),
str(metadata.get("trial_id") or ""),
str(metadata.get("name") or ""),
}
safe_matches = {_safe_stem(match, default="") for match in raw_matches}
if clean_id in raw_matches or clean_id in safe_matches:
_saved_maps_cache[clean_id] = payload
_saved_maps_cache[str(metadata["id"])] = payload
_saved_maps_cache[str(metadata["load_id"])] = payload
_saved_maps_cache[path.stem] = payload
return payload
return None
def _list_saved_maps() -> list[dict[str, Any]]:
entries: list[dict[str, Any]] = []
seen_ids: set[str] = set()
for path in _iter_saved_map_paths():
payload = _read_saved_map_file(path)
if payload is None:
continue
metadata = _saved_map_metadata(payload, path=path)
saved_id = str(metadata.get("load_id") or metadata.get("id") or path.stem)
if saved_id in seen_ids:
continue
seen_ids.add(saved_id)
entries.append(metadata)
entries.sort(key=lambda item: (int(item.get("saved_at", 0) or 0), str(item.get("id", ""))), reverse=True)
return entries
def _frame_from_env(env: FastFloatingBeaconEnv) -> dict[str, Any]:
platforms = env.platforms[0].cpu().tolist()
sizes = env.sizes[0].cpu().tolist()
cfg = env.cfg
return {
"platforms": platforms,
"sizes": sizes,
"goal": int(env.route_len) - 1,
"goalStage": int(env.route_len) - 1,
"config": plain(cfg),
}
@app.api(name="generate_certified_trial")
def generate_certified_trial(
difficulty: str = "standard",
vibe: str = "cursed vertical wood ruins with fake-looking jumps",
seed: int | None = None,
generation_mode: str = "procedural",
verticality: float = KNOB_DEFAULTS["verticality"],
traps: float = KNOB_DEFAULTS["traps"],
loopiness: float = KNOB_DEFAULTS["loopiness"],
precision: float = KNOB_DEFAULTS["precision"],
length: float = KNOB_DEFAULTS["length"],
jump_gap: float = KNOB_DEFAULTS["jump_gap"],
platform_size: float = KNOB_DEFAULTS["platform_size"],
decoys: float = KNOB_DEFAULTS["decoys"],
elevation_scale: float = KNOB_DEFAULTS["elevation_scale"],
turniness: float = KNOB_DEFAULTS["turniness"],
tiny_platforms: float = KNOB_DEFAULTS["tiny_platforms"],
large_platforms: float = KNOB_DEFAULTS["large_platforms"],
unintuitive: float = KNOB_DEFAULTS["unintuitive"],
) -> dict[str, Any]:
with _lock:
try:
return _certify(
difficulty=difficulty,
vibe=vibe,
seed=seed,
generation_mode=_generation_mode_alias(generation_mode),
verticality=verticality,
traps=traps,
loopiness=loopiness,
precision=precision,
length=length,
jump_gap=jump_gap,
platform_size=platform_size,
decoys=decoys,
elevation_scale=elevation_scale,
turniness=turniness,
tiny_platforms=tiny_platforms,
large_platforms=large_platforms,
unintuitive=unintuitive,
)
except Exception as exc:
traceback.print_exc()
return {
"status": "error",
"error": str(exc),
"error_type": type(exc).__name__,
"traceback": traceback.format_exc(),
}
@app.api(name="get_trial")
def get_trial(trial_id: str) -> dict[str, Any]:
trial = _load_trial(trial_id)
if trial is None:
return {"status": "missing", "trial_id": trial_id}
return trial
@app.api(name="analyze_attempt")
def analyze_attempt(trial_id: str, user_time: float = 0.0, deaths: int = 0) -> dict[str, Any]:
trial = _load_trial(trial_id)
if trial is None:
return {"status": "missing", "trial_id": trial_id}
bot_time = float(trial.get("bot", {}).get("par_time", 0.0) or 0.0)
delta = float(user_time) - bot_time
return {
"status": "analyzed",
"trial_id": trial_id,
"bot_time": bot_time,
"user_time": float(user_time),
"delta": delta,
"deaths": int(deaths),
"verdict": "beat_the_bot" if deaths == 0 and delta < 0 else "bot_survived",
}
@app.api(name="runtime_diagnostics")
def runtime_diagnostics() -> dict[str, Any]:
model: torch.nn.Module | None = None
try:
_checkpoint, _cfg, model = _load_checkpoint()
except Exception:
model = None
return {
"runtime": _runtime_report(model),
"physics_defaults": PHYSICS_DEFAULTS,
"trial_snapshot_strategy": "batched device rollout, selected rollout JSON materialization",
}
@app.api(name="generate_map")
def generate_map(seed: int = 7, route_jumps: int = 12, distractors: int = 6) -> dict[str, Any]:
env = _make_env(seed=seed, route_jumps=route_jumps, distractors=distractors)
env.generate_maps()
return _frame_from_env(env)
@app.get("/api/generate_certified_trial")
def generate_certified_trial_get(
difficulty: str = "standard",
vibe: str = "cursed vertical wood ruins with fake-looking jumps",
seed: int | None = None,
generation_mode: str = "procedural",
verticality: float = KNOB_DEFAULTS["verticality"],
traps: float = KNOB_DEFAULTS["traps"],
loopiness: float = KNOB_DEFAULTS["loopiness"],
precision: float = KNOB_DEFAULTS["precision"],
length: float = KNOB_DEFAULTS["length"],
jump_gap: float = KNOB_DEFAULTS["jump_gap"],
platform_size: float = KNOB_DEFAULTS["platform_size"],
decoys: float = KNOB_DEFAULTS["decoys"],
elevation_scale: float = KNOB_DEFAULTS["elevation_scale"],
turniness: float = KNOB_DEFAULTS["turniness"],
tiny_platforms: float = KNOB_DEFAULTS["tiny_platforms"],
large_platforms: float = KNOB_DEFAULTS["large_platforms"],
unintuitive: float = KNOB_DEFAULTS["unintuitive"],
) -> JSONResponse:
with _lock:
try:
return JSONResponse(content=_certify(
difficulty=difficulty,
vibe=vibe,
seed=seed,
generation_mode=_generation_mode_alias(generation_mode),
verticality=verticality,
traps=traps,
loopiness=loopiness,
precision=precision,
length=length,
jump_gap=jump_gap,
platform_size=platform_size,
decoys=decoys,
elevation_scale=elevation_scale,
turniness=turniness,
tiny_platforms=tiny_platforms,
large_platforms=large_platforms,
unintuitive=unintuitive,
))
except Exception as exc:
traceback.print_exc()
return JSONResponse(
content={
"status": "error",
"error": str(exc),
"error_type": type(exc).__name__,
"traceback": traceback.format_exc(),
},
status_code=500,
)
@app.get("/api/generate_certified_trial_stream")
def generate_certified_trial_stream_get(
difficulty: str = "standard",
vibe: str = "cursed vertical wood ruins with fake-looking jumps",
seed: int | None = None,
generation_mode: str = "procedural",
verticality: float = KNOB_DEFAULTS["verticality"],
traps: float = KNOB_DEFAULTS["traps"],
loopiness: float = KNOB_DEFAULTS["loopiness"],
precision: float = KNOB_DEFAULTS["precision"],
length: float = KNOB_DEFAULTS["length"],
jump_gap: float = KNOB_DEFAULTS["jump_gap"],
platform_size: float = KNOB_DEFAULTS["platform_size"],
decoys: float = KNOB_DEFAULTS["decoys"],
elevation_scale: float = KNOB_DEFAULTS["elevation_scale"],
turniness: float = KNOB_DEFAULTS["turniness"],
tiny_platforms: float = KNOB_DEFAULTS["tiny_platforms"],
large_platforms: float = KNOB_DEFAULTS["large_platforms"],
unintuitive: float = KNOB_DEFAULTS["unintuitive"],
) -> StreamingResponse:
"""Stream JSONL events. The LLM direct path emits `llm_text_delta` per
chunk so the user can watch the platform JSON being written.
"""
mode = _generation_mode_alias(generation_mode)
events: queue.Queue[Any] = queue.Queue()
sentinel = object()
def emit(event: dict[str, Any]) -> None:
events.put(event)
def worker() -> None:
try:
with _lock:
emit({"type": "status", "message": "starting", "generation_mode": mode})
_certify_stream(
difficulty=difficulty,
vibe=vibe,
seed=seed,
generation_mode=mode,
verticality=verticality,
traps=traps,
loopiness=loopiness,
precision=precision,
length=length,
jump_gap=jump_gap,
platform_size=platform_size,
decoys=decoys,
elevation_scale=elevation_scale,
turniness=turniness,
tiny_platforms=tiny_platforms,
large_platforms=large_platforms,
unintuitive=unintuitive,
emit=emit,
)
except Exception as exc:
traceback.print_exc()
emit({
"type": "error",
"message": str(exc),
"error": str(exc),
"error_type": type(exc).__name__,
})
finally:
events.put(sentinel)
thread = threading.Thread(target=worker, daemon=True)
thread.start()
def event_stream():
while True:
event = events.get()
if event is sentinel:
break
yield _stream_event(event)
return StreamingResponse(
event_stream(),
media_type="application/x-ndjson",
headers={"Cache-Control": "no-store", "X-Accel-Buffering": "no"},
)
@app.get("/api/trials/{trial_id}")
def get_trial_get(trial_id: str) -> JSONResponse:
trial = _load_trial(trial_id)
if trial is None:
return JSONResponse(content={"status": "missing", "trial_id": trial_id}, status_code=404)
return JSONResponse(content=trial)
@app.get("/api/saved_maps")
def list_saved_maps_get() -> JSONResponse:
maps = _list_saved_maps()
return JSONResponse(
content={"status": "ok", "count": len(maps), "maps": maps},
headers={"Cache-Control": "no-store"},
)
@app.post("/api/saved_maps")
async def save_saved_map_post(request: Request) -> JSONResponse:
try:
_local_request_only(request)
body = await request.json()
if not isinstance(body, dict):
raise ValueError("expected JSON object")
return JSONResponse(content=_save_trial_as_sample(
str(body.get("trial_id") or ""),
name=body.get("name"),
))
except Exception as exc:
traceback.print_exc()
status = 403 if isinstance(exc, PermissionError) else 500
return JSONResponse(
content={"status": "error", "error": str(exc), "error_type": type(exc).__name__},
status_code=status,
)
@app.get("/api/save_sample_map")
def save_saved_map_get(request: Request, trial_id: str, name: str | None = None) -> JSONResponse:
try:
_local_request_only(request)
return JSONResponse(content=_save_trial_as_sample(trial_id, name=name))
except Exception as exc:
traceback.print_exc()
status = 403 if isinstance(exc, PermissionError) else 500
return JSONResponse(
content={"status": "error", "error": str(exc), "error_type": type(exc).__name__},
status_code=status,
)
@app.get("/api/saved_maps/{saved_id}")
def get_saved_map_get(saved_id: str) -> JSONResponse:
saved = _load_saved_map(saved_id)
if saved is None:
return JSONResponse(content={"status": "missing", "saved_id": saved_id}, status_code=404)
trial = saved.get("trial") if isinstance(saved.get("trial"), dict) else saved
return JSONResponse(
content={"status": "ok", "map": _saved_map_metadata(saved), "trial": trial},
headers={"Cache-Control": "no-store"},
)
@app.get("/api/runtime_diagnostics")
def runtime_diagnostics_get() -> JSONResponse:
return JSONResponse(content=runtime_diagnostics())
@app.get("/api/generate_map")
def generate_map_get(seed: int = 7, route_jumps: int = 12, distractors: int = 6) -> JSONResponse:
env = _make_env(seed=seed, route_jumps=route_jumps, distractors=distractors)
env.generate_maps()
return JSONResponse(content=_frame_from_env(env))
def _map_id(vibe: str, difficulty_key: str, seed: int, route_jumps: int, distractors: int) -> str:
digest = hashlib.sha1(
f"{APP_MAPGEN_VERSION}:{difficulty_key}:{int(seed)}:{int(route_jumps)}:{int(distractors)}:{vibe}".encode("utf-8")
).hexdigest()[:10]
return f"map_{difficulty_key}_{int(seed)}_{digest}"
def _map_path(map_id: str) -> Path:
return MAPS_DIR / f"{map_id}.json"
def _build_map_snapshot_from_env(
env: FastFloatingBeaconEnv,
*,
difficulty_key: str,
seed: int,
vibe_plan: dict[str, Any],
name: str | None = None,
) -> dict[str, Any]:
frame = _frame_from_env(env)
map_id = _map_id(
str(vibe_plan.get("raw_vibe") or ""),
difficulty_key,
int(seed),
int(getattr(env.cfg, "route_jumps", frame.get("goal", 0))),
int(getattr(env.cfg, "distractors", 0)),
)
return {
"id": map_id,
"name": _clean_text(name, default=f"{difficulty_key.title()} {seed}", limit=48),
"difficulty": str(difficulty_key),
"seed": int(seed),
"route_jumps": int(getattr(env.cfg, "route_jumps", 0)),
"distractors": int(getattr(env.cfg, "distractors", 0)),
"style": "floating_platforms",
"theme": vibe_plan.get("theme", "misty wood ruins"),
"mood": vibe_plan.get("mood", "cool teal fog"),
"tags": vibe_plan.get("tags", ["balanced"]),
"platforms": frame.get("platforms", []),
"sizes": frame.get("sizes", []),
"goal": int(frame.get("goal", 0)),
"config": frame.get("config", {}),
"vibe_plan": {key: value for key, value in vibe_plan.items() if key != "params"},
"params": vibe_plan.get("params", {}),
"generated_at": int(time.time()),
"mapgen_version": APP_MAPGEN_VERSION,
}
def _save_map_snapshot(snapshot: dict[str, Any]) -> Path:
path = _map_path(snapshot["id"])
write_json(path, snapshot, compact=True)
_maps_cache[snapshot["id"]] = snapshot
return path
def _load_map_snapshot(map_id: str) -> dict[str, Any] | None:
cached = _maps_cache.get(map_id)
if cached is not None:
return cached
path = _map_path(map_id)
if not path.exists():
return None
try:
payload = json.loads(path.read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError):
return None
_maps_cache[map_id] = payload
return payload
def _list_map_snapshots() -> list[dict[str, Any]]:
entries: list[dict[str, Any]] = []
for path in sorted(MAPS_DIR.glob("*.json")):
try:
payload = json.loads(path.read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError):
continue
entries.append(
{
"id": payload.get("id", path.stem),
"name": payload.get("name", path.stem),
"difficulty": payload.get("difficulty", "standard"),
"seed": int(payload.get("seed", 0)),
"route_jumps": int(payload.get("route_jumps", 0)),
"distractors": int(payload.get("distractors", 0)),
"style": payload.get("style", "floating_platforms"),
"theme": payload.get("theme", ""),
"mood": payload.get("mood", ""),
"tags": payload.get("tags", []),
"goal": int(payload.get("goal", 0)),
"platform_count": len(payload.get("platforms", []) or []),
"generated_at": int(payload.get("generated_at", 0)),
"mapgen_version": payload.get("mapgen_version", ""),
}
)
return entries
def _mapgen_llm_report() -> dict[str, Any]:
return {
"mode": _llm_mode(),
"provider": "openrouter",
"model": _llm_model(),
"configured": bool(_llm_api_key()),
"timeout_seconds": _llm_timeout(),
"in_use": _llm_in_use(),
}
@app.api(name="mapgen_config")
def mapgen_config() -> dict[str, Any]:
return {
"mapgen_version": APP_MAPGEN_VERSION,
"mapgen_llm": _mapgen_llm_report(),
"generation_modes": _generation_mode_labels(),
"default_generation_mode": "procedural",
"llm_direct_contract": (
"LLM returns short JSON only: {\"platforms\": [{x, y, z, w, d}, ...]}. "
"The platforms are ordered from start to goal; no distractors, labels, features, or route flags. "
"Backend validates bounds, runs the standard legalizer (separate_route_overlaps, "
"enforce_route_reach, etc.) and the trained policy is rolled out against the result."
),
}
@app.api(name="list_cached_maps")
def list_cached_maps() -> dict[str, Any]:
return {
"status": "ok",
"count": len(_list_map_snapshots()),
"maps": _list_map_snapshots(),
}
@app.api(name="get_cached_map")
def get_cached_map(map_id: str) -> dict[str, Any]:
snapshot = _load_map_snapshot(map_id)
if snapshot is None:
return {"status": "missing", "map_id": map_id}
return {"status": "ok", "map": snapshot}
@app.api(name="save_cached_map")
def save_cached_map(
difficulty: str = "standard",
vibe: str = "",
seed: int | None = None,
generation_mode: str = "procedural",
verticality: float = KNOB_DEFAULTS["verticality"],
traps: float = KNOB_DEFAULTS["traps"],
loopiness: float = KNOB_DEFAULTS["loopiness"],
precision: float = KNOB_DEFAULTS["precision"],
length: float = KNOB_DEFAULTS["length"],
jump_gap: float = KNOB_DEFAULTS["jump_gap"],
platform_size: float = KNOB_DEFAULTS["platform_size"],
decoys: float = KNOB_DEFAULTS["decoys"],
elevation_scale: float = KNOB_DEFAULTS["elevation_scale"],
turniness: float = KNOB_DEFAULTS["turniness"],
tiny_platforms: float = KNOB_DEFAULTS["tiny_platforms"],
large_platforms: float = KNOB_DEFAULTS["large_platforms"],
unintuitive: float = KNOB_DEFAULTS["unintuitive"],
name: str | None = None,
) -> dict[str, Any]:
"""Build a map (procedural or LLM direct) and save it to app/maps/.
Useful for local map authoring via curl/CLI without running the full
policy rollout. The same legalizer is applied to LLM-placed maps.
"""
if seed is None:
seed = int.from_bytes(os.urandom(4), "little") % 1_000_000
requested_knobs = _knobs(
verticality,
traps,
loopiness,
precision,
length,
jump_gap,
platform_size,
decoys,
elevation_scale,
turniness,
tiny_platforms,
large_platforms,
unintuitive,
)
mode = _generation_mode_alias(generation_mode)
if mode == "llm_direct":
base_knobs = requested_knobs
tuned_spec = _llm_direct_spec(base_knobs)
else:
spec = _difficulty_spec(difficulty)
base_knobs = _difficulty_knobs(str(spec["key"]), requested_knobs)
tuned_spec = _spec_with_knobs(spec, base_knobs)
route_jumps = int(tuned_spec["route_jumps"])
distractors = int(tuned_spec["distractors"])
if mode == "llm_direct":
if not _llm_in_use():
raise RuntimeError("LLM direct path requires MAPGEN_LLM_API_KEY (or OPENROUTER_API_KEY) and MAPGEN_LLM=auto")
result = _request_direct_platforms_with_llm(vibe, str(tuned_spec["key"]), route_jumps, distractors)
if not result.get("ok"):
raise RuntimeError(f"LLM did not produce a usable platform list: {result.get('reason')}")
env = _make_env(
seed=int(seed),
route_jumps=route_jumps,
distractors=distractors,
direct_platforms=result,
)
vibe_plan = {
"theme": "llm direct platforms",
"mood": "out of distribution",
"tags": ["llm-direct", "ood"],
"knobs": {},
"params": {},
"raw_vibe": str(vibe or "").strip(),
"direct_platforms": {
"source": "llm",
"model": _llm_model(),
"seed": int(seed),
"route_count": len(result.get("route", [])),
"extras_count": len(result.get("extras", [])),
},
}
else:
vibe_plan = _build_vibe_plan(vibe, str(spec["key"]), base_knobs)
env = _make_env(
seed=int(seed),
route_jumps=route_jumps,
distractors=distractors,
motif_params=vibe_plan.get("params", {}),
)
env.reset()
snapshot = _build_map_snapshot_from_env(
env,
difficulty_key=str(tuned_spec["key"]),
seed=int(seed),
vibe_plan=vibe_plan,
name=name,
)
_save_map_snapshot(snapshot)
return {
"status": "ok",
"map_id": snapshot["id"],
"platform_count": len(snapshot["platforms"]),
"tags": snapshot["tags"],
"theme": snapshot["theme"],
"mood": snapshot["mood"],
"used_llm": bool(vibe_plan.get("direct_platforms", {}).get("source") == "llm"),
"generation_mode": mode,
"direct_platforms": vibe_plan.get("direct_platforms", {}),
}
@app.get("/api/maps")
def list_cached_maps_get() -> JSONResponse:
return JSONResponse(
content={"status": "ok", "count": len(_list_map_snapshots()), "maps": _list_map_snapshots()},
headers={"Cache-Control": "public, max-age=60"},
)
@app.get("/api/maps/{map_id}")
def get_cached_map_get(map_id: str):
snapshot = _load_map_snapshot(map_id)
if snapshot is None:
return JSONResponse(content={"status": "missing", "map_id": map_id}, status_code=404)
return FileResponse(
_map_path(map_id),
media_type="application/json",
headers={"Cache-Control": "public, max-age=3600, immutable"},
)
@app.get("/api/mapgen_config")
def mapgen_config_get() -> JSONResponse:
return JSONResponse(content=mapgen_config())
@app.get("/api/save_cached_map")
def save_cached_map_get(
difficulty: str = "standard",
vibe: str = "",
seed: int | None = None,
generation_mode: str = "procedural",
verticality: float = KNOB_DEFAULTS["verticality"],
traps: float = KNOB_DEFAULTS["traps"],
loopiness: float = KNOB_DEFAULTS["loopiness"],
precision: float = KNOB_DEFAULTS["precision"],
length: float = KNOB_DEFAULTS["length"],
jump_gap: float = KNOB_DEFAULTS["jump_gap"],
platform_size: float = KNOB_DEFAULTS["platform_size"],
decoys: float = KNOB_DEFAULTS["decoys"],
elevation_scale: float = KNOB_DEFAULTS["elevation_scale"],
turniness: float = KNOB_DEFAULTS["turniness"],
tiny_platforms: float = KNOB_DEFAULTS["tiny_platforms"],
large_platforms: float = KNOB_DEFAULTS["large_platforms"],
unintuitive: float = KNOB_DEFAULTS["unintuitive"],
name: str | None = None,
) -> JSONResponse:
try:
return JSONResponse(content=save_cached_map(
difficulty=difficulty,
vibe=vibe,
seed=seed,
generation_mode=generation_mode,
verticality=verticality,
traps=traps,
loopiness=loopiness,
precision=precision,
length=length,
jump_gap=jump_gap,
platform_size=platform_size,
decoys=decoys,
elevation_scale=elevation_scale,
turniness=turniness,
tiny_platforms=tiny_platforms,
large_platforms=large_platforms,
unintuitive=unintuitive,
name=name,
))
except Exception as exc:
traceback.print_exc()
return JSONResponse(
content={"status": "error", "error": str(exc), "error_type": type(exc).__name__},
status_code=500,
)
frontend_dist = Path(__file__).resolve().parent / "frontend" / "dist"
@app.middleware("http")
async def spa_middleware(request: Request, call_next):
path = request.url.path
if path.startswith("/api"):
origin = request.headers.get("origin", "")
cors_headers = {
"Access-Control-Allow-Origin": origin if origin else "*",
"Access-Control-Allow-Methods": "GET,POST,OPTIONS",
"Access-Control-Allow-Headers": "content-type,authorization",
}
if request.method == "OPTIONS":
return JSONResponse(content={}, headers=cors_headers)
response = await call_next(request)
for key, value in cors_headers.items():
response.headers[key] = value
return response
if path.startswith("/gradio_api") or not frontend_dist.exists():
return await call_next(request)
target = (frontend_dist / path.lstrip("/")).resolve()
if target.is_file() and str(target).startswith(str(frontend_dist.resolve())):
return FileResponse(target)
index = frontend_dist / "index.html"
if index.exists():
return FileResponse(index)
return await call_next(request)
if __name__ == "__main__":
port = int(os.environ.get("PORT", 7860))
app.launch(server_port=port, show_error=True)