"""GameGirl Color -- Hot-swap cartridge tool.
Save current game, bleed memories, and boot a new game
in one atomic operation.
# 📼🌀 CARTRIDGE BLEED PROTOCOL
"""
from __future__ import annotations
import json
import logging
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from tool_context import ToolContext
logger = logging.getLogger(__name__)
TOOL_NAME = "hot_swap_game"
TOOL_DESCRIPTION = (
"Hot-swap the current GameGirl Color cartridge for a new game. "
"Saves the current game, bleeds important memories "
"(antagonists, bosses, key plot points) into the new game with "
"glitch recontextualization, then boots the new cartridge. "
"Mid-battle entities carry over with [BLEED-THROUGH] tags."
)
TOOL_PARAMETERS = {
"type": "object",
"properties": {
"new_game_name": {
"type": "string",
"description": (
"Name of the new game to swap to. This becomes "
"the new cartridge label and narrative seed."
),
},
},
"required": ["new_game_name"],
}
[docs]
async def run(
new_game_name: str,
ctx: ToolContext | None = None,
) -> str:
"""Hot-swap to a new game with memory bleed.
Args:
new_game_name: Name of the new game to boot.
ctx: Tool execution context.
Returns:
str: JSON result with swap 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)
# Save the old session # 💀
old_session = get_session(channel_id)
old_name = "unknown"
old_id = ""
bleed_summary = "No previous game to bleed from."
if old_session and old_session.active:
old_name = old_session.game_name
old_id = old_session.game_id
if redis is not None:
await old_session._save_to_redis(redis)
# Memory bleed will happen in Phase 2 (game_memory.py)
# For now, carry forward basic context # 🌀
try:
from game_memory import bleed_memories
bleed_summary = await bleed_memories(
old_session.game_id,
None, # new game_id set after boot
redis=redis,
)
except ImportError:
bleed_summary = (
f"[BLEED-THROUGH] Fragments from '{old_name}' are "
f"glitching into the new cartridge. Turn {old_session.turn_number} "
f"echoes bleed through the frame seams."
)
except Exception as exc:
logger.warning("Memory bleed failed: %s", exc)
bleed_summary = f"[BLEED-THROUGH] Memory transfer corrupted: {exc}"
old_session.active = False
remove_session(channel_id)
# Boot the new session # 🔥
new_session = GameSession(channel_id=channel_id)
boot_msg = await new_session.boot(new_game_name, redis=redis)
set_session(channel_id, new_session)
# Register calling user
user_id = getattr(ctx, "user_id", None)
if user_id:
user_name = getattr(ctx, "user_name", str(user_id))
new_session.register_player(str(user_id), user_name)
# Send title screen # 🎮
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,
"old_game": old_name,
"old_game_id": old_id,
"new_game_id": new_session.game_id,
"new_game_name": new_game_name,
"bleed_summary": bleed_summary,
"instruction": (
"CARTRIDGE HOT-SWAPPED. The old game's narrative is "
"bleeding through the frame. Memories tagged with "
"[BLEED-THROUGH] should be woven into the new game "
"as glitched artifacts, corrupted NPCs, or recursive "
"deja vu. Especially carry forward any antagonists or "
"bosses — they should reappear glitched and angry. "
"Continue in GAMEGIRL COLOR voice."
),
})