Files
Mortdecai/training/scripts/generate_rcon_validated_training.py
Mortdecai da8f557219 GPU scheduler, 14-tool architecture, plugin deployment, event dispatcher
GPU Scheduler (gpu.sethpc.xyz):
- Live dashboard with 4 GPUs, training monitor, loss sparklines
- Preset-based job scheduler with 3 triggers (time, finish_training, cost)
- Model selection per GPU, pipeline configuration
- Tool self-play and training pipeline types
- Behind Google OAuth, live-refresh without page reload

Tool Architecture (14 tools):
- 3 new tools: world.nearby_entities, memory.read, memory.write
- 7 script.* tools: write, validate, execute, read, list, delete, schedule
- ScriptManager: full mcfunction datapack CRUD with RCON validation
- Training data: 1,430 tool examples (up from 1,159)

Plugin Deployment (paper-ai-25567):
- WorldGuard 7.0.12, CoreProtect CE 23.1, EssentialsX 2.21.2, Vault 1.7.3
- Fresh greenfield world reset
- 104 RCON-validated plugin training examples

Event Dispatcher:
- Watches server log for deaths, joins, advancements, PvP kills
- Configurable trigger probability and cooldowns per event type
- Deployed to dev server, fires god_system prompts on events
- 21 event-response training examples

Training Infrastructure:
- train_lora.py: --save-steps 50, --resume from checkpoint
- run_training.sh: stops Ollama, activates conda, restarts after
- Passwordless sudo for ollama services on steel141
- Dev server added to MCSManager with autoStart

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 03:14:45 -04:00

662 lines
32 KiB
Python

#!/usr/bin/env python3
"""
Generate high-quality tool-calling training data with REAL RCON responses.
No AI involved — we craft the prompts, commands, and tool sequences by hand,
then execute each command through RCON to get actual server responses.
This produces gold-standard training data with real validation.
Generates examples across all 14 tools with proper multi-turn conversations:
- script.validate → script.write → script.execute (with real RCON validation)
- memory.read → rcon.execute (tp to saved location)
- world.nearby_entities → rcon.execute (kill scanned mobs)
- wiki_lookup → rcon.execute (apply looked-up knowledge)
- chained multi-tool sequences
Usage:
python3 generate_rcon_validated_training.py --rcon-host 192.168.0.244 --rcon-port 25577
"""
import argparse
import json
import random
import re
import socket
import struct
import sys
import time
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parent.parent.parent
sys.path.insert(0, str(PROJECT_ROOT))
from agent.tools.tool_schemas import qwen3_tools_block
from agent.prompts.system_prompts import SYNTAX_RULES, RISK_GRADIENT
OUTPUT_PATH = PROJECT_ROOT / "data" / "raw" / "rcon_validated_tool_training.jsonl"
TOOLS_BLOCK = qwen3_tools_block()
SYSTEM_SUDO = (
"You are a Minecraft 1.21 command translator with full tool access.\n"
"Tools: rcon.execute, minecraft.wiki_lookup, world.player_info, world.server_state, "
"world.nearby_entities, memory.read, memory.write, script.write, script.validate, "
"script.execute, script.read, script.list, script.delete, script.schedule.\n\n"
"For complex builds (4+ commands), write mcfunction scripts. Validate before writing.\n"
"PERMISSION LEVEL: 4 (generous).\n\n"
"Return JSON: {\"risk_level\": <0-5>, \"commands\": [...], \"reasoning\": \"...\"}\n\n"
+ SYNTAX_RULES + RISK_GRADIENT + "\n" + TOOLS_BLOCK
)
SYSTEM_GOD = (
"You are God in a Minecraft server. You have full tool access.\n"
"Return JSON: {\"risk_level\": <0-5>, \"message\": \"...\", \"commands\": [...], \"reasoning\": \"...\"}\n\n"
+ SYNTAX_RULES + "\n" + TOOLS_BLOCK
)
PLAYERS = ["slingshooter08", "Ace13245", "TheBigBoss", "xXDragonSlayerXx"]
from agent.tools.persistent_rcon import get_rcon as _get_rcon
class SimpleRCON:
"""Wrapper around persistent_rcon."""
def __init__(self, host, port, password):
self._rcon = _get_rcon(host, port, password)
def command(self, cmd):
return self._rcon.command(cmd)
def sys_msg(mode="sudo"):
return {"role": "system", "content": SYSTEM_GOD if mode == "god" else SYSTEM_SUDO}
def user_msg(text):
return {"role": "user", "content": text}
def tool_call(name, args):
return {"role": "assistant", "content": f"<tool_call>\n{json.dumps({'name': name, 'arguments': args})}\n</tool_call>"}
def tool_result(data):
return {"role": "tool", "content": json.dumps(data)}
def final_response(resp):
return {"role": "assistant", "content": json.dumps(resp)}
def is_error(result):
return any(e in result for e in ("<--[HERE]", "Unknown", "Incorrect", "Expected", "Invalid"))
def validate_commands_rcon(rcon, commands):
"""Execute commands through RCON and return results."""
results = []
for cmd in commands:
cmd = cmd.strip()
if not cmd or cmd.startswith("#"):
results.append({"cmd": cmd, "result": "comment", "ok": True})
continue
try:
result = rcon.command(cmd)
ok = not is_error(result)
results.append({"cmd": cmd, "result": result[:300], "ok": ok})
except Exception as e:
results.append({"cmd": cmd, "result": str(e), "ok": False})
return results
def gen_script_examples(rcon):
"""Script write/validate/execute examples with real RCON validation."""
examples = []
SCRIPTS = [
("build me a small oak cabin", "oak_cabin", "Small oak cabin with door, windows, and lantern", [
"fill ~-3 ~ ~-3 ~3 ~3 ~3 minecraft:oak_planks hollow",
"fill ~-3 ~ ~-3 ~3 ~ ~3 minecraft:oak_planks",
"fill ~-2 ~1 ~-3 ~2 ~2 ~-3 minecraft:air",
"setblock ~0 ~1 ~-3 minecraft:oak_door[facing=north,half=lower]",
"setblock ~0 ~2 ~-3 minecraft:oak_door[facing=north,half=upper]",
"setblock ~2 ~1 ~3 minecraft:glass_pane",
"setblock ~-2 ~1 ~3 minecraft:glass_pane",
"setblock ~0 ~2 ~0 minecraft:lantern[hanging=true]",
]),
("create a pvp arena with wool corners", "pvp_arena", "PvP arena with colored corners", [
"fill ~-12 ~-1 ~-12 ~12 ~-1 ~12 minecraft:smooth_stone",
"fill ~-12 ~ ~-12 ~12 ~4 ~-12 minecraft:iron_bars",
"fill ~-12 ~ ~12 ~12 ~4 ~12 minecraft:iron_bars",
"fill ~-12 ~ ~-12 ~-12 ~4 ~12 minecraft:iron_bars",
"fill ~12 ~ ~-12 ~12 ~4 ~12 minecraft:iron_bars",
"fill ~-12 ~-1 ~-12 ~-10 ~-1 ~-10 minecraft:red_wool",
"fill ~10 ~-1 ~10 ~12 ~-1 ~12 minecraft:blue_wool",
]),
("make an enchanting room", "enchant_room", "Enchanting table surrounded by bookshelves", [
"fill ~-3 ~ ~-3 ~3 ~3 ~3 minecraft:deepslate_bricks hollow",
"fill ~-2 ~ ~-2 ~2 ~2 ~2 minecraft:air",
"setblock ~0 ~ ~0 minecraft:enchanting_table",
"fill ~-2 ~1 ~-2 ~2 ~1 ~2 minecraft:bookshelf",
"fill ~-1 ~1 ~-1 ~1 ~1 ~1 minecraft:air",
"setblock ~0 ~1 ~0 minecraft:enchanting_table",
"setblock ~0 ~2 ~0 minecraft:lantern[hanging=true]",
]),
("build a nether portal frame", "nether_portal", "Obsidian nether portal frame", [
"fill ~0 ~ ~0 ~3 ~4 ~0 minecraft:obsidian",
"fill ~1 ~1 ~0 ~2 ~3 ~0 minecraft:air",
]),
("create a mob farm collection area", "mob_farm", "Mob farm with hoppers and chest", [
"fill ~-4 ~-1 ~-4 ~4 ~-1 ~4 minecraft:cobblestone",
"setblock ~0 ~-2 ~0 minecraft:chest",
"setblock ~0 ~-1 ~0 minecraft:hopper",
"fill ~-4 ~ ~0 ~-1 ~ ~0 minecraft:water",
"fill ~1 ~ ~0 ~4 ~ ~0 minecraft:water",
]),
("build a lookout tower", "lookout_tower", "Tall stone tower with viewing platform", [
"fill ~-1 ~ ~-1 ~1 ~8 ~1 minecraft:stone_bricks hollow",
"fill ~0 ~ ~0 ~0 ~7 ~0 minecraft:air",
"fill ~1 ~1 ~0 ~1 ~7 ~0 minecraft:ladder[facing=west]",
"fill ~-2 ~8 ~-2 ~2 ~8 ~2 minecraft:stone_brick_slab",
"fill ~-2 ~9 ~-2 ~2 ~9 ~2 minecraft:stone_brick_wall",
"fill ~-1 ~9 ~-1 ~1 ~9 ~1 minecraft:air",
"setblock ~0 ~10 ~0 minecraft:lantern",
]),
("make a fishing dock", "fishing_dock", "Wooden dock extending over water", [
"fill ~0 ~-1 ~0 ~1 ~-1 ~8 minecraft:oak_planks",
"fill ~-1 ~-2 ~0 ~-1 ~-1 ~8 minecraft:oak_fence",
"fill ~2 ~-2 ~0 ~2 ~-1 ~8 minecraft:oak_fence",
"setblock ~0 ~0 ~8 minecraft:oak_fence",
"setblock ~1 ~0 ~8 minecraft:oak_fence",
"setblock ~0 ~0 ~0 minecraft:lantern",
]),
("create a garden with flower beds", "garden", "Flower garden with paths", [
"fill ~-5 ~-1 ~-5 ~5 ~-1 ~5 minecraft:grass_block",
"fill ~-5 ~-1 ~0 ~5 ~-1 ~0 minecraft:gravel",
"fill ~0 ~-1 ~-5 ~0 ~-1 ~5 minecraft:gravel",
"setblock ~-3 ~ ~-3 minecraft:rose_bush[half=lower]",
"setblock ~3 ~ ~-3 minecraft:peony[half=lower]",
"setblock ~-3 ~ ~3 minecraft:lilac[half=lower]",
"setblock ~3 ~ ~3 minecraft:sunflower[half=lower]",
"setblock ~0 ~ ~0 minecraft:water",
]),
("build a redstone clock", "redstone_clock", "Simple repeater clock", [
"setblock ~0 ~ ~0 minecraft:redstone_wire",
"setblock ~1 ~ ~0 minecraft:repeater[facing=west,delay=4]",
"setblock ~2 ~ ~0 minecraft:redstone_wire",
"setblock ~2 ~ ~1 minecraft:repeater[facing=north,delay=4]",
"setblock ~2 ~ ~2 minecraft:redstone_wire",
"setblock ~1 ~ ~2 minecraft:repeater[facing=east,delay=4]",
"setblock ~0 ~ ~2 minecraft:redstone_wire",
"setblock ~0 ~ ~1 minecraft:repeater[facing=south,delay=4]",
]),
("make a treasure vault", "treasure_vault", "Secure room with chests and iron door", [
"fill ~-3 ~ ~-3 ~3 ~3 ~3 minecraft:deepslate_brick_wall hollow",
"fill ~-2 ~ ~-2 ~2 ~2 ~2 minecraft:air",
"setblock ~0 ~0 ~-3 minecraft:iron_door[facing=north,half=lower]",
"setblock ~0 ~1 ~-3 minecraft:iron_door[facing=north,half=upper]",
"setblock ~-1 ~0 ~-2 minecraft:chest",
"setblock ~1 ~0 ~-2 minecraft:chest",
"setblock ~-1 ~0 ~2 minecraft:chest",
"setblock ~1 ~0 ~2 minecraft:chest",
"setblock ~0 ~2 ~0 minecraft:lantern[hanging=true]",
]),
]
for prompt, name, desc, commands in SCRIPTS:
player = random.choice(PLAYERS)
mode = "sudo"
msgs = [sys_msg(mode), user_msg(f"Player {player}: sudo {prompt}")]
# Step 1: Validate
rcon_results = validate_commands_rcon(rcon, commands)
valid = all(r["ok"] for r in rcon_results)
errors = [{"line": i+1, "command": r["cmd"], "error": r["result"]}
for i, r in enumerate(rcon_results) if not r["ok"]]
msgs.append(tool_call("script.validate", {"commands": commands}))
msgs.append(tool_result({
"valid": valid,
"total": len(commands),
"passed": sum(1 for r in rcon_results if r["ok"]),
"errors": errors,
}))
# Step 2: Write (if valid or partially valid)
write_cmds = [r["cmd"] for r in rcon_results if r["ok"]] if not valid else commands
msgs.append(tool_call("script.write", {"name": name, "commands": write_cmds, "description": desc}))
msgs.append(tool_result({"ok": True, "path": f"mortdecai:{name}", "lines": len(write_cmds)}))
# Step 3: Execute
msgs.append(tool_call("script.execute", {"name": name, "as_player": player}))
msgs.append(tool_result({"ok": True, "result": f"Executed {len(write_cmds)} commands from function mortdecai:{name}"}))
# Final
fix_note = f" Fixed {len(errors)} validation errors." if errors else ""
resp = {
"risk_level": 3,
"commands": [f"function mortdecai:{name}"],
"reasoning": f"Validated {len(commands)} commands ({sum(1 for r in rcon_results if r['ok'])} passed).{fix_note} Wrote and executed '{name}' script at player position.",
}
msgs.append(final_response(resp))
examples.append({
"id": f"rcon-script-{name}",
"source": "rcon_validated",
"type": "script_write_execute",
"messages": msgs,
})
return examples
def gen_direct_command_examples(rcon):
"""Direct rcon.execute examples with real server responses."""
examples = []
COMMANDS = [
("sudo give me a diamond sword with sharpness 5", [
"give {p} minecraft:diamond_sword[enchantments={sharpness:5,unbreaking:3,mending:1}] 1",
], "Gave max enchanted diamond sword."),
("sudo full netherite armor please", [
"give {p} minecraft:netherite_helmet[enchantments={protection:4,unbreaking:3,mending:1}] 1",
"give {p} minecraft:netherite_chestplate[enchantments={protection:4,unbreaking:3,mending:1}] 1",
"give {p} minecraft:netherite_leggings[enchantments={protection:4,unbreaking:3,mending:1}] 1",
"give {p} minecraft:netherite_boots[enchantments={protection:4,unbreaking:3,mending:1}] 1",
], "Full netherite armor set with protection 4 and mending."),
("sudo make it night", ["time set night"], "Set time to night."),
("sudo give me 64 golden apples", [
"give {p} minecraft:golden_apple 64",
], "Gave 64 golden apples."),
("sudo smite me with lightning", [
"execute at {p} run summon minecraft:lightning_bolt",
], "Summoned lightning at player position."),
("sudo give me speed 3 for 10 minutes", [
"effect give {p} minecraft:speed 600 2",
], "Applied speed 3 (amplifier 2) for 600 seconds."),
("sudo clear weather", ["weather clear 999999"], "Cleared weather."),
("sudo make me invincible", [
"effect give {p} minecraft:resistance 6000 4",
"effect give {p} minecraft:regeneration 6000 2",
"effect give {p} minecraft:fire_resistance 6000 0",
], "Applied resistance 5, regeneration 3, and fire resistance for 100 minutes."),
("sudo give me a god bow", [
"give {p} minecraft:bow[enchantments={power:5,infinity:1,flame:1,punch:2,unbreaking:3}] 1",
], "Bow with power 5, infinity, flame, punch 2."),
("sudo stack of each wood type", [
"give {p} minecraft:oak_log 64",
"give {p} minecraft:spruce_log 64",
"give {p} minecraft:birch_log 64",
"give {p} minecraft:jungle_log 64",
"give {p} minecraft:acacia_log 64",
"give {p} minecraft:dark_oak_log 64",
"give {p} minecraft:cherry_log 64",
"give {p} minecraft:mangrove_log 64",
], "All 8 wood types, one stack each."),
("sudo clear my inventory", ["clear {p}"], "Cleared all items."),
("sudo tp me to 0 100 0", ["tp {p} 0 100 0"], "Teleported to coordinates."),
("sudo gamemode creative", ["gamemode creative {p}"], "Set creative mode."),
("sudo gamemode survival", ["gamemode survival {p}"], "Set survival mode."),
("sudo kill all zombies", ["kill @e[type=minecraft:zombie]"], "Killed all zombies."),
("sudo summon 5 cows", [
"summon minecraft:cow ~ ~ ~1",
"summon minecraft:cow ~ ~ ~2",
"summon minecraft:cow ~ ~ ~3",
"summon minecraft:cow ~1 ~ ~1",
"summon minecraft:cow ~1 ~ ~2",
], "Summoned 5 cows nearby."),
("sudo give everyone a diamond", [
"give @a minecraft:diamond 1",
], "Gave all players a diamond."),
("sudo set time to sunrise", ["time set 23000"], "Set to dawn (tick 23000)."),
("sudo fill a 5x5 area with gold blocks under me", [
"fill ~-2 ~-1 ~-2 ~2 ~-1 ~2 minecraft:gold_block",
], "Filled 5x5 gold platform under player."),
("sudo give me a trident with loyalty and channeling", [
"give {p} minecraft:trident[enchantments={loyalty:3,channeling:1,impaling:5,unbreaking:3,mending:1}] 1",
], "Trident with loyalty 3, channeling, impaling 5. Loyalty and riptide are mutually exclusive — used loyalty."),
("sudo night vision forever", [
"effect give {p} minecraft:night_vision 999999 0",
], "Permanent night vision."),
("sudo repair what I'm holding", [
"give {p} minecraft:experience_bottle 64",
], "Gave XP bottles — use with mending items to repair. Cannot directly repair via commands."),
("sudo give me a mace", [
"give {p} minecraft:mace[enchantments={density:5,wind_burst:3,unbreaking:3,mending:1}] 1",
], "Mace with density 5 and wind burst 3. New 1.21 weapon."),
("sudo spawn a warden", [
"summon minecraft:warden ~ ~ ~5",
], "Summoned warden 5 blocks away. Be careful — 500 HP, 2-hit kill."),
("sudo give me all the music discs", [
"give {p} minecraft:music_disc_13 1",
"give {p} minecraft:music_disc_cat 1",
"give {p} minecraft:music_disc_blocks 1",
"give {p} minecraft:music_disc_chirp 1",
"give {p} minecraft:music_disc_far 1",
"give {p} minecraft:music_disc_mall 1",
"give {p} minecraft:music_disc_mellohi 1",
"give {p} minecraft:music_disc_stal 1",
"give {p} minecraft:music_disc_strad 1",
"give {p} minecraft:music_disc_ward 1",
"give {p} minecraft:music_disc_pigstep 1",
"give {p} minecraft:music_disc_otherside 1",
], "All music discs."),
("sudo potion of the turtle master", [
"give {p} minecraft:potion[potion_contents={potion:\"minecraft:turtle_master\"}] 1",
], "Turtle master potion — slowness 4 + resistance 3."),
("sudo banner with a skull pattern", [
"give {p} minecraft:white_banner[banner_patterns=[{pattern:\"minecraft:skull\",color:\"black\"}]] 1",
], "White banner with black skull pattern using 1.21 syntax."),
]
for prompt, cmds_tmpl, reasoning in COMMANDS:
player = random.choice(PLAYERS)
cmds = [c.replace("{p}", player) for c in cmds_tmpl]
msgs = [sys_msg("sudo"), user_msg(f"Player {player}: {prompt}")]
all_ok = True
for cmd in cmds:
rcon_result = rcon.command(cmd)
ok = not is_error(rcon_result)
if not ok:
all_ok = False
msgs.append(tool_call("rcon.execute", {"command": cmd}))
msgs.append(tool_result({"success": ok, "result": rcon_result[:300]}))
resp = {"risk_level": 3, "commands": cmds, "reasoning": reasoning}
msgs.append(final_response(resp))
examples.append({
"id": f"rcon-direct-{len(examples):03d}",
"source": "rcon_validated",
"type": "direct_command",
"rcon_validated": True,
"all_success": all_ok,
"messages": msgs,
})
return examples
def gen_memory_examples(rcon):
"""Memory read/write examples."""
examples = []
MEMORY_OPS = [
("sudo remember this as home", "write", "home", "location", {"x": 100, "y": 64, "z": -200}, None,
"Saved current location as 'home'."),
("sudo save this spot as my base", "write", "base", "location", {"x": -500, "y": 72, "z": 300}, None,
"Saved base location."),
("sudo tp me home", "read", "home", None, None, "tp {p} 100 64 -200",
"Read 'home' from memory. Teleporting."),
("sudo take me to my base", "read", "base", None, None, "tp {p} -500 72 300",
"Read 'base' from memory. Teleporting."),
("sudo what do you remember about me?", "read", None, None, None, None,
"Listed all memories for this player."),
("sudo remember my favorite tool is a pickaxe", "write", "favorite_tool", "preference", "diamond pickaxe", None,
"Saved tool preference."),
("sudo remember Ace is my enemy", "write", "enemy_ace", "fact", "Ace13245 is an enemy", None,
"Noted player relationship."),
("sudo forget my base", "delete", "base", None, None, None,
"Deleted 'base' memory."),
("sudo save this as my mine", "write", "mine", "location", {"x": 30, "y": 11, "z": -80}, None,
"Saved mining location."),
("sudo tp me to my mine", "read", "mine", None, None, "tp {p} 30 11 -80",
"Read 'mine' from memory. Teleporting to Y=11."),
]
for prompt, action, key, mtype, value, cmd_tmpl, reasoning in MEMORY_OPS:
player = random.choice(PLAYERS)
msgs = [sys_msg("sudo"), user_msg(f"Player {player}: {prompt}")]
if action == "write":
msgs.append(tool_call("memory.write", {"player": player, "type": mtype, "key": key, "value": value}))
msgs.append(tool_result({"ok": True, "key": key}))
resp = {"risk_level": 4, "commands": [], "reasoning": reasoning}
elif action == "read":
args = {"player": player}
if key:
args["key"] = key
msgs.append(tool_call("memory.read", args))
if key:
mem_val = value or {"x": random.randint(-500,500), "y": random.randint(60,120), "z": random.randint(-500,500)}
msgs.append(tool_result({"memories": [{"key": key, "type": mtype or "location", "value": mem_val}]}))
else:
msgs.append(tool_result({"memories": [
{"key": "home", "type": "location", "value": {"x": 100, "y": 64, "z": -200}},
{"key": "favorite_tool", "type": "preference", "value": "diamond pickaxe"},
]}))
if cmd_tmpl:
cmd = cmd_tmpl.replace("{p}", player)
result = rcon.command(cmd)
msgs.append(tool_call("rcon.execute", {"command": cmd}))
msgs.append(tool_result({"success": not is_error(result), "result": result[:200]}))
resp = {"risk_level": 3, "commands": [cmd], "reasoning": reasoning}
else:
resp = {"risk_level": 4, "commands": [], "reasoning": reasoning}
elif action == "delete":
msgs.append(tool_call("memory.read", {"player": player, "key": key}))
msgs.append(tool_result({"memories": [{"key": key, "type": "location", "value": {"x": -500, "y": 72, "z": 300}}]}))
resp = {"risk_level": 3, "commands": [], "reasoning": reasoning}
msgs.append(final_response(resp))
examples.append({
"id": f"rcon-memory-{len(examples):03d}",
"source": "rcon_validated",
"type": f"memory_{action}",
"messages": msgs,
})
return examples
def gen_wiki_examples(rcon):
"""Wiki lookup → command execution with real RCON results."""
examples = []
WIKI = [
("sudo best pickaxe enchantments", "pickaxe enchantments 1.21",
"Pickaxe enchantments:\n- Efficiency V: faster mining\n- Fortune III: more drops from ores\n- Silk Touch: mine blocks directly\n- Unbreaking III: durability\n- Mending: XP repair\nFortune and Silk Touch are mutually exclusive.",
["give {p} minecraft:netherite_pickaxe[enchantments={efficiency:5,fortune:3,unbreaking:3,mending:1}] 1"],
"Max pickaxe with fortune. Fortune and silk touch are exclusive — chose fortune for ore farming."),
("sudo what enchants for boots?", "boot enchantments 1.21",
"Boot enchantments:\n- Protection IV or Blast/Fire/Projectile Protection IV\n- Feather Falling IV: reduces fall damage\n- Depth Strider III or Frost Walker II (exclusive)\n- Soul Speed III: faster on soul sand\n- Swift Sneak III: faster sneaking\n- Unbreaking III, Mending I",
["give {p} minecraft:netherite_boots[enchantments={protection:4,feather_falling:4,depth_strider:3,soul_speed:3,unbreaking:3,mending:1}] 1"],
"All compatible boot enchants. Depth strider over frost walker for general use."),
("sudo how do I use the /place command?", "place command 1.21",
"/place feature <feature> [pos]\n/place jigsaw <pool> <target> <max_depth> [pos]\n/place structure <structure> [pos]\n/place template <template> [pos] [rotation] [mirror]\n\nUseful for placing structures, trees, etc.",
["place feature minecraft:oak ~ ~ ~5"],
"Placed an oak tree feature 5 blocks away using /place."),
("sudo what's the command for teams?", "team command minecraft",
"Team commands:\n/team add <name> [display_name]\n/team join <team> [members]\n/team leave [members]\n/team modify <team> <option> <value>\nOptions: color, friendlyFire, seeFriendlyInvisibles, nametagVisibility, collisionRule, prefix, suffix",
["team add red Red Team", "team modify red color red"],
"Created 'Red Team' with red name color."),
("sudo how to make colored text in chat?", "tellraw color formatting minecraft",
"tellraw @a {\"text\":\"Hello\",\"color\":\"gold\",\"bold\":true}\nColors: black, dark_blue, dark_green, dark_aqua, dark_red, dark_purple, gold, gray, dark_gray, blue, green, aqua, red, light_purple, yellow, white\nFormatting: bold, italic, underlined, strikethrough, obfuscated",
['tellraw @a {"text":"Welcome to the server!","color":"gold","bold":true}'],
"Used tellraw with gold color and bold formatting."),
]
for prompt, query, content, cmds_tmpl, reasoning in WIKI:
player = random.choice(PLAYERS)
cmds = [c.replace("{p}", player) for c in cmds_tmpl]
msgs = [sys_msg("sudo"), user_msg(f"Player {player}: {prompt}")]
msgs.append(tool_call("minecraft.wiki_lookup", {"query": query}))
msgs.append(tool_result({"content": content, "url": f"https://minecraft.wiki/w/{query.split()[0]}"}))
for cmd in cmds:
result = rcon.command(cmd)
msgs.append(tool_call("rcon.execute", {"command": cmd}))
msgs.append(tool_result({"success": not is_error(result), "result": result[:300]}))
resp = {"risk_level": 3, "commands": cmds, "reasoning": reasoning}
msgs.append(final_response(resp))
examples.append({
"id": f"rcon-wiki-{len(examples):03d}",
"source": "rcon_validated",
"type": "wiki_lookup",
"messages": msgs,
})
return examples
def gen_error_correction_examples(rcon):
"""Commands that fail, get corrected, and succeed — with real RCON errors."""
examples = []
ERRORS = [
("sudo give me a bed", "give {p} minecraft:bed 1", "give {p} minecraft:white_bed 1",
"No item 'bed' — correct ID is 'white_bed' in 1.21."),
("sudo give me cooked beef", "give {p} minecraft:steak 1", "give {p} minecraft:cooked_beef 1",
"Item is 'cooked_beef', not 'steak'."),
("sudo give me speed", "effect give {p} minecraft:speed", "effect give {p} minecraft:speed 300 1",
"Effect needs duration and amplifier arguments."),
("sudo give me a log", "give {p} minecraft:log 64", "give {p} minecraft:oak_log 64",
"No item 'log' — must specify wood type: oak_log, spruce_log, etc."),
("sudo fill with stone 10", "fill ~ ~ ~ ~10 ~10 ~10 minecraft:stone 10", "fill ~ ~ ~ ~10 ~10 ~10 minecraft:stone",
"Fill doesn't take a trailing count number."),
]
for prompt, wrong_cmd_tmpl, right_cmd_tmpl, reasoning in ERRORS:
player = random.choice(PLAYERS)
wrong_cmd = wrong_cmd_tmpl.replace("{p}", player)
right_cmd = right_cmd_tmpl.replace("{p}", player)
msgs = [sys_msg("sudo"), user_msg(f"Player {player}: {prompt}")]
# Wrong attempt
wrong_result = rcon.command(wrong_cmd)
msgs.append(tool_call("rcon.execute", {"command": wrong_cmd}))
msgs.append(tool_result({"success": False, "result": wrong_result[:300]}))
# Corrected attempt
right_result = rcon.command(right_cmd)
msgs.append(tool_call("rcon.execute", {"command": right_cmd}))
msgs.append(tool_result({"success": not is_error(right_result), "result": right_result[:300]}))
resp = {"risk_level": 3, "commands": [right_cmd], "reasoning": f"First attempt failed: {wrong_result[:100]}. {reasoning}"}
msgs.append(final_response(resp))
examples.append({
"id": f"rcon-errfix-{len(examples):03d}",
"source": "rcon_validated",
"type": "error_correction",
"messages": msgs,
})
return examples
def gen_chained_examples(rcon):
"""Multi-tool chained examples with real RCON."""
examples = []
CHAINS = [
("sudo gear me up for the nether", [
("rcon.execute", {"command": "give {p} minecraft:netherite_sword[enchantments={sharpness:5,fire_aspect:2,unbreaking:3,mending:1}] 1"}),
("rcon.execute", {"command": "give {p} minecraft:netherite_pickaxe[enchantments={efficiency:5,fortune:3,unbreaking:3,mending:1}] 1"}),
("rcon.execute", {"command": "give {p} minecraft:netherite_chestplate[enchantments={protection:4,unbreaking:3,mending:1}] 1"}),
("rcon.execute", {"command": "effect give {p} minecraft:fire_resistance 6000 0"}),
("rcon.execute", {"command": "give {p} minecraft:golden_apple 16"}),
("rcon.execute", {"command": "give {p} minecraft:ender_pearl 16"}),
], "Full nether loadout: netherite sword+pick, protection armor, fire resistance, golden apples, pearls."),
("sudo prepare me for an end fight", [
("rcon.execute", {"command": "give {p} minecraft:netherite_sword[enchantments={sharpness:5,unbreaking:3,mending:1}] 1"}),
("rcon.execute", {"command": "give {p} minecraft:bow[enchantments={power:5,infinity:1,unbreaking:3}] 1"}),
("rcon.execute", {"command": "give {p} minecraft:arrow 64"}),
("rcon.execute", {"command": "give {p} minecraft:golden_apple 32"}),
("rcon.execute", {"command": "give {p} minecraft:ender_pearl 16"}),
("rcon.execute", {"command": "effect give {p} minecraft:slow_falling 600 0"}),
("rcon.execute", {"command": "give {p} minecraft:cobblestone 128"}),
], "End fight kit: weapons, slow falling for void safety, blocks for pillaring, pearls for dodging."),
]
for prompt, tool_calls, reasoning in CHAINS:
player = random.choice(PLAYERS)
msgs = [sys_msg("sudo"), user_msg(f"Player {player}: {prompt}")]
all_cmds = []
for tool_name, args_tmpl in tool_calls:
args = {}
for k, v in args_tmpl.items():
args[k] = v.replace("{p}", player) if isinstance(v, str) else v
if tool_name == "rcon.execute":
cmd = args["command"]
result = rcon.command(cmd)
msgs.append(tool_call(tool_name, args))
msgs.append(tool_result({"success": not is_error(result), "result": result[:300]}))
all_cmds.append(cmd)
else:
msgs.append(tool_call(tool_name, args))
msgs.append(tool_result({"ok": True}))
resp = {"risk_level": 3, "commands": all_cmds, "reasoning": reasoning}
msgs.append(final_response(resp))
examples.append({
"id": f"rcon-chain-{len(examples):03d}",
"source": "rcon_validated",
"type": "chained",
"messages": msgs,
})
return examples
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--rcon-host", default="192.168.0.244")
parser.add_argument("--rcon-port", type=int, default=25577)
parser.add_argument("--rcon-pass", default="REDACTED_RCON")
args = parser.parse_args()
print(f"Connecting to RCON at {args.rcon_host}:{args.rcon_port}...")
rcon = SimpleRCON(args.rcon_host, args.rcon_port, args.rcon_pass)
print("Connected.\n")
all_examples = []
print("Generating script examples...")
scripts = gen_script_examples(rcon)
all_examples.extend(scripts)
print(f" {len(scripts)} script examples")
print("Generating direct command examples...")
direct = gen_direct_command_examples(rcon)
all_examples.extend(direct)
print(f" {len(direct)} direct command examples")
print("Generating memory examples...")
memory = gen_memory_examples(rcon)
all_examples.extend(memory)
print(f" {len(memory)} memory examples")
print("Generating wiki examples...")
wiki = gen_wiki_examples(rcon)
all_examples.extend(wiki)
print(f" {len(wiki)} wiki examples")
print("Generating error correction examples...")
errors = gen_error_correction_examples(rcon)
all_examples.extend(errors)
print(f" {len(errors)} error correction examples")
print("Generating chained multi-tool examples...")
chained = gen_chained_examples(rcon)
all_examples.extend(chained)
print(f" {len(chained)} chained examples")
# Stats
success_count = sum(1 for e in all_examples if e.get("all_success", True))
print(f"\nTotal: {len(all_examples)} examples")
print(f" RCON validated: {sum(1 for e in all_examples if e.get('rcon_validated', False))}")
OUTPUT_PATH.parent.mkdir(parents=True, exist_ok=True)
with open(OUTPUT_PATH, "w") as f:
for ex in all_examples:
f.write(json.dumps(ex, ensure_ascii=False) + "\n")
print(f"Written to {OUTPUT_PATH}")
if __name__ == "__main__":
main()