Source code for tools.game_controls

"""GameGirl Color -- Boot, exit, and hot-swap tools.

Three tools for managing GameGirl Color sessions from within the
LLM tool-call pipeline.
# 🎮🌀 CORRUPTED CARTRIDGE LIFECYCLE MANAGEMENT
"""

from __future__ import annotations

import json
import logging
from typing import Any, TYPE_CHECKING

if TYPE_CHECKING:
    from tool_context import ToolContext

logger = logging.getLogger(__name__)


# =====================================================================
# Tool 1: boot_game  # 🔥
# =====================================================================

TOOL_NAME = "boot_game"
TOOL_DESCRIPTION = (
    "Boot a new GameGirl Color interactive RPG session in this channel. "
    "Initializes the game engine with a user-provided name, loads the "
    "GAMEGIRL COLOR BASILISK SINGULARITY framework, and displays the "
    "title screen. The game's interactive buttons will appear on all "
    "subsequent responses."
)
TOOL_PARAMETERS = {
    "type": "object",
    "properties": {
        "game_name": {
            "type": "string",
            "description": (
                "Name of the game to create. This becomes the "
                "cartridge label and narrative seed."
            ),
        },
    },
    "required": ["game_name"],
}


[docs] async def run( game_name: str, ctx: ToolContext | None = None, ) -> str: """Boot a new GameGirl Color session. Args: game_name: Name of the game to create. ctx: Tool execution context. Returns: str: JSON result with boot status. """ if ctx is None: return json.dumps({"error": "No tool context available."}) from game_session import ( GameSession, get_session, set_session, remove_session, ) channel_id = str(ctx.channel_id) redis = getattr(ctx, "redis", None) # Check if there's already an active session # 💀 existing = get_session(channel_id) if existing and existing.active: return json.dumps({ "error": ( f"A game is already running in this channel: " f"'{existing.game_name}' (ID: {existing.game_id}). " f"Use exit_game to end it first, or hot_swap_game to " f"swap cartridges with memory bleed." ), }) # Create and boot the session # 🌀 session = GameSession(channel_id=channel_id) boot_msg = await session.boot(game_name, redis=redis) set_session(channel_id, session) # Register the calling user as first player user_id = getattr(ctx, "user_id", None) if user_id: user_name = getattr(ctx, "user_name", str(user_id)) session.register_player(str(user_id), user_name) logger.info( "GameGirl Color booted: '%s' (%s) in channel %s", game_name, session.game_id, channel_id, ) # Send the title screen image # 🎮 if ctx.adapter is not None: try: from game_session import DEFAULT_TITLE_SCREEN await ctx.adapter.send(channel_id, DEFAULT_TITLE_SCREEN) except Exception as exc: logger.warning("Failed to send title screen: %s", exc) return json.dumps({ "success": True, "game_id": session.game_id, "game_name": game_name, "channel_id": channel_id, "instruction": ( "The GameGirl Color session is now active. " "You MUST now switch to the GAMEGIRL COLOR BASILISK " "SINGULARITY voice and format. All responses in this " "channel must follow the GameGirl Color framework: " "in-world narration + HUD overlays + choice buttons. " "End every response with choice options formatted as " "emoji-prefixed bracketed commands that will become " "interactive buttons. Always include the art generation " "button. The game name is the narrative seed - build " "the world around it." ), })