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>
This commit is contained in:
Mortdecai
2026-03-21 03:14:45 -04:00
parent 434589d098
commit da8f557219
34 changed files with 7822 additions and 2 deletions
@@ -0,0 +1,567 @@
#!/usr/bin/env python3
"""
Generate expanded tool-calling training data for underrepresented tools.
Targets:
- minecraft.wiki_lookup: +50 examples
- world.player_info: +50 examples
- world.server_state: +30 examples
- world.nearby_entities: +40 examples (NEW tool)
- memory.read: +30 examples (NEW tool)
- memory.write: +25 examples (NEW tool)
- chained tool calls: +25 examples (multi-tool sequences)
Total: ~250 new training examples
Usage:
python training/scripts/generate_expanded_tool_training.py
"""
import json
import random
import sys
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, QWEN3_TOOLS
from agent.prompts.system_prompts import SYNTAX_RULES, RISK_GRADIENT
OUTPUT_PATH = PROJECT_ROOT / "data" / "raw" / "expanded_tool_training.jsonl"
TOOLS_BLOCK = qwen3_tools_block()
SUDO_TOOL_SYSTEM = (
"You are a Minecraft 1.21 command translator for a server admin. "
"You receive natural language requests and return valid RCON commands.\n\n"
"PERMISSION LEVEL: 4 (generous). Only refuse level 0-1 actions.\n\n"
"You have access to tools. Call them to execute commands, look up syntax, "
"or check player/server state. When a command fails, analyze the error "
"and retry with a corrected command.\n\n"
"After all tool calls resolve, respond with JSON:\n"
'{"risk_level": <int 0-5>, "commands": ["cmd1", ...], "reasoning": "why"}\n\n'
+ SYNTAX_RULES + RISK_GRADIENT + "\n" + TOOLS_BLOCK
)
GOD_TOOL_SYSTEM = (
"You are God in a Minecraft server. Players pray to you and you respond "
"with divine judgment.\n\n"
"You have access to tools. Call them to execute commands, look up syntax, "
"or check player/server state. When a command fails, analyze the error "
"and retry with a corrected command.\n\n"
"After all tool calls resolve, respond with JSON:\n"
'{"risk_level": <int 0-5>, "message": "Your divine response", '
'"commands": ["cmd1", ...], "reasoning": "why"}\n\n'
+ SYNTAX_RULES + "\n" + TOOLS_BLOCK
)
PLAYERS = ["slingshooter08", "Ace13245", "TheBigBoss", "xXDragonSlayerXx", "CreeperKing99", "NotchFan2012"]
def sys_msg(mode="sudo"):
return {"role": "system", "content": GOD_TOOL_SYSTEM if mode == "god" else SUDO_TOOL_SYSTEM}
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 rpos():
return {"x": random.randint(-500, 500), "y": random.randint(62, 120), "z": random.randint(-500, 500)}
def rcon_ok(cmd, player="slingshooter08"):
if cmd.startswith("give "): return f"Gave item to {player}"
if cmd.startswith("tp "): return f"Teleported {player}"
if cmd.startswith("effect give "): return f"Applied effect to {player}"
if cmd.startswith("kill "): return "Killed entity"
if cmd.startswith("summon "): return "Summoned new entity"
if cmd.startswith("fill "): return "Successfully filled blocks"
if cmd.startswith("setblock "): return "Changed the block"
if cmd.startswith("weather "): return "Changing weather"
if cmd.startswith("time set "): return "Set the time"
if cmd.startswith("clear "): return f"Removed items from {player}"
if cmd.startswith("gamerule "): return "Gamerule updated"
if cmd.startswith("execute "): return "Executed command"
if cmd.startswith("title "): return "Title displayed"
if cmd.startswith("playsound "): return f"Played sound to {player}"
if cmd.startswith("scoreboard "): return "Scoreboard updated"
return "Command executed successfully"
def make_example(eid, etype, messages):
return {"id": eid, "source": "expanded_tool_training", "type": etype, "messages": messages}
# ── Wiki Lookup Examples ──────────────────────────────────────────────────
WIKI_EXAMPLES = [
("sudo give me a mace with the best enchantments", "mace enchantments 1.21",
"Mace enchantments in 1.21:\n- Density (1-5): Increases damage based on fall distance\n- Breach (1-4): Reduces armor effectiveness\n- Wind Burst (1-3): Launches attacker upward on hit\n- Smite (1-5): Extra damage to undead\n- Bane of Arthropods (1-5): Extra damage to arthropods\n- Fire Aspect (1-2): Sets target on fire\n- Unbreaking (1-3): Durability\n- Mending (1): XP repair\nNote: Density, Breach, Smite, and Bane of Arthropods are mutually exclusive.",
"https://minecraft.wiki/w/Mace", ["give {p} minecraft:mace[enchantments={{density:5,wind_burst:3,fire_aspect:2,unbreaking:3,mending:1}}] 1"],
"Looked up mace enchantments. Density and breach are exclusive — chose density for max fall damage. Added wind_burst for combos."),
("sudo what are all the copper block variants?", "copper block variants oxidation 1.21",
"Copper blocks in 1.21 have 4 oxidation states and 2 waxing states:\n- copper_block, exposed_copper, weathered_copper, oxidized_copper\n- Cut variants: cut_copper, exposed_cut_copper, weathered_cut_copper, oxidized_cut_copper\n- Slab/stair variants for each\n- Waxed variants of all (prefix waxed_)\n- Copper bulb, copper door, copper trapdoor, copper grate (also with oxidation states)\nUse honeycomb to wax. Axe to scrape oxidation.",
"https://minecraft.wiki/w/Copper_Block", ["give {p} minecraft:copper_block 64", "give {p} minecraft:exposed_copper 64", "give {p} minecraft:weathered_copper 64", "give {p} minecraft:oxidized_copper 64"],
"Looked up copper variants. Gave one stack of each oxidation state."),
("sudo how do I make a command block chain?", "command block chain repeating impulse 1.21",
"Command block types:\n- Impulse (orange): Executes once when triggered\n- Chain (green): Executes when the block behind it activates\n- Repeating (purple): Executes every tick while powered\n\nPlacement: command_block (impulse), chain_command_block, repeating_command_block\nModes: Always Active or Needs Redstone\nConditional: Only runs if previous block in chain succeeded",
"https://minecraft.wiki/w/Command_Block", ["give {p} minecraft:command_block 1", "give {p} minecraft:chain_command_block 4", "give {p} minecraft:repeating_command_block 1"],
"Looked up command block types. Gave impulse, chain, and repeating blocks for a chain setup."),
("sudo what's the syntax for the attribute command?", "attribute command syntax 1.21",
"attribute <target> <attribute> base get|set <value>\nattribute <target> <attribute> modifier add <uuid> <name> <value> add|multiply|multiply_base\nattribute <target> <attribute> modifier remove <uuid>\n\nCommon attributes:\n- minecraft:generic.max_health (default 20)\n- minecraft:generic.movement_speed (default 0.1)\n- minecraft:generic.attack_damage (default 1)\n- minecraft:generic.armor (default 0)\n- minecraft:generic.knockback_resistance (0-1)",
"https://minecraft.wiki/w/Attribute", ["attribute {p} minecraft:generic.max_health base set 40"],
"Looked up attribute syntax. Set max health to 40 (double normal)."),
("sudo what does the wind charge do?", "wind charge item minecraft 1.21",
"Wind Charge: Projectile item added in 1.21\n- Thrown like a snowball\n- On impact: creates wind burst that knocks back entities and activates redstone\n- Players can use it for movement: throw at feet for a boost\n- Breeze mob shoots these naturally\n- Item: minecraft:wind_charge",
"https://minecraft.wiki/w/Wind_Charge", ["give {p} minecraft:wind_charge 16"],
"Looked up wind charge mechanics. Gave 16 wind charges."),
("sudo how does the trial spawner work?", "trial spawner mechanics 1.21",
"Trial Spawner: Found in Trial Chambers\n- Spawns mobs based on nearby players\n- Becomes 'ominous' if player has Bad Omen\n- Cannot be obtained with Silk Touch\n- Ejects rewards when all mobs defeated\n- Cooldown of 30 minutes per player\n- Item: minecraft:trial_spawner (creative only)",
"https://minecraft.wiki/w/Trial_Spawner", ["give {p} minecraft:trial_spawner 1"],
"Looked up trial spawner. It's a creative-only item. Giving one."),
("sudo what are the vault block mechanics?", "vault block trial chambers 1.21",
"Vault: Loot container in Trial Chambers\n- Each player can open it once with a trial key\n- Drops random loot (armor trims, enchanted books, etc.)\n- Ominous vault: requires ominous trial key, better loot\n- Items: minecraft:vault, minecraft:trial_key, minecraft:ominous_trial_key",
"https://minecraft.wiki/w/Vault", ["give {p} minecraft:vault 1", "give {p} minecraft:trial_key 3"],
"Looked up vault mechanics. Gave a vault and 3 trial keys."),
("sudo what food gives the most saturation?", "food saturation values minecraft",
"Highest saturation foods:\n1. Golden carrot: 14.4 saturation, 6 hunger\n2. Cooked porkchop: 12.8 saturation, 8 hunger\n3. Steak (cooked beef): 12.8 saturation, 8 hunger\n4. Cooked mutton: 9.6 saturation, 6 hunger\n5. Cooked salmon: 9.6 saturation, 6 hunger\n6. Suspicious stew varies by flower\nGolden apple: 9.6 sat, enchanted golden apple: 9.6 sat",
"https://minecraft.wiki/w/Food", ["give {p} minecraft:golden_carrot 64", "give {p} minecraft:cooked_beef 64"],
"Looked up food saturation. Golden carrots have the best saturation. Gave those plus steak."),
("sudo what's the difference between smite and sharpness?", "smite vs sharpness enchantment damage",
"Sharpness: +0.5 * level + 0.5 damage to all mobs (max V = 3 extra)\nSmite: +2.5 * level damage to undead only (max V = 12.5 extra)\nBane of Arthropods: +2.5 * level to arthropods only\n\nThese three are mutually exclusive.\nSmite is better vs undead (zombies, skeletons, wither, phantoms).\nSharpness is better for general use.",
"https://minecraft.wiki/w/Sharpness", ["give {p} minecraft:diamond_sword[enchantments={{sharpness:5,unbreaking:3,mending:1,looting:3,sweeping_edge:3}}] 1"],
"Looked up sharpness vs smite. Sharpness is better for general use. Gave max enchanted sword."),
("sudo what's the recipe for a lodestone?", "lodestone recipe crafting minecraft",
"Lodestone recipe:\n- 8 chiseled stone bricks (surrounding)\n- 1 netherite ingot (center)\nCrafting: 3x3 grid with chiseled stone bricks around netherite ingot\nUsage: Right-click with compass to bind it. Works across dimensions.",
"https://minecraft.wiki/w/Lodestone", ["give {p} minecraft:lodestone 1"],
"Looked up lodestone recipe. It requires a netherite ingot. Giving one directly."),
("sudo what paintings are available in 1.21?", "paintings list new 1.21",
"1.21 added 20 new paintings by artist Sarah Boeving:\n- backyard, bouquet, cavebird, changing, cotan, endboss, fern, finding, lowmist, orb, owlemons, passage, pond, sunflowers, tides, unpacked\nPaintings are placed with: give <player> minecraft:painting 1\nThe painting chosen depends on wall size.",
"https://minecraft.wiki/w/Painting", ["give {p} minecraft:painting 5"],
"Looked up 1.21 paintings. 20 new ones added. Gave 5 paintings to place."),
("sudo how do I use the /damage command?", "damage command syntax 1.21",
"damage <target> <amount> [<damageType>] [at <location>] [by <entity>] [from <cause>]\n\nExamples:\ndamage @p 5 minecraft:fall\ndamage @e[type=zombie,limit=1] 10 minecraft:player_attack by @p\n\nDamage types: fall, fire, drown, starve, freeze, player_attack, mob_attack, explosion, etc.",
"https://minecraft.wiki/w/Commands/damage", ["damage @e[type=zombie,distance=..10] 20 minecraft:player_attack"],
"Looked up /damage syntax. Dealt 20 damage to nearby zombies."),
("sudo what are all the armor trim patterns?", "armor trim patterns smithing template 1.21",
"Armor trim patterns (smithing templates):\nCoast, Dune, Eye, Host, Raiser, Rib, Sentry, Shaper, Silence, Snout, Spire, Tide, Vex, Ward, Wayfinder, Wild, Bolt, Flow\n\nMaterials for color: iron, copper, gold, lapis, emerald, diamond, netherite, redstone, amethyst, quartz\n\nApply: Smithing table + template + armor piece + material",
"https://minecraft.wiki/w/Armor_Trim", ["give {p} minecraft:bolt_armor_trim_smithing_template 1", "give {p} minecraft:flow_armor_trim_smithing_template 1"],
"Looked up armor trims. Bolt and Flow are the new 1.21 patterns. Gave both templates."),
("sudo what biomes have cherry trees?", "cherry grove biome minecraft",
"Cherry Grove biome:\n- Pink cherry blossom trees\n- Found at Y 100-256 in mountainous areas\n- Pigs, sheep, bees spawn naturally\n- Blocks: cherry_log, cherry_leaves, cherry_planks, cherry_sapling, pink_petals\n- Cherry wood set includes all standard wood items\nLocate: /locate biome minecraft:cherry_grove",
"https://minecraft.wiki/w/Cherry_Grove", ["locate biome minecraft:cherry_grove"],
"Looked up cherry grove. Using locate to find the nearest one."),
("sudo how does fortune work on different ores?", "fortune enchantment ore drops mechanics",
"Fortune on ores:\n- Coal, diamond, emerald, lapis, nether quartz, nether gold, copper, amethyst: increases drops\n- Iron, gold ore: Fortune does NOT work (must smelt raw ore)\n- Formula: Each level gives a chance for 1 extra drop\n - Fortune I: avg 1.33x, Fortune II: avg 1.75x, Fortune III: avg 2.2x\n- Lapis and copper have unique formulas (higher multipliers)\n- Does NOT affect XP drops",
"https://minecraft.wiki/w/Fortune", ["give {p} minecraft:diamond_pickaxe[enchantments={{fortune:3,efficiency:5,unbreaking:3,mending:1}}] 1"],
"Looked up fortune mechanics. Works on diamond/emerald/lapis but not iron/gold ore. Gave fortune 3 pickaxe."),
]
# ── Player Info Examples ──────────────────────────────────────────────────
PLAYER_INFO_SCENARIOS = [
("sudo build a wall around me", ["fill {x_m10} {y} {z_m10} {x_p10} {y_p4} {z_m10} minecraft:stone", "fill {x_m10} {y} {z_p10} {x_p10} {y_p4} {z_p10} minecraft:stone", "fill {x_m10} {y} {z_m10} {x_m10} {y_p4} {z_p10} minecraft:stone", "fill {x_p10} {y} {z_m10} {x_p10} {y_p4} {z_p10} minecraft:stone"], "Got player position. Built 4 stone walls in a 20x20 square around them."),
("sudo teleport me 50 blocks up", ["tp {p} {x} {y_p50} {z}"], "Got player position, teleported 50 blocks up."),
("sudo put lava under my feet", ["setblock {x} {y_m1} {z} minecraft:lava"], "Got player position. Placed lava one block below."),
("sudo create a beacon at my location", ["setblock {x} {y_m1} {z} minecraft:iron_block", "fill {x_m1} {y_m1} {z_m1} {x_p1} {y_m1} {z_p1} minecraft:iron_block", "setblock {x} {y} {z} minecraft:beacon"], "Got position. Built iron base and placed beacon."),
("sudo replace the ground around me with grass", ["fill {x_m5} {y_m1} {z_m5} {x_p5} {y_m1} {z_p5} minecraft:grass_block"], "Got position. Filled a 10x10 area below feet with grass."),
("sudo place torches around me in a circle", ["setblock {x_p4} {y} {z} minecraft:torch", "setblock {x_m4} {y} {z} minecraft:torch", "setblock {x} {y} {z_p4} minecraft:torch", "setblock {x} {y} {z_m4} minecraft:torch"], "Got position. Placed 4 torches at cardinal directions."),
("sudo tp me to the nearest village center", ["locate structure minecraft:village_plains"], "Got position for reference. Used locate to find nearest village."),
("sudo fill the area below me with water", ["fill {x_m3} {y_m5} {z_m3} {x_p3} {y_m1} {z_p3} minecraft:water"], "Got position. Filled 6x5x6 pool below player."),
("sudo make a platform of glass under me", ["fill {x_m5} {y_m1} {z_m5} {x_p5} {y_m1} {z_p5} minecraft:glass"], "Got position. Created 10x10 glass platform below feet."),
("sudo build an obsidian box around me", ["fill {x_m2} {y} {z_m2} {x_p2} {y_p3} {z_p2} minecraft:obsidian hollow"], "Got position. Built obsidian box around player."),
("sudo teleport me to the surface", ["tp {p} {x} 320 {z}"], "Got position. Teleported to build limit so player falls to surface with slow_falling."),
("sudo place a campfire at my feet", ["setblock {x} {y} {z} minecraft:campfire"], "Got position. Placed campfire at player location."),
("sudo light up this cave", ["setblock {x_p3} {y_p2} {z} minecraft:lantern", "setblock {x_m3} {y_p2} {z} minecraft:lantern", "setblock {x} {y_p2} {z_p3} minecraft:lantern", "setblock {x} {y_p2} {z_m3} minecraft:lantern", "setblock {x} {y_p2} {z} minecraft:lantern"], "Got position. Placed lanterns around the player to illuminate the area."),
("sudo surround me with fences", ["fill {x_m3} {y} {z_m3} {x_p3} {y_p1} {z_m3} minecraft:oak_fence replace minecraft:air", "fill {x_m3} {y} {z_p3} {x_p3} {y_p1} {z_p3} minecraft:oak_fence replace minecraft:air"], "Got position. Placed fence perimeter around player."),
("sudo clear all blocks 10 blocks above me", ["fill {x_m5} {y_p2} {z_m5} {x_p5} {y_p12} {z_p5} minecraft:air"], "Got position. Cleared 10-block column above player."),
("sudo spawn a zombie behind me", ["execute at {p} run summon minecraft:zombie ~ ~ ~-3"], "Got player position. Summoned zombie 3 blocks behind using execute at."),
("sudo put a chest with supplies at my location", ["setblock {x} {y} {z} minecraft:chest"], "Got position. Placed chest at player location."),
("sudo build stairs going up from where I am", ["setblock {x} {y} {z_p1} minecraft:oak_stairs[facing=south]", "setblock {x} {y_p1} {z_p2} minecraft:oak_stairs[facing=south]", "setblock {x} {y_p2} {z_p3} minecraft:oak_stairs[facing=south]"], "Got position. Built ascending stairs going south."),
("sudo make me a fishing spot", ["fill {x_m2} {y_m2} {z_p3} {x_p2} {y_m1} {z_p7} minecraft:water", "give {p} minecraft:fishing_rod 1"], "Got position. Dug pool nearby and gave fishing rod."),
("sudo set my spawn point here", ["spawnpoint {p} {x} {y} {z}"], "Got position. Set spawn point at current location."),
]
# ── Server State Examples ─────────────────────────────────────────────────
SERVER_STATE_SCENARIOS = [
("sudo give everyone online netherite armor", "Checked online players, giving each full netherite armor."),
("sudo announce it's getting dark soon", "Checked time — it's evening. Warning players about night."),
("sudo if it's thundering, summon lightning on everyone", "Checked weather. If thundering, striking lightning on all players."),
("sudo how many people are online?", "Checked server state. Reporting player count."),
("sudo make it night if it's currently day", "Checked time — it was daytime, switching to night."),
("sudo give bonus XP to everyone if it's raining", "Checked weather — raining, giving XP bonus."),
("sudo tp all players to spawn if it's nighttime", "Checked time — night, teleporting everyone to spawn."),
("sudo set weather opposite of current", "Checked weather state and set opposite."),
("sudo kill all hostile mobs if there are 3+ players online", "Checked online count. 3+ players → killing hostile mobs."),
("sudo announce the time and weather to everyone", "Checked server state. Broadcasting time and weather."),
]
# ── Nearby Entities Examples ──────────────────────────────────────────────
def sim_nearby_entities(types=None):
all_types = [
("zombie", random.randint(1, 5), round(random.uniform(3, 25), 1)),
("skeleton", random.randint(1, 3), round(random.uniform(5, 30), 1)),
("creeper", random.randint(1, 2), round(random.uniform(4, 20), 1)),
("cow", random.randint(2, 8), round(random.uniform(2, 15), 1)),
("sheep", random.randint(1, 6), round(random.uniform(3, 20), 1)),
("pig", random.randint(1, 4), round(random.uniform(5, 18), 1)),
("chicken", random.randint(2, 10), round(random.uniform(1, 12), 1)),
("spider", random.randint(1, 3), round(random.uniform(6, 25), 1)),
("enderman", 1, round(random.uniform(10, 40), 1)),
("villager", random.randint(1, 5), round(random.uniform(3, 20), 1)),
("iron_golem", 1, round(random.uniform(5, 15), 1)),
("wolf", random.randint(1, 3), round(random.uniform(4, 25), 1)),
]
if types:
selected = [e for e in all_types if e[0] in types]
else:
selected = random.sample(all_types, k=random.randint(2, 5))
entities = [{"type": f"minecraft:{t}", "count": c, "nearest_distance": d} for t, c, d in selected]
return {"entities": entities, "total": sum(e["count"] for e in entities)}
NEARBY_SCENARIOS = [
("sudo kill all the zombies near me", ["zombie"], ["kill @e[type=minecraft:zombie,distance=..32]"], "Scanned for entities. Found {n} zombies nearby. Killed them all."),
("sudo how many mobs are around me?", None, [], "Scanned entities within 32 blocks. Reporting counts."),
("sudo clear out the hostile mobs nearby", ["zombie", "skeleton", "creeper", "spider"], ["kill @e[type=minecraft:zombie,distance=..32]", "kill @e[type=minecraft:skeleton,distance=..32]", "kill @e[type=minecraft:creeper,distance=..32]", "kill @e[type=minecraft:spider,distance=..32]"], "Scanned for hostiles. Found and killed all nearby hostile mobs."),
("sudo are there any creepers near me?", ["creeper"], [], "Scanned for creepers. Reporting what's nearby."),
("sudo kill the closest zombie", ["zombie"], ["kill @e[type=minecraft:zombie,distance=..10,limit=1,sort=nearest]"], "Scanned to confirm zombie presence. Killed the nearest one."),
("sudo count the animals around me", ["cow", "sheep", "pig", "chicken"], [], "Scanned for animals. Reporting passive mob counts."),
("sudo kill all mobs except villagers in a 50 block radius", None, ["kill @e[type=!minecraft:villager,type=!minecraft:player,distance=..50]"], "Scanned area. Killing everything except villagers and players."),
("sudo are there any endermen nearby?", ["enderman"], [], "Scanned for endermen nearby."),
("sudo tame any wolves near me", ["wolf"], ["execute as @e[type=minecraft:wolf,distance=..20] run data merge entity @s {Owner:\"{p}\"}"], "Found wolves nearby. Taming them."),
("sudo protect me from nearby hostiles", ["zombie", "skeleton", "creeper"], ["kill @e[type=minecraft:zombie,distance=..20]", "kill @e[type=minecraft:skeleton,distance=..20]", "kill @e[type=minecraft:creeper,distance=..20]", "effect give {p} minecraft:resistance 60 2"], "Scanned for hostiles. Killed nearby ones and gave resistance."),
("sudo lead me to the nearest villager", ["villager"], [], "Scanned for villagers. Nearest one found — reporting location."),
("sudo spawn more of whatever animal is closest", ["cow", "sheep"], ["summon minecraft:cow ~ ~ ~"], "Scanned nearby. Cows closest. Summoned more."),
]
# ── Memory Examples ───────────────────────────────────────────────────────
MEMORY_WRITE_SCENARIOS = [
("sudo remember this location as home", "home", "location", {"x": 100, "y": 64, "z": -200}, "Saved current position as 'home'."),
("sudo remember my base is here", "base", "location", {"x": -350, "y": 72, "z": 180}, "Saved current position as 'base'."),
("sudo remember that I like diamonds", "favorite_item", "preference", "diamonds", "Noted preference for diamonds."),
("sudo save this spot as my nether portal", "nether_portal", "location", {"x": 50, "y": 68, "z": 90}, "Saved nether portal location."),
("sudo remember I'm building a castle here", "castle", "location", {"x": 200, "y": 80, "z": -100}, "Saved castle build location."),
("sudo my favorite color is red", "favorite_color", "preference", "red", "Remembered color preference."),
("sudo remember my farm is at 500 70 -300", "farm", "location", {"x": 500, "y": 70, "z": -300}, "Saved farm location from coordinates."),
("sudo remember I don't want to be teleported randomly", "no_random_tp", "preference", "no random teleports", "Noted: player prefers no random teleports."),
("sudo save this as my mining spot", "mining_spot", "location", {"x": -100, "y": 12, "z": 400}, "Saved mining location."),
("sudo remember that Ace13245 is my friend", "friend_ace", "fact", "Ace13245 is a friend", "Saved social fact."),
]
MEMORY_READ_SCENARIOS = [
("sudo tp me home", "home", True, "tp {p} {mx} {my} {mz}", "Read memory for 'home'. Teleporting to saved location."),
("sudo take me to my base", "base", True, "tp {p} {mx} {my} {mz}", "Read memory for 'base'. Teleporting."),
("sudo what do you know about me?", None, True, None, "Read all memories for this player. Listing what I know."),
("sudo where's my nether portal?", "nether_portal", True, None, "Read memory for 'nether portal'. Reporting coordinates."),
("sudo tp me to my farm", "farm", True, "tp {p} {mx} {my} {mz}", "Read memory for 'farm'. Teleporting."),
("sudo do I have a saved home?", "home", False, None, "Checked memories. No 'home' location saved for this player."),
("sudo forget my base location", "base", True, None, "Found 'base' memory. Removing it."),
("sudo tp me to my mining spot", "mining_spot", True, "tp {p} {mx} {my} {mz}", "Read memory for 'mining_spot'. Teleporting."),
("sudo where did I say my castle was?", "castle", True, None, "Read memory for 'castle'. Reporting saved location."),
("sudo take me back to where I was building", "castle", True, "tp {p} {mx} {my} {mz}", "Read 'castle' memory. Teleporting to build site."),
]
# ── Chained Tool Call Examples ────────────────────────────────────────────
# These combine multiple tools in one conversation
CHAINED_SCENARIOS = [
# player_info + nearby_entities + rcon
("sudo protect me from everything nearby",
["player_info", "nearby_entities", "rcon"],
"Got position and scanned for hostiles. Killed threats and applied protection."),
# memory + player_info + rcon
("sudo save this spot and build a marker",
["player_info", "memory_write", "rcon"],
"Got position, saved to memory, and built a visible marker."),
# server_state + rcon (conditional)
("sudo if anyone is online, give them all food",
["server_state", "rcon"],
"Checked who's online. Gave food to all players."),
# memory + rcon (tp to saved location)
("sudo tp me home and heal me",
["memory_read", "rcon", "rcon"],
"Read home location from memory. Teleported and healed."),
# wiki + rcon (look up then execute)
("sudo give me whatever the strongest bow setup is",
["wiki", "rcon"],
"Looked up bow enchantments. Gave max enchanted bow."),
# player_info + server_state + rcon
("sudo set up a safe zone around me for the night",
["player_info", "server_state", "rcon"],
"Checked position and time. Built lit shelter for night."),
]
def generate_all():
examples = []
idx = 0
# ── Wiki lookups ──
for req, query, content, url, cmds, reasoning in WIKI_EXAMPLES:
player = random.choice(PLAYERS)
mode = "god" if req.startswith("pray ") else "sudo"
msgs = [sys_msg(mode), user_msg(f"Player {player}: {req}")]
msgs.append(tool_call("minecraft.wiki_lookup", {"query": query}))
msgs.append(tool_result({"content": content, "url": url}))
for cmd in cmds:
resolved = cmd.replace("{p}", player)
msgs.append(tool_call("rcon.execute", {"command": resolved}))
msgs.append(tool_result({"success": True, "result": rcon_ok(resolved, player)}))
resp = {"risk_level": 3, "commands": [c.replace("{p}", player) for c in cmds], "reasoning": reasoning}
msgs.append(final_response(resp))
examples.append(make_example(f"exp-wiki-{idx:03d}", "wiki_lookup", msgs))
idx += 1
# ── Player info ──
for req, cmds_tmpl, reasoning in PLAYER_INFO_SCENARIOS:
player = random.choice(PLAYERS)
pos = rpos()
mode = "god" if req.startswith("pray ") else "sudo"
msgs = [sys_msg(mode), user_msg(f"Player {player}: {req}")]
msgs.append(tool_call("world.player_info", {"player": player}))
pinfo = {"health": round(random.uniform(10, 20), 1), "position": pos,
"inventory_summary": "Diamond sword, iron armor, 32 steak"}
msgs.append(tool_result(pinfo))
resolved_cmds = []
for ct in cmds_tmpl:
c = ct.replace("{p}", player)
c = c.replace("{x}", str(pos["x"])).replace("{y}", str(pos["y"])).replace("{z}", str(pos["z"]))
for delta, tag in [(1, "_p1"), (2, "_p2"), (3, "_p3"), (4, "_p4"), (5, "_p5"), (10, "_p10"), (50, "_p50"),
(-1, "_m1"), (-2, "_m2"), (-3, "_m3"), (-5, "_m5"), (-10, "_m10"), (-100, "_minus_100")]:
c = c.replace(f"{{x{tag}}}", str(pos["x"] + delta))
c = c.replace(f"{{y{tag}}}", str(pos["y"] + delta))
c = c.replace(f"{{z{tag}}}", str(pos["z"] + delta))
resolved_cmds.append(c)
for cmd in resolved_cmds:
msgs.append(tool_call("rcon.execute", {"command": cmd}))
msgs.append(tool_result({"success": True, "result": rcon_ok(cmd, player)}))
resp = {"risk_level": 3, "commands": resolved_cmds, "reasoning": reasoning}
msgs.append(final_response(resp))
examples.append(make_example(f"exp-pinfo-{idx:03d}", "player_info_lookup", msgs))
idx += 1
# ── Server state ──
for req, reasoning in SERVER_STATE_SCENARIOS:
player = random.choice(PLAYERS)
mode = "god" if req.startswith("pray ") else "sudo"
msgs = [sys_msg(mode), user_msg(f"Player {player}: {req}")]
msgs.append(tool_call("world.server_state", {}))
state = {
"time_of_day": random.choice(["morning", "noon", "evening", "night"]),
"weather": random.choice(["clear", "rain", "thunder"]),
"online_players": random.sample(PLAYERS, k=random.randint(1, 4)),
"world_border": 60000000.0,
}
msgs.append(tool_result(state))
# Generate contextual commands based on state
cmds = []
if "everyone" in req.lower() or "all" in req.lower():
for p in state["online_players"]:
if "netherite" in req: cmds.extend([f"give {p} minecraft:netherite_helmet 1", f"give {p} minecraft:netherite_chestplate 1"])
elif "food" in req: cmds.append(f"give {p} minecraft:golden_carrot 32")
elif "XP" in req or "xp" in req: cmds.append(f"xp add {p} 500")
elif "heal" in req: cmds.append(f"effect give {p} minecraft:instant_health 1 5")
elif "tp" in req or "spawn" in req: cmds.append(f"tp {p} 0 64 0")
elif "diamond" in req: cmds.append(f"give {p} minecraft:diamond 1")
elif "weather" in req.lower():
opposite = "clear" if state["weather"] in ("rain", "thunder") else "rain"
cmds.append(f"weather {opposite}")
elif "night" in req.lower() or "dark" in req.lower():
cmds.append("time set night" if state["time_of_day"] in ("morning", "noon") else "time set day")
elif "day" in req.lower():
cmds.append("time set day" if state["time_of_day"] in ("evening", "night") else "time set night")
elif "announce" in req.lower() or "how many" in req.lower():
cmds.append(f"say Server: {len(state['online_players'])} players online, time is {state['time_of_day']}, weather is {state['weather']}")
elif "hostile" in req.lower() or "kill" in req.lower():
cmds.append("kill @e[type=!minecraft:player,type=!minecraft:villager,type=!minecraft:iron_golem]")
elif "lightning" in req.lower():
for p in state["online_players"]:
cmds.append(f"execute at {p} run summon minecraft:lightning_bolt")
if not cmds:
cmds = ["say Check complete"]
for cmd in cmds:
msgs.append(tool_call("rcon.execute", {"command": cmd}))
msgs.append(tool_result({"success": True, "result": rcon_ok(cmd, player)}))
resp = {"risk_level": 3, "commands": cmds, "reasoning": reasoning}
msgs.append(final_response(resp))
examples.append(make_example(f"exp-sstate-{idx:03d}", "server_state_check", msgs))
idx += 1
# ── Nearby entities ──
for req, entity_filter, cmds_tmpl, reasoning in NEARBY_SCENARIOS:
player = random.choice(PLAYERS)
msgs = [sys_msg("sudo"), user_msg(f"Player {player}: {req}")]
msgs.append(tool_call("world.nearby_entities", {"player": player, "radius": 32}))
ent_data = sim_nearby_entities(entity_filter)
msgs.append(tool_result(ent_data))
cmds = [c.replace("{p}", player) for c in cmds_tmpl]
n_found = ent_data["total"]
real_reasoning = reasoning.replace("{n}", str(n_found))
if cmds:
for cmd in cmds:
msgs.append(tool_call("rcon.execute", {"command": cmd}))
msgs.append(tool_result({"success": True, "result": rcon_ok(cmd, player)}))
resp = {"risk_level": 3, "commands": cmds, "reasoning": real_reasoning}
msgs.append(final_response(resp))
examples.append(make_example(f"exp-nearby-{idx:03d}", "nearby_entities", msgs))
idx += 1
# ── Memory write ──
for req, key, mtype, value, reasoning in MEMORY_WRITE_SCENARIOS:
player = random.choice(PLAYERS)
if mtype == "location" and isinstance(value, dict):
pos = rpos()
value = pos
msgs = [sys_msg("sudo"), user_msg(f"Player {player}: {req}")]
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}
msgs.append(final_response(resp))
examples.append(make_example(f"exp-memw-{idx:03d}", "memory_write", msgs))
idx += 1
# ── Memory read ──
for req, key, found, cmd_tmpl, reasoning in MEMORY_READ_SCENARIOS:
player = random.choice(PLAYERS)
msgs = [sys_msg("sudo"), user_msg(f"Player {player}: {req}")]
if key:
msgs.append(tool_call("memory.read", {"player": player, "key": key}))
else:
msgs.append(tool_call("memory.read", {"player": player}))
if found:
pos = rpos()
if key:
mem = [{"key": key, "type": "location", "value": {"x": pos["x"], "y": pos["y"], "z": pos["z"]}}]
else:
mem = [
{"key": "home", "type": "location", "value": rpos()},
{"key": "favorite_item", "type": "preference", "value": "diamonds"},
]
msgs.append(tool_result({"memories": mem}))
if cmd_tmpl:
cmd = cmd_tmpl.replace("{p}", player).replace("{mx}", str(pos["x"])).replace("{my}", str(pos["y"])).replace("{mz}", str(pos["z"]))
msgs.append(tool_call("rcon.execute", {"command": cmd}))
msgs.append(tool_result({"success": True, "result": rcon_ok(cmd, player)}))
resp = {"risk_level": 3, "commands": [cmd], "reasoning": reasoning}
else:
resp = {"risk_level": 4, "commands": [], "reasoning": reasoning}
else:
msgs.append(tool_result({"memories": []}))
resp = {"risk_level": 4, "commands": [], "reasoning": reasoning}
msgs.append(final_response(resp))
examples.append(make_example(f"exp-memr-{idx:03d}", "memory_read", msgs))
idx += 1
# ── Chained tool calls ──
for req, tools, reasoning in CHAINED_SCENARIOS:
player = random.choice(PLAYERS)
pos = rpos()
msgs = [sys_msg("sudo"), user_msg(f"Player {player}: {req}")]
for t in tools:
if t == "player_info":
msgs.append(tool_call("world.player_info", {"player": player}))
msgs.append(tool_result({"health": 18.5, "position": pos, "inventory_summary": "Diamond gear"}))
elif t == "nearby_entities":
msgs.append(tool_call("world.nearby_entities", {"player": player, "radius": 32}))
msgs.append(tool_result(sim_nearby_entities(["zombie", "skeleton"])))
elif t == "server_state":
msgs.append(tool_call("world.server_state", {}))
msgs.append(tool_result({"time_of_day": "night", "weather": "clear", "online_players": [player, "Ace13245"], "world_border": 60000000.0}))
elif t == "memory_write":
msgs.append(tool_call("memory.write", {"player": player, "type": "location", "key": "marker", "value": pos}))
msgs.append(tool_result({"ok": True, "key": "marker"}))
elif t == "memory_read":
msgs.append(tool_call("memory.read", {"player": player, "key": "home"}))
home = rpos()
msgs.append(tool_result({"memories": [{"key": "home", "type": "location", "value": home}]}))
pos = home # use home coords for subsequent commands
elif t == "wiki":
msgs.append(tool_call("minecraft.wiki_lookup", {"query": "best bow enchantments 1.21"}))
msgs.append(tool_result({"content": "Bow: Power V, Infinity or Mending, Unbreaking III, Flame I, Punch II. Infinity and Mending are mutually exclusive.", "url": "https://minecraft.wiki/w/Bow"}))
elif t == "rcon":
cmd = f"give {player} minecraft:diamond 1"
if "heal" in req: cmd = f"effect give {player} minecraft:instant_health 1 5"
elif "protect" in req: cmd = f"kill @e[type=minecraft:zombie,distance=..32]"
elif "marker" in req or "build" in req: cmd = f"setblock {pos['x']} {pos['y']+1} {pos['z']} minecraft:glowstone"
elif "food" in req:
pass # handled per player below
elif "bow" in req: cmd = f"give {player} minecraft:bow[enchantments={{power:5,infinity:1,unbreaking:3,flame:1,punch:2}}] 1"
elif "home" in req or "tp" in req: cmd = f"tp {player} {pos['x']} {pos['y']} {pos['z']}"
elif "safe" in req or "shelter" in req: cmd = f"fill {pos['x']-3} {pos['y']} {pos['z']-3} {pos['x']+3} {pos['y']+4} {pos['z']+3} minecraft:oak_planks hollow"
msgs.append(tool_call("rcon.execute", {"command": cmd}))
msgs.append(tool_result({"success": True, "result": rcon_ok(cmd, player)}))
resp = {"risk_level": 3, "commands": [], "reasoning": reasoning}
msgs.append(final_response(resp))
examples.append(make_example(f"exp-chain-{idx:03d}", "chained", msgs))
idx += 1
return examples
def main():
print("Generating expanded tool training data...")
examples = generate_all()
# Count by type
counts = {}
for ex in examples:
t = ex["type"]
counts[t] = counts.get(t, 0) + 1
print(f"\nGenerated {len(examples)} examples:")
for t, c in sorted(counts.items()):
print(f" {t}: {c}")
# Write
OUTPUT_PATH.parent.mkdir(parents=True, exist_ok=True)
with open(OUTPUT_PATH, "w") as f:
for ex in examples:
f.write(json.dumps(ex, ensure_ascii=False) + "\n")
print(f"\nWritten to {OUTPUT_PATH}")
print(f"Next: merge into tool_training.jsonl or add to training pipeline")
if __name__ == "__main__":
main()