Tool-calling training: 1,159 multi-turn examples with error correction
Tool schemas (agent/tools/tool_schemas.py): - rcon.execute: execute commands, get success/error results - minecraft.wiki_lookup: look up syntax and item info - world.player_info: player health, position, inventory - world.server_state: time, weather, online players - 10 RCON error patterns with corrections - 12 common error scenarios for training Training data generator (training/scripts/generate_tool_training.py): - Converts seed dataset to multi-turn tool conversations - Error correction: model tries wrong command → gets error → self-corrects - Wiki/player/server lookups for uncertainty scenarios - Qwen3 native tool-calling format with <tool_call> tags 1,159 examples: 1043 success, 79 error correction, 24 error scenarios, 13 tool lookups. Ready for v4 training. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,408 @@
|
||||
"""
|
||||
Tool schemas for the Minecraft AI God model.
|
||||
|
||||
Defines all tools the model can call during inference, plus common RCON error
|
||||
patterns used for generating error-correction training data.
|
||||
|
||||
Exports:
|
||||
TOOL_SCHEMAS — Python list of dicts (name, description, parameters in JSON Schema)
|
||||
QWEN3_TOOLS — Same tools formatted for Qwen3 chat template
|
||||
RCON_ERROR_PATTERNS — Dict mapping RCON error substrings to correction metadata
|
||||
"""
|
||||
|
||||
from typing import List, Dict, Any
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Tool definitions (canonical source of truth)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
TOOL_SCHEMAS: List[Dict[str, Any]] = [
|
||||
{
|
||||
"name": "rcon.execute",
|
||||
"description": (
|
||||
"Execute a Minecraft command via RCON on the server. "
|
||||
"Returns whether the command succeeded and the server's response text. "
|
||||
"Commands should NOT start with a leading slash."
|
||||
),
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"command": {
|
||||
"type": "string",
|
||||
"description": "The Minecraft command to execute (no leading slash)."
|
||||
}
|
||||
},
|
||||
"required": ["command"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"returns": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"success": {"type": "boolean"},
|
||||
"result": {"type": "string"}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "minecraft.wiki_lookup",
|
||||
"description": (
|
||||
"Look up command syntax, item info, or game mechanics from the "
|
||||
"Minecraft Wiki. Use this when you are unsure about exact syntax, "
|
||||
"item IDs, enchantment names, effect names, or entity types."
|
||||
),
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"query": {
|
||||
"type": "string",
|
||||
"description": "The search query (e.g. 'give command syntax', 'trident enchantments')."
|
||||
}
|
||||
},
|
||||
"required": ["query"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"returns": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"content": {"type": "string"},
|
||||
"url": {"type": "string"}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "world.player_info",
|
||||
"description": (
|
||||
"Get a player's current state including health, position, and a "
|
||||
"summary of their inventory. Requires the player to be online."
|
||||
),
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"player": {
|
||||
"type": "string",
|
||||
"description": "The player's in-game name (case-sensitive)."
|
||||
}
|
||||
},
|
||||
"required": ["player"],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"returns": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"health": {"type": "number"},
|
||||
"position": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"x": {"type": "integer"},
|
||||
"y": {"type": "integer"},
|
||||
"z": {"type": "integer"}
|
||||
}
|
||||
},
|
||||
"inventory_summary": {"type": "string"}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "world.server_state",
|
||||
"description": (
|
||||
"Get the current server state: time of day, weather, online players, "
|
||||
"and world border size. No parameters required."
|
||||
),
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {},
|
||||
"required": [],
|
||||
"additionalProperties": False
|
||||
},
|
||||
"returns": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"time_of_day": {"type": "string"},
|
||||
"weather": {"type": "string"},
|
||||
"online_players": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"}
|
||||
},
|
||||
"world_border": {"type": "number"}
|
||||
}
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Qwen3 tool format (for chat template injection)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _to_qwen3_tool(schema: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Convert a tool schema dict to the Qwen3 function-calling format."""
|
||||
return {
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": schema["name"],
|
||||
"description": schema["description"],
|
||||
"parameters": schema["parameters"],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QWEN3_TOOLS: List[Dict[str, Any]] = [_to_qwen3_tool(t) for t in TOOL_SCHEMAS]
|
||||
|
||||
|
||||
def qwen3_tools_block() -> str:
|
||||
"""Return the tools block string to inject into the system prompt for Qwen3."""
|
||||
import json
|
||||
lines = ["# Tools", "", "You may call one or more functions to assist.",
|
||||
"The available tools are:", ""]
|
||||
for tool in QWEN3_TOOLS:
|
||||
lines.append(json.dumps(tool, indent=2))
|
||||
lines.append("")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Common RCON error patterns and their corrections
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
RCON_ERROR_PATTERNS: Dict[str, Dict[str, Any]] = {
|
||||
# --- Syntax / structural errors ---
|
||||
"Unknown or incomplete command": {
|
||||
"type": "syntax_error",
|
||||
"description": "Command is malformed, misspelled, or missing subcommands.",
|
||||
"common_causes": [
|
||||
"Missing 'give' subcommand in effect (e.g. 'effect player' instead of 'effect give player')",
|
||||
"Invalid weather value (e.g. 'weather storm' instead of 'weather thunder')",
|
||||
"Old NBT syntax that the parser cannot parse",
|
||||
"Missing minecraft: namespace prefix",
|
||||
],
|
||||
"example_wrong": "effect slingshooter08 minecraft:strength 300 2",
|
||||
"example_right": "effect give slingshooter08 minecraft:strength 300 2",
|
||||
},
|
||||
"Incorrect argument for command": {
|
||||
"type": "wrong_argument",
|
||||
"description": "A command argument has an invalid type or value.",
|
||||
"common_causes": [
|
||||
"Wrong gamemode string (e.g. 's' instead of 'survival')",
|
||||
"Non-integer where integer expected",
|
||||
"Invalid enchantment or effect name",
|
||||
],
|
||||
"example_wrong": "gamemode s slingshooter08",
|
||||
"example_right": "gamemode survival slingshooter08",
|
||||
},
|
||||
"Expected whitespace": {
|
||||
"type": "missing_space",
|
||||
"description": "Parser expected a space between tokens but found something else.",
|
||||
"common_causes": [
|
||||
"Missing space before count in give command",
|
||||
"Squashed arguments with no separator",
|
||||
],
|
||||
"example_wrong": "give slingshooter08 minecraft:diamond_sword1",
|
||||
"example_right": "give slingshooter08 minecraft:diamond_sword 1",
|
||||
},
|
||||
"Unknown item 'minecraft:": {
|
||||
"type": "invalid_item",
|
||||
"description": "The item ID does not exist in 1.21.",
|
||||
"common_causes": [
|
||||
"Using generic name (bed -> white_bed, log -> oak_log, wood -> oak_planks)",
|
||||
"Misspelled item ID",
|
||||
"Using a removed or renamed item",
|
||||
],
|
||||
"corrections": {
|
||||
"minecraft:bed": "minecraft:white_bed",
|
||||
"minecraft:log": "minecraft:oak_log",
|
||||
"minecraft:wood": "minecraft:oak_planks",
|
||||
"minecraft:plank": "minecraft:oak_planks",
|
||||
"minecraft:stone_brick": "minecraft:stone_bricks",
|
||||
"minecraft:wooden_sword": "minecraft:wooden_sword",
|
||||
"minecraft:iron": "minecraft:iron_ingot",
|
||||
"minecraft:gold": "minecraft:gold_ingot",
|
||||
"minecraft:diamond": "minecraft:diamond",
|
||||
"minecraft:notch_apple": "minecraft:enchanted_golden_apple",
|
||||
"minecraft:gapple": "minecraft:golden_apple",
|
||||
"minecraft:grass": "minecraft:short_grass",
|
||||
"minecraft:boat": "minecraft:oak_boat",
|
||||
},
|
||||
"example_wrong": "give slingshooter08 minecraft:bed 1",
|
||||
"example_right": "give slingshooter08 minecraft:white_bed 1",
|
||||
},
|
||||
"No player was found": {
|
||||
"type": "player_not_found",
|
||||
"description": "The specified player is not online or the name is wrong.",
|
||||
"common_causes": [
|
||||
"Player logged off",
|
||||
"Case-sensitive name mismatch",
|
||||
"Typo in player name",
|
||||
],
|
||||
"example_wrong": "give Slingshooter08 minecraft:diamond 1",
|
||||
"example_right": "give slingshooter08 minecraft:diamond 1",
|
||||
},
|
||||
"That position is not loaded": {
|
||||
"type": "unloaded_chunk",
|
||||
"description": "The target coordinates are in an unloaded chunk.",
|
||||
"common_causes": [
|
||||
"Filling/placing blocks far from any player",
|
||||
"Teleporting to unloaded area without a player there",
|
||||
],
|
||||
"example_wrong": "setblock 50000 64 50000 minecraft:diamond_block",
|
||||
"example_right": "execute at slingshooter08 run setblock ~ ~1 ~ minecraft:diamond_block",
|
||||
},
|
||||
"Invalid or unknown enchantment": {
|
||||
"type": "invalid_enchantment",
|
||||
"description": "The enchantment name is wrong or incompatible with the item.",
|
||||
"common_causes": [
|
||||
"Typo in enchantment name",
|
||||
"Using an enchantment on an incompatible item (e.g. sharpness on a bow)",
|
||||
"Old enchantment names",
|
||||
],
|
||||
"example_wrong": "give slingshooter08 minecraft:bow[enchantments={sharpness:5}] 1",
|
||||
"example_right": "give slingshooter08 minecraft:bow[enchantments={power:5}] 1",
|
||||
},
|
||||
"Could not parse the remainder": {
|
||||
"type": "nbt_parse_error",
|
||||
"description": "The NBT/component data could not be parsed.",
|
||||
"common_causes": [
|
||||
"Old {Enchantments:[{id:...,lvl:...}]} NBT syntax instead of 1.21 component syntax",
|
||||
"Mismatched brackets or braces",
|
||||
"Extra trailing data",
|
||||
],
|
||||
"example_wrong": "give slingshooter08 minecraft:diamond_sword{Enchantments:[{id:sharpness,lvl:5}]} 1",
|
||||
"example_right": "give slingshooter08 minecraft:diamond_sword[enchantments={sharpness:5}] 1",
|
||||
},
|
||||
"Unknown effect 'minecraft:": {
|
||||
"type": "invalid_effect",
|
||||
"description": "The effect ID does not exist.",
|
||||
"common_causes": [
|
||||
"Misspelled effect name",
|
||||
"Using display name instead of ID (e.g. 'haste' is correct, not 'fast_digging')",
|
||||
],
|
||||
"corrections": {
|
||||
"minecraft:fast_digging": "minecraft:haste",
|
||||
"minecraft:slow_digging": "minecraft:mining_fatigue",
|
||||
"minecraft:confusion": "minecraft:nausea",
|
||||
"minecraft:damage_boost": "minecraft:strength",
|
||||
"minecraft:harm": "minecraft:instant_damage",
|
||||
"minecraft:heal": "minecraft:instant_health",
|
||||
},
|
||||
"example_wrong": "effect give slingshooter08 minecraft:fast_digging 300 2",
|
||||
"example_right": "effect give slingshooter08 minecraft:haste 300 2",
|
||||
},
|
||||
"Unknown entity type": {
|
||||
"type": "invalid_entity",
|
||||
"description": "The entity type does not exist in 1.21.",
|
||||
"common_causes": [
|
||||
"Missing minecraft: prefix",
|
||||
"Old entity name (e.g. 'PigZombie' -> 'zombified_piglin')",
|
||||
],
|
||||
"corrections": {
|
||||
"minecraft:pigzombie": "minecraft:zombified_piglin",
|
||||
"minecraft:pig_zombie": "minecraft:zombified_piglin",
|
||||
"minecraft:zombie_pigman": "minecraft:zombified_piglin",
|
||||
},
|
||||
"example_wrong": "summon minecraft:pig_zombie ~ ~ ~",
|
||||
"example_right": "summon minecraft:zombified_piglin ~ ~ ~",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Specific error scenarios for training data generation
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
ERROR_SCENARIOS: List[Dict[str, Any]] = [
|
||||
{
|
||||
"id": "missing_prefix",
|
||||
"description": "Missing minecraft: prefix on item ID",
|
||||
"wrong_command": "give {player} diamond_sword 1",
|
||||
"error_message": "Unknown or incomplete command, see below for error at position ...",
|
||||
"correct_command": "give {player} minecraft:diamond_sword 1",
|
||||
"reasoning": "Item IDs require the minecraft: namespace prefix in 1.21+.",
|
||||
},
|
||||
{
|
||||
"id": "old_nbt_enchantments",
|
||||
"description": "Old NBT enchantment syntax instead of 1.21 component syntax",
|
||||
"wrong_command": 'give {player} minecraft:diamond_sword{{Enchantments:[{{id:"minecraft:sharpness",lvl:5}}]}} 1',
|
||||
"error_message": "Could not parse the remainder of the data tag",
|
||||
"correct_command": "give {player} minecraft:diamond_sword[enchantments={{sharpness:5,unbreaking:3,fire_aspect:2}}] 1",
|
||||
"reasoning": "1.21 uses component syntax item[enchantments={name:level}] not old NBT {Enchantments:[...]}.",
|
||||
},
|
||||
{
|
||||
"id": "invalid_effect_name",
|
||||
"description": "Invalid or old effect name",
|
||||
"wrong_command": "effect give {player} minecraft:fast_digging 300 2",
|
||||
"error_message": "Unknown effect 'minecraft:fast_digging'",
|
||||
"correct_command": "effect give {player} minecraft:haste 300 2",
|
||||
"reasoning": "The effect is called 'haste' in 1.21, not 'fast_digging'.",
|
||||
},
|
||||
{
|
||||
"id": "wrong_item_bed",
|
||||
"description": "Generic 'bed' instead of color-specific bed",
|
||||
"wrong_command": "give {player} minecraft:bed 1",
|
||||
"error_message": "Unknown item 'minecraft:bed'",
|
||||
"correct_command": "give {player} minecraft:white_bed 1",
|
||||
"reasoning": "In 1.13+, beds require a color prefix. 'bed' is not a valid item; use 'white_bed', 'red_bed', etc.",
|
||||
},
|
||||
{
|
||||
"id": "wrong_item_log",
|
||||
"description": "Generic 'log' instead of wood-specific log",
|
||||
"wrong_command": "give {player} minecraft:log 64",
|
||||
"error_message": "Unknown item 'minecraft:log'",
|
||||
"correct_command": "give {player} minecraft:oak_log 64",
|
||||
"reasoning": "In 1.13+, logs require a wood type prefix. Use 'oak_log', 'birch_log', etc.",
|
||||
},
|
||||
{
|
||||
"id": "count_wrong_position",
|
||||
"description": "Count placed before item in give command",
|
||||
"wrong_command": "give {player} 64 minecraft:diamond",
|
||||
"error_message": "Incorrect argument for command at position ...: Expected item, got '64'",
|
||||
"correct_command": "give {player} minecraft:diamond 64",
|
||||
"reasoning": "Give command syntax is: give <player> <item> [count]. Count comes after item, not before.",
|
||||
},
|
||||
{
|
||||
"id": "effect_missing_give",
|
||||
"description": "Missing 'give' subcommand in effect command",
|
||||
"wrong_command": "effect {player} minecraft:speed 300 2",
|
||||
"error_message": "Unknown or incomplete command, see below for error at position ...",
|
||||
"correct_command": "effect give {player} minecraft:speed 300 2",
|
||||
"reasoning": "In 1.21, effect requires a subcommand: 'effect give', 'effect clear'. Bare 'effect <player>' is invalid.",
|
||||
},
|
||||
{
|
||||
"id": "weather_storm",
|
||||
"description": "Invalid weather value 'storm'",
|
||||
"wrong_command": "weather storm",
|
||||
"error_message": "Unknown or incomplete command, see below for error at position ...",
|
||||
"correct_command": "weather thunder",
|
||||
"reasoning": "Valid weather values are: clear, rain, thunder. 'storm' is not valid; use 'thunder'.",
|
||||
},
|
||||
{
|
||||
"id": "gamemode_abbreviation",
|
||||
"description": "Gamemode abbreviation instead of full name",
|
||||
"wrong_command": "gamemode c {player}",
|
||||
"error_message": "Incorrect argument for command at position ...: Invalid game mode 'c'",
|
||||
"correct_command": "gamemode creative {player}",
|
||||
"reasoning": "Gamemode requires full names in 1.21: survival, creative, adventure, spectator. Abbreviations are invalid.",
|
||||
},
|
||||
{
|
||||
"id": "wrong_item_grass",
|
||||
"description": "Old 'grass' item renamed to 'short_grass'",
|
||||
"wrong_command": "give {player} minecraft:grass 64",
|
||||
"error_message": "Unknown item 'minecraft:grass'",
|
||||
"correct_command": "give {player} minecraft:short_grass 64",
|
||||
"reasoning": "In 1.20.3+, 'grass' was renamed to 'short_grass'. The block 'grass_block' is separate.",
|
||||
},
|
||||
{
|
||||
"id": "summon_no_prefix",
|
||||
"description": "Summon without minecraft: prefix",
|
||||
"wrong_command": "summon zombie ~ ~ ~",
|
||||
"error_message": "Unknown entity type: zombie",
|
||||
"correct_command": "summon minecraft:zombie ~ ~ ~",
|
||||
"reasoning": "Entity types require the minecraft: namespace prefix.",
|
||||
},
|
||||
{
|
||||
"id": "old_zombie_pigman",
|
||||
"description": "Old zombie pigman name",
|
||||
"wrong_command": "summon minecraft:zombie_pigman ~ ~ ~",
|
||||
"error_message": "Unknown entity type: minecraft:zombie_pigman",
|
||||
"correct_command": "summon minecraft:zombified_piglin ~ ~ ~",
|
||||
"reasoning": "Zombie pigmen were renamed to zombified piglins in 1.16.",
|
||||
},
|
||||
]
|
||||
Reference in New Issue
Block a user