""" Prompt template loader — shared between self-play and the chat app. Loads prompt templates from per-category JSONL files with placeholder expansion ({player}, {target}, {region}, etc.) and filtering by mode (sudo/god/god_system) and call_type (model/gateway). Usage: from training.prompts.loader import load_prompts, load_manifest, expand_template # Self-play: load all sudo prompts prompts = load_prompts(mode_filter="sudo") # Chat app: get manifest for template selector UI manifest = load_manifest() # Expand a template with random values expanded = expand_template("sudo protect {region} for {target}") """ import json import random from pathlib import Path PROMPTS_DIR = Path(__file__).resolve().parent TEMPLATE_VARS = { "player": ["slingshooter08", "Ace13245", "TheBigBoss", "xXDragonSlayerXx"], "target": ["Ace13245", "TheBigBoss", "xXDragonSlayerXx", "slingshooter08"], "region": ["my-base", "spawn-zone", "pvp-arena", "vip-lounge", "farm-area"], "warp": ["arena", "spawn", "shop", "nether", "farm", "end"], "group": ["vip", "builder", "moderator", "default"], "world": ["world", "world_nether", "world_the_end"], } def expand_template(prompt: str, overrides: dict = None) -> str: """Replace {placeholder} tokens with random values. Args: prompt: Template string with {placeholder} tokens. overrides: Optional dict of placeholder -> value to use instead of random. e.g. {"player": "slingshooter08"} forces that player name. """ overrides = overrides or {} for key, values in TEMPLATE_VARS.items(): token = "{" + key + "}" while token in prompt: value = overrides.get(key, random.choice(values)) prompt = prompt.replace(token, value, 1) return prompt def load_manifest(prompts_dir: Path = PROMPTS_DIR) -> dict: """Load the prompt manifest with full metadata. Returns dict of category -> {file, mode, call_type, count}. Used by the chat app for template selection UI. """ manifest_path = prompts_dir / "manifest.json" if not manifest_path.exists(): return {} with open(manifest_path) as f: return json.load(f) def load_prompts(prompts_dir: Path = PROMPTS_DIR, mode_filter: str = None, call_type_filter: str = None, categories: list = None) -> dict[str, list[str]]: """Load prompt templates from per-category JSONL files. Args: prompts_dir: Directory containing manifest.json and prompt JSONL files. mode_filter: Only load categories matching this mode (sudo/god/god_system). call_type_filter: Only load categories matching call type (model/gateway). categories: Only load these specific category names. Returns: Dict mapping category name -> list of prompt template strings. """ manifest = load_manifest(prompts_dir) if not manifest: return {} prompts = {} for category, meta in manifest.items(): if categories and category not in categories: continue if mode_filter and meta.get("mode") not in (mode_filter, "mixed"): continue if call_type_filter and meta.get("call_type") != call_type_filter: continue filepath = prompts_dir / meta["file"] if not filepath.exists(): continue cat_prompts = [] with open(filepath) as f: for line in f: line = line.strip() if not line: continue entry = json.loads(line) cat_prompts.append(entry["prompt"]) if cat_prompts: prompts[category] = cat_prompts return prompts def load_prompt_entries(category: str, prompts_dir: Path = PROMPTS_DIR) -> list[dict]: """Load full prompt entries (with all metadata) for a single category. Returns list of dicts with prompt, category, mode, etc. Used by the chat app to populate the template editor. """ manifest = load_manifest(prompts_dir) meta = manifest.get(category) if not meta: return [] filepath = prompts_dir / meta["file"] if not filepath.exists(): return [] entries = [] with open(filepath) as f: for line in f: line = line.strip() if not line: continue entries.append(json.loads(line)) return entries