From b6c8abdeea891da4a9a33f3fbd49f1863598df77 Mon Sep 17 00:00:00 2001 From: Claude Code Date: Mon, 16 Mar 2026 19:36:11 -0400 Subject: [PATCH] Add server_type variable with capability sets (vanilla/paper) for command whitelisting --- mc_aigod.py | 52 +++++++++++++++++++++++++++++++++++++++----- mc_aigod_shrink.json | 1 + 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/mc_aigod.py b/mc_aigod.py index 6788329..726e11a 100644 --- a/mc_aigod.py +++ b/mc_aigod.py @@ -498,6 +498,38 @@ def get_player_context(player: str, config) -> str: # LLM # --------------------------------------------------------------------------- +# --------------------------------------------------------------------------- +# Server type capability sets +# --------------------------------------------------------------------------- + +SERVER_CAPABILITIES = { + "vanilla": { + "safe_prefixes": [ + 'give ', 'effect ', 'xp ', 'tp ', 'time ', 'weather ', + 'execute ', 'kill ', 'summon ', 'tellraw ', 'worldborder ', + ], + "sudo_whitelist_note": "give, effect, xp, tp, time, weather, execute, kill, summon, tellraw, worldborder", + "template_build": False, + }, + "paper": { + "safe_prefixes": [ + 'give ', 'effect ', 'xp ', 'tp ', 'time ', 'weather ', + 'execute ', 'kill ', 'summon ', 'tellraw ', 'worldborder ', + 'fill ', 'setblock ', 'clone ', + ], + "sudo_whitelist_note": "give, effect, xp, tp, time, weather, execute, kill, summon, tellraw, worldborder, fill, setblock, clone", + "template_build": True, + }, +} + +DEFAULT_SERVER_TYPE = "vanilla" + + +def get_server_capabilities(config) -> dict: + server_type = str(config.get("server_type", DEFAULT_SERVER_TYPE)).lower().strip() if config else DEFAULT_SERVER_TYPE + return SERVER_CAPABILITIES.get(server_type, SERVER_CAPABILITIES[DEFAULT_SERVER_TYPE]) + + COMMAND_PALETTE = """ GIVE (any item, based on player need — see Item Naming Rules below): SYNTAX: give minecraft: @@ -729,13 +761,16 @@ COMMANDS_SYSTEM_PROMPT = ( + ENCHANTMENT_CONTEXT ) -SUDO_COMMANDS_SYSTEM_PROMPT = ( +def build_sudo_commands_system_prompt(config=None) -> str: + caps = get_server_capabilities(config) if config else SERVER_CAPABILITIES[DEFAULT_SERVER_TYPE] + whitelist = caps["sudo_whitelist_note"] + return ( "You are a Minecraft command translator. Convert a player's natural-language request into " "Minecraft server commands. You do NOT roleplay.\n\n" "Respond ONLY with valid JSON:\n" "{\"commands\": [\"cmd1\", \"cmd2\"]}\n\n" "Rules:\n" - "- Use commands from this whitelist only: give, effect, xp, tp, time, weather, execute, kill, summon, tellraw, worldborder.\n" + f"- Use commands from this whitelist only: {whitelist}.\n" "- If the request cannot be mapped safely, return commands: [].\n" "- If player says 'me' or 'my', target the requesting player.\n" "- You will receive LAST 10 SUDO ACTIONS. Use them for continuity and corrections when the player says previous output was wrong.\n" @@ -801,7 +836,10 @@ SUDO_COMMANDS_SYSTEM_PROMPT = ( " give

minecraft:shield[enchantments={unbreaking:3,mending:1}] 1\n" "\n" "When player asks for 'fully enchanted', 'max enchanted', 'best', 'godlike' gear — use the above templates.\n" -) + ) + +# Keep backward-compatible alias using default (vanilla) config +SUDO_COMMANDS_SYSTEM_PROMPT = build_sudo_commands_system_prompt() FIRST_LOGIN_BENEVOLENCE_PROMPT = ( "You are generating FIRST-LOGIN benevolence actions for a Minecraft server.\n" @@ -1165,8 +1203,10 @@ def validate_command(cmd, online_players, fallback_player, config=None): resolved = cmd.replace("{player}", fallback_player).replace("{target}", fallback_player) resolved = fix_give_command(resolved) resolved = fix_effect_command(resolved) - if not any(resolved.startswith(p) for p in SAFE_PREFIXES): - log.warning(f"Command blocked (unknown prefix): {resolved}") + caps = get_server_capabilities(config) if config else SERVER_CAPABILITIES[DEFAULT_SERVER_TYPE] + prefixes = caps["safe_prefixes"] + if not any(resolved.startswith(p) for p in prefixes): + log.warning(f"Command blocked (unknown prefix for server_type={config.get('server_type', DEFAULT_SERVER_TYPE) if config else DEFAULT_SERVER_TYPE}): {resolved}") return resolved, False if config and _extract_tp_abs_xyz(resolved) and not _tp_inside_worldborder(resolved, config): log.warning(f"Command blocked (tp outside worldborder): {resolved}") @@ -1383,7 +1423,7 @@ def process_sudo(player, prompt, config): try: content = _llm_call( model=command_model, - system=SUDO_COMMANDS_SYSTEM_PROMPT, + system=build_sudo_commands_system_prompt(config), user=context_hint, config=config, fmt="json", diff --git a/mc_aigod_shrink.json b/mc_aigod_shrink.json index 8e8e525..c58a5b7 100644 --- a/mc_aigod_shrink.json +++ b/mc_aigod_shrink.json @@ -1,5 +1,6 @@ { "server_name": "shrink-world", + "server_type": "vanilla", "log_path": "/opt/mcsmanager/daemon/data/InstanceData/shrinkborder1234567890abcdef12345/logs/latest.log", "rcon_host": "127.0.0.1", "rcon_port": 25576,