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)