Agentic-zork / run_agent.py
nathanael-fijalkow's picture
Major refactoring
450ea3f
#!/usr/bin/env python3
"""
Text Adventure Agent Runner
Run the MCP ReAct agent to play text adventure games like Zork.
Usage:
python run_agent.py
python run_agent.py --game advent
python run_agent.py --max-steps 50
python run_agent.py --agent hidden_submission
Examples:
# Run on Zork 1 with example agent (default)
python run_agent.py
# Play a different game
python run_agent.py --game advent
# Use a different agent folder
python run_agent.py --agent hidden_submission
# List all available games
python run_agent.py --list-games
# Run with verbose output
python run_agent.py -v
"""
import argparse
import sys
import os
import asyncio
from pathlib import Path
# Add games module to path for discovering available games
sys.path.insert(0, str(Path(__file__).parent))
from games.zork_env import list_available_games
def find_agent_folders() -> list[str]:
"""Find all folders containing agent.py and mcp_server.py."""
project_root = Path(__file__).parent
agent_folders = []
for folder in project_root.iterdir():
if folder.is_dir():
agent_file = folder / "agent.py"
server_file = folder / "mcp_server.py"
if agent_file.exists() and server_file.exists():
agent_folders.append(folder.name)
return sorted(agent_folders)
async def run_mcp_agent(args):
"""Run MCP ReAct Agent from the specified folder."""
agent_folder = Path(__file__).parent / args.agent
agent_file = agent_folder / "agent.py"
server_file = agent_folder / "mcp_server.py"
# Validate folder structure
if not agent_folder.exists():
raise FileNotFoundError(f"Agent folder not found: {agent_folder}")
if not agent_file.exists():
raise FileNotFoundError(f"agent.py not found in {agent_folder}")
if not server_file.exists():
raise FileNotFoundError(f"mcp_server.py not found in {agent_folder}")
# Import from the specified folder
sys.path.insert(0, str(agent_folder))
from agent import StudentAgent
from fastmcp import Client
from fastmcp.client.transports import StdioTransport
print(f"\n[MCP] Running Student Agent with FastMCP")
print(f" Agent: {args.agent}/")
print(f" Game: {args.game}")
print()
agent = StudentAgent()
# Create transport for the MCP server
env_vars = os.environ.copy()
env_vars["GAME"] = args.game
transport = StdioTransport(
command=sys.executable,
args=[str(server_file)],
env=env_vars,
)
async with Client(transport) as client:
return await agent.run(
client=client,
game=args.game,
max_steps=args.max_steps,
seed=42, # Using a fixed seed for direct running
verbose=args.verbose,
)
def main():
# Find available agent folders
agent_folders = find_agent_folders()
parser = argparse.ArgumentParser(
description="Run the MCP ReAct agent to play text adventure games",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog=f"""
Examples:
python run_agent.py # Play Zork 1 with example agent
python run_agent.py --game advent # Play Adventure
python run_agent.py --agent hidden_submission # Use hidden agent
python run_agent.py --list-games # List all games
python run_agent.py --list-agents # List all agent folders
python run_agent.py -v # Verbose output
"""
)
# Get available games for help text
available_games = list_available_games()
game_help = f"Game to play (default: zork1). {len(available_games)} games available."
agent_help = f"Agent folder to use (default: example_submission). Available: {', '.join(agent_folders)}"
parser.add_argument(
"--agent", "-a",
type=str,
default="example_submission",
help=agent_help
)
parser.add_argument(
"--game", "-g",
type=str,
default="lostpig",
help=game_help
)
parser.add_argument(
"--list-games",
action="store_true",
help="List all available games and exit"
)
parser.add_argument(
"--list-agents",
action="store_true",
help="List all available agent folders and exit"
)
parser.add_argument(
"--max-steps", "-n",
type=int,
default=100,
help="Maximum number of steps to run (default: 100)"
)
parser.add_argument(
"--verbose", "-v",
action="store_true",
help="Show detailed reasoning from the agent"
)
args = parser.parse_args()
# Handle --list-agents
if args.list_agents:
print(f"\nAvailable agent folders ({len(agent_folders)} total):\n")
for folder in agent_folders:
print(f" {folder}/")
print("\nEach folder must contain agent.py and mcp_server.py")
print()
sys.exit(0)
# Handle --list-games
if args.list_games:
print(f"\nAvailable games ({len(available_games)} total):\n")
# Print in columns
cols = 5
for i in range(0, len(available_games), cols):
row = available_games[i:i+cols]
print(" " + " ".join(f"{g:<15}" for g in row))
print()
sys.exit(0)
# Validate agent choice
if args.agent not in agent_folders:
print(f"\nError: Unknown agent folder '{args.agent}'")
print(f"Available: {', '.join(agent_folders)}")
print("Use --list-agents to see details.")
sys.exit(1)
# Validate game choice
if args.game.lower() not in available_games:
print(f"\nError: Unknown game '{args.game}'")
print(f"Use --list-games to see {len(available_games)} available options.")
sys.exit(1)
print("\n" + "=" * 60)
print("Text Adventure MCP Agent Runner")
print("=" * 60)
print(f"Agent: {args.agent}/")
print(f"Game: {args.game}")
print(f"Max Steps: {args.max_steps}")
print(f"Verbose: {args.verbose}")
# Run the agent
try:
results = asyncio.run(run_mcp_agent(args))
except FileNotFoundError as e:
print(f"\n[Error] {e}")
sys.exit(1)
except ValueError as e:
print(f"\n[Error] {e}")
print("\nTo fix this:")
print("1. Copy .env.example to .env")
print("2. Add your HuggingFace token (HF_TOKEN)")
sys.exit(1)
except ImportError as e:
print(f"\n[Import Error] {e}")
print("\nMake sure to install dependencies:")
print(" pip install -r requirements.txt")
sys.exit(1)
return results
if __name__ == "__main__":
main()