5b28002001
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>
1480 lines
92 KiB
Python
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()
|