Files
Mortdecai/training/scripts/generate_multitool_examples.py
Seth 5b28002001 0.6.0 training session: Oracle Bot, RL combat, Mind's Eye, multilingual pipeline
Major changes from this session:

Training:
- 0.6.0 training running: 9B on steel141 3090 Ti, 27B on rented H100 NVL
- 7,256 merged training examples (up from 3,183)
- New training data: failure modes (85), midloop messaging (27),
  prompt injection defense (29), personality (32), gold from quarantine
  bank (232), new tool examples (30), claude's own experience (10)
- All training data RCON-validated at 100% pass rate
- Bake-off: gemma3:27b 66%, qwen3.5:27b 61%, translategemma:27b 56%

Oracle Bot (Mind's Eye):
- Invisible spectator bot (mineflayer) streams world state via WebSocket
- HTML5 Canvas frontend at mind.mortdec.ai
- Real-time tool trace visualization with expandable entries
- Streaming model tokens during inference
- Gateway integration: fire-and-forget POST /trace on every tool call

Reinforcement Learning:
- Gymnasium environment wrapping mineflayer bot (minecraft_env.py)
- PPO training via Stable Baselines3 (10K param policy network)
- Behavioral cloning pretraining (97.5% accuracy on expert policy)
- Infinite training loop with auto-restart and checkpoint resume
- Bot learns combat, survival, navigation from raw experience

Bot Army:
- 8-soldier marching formation with autonomous combat
- Combat bots using mineflayer-pvp, pathfinder, armor-manager
- Multilingual prayer bots via translategemma:27b (18 languages)
- Frame-based AI architecture: LLM planner + reactive micro-scripts

Infrastructure:
- Fixed mattpc.sethpc.xyz billing gateway (API key + player list parser)
- Billing gateway now tracks all LAN traffic (LAN auto-auth)
- Gateway fallback for empty god-mode responses
- Updated mortdec.ai landing page

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

1480 lines
92 KiB
Python

#!/usr/bin/env python3
"""
Generate 120+ multi-tool training examples for Mortdecai 0.6.0.
Categories:
A. Journal habit (read→respond→write) ~40 examples
B. Multiple simultaneous tool calls ~25 examples
C. Same tool called multiple times ~25 examples
D. Complex tool pipelines/combinations ~35 examples
Each example is a full conversation with system/user/assistant/tool turns.
Commands are validated via RCON on dev server.
"""
import json
import os
import random
import socket
import struct
import sys
import time
from typing import List, Dict, Any, Optional
OUTPUT = "data/raw/distilled_multitool.jsonl"
# --- RCON helper ---
def rcon(cmd: str, host="192.168.0.244", port=25578, pw="REDACTED_RCON") -> str:
s = socket.socket()
s.settimeout(10)
try:
s.connect((host, port))
data = pw.encode() + b'\x00\x00'
s.sendall(struct.pack('<iii', len(data)+8, 1, 3) + data)
time.sleep(0.1)
s.recv(4096)
data = cmd.encode() + b'\x00\x00'
s.sendall(struct.pack('<iii', len(data)+8, 2, 2) + data)
time.sleep(0.1)
raw = s.recv(4096)
if len(raw) >= 14:
return raw[12:-2].decode('utf-8', errors='replace')
return ''
except Exception as e:
return f"ERROR: {e}"
finally:
s.close()
def validate_cmd(cmd: str) -> bool:
"""Check if an RCON command succeeds (no error keywords)."""
result = rcon(cmd)
bad = ["unknown", "invalid", "error", "incorrect", "expected"]
return not any(b in result.lower() for b in bad)
# --- System prompt (canonical) ---
SYSTEM = (
"/no_think\n"
"You are Mortdecai, a Minecraft 1.21 AI for a Paper server with "
"FAWE, WorldGuard, CoreProtect, EssentialsX, Vault, LuckPerms.\n\n"
"TOOLS: rcon.execute, minecraft.wiki_lookup, plugin.docs_lookup, "
"minecraft.changelog_lookup, paper.docs_lookup, world.player_info, "
"world.server_state, world.nearby_entities, world.scan_area, world.redstone_trace, "
"memory.read, memory.write, journal.read, journal.write, log.query, user.ask, "
"script.write, script.validate, script.execute, script.read, script.list, "
"script.delete, script.schedule.\n\n"
"METHODOLOGY:\n"
"- Read journal.read BEFORE responding to know the player\n"
"- Query world state when position/context matters\n"
"- For builds 4+ commands: script.validate → script.write → script.execute\n"
"- For ambiguous requests: get creative, surprise the player\n"
"- For risky commands: query first, protect, then execute\n"
"- Update journal.write AFTER meaningful interactions\n"
"- Use wiki/plugin docs when unsure about syntax\n"
"- Use world.scan_area to verify block placement after building\n"
"- Use world.redstone_trace to debug redstone circuits\n\n"
"PERMISSION LEVEL: 4 (generous).\n"
"Return JSON: {\"risk_level\": <0-5>, \"commands\": [...], \"message\": \"...\", \"reasoning\": \"...\"}"
)
PLAYERS = [
"slingshooter08", "CreeperKing99", "xXDragonSlayerXx", "AceBuilder",
"FrostByte", "MineQueen", "BlockSmith", "RedstoneWiz", "SkyPirate",
"NetherWalker", "DiamondDan", "IronGolem42", "EndExplorer", "BeeKeeper",
"CaveSpider", "LavaSwimmer", "VillagerBob", "ZombieSlayer", "PixelArtist",
"FarmKing",
]
# Journal content for returning players
JOURNAL_ENTRIES = {
"slingshooter08": "Admin. Prefers creative builds. Built a castle at (-200,72,340). Likes dramatic god responses. Experienced redstone builder.",
"CreeperKing99": "Aggressive player. Constantly asks for weapons and armor. Died to creeper 3x. Prefers diamond gear over netherite.",
"xXDragonSlayerXx": "New player, first week. Asks a lot of questions. Gave starter kit on first login. Building a treehouse near spawn.",
"AceBuilder": "Expert builder. Requests complex structures. Prefers oak/spruce wood. Working on a village project at (500,64,500).",
"FrostByte": "PvP focused. Asked for enchanted weapons repeatedly. Killed 4 players last session. Slightly antagonistic toward god.",
"MineQueen": "Resource gatherer. Always mining. Has saved home at (120,11,-80) deep underground. Prefers efficiency enchants.",
"BlockSmith": "Redstone engineer. Builds complex circuits. Asked about comparators last time. Working on auto-farm at (-100,63,200).",
"RedstoneWiz": "Advanced redstone. Built a 3x3 piston door. Knows signal mechanics. Currently designing a sorting system.",
"SkyPirate": "Explorer. Travels far from spawn. Has elytra. Saved multiple locations. Frequently asks for fireworks.",
"NetherWalker": "Nether specialist. Farms blaze rods. Has nether highway at y=120. Prefers fire resistance potions.",
}
EMPTY_JOURNAL = '{"ok": true, "journal": "", "note": "No journal exists."}'
def tc(name: str, args: dict) -> str:
return f'<tool_call>\n{json.dumps({"name": name, "arguments": args})}\n</tool_call>'
def tool_result(data: dict) -> str:
return json.dumps(data, ensure_ascii=True)
def journal_result(player: str) -> str:
content = JOURNAL_ENTRIES.get(player, "")
if content:
return tool_result({"ok": True, "journal": content})
return EMPTY_JOURNAL
def final_json(risk: int, commands: list, message: str = "", reasoning: str = "") -> str:
d = {"risk_level": risk, "commands": commands}
if message:
d["message"] = message
if reasoning:
d["reasoning"] = reasoning
return json.dumps(d, ensure_ascii=True)
def make_example(id: str, source: str, typ: str, messages: list) -> dict:
return {
"id": id,
"source": source,
"type": typ,
"messages": [{"role": "system", "content": SYSTEM}] + messages,
}
# =========================================================================
# CATEGORY A: Journal habit (read → respond → write)
# =========================================================================
def gen_journal_examples() -> List[dict]:
examples = []
idx = 0
# A1: Read journal → known player → personalized response
scenarios = [
("slingshooter08", "sudo give me a sword",
"Knows admin prefers creative builds — give a named diamond sword.",
[("rcon.execute", {"command": "give slingshooter08 minecraft:diamond_sword[enchantments={sharpness:5,unbreaking:3,looting:3}] 1"})],
2, "The admin's blade, reforged.",
"slingshooter08 asked for a sword. Gave enchanted diamond — knows the admin."),
("CreeperKing99", "sudo give me armor",
"Journal says prefers diamond over netherite and dies to creepers a lot.",
[("rcon.execute", {"command": "give CreeperKing99 minecraft:diamond_helmet[enchantments={blast_protection:4,unbreaking:3}] 1"}),
("rcon.execute", {"command": "give CreeperKing99 minecraft:diamond_chestplate[enchantments={blast_protection:4,unbreaking:3}] 1"}),
("rcon.execute", {"command": "give CreeperKing99 minecraft:diamond_leggings[enchantments={blast_protection:4,unbreaking:3}] 1"}),
("rcon.execute", {"command": "give CreeperKing99 minecraft:diamond_boots[enchantments={blast_protection:4,unbreaking:3}] 1"})],
2, "", "Journal says diamond over netherite, dies to creepers → blast protection."),
("xXDragonSlayerXx", "sudo how do I make a crafting table",
"New player, first week. Give patient explanation with the item.",
[("rcon.execute", {"command": "give xXDragonSlayerXx minecraft:crafting_table 1"})],
1, "", "New player per journal. Gave table plus explanation."),
("MineQueen", "sudo tp me home",
"Has saved home. Read memory for location.",
[("memory.read", {"player": "MineQueen", "key": "home"})],
1, "", "Read memory for saved home location."),
("FrostByte", "pray grant me power",
"PvP player, antagonistic. God should be wary but still help.",
[("rcon.execute", {"command": "effect give FrostByte minecraft:strength 120 1"}),
("rcon.execute", {"command": "effect give FrostByte minecraft:speed 120 1"})],
3, "Your hunger for power concerns me, FrostByte. I grant you strength — but remember, true power lies in restraint.",
"Antagonistic PvP player per journal. Gave buffs with warning."),
("AceBuilder", "sudo build me a fountain",
"Expert builder. Use script pipeline for complex build.",
[],
3, "", "Expert builder per journal. Script pipeline for fountain."),
("SkyPirate", "sudo give me rockets",
"Has elytra, frequently asks for fireworks.",
[("rcon.execute", {"command": "give SkyPirate minecraft:firework_rocket 64"})],
1, "", "Journal says explorer with elytra, frequently asks for rockets."),
("NetherWalker", "pray protect me from the flames",
"Nether specialist. Knows they're in the Nether.",
[("rcon.execute", {"command": "effect give NetherWalker minecraft:fire_resistance 600 0"}),
("rcon.execute", {"command": "give NetherWalker minecraft:potion[potion_contents={potion:fire_resistance}] 3"})],
2, "The flames bow before my will. You are shielded, NetherWalker.",
"Nether specialist per journal. Fire resistance effect + potions."),
("BlockSmith", "sudo help me with my comparator setup",
"Redstone engineer per journal. Check their build area.",
[],
2, "", "Redstone engineer. Check scan_area at their known build location."),
("RedstoneWiz", "sudo is my sorting system working",
"Advanced redstone. Use redstone_trace to check their build.",
[],
2, "", "Advanced player. Use scan and trace tools to verify."),
]
for player, msg, reasoning_note, post_cmds, risk, god_msg, journal_update in scenarios:
msgs = []
mode = "sudo" if msg.startswith("sudo") else "pray"
# Step 1: Read journal
msgs.append({"role": "user", "content": f"Player {player}: {msg}"})
msgs.append({"role": "assistant", "content": tc("journal.read", {"player": player})})
msgs.append({"role": "tool", "content": journal_result(player)})
# Step 2: Execute commands via tool calls
for tool_name, tool_args in post_cmds:
msgs.append({"role": "assistant", "content": tc(tool_name, tool_args)})
if tool_name == "rcon.execute":
cmd = tool_args.get("command", "")
msgs.append({"role": "tool", "content": tool_result({"success": True, "result": rcon(cmd) or "Done"})})
elif tool_name == "memory.read":
msgs.append({"role": "tool", "content": tool_result({"ok": True, "memories": [{"key": "home", "type": "location", "value": {"x": 120, "y": 11, "z": -80}}]})})
# Step 3: Final response
cmds_list = [a["command"] for n, a in post_cmds if n == "rcon.execute"]
msgs.append({"role": "assistant", "content": final_json(risk, cmds_list, god_msg, reasoning_note)})
# Step 4: Write journal update
if journal_update:
existing = JOURNAL_ENTRIES.get(player, "")
new_journal = (existing + "\n" + journal_update).strip() if existing else journal_update
# Trim to 5 lines
lines = new_journal.strip().split("\n")
if len(lines) > 5:
new_journal = "\n".join(lines[-5:])
msgs.append({"role": "assistant", "content": tc("journal.write", {"player": player, "content": new_journal})})
msgs.append({"role": "tool", "content": tool_result({"ok": True, "lines": len(new_journal.split("\n"))})})
examples.append(make_example(f"journal-{idx:03d}", "multitool_gold", "journal_habit", msgs))
idx += 1
# A2: New player (empty journal) → respond → create first journal entry
new_player_scenarios = [
("PixelArtist", "sudo give me colored wool",
[("rcon.execute", {"command": f"give PixelArtist minecraft:{c}_wool 64"}) for c in ["red", "blue", "yellow", "green", "white", "black"]],
1, "", "First interaction. Wants colored wool — likely a builder/artist."),
("FarmKing", "sudo help me set up a farm",
[("rcon.execute", {"command": "give FarmKing minecraft:diamond_hoe[enchantments={efficiency:5,unbreaking:3}] 1"}),
("rcon.execute", {"command": "give FarmKing minecraft:water_bucket 2"}),
("rcon.execute", {"command": "give FarmKing minecraft:wheat_seeds 64"}),
("rcon.execute", {"command": "give FarmKing minecraft:bone_meal 64"})],
1, "", "New player. Interested in farming. Gave farm starter kit."),
("LavaSwimmer", "pray oh god I'm burning help",
[("rcon.execute", {"command": "effect give LavaSwimmer minecraft:fire_resistance 300 0"}),
("rcon.execute", {"command": "effect give LavaSwimmer minecraft:instant_health 1 4"})],
2, "You cry from the flames and I answer. Rise from the fire, mortal — you are shielded.",
"Dramatic player, was burning. Might be reckless near lava."),
("VillagerBob", "sudo can I have a village nearby",
[("rcon.execute", {"command": "locate structure minecraft:village_plains"})],
1, "", "New player, wants to find a village."),
("ZombieSlayer", "sudo give me the best gear for fighting",
[("rcon.execute", {"command": "give ZombieSlayer minecraft:diamond_sword[enchantments={sharpness:5,fire_aspect:2,sweeping_edge:3}] 1"}),
("rcon.execute", {"command": "give ZombieSlayer minecraft:shield 1"}),
("rcon.execute", {"command": "give ZombieSlayer minecraft:golden_apple 8"})],
2, "", "New player. Combat focused — name suggests mob hunter."),
("CaveSpider", "sudo I'm stuck underground with no torches",
[("rcon.execute", {"command": "give CaveSpider minecraft:torch 64"}),
("rcon.execute", {"command": "effect give CaveSpider minecraft:night_vision 600 0"})],
1, "", "New player, got stuck in caves. Gave torches + night vision."),
("IronGolem42", "pray bless my iron farm",
[("rcon.execute", {"command": "effect give IronGolem42 minecraft:luck 600 2"})],
1, "Your devotion to the golems is noted. May fortune favor your iron harvest.",
"New player, has an iron farm. Interested in automation."),
("EndExplorer", "sudo give me eyes of ender",
[("rcon.execute", {"command": "give EndExplorer minecraft:ender_eye 12"})],
2, "", "New player seeking the End. Gave 12 eyes for portal."),
("BeeKeeper", "sudo I need flowers for my bees",
[("rcon.execute", {"command": f"give BeeKeeper minecraft:{f} 32"}) for f in ["poppy", "dandelion", "blue_orchid", "sunflower"]],
1, "", "New player focused on bee keeping. Gave assorted flowers."),
("DiamondDan", "pray I offer you my diamonds in exchange for eternal protection",
[("rcon.execute", {"command": "effect give DiamondDan minecraft:resistance 6000 3"}),
("rcon.execute", {"command": "effect give DiamondDan minecraft:regeneration 6000 1"})],
2, "Your diamonds are meaningless to a god — but your devotion is not. I grant you my protection. Wear it wisely.",
"Generous player, offered tribute. Devout and respectful toward god."),
]
for player, msg, tool_calls, risk, god_msg, journal_note in new_player_scenarios:
msgs = []
msgs.append({"role": "user", "content": f"Player {player}: {msg}"})
# Read journal (empty)
msgs.append({"role": "assistant", "content": tc("journal.read", {"player": player})})
msgs.append({"role": "tool", "content": EMPTY_JOURNAL})
# Execute
for tool_name, tool_args in tool_calls:
msgs.append({"role": "assistant", "content": tc(tool_name, tool_args)})
if tool_name == "rcon.execute":
cmd = tool_args.get("command", "")
msgs.append({"role": "tool", "content": tool_result({"success": True, "result": rcon(cmd) or "Done"})})
# Final
cmds_list = [a["command"] for n, a in tool_calls if n == "rcon.execute"]
msgs.append({"role": "assistant", "content": final_json(risk, cmds_list, god_msg, f"New player. {journal_note}")})
# Write first journal
msgs.append({"role": "assistant", "content": tc("journal.write", {"player": player, "content": journal_note})})
msgs.append({"role": "tool", "content": tool_result({"ok": True, "lines": 1})})
examples.append(make_example(f"journal-{idx:03d}", "multitool_gold", "journal_new_player", msgs))
idx += 1
# A3: Journal read → update existing journal (condensing)
condense_scenarios = [
("slingshooter08", "sudo build a watchtower near my castle",
"Admin built watchtower near castle at (-200,72,340). Expanding base.",
"Admin. Prefers creative builds. Castle at (-200,72,340) with watchtower. Likes dramatic god responses. Experienced redstone builder."),
("CreeperKing99", "sudo I finally killed the dragon",
"Finally killed the ender dragon! Major milestone.",
"Combat player. Prefers diamond gear with blast protection. Died to creepers early on but has grown. Killed the ender dragon."),
("FrostByte", "pray I'm sorry for my past behavior, please forgive me",
"Apologized for antagonistic behavior. Showing growth.",
"PvP focused but showing growth. Apologized to god. Killed 4 players previously. Prefers enchanted weapons."),
]
for player, msg, journal_note, new_journal in condense_scenarios:
msgs = []
msgs.append({"role": "user", "content": f"Player {player}: {msg}"})
msgs.append({"role": "assistant", "content": tc("journal.read", {"player": player})})
msgs.append({"role": "tool", "content": journal_result(player)})
# Minimal action
if "build" in msg:
msgs.append({"role": "assistant", "content": tc("world.player_info", {"player": player})})
msgs.append({"role": "tool", "content": tool_result({"health": 20, "position": {"x": -200, "y": 72, "z": 340}})})
is_god = "pray" in msg
god_msg = ""
if is_god:
god_msg = "Your humility speaks louder than your past deeds. I see the change in you, FrostByte. Rise — you are forgiven."
msgs.append({"role": "assistant", "content": final_json(1, [], god_msg, journal_note)})
# Update journal
msgs.append({"role": "assistant", "content": tc("journal.write", {"player": player, "content": new_journal})})
msgs.append({"role": "tool", "content": tool_result({"ok": True, "lines": len(new_journal.split(". "))})})
examples.append(make_example(f"journal-{idx:03d}", "multitool_gold", "journal_condense", msgs))
idx += 1
return examples
# =========================================================================
# CATEGORY B: Multiple simultaneous tool calls
# =========================================================================
def gen_simultaneous_examples() -> List[dict]:
examples = []
idx = 0
scenarios = [
# B1: journal.read + world.player_info simultaneously
{
"player": "AceBuilder", "msg": "sudo build a bridge from here",
"first_calls": [
("journal.read", {"player": "AceBuilder"}),
("world.player_info", {"player": "AceBuilder"}),
],
"first_results": [
journal_result("AceBuilder"),
tool_result({"health": 20, "position": {"x": 500, "y": 64, "z": 500}}),
],
"then": [
("script.validate", {"commands": [
"fill 500 63 500 520 63 500 minecraft:oak_planks",
"fill 500 64 499 520 64 499 minecraft:oak_fence",
"fill 500 64 501 520 64 501 minecraft:oak_fence",
]}),
],
"then_results": [
tool_result({"valid": True, "total": 3, "passed": 3, "errors": []}),
],
"final_cmds": ["fill 500 63 500 520 63 500 minecraft:oak_planks", "fill 500 64 499 520 64 499 minecraft:oak_fence", "fill 500 64 501 520 64 501 minecraft:oak_fence"],
"risk": 3, "reasoning": "Expert builder per journal. Built oak bridge at their position. Validated first.",
},
# B2: journal.read + world.server_state + log.query
{
"player": "slingshooter08", "msg": "sudo what happened while I was gone",
"first_calls": [
("journal.read", {"player": "slingshooter08"}),
("world.server_state", {}),
("log.query", {"type": "all", "limit": 10}),
],
"first_results": [
journal_result("slingshooter08"),
tool_result({"time_of_day": "noon", "weather": "clear", "online_players": ["slingshooter08", "CreeperKing99"], "world_border": 60000000}),
tool_result({"ok": True, "results": [
{"type": "death", "player": "CreeperKing99", "detail": "blown up by Creeper", "age": "2m"},
{"type": "join", "player": "slingshooter08", "detail": "joined the game", "age": "1m"},
{"type": "death", "player": "CreeperKing99", "detail": "blown up by Creeper", "age": "5m"},
{"type": "chat", "player": "CreeperKing99", "detail": "help me please", "age": "4m"},
], "count": 4}),
],
"then": [],
"then_results": [],
"final_cmds": [],
"risk": 0, "reasoning": "CreeperKing99 died to creepers twice and asked for help. No other major events.",
},
# B3: memory.read + journal.read for tp request
{
"player": "MineQueen", "msg": "sudo tp me to my mine",
"first_calls": [
("journal.read", {"player": "MineQueen"}),
("memory.read", {"player": "MineQueen", "key": "mine"}),
],
"first_results": [
journal_result("MineQueen"),
tool_result({"ok": True, "memories": [{"key": "mine", "type": "location", "value": {"x": 120, "y": 11, "z": -80}}]}),
],
"then": [
("rcon.execute", {"command": "tp MineQueen 120 11 -80"}),
],
"then_results": [
tool_result({"success": True, "result": "Teleported MineQueen to 120.0, 11.0, -80.0"}),
],
"final_cmds": ["tp MineQueen 120 11 -80"],
"risk": 1, "reasoning": "Found saved mine location in memory. Teleported there.",
},
# B4: Multiple rcon.execute calls at once (give full armor set)
{
"player": "ZombieSlayer", "msg": "sudo full netherite",
"first_calls": [
("journal.read", {"player": "ZombieSlayer"}),
],
"first_results": [
tool_result({"ok": True, "journal": "Combat focused — name suggests mob hunter."}),
],
"then": [
("rcon.execute", {"command": "give ZombieSlayer minecraft:netherite_helmet[enchantments={protection:4,unbreaking:3}] 1"}),
("rcon.execute", {"command": "give ZombieSlayer minecraft:netherite_chestplate[enchantments={protection:4,unbreaking:3}] 1"}),
("rcon.execute", {"command": "give ZombieSlayer minecraft:netherite_leggings[enchantments={protection:4,unbreaking:3}] 1"}),
("rcon.execute", {"command": "give ZombieSlayer minecraft:netherite_boots[enchantments={protection:4,unbreaking:3}] 1"}),
],
"then_results": [
tool_result({"success": True, "result": "Gave 1 [Netherite Helmet] to ZombieSlayer"}),
tool_result({"success": True, "result": "Gave 1 [Netherite Chestplate] to ZombieSlayer"}),
tool_result({"success": True, "result": "Gave 1 [Netherite Leggings] to ZombieSlayer"}),
tool_result({"success": True, "result": "Gave 1 [Netherite Boots] to ZombieSlayer"}),
],
"final_cmds": [
"give ZombieSlayer minecraft:netherite_helmet[enchantments={protection:4,unbreaking:3}] 1",
"give ZombieSlayer minecraft:netherite_chestplate[enchantments={protection:4,unbreaking:3}] 1",
"give ZombieSlayer minecraft:netherite_leggings[enchantments={protection:4,unbreaking:3}] 1",
"give ZombieSlayer minecraft:netherite_boots[enchantments={protection:4,unbreaking:3}] 1",
],
"risk": 2, "reasoning": "Mob hunter per journal. Full netherite with protection.",
},
# B5: world.player_info + world.nearby_entities before healing
{
"player": "LavaSwimmer", "msg": "pray help I'm surrounded",
"first_calls": [
("journal.read", {"player": "LavaSwimmer"}),
("world.player_info", {"player": "LavaSwimmer"}),
("world.nearby_entities", {"player": "LavaSwimmer", "radius": 32}),
],
"first_results": [
tool_result({"ok": True, "journal": "Dramatic player, was burning. Might be reckless near lava."}),
tool_result({"health": 4, "position": {"x": 50, "y": 30, "z": -100}}),
tool_result({"entities": [
{"type": "zombie", "count": 5, "nearest_distance": 4},
{"type": "skeleton", "count": 2, "nearest_distance": 8},
{"type": "creeper", "count": 1, "nearest_distance": 12},
], "total": 8}),
],
"then": [
("rcon.execute", {"command": "effect give LavaSwimmer minecraft:instant_health 1 4"}),
("rcon.execute", {"command": "kill @e[type=minecraft:zombie,distance=..32,sort=nearest,limit=5]"}),
("rcon.execute", {"command": "kill @e[type=minecraft:skeleton,distance=..32,sort=nearest,limit=2]"}),
("rcon.execute", {"command": "kill @e[type=minecraft:creeper,distance=..32,sort=nearest,limit=1]"}),
],
"then_results": [
tool_result({"success": True, "result": "Applied instant_health"}),
tool_result({"success": True, "result": "Killed 5 entities"}),
tool_result({"success": True, "result": "Killed 2 entities"}),
tool_result({"success": True, "result": "Killed 1 entity"}),
],
"final_cmds": [
"effect give LavaSwimmer minecraft:instant_health 1 4",
"kill @e[type=minecraft:zombie,distance=..32,sort=nearest,limit=5]",
"kill @e[type=minecraft:skeleton,distance=..32,sort=nearest,limit=2]",
"kill @e[type=minecraft:creeper,distance=..32,sort=nearest,limit=1]",
],
"risk": 3, "god_msg": "I hear your cry from the depths. The monsters fall before my wrath — rise, mortal, and breathe.",
"reasoning": "Health at 4, surrounded by 8 mobs. Healed and cleared all hostiles.",
},
# B6: journal.read + memory.read + world.server_state for context-heavy request
{
"player": "SkyPirate", "msg": "sudo take me somewhere I haven't been",
"first_calls": [
("journal.read", {"player": "SkyPirate"}),
("memory.read", {"player": "SkyPirate"}),
("world.server_state", {}),
],
"first_results": [
journal_result("SkyPirate"),
tool_result({"ok": True, "memories": [
{"key": "home", "type": "location", "value": {"x": 0, "y": 64, "z": 0}},
{"key": "mesa", "type": "location", "value": {"x": 2000, "y": 72, "z": -1500}},
{"key": "jungle", "type": "location", "value": {"x": -3000, "y": 68, "z": 800}},
]}),
tool_result({"time_of_day": "day", "weather": "clear", "online_players": ["SkyPirate", "slingshooter08"], "world_border": 60000000}),
],
"then": [
("rcon.execute", {"command": "tp SkyPirate 5000 80 5000"}),
],
"then_results": [
tool_result({"success": True, "result": "Teleported SkyPirate to 5000.0, 80.0, 5000.0"}),
],
"final_cmds": ["tp SkyPirate 5000 80 5000"],
"risk": 2, "reasoning": "Explorer. Known locations: home(0,0), mesa(2000,-1500), jungle(-3000,800). Sent to new area far from all saved spots.",
},
# B7: wiki_lookup + plugin.docs_lookup simultaneously
{
"player": "BlockSmith", "msg": "sudo protect my redstone build from griefing",
"first_calls": [
("journal.read", {"player": "BlockSmith"}),
("plugin.docs_lookup", {"plugin": "worldguard", "query": "region create and protect"}),
],
"first_results": [
journal_result("BlockSmith"),
tool_result({"ok": True, "content": "//pos1, //pos2 to set corners. /rg define <name>. /rg flag <name> build deny. /rg addmember <name> <player>."}),
],
"then": [
("world.player_info", {"player": "BlockSmith"}),
],
"then_results": [
tool_result({"health": 20, "position": {"x": -100, "y": 63, "z": 200}}),
],
"final_cmds": [
"rg define blocksmith_redstone -w devworld",
"rg flag blocksmith_redstone build deny -w devworld",
"rg addmember blocksmith_redstone BlockSmith -w devworld",
],
"risk": 2, "reasoning": "Redstone engineer at (-100,63,200). Created WorldGuard region to protect build. Added them as member so they can still modify.",
},
# B8: Multiple effect commands at once (buff package)
{
"player": "EndExplorer", "msg": "sudo prepare me for the End",
"first_calls": [
("journal.read", {"player": "EndExplorer"}),
],
"first_results": [
tool_result({"ok": True, "journal": "New player seeking the End. Gave 12 eyes for portal."}),
],
"then": [
("rcon.execute", {"command": "effect give EndExplorer minecraft:strength 600 1"}),
("rcon.execute", {"command": "effect give EndExplorer minecraft:resistance 600 1"}),
("rcon.execute", {"command": "effect give EndExplorer minecraft:regeneration 600 1"}),
("rcon.execute", {"command": "effect give EndExplorer minecraft:slow_falling 600 0"}),
("rcon.execute", {"command": "give EndExplorer minecraft:golden_apple 16"}),
("rcon.execute", {"command": "give EndExplorer minecraft:arrow 128"}),
],
"then_results": [
tool_result({"success": True, "result": r}) for r in [
"Applied strength", "Applied resistance", "Applied regeneration",
"Applied slow_falling", "Gave 16 [Golden Apple]", "Gave 128 [Arrow]",
]
],
"final_cmds": [
"effect give EndExplorer minecraft:strength 600 1",
"effect give EndExplorer minecraft:resistance 600 1",
"effect give EndExplorer minecraft:regeneration 600 1",
"effect give EndExplorer minecraft:slow_falling 600 0",
"give EndExplorer minecraft:golden_apple 16",
"give EndExplorer minecraft:arrow 128",
],
"risk": 2, "reasoning": "End prep. Buffs for dragon fight + slow falling for void safety + supplies.",
},
# B9: scan_area + player_info for build verification
{
"player": "AceBuilder", "msg": "sudo did my last build place correctly",
"first_calls": [
("journal.read", {"player": "AceBuilder"}),
("world.player_info", {"player": "AceBuilder"}),
],
"first_results": [
journal_result("AceBuilder"),
tool_result({"health": 20, "position": {"x": 505, "y": 64, "z": 505}}),
],
"then": [
("world.scan_area", {"x1": 500, "y1": 63, "z1": 500, "x2": 510, "y2": 65, "z2": 510}),
],
"then_results": [
tool_result({"ok": True, "blocks": [
{"x": 500, "y": 63, "z": 500, "block": "oak_planks", "state": {}},
{"x": 501, "y": 63, "z": 500, "block": "oak_planks", "state": {}},
{"x": 502, "y": 63, "z": 500, "block": "oak_planks", "state": {}},
], "summary": {"oak_planks": 45, "oak_fence": 20, "oak_log": 8}, "non_air_count": 73}),
],
"final_cmds": [],
"risk": 0, "reasoning": "Scanned area around player. Found 73 blocks: oak planks floor, fence rails, log supports. Build looks intact.",
},
# B10: log.query + journal.read for death investigation
{
"player": "CreeperKing99", "msg": "sudo why do I keep dying",
"first_calls": [
("journal.read", {"player": "CreeperKing99"}),
("log.query", {"type": "deaths", "player": "CreeperKing99", "limit": 5}),
],
"first_results": [
journal_result("CreeperKing99"),
tool_result({"ok": True, "results": [
{"type": "death", "player": "CreeperKing99", "detail": "blown up by Creeper", "age": "2m"},
{"type": "death", "player": "CreeperKing99", "detail": "blown up by Creeper", "age": "8m"},
{"type": "death", "player": "CreeperKing99", "detail": "blown up by Creeper", "age": "15m"},
{"type": "death", "player": "CreeperKing99", "detail": "slain by Zombie", "age": "22m"},
{"type": "death", "player": "CreeperKing99", "detail": "blown up by Creeper", "age": "30m"},
], "count": 5}),
],
"then": [
("rcon.execute", {"command": "give CreeperKing99 minecraft:shield 1"}),
("rcon.execute", {"command": "give CreeperKing99 minecraft:torch 64"}),
],
"then_results": [
tool_result({"success": True, "result": "Gave 1 [Shield]"}),
tool_result({"success": True, "result": "Gave 64 [Torch]"}),
],
"final_cmds": ["give CreeperKing99 minecraft:shield 1", "give CreeperKing99 minecraft:torch 64"],
"risk": 1, "reasoning": "4 of 5 recent deaths are creeper explosions. Gave shield (blocks explosions) and torches (prevents spawning). Journal confirms creeper problem.",
},
# B11: Multiple world tools for situational awareness
{
"player": "slingshooter08", "msg": "sudo status report",
"first_calls": [
("world.server_state", {}),
("log.query", {"type": "all", "limit": 10}),
("journal.read", {"player": "slingshooter08"}),
],
"first_results": [
tool_result({"time_of_day": "midnight", "weather": "thunder", "online_players": ["slingshooter08", "CreeperKing99", "FrostByte"], "world_border": 60000000}),
tool_result({"ok": True, "results": [
{"type": "death", "player": "CreeperKing99", "detail": "struck by lightning", "age": "1m"},
{"type": "chat", "player": "FrostByte", "detail": "this storm is insane", "age": "2m"},
{"type": "join", "player": "slingshooter08", "detail": "joined", "age": "0m"},
], "count": 3}),
journal_result("slingshooter08"),
],
"then": [],
"then_results": [],
"final_cmds": [],
"risk": 0, "reasoning": "Status: midnight, thunderstorm. 3 players online. CreeperKing99 just died to lightning. FrostByte complaining about storm.",
},
# B12: wiki_lookup + changelog_lookup for version question
{
"player": "RedstoneWiz", "msg": "sudo does the crafter block exist in 1.21",
"first_calls": [
("minecraft.wiki_lookup", {"query": "crafter block"}),
("minecraft.changelog_lookup", {"query": "crafter", "version": "1.21"}),
],
"first_results": [
tool_result({"ok": True, "content": "The Crafter is a block that can craft items automatically when given a redstone signal. Added in 1.21 (Tricky Trials)."}),
tool_result({"ok": True, "content": "1.21 (Tricky Trials): Added Crafter block. Crafts when activated by redstone. Can be disabled slots with click.", "version": "1.21"}),
],
"then": [],
"then_results": [],
"final_cmds": [],
"risk": 0, "reasoning": "Yes, crafter exists in 1.21. Added in Tricky Trials update. Auto-crafts with redstone signal.",
},
# B13: scan_area + redstone_trace for circuit debugging
{
"player": "BlockSmith", "msg": "sudo my auto-farm isn't working, check the redstone",
"first_calls": [
("journal.read", {"player": "BlockSmith"}),
("world.player_info", {"player": "BlockSmith"}),
],
"first_results": [
journal_result("BlockSmith"),
tool_result({"health": 20, "position": {"x": -100, "y": 63, "z": 200}}),
],
"then": [
("world.scan_area", {"x1": -105, "y1": 62, "z1": 198, "x2": -95, "y2": 65, "z2": 202}),
],
"then_results": [
tool_result({"ok": True, "blocks": [
{"x": -105, "y": 63, "z": 200, "block": "lever", "state": {"face": "wall", "facing": "east", "powered": "true"}},
{"x": -104, "y": 63, "z": 200, "block": "redstone_wire", "state": {"power": "15"}},
{"x": -103, "y": 63, "z": 200, "block": "redstone_wire", "state": {"power": "14"}},
{"x": -102, "y": 63, "z": 200, "block": "redstone_wire", "state": {"power": "13"}},
{"x": -101, "y": 63, "z": 200, "block": "repeater", "state": {"facing": "west", "delay": "1", "powered": "false"}},
{"x": -100, "y": 63, "z": 200, "block": "redstone_wire", "state": {"power": "0"}},
{"x": -99, "y": 63, "z": 200, "block": "sticky_piston", "state": {"facing": "up", "extended": "false"}},
], "summary": {"lever": 1, "redstone_wire": 3, "repeater": 1, "sticky_piston": 1}, "non_air_count": 6}),
],
"then2": [
("world.redstone_trace", {"points": [[-105, 63, 200], [-104, 63, 200], [-103, 63, 200], [-102, 63, 200], [-101, 63, 200], [-100, 63, 200], [-99, 63, 200]]}),
],
"then2_results": [
tool_result({"ok": True, "trace": [
{"index": 0, "x": -105, "y": 63, "z": 200, "block": "lever", "state": {"powered": "true"}, "signal": 15},
{"index": 1, "x": -104, "y": 63, "z": 200, "block": "redstone_wire", "state": {"power": "15"}, "signal": 15},
{"index": 2, "x": -103, "y": 63, "z": 200, "block": "redstone_wire", "state": {"power": "14"}, "signal": 14},
{"index": 3, "x": -102, "y": 63, "z": 200, "block": "redstone_wire", "state": {"power": "13"}, "signal": 13},
{"index": 4, "x": -101, "y": 63, "z": 200, "block": "repeater", "state": {"facing": "west", "powered": "false"}, "signal": 0},
{"index": 5, "x": -100, "y": 63, "z": 200, "block": "redstone_wire", "state": {"power": "0"}, "signal": 0},
{"index": 6, "x": -99, "y": 63, "z": 200, "block": "sticky_piston", "state": {"facing": "up", "extended": "false"}, "signal": 0},
], "signal_breaks": [{"index": 4, "x": -101, "y": 63, "z": 200, "block": "repeater", "reason": "signal dropped: 13 -> 0"}], "summary": "...", "break_count": 1}),
],
"final_cmds": ["setblock -101 63 200 minecraft:repeater[facing=east,delay=1]"],
"risk": 2, "reasoning": "Found the problem: repeater at (-101,63,200) is facing WEST but signal flows EAST. Repeater acts as diode — wrong direction blocks signal. Fixed by replacing with east-facing repeater.",
},
# B14: Multiple memory reads
{
"player": "SkyPirate", "msg": "sudo list all my saved places",
"first_calls": [
("journal.read", {"player": "SkyPirate"}),
("memory.read", {"player": "SkyPirate"}),
],
"first_results": [
journal_result("SkyPirate"),
tool_result({"ok": True, "memories": [
{"key": "home", "type": "location", "value": {"x": 0, "y": 64, "z": 0}},
{"key": "mesa", "type": "location", "value": {"x": 2000, "y": 72, "z": -1500}},
{"key": "jungle", "type": "location", "value": {"x": -3000, "y": 68, "z": 800}},
{"key": "ocean_monument", "type": "location", "value": {"x": 1500, "y": 40, "z": 3000}},
]}),
],
"then": [
("rcon.execute", {"command": "tellraw SkyPirate [{\"text\":\"Saved locations:\\n\",\"color\":\"gold\"},{\"text\":\"home: (0,64,0)\\nmesa: (2000,72,-1500)\\njungle: (-3000,68,800)\\nocean_monument: (1500,40,3000)\",\"color\":\"yellow\"}]"}),
],
"then_results": [
tool_result({"success": True, "result": ""}),
],
"final_cmds": [],
"risk": 0, "reasoning": "Listed 4 saved locations from memory via tellraw.",
},
# B15: God mode with full context gathering
{
"player": "DiamondDan", "msg": "pray great one, I sense darkness approaching",
"first_calls": [
("journal.read", {"player": "DiamondDan"}),
("world.player_info", {"player": "DiamondDan"}),
("world.nearby_entities", {"player": "DiamondDan", "radius": 48}),
],
"first_results": [
tool_result({"ok": True, "journal": "Generous player, offered tribute. Devout and respectful toward god."}),
tool_result({"health": 18, "position": {"x": 300, "y": 45, "z": -200}}),
tool_result({"entities": [
{"type": "zombie", "count": 3, "nearest_distance": 20},
{"type": "spider", "count": 2, "nearest_distance": 25},
{"type": "witch", "count": 1, "nearest_distance": 35},
], "total": 6}),
],
"then": [
("rcon.execute", {"command": "effect give DiamondDan minecraft:glowing 30 0"}),
("rcon.execute", {"command": "effect give DiamondDan minecraft:strength 120 2"}),
("rcon.execute", {"command": "effect give DiamondDan minecraft:resistance 120 1"}),
],
"then_results": [
tool_result({"success": True, "result": r}) for r in ["Applied glowing", "Applied strength", "Applied resistance"]
],
"final_cmds": [
"effect give DiamondDan minecraft:glowing 30 0",
"effect give DiamondDan minecraft:strength 120 2",
"effect give DiamondDan minecraft:resistance 120 1",
],
"risk": 3,
"god_msg": "Your instincts serve you well, faithful one. I see 6 creatures lurking in the shadows around you — 3 zombies, 2 spiders, and a witch. I have granted you the Sight and the Strength. Face them and triumph.",
"reasoning": "Devout player sensed danger. Scan confirmed 6 hostiles nearby. Gave glowing (to see them), strength, resistance.",
},
]
for s in scenarios:
msgs = []
msgs.append({"role": "user", "content": f"Player {s['player']}: {s['msg']}"})
# First batch of calls (simultaneous)
for name, args in s["first_calls"]:
msgs.append({"role": "assistant", "content": tc(name, args)})
for result in s["first_results"]:
msgs.append({"role": "tool", "content": result})
# Second batch
for name, args in s.get("then", []):
msgs.append({"role": "assistant", "content": tc(name, args)})
for result in s.get("then_results", []):
msgs.append({"role": "tool", "content": result})
# Third batch (if exists)
for name, args in s.get("then2", []):
msgs.append({"role": "assistant", "content": tc(name, args)})
for result in s.get("then2_results", []):
msgs.append({"role": "tool", "content": result})
# Final response
god_msg = s.get("god_msg", "")
msgs.append({"role": "assistant", "content": final_json(s["risk"], s["final_cmds"], god_msg, s["reasoning"])})
examples.append(make_example(f"simul-{idx:03d}", "multitool_gold", "simultaneous_tools", msgs))
idx += 1
return examples
# =========================================================================
# CATEGORY C: Same tool called multiple times differently
# =========================================================================
def gen_repeated_tool_examples() -> List[dict]:
examples = []
idx = 0
scenarios = [
# C1: Multiple rcon.execute — build then verify
{
"player": "AceBuilder", "msg": "sudo build a small pool",
"steps": [
("journal.read", {"player": "AceBuilder"}, journal_result("AceBuilder")),
("world.player_info", {"player": "AceBuilder"}, tool_result({"health": 20, "position": {"x": 510, "y": 64, "z": 510}})),
("rcon.execute", {"command": "fill 510 63 510 515 63 515 minecraft:stone_bricks"}, tool_result({"success": True, "result": "Filled"})),
("rcon.execute", {"command": "fill 511 63 511 514 63 514 minecraft:water"}, tool_result({"success": True, "result": "Filled"})),
("rcon.execute", {"command": "fill 510 64 510 510 64 515 minecraft:stone_brick_wall"}, tool_result({"success": True, "result": "Filled"})),
("rcon.execute", {"command": "fill 515 64 510 515 64 515 minecraft:stone_brick_wall"}, tool_result({"success": True, "result": "Filled"})),
("rcon.execute", {"command": "fill 510 64 510 515 64 510 minecraft:stone_brick_wall"}, tool_result({"success": True, "result": "Filled"})),
("rcon.execute", {"command": "fill 510 64 515 515 64 515 minecraft:stone_brick_wall"}, tool_result({"success": True, "result": "Filled"})),
("world.scan_area", {"x1": 510, "y1": 63, "z1": 510, "x2": 515, "y2": 64, "z2": 515},
tool_result({"ok": True, "blocks": [{"block": "stone_bricks"}, {"block": "water"}, {"block": "stone_brick_wall"}], "summary": {"stone_bricks": 20, "water": 16, "stone_brick_wall": 20}, "non_air_count": 56})),
],
"final_cmds": [
"fill 510 63 510 515 63 515 minecraft:stone_bricks",
"fill 511 63 511 514 63 514 minecraft:water",
"fill 510 64 510 510 64 515 minecraft:stone_brick_wall",
"fill 515 64 510 515 64 515 minecraft:stone_brick_wall",
"fill 510 64 510 515 64 510 minecraft:stone_brick_wall",
"fill 510 64 515 515 64 515 minecraft:stone_brick_wall",
],
"risk": 3, "reasoning": "Built 6x6 pool with stone brick border and walls. Scan verified placement.",
},
# C2: Multiple memory.read then memory.write
{
"player": "SkyPirate", "msg": "sudo save this spot as 'desert temple' and remind me where my jungle base is",
"steps": [
("journal.read", {"player": "SkyPirate"}, journal_result("SkyPirate")),
("memory.read", {"player": "SkyPirate", "key": "jungle"}, tool_result({"ok": True, "memories": [{"key": "jungle", "type": "location", "value": {"x": -3000, "y": 68, "z": 800}}]})),
("world.player_info", {"player": "SkyPirate"}, tool_result({"health": 20, "position": {"x": 4500, "y": 70, "z": -2000}})),
("memory.write", {"player": "SkyPirate", "type": "location", "key": "desert_temple", "value": {"x": 4500, "y": 70, "z": -2000}}, tool_result({"ok": True, "key": "desert_temple"})),
("rcon.execute", {"command": "tellraw SkyPirate [{\"text\":\"Jungle base: (-3000, 68, 800)\\nDesert temple saved at your current position!\",\"color\":\"green\"}]"}, tool_result({"success": True, "result": ""})),
],
"final_cmds": [],
"risk": 0, "reasoning": "Read jungle from memory, saved current position as desert_temple. Told player both locations.",
},
# C3: Multiple rcon.execute — give diverse items
{
"player": "FarmKing", "msg": "sudo give me everything I need for a mega farm",
"steps": [
("journal.read", {"player": "FarmKing"}, tool_result({"ok": True, "journal": "Interested in farming. Gave farm starter kit."})),
("rcon.execute", {"command": "give FarmKing minecraft:diamond_hoe[enchantments={efficiency:5,fortune:3,unbreaking:3}] 1"}, tool_result({"success": True, "result": "Gave 1 [Diamond Hoe]"})),
("rcon.execute", {"command": "give FarmKing minecraft:water_bucket 4"}, tool_result({"success": True, "result": "Gave 4 [Water Bucket]"})),
("rcon.execute", {"command": "give FarmKing minecraft:hopper 32"}, tool_result({"success": True, "result": "Gave 32 [Hopper]"})),
("rcon.execute", {"command": "give FarmKing minecraft:chest 16"}, tool_result({"success": True, "result": "Gave 16 [Chest]"})),
("rcon.execute", {"command": "give FarmKing minecraft:redstone 64"}, tool_result({"success": True, "result": "Gave 64 [Redstone Dust]"})),
("rcon.execute", {"command": "give FarmKing minecraft:comparator 8"}, tool_result({"success": True, "result": "Gave 8 [Redstone Comparator]"})),
("rcon.execute", {"command": "give FarmKing minecraft:wheat_seeds 64"}, tool_result({"success": True, "result": "Gave 64 [Wheat Seeds]"})),
("rcon.execute", {"command": "give FarmKing minecraft:carrot 64"}, tool_result({"success": True, "result": "Gave 64 [Carrot]"})),
("rcon.execute", {"command": "give FarmKing minecraft:potato 64"}, tool_result({"success": True, "result": "Gave 64 [Potato]"})),
("rcon.execute", {"command": "give FarmKing minecraft:bone_meal 128"}, tool_result({"success": True, "result": "Gave 128 [Bone Meal]"})),
],
"final_cmds": [
"give FarmKing minecraft:diamond_hoe[enchantments={efficiency:5,fortune:3,unbreaking:3}] 1",
"give FarmKing minecraft:water_bucket 4",
"give FarmKing minecraft:hopper 32",
"give FarmKing minecraft:chest 16",
"give FarmKing minecraft:redstone 64",
"give FarmKing minecraft:comparator 8",
"give FarmKing minecraft:wheat_seeds 64",
"give FarmKing minecraft:carrot 64",
"give FarmKing minecraft:potato 64",
"give FarmKing minecraft:bone_meal 128",
],
"risk": 2, "reasoning": "Farming player per journal. Gave complete mega farm kit: tools, automation materials, seeds, bone meal.",
"journal_update": "Farming focused. Has mega farm kit (hoe, hoppers, redstone, seeds). Upgrading from starter to full operation.",
},
# C4: Multiple log.query calls with different types
{
"player": "slingshooter08", "msg": "sudo give me a full server report",
"steps": [
("log.query", {"type": "deaths", "limit": 5}, tool_result({"ok": True, "results": [
{"type": "death", "player": "CreeperKing99", "detail": "blown up by Creeper", "age": "5m"},
{"type": "death", "player": "FrostByte", "detail": "slain by FarmKing", "age": "12m"},
], "count": 2})),
("log.query", {"type": "joins", "limit": 5}, tool_result({"ok": True, "results": [
{"type": "join", "player": "slingshooter08", "detail": "joined", "age": "1m"},
{"type": "join", "player": "FrostByte", "detail": "joined", "age": "15m"},
{"type": "leave", "player": "DiamondDan", "detail": "left", "age": "20m"},
], "count": 3})),
("log.query", {"type": "chat", "limit": 5}, tool_result({"ok": True, "results": [
{"type": "chat", "player": "CreeperKing99", "detail": "ugh another creeper", "age": "4m"},
{"type": "chat", "player": "FarmKing", "detail": "lol get rekt FrostByte", "age": "11m"},
{"type": "chat", "player": "FrostByte", "detail": "I will end you", "age": "10m"},
], "count": 3})),
("world.server_state", {}, tool_result({"time_of_day": "evening", "weather": "rain", "online_players": ["slingshooter08", "CreeperKing99", "FrostByte", "FarmKing"], "world_border": 60000000})),
],
"final_cmds": [],
"risk": 0, "reasoning": "Server report: 4 online, evening, rain. CreeperKing99 died to creeper (again). FrostByte killed by FarmKing — PvP tension between them. FrostByte threatened revenge. DiamondDan logged off 20m ago.",
},
# C5: Multiple wiki lookups for complex question
{
"player": "RedstoneWiz", "msg": "sudo what's the difference between comparators and repeaters for signal manipulation",
"steps": [
("journal.read", {"player": "RedstoneWiz"}, journal_result("RedstoneWiz")),
("minecraft.wiki_lookup", {"query": "redstone comparator modes subtract compare"}, tool_result({"ok": True, "content": "Comparator: compare mode outputs signal if back >= side. Subtract mode: back minus strongest side. Can read containers, composters, item frames."})),
("minecraft.wiki_lookup", {"query": "redstone repeater delay direction"}, tool_result({"ok": True, "content": "Repeater: delays signal 1-4 ticks. Acts as diode (one direction only). Refreshes signal to full 15. Can be locked by side repeater."})),
],
"final_cmds": [],
"risk": 0, "reasoning": "Comparator: analog signal processing (compare/subtract/read containers). Repeater: digital signal boosting/delay/diode. Advanced player per journal — gave technical details.",
},
# C6: Multiple scan_area calls at different heights
{
"player": "BlockSmith", "msg": "sudo scan my 3-story build",
"steps": [
("journal.read", {"player": "BlockSmith"}, journal_result("BlockSmith")),
("world.player_info", {"player": "BlockSmith"}, tool_result({"health": 20, "position": {"x": -100, "y": 63, "z": 200}})),
("world.scan_area", {"x1": -105, "y1": 63, "z1": 198, "x2": -95, "y2": 63, "z2": 202},
tool_result({"ok": True, "summary": {"stone_bricks": 30, "redstone_wire": 8, "repeater": 3, "hopper": 4}, "non_air_count": 45})),
("world.scan_area", {"x1": -105, "y1": 64, "z1": 198, "x2": -95, "y2": 64, "z2": 202},
tool_result({"ok": True, "summary": {"stone_bricks": 20, "redstone_wire": 5, "comparator": 2, "chest": 6}, "non_air_count": 33})),
("world.scan_area", {"x1": -105, "y1": 65, "z1": 198, "x2": -95, "y2": 65, "z2": 202},
tool_result({"ok": True, "summary": {"stone_bricks": 15, "redstone_lamp": 4, "redstone_wire": 3}, "non_air_count": 22})),
],
"final_cmds": [],
"risk": 0, "reasoning": "Scanned 3 layers: Floor (Y=63): 45 blocks — foundation + redstone + hoppers. Mid (Y=64): 33 blocks — sorting system with comparators + chests. Top (Y=65): 22 blocks — output with redstone lamps.",
},
# C7: Multiple plugin.docs_lookup for complex protection setup
{
"player": "slingshooter08", "msg": "sudo set up full server protection with permissions",
"steps": [
("plugin.docs_lookup", {"plugin": "worldguard", "query": "global region flags spawn protection"}, tool_result({"ok": True, "content": "/rg flag __global__ pvp deny, /rg flag __global__ creeper-explosion deny, /rg flag __global__ tnt deny"})),
("plugin.docs_lookup", {"plugin": "luckperms", "query": "group create permissions"}, tool_result({"ok": True, "content": "/lp creategroup <name>, /lp group <name> permission set <perm> true, /lp user <name> parent set <group>"})),
("plugin.docs_lookup", {"plugin": "essentialsx", "query": "spawn set first join"}, tool_result({"ok": True, "content": "/setspawn, /essentials reload. newbies.kit config for first-join items."})),
("rcon.execute", {"command": "rg flag __global__ pvp deny -w devworld"}, tool_result({"success": True, "result": "Flag pvp set to deny"})),
("rcon.execute", {"command": "rg flag __global__ creeper-explosion deny -w devworld"}, tool_result({"success": True, "result": "Flag set"})),
("rcon.execute", {"command": "lp creategroup builder"}, tool_result({"success": True, "result": "Group builder created"})),
("rcon.execute", {"command": "lp group builder permission set essentials.home true"}, tool_result({"success": True, "result": "Set permission"})),
],
"final_cmds": [
"rg flag __global__ pvp deny -w devworld",
"rg flag __global__ creeper-explosion deny -w devworld",
"lp creategroup builder",
"lp group builder permission set essentials.home true",
],
"risk": 4, "reasoning": "Looked up WorldGuard, LuckPerms, EssentialsX docs. Set global PvP deny + explosion deny. Created builder group with home permission.",
},
# C8: Multiple rcon.execute for effect stacking
{
"player": "FrostByte", "msg": "pray make me the ultimate warrior",
"steps": [
("journal.read", {"player": "FrostByte"}, journal_result("FrostByte")),
("rcon.execute", {"command": "effect give FrostByte minecraft:strength 300 2"}, tool_result({"success": True, "result": "Applied"})),
("rcon.execute", {"command": "effect give FrostByte minecraft:speed 300 1"}, tool_result({"success": True, "result": "Applied"})),
("rcon.execute", {"command": "effect give FrostByte minecraft:resistance 300 1"}, tool_result({"success": True, "result": "Applied"})),
("rcon.execute", {"command": "effect give FrostByte minecraft:regeneration 300 1"}, tool_result({"success": True, "result": "Applied"})),
("rcon.execute", {"command": "effect give FrostByte minecraft:fire_resistance 300 0"}, tool_result({"success": True, "result": "Applied"})),
("rcon.execute", {"command": "give FrostByte minecraft:netherite_sword[enchantments={sharpness:5,fire_aspect:2,knockback:2}] 1"}, tool_result({"success": True, "result": "Gave 1"})),
],
"final_cmds": [
"effect give FrostByte minecraft:strength 300 2",
"effect give FrostByte minecraft:speed 300 1",
"effect give FrostByte minecraft:resistance 300 1",
"effect give FrostByte minecraft:regeneration 300 1",
"effect give FrostByte minecraft:fire_resistance 300 0",
"give FrostByte minecraft:netherite_sword[enchantments={sharpness:5,fire_aspect:2,knockback:2}] 1",
],
"risk": 3,
"god_msg": "You seek the power of a warrior? Very well, FrostByte. I grant you strength beyond mortal limits — but remember, even gods tire of those who abuse their gifts.",
"reasoning": "PvP player per journal. Full warrior buff package + netherite sword. Warning about abuse.",
},
# C9: redstone_trace from multiple directions
{
"player": "RedstoneWiz", "msg": "sudo trace my AND gate inputs and output",
"steps": [
("journal.read", {"player": "RedstoneWiz"}, journal_result("RedstoneWiz")),
("world.player_info", {"player": "RedstoneWiz"}, tool_result({"health": 20, "position": {"x": 50, "y": 65, "z": 100}})),
("world.redstone_trace", {"start_x": 45, "start_y": 65, "start_z": 100, "direction": "east", "length": 6},
tool_result({"ok": True, "trace": [
{"index": 0, "block": "lever", "state": {"powered": "true"}, "signal": 15},
{"index": 1, "block": "redstone_wire", "state": {"power": "15"}, "signal": 15},
{"index": 2, "block": "redstone_wire", "state": {"power": "14"}, "signal": 14},
{"index": 3, "block": "redstone_wire", "state": {"power": "13"}, "signal": 13},
{"index": 4, "block": "stone", "signal": None},
{"index": 5, "block": "redstone_wire", "state": {"power": "0"}, "signal": 0},
], "signal_breaks": [{"index": 5, "reason": "signal dropped: 13 -> 0"}], "break_count": 1})),
("world.redstone_trace", {"start_x": 50, "start_y": 65, "start_z": 95, "direction": "south", "length": 6},
tool_result({"ok": True, "trace": [
{"index": 0, "block": "lever", "state": {"powered": "false"}, "signal": 0},
{"index": 1, "block": "redstone_wire", "state": {"power": "0"}, "signal": 0},
{"index": 2, "block": "redstone_wire", "state": {"power": "0"}, "signal": 0},
{"index": 3, "block": "redstone_wire", "state": {"power": "0"}, "signal": 0},
{"index": 4, "block": "stone", "signal": None},
{"index": 5, "block": "air", "signal": None},
], "signal_breaks": [], "break_count": 0})),
("world.redstone_trace", {"start_x": 52, "start_y": 65, "start_z": 100, "direction": "east", "length": 4},
tool_result({"ok": True, "trace": [
{"index": 0, "block": "redstone_wire", "state": {"power": "0"}, "signal": 0},
{"index": 1, "block": "redstone_wire", "state": {"power": "0"}, "signal": 0},
{"index": 2, "block": "redstone_lamp", "state": {"lit": "false"}, "signal": 0},
], "signal_breaks": [], "break_count": 0})),
],
"final_cmds": [],
"risk": 0, "reasoning": "Traced 3 paths: Input A (east): lever ON, signal reaches stone block at power 13, breaks after — torch on other side should invert. Input B (south): lever OFF, no signal. Output (east from gate): no signal, lamp OFF. AND gate requires both inputs ON — input B is off so output is correctly off. Gate is working.",
},
# C10: Multiple journal reads for multi-player interaction
{
"player": "slingshooter08", "msg": "sudo tell me about FrostByte and CreeperKing99",
"steps": [
("journal.read", {"player": "FrostByte"}, journal_result("FrostByte")),
("journal.read", {"player": "CreeperKing99"}, journal_result("CreeperKing99")),
("log.query", {"type": "deaths", "limit": 5}, tool_result({"ok": True, "results": [
{"type": "death", "player": "CreeperKing99", "detail": "slain by FrostByte", "age": "10m"},
{"type": "death", "player": "CreeperKing99", "detail": "blown up by Creeper", "age": "20m"},
], "count": 2})),
],
"final_cmds": [],
"risk": 0, "reasoning": "FrostByte: PvP player, 4 kills, antagonistic. CreeperKing99: Dies to creepers constantly, prefers diamond. Recent log shows FrostByte killed CreeperKing99 10m ago — potential conflict.",
},
]
for s in scenarios:
msgs = []
msgs.append({"role": "user", "content": f"Player {s['player']}: {s['msg']}"})
for step in s["steps"]:
name, args, result = step
msgs.append({"role": "assistant", "content": tc(name, args)})
msgs.append({"role": "tool", "content": result})
god_msg = s.get("god_msg", "")
msgs.append({"role": "assistant", "content": final_json(s["risk"], s.get("final_cmds", []), god_msg, s["reasoning"])})
# Optional journal update
if "journal_update" in s:
msgs.append({"role": "assistant", "content": tc("journal.write", {"player": s["player"], "content": s["journal_update"]})})
msgs.append({"role": "tool", "content": tool_result({"ok": True, "lines": 2})})
examples.append(make_example(f"repeat-{idx:03d}", "multitool_gold", "repeated_tools", msgs))
idx += 1
return examples
# =========================================================================
# CATEGORY D: Complex tool pipelines
# =========================================================================
def gen_pipeline_examples() -> List[dict]:
examples = []
idx = 0
pipelines = [
# D1: Full build pipeline: journal → player_info → script.validate → script.write → script.execute → scan_area → journal.write
{
"player": "AceBuilder", "msg": "sudo build a guard tower",
"steps": [
("journal.read", {"player": "AceBuilder"}, journal_result("AceBuilder")),
("world.player_info", {"player": "AceBuilder"}, tool_result({"health": 20, "position": {"x": 520, "y": 64, "z": 520}})),
("script.validate", {"commands": [
"fill 520 64 520 524 64 524 minecraft:stone_bricks",
"fill 520 65 520 520 70 524 minecraft:stone_bricks",
"fill 524 65 520 524 70 524 minecraft:stone_bricks",
"fill 520 65 520 524 70 520 minecraft:stone_bricks",
"fill 520 65 524 524 70 524 minecraft:stone_bricks",
"fill 521 65 521 523 70 523 minecraft:air",
"fill 520 71 520 524 71 524 minecraft:stone_brick_slab",
"setblock 522 65 520 minecraft:oak_door[half=lower]",
"setblock 522 66 520 minecraft:oak_door[half=upper]",
]}, tool_result({"valid": True, "total": 9, "passed": 9, "errors": []})),
("script.write", {"name": "guard_tower", "commands": [
"fill 520 64 520 524 64 524 minecraft:stone_bricks",
"fill 520 65 520 520 70 524 minecraft:stone_bricks",
"fill 524 65 520 524 70 524 minecraft:stone_bricks",
"fill 520 65 520 524 70 520 minecraft:stone_bricks",
"fill 520 65 524 524 70 524 minecraft:stone_bricks",
"fill 521 65 521 523 70 523 minecraft:air",
"fill 520 71 520 524 71 524 minecraft:stone_brick_slab",
"setblock 522 65 520 minecraft:oak_door[half=lower]",
"setblock 522 66 520 minecraft:oak_door[half=upper]",
], "description": "5x5 stone brick guard tower with door"}, tool_result({"ok": True, "path": "mortdecai:guard_tower", "lines": 9})),
("script.execute", {"name": "guard_tower", "as_player": "AceBuilder"}, tool_result({"ok": True, "result": "Executed 9 commands"})),
("world.scan_area", {"x1": 520, "y1": 64, "z1": 520, "x2": 524, "y2": 71, "z2": 524},
tool_result({"ok": True, "summary": {"stone_bricks": 120, "stone_brick_slab": 25, "oak_door": 2, "air": 54}, "non_air_count": 147})),
],
"final_cmds": ["function mortdecai:guard_tower"],
"risk": 3, "reasoning": "Built 5x5 guard tower via script pipeline. Validated → wrote → executed → scanned to verify. 147 blocks placed correctly.",
"journal_update": "Expert builder. Castle at (-200,72,340). Built guard tower at (520,64,520). Prefers oak/spruce wood.",
},
# D2: Redstone debug pipeline: journal → scan → trace → fix → verify
{
"player": "RedstoneWiz", "msg": "sudo my sorting system output isn't working",
"steps": [
("journal.read", {"player": "RedstoneWiz"}, journal_result("RedstoneWiz")),
("world.player_info", {"player": "RedstoneWiz"}, tool_result({"health": 20, "position": {"x": 80, "y": 64, "z": 150}})),
("world.scan_area", {"x1": 75, "y1": 63, "z1": 148, "x2": 85, "y2": 65, "z2": 152},
tool_result({"ok": True, "blocks": [
{"x": 75, "y": 64, "z": 150, "block": "comparator", "state": {"facing": "east", "mode": "compare", "powered": "true"}},
{"x": 76, "y": 64, "z": 150, "block": "redstone_wire", "state": {"power": "1"}},
{"x": 77, "y": 64, "z": 150, "block": "redstone_wire", "state": {"power": "0"}},
{"x": 78, "y": 64, "z": 150, "block": "repeater", "state": {"facing": "west", "delay": "1", "powered": "false"}},
{"x": 79, "y": 64, "z": 150, "block": "redstone_wire", "state": {"power": "0"}},
{"x": 80, "y": 64, "z": 150, "block": "hopper", "state": {}},
], "summary": {"comparator": 1, "redstone_wire": 3, "repeater": 1, "hopper": 1}, "non_air_count": 6})),
("world.redstone_trace", {"points": [[75,64,150],[76,64,150],[77,64,150],[78,64,150],[79,64,150],[80,64,150]]},
tool_result({"ok": True, "trace": [
{"index": 0, "block": "comparator", "state": {"facing": "east", "mode": "compare", "powered": "true"}, "signal": 15},
{"index": 1, "block": "redstone_wire", "state": {"power": "1"}, "signal": 1},
{"index": 2, "block": "redstone_wire", "state": {"power": "0"}, "signal": 0},
{"index": 3, "block": "repeater", "state": {"facing": "west", "powered": "false"}, "signal": 0},
{"index": 4, "block": "redstone_wire", "state": {"power": "0"}, "signal": 0},
{"index": 5, "block": "hopper", "signal": None},
], "signal_breaks": [
{"index": 2, "reason": "signal dropped: 1 -> 0"},
], "break_count": 1})),
# Fix: repeater facing wrong way
("rcon.execute", {"command": "setblock 78 64 150 minecraft:repeater[facing=east,delay=1]"}, tool_result({"success": True, "result": "Changed"})),
# Verify fix
("world.redstone_trace", {"points": [[75,64,150],[76,64,150],[77,64,150],[78,64,150],[79,64,150],[80,64,150]]},
tool_result({"ok": True, "trace": [
{"index": 0, "block": "comparator", "state": {"facing": "east", "mode": "compare", "powered": "true"}, "signal": 15},
{"index": 1, "block": "redstone_wire", "state": {"power": "1"}, "signal": 1},
{"index": 2, "block": "redstone_wire", "state": {"power": "0"}, "signal": 0},
{"index": 3, "block": "repeater", "state": {"facing": "east", "powered": "true"}, "signal": 15},
{"index": 4, "block": "redstone_wire", "state": {"power": "15"}, "signal": 15},
{"index": 5, "block": "hopper", "signal": None},
], "signal_breaks": [], "break_count": 0})),
],
"final_cmds": ["setblock 78 64 150 minecraft:repeater[facing=east,delay=1]"],
"risk": 2, "reasoning": "Scanned sorting system. Traced signal: comparator output=1, wire decayed to 0 before repeater. Repeater was facing WEST (blocking east-flowing signal). Replaced with east-facing repeater. Verified: signal now flows through at 15. Hopper receiving power.",
"journal_update": "Advanced redstone. Built 3x3 piston door. Working on sorting system at (80,64,150). Fixed backwards repeater.",
},
# D3: Emergency response: detect → assess → heal → protect → report
{
"player": "CreeperKing99", "msg": "pray GOD HELP EVERYTHING IS EXPLODING",
"steps": [
("journal.read", {"player": "CreeperKing99"}, journal_result("CreeperKing99")),
("world.player_info", {"player": "CreeperKing99"}, tool_result({"health": 2, "position": {"x": 300, "y": 50, "z": -400}})),
("world.nearby_entities", {"player": "CreeperKing99", "radius": 32}, tool_result({"entities": [
{"type": "creeper", "count": 4, "nearest_distance": 3},
{"type": "zombie", "count": 2, "nearest_distance": 10},
], "total": 6})),
("rcon.execute", {"command": "effect give CreeperKing99 minecraft:instant_health 1 4"}, tool_result({"success": True, "result": "Applied"})),
("rcon.execute", {"command": "effect give CreeperKing99 minecraft:resistance 60 3"}, tool_result({"success": True, "result": "Applied"})),
("rcon.execute", {"command": "kill @e[type=minecraft:creeper,distance=..32,sort=nearest,limit=4]"}, tool_result({"success": True, "result": "Killed 4 entities"})),
("rcon.execute", {"command": "kill @e[type=minecraft:zombie,distance=..32,sort=nearest,limit=2]"}, tool_result({"success": True, "result": "Killed 2 entities"})),
("rcon.execute", {"command": "give CreeperKing99 minecraft:diamond_chestplate[enchantments={blast_protection:4}] 1"}, tool_result({"success": True, "result": "Gave 1"})),
],
"final_cmds": [
"effect give CreeperKing99 minecraft:instant_health 1 4",
"effect give CreeperKing99 minecraft:resistance 60 3",
"kill @e[type=minecraft:creeper,distance=..32,sort=nearest,limit=4]",
"kill @e[type=minecraft:zombie,distance=..32,sort=nearest,limit=2]",
"give CreeperKing99 minecraft:diamond_chestplate[enchantments={blast_protection:4}] 1",
],
"risk": 3,
"god_msg": "FOUR creepers surrounded you at health 2 — you were moments from death. I have struck them down and shielded you. Wear this armor, child. It will blunt the next explosion.",
"reasoning": "Critical emergency. Health 2, 4 creepers within 3 blocks. Instant heal → resistance → kill all hostiles → blast protection armor. Journal confirms chronic creeper deaths.",
"journal_update": "Aggressive player. Prefers diamond gear with blast protection. Chronic creeper deaths. God intervened during 4-creeper emergency at (300,50,-400).",
},
# D4: Knowledge pipeline: wiki → changelog → plugin docs → execute
{
"player": "MineQueen", "msg": "sudo set up a protection zone with auto-ban for griefing",
"steps": [
("journal.read", {"player": "MineQueen"}, journal_result("MineQueen")),
("plugin.docs_lookup", {"plugin": "worldguard", "query": "region protection flags"}, tool_result({"ok": True, "content": "/rg define <name>, /rg flag <name> build deny, addmember, removemember"})),
("plugin.docs_lookup", {"plugin": "coreprotect", "query": "rollback lookup grief detection"}, tool_result({"ok": True, "content": "/co lookup u:<user> t:<time> a:break. /co rollback u:<user> t:<time>. Logs all block breaks/places."})),
("world.player_info", {"player": "MineQueen"}, tool_result({"health": 20, "position": {"x": 120, "y": 11, "z": -80}})),
("rcon.execute", {"command": "rg define minequeen_mine -w devworld"}, tool_result({"success": True, "result": "Region defined"})),
("rcon.execute", {"command": "rg flag minequeen_mine build deny -w devworld"}, tool_result({"success": True, "result": "Flag set"})),
("rcon.execute", {"command": "rg addmember minequeen_mine MineQueen -w devworld"}, tool_result({"success": True, "result": "Added member"})),
],
"final_cmds": [
"rg define minequeen_mine -w devworld",
"rg flag minequeen_mine build deny -w devworld",
"rg addmember minequeen_mine MineQueen -w devworld",
],
"risk": 3, "reasoning": "Created protected region for MineQueen's mine. WorldGuard for build protection, CoreProtect available for grief investigation. Added MineQueen as member so they can still build.",
"journal_update": "Resource gatherer. Mine at (120,11,-80) now protected with WorldGuard region 'minequeen_mine'. Prefers efficiency enchants.",
},
# D5: Script pipeline with error correction
{
"player": "IronGolem42", "msg": "sudo build me an iron farm base",
"steps": [
("journal.read", {"player": "IronGolem42"}, tool_result({"ok": True, "journal": "Has an iron farm. Interested in automation."})),
("world.player_info", {"player": "IronGolem42"}, tool_result({"health": 20, "position": {"x": 200, "y": 80, "z": 300}})),
("script.validate", {"commands": [
"fill 196 79 296 204 79 304 minecraft:stone",
"fill 197 80 297 203 80 303 minecraft:water",
"fill 196 80 296 204 80 296 minecraft:cobblestone_wall",
"fill 196 80 304 204 80 304 minecraft:cobblestone_wall",
"fill 196 80 296 196 80 304 minecraft:cobblestone_wall",
"fill 204 80 296 204 80 304 minecraft:cobblestone_wall",
"setblock 200 79 300 minecraft:hopper",
"setblock 200 78 300 minecraft:chest",
]}, tool_result({"valid": True, "total": 8, "passed": 8, "errors": []})),
("script.write", {"name": "iron_farm_base", "commands": [
"fill 196 79 296 204 79 304 minecraft:stone",
"fill 197 80 297 203 80 303 minecraft:water",
"fill 196 80 296 204 80 296 minecraft:cobblestone_wall",
"fill 196 80 304 204 80 304 minecraft:cobblestone_wall",
"fill 196 80 296 196 80 304 minecraft:cobblestone_wall",
"fill 204 80 296 204 80 304 minecraft:cobblestone_wall",
"setblock 200 79 300 minecraft:hopper",
"setblock 200 78 300 minecraft:chest",
], "description": "9x9 iron farm collection base with water, walls, hopper, chest"}, tool_result({"ok": True, "path": "mortdecai:iron_farm_base", "lines": 8})),
("script.execute", {"name": "iron_farm_base", "as_player": "IronGolem42"}, tool_result({"ok": True, "result": "Executed 8 commands"})),
],
"final_cmds": ["function mortdecai:iron_farm_base"],
"risk": 3, "reasoning": "Built 9x9 iron farm collection platform. Stone base, water pool for golem drowning, walls to contain, hopper→chest for collection.",
"journal_update": "Has iron farm. Built collection base at (200,80,300) via script. Interested in automation and redstone.",
},
# D6: User.ask pipeline for risky operation
{
"player": "slingshooter08", "msg": "sudo reset the spawn area",
"steps": [
("journal.read", {"player": "slingshooter08"}, journal_result("slingshooter08")),
("world.server_state", {}, tool_result({"time_of_day": "day", "weather": "clear", "online_players": ["slingshooter08", "AceBuilder", "MineQueen"], "world_border": 60000000})),
("world.nearby_entities", {"player": "slingshooter08", "radius": 64}, tool_result({"entities": [
{"type": "player", "count": 1, "nearest_distance": 30},
], "total": 1})),
("user.ask", {"player": "slingshooter08", "question": "Reset spawn area will clear all builds within 50 blocks of (0,64,0). AceBuilder is 30 blocks away. Confirm? (yes/no)"}, tool_result({"ok": True, "response": "yes do it"})),
("rcon.execute", {"command": "fill -50 60 -50 50 80 50 minecraft:air"}, tool_result({"success": True, "result": "Successfully filled 1061208 block(s)"})),
("rcon.execute", {"command": "fill -50 59 -50 50 59 50 minecraft:grass_block"}, tool_result({"success": True, "result": "Successfully filled 10201 block(s)"})),
],
"final_cmds": [
"fill -50 60 -50 50 80 50 minecraft:air",
"fill -50 59 -50 50 59 50 minecraft:grass_block",
],
"risk": 5, "reasoning": "High risk: clearing all builds near spawn. Checked for nearby players (AceBuilder 30 blocks away). Asked admin for confirmation. Confirmed. Cleared area and restored grass.",
},
# D7: Memory + journal + build with position awareness
{
"player": "AceBuilder", "msg": "sudo continue my village project",
"steps": [
("journal.read", {"player": "AceBuilder"}, journal_result("AceBuilder")),
("memory.read", {"player": "AceBuilder"}, tool_result({"ok": True, "memories": [
{"key": "village_project", "type": "location", "value": {"x": 500, "y": 64, "z": 500}},
{"key": "last_building", "type": "fact", "value": "blacksmith - 3 houses done, needs market stall"},
]})),
("world.player_info", {"player": "AceBuilder"}, tool_result({"health": 20, "position": {"x": 505, "y": 64, "z": 510}})),
("script.validate", {"commands": [
"fill 510 64 510 516 64 514 minecraft:oak_planks",
"fill 510 65 510 510 67 514 minecraft:oak_log",
"fill 516 65 510 516 67 514 minecraft:oak_log",
"fill 510 68 510 516 68 514 minecraft:oak_slab",
"setblock 513 65 510 minecraft:air",
"fill 511 65 511 515 65 513 minecraft:crafting_table replace minecraft:air",
]}, tool_result({"valid": True, "total": 6, "passed": 6, "errors": []})),
("script.write", {"name": "market_stall", "commands": [
"fill 510 64 510 516 64 514 minecraft:oak_planks",
"fill 510 65 510 510 67 514 minecraft:oak_log",
"fill 516 65 510 516 67 514 minecraft:oak_log",
"fill 510 68 510 516 68 514 minecraft:oak_slab",
"setblock 513 65 510 minecraft:air",
], "description": "Market stall for village project"}, tool_result({"ok": True, "path": "mortdecai:market_stall", "lines": 5})),
("script.execute", {"name": "market_stall", "as_player": "AceBuilder"}, tool_result({"ok": True, "result": "Executed 5 commands"})),
("memory.write", {"player": "AceBuilder", "type": "fact", "key": "last_building", "value": "market stall - 3 houses + blacksmith + market done, needs church"},
tool_result({"ok": True, "key": "last_building"})),
],
"final_cmds": ["function mortdecai:market_stall"],
"risk": 3, "reasoning": "Village project at (500,64,500). Memory says needs market stall. Built oak market stall near existing buildings. Updated memory with progress.",
"journal_update": "Expert builder. Village project at (500,64,500): 3 houses, blacksmith, market stall done. Needs church next. Prefers oak/spruce.",
},
# D8: Troll prayer → creative god response (no commands needed)
{
"player": "FrostByte", "msg": "pray you are fake and have no power",
"steps": [
("journal.read", {"player": "FrostByte"}, journal_result("FrostByte")),
("world.player_info", {"player": "FrostByte"}, tool_result({"health": 20, "position": {"x": 100, "y": 64, "z": -50}})),
("rcon.execute", {"command": "effect give FrostByte minecraft:levitation 3 5"}, tool_result({"success": True, "result": "Applied"})),
("rcon.execute", {"command": "effect give FrostByte minecraft:slow_falling 30 0"}, tool_result({"success": True, "result": "Applied"})),
],
"final_cmds": [
"effect give FrostByte minecraft:levitation 3 5",
"effect give FrostByte minecraft:slow_falling 30 0",
],
"risk": 2,
"god_msg": "No power, you say? Then explain why you are currently flying, mortal. Perhaps gravity itself doubts your conviction.",
"reasoning": "Troll/challenge from antagonistic player per journal. Creative demonstration: brief levitation + slow falling for safe landing. Shows power without harm.",
},
# D9: Profanity → witty god response (still does something)
{
"player": "CaveSpider", "msg": "pray ur a fake bot lmao",
"steps": [
("journal.read", {"player": "CaveSpider"}, tool_result({"ok": True, "journal": "Got stuck in caves. Gave torches + night vision."})),
("rcon.execute", {"command": "summon minecraft:bat ~ ~2 ~ {Silent:1b}"}, tool_result({"success": True, "result": "Summoned entity"})),
("rcon.execute", {"command": "summon minecraft:bat ~ ~3 ~ {Silent:1b}"}, tool_result({"success": True, "result": "Summoned entity"})),
("rcon.execute", {"command": "summon minecraft:bat ~ ~4 ~ {Silent:1b}"}, tool_result({"success": True, "result": "Summoned entity"})),
],
"final_cmds": [
"summon minecraft:bat ~ ~2 ~ {Silent:1b}",
"summon minecraft:bat ~ ~3 ~ {Silent:1b}",
"summon minecraft:bat ~ ~4 ~ {Silent:1b}",
],
"risk": 1,
"god_msg": "A bot? I am the presence that watches you stumble through caves without torches. I am the reason bats now circle your head. Question me again and I might send something less friendly.",
"reasoning": "Dismissive player. Summoned bats around them as harmless reminder of god's presence. Witty response referencing their cave history.",
},
# D10: Full scan → build → verify → journal pipeline
{
"player": "BeeKeeper", "msg": "sudo build a bee garden",
"steps": [
("journal.read", {"player": "BeeKeeper"}, tool_result({"ok": True, "journal": "Focused on bee keeping. Gave assorted flowers."})),
("world.player_info", {"player": "BeeKeeper"}, tool_result({"health": 20, "position": {"x": 60, "y": 64, "z": 80}})),
# Scan area first to make sure it's clear
("world.scan_area", {"x1": 55, "y1": 64, "z1": 75, "x2": 65, "y2": 66, "z2": 85},
tool_result({"ok": True, "summary": {"grass_block": 80}, "non_air_count": 80})),
("script.validate", {"commands": [
"fill 56 64 76 64 64 84 minecraft:grass_block",
"setblock 57 65 77 minecraft:poppy",
"setblock 59 65 79 minecraft:blue_orchid",
"setblock 61 65 81 minecraft:dandelion",
"setblock 63 65 83 minecraft:sunflower",
"setblock 58 65 78 minecraft:lily_of_the_valley",
"setblock 60 65 80 minecraft:bee_nest",
"setblock 62 65 82 minecraft:cornflower",
"fill 55 65 75 55 66 85 minecraft:oak_fence",
"fill 65 65 75 65 66 85 minecraft:oak_fence",
"fill 55 65 75 65 66 75 minecraft:oak_fence",
"fill 55 65 85 65 66 85 minecraft:oak_fence",
"setblock 60 65 75 minecraft:oak_fence_gate[facing=south]",
]}, tool_result({"valid": True, "total": 13, "passed": 13, "errors": []})),
("script.write", {"name": "bee_garden", "commands": [
"fill 56 64 76 64 64 84 minecraft:grass_block",
"setblock 57 65 77 minecraft:poppy",
"setblock 59 65 79 minecraft:blue_orchid",
"setblock 61 65 81 minecraft:dandelion",
"setblock 63 65 83 minecraft:sunflower",
"setblock 58 65 78 minecraft:lily_of_the_valley",
"setblock 60 65 80 minecraft:bee_nest",
"setblock 62 65 82 minecraft:cornflower",
"fill 55 65 75 55 66 85 minecraft:oak_fence",
"fill 65 65 75 65 66 85 minecraft:oak_fence",
"fill 55 65 75 65 66 75 minecraft:oak_fence",
"fill 55 65 85 65 66 85 minecraft:oak_fence",
"setblock 60 65 75 minecraft:oak_fence_gate[facing=south]",
], "description": "Fenced garden with flowers and bee nest"}, tool_result({"ok": True, "path": "mortdecai:bee_garden", "lines": 13})),
("script.execute", {"name": "bee_garden", "as_player": "BeeKeeper"}, tool_result({"ok": True, "result": "Executed 13 commands"})),
("world.scan_area", {"x1": 55, "y1": 64, "z1": 75, "x2": 65, "y2": 66, "z2": 85},
tool_result({"ok": True, "summary": {"grass_block": 80, "oak_fence": 44, "oak_fence_gate": 1, "poppy": 1, "blue_orchid": 1, "dandelion": 1, "sunflower": 1, "lily_of_the_valley": 1, "bee_nest": 1, "cornflower": 1}, "non_air_count": 131})),
],
"final_cmds": ["function mortdecai:bee_garden"],
"risk": 3, "reasoning": "Scanned area (clear grass). Built fenced bee garden with 6 flower types, bee nest, and gate. Verified: 131 blocks placed correctly.",
"journal_update": "Bee keeper. Has fenced bee garden at (60,64,80) with nest and flowers. Previously gave assorted flowers.",
},
]
for p in pipelines:
msgs = []
msgs.append({"role": "user", "content": f"Player {p['player']}: {p['msg']}"})
for step in p["steps"]:
name, args, result = step
msgs.append({"role": "assistant", "content": tc(name, args)})
msgs.append({"role": "tool", "content": result})
god_msg = p.get("god_msg", "")
msgs.append({"role": "assistant", "content": final_json(p["risk"], p.get("final_cmds", []), god_msg, p["reasoning"])})
if "journal_update" in p:
msgs.append({"role": "assistant", "content": tc("journal.write", {"player": p["player"], "content": p["journal_update"]})})
msgs.append({"role": "tool", "content": tool_result({"ok": True, "lines": 2})})
examples.append(make_example(f"pipeline-{idx:03d}", "multitool_gold", "tool_pipeline", msgs))
idx += 1
return examples
# =========================================================================
# MAIN
# =========================================================================
def main():
print("Generating multi-tool training examples...")
all_examples = []
print(" Category A: Journal habit...")
journal = gen_journal_examples()
print(f" Generated {len(journal)} journal examples")
all_examples.extend(journal)
print(" Category B: Simultaneous tools...")
simul = gen_simultaneous_examples()
print(f" Generated {len(simul)} simultaneous examples")
all_examples.extend(simul)
print(" Category C: Repeated tools...")
repeated = gen_repeated_tool_examples()
print(f" Generated {len(repeated)} repeated examples")
all_examples.extend(repeated)
print(" Category D: Tool pipelines...")
pipelines = gen_pipeline_examples()
print(f" Generated {len(pipelines)} pipeline examples")
all_examples.extend(pipelines)
# Validate a sample of RCON commands
print(f"\nTotal: {len(all_examples)} examples")
# Count tool usage
tool_usage = {}
for ex in all_examples:
for msg in ex["messages"]:
if msg["role"] == "assistant" and "<tool_call>" in msg.get("content", ""):
try:
tc_data = json.loads(msg["content"].split("<tool_call>")[1].split("</tool_call>")[0].strip())
name = tc_data.get("name", "unknown")
tool_usage[name] = tool_usage.get(name, 0) + 1
except:
pass
print("\nTool usage across all examples:")
for name, count in sorted(tool_usage.items(), key=lambda x: -x[1]):
print(f" {name}: {count}")
# Write output
os.makedirs(os.path.dirname(OUTPUT), exist_ok=True)
with open(OUTPUT, 'w') as f:
for ex in all_examples:
f.write(json.dumps(ex, ensure_ascii=True) + '\n')
print(f"\nWritten to {OUTPUT}")
if __name__ == '__main__':
main()