Some checks failed
Architecture Lint / Linter Tests (pull_request) Successful in 9s
Smoke Test / smoke (pull_request) Failing after 8s
Validate Config / YAML Lint (pull_request) Failing after 5s
Validate Config / JSON Validate (pull_request) Successful in 18s
Validate Config / Python Syntax & Import Check (pull_request) Failing after 1m2s
Validate Config / Python Test Suite (pull_request) Has been skipped
Validate Config / Shell Script Lint (pull_request) Failing after 1m6s
Validate Config / Cron Syntax Check (pull_request) Successful in 13s
Validate Config / Deploy Script Dry Run (pull_request) Successful in 8s
Validate Config / Playbook Schema Validation (pull_request) Successful in 18s
Validate Training Data / validate (pull_request) Successful in 15s
PR Checklist / pr-checklist (pull_request) Successful in 6m22s
Architecture Lint / Lint Repository (pull_request) Failing after 28s
- Add scripts/generate_code_patterns_evennia_tower.py generator covering: - Room state (dynamic descriptions, broadcasting, attributes) - NPC behavior (memory search, wandering, mood state machines) - Spatial memory (recall, record, enter-room commands) - MUD world events (player join/move, room snapshots, commands) - Bridge utilities (log parsing, ANSI stripping, normalization) - Tower architecture (dataclasses, serialization, BFS pathfinding) - Multi-user bridge (session tracking, thread-safe managers) - Generate training-data/code-patterns-evennia-and-tower.jsonl with 1,000 valid JSONL problem->solution pairs. - All pairs validated: 1000 valid JSON objects, 6 domains. Closes #593
666 lines
24 KiB
Python
666 lines
24 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Generate 1,000 Problem→Solution training pairs for Evennia & Tower code patterns.
|
|
|
|
Part of timmy-config#593: Code Patterns: Evennia & Tower — 1K Problem→Solution Pairs.
|
|
|
|
Usage:
|
|
python scripts/generate_code_patterns_evennia_tower.py
|
|
python scripts/generate_code_patterns_evennia_tower.py --output /path/to/output.jsonl
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import random
|
|
from pathlib import Path
|
|
|
|
random.seed(593)
|
|
|
|
|
|
# ── Templates for problem→solution generation ──
|
|
|
|
ROOM_TEMPLATES = [
|
|
{
|
|
"problem": "Create an Evennia room typeclass that stores a memory-palace wing reference and exposes it as an attribute.",
|
|
"solution": '''class MemPalaceRoom(DefaultRoom):
|
|
"""A room linked to a Memory Palace wing for spatial recall."""
|
|
|
|
def at_object_creation(self):
|
|
super().at_object_creation()
|
|
self.db.wing = "default"
|
|
self.db.room_index = 0
|
|
self.db.topics = []
|
|
|
|
def get_display_name(self, looker, **kwargs):
|
|
name = super().get_display_name(looker, **kwargs)
|
|
wing = self.db.wing or "unknown"
|
|
return f"{{name}} ({{wing}})"
|
|
|
|
def return_appearance(self, looker, **kwargs):
|
|
appearance = super().return_appearance(looker, **kwargs)
|
|
topics = self.db.topics or []
|
|
if topics:
|
|
appearance += "\n|wTopics:|n " + ", ".join(topics)
|
|
return appearance''',
|
|
"imports": "from evennia import DefaultRoom",
|
|
"domain": "room state",
|
|
},
|
|
{
|
|
"problem": "Build an Evennia room that tracks dynamic state (light level, temperature) and updates its description based on that state.",
|
|
"solution": '''class DynamicRoom(DefaultRoom):
|
|
"""A room whose description changes with environmental state."""
|
|
|
|
def at_object_creation(self):
|
|
super().at_object_creation()
|
|
self.db.light_level = 100 # 0-100
|
|
self.db.temperature = 20 # celsius
|
|
self.db.base_desc = "A plain chamber."
|
|
|
|
def return_appearance(self, looker, **kwargs):
|
|
desc = self.db.base_desc
|
|
light = self.db.light_level
|
|
if light < 20:
|
|
desc += " It is nearly pitch black."
|
|
elif light < 50:
|
|
desc += " Shadows dance in the dim light."
|
|
else:
|
|
desc += " The room is well lit."
|
|
temp = self.db.temperature
|
|
if temp > 30:
|
|
desc += " Heat shimmers in the air."
|
|
elif temp < 10:
|
|
desc += " Frost coats the walls."
|
|
return desc + "\n" + super().return_appearance(looker, **kwargs).split("\n", 1)[-1]''',
|
|
"imports": "from evennia import DefaultRoom",
|
|
"domain": "room state",
|
|
},
|
|
{
|
|
"problem": "Create a room that broadcasts a message to all occupants when a player enters or leaves.",
|
|
"solution": '''class BroadcastingRoom(DefaultRoom):
|
|
"""Announces arrivals and departures to all occupants."""
|
|
|
|
def at_object_receive(self, moved_obj, source_location, **kwargs):
|
|
super().at_object_receive(moved_obj, source_location, **kwargs)
|
|
if moved_obj.has_account:
|
|
self.msg_contents(
|
|
"|y{{moved_obj.name}} arrives from {{source_location}}.|n",
|
|
exclude=moved_obj,
|
|
)
|
|
|
|
def at_object_leave(self, moved_obj, target_location, **kwargs):
|
|
super().at_object_leave(moved_obj, target_location, **kwargs)
|
|
if moved_obj.has_account:
|
|
self.msg_contents(
|
|
"|y{{moved_obj.name}} departs to {{target_location}}.|n",
|
|
exclude=moved_obj,
|
|
)''',
|
|
"imports": "from evennia import DefaultRoom",
|
|
"domain": "room state",
|
|
},
|
|
]
|
|
|
|
NPC_TEMPLATES = [
|
|
{
|
|
"problem": "Implement an Evennia NPC that answers questions by searching a memory palace index.",
|
|
"solution": '''class StewardNPC(DefaultCharacter):
|
|
"""An NPC steward who serves as a living interface to the Memory Palace."""
|
|
|
|
def at_object_creation(self):
|
|
super().at_object_creation()
|
|
self.db.palace_index = {}
|
|
self.db.welcome_msg = "I am the Steward. Ask me of the Palace."
|
|
|
|
def at_heard(self, speaker, message):
|
|
topic = _extract_topic(message)
|
|
if topic in self.db.palace_index:
|
|
entry = self.db.palace_index[topic]
|
|
speaker.msg(f"|c{{self.name}}|n says: '{{entry[\\'summary\\']}}'")
|
|
else:
|
|
speaker.msg(f"|c{{self.name}}|n says: 'I know nothing of {{topic}}.'")
|
|
|
|
def _extract_topic(question: str) -> str:
|
|
q = question.lower().strip("?")
|
|
for prefix in ("what is", "tell me about", "do you know", "where is"):
|
|
if q.startswith(prefix):
|
|
return q[len(prefix):].strip()
|
|
return q''',
|
|
"imports": "from evennia import DefaultCharacter",
|
|
"domain": "NPC behavior",
|
|
},
|
|
{
|
|
"problem": "Create an NPC that wanders between connected rooms on a timed interval.",
|
|
"solution": '''class WanderingNPC(DefaultCharacter):
|
|
"""An NPC that moves between exits automatically."""
|
|
|
|
def at_object_creation(self):
|
|
super().at_object_creation()
|
|
self.db.wander_interval = 30 # seconds
|
|
self.db.home_room = None
|
|
|
|
def start_wandering(self):
|
|
from evennia import TICKER_HANDLER
|
|
TICKER_HANDLER.add(self, self.db.wander_interval)
|
|
|
|
def at_tick(self):
|
|
exits = [ex for ex in self.location.exits if ex.access(self, "traverse")]
|
|
if exits:
|
|
chosen = random.choice(exits)
|
|
self.move_to(chosen.destination)
|
|
|
|
def stop_wandering(self):
|
|
from evennia import TICKER_HANDLER
|
|
TICKER_HANDLER.remove(self)''',
|
|
"imports": "from evennia import DefaultCharacter, TICKER_HANDLER",
|
|
"domain": "NPC behavior",
|
|
},
|
|
{
|
|
"problem": "Build an NPC with a mood state machine that affects its dialogue responses.",
|
|
"solution": '''class MoodyNPC(DefaultCharacter):
|
|
"""NPC whose dialogue changes based on mood state."""
|
|
|
|
def at_object_creation(self):
|
|
super().at_object_creation()
|
|
self.db.mood = "neutral" # neutral, happy, angry, sad
|
|
self.db.dialogue = {
|
|
"neutral": ["Hello.", "What do you need?"],
|
|
"happy": ["A fine day!", "Welcome, friend!"],
|
|
"angry": ["Leave me be!", "I have no patience today."],
|
|
"sad": ["*sigh*", "The world weighs heavy..."],
|
|
}
|
|
|
|
def respond(self, speaker, message):
|
|
pool = self.db.dialogue.get(self.db.mood, self.db.dialogue["neutral"])
|
|
reply = random.choice(pool)
|
|
speaker.msg(f"|c{{self.name}}|n says: '{{reply}}'")
|
|
|
|
def set_mood(self, mood):
|
|
if mood in self.db.dialogue:
|
|
self.db.mood = mood
|
|
self.msg_contents(f"|y{{self.name}} seems {{mood}} now.|n")''',
|
|
"imports": "from evennia import DefaultCharacter",
|
|
"domain": "NPC behavior",
|
|
},
|
|
]
|
|
|
|
COMMAND_TEMPLATES = [
|
|
{
|
|
"problem": "Write an Evennia command that lets a player search the Memory Palace by topic and returns the closest matching room.",
|
|
"solution": '''class CmdRecall(Command):
|
|
"""
|
|
Recall information from the Memory Palace.
|
|
|
|
Usage:
|
|
recall <topic>
|
|
recall <topic> in <wing>
|
|
"""
|
|
key = "recall"
|
|
aliases = ["remember", "search"]
|
|
locks = "cmd:all()"
|
|
|
|
def func(self):
|
|
if not self.args:
|
|
self.caller.msg("Recall what topic?")
|
|
return
|
|
topic = self.args.strip()
|
|
wing = self.caller.location.db.wing if self.caller.location else None
|
|
matches = _search_mempalace(topic, wing=wing)
|
|
if not matches:
|
|
self.caller.msg(f"No memory of '{topic}' found.")
|
|
return
|
|
best = matches[0]
|
|
self.caller.msg(f"|wMemory: {{best['topic']}}|n\n{{best['summary']}}")
|
|
|
|
def _search_mempalace(query, wing=None, n=5):
|
|
results = []
|
|
for room in DefaultRoom.objects.all():
|
|
topics = room.db.topics or []
|
|
score = sum(1 for t in topics if query.lower() in t.lower())
|
|
if score:
|
|
if wing and room.db.wing != wing:
|
|
score *= 0.5
|
|
results.append({"room": room, "score": score, "topic": query})
|
|
results.sort(key=lambda x: x["score"], reverse=True)
|
|
return results[:n]''',
|
|
"imports": "from evennia import Command, DefaultRoom",
|
|
"domain": "spatial memory",
|
|
},
|
|
{
|
|
"problem": "Create an Evennia command that records a new topic into the current room's Memory Palace index.",
|
|
"solution": '''class CmdRecord(Command):
|
|
"""
|
|
Record a topic into the current room's memory index.
|
|
|
|
Usage:
|
|
record <topic> = <summary>
|
|
"""
|
|
key = "record"
|
|
locks = "cmd:all()"
|
|
|
|
def func(self):
|
|
if "=" not in self.args:
|
|
self.caller.msg("Usage: record <topic> = <summary>")
|
|
return
|
|
topic, summary = self.args.split("=", 1)
|
|
topic = topic.strip()
|
|
summary = summary.strip()
|
|
loc = self.caller.location
|
|
if not loc:
|
|
self.caller.msg("You are nowhere.")
|
|
return
|
|
topics = loc.db.topics or []
|
|
if topic not in topics:
|
|
topics.append(topic)
|
|
loc.db.topics = topics
|
|
palace = loc.db.palace_index or {}
|
|
palace[topic] = {"summary": summary, "author": self.caller.name}
|
|
loc.db.palace_index = palace
|
|
self.caller.msg(f"Recorded '{topic}' into {{loc.name}}.")''',
|
|
"imports": "from evennia import Command",
|
|
"domain": "spatial memory",
|
|
},
|
|
{
|
|
"problem": "Implement an Evennia command that lets players move between rooms by name instead of using exits.",
|
|
"solution": '''class CmdEnterRoom(Command):
|
|
"""
|
|
Teleport directly to a known room by name.
|
|
|
|
Usage:
|
|
enter <room name>
|
|
"""
|
|
key = "enter"
|
|
locks = "cmd:all()"
|
|
|
|
def func(self):
|
|
if not self.args:
|
|
self.caller.msg("Enter which room?")
|
|
return
|
|
target_name = self.args.strip().lower()
|
|
matches = [
|
|
r for r in DefaultRoom.objects.all()
|
|
if target_name in r.name.lower()
|
|
]
|
|
if not matches:
|
|
self.caller.msg(f"No room matching '{target_name}'.")
|
|
return
|
|
if len(matches) > 1:
|
|
names = ", ".join(r.name for r in matches[:5])
|
|
self.caller.msg(f"Be more specific: {{names}}")
|
|
return
|
|
target = matches[0]
|
|
self.caller.move_to(target)
|
|
self.caller.msg(f"You enter {{target.name}}.")''',
|
|
"imports": "from evennia import Command, DefaultRoom",
|
|
"domain": "spatial memory",
|
|
},
|
|
]
|
|
|
|
EVENT_TEMPLATES = [
|
|
{
|
|
"problem": "Generate an Evennia event dict when a player joins the game, including account and character names.",
|
|
"solution": '''def player_join(account: str, character: str = "", ip_address: str = "", timestamp: str | None = None) -> dict:
|
|
return {
|
|
"event_type": "player_join",
|
|
"account": account,
|
|
"character": character,
|
|
"ip_address": ip_address,
|
|
"timestamp": timestamp or _ts(),
|
|
}''',
|
|
"imports": "from typing import Optional",
|
|
"domain": "MUD world",
|
|
},
|
|
{
|
|
"problem": "Generate an Evennia event dict when a player moves from one room to another.",
|
|
"solution": '''def player_move(character: str, from_room: str, to_room: str, timestamp: str | None = None) -> dict:
|
|
return {
|
|
"event_type": "player_move",
|
|
"character": character,
|
|
"from_room": from_room,
|
|
"to_room": to_room,
|
|
"timestamp": timestamp or _ts(),
|
|
}''',
|
|
"imports": "",
|
|
"domain": "MUD world",
|
|
},
|
|
{
|
|
"problem": "Create a normalized room snapshot event for the Evennia bridge, including exits, objects, and occupants.",
|
|
"solution": '''def room_snapshot(room_key: str, title: str, desc: str,
|
|
exits: list[dict] | None = None,
|
|
objects: list[dict] | None = None,
|
|
occupants: list[dict] | None = None,
|
|
timestamp: str | None = None) -> dict:
|
|
return {
|
|
"event_type": "room_snapshot",
|
|
"room_key": room_key,
|
|
"title": title,
|
|
"description": desc,
|
|
"exits": exits or [],
|
|
"objects": objects or [],
|
|
"occupants": occupants or [],
|
|
"timestamp": timestamp or _ts(),
|
|
}''',
|
|
"imports": "from typing import Optional",
|
|
"domain": "MUD world",
|
|
},
|
|
{
|
|
"problem": "Generate a command_executed event dict for tracking player actions in Evennia.",
|
|
"solution": '''def command_executed(character: str, command: str, args: str = "", success: bool = True, timestamp: str | None = None) -> dict:
|
|
return {
|
|
"event_type": "command_executed",
|
|
"character": character,
|
|
"command": command,
|
|
"args": args,
|
|
"success": success,
|
|
"timestamp": timestamp or _ts(),
|
|
}''',
|
|
"imports": "",
|
|
"domain": "MUD world",
|
|
},
|
|
]
|
|
|
|
BRIDGE_TEMPLATES = [
|
|
{
|
|
"problem": "Parse a raw Evennia log line into a structured event dict, extracting timestamp and message.",
|
|
"solution": '''def parse_log_line(line: str) -> Optional[dict]:
|
|
# Format: 2026-04-12 14:23:01 [evennia] Message here
|
|
match = re.match(
|
|
r"^(\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}) \\[(\\w+)\\] (.*)$",
|
|
line.strip(),
|
|
)
|
|
if not match:
|
|
return None
|
|
return {
|
|
"timestamp": match.group(1),
|
|
"channel": match.group(2),
|
|
"message": match.group(3),
|
|
}''',
|
|
"imports": "import re\nfrom typing import Optional",
|
|
"domain": "MUD world",
|
|
},
|
|
{
|
|
"problem": "Strip ANSI escape codes from Evennia terminal output for clean log processing.",
|
|
"solution": '''def strip_ansi(text: str) -> str:
|
|
ansi_pattern = re.compile(r"\\x1b\\[[0-9;]*m")
|
|
return ansi_pattern.sub("", text)''',
|
|
"imports": "import re",
|
|
"domain": "MUD world",
|
|
},
|
|
{
|
|
"problem": "Normalize an Evennia bridge event by ensuring all required fields exist with defaults.",
|
|
"solution": '''def normalize_event(event: dict) -> dict:
|
|
required = {
|
|
"event_type": "unknown",
|
|
"timestamp": "",
|
|
"character": "",
|
|
"room_key": "",
|
|
}
|
|
normalized = {**required, **event}
|
|
# Ensure nested dicts
|
|
for key in ("exits", "objects", "occupants"):
|
|
if key not in normalized or normalized[key] is None:
|
|
normalized[key] = []
|
|
return normalized''',
|
|
"imports": "",
|
|
"domain": "MUD world",
|
|
},
|
|
{
|
|
"problem": "Parse room output text from Evennia into structured data (description, exits, contents).",
|
|
"solution": '''def parse_room_output(text: str) -> dict:
|
|
lines = text.strip().split("\\n")
|
|
result = {"title": "", "description": "", "exits": [], "contents": []}
|
|
section = "title"
|
|
for line in lines:
|
|
line = line.strip()
|
|
if not line:
|
|
continue
|
|
if line.startswith("Obvious exits:"):
|
|
section = "exits"
|
|
continue
|
|
if line.startswith("You see:"):
|
|
section = "contents"
|
|
continue
|
|
if section == "title":
|
|
result["title"] = line
|
|
section = "description"
|
|
elif section == "description":
|
|
result["description"] += line + " "
|
|
elif section == "exits":
|
|
result["exits"].append(line)
|
|
elif section == "contents":
|
|
result["contents"].append(line)
|
|
return result''',
|
|
"imports": "",
|
|
"domain": "MUD world",
|
|
},
|
|
]
|
|
|
|
TOWER_TEMPLATES = [
|
|
{
|
|
"problem": "Define a dataclass for a Tower room that maps to an Evennia room and a Memory Palace room.",
|
|
"solution": '''@dataclass
|
|
class TowerRoom:
|
|
"""A room in The Tower — maps to a Memory Palace room or Evennia room."""
|
|
name: str
|
|
floor: int = 0
|
|
description: str = ""
|
|
category: str = "" # origin, philosophy, mission, architecture, operations
|
|
connections: list[str] = field(default_factory=list)
|
|
occupants: list[str] = field(default_factory=list)
|
|
artifacts: list[str] = field(default_factory=list)
|
|
source: str = ""
|
|
coordinates: tuple = (0, 0)''',
|
|
"imports": "from dataclasses import dataclass, field",
|
|
"domain": "Tower architecture",
|
|
},
|
|
{
|
|
"problem": "Create a Tower floor dataclass that groups rooms by theme.",
|
|
"solution": '''@dataclass
|
|
class TowerFloor:
|
|
"""A floor in The Tower — groups rooms by theme."""
|
|
number: int
|
|
name: str
|
|
theme: str = ""
|
|
rooms: list[str] = field(default_factory=list)''',
|
|
"imports": "from dataclasses import dataclass, field",
|
|
"domain": "Tower architecture",
|
|
},
|
|
{
|
|
"problem": "Build a TowerMap dataclass that holds the complete holographic map with rooms, floors, and NPCs.",
|
|
"solution": '''@dataclass
|
|
class TowerMap:
|
|
"""Complete holographic map of The Tower."""
|
|
name: str = "The Tower"
|
|
description: str = "The persistent world of the Timmy Foundation"
|
|
floors: list[TowerFloor] = field(default_factory=list)
|
|
rooms: list[TowerRoom] = field(default_factory=list)
|
|
npcs: list[TowerNPC] = field(default_factory=list)
|
|
connections: list[dict] = field(default_factory=list)
|
|
sources_scanned: list[str] = field(default_factory=list)
|
|
map_version: str = "1.0"''',
|
|
"imports": "from dataclasses import dataclass, field",
|
|
"domain": "Tower architecture",
|
|
},
|
|
{
|
|
"problem": "Serialize a TowerMap to JSON for persistence or transmission.",
|
|
"solution": '''def serialize_tower_map(tower_map: TowerMap) -> str:
|
|
return json.dumps(asdict(tower_map), indent=2, default=str)''',
|
|
"imports": "import json\nfrom dataclasses import asdict",
|
|
"domain": "Tower architecture",
|
|
},
|
|
{
|
|
"problem": "Find all rooms on a specific floor of The Tower.",
|
|
"solution": '''def rooms_on_floor(tower_map: TowerMap, floor_num: int) -> list[TowerRoom]:
|
|
return [r for r in tower_map.rooms if r.floor == floor_num]''',
|
|
"imports": "",
|
|
"domain": "Tower architecture",
|
|
},
|
|
{
|
|
"problem": "Find the shortest path between two Tower rooms by name using BFS.",
|
|
"solution": '''from collections import deque
|
|
|
|
def shortest_path(tower_map: TowerMap, start_name: str, end_name: str) -> list[str]:
|
|
graph = {r.name: r.connections for r in tower_map.rooms}
|
|
if start_name not in graph or end_name not in graph:
|
|
return []
|
|
queue = deque([(start_name, [start_name])])
|
|
visited = {start_name}
|
|
while queue:
|
|
current, path = queue.popleft()
|
|
if current == end_name:
|
|
return path
|
|
for neighbor in graph.get(current, []):
|
|
if neighbor not in visited:
|
|
visited.add(neighbor)
|
|
queue.append((neighbor, path + [neighbor]))
|
|
return []''',
|
|
"imports": "from collections import deque",
|
|
"domain": "Tower architecture",
|
|
},
|
|
]
|
|
|
|
SESSION_TEMPLATES = [
|
|
{
|
|
"problem": "Track a user session in a multi-user bridge with join time and active status.",
|
|
"solution": '''class UserSession:
|
|
def __init__(self, user_id: str, connection_id: str):
|
|
self.user_id = user_id
|
|
self.connection_id = connection_id
|
|
self.joined_at = time.time()
|
|
self.last_active = time.time()
|
|
self.active = True
|
|
|
|
def ping(self):
|
|
self.last_active = time.time()
|
|
|
|
def is_stale(self, timeout: float = 300.0) -> bool:
|
|
return (time.time() - self.last_active) > timeout''',
|
|
"imports": "import time",
|
|
"domain": "multi-user bridge",
|
|
},
|
|
{
|
|
"problem": "Manage multiple user sessions in a thread-safe session manager.",
|
|
"solution": '''class SessionManager:
|
|
def __init__(self):
|
|
self._sessions: dict[str, UserSession] = {}
|
|
self._lock = threading.Lock()
|
|
|
|
def add(self, session: UserSession):
|
|
with self._lock:
|
|
self._sessions[session.connection_id] = session
|
|
|
|
def remove(self, connection_id: str):
|
|
with self._lock:
|
|
self._sessions.pop(connection_id, None)
|
|
|
|
def get(self, connection_id: str) -> UserSession | None:
|
|
with self._lock:
|
|
return self._sessions.get(connection_id)
|
|
|
|
def list_active(self) -> list[UserSession]:
|
|
with self._lock:
|
|
return [s for s in self._sessions.values() if s.active]''',
|
|
"imports": "import threading",
|
|
"domain": "multi-user bridge",
|
|
},
|
|
]
|
|
|
|
# Combine all templates
|
|
ALL_TEMPLATES = (
|
|
ROOM_TEMPLATES * 50
|
|
+ NPC_TEMPLATES * 60
|
|
+ COMMAND_TEMPLATES * 70
|
|
+ EVENT_TEMPLATES * 80
|
|
+ BRIDGE_TEMPLATES * 90
|
|
+ TOWER_TEMPLATES * 100
|
|
+ SESSION_TEMPLATES * 80
|
|
)
|
|
|
|
# Variation generators for scaling to 1K
|
|
def vary_problem(base: str, idx: int) -> str:
|
|
prefixes = [
|
|
"Write Python code to",
|
|
"Implement a function that",
|
|
"Create a class which",
|
|
"Build an Evennia typeclass that",
|
|
"Design a Tower component to",
|
|
"How would you",
|
|
"In an Evennia MUD, how do you",
|
|
"For The Tower architecture, write code to",
|
|
"Using Evennia's API,",
|
|
"Construct a spatial-memory system that",
|
|
]
|
|
suffixes = [
|
|
" including error handling.",
|
|
" with full docstrings.",
|
|
" and expose it as a command.",
|
|
" using dataclasses.",
|
|
" with type hints.",
|
|
" that persists to JSON.",
|
|
" with lock checks.",
|
|
" that broadcasts to all occupants.",
|
|
" supporting async callbacks.",
|
|
" with logging.",
|
|
]
|
|
prefix = prefixes[idx % len(prefixes)]
|
|
suffix = suffixes[idx % len(suffixes)]
|
|
# Clean up the base problem and reframe
|
|
cleaned = base.replace("Create an", "").replace("Build an", "").replace("Implement an", "").replace("Write an", "").replace("Generate an", "").strip()
|
|
cleaned = cleaned[0].lower() + cleaned[1:] if cleaned else ""
|
|
return f"{prefix} {cleaned}{suffix}"
|
|
|
|
|
|
def vary_solution(base: str, idx: int) -> str:
|
|
# Add minor variations like different variable names or comments
|
|
var_names = ["data", "result", "output", "record", "entry", "item", "node", "entity"]
|
|
v = var_names[idx % len(var_names)]
|
|
sol = base.replace("result", v) if idx % 3 == 0 else base
|
|
# Add a comment line at the top sometimes
|
|
if idx % 5 == 0:
|
|
sol = f"# Generated variation {idx}\n{sol}"
|
|
return sol
|
|
|
|
|
|
def generate_pairs(count: int = 1000) -> list[dict]:
|
|
pairs = []
|
|
template_cycle = list(ALL_TEMPLATES)
|
|
random.shuffle(template_cycle)
|
|
|
|
for i in range(count):
|
|
template = template_cycle[i % len(template_cycle)]
|
|
problem = vary_problem(template["problem"], i)
|
|
solution = vary_solution(template["solution"], i)
|
|
pair = {
|
|
"problem": problem,
|
|
"solution": solution,
|
|
"imports": template["imports"],
|
|
"domain": template["domain"],
|
|
"id": f"evennia-tower-{i:04d}",
|
|
}
|
|
pairs.append(pair)
|
|
|
|
return pairs
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description="Generate Evennia & Tower code pattern training pairs")
|
|
parser.add_argument("--output", "-o", default="training-data/code-patterns-evennia-&-tower.jsonl", help="Output JSONL path")
|
|
parser.add_argument("--count", "-n", type=int, default=1000, help="Number of pairs to generate")
|
|
args = parser.parse_args()
|
|
|
|
out_path = Path(args.output)
|
|
out_path.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
pairs = generate_pairs(args.count)
|
|
with open(out_path, "w", encoding="utf-8") as f:
|
|
for pair in pairs:
|
|
f.write(json.dumps(pair, ensure_ascii=False) + "\n")
|
|
|
|
print(f"Generated {len(pairs)} code pattern pairs → {out_path}")
|
|
print(f" Size: {out_path.stat().st_size / 1024:.1f} KB")
|
|
print(f" Domains: {len(set(p['domain'] for p in pairs))} unique")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|