Spaces:
Configuration error
Configuration error
Upload 6 files
Browse files- .gitattributes +1 -0
- README.md +61 -0
- TP3_LLM.pdf +3 -0
- agent.py +367 -0
- mcp_server.py +348 -0
- results_Qwen2.5-72B-Instruct_lostpig +230 -0
- results_Qwen2.5-7B-Instruct_lostpig +218 -0
.gitattributes
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
TP3_LLM.pdf filter=lfs diff=lfs merge=lfs -text
|
README.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Agentic Zork: MCP ReAct Agent
|
| 2 |
+
|
| 3 |
+
This project implements an autonomous AI agent to play classic text adventure games (like Zork or Lost Pig) using the Model Context Protocol (MCP) and the ReAct (Reason + Act) framework.
|
| 4 |
+
|
| 5 |
+
Designed to be robust and fault-tolerant for blind evaluations on smaller language models (like Qwen 2.5), this implementation focuses on stateful memory management, strict tool execution, and avoiding the dreaded "infinite loops" common in text adventures.
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
## Core Architecture
|
| 9 |
+
|
| 10 |
+
The system is decoupled into two primary components to maximize stability and context-window efficiency:
|
| 11 |
+
|
| 12 |
+
### 1. The ReAct Agent (`agent.py`)
|
| 13 |
+
Mine acts as a "Hierarchical Agent Manager", orchestrating three internal personas to decide the next move:
|
| 14 |
+
* **The Navigator:** Focuses on movement and exploration using the map.
|
| 15 |
+
* **The Interaction Specialist:** Focuses on interacting with objects and solving puzzles.
|
| 16 |
+
* **The Historian:** Keeps track of the story, recent history, and prevents repetitive looping.
|
| 17 |
+
|
| 18 |
+
It utilizes a Chain-of-Thought scratchpad (`THOUGHT:`) to reason about the environment before committing to an action (`TOOL:` / `ARGS:`), which significantly reduces hallucinated commands.
|
| 19 |
+
|
| 20 |
+
### 2. The Stateful MCP Server (`mcp_server.py`)
|
| 21 |
+
Solves the inherent "statelessness" of LLMs by maintaining the game environment, tracking historical moves, and mapping the world. It acts as the bridge between the Jericho game engine and the agent, providing persistent state as MCP resources.
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
## Available MCP Tools
|
| 25 |
+
|
| 26 |
+
The agent interacts with the game world exclusively through the following tools exposed by FastMCP:
|
| 27 |
+
|
| 28 |
+
* `play_action`: Executes a physical game command (e.g., "go north", "take lamp") and advances the game state.
|
| 29 |
+
* `inventory`: Checks the items currently held by the player.
|
| 30 |
+
* `get_map`: Returns a topological map of explored locations and their known exits.
|
| 31 |
+
* `get_historian_summary`: Returns a concise log of the last few actions and their corresponding observations to maintain narrative continuity.
|
| 32 |
+
* `get_valid_actions`: Queries the game engine for a list of physically valid interactive commands for the current room.
|
| 33 |
+
* `get_room_context`: Returns a highly structured breakdown of the current location, including previously tried actions and warnings about where the agent just came from to prevent backtracking.
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
## Usage Instructions
|
| 37 |
+
|
| 38 |
+
**1. Install Dependencies**
|
| 39 |
+
Ensure you have the required packages installed, including FastMCP, Jericho, and the HuggingFace Hub client.
|
| 40 |
+
```bash
|
| 41 |
+
pip install -r requirements.txt
|
| 42 |
+
```
|
| 43 |
+
|
| 44 |
+
**2. Set up your Environment**
|
| 45 |
+
Copy .env.example to .env and add your HuggingFace token:
|
| 46 |
+
```bash
|
| 47 |
+
HF_TOKEN=your_token_here
|
| 48 |
+
```
|
| 49 |
+
|
| 50 |
+
**3. Run the Agent**
|
| 51 |
+
You can run the agent locally using the provided runner script.
|
| 52 |
+
```bash
|
| 53 |
+
# Run on Zork 1 with example agent (default)
|
| 54 |
+
python run_agent.py
|
| 55 |
+
|
| 56 |
+
# Play a different game (e.g., lostpig) with verbose reasoning and a 50-step limit
|
| 57 |
+
python run_agent.py --agent . --game lostpig -v -n 50
|
| 58 |
+
|
| 59 |
+
# List all 57 available games
|
| 60 |
+
python run_agent.py --list-games
|
| 61 |
+
```
|
TP3_LLM.pdf
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:bd97184220273cbf32bf76a151036f07306b7f5ac7f83e1311062d4955e052d0
|
| 3 |
+
size 129363
|
agent.py
ADDED
|
@@ -0,0 +1,367 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Student Agent for Text Adventure Games
|
| 3 |
+
|
| 4 |
+
This is your submission file. Implement the StudentAgent class to play
|
| 5 |
+
text adventure games using the MCP server you also implement.
|
| 6 |
+
|
| 7 |
+
Your agent should:
|
| 8 |
+
1. Connect to the MCP server via the provided client
|
| 9 |
+
2. Use the ReAct pattern (Thought -> Action -> Observation)
|
| 10 |
+
3. Call MCP tools to interact with the game
|
| 11 |
+
4. Maximize the game score within the step limit
|
| 12 |
+
|
| 13 |
+
Required method:
|
| 14 |
+
async def run(self, client, game, max_steps, seed, verbose) -> RunResult
|
| 15 |
+
|
| 16 |
+
The 'client' is a FastMCP Client already connected to your MCP server.
|
| 17 |
+
Use it to call tools like: await client.call_tool("play_action", {"action": "look"})
|
| 18 |
+
|
| 19 |
+
Tips:
|
| 20 |
+
- Start by looking around and understanding your environment
|
| 21 |
+
- Keep track of visited locations to avoid loops
|
| 22 |
+
- Pick up useful items (lamp, sword, etc.)
|
| 23 |
+
- The seed parameter should be used to set your LLM's seed for reproducibility
|
| 24 |
+
"""
|
| 25 |
+
|
| 26 |
+
import json
|
| 27 |
+
import os
|
| 28 |
+
import re
|
| 29 |
+
from dataclasses import dataclass, field
|
| 30 |
+
from typing import Optional
|
| 31 |
+
|
| 32 |
+
from dotenv import load_dotenv
|
| 33 |
+
from huggingface_hub import InferenceClient
|
| 34 |
+
|
| 35 |
+
# Load environment variables
|
| 36 |
+
load_dotenv()
|
| 37 |
+
|
| 38 |
+
# =============================================================================
|
| 39 |
+
# LLM Configuration - DO NOT MODIFY
|
| 40 |
+
# =============================================================================
|
| 41 |
+
|
| 42 |
+
# Model to use (fixed for fair evaluation)
|
| 43 |
+
LLM_MODEL = "Qwen/Qwen2.5-72B-Instruct"
|
| 44 |
+
|
| 45 |
+
# Initialize the LLM client (uses HF_TOKEN from environment)
|
| 46 |
+
_hf_token = os.getenv("HF_TOKEN")
|
| 47 |
+
if not _hf_token:
|
| 48 |
+
raise ValueError("HF_TOKEN not found. Set it in your .env file.")
|
| 49 |
+
|
| 50 |
+
LLM_CLIENT = InferenceClient(token=_hf_token)
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
def call_llm(prompt: str, system_prompt: str, seed: int, max_tokens: int = 300) -> str:
|
| 54 |
+
"""
|
| 55 |
+
Call the LLM with the given prompt. Use this function in your agent.
|
| 56 |
+
|
| 57 |
+
Args:
|
| 58 |
+
prompt: The user prompt (current game state, history, etc.)
|
| 59 |
+
system_prompt: The system prompt (instructions for the agent)
|
| 60 |
+
seed: Random seed for reproducibility
|
| 61 |
+
max_tokens: Maximum tokens in response (default: 300)
|
| 62 |
+
|
| 63 |
+
Returns:
|
| 64 |
+
The LLM's response text
|
| 65 |
+
|
| 66 |
+
Example:
|
| 67 |
+
response = call_llm(
|
| 68 |
+
prompt="You are in a forest. What do you do?",
|
| 69 |
+
system_prompt=SYSTEM_PROMPT,
|
| 70 |
+
seed=42,
|
| 71 |
+
)
|
| 72 |
+
"""
|
| 73 |
+
messages = [
|
| 74 |
+
{"role": "system", "content": system_prompt},
|
| 75 |
+
{"role": "user", "content": prompt},
|
| 76 |
+
]
|
| 77 |
+
|
| 78 |
+
response = LLM_CLIENT.chat.completions.create(
|
| 79 |
+
model=LLM_MODEL,
|
| 80 |
+
messages=messages,
|
| 81 |
+
temperature=0.0, # Deterministic for reproducibility
|
| 82 |
+
max_tokens=max_tokens,
|
| 83 |
+
seed=seed,
|
| 84 |
+
)
|
| 85 |
+
|
| 86 |
+
return response.choices[0].message.content
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
@dataclass
|
| 90 |
+
class RunResult:
|
| 91 |
+
"""Result of running the agent. Do not modify this class."""
|
| 92 |
+
final_score: int
|
| 93 |
+
max_score: int
|
| 94 |
+
moves: int
|
| 95 |
+
locations_visited: set[str]
|
| 96 |
+
game_completed: bool
|
| 97 |
+
error: Optional[str] = None
|
| 98 |
+
history: list[tuple[str, str, str]] = field(default_factory=list)
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
# =============================================================================
|
| 102 |
+
# System Prompt - Customize this for your agent
|
| 103 |
+
# =============================================================================
|
| 104 |
+
|
| 105 |
+
SYSTEM_PROMPT = """You are a Hierarchical Agent Manager playing a text adventure game.
|
| 106 |
+
You orchestrate three internal experts to decide your next move.
|
| 107 |
+
|
| 108 |
+
INTERNAL PERSONAS:
|
| 109 |
+
1. Navigator: Proposes movement to explore new areas using 'get_map'.
|
| 110 |
+
2. Interaction Specialist: Focuses on items and puzzles using 'inventory' and 'get_valid_actions'.
|
| 111 |
+
3. Historian: Prevents loops and tracks story progress using 'get_historian_summary'.
|
| 112 |
+
|
| 113 |
+
GOAL: Explore the world, solve puzzles, and maximize your score.
|
| 114 |
+
|
| 115 |
+
STRICT FORMAT:
|
| 116 |
+
THOUGHT: <Internal dialogue between Navigator, Specialist, and Historian>
|
| 117 |
+
TOOL: <tool_name>
|
| 118 |
+
ARGS: <JSON arguments>
|
| 119 |
+
|
| 120 |
+
AVAILABLE TOOLS:
|
| 121 |
+
- play_action: {"action": "command"}
|
| 122 |
+
- inventory: {}
|
| 123 |
+
- get_map: {}
|
| 124 |
+
- get_historian_summary: {}
|
| 125 |
+
- get_valid_actions: {}
|
| 126 |
+
- get_room_context: {}
|
| 127 |
+
"""
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
# =============================================================================
|
| 131 |
+
# Student Agent - IMPLEMENT THIS CLASS
|
| 132 |
+
# =============================================================================
|
| 133 |
+
|
| 134 |
+
class StudentAgent:
|
| 135 |
+
"""
|
| 136 |
+
Your ReAct agent implementation.
|
| 137 |
+
|
| 138 |
+
TODO:
|
| 139 |
+
1. Implement the run() method with the ReAct loop
|
| 140 |
+
2. Parse LLM responses to extract tool calls
|
| 141 |
+
3. Track state and avoid loops
|
| 142 |
+
|
| 143 |
+
Use the provided call_llm() function to interact with the LLM.
|
| 144 |
+
"""
|
| 145 |
+
|
| 146 |
+
def __init__(self):
|
| 147 |
+
"""Initialize your agent here."""
|
| 148 |
+
# TODO: Initialize any state tracking you need
|
| 149 |
+
self.history = []
|
| 150 |
+
self.visited_locations = set()
|
| 151 |
+
self.score = 0
|
| 152 |
+
|
| 153 |
+
async def run(
|
| 154 |
+
self,
|
| 155 |
+
client, # FastMCP Client connected to your MCP server
|
| 156 |
+
game: str,
|
| 157 |
+
max_steps: int,
|
| 158 |
+
seed: int,
|
| 159 |
+
verbose: bool = False,
|
| 160 |
+
) -> RunResult:
|
| 161 |
+
"""
|
| 162 |
+
Run the agent for a game session.
|
| 163 |
+
|
| 164 |
+
Args:
|
| 165 |
+
client: FastMCP Client connected to your MCP server
|
| 166 |
+
game: Name of the game being played (e.g., "zork1")
|
| 167 |
+
max_steps: Maximum number of steps to take
|
| 168 |
+
seed: Random seed for reproducibility (use for LLM calls)
|
| 169 |
+
verbose: Whether to print detailed output
|
| 170 |
+
|
| 171 |
+
Returns:
|
| 172 |
+
RunResult with final score and statistics
|
| 173 |
+
"""
|
| 174 |
+
# TODO: Implement your ReAct loop here
|
| 175 |
+
#
|
| 176 |
+
# Basic structure:
|
| 177 |
+
# 1. Get initial observation (call play_action with "look")
|
| 178 |
+
initial_res = await client.call_tool("play_action", {"action": "look"})
|
| 179 |
+
observation = self._extract_result(initial_res)
|
| 180 |
+
self._track_location(observation)
|
| 181 |
+
|
| 182 |
+
moves = 0
|
| 183 |
+
|
| 184 |
+
# 2. Loop for max_steps:
|
| 185 |
+
for step in range(max_steps):
|
| 186 |
+
hist_res = await client.call_tool("get_historian_summary", {})
|
| 187 |
+
map_res = await client.call_tool("get_map", {})
|
| 188 |
+
valid_res = await client.call_tool("get_valid_actions", {})
|
| 189 |
+
context_res = await client.call_tool("get_room_context", {})
|
| 190 |
+
|
| 191 |
+
hist_obs = self._extract_result(hist_res)
|
| 192 |
+
map_obs = self._extract_result(map_res)
|
| 193 |
+
valid_obs = self._extract_result(valid_res)
|
| 194 |
+
context_obs = self._extract_result(context_res)
|
| 195 |
+
|
| 196 |
+
# a. Build prompt with current observation and history
|
| 197 |
+
prompt = self._build_prompt(observation, hist_obs, map_obs, valid_obs, context_obs)
|
| 198 |
+
|
| 199 |
+
# b. Call LLM to get thought and action
|
| 200 |
+
response = call_llm(prompt, SYSTEM_PROMPT, seed)
|
| 201 |
+
|
| 202 |
+
# c. Parse the response to extract tool and args
|
| 203 |
+
try:
|
| 204 |
+
thought, tool_name, args = self._parse_response(response)
|
| 205 |
+
except:
|
| 206 |
+
# Fallback if parsing fails
|
| 207 |
+
thought, tool_name, args = "Parsing error, looking around.", "play_action", {"action": "look"}
|
| 208 |
+
|
| 209 |
+
if verbose:
|
| 210 |
+
print(f"\n--- Step {step+1} ---")
|
| 211 |
+
print("THOUGHT:", thought)
|
| 212 |
+
print("TOOL:", tool_name)
|
| 213 |
+
print("ARGS:", args)
|
| 214 |
+
|
| 215 |
+
# d. Call the tool via client.call_tool(tool_name, args)
|
| 216 |
+
try:
|
| 217 |
+
result = await client.call_tool(tool_name, args)
|
| 218 |
+
observation = self._extract_result(result)
|
| 219 |
+
|
| 220 |
+
except Exception as e:
|
| 221 |
+
# If the tool crashes (e.g. bad JSON, validation error), we catch it so the game doesn't instantly die!
|
| 222 |
+
observation = f"System Error: {str(e)}. Please try a different basic command."
|
| 223 |
+
if verbose:
|
| 224 |
+
print(f"ERROR CAUGHT: {e}")
|
| 225 |
+
|
| 226 |
+
if verbose:
|
| 227 |
+
print("OBSERVATION:", observation)
|
| 228 |
+
|
| 229 |
+
# e. Update history and state
|
| 230 |
+
moves += 1
|
| 231 |
+
self.history.append((thought, f"{tool_name}: {args}", observation))
|
| 232 |
+
self._track_location(observation)
|
| 233 |
+
self._update_score(observation)
|
| 234 |
+
|
| 235 |
+
# f. Check for game over
|
| 236 |
+
if self._is_game_over(observation):
|
| 237 |
+
if verbose:
|
| 238 |
+
print("\n*** GAME OVER ***")
|
| 239 |
+
break
|
| 240 |
+
|
| 241 |
+
# 3. Return RunResult with final statistics
|
| 242 |
+
return RunResult(
|
| 243 |
+
final_score=self.score,
|
| 244 |
+
max_score=350, # Zork1 max score, adjust if needed
|
| 245 |
+
moves=moves,
|
| 246 |
+
locations_visited=self.visited_locations,
|
| 247 |
+
game_completed=False,
|
| 248 |
+
history=self.history,
|
| 249 |
+
)
|
| 250 |
+
|
| 251 |
+
def _build_prompt(self, observation: str, history: str, world_map: str, valid_actions: str, context: str) -> str:
|
| 252 |
+
"""
|
| 253 |
+
Build the prompt for the LLM.
|
| 254 |
+
|
| 255 |
+
"""
|
| 256 |
+
# TODO: Combine system prompt, history, and current observation
|
| 257 |
+
return f"""### CURRENT OBSERVATION
|
| 258 |
+
{observation}
|
| 259 |
+
|
| 260 |
+
### CURRENT LOCATION CONTEXT
|
| 261 |
+
{context}
|
| 262 |
+
|
| 263 |
+
### HISTORIAN MEMORY
|
| 264 |
+
{history}
|
| 265 |
+
|
| 266 |
+
### NAVIGATOR MAP
|
| 267 |
+
{world_map}
|
| 268 |
+
|
| 269 |
+
### SUGGESTED VALID ACTIONS
|
| 270 |
+
{valid_actions}
|
| 271 |
+
|
| 272 |
+
What is the best next step?"""
|
| 273 |
+
|
| 274 |
+
def _parse_response(self, response: str) -> tuple[str, str, dict]:
|
| 275 |
+
"""
|
| 276 |
+
Parse LLM response to extract thought, tool name, and arguments.
|
| 277 |
+
|
| 278 |
+
TODO: Implement robust parsing
|
| 279 |
+
|
| 280 |
+
Returns:
|
| 281 |
+
Tuple of (thought, tool_name, args_dict)
|
| 282 |
+
"""
|
| 283 |
+
# TODO: Parse the response format:
|
| 284 |
+
thought = re.search(r"THOUGHT:\s*(.*?)(?=TOOL:|$)", response, re.S).group(1).strip()
|
| 285 |
+
tool = re.search(r"TOOL:\s*(\w+)", response).group(1).strip()
|
| 286 |
+
args_str = re.search(r"ARGS:\s*(\{.*?\})", response, re.S).group(1).strip()
|
| 287 |
+
return thought, tool, json.loads(args_str)
|
| 288 |
+
|
| 289 |
+
def _call_llm(self, prompt: str, system_prompt: str, seed: int) -> str:
|
| 290 |
+
"""
|
| 291 |
+
Call the LLM with the given prompt.
|
| 292 |
+
|
| 293 |
+
This is a convenience wrapper - you can also use call_llm() directly.
|
| 294 |
+
"""
|
| 295 |
+
return call_llm(prompt, system_prompt, seed)
|
| 296 |
+
|
| 297 |
+
def _track_location(self, observation: str):
|
| 298 |
+
"""Extracts location name (usually the first line) to track movement."""
|
| 299 |
+
lines = [l.strip() for l in observation.split('\n') if l.strip()]
|
| 300 |
+
if lines:
|
| 301 |
+
room_candidate = lines[0]
|
| 302 |
+
if len(room_candidate) < 60 and not any(c in room_candidate for c in ".!?"):
|
| 303 |
+
self.visited_locations.add(room_candidate)
|
| 304 |
+
|
| 305 |
+
def _extract_result(self, result) -> str:
|
| 306 |
+
"""Extract text from MCP tool result."""
|
| 307 |
+
if hasattr(result, 'content') and result.content:
|
| 308 |
+
return result.content[0].text
|
| 309 |
+
if isinstance(result, list) and result:
|
| 310 |
+
return result[0].text if hasattr(result[0], 'text') else str(result[0])
|
| 311 |
+
return str(result)
|
| 312 |
+
|
| 313 |
+
def _update_score(self, text: str) -> None:
|
| 314 |
+
"""Update score from game text."""
|
| 315 |
+
patterns = [
|
| 316 |
+
r'Score:\s*(\d+)',
|
| 317 |
+
r'score[:\s]+(\d+)',
|
| 318 |
+
r'\[Score:\s*(\d+)',
|
| 319 |
+
]
|
| 320 |
+
|
| 321 |
+
for pattern in patterns:
|
| 322 |
+
match = re.search(pattern, text, re.IGNORECASE)
|
| 323 |
+
if match:
|
| 324 |
+
self.score = max(self.score, int(match.group(1)))
|
| 325 |
+
|
| 326 |
+
def _is_game_over(self, text: str) -> bool:
|
| 327 |
+
"""Check if the game is over."""
|
| 328 |
+
game_over_phrases = [
|
| 329 |
+
"game over",
|
| 330 |
+
"you have died",
|
| 331 |
+
"you are dead",
|
| 332 |
+
"*** you have died ***",
|
| 333 |
+
]
|
| 334 |
+
text_lower = text.lower()
|
| 335 |
+
return any(phrase in text_lower for phrase in game_over_phrases)
|
| 336 |
+
|
| 337 |
+
|
| 338 |
+
# =============================================================================
|
| 339 |
+
# For local testing
|
| 340 |
+
# =============================================================================
|
| 341 |
+
|
| 342 |
+
async def test_agent():
|
| 343 |
+
"""Test the agent locally."""
|
| 344 |
+
from fastmcp import Client
|
| 345 |
+
|
| 346 |
+
# Path to your MCP server
|
| 347 |
+
server_path = "mcp_server.py"
|
| 348 |
+
|
| 349 |
+
agent = StudentAgent()
|
| 350 |
+
|
| 351 |
+
async with Client(server_path) as client:
|
| 352 |
+
result = await agent.run(
|
| 353 |
+
client=client,
|
| 354 |
+
game="zork1",
|
| 355 |
+
max_steps=10,
|
| 356 |
+
seed=42,
|
| 357 |
+
verbose=True,
|
| 358 |
+
)
|
| 359 |
+
|
| 360 |
+
print(f"\nFinal Score: {result.final_score}")
|
| 361 |
+
print(f"Moves: {result.moves}")
|
| 362 |
+
print(f"Locations: {result.locations_visited}")
|
| 363 |
+
|
| 364 |
+
|
| 365 |
+
if __name__ == "__main__":
|
| 366 |
+
import asyncio
|
| 367 |
+
asyncio.run(test_agent())
|
mcp_server.py
ADDED
|
@@ -0,0 +1,348 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Student MCP Server for Text Adventure Games
|
| 3 |
+
|
| 4 |
+
This is your MCP server submission. Implement the tools that your agent
|
| 5 |
+
will use to play text adventure games.
|
| 6 |
+
|
| 7 |
+
Required tool:
|
| 8 |
+
play_action(action: str) -> str
|
| 9 |
+
Execute a game command and return the result.
|
| 10 |
+
|
| 11 |
+
Recommended tools:
|
| 12 |
+
memory() -> str
|
| 13 |
+
Return current game state, score, and recent history.
|
| 14 |
+
|
| 15 |
+
inventory() -> str
|
| 16 |
+
Return the player's current inventory.
|
| 17 |
+
|
| 18 |
+
get_map() -> str
|
| 19 |
+
Return a map of explored locations.
|
| 20 |
+
|
| 21 |
+
Test your server with:
|
| 22 |
+
fastmcp dev submission_template/mcp_server.py
|
| 23 |
+
|
| 24 |
+
Then open the MCP Inspector in your browser to test the tools interactively.
|
| 25 |
+
"""
|
| 26 |
+
|
| 27 |
+
import sys
|
| 28 |
+
import os
|
| 29 |
+
import json
|
| 30 |
+
|
| 31 |
+
# Add parent directory to path to import games module
|
| 32 |
+
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
| 33 |
+
|
| 34 |
+
from fastmcp import FastMCP
|
| 35 |
+
from games.zork_env import TextAdventureEnv
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
# =============================================================================
|
| 39 |
+
# Create the MCP Server
|
| 40 |
+
# =============================================================================
|
| 41 |
+
|
| 42 |
+
mcp = FastMCP("Student Text Adventure Server")
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
# =============================================================================
|
| 46 |
+
# Game State Management
|
| 47 |
+
# =============================================================================
|
| 48 |
+
|
| 49 |
+
class GameManager:
|
| 50 |
+
"""
|
| 51 |
+
Manages the text adventure game state.
|
| 52 |
+
|
| 53 |
+
TODO: Extend this class to track:
|
| 54 |
+
- Action history (for memory tool)
|
| 55 |
+
- Explored locations (for mapping)
|
| 56 |
+
- Current score and moves
|
| 57 |
+
"""
|
| 58 |
+
|
| 59 |
+
def __init__(self):
|
| 60 |
+
self.env: TextAdventureEnv = None
|
| 61 |
+
self.state = None
|
| 62 |
+
self.game_name: str = ""
|
| 63 |
+
# TODO: Add more state tracking
|
| 64 |
+
# self.history: list[tuple[str, str]] = []
|
| 65 |
+
# self.explored_locations: dict[str, set[str]] = {}
|
| 66 |
+
# self.current_location: str = ""
|
| 67 |
+
self.full_history: list[dict] = []
|
| 68 |
+
# Topological Map: { "Room Name": {"north": "Other Room", "south": "..."} }
|
| 69 |
+
self.world_map = {}
|
| 70 |
+
self.current_location = "Unknown"
|
| 71 |
+
self.came_from = None
|
| 72 |
+
self.room_attempts = {}
|
| 73 |
+
|
| 74 |
+
def initialize(self, game: str = "zork1"):
|
| 75 |
+
"""Initialize or reset the game."""
|
| 76 |
+
self.game_name = game
|
| 77 |
+
self.env = TextAdventureEnv(game)
|
| 78 |
+
self.state = self.env.reset()
|
| 79 |
+
# TODO: Reset your state tracking here
|
| 80 |
+
self.current_location = self._extract_room(self.state.observation)
|
| 81 |
+
self.full_history = [{"action": "start", "observation": self.state.observation}]
|
| 82 |
+
return self.state.observation
|
| 83 |
+
|
| 84 |
+
def _extract_room(self, observation: str) -> str:
|
| 85 |
+
"""Extract the name of the room."""
|
| 86 |
+
# Option A : Get via Jericho (more precise)
|
| 87 |
+
if self.env and self.env.env:
|
| 88 |
+
try:
|
| 89 |
+
loc = self.env.env.get_player_location()
|
| 90 |
+
if hasattr(loc, 'num') and loc.num:
|
| 91 |
+
return f"{loc.name}_{loc.num}"
|
| 92 |
+
else:
|
| 93 |
+
return loc.name
|
| 94 |
+
except:
|
| 95 |
+
pass
|
| 96 |
+
|
| 97 |
+
# Option B : Fallback on observation parsing (personal observation: keep the first line without punctuation)
|
| 98 |
+
lines = [l.strip() for l in observation.split('\n') if l.strip()]
|
| 99 |
+
if lines:
|
| 100 |
+
candidate = lines[0]
|
| 101 |
+
if len(candidate) < 50 and not candidate.endswith(('.', '!', '?')):
|
| 102 |
+
return candidate
|
| 103 |
+
|
| 104 |
+
return "Unknown"
|
| 105 |
+
|
| 106 |
+
def step(self, action: str) -> str:
|
| 107 |
+
"""Execute an action and return the result."""
|
| 108 |
+
if self.env is None:
|
| 109 |
+
self.initialize()
|
| 110 |
+
|
| 111 |
+
prev_location = self.current_location
|
| 112 |
+
|
| 113 |
+
if prev_location not in self.room_attempts:
|
| 114 |
+
self.room_attempts[prev_location] = []
|
| 115 |
+
if action not in self.room_attempts[prev_location]:
|
| 116 |
+
self.room_attempts[prev_location].append(action)
|
| 117 |
+
|
| 118 |
+
self.state = self.env.step(action)
|
| 119 |
+
self.current_location = self._extract_room(self.state.observation)
|
| 120 |
+
|
| 121 |
+
# TODO: Update your state tracking here
|
| 122 |
+
# self.history.append((action, self.state.observation))
|
| 123 |
+
# Update location tracking, etc.
|
| 124 |
+
if self.current_location != prev_location:
|
| 125 |
+
opposites = {
|
| 126 |
+
"north": "south", "south": "north", "east": "west", "west": "east",
|
| 127 |
+
"nw": "se", "se": "nw", "ne": "sw", "sw": "ne",
|
| 128 |
+
"up": "down", "down": "up",
|
| 129 |
+
"northwest": "southeast", "southeast": "northwest",
|
| 130 |
+
"northeast": "southwest", "southwest": "northeast"
|
| 131 |
+
}
|
| 132 |
+
clean_action = action.lower().strip()
|
| 133 |
+
if clean_action in opposites:
|
| 134 |
+
self.came_from = opposites[clean_action]
|
| 135 |
+
else:
|
| 136 |
+
self.came_from = None
|
| 137 |
+
|
| 138 |
+
self.full_history.append({"action": action, "observation": self.state.observation})
|
| 139 |
+
|
| 140 |
+
return self.state.observation
|
| 141 |
+
|
| 142 |
+
def get_score(self) -> int:
|
| 143 |
+
"""Get current score."""
|
| 144 |
+
return self.state.score if self.state else 0
|
| 145 |
+
|
| 146 |
+
def get_moves(self) -> int:
|
| 147 |
+
"""Get number of moves taken."""
|
| 148 |
+
return self.state.moves if self.state else 0
|
| 149 |
+
|
| 150 |
+
|
| 151 |
+
# Global game manager
|
| 152 |
+
_game = GameManager()
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
def get_game() -> GameManager:
|
| 156 |
+
"""Get or initialize the game manager."""
|
| 157 |
+
global _game
|
| 158 |
+
if _game.env is None:
|
| 159 |
+
# Get game from environment variable (set by evaluator)
|
| 160 |
+
game = os.environ.get("GAME", "zork1")
|
| 161 |
+
_game.initialize(game)
|
| 162 |
+
return _game
|
| 163 |
+
|
| 164 |
+
|
| 165 |
+
# =============================================================================
|
| 166 |
+
# MCP Tools - IMPLEMENT THESE
|
| 167 |
+
# =============================================================================
|
| 168 |
+
|
| 169 |
+
@mcp.tool()
|
| 170 |
+
def play_action(action: str) -> str:
|
| 171 |
+
"""
|
| 172 |
+
Execute a game command and return the result.
|
| 173 |
+
|
| 174 |
+
This is the main tool for interacting with the game.
|
| 175 |
+
|
| 176 |
+
Args:
|
| 177 |
+
action: The command to execute (e.g., "north", "take lamp", "open mailbox")
|
| 178 |
+
|
| 179 |
+
Returns:
|
| 180 |
+
The game's response to the action
|
| 181 |
+
|
| 182 |
+
Valid commands include:
|
| 183 |
+
- Movement: north, south, east, west, northeast, southeast, northwest, southwest, up, down, enter, exit
|
| 184 |
+
- Objects: take <item>, drop <item>, open <thing>, examine <thing>
|
| 185 |
+
- Other: look, inventory, read <thing>, turn on lamp, listen
|
| 186 |
+
"""
|
| 187 |
+
game = get_game()
|
| 188 |
+
|
| 189 |
+
# TODO: You might want to add action validation here
|
| 190 |
+
# TODO: You might want to include score changes in the response
|
| 191 |
+
|
| 192 |
+
result = game.step(action)
|
| 193 |
+
|
| 194 |
+
# Optional: Append score info
|
| 195 |
+
result += f"\n[Score: {game.get_score()} | Moves: {game.get_moves()}]"
|
| 196 |
+
|
| 197 |
+
return result
|
| 198 |
+
|
| 199 |
+
|
| 200 |
+
# TODO: Implement additional tools to help your agent
|
| 201 |
+
|
| 202 |
+
# @mcp.tool()
|
| 203 |
+
# def memory() -> str:
|
| 204 |
+
# """
|
| 205 |
+
# Get the current game state summary.
|
| 206 |
+
#
|
| 207 |
+
# Returns:
|
| 208 |
+
# A summary including current location, score, moves, and recent history
|
| 209 |
+
# """
|
| 210 |
+
# game = get_game()
|
| 211 |
+
# # TODO: Return useful state information
|
| 212 |
+
# pass
|
| 213 |
+
|
| 214 |
+
|
| 215 |
+
@mcp.tool()
|
| 216 |
+
def inventory() -> str:
|
| 217 |
+
"""
|
| 218 |
+
Check what the player is carrying.
|
| 219 |
+
|
| 220 |
+
Returns:
|
| 221 |
+
List of items in the player's inventory
|
| 222 |
+
"""
|
| 223 |
+
game = get_game()
|
| 224 |
+
result = game.step("inventory")
|
| 225 |
+
return result
|
| 226 |
+
|
| 227 |
+
|
| 228 |
+
@mcp.tool()
|
| 229 |
+
def get_map() -> str:
|
| 230 |
+
"""
|
| 231 |
+
Get a map of explored locations.
|
| 232 |
+
|
| 233 |
+
Returns:
|
| 234 |
+
A formatted string showing connections from explored rooms to adjacent locations or "Map is empty" message.
|
| 235 |
+
"""
|
| 236 |
+
game = get_game()
|
| 237 |
+
# TODO: Return map of explored locations
|
| 238 |
+
if not game.world_map:
|
| 239 |
+
return "Map is empty. Start moving to explore!"
|
| 240 |
+
|
| 241 |
+
output = "CURRENT MAP CONNECTIONS:\n"
|
| 242 |
+
for room, exits in game.world_map.items():
|
| 243 |
+
exit_str = ", ".join([f"{direction}->{dest}" for direction, dest in exits.items()])
|
| 244 |
+
output += f"- {room}: {exit_str}\n"
|
| 245 |
+
return output
|
| 246 |
+
|
| 247 |
+
@mcp.tool()
|
| 248 |
+
def get_historian_summary() -> str:
|
| 249 |
+
"""
|
| 250 |
+
Acts as the Historian agent's memory. Returns current score,
|
| 251 |
+
moves, and a summary of the last 5 actions to maintain context.
|
| 252 |
+
|
| 253 |
+
Returns:
|
| 254 |
+
Log containing the last 5 actions, their observations,
|
| 255 |
+
and the current score and move count.
|
| 256 |
+
"""
|
| 257 |
+
game = get_game()
|
| 258 |
+
recent = game.full_history
|
| 259 |
+
summary = "HISTORIAN LOG:\n"
|
| 260 |
+
for n, entry in enumerate(recent):
|
| 261 |
+
summary += f"- Action {n}: {entry['action']} -> {entry['observation']}"
|
| 262 |
+
return f"{summary}"
|
| 263 |
+
|
| 264 |
+
@mcp.tool()
|
| 265 |
+
def get_valid_actions() -> str:
|
| 266 |
+
"""
|
| 267 |
+
Get a list of likely valid actions from the current location.
|
| 268 |
+
|
| 269 |
+
Returns:
|
| 270 |
+
List of actions that might work here
|
| 271 |
+
"""
|
| 272 |
+
# This is a hint: Jericho provides get_valid_actions()
|
| 273 |
+
game = get_game()
|
| 274 |
+
if game.env and game.env.env:
|
| 275 |
+
valid = game.env.env.get_valid_actions(
|
| 276 |
+
use_object_tree = True,
|
| 277 |
+
use_ctypes = True,
|
| 278 |
+
use_parallel = False
|
| 279 |
+
)
|
| 280 |
+
if valid and len(valid) > 0:
|
| 281 |
+
# result = json.dumps({
|
| 282 |
+
# "available": True,
|
| 283 |
+
# "actions": valid
|
| 284 |
+
# })
|
| 285 |
+
result = "Valid actions: " + ", ".join(valid)
|
| 286 |
+
return result
|
| 287 |
+
# result = json.dumps({
|
| 288 |
+
# "available": False,
|
| 289 |
+
# "actions": []
|
| 290 |
+
# })
|
| 291 |
+
result = "No obvious actions found."
|
| 292 |
+
return result
|
| 293 |
+
|
| 294 |
+
@mcp.tool()
|
| 295 |
+
def get_room_context() -> str:
|
| 296 |
+
"""
|
| 297 |
+
Returns a summary of the current room, including:
|
| 298 |
+
1. Room Name & Description
|
| 299 |
+
2. Guaranteed Valid Actions (so you don't guess)
|
| 300 |
+
3. Actions you already tried in this specific room (so you don't loop)
|
| 301 |
+
"""
|
| 302 |
+
game = get_game()
|
| 303 |
+
|
| 304 |
+
valid_actions = []
|
| 305 |
+
if game.env and game.env.env:
|
| 306 |
+
try:
|
| 307 |
+
valid_actions = game.env.env.get_valid_actions(
|
| 308 |
+
use_object_tree = True,
|
| 309 |
+
use_ctypes = True,
|
| 310 |
+
use_parallel = False
|
| 311 |
+
)
|
| 312 |
+
except:
|
| 313 |
+
pass
|
| 314 |
+
|
| 315 |
+
current_room_name = game.current_location
|
| 316 |
+
past_attempts = game.room_attempts.get(current_room_name, [])
|
| 317 |
+
|
| 318 |
+
# Small models read bullet points much better than JSON
|
| 319 |
+
output = []
|
| 320 |
+
|
| 321 |
+
output.append(f"Location: {current_room_name}")
|
| 322 |
+
|
| 323 |
+
if valid_actions:
|
| 324 |
+
# Only show top 15 to save tokens
|
| 325 |
+
actions_str = ", ".join(valid_actions)
|
| 326 |
+
output.append(f"VALID ACTIONS: {actions_str}")
|
| 327 |
+
else:
|
| 328 |
+
output.append("VALID ACTIONS: Try basic directions (north, south, east, west) or 'look'.")
|
| 329 |
+
|
| 330 |
+
if past_attempts:
|
| 331 |
+
attempts_str = ", ".join(past_attempts) # Last 10 attempts
|
| 332 |
+
output.append(f"ALREADY TRIED HERE: {attempts_str}")
|
| 333 |
+
else:
|
| 334 |
+
output.append("ALREADY TRIED HERE: New room, nothing tried yet.")
|
| 335 |
+
|
| 336 |
+
if game.came_from:
|
| 337 |
+
output.append(f"WARNING: You entered from the {game.came_from}. Avoid going '{game.came_from}', unless you ar stuck.")
|
| 338 |
+
|
| 339 |
+
return "\n".join(output)
|
| 340 |
+
|
| 341 |
+
|
| 342 |
+
# =============================================================================
|
| 343 |
+
# Run the server
|
| 344 |
+
# =============================================================================
|
| 345 |
+
|
| 346 |
+
if __name__ == "__main__":
|
| 347 |
+
# This runs the server with stdio transport (for MCP clients)
|
| 348 |
+
mcp.run()
|
results_Qwen2.5-72B-Instruct_lostpig
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
(Agentic-zork) ocebo@WIN-D52PPDAKV0F:/mnt/c/Users/ocebo/Documents/ENS - MVA/S2/LLMs/TP/TP3/Agentic-zork$ python run_agent.py --agent multi-agent --game lostpig -v -n 20
|
| 2 |
+
|
| 3 |
+
============================================================
|
| 4 |
+
Text Adventure MCP Agent Runner
|
| 5 |
+
============================================================
|
| 6 |
+
Agent: multi-agent/
|
| 7 |
+
Game: lostpig
|
| 8 |
+
Max Steps: 20
|
| 9 |
+
Verbose: True
|
| 10 |
+
|
| 11 |
+
[MCP] Running Student Agent with FastMCP
|
| 12 |
+
Agent: multi-agent/
|
| 13 |
+
Game: lostpig
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
| 18 |
+
│ │
|
| 19 |
+
│ │
|
| 20 |
+
│ ▄▀▀ ▄▀█ █▀▀ ▀█▀ █▀▄▀█ █▀▀ █▀█ │
|
| 21 |
+
│ █▀ █▀█ ▄▄█ █ █ ▀ █ █▄▄ █▀▀ │
|
| 22 |
+
│ │
|
| 23 |
+
│ │
|
| 24 |
+
│ FastMCP 3.0.1 │
|
| 25 |
+
│ https://gofastmcp.com │
|
| 26 |
+
│ │
|
| 27 |
+
│ 🖥 Server: Student Text Adventure Server, 3.0.1 │
|
| 28 |
+
│ 🚀 Deploy free: https://fastmcp.cloud │
|
| 29 |
+
│ │
|
| 30 |
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
[02/22/26 20:59:49] INFO Starting MCP server 'Student Text Adventure Server' with transport 'stdio' transport.py:183
|
| 34 |
+
|
| 35 |
+
--- Step 1 ---
|
| 36 |
+
THOUGHT: The Navigator suggests moving into the forest to the east or north to explore new areas. However, the Historian notes that we should be cautious of the darkness and strange animals. The Interaction Specialist thinks we should try to interact with the environment here before moving on, such as looking for an animal or examining the wall.
|
| 37 |
+
|
| 38 |
+
Given the current context, it seems prudent to first check if there are any animals around that might give us a clue about the pig's whereabouts. If nothing useful is found, we can then consider moving into the forest.
|
| 39 |
+
TOOL: play_action
|
| 40 |
+
ARGS: {'action': 'look for animal'}
|
| 41 |
+
OBSERVATION: Grunk look all around for any thing that moving or hiding.
|
| 42 |
+
|
| 43 |
+
Grunk hear noise! It come from some place in bushes, but Grunk not sure which way it come from.
|
| 44 |
+
[Score: 0 | Moves: 2]
|
| 45 |
+
|
| 46 |
+
--- Step 2 ---
|
| 47 |
+
THOUGHT: The noise heard by Grunk could be the pig or another animal. We should investigate the source of the noise. However, we need to be cautious and ensure we have a clear understanding of our surroundings and available actions.
|
| 48 |
+
TOOL: get_valid_actions
|
| 49 |
+
ARGS: {}
|
| 50 |
+
OBSERVATION: Valid actions: look for animal, put fire across animal, put fire across wall, eat pants, get in wall, put fire out in pants
|
| 51 |
+
|
| 52 |
+
--- Step 3 ---
|
| 53 |
+
THOUGHT: The Navigator suggests exploring the forest to the east or north since it's a likely place where the pig might have gone. However, the Historian notes that we should be cautious not to repeat actions and that we haven't tried any of the suggested valid actions yet. The Interaction Specialist thinks we should investigate the noise Grunk heard, which might lead us to the pig.
|
| 54 |
+
TOOL: play_action
|
| 55 |
+
ARGS: {'action': 'look for animal'}
|
| 56 |
+
OBSERVATION: Grunk look all around for any thing that moving or hiding.
|
| 57 |
+
|
| 58 |
+
There, hear noise again! It come from northeast. Must be pig, hiding in bushes.
|
| 59 |
+
|
| 60 |
+
[Grunk score go up one.]
|
| 61 |
+
[Score: 1 | Moves: 3]
|
| 62 |
+
|
| 63 |
+
--- Step 4 ---
|
| 64 |
+
THOUGHT: The Navigator suggests moving northeast since the pig's noise was heard coming from that direction. The Interaction Specialist notes that we should avoid actions like eating pants or putting fire out in pants, as they don't seem relevant to finding the pig. The Historian agrees that moving northeast is the logical next step, as it aligns with the goal of finding the pig and no other actions have been tried in this location yet.
|
| 65 |
+
TOOL: play_action
|
| 66 |
+
ARGS: {'action': 'northeast'}
|
| 67 |
+
OBSERVATION: If that where pig go, that where Grunk go. It hard to see where Grunk going to, because there so much dark and leaves and branches here. Then suddenly, there not ground here any more!
|
| 68 |
+
|
| 69 |
+
Oof! Ow! Umf! Ugh!
|
| 70 |
+
|
| 71 |
+
Grunk fall down deep hole! Drop torch. Torch go out when Grunk land on it, so now it dark, too.
|
| 72 |
+
|
| 73 |
+
Hole
|
| 74 |
+
Grunk at bottom of deep, dark hole. It even smell like deep, dark hole. There some light that come from tunnel to east; that how Grunk see where Grunk at. Look like there maybe stairs at west side of hole that go up to outside, but them all broken now. There big crack in ground near stairs, too.
|
| 75 |
+
|
| 76 |
+
Grunk see torch (black and sooty) here.
|
| 77 |
+
[Score: 1 | Moves: 4]
|
| 78 |
+
|
| 79 |
+
--- Step 5 ---
|
| 80 |
+
THOUGHT: The Navigator suggests we should try to move east since there's some light coming from that direction. However, the Historian notes that we should first ensure we have a source of light, as the area is described as being very dark. The Interaction Specialist points out that the torch is nearby and can be taken, which would be useful for exploring further.
|
| 81 |
+
TOOL: play_action
|
| 82 |
+
ARGS: {'action': 'take torch'}
|
| 83 |
+
OBSERVATION: OK, got it.
|
| 84 |
+
[Score: 1 | Moves: 5]
|
| 85 |
+
|
| 86 |
+
--- Step 6 ---
|
| 87 |
+
THOUGHT: The Navigator suggests moving east since there's some light coming from that direction, which could help Grunk see better. The Interaction Specialist thinks we should try to use the torch to illuminate the area further, possibly by placing it across the crack or the light source. The Historian notes that we haven't tried any of these actions yet, so it's safe to proceed without risking a loop.
|
| 88 |
+
TOOL: play_action
|
| 89 |
+
ARGS: {'action': 'east'}
|
| 90 |
+
OBSERVATION:
|
| 91 |
+
Fountain Room
|
| 92 |
+
All wall in this room glow! It bright, just like day time. Except that instead of sun, it wall that glow. And instead of grass and tree, it square room with four wall. And instead of outside, it all under ground. But beside those thing, it just like it! Tunnel keep going out to east and west, but normal doorway go north and southeast and southwest.
|
| 93 |
+
|
| 94 |
+
In middle of room, there fountain. But fountain not have any water.
|
| 95 |
+
|
| 96 |
+
South wall have big curtain hanging on it.
|
| 97 |
+
|
| 98 |
+
Hey! There pig! It good thing that Grunk fall down same hole as pig.
|
| 99 |
+
[Score: 1 | Moves: 6]
|
| 100 |
+
|
| 101 |
+
--- Step 7 ---
|
| 102 |
+
THOUGHT: The Navigator suggests exploring the exits to find more areas, but the Historian reminds us that we should interact with the pig first since it's a key part of our quest. The Interaction Specialist agrees and points out that we can try to communicate with the pig or examine the fountain for clues.
|
| 103 |
+
TOOL: play_action
|
| 104 |
+
ARGS: {'action': 'talk piglish'}
|
| 105 |
+
OBSERVATION: Pig stare at Grunk like Grunk crazy.
|
| 106 |
+
|
| 107 |
+
[Grunk can try TELL PIG ABOUT FOUNTAIN or SHOW PANTS TO PIG or OINK AT PIG. And that just what Grunk think of. There probably lots of other thing Grunk can talk about too.]
|
| 108 |
+
[Score: 1 | Moves: 7]
|
| 109 |
+
|
| 110 |
+
--- Step 8 ---
|
| 111 |
+
THOUGHT: The pig seems unresponsive to talking in Piglish. We should try a different approach to interact with the pig. Perhaps showing it something or telling it about something might work better. Let's try showing the pig the coin, as it might be interested in shiny objects.
|
| 112 |
+
TOOL: play_action
|
| 113 |
+
ARGS: {'action': 'SHOW PIG COIN'}
|
| 114 |
+
OBSERVATION: (Grunk take coin first)
|
| 115 |
+
|
| 116 |
+
[Grunk score go up one.]
|
| 117 |
+
Pig walk toward Grunk and sniffle. Then it paw at ground. Then cough.
|
| 118 |
+
|
| 119 |
+
[Grunk can try TELL PIG ABOUT FOUNTAIN or SHOW PANTS TO PIG or OINK AT PIG. And probably lots of other thing too.]
|
| 120 |
+
[Score: 2 | Moves: 8]
|
| 121 |
+
|
| 122 |
+
--- Step 9 ---
|
| 123 |
+
THOUGHT: The Navigator suggests exploring the tunnels to the east or west, but the Historian notes that we've already tried moving west, which would take us back to the hole. The Interaction Specialist thinks it might be useful to interact with the pig further to potentially learn more or get it to follow us. Since the pig seems interested in the coin, perhaps showing it something else might elicit a different reaction.
|
| 124 |
+
TOOL: play_action
|
| 125 |
+
ARGS: {'action': 'SHOW PANTS TO PIG'}
|
| 126 |
+
OBSERVATION: Pig snarl and look at ground.
|
| 127 |
+
|
| 128 |
+
[Grunk can try TELL PIG ABOUT FOUNTAIN or ASK PIG ABOUT CAVE or OINK AT PIG. And probably lots of other thing too.]
|
| 129 |
+
[Score: 2 | Moves: 9]
|
| 130 |
+
|
| 131 |
+
--- Step 10 ---
|
| 132 |
+
THOUGHT: The pig seems uninterested in the pants and has already reacted to the coin. We should try to engage the pig with different actions. Let's try talking to the pig about the cave, as it might be curious about its surroundings.
|
| 133 |
+
TOOL: play_action
|
| 134 |
+
ARGS: {'action': 'ASK PIG ABOUT CAVE'}
|
| 135 |
+
OBSERVATION: Pig oink and sniffle.
|
| 136 |
+
|
| 137 |
+
[Grunk can try TELL PIG ABOUT FOUNTAIN or TELL PIG ABOUT GATE or OINK AT PIG. And probably lots of other thing too.]
|
| 138 |
+
[Score: 2 | Moves: 10]
|
| 139 |
+
|
| 140 |
+
--- Step 11 ---
|
| 141 |
+
THOUGHT: The Navigator suggests exploring further to find more clues or items that might help with the pig. The Interaction Specialist thinks we should interact more with the pig, trying different commands to see if we can influence its behavior. The Historian notes that we've already tried showing the pig the coin and pants, and talking piglish, so we should avoid repeating these actions unless necessary.
|
| 142 |
+
TOOL: play_action
|
| 143 |
+
ARGS: {'action': 'TELL PIG ABOUT FOUNTAIN'}
|
| 144 |
+
OBSERVATION: Pig turn away and make funny noise.
|
| 145 |
+
|
| 146 |
+
[Grunk can try TELL PIG ABOUT GATE or ASK PIG ABOUT CAVE or OINK AT PIG. And probably lots of other thing too.]
|
| 147 |
+
[Score: 2 | Moves: 11]
|
| 148 |
+
|
| 149 |
+
--- Step 12 ---
|
| 150 |
+
THOUGHT: The Pig seems uninterested in the Fountain and has made a funny noise. We should try a different approach. Perhaps we can use the coin or another item to attract the Pig's attention. Let's check our inventory to see what we have.
|
| 151 |
+
TOOL: inventory
|
| 152 |
+
ARGS: {}
|
| 153 |
+
OBSERVATION: Grunk have:
|
| 154 |
+
coin
|
| 155 |
+
torch (black and sooty)
|
| 156 |
+
pants (Grunk wearing them)
|
| 157 |
+
|
| 158 |
+
--- Step 13 ---
|
| 159 |
+
THOUGHT: The Navigator suggests exploring further into the tunnels to discover new areas, while the Interaction Specialist thinks we should interact with the pig or the environment to uncover potential clues or items. The Historian reminds us that we've already tried talking to the pig about various topics and showing it items, so we might want to avoid repeating these actions unless necessary. Let's start by checking the map to understand our surroundings better.
|
| 160 |
+
TOOL: get_map
|
| 161 |
+
ARGS: {}
|
| 162 |
+
OBSERVATION: Map is empty. Start moving to explore!
|
| 163 |
+
|
| 164 |
+
--- Step 14 ---
|
| 165 |
+
THOUGHT: The Navigator suggests exploring further to the east or west since the map is still empty and we need to discover more areas. However, the Interaction Specialist notes that there are several items and interactions available, such as the curtain and the fountain, which might be important. The Historian reminds us that we've already tried talking to the pig about various topics without much success, so we should focus on other actions.
|
| 166 |
+
TOOL: get_valid_actions
|
| 167 |
+
ARGS: {}
|
| 168 |
+
OBSERVATION: Valid actions: talk piglish, topics, eat pants, take pig, east, west, get in southwest, put torch across pants, put torch across curtain, put torch across wall, put torch across east, put torch across middle, put torch across west, put torch across coin, put all on pig, north, southeast
|
| 169 |
+
|
| 170 |
+
--- Step 15 ---
|
| 171 |
+
THOUGHT: The Navigator suggests exploring the tunnels further since we haven't fully mapped the area yet. The Interaction Specialist thinks we should try interacting with the pig again, as it seems to be responsive to certain actions. The Historian notes that we've already tried talking about the cave and the fountain, so we might want to try something different.
|
| 172 |
+
TOOL: get_valid_actions
|
| 173 |
+
ARGS: {}
|
| 174 |
+
OBSERVATION: Valid actions: talk piglish, topics, eat pants, take pig, east, west, get in southwest, put torch across pants, put torch across curtain, put torch across wall, put torch across east, put torch across middle, put torch across west, put torch across coin, put all on pig, north, southeast
|
| 175 |
+
|
| 176 |
+
--- Step 16 ---
|
| 177 |
+
THOUGHT: The Historian notes that we've already tried talking to the pig in various ways without much success. The Navigator suggests exploring further into the tunnels, while the Interaction Specialist thinks we should try interacting with the curtain or the fountain. Given that we haven't explored the tunnels yet, let's move east to see what's there.
|
| 178 |
+
TOOL: play_action
|
| 179 |
+
ARGS: {'action': 'east'}
|
| 180 |
+
OBSERVATION:
|
| 181 |
+
Cave With Stream
|
| 182 |
+
Tunnel come to little cave here, but wide stream block way east. Grunk not see much on other side. Not know if tunnel keep going or stop here. Only light that Grunk see come from bright room, far off to west. But Grunk hear lots of water.
|
| 183 |
+
|
| 184 |
+
There stone bench next to stream.
|
| 185 |
+
|
| 186 |
+
Seeing over there not easy in dark, but Grunk think there little reddish thing on other side of stream.
|
| 187 |
+
[Score: 2 | Moves: 13]
|
| 188 |
+
|
| 189 |
+
--- Step 17 ---
|
| 190 |
+
THOUGHT: The stream blocks the way east, and the only light comes from the west. We should try to cross the stream to explore further. The stone bench could be used to create a makeshift bridge. However, we need to ensure we don't lose any important items in the process.
|
| 191 |
+
|
| 192 |
+
Navigator: We should try to use the stone bench to cross the stream. It might serve as a bridge.
|
| 193 |
+
Specialist: We should check if the bench is stable enough to support Grunk's weight. We can also try to use the torch to light up the area better.
|
| 194 |
+
Historian: We haven't tried using the bench yet, so this is a new action. Let's proceed carefully to avoid losing any items.
|
| 195 |
+
TOOL: play_action
|
| 196 |
+
ARGS: {'action': 'push bench with torch'}
|
| 197 |
+
OBSERVATION: Grunk rub torch all over bench. Now bench all black and sooty too.
|
| 198 |
+
[Score: 2 | Moves: 14]
|
| 199 |
+
|
| 200 |
+
--- Step 18 ---
|
| 201 |
+
THOUGHT: The Navigator suggests trying to cross the stream to explore further, while the Interaction Specialist thinks we should examine the cave and interact with the objects around us. The Historian reminds us that we haven't tried putting the pants across the stream yet, which might help us cross.
|
| 202 |
+
TOOL: play_action
|
| 203 |
+
ARGS: {'action': 'put pants across stream'}
|
| 204 |
+
OBSERVATION: (Grunk take pants off first)
|
| 205 |
+
Grunk stick pants in water. Then Grunk take pants back and look at them. Pants all wet!
|
| 206 |
+
[Score: 2 | Moves: 15]
|
| 207 |
+
|
| 208 |
+
--- Step 19 ---
|
| 209 |
+
THOUGHT: The Navigator suggests exploring further by crossing the stream, possibly using the bench as a makeshift bridge. The Interaction Specialist thinks we should try using the torch to light up the area more before attempting to cross. The Historian notes that we've already tried putting the pants across the stream and pushing the bench with the torch, so we should avoid repeating these actions.
|
| 210 |
+
TOOL: play_action
|
| 211 |
+
ARGS: {'action': 'put torch across light'}
|
| 212 |
+
OBSERVATION: Grunk rub torch all over tunnel. Now tunnel all black and sooty too.
|
| 213 |
+
[Score: 2 | Moves: 16]
|
| 214 |
+
|
| 215 |
+
--- Step 20 ---
|
| 216 |
+
THOUGHT: The Navigator suggests exploring further by crossing the stream, but we need a way to do that. The Interaction Specialist thinks we should try to use the bench as a bridge. The Historian reminds us that we've already tried pushing the bench with the torch and putting the pants across the stream, so we should try something different.
|
| 217 |
+
TOOL: play_action
|
| 218 |
+
ARGS: {'action': 'put bench across stream'}
|
| 219 |
+
OBSERVATION: (Grunk take bench first)
|
| 220 |
+
Gurrnngh! Bench too heavy for Grunk.
|
| 221 |
+
[Score: 2 | Moves: 17]
|
| 222 |
+
|
| 223 |
+
============================================================
|
| 224 |
+
FINAL RESULTS
|
| 225 |
+
============================================================
|
| 226 |
+
Final Score: 2
|
| 227 |
+
Steps: 20
|
| 228 |
+
Moves: 17
|
| 229 |
+
Locations Visited: 7
|
| 230 |
+
Game Completed: False
|
results_Qwen2.5-7B-Instruct_lostpig
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
(Agentic-zork) ocebo@WIN-D52PPDAKV0F:/mnt/c/Users/ocebo/Documents/ENS - MVA/S2/LLMs/TP/TP3/Agentic-zork$ python run_agent.py --agent multi-agent --game lostpig -v -n 20
|
| 2 |
+
|
| 3 |
+
============================================================
|
| 4 |
+
Text Adventure MCP Agent Runner
|
| 5 |
+
============================================================
|
| 6 |
+
Agent: multi-agent/
|
| 7 |
+
Game: lostpig
|
| 8 |
+
Max Steps: 20
|
| 9 |
+
Verbose: True
|
| 10 |
+
|
| 11 |
+
[MCP] Running Student Agent with FastMCP
|
| 12 |
+
Agent: multi-agent/
|
| 13 |
+
Game: lostpig
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
|
| 17 |
+
╭──────────────────────────────────────────────────────────────────────────────╮
|
| 18 |
+
│ │
|
| 19 |
+
│ │
|
| 20 |
+
│ ▄▀▀ ▄▀█ █▀▀ ▀█▀ █▀▄▀█ █▀▀ █▀█ │
|
| 21 |
+
│ █▀ █▀█ ▄▄█ █ █ ▀ █ █▄▄ █▀▀ │
|
| 22 |
+
│ │
|
| 23 |
+
│ │
|
| 24 |
+
│ FastMCP 3.0.1 │
|
| 25 |
+
│ https://gofastmcp.com │
|
| 26 |
+
│ │
|
| 27 |
+
│ 🖥 Server: Student Text Adventure Server, 3.0.1 │
|
| 28 |
+
│ 🚀 Deploy free: https://fastmcp.cloud │
|
| 29 |
+
│ │
|
| 30 |
+
╰──────────────────────────────────────────────────────────────────────────────╯
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
[02/22/26 22:33:04] INFO Starting MCP server 'Student Text Adventure Server' with transport 'stdio' transport.py:183
|
| 34 |
+
|
| 35 |
+
--- Step 1 ---
|
| 36 |
+
THOUGHT: The Navigator suggests exploring the forest to the east or north since it might be a logical path for the pig to have taken. However, the Interaction Specialist notes that the valid actions include looking for an animal, which could be more directly related to finding the pig. The Historian reminds us that we haven't tried any of these actions yet, so it's worth trying to look for the animal before moving further into the forest.
|
| 37 |
+
TOOL: play_action
|
| 38 |
+
ARGS: {'action': 'look for animal'}
|
| 39 |
+
OBSERVATION: Grunk look all around for any thing that moving or hiding.
|
| 40 |
+
|
| 41 |
+
Grunk hear noise! It come from some place in bushes, but Grunk not sure which way it come from.
|
| 42 |
+
[Score: 0 | Moves: 2]
|
| 43 |
+
|
| 44 |
+
--- Step 2 ---
|
| 45 |
+
THOUGHT: The noise coming from the bushes could be the pig or another animal. We should investigate the source of the noise. However, we need to ensure we don't miss any important details in the current location.
|
| 46 |
+
TOOL: play_action
|
| 47 |
+
ARGS: {'action': 'look for animal'}
|
| 48 |
+
OBSERVATION: Grunk look all around for any thing that moving or hiding.
|
| 49 |
+
|
| 50 |
+
There, hear noise again! It come from northeast. Must be pig, hiding in bushes.
|
| 51 |
+
|
| 52 |
+
[Grunk score go up one.]
|
| 53 |
+
[Score: 1 | Moves: 3]
|
| 54 |
+
|
| 55 |
+
--- Step 3 ---
|
| 56 |
+
THOUGHT: The noise from the northeast seems significant, and since the goal is to find the pig, it makes sense to investigate that direction. We haven't explored that area yet, and it could lead us closer to the pig. Let's move northeast.
|
| 57 |
+
TOOL: play_action
|
| 58 |
+
ARGS: {'action': 'northeast'}
|
| 59 |
+
OBSERVATION: If that where pig go, that where Grunk go. It hard to see where Grunk going to, because there so much dark and leaves and branches here. Then suddenly, there not ground here any more!
|
| 60 |
+
|
| 61 |
+
Oof! Ow! Umf! Ugh!
|
| 62 |
+
|
| 63 |
+
Grunk fall down deep hole! Drop torch. Torch go out when Grunk land on it, so now it dark, too.
|
| 64 |
+
|
| 65 |
+
Hole
|
| 66 |
+
Grunk at bottom of deep, dark hole. It even smell like deep, dark hole. There some light that come from tunnel to east; that how Grunk see where Grunk at. Look like there maybe stairs at west side of hole that go up to outside, but them all broken now. There big crack in ground near stairs, too.
|
| 67 |
+
|
| 68 |
+
Grunk see torch (black and sooty) here.
|
| 69 |
+
[Score: 1 | Moves: 4]
|
| 70 |
+
|
| 71 |
+
--- Step 4 ---
|
| 72 |
+
THOUGHT: The first priority should be to regain visibility. The torch is black and sooty, but it's the only source of light available. We should try to light it or use it to navigate the environment better.
|
| 73 |
+
TOOL: play_action
|
| 74 |
+
ARGS: {'action': 'take torch'}
|
| 75 |
+
OBSERVATION: OK, got it.
|
| 76 |
+
[Score: 1 | Moves: 5]
|
| 77 |
+
|
| 78 |
+
--- Step 5 ---
|
| 79 |
+
THOUGHT: The Navigator suggests exploring the tunnel to the east since it's the only clear direction and provides some light. The Interaction Specialist thinks we should try to do something with the torch, possibly illuminating the area better by putting it across the crack. The Historian notes that we haven't tried any of these actions yet and suggests we prioritize exploration to gather more context.
|
| 80 |
+
TOOL: play_action
|
| 81 |
+
ARGS: {'action': 'east'}
|
| 82 |
+
OBSERVATION:
|
| 83 |
+
Fountain Room
|
| 84 |
+
All wall in this room glow! It bright, just like day time. Except that instead of sun, it wall that glow. And instead of grass and tree, it square room with four wall. And instead of outside, it all under ground. But beside those thing, it just like it! Tunnel keep going out to east and west, but normal doorway go north and southeast and southwest.
|
| 85 |
+
|
| 86 |
+
In middle of room, there fountain. But fountain not have any water.
|
| 87 |
+
|
| 88 |
+
South wall have big curtain hanging on it.
|
| 89 |
+
|
| 90 |
+
Hey! There pig! It good thing that Grunk fall down same hole as pig.
|
| 91 |
+
[Score: 1 | Moves: 6]
|
| 92 |
+
|
| 93 |
+
--- Step 6 ---
|
| 94 |
+
THOUGHT: The Navigator suggests exploring the room further by checking the fountain and the curtain. The Interaction Specialist thinks it's a good idea to interact with the pig since it's a key element in the story. The Historian notes that we haven't tried any actions in this room yet, so we should avoid retracing steps unnecessarily.
|
| 95 |
+
TOOL: play_action
|
| 96 |
+
ARGS: {'action': 'look in fountain'}
|
| 97 |
+
OBSERVATION: Hey, there coin inside fountain bowl! Grunk keep coin, because coin handy thing.
|
| 98 |
+
|
| 99 |
+
Pig peek over at fountain bowl too.
|
| 100 |
+
|
| 101 |
+
[Grunk score go up one.]
|
| 102 |
+
[Score: 2 | Moves: 7]
|
| 103 |
+
|
| 104 |
+
--- Step 7 ---
|
| 105 |
+
THOUGHT: The Navigator suggests exploring the room further by moving to the southeast, as it's a valid direction and might lead to new discoveries. The Interaction Specialist notes that there's a pig in the room and suggests interacting with it, possibly to gain more information or items. The Historian reminds us that we've already looked in the fountain and taken the coin, so we should avoid repeating actions.
|
| 106 |
+
TOOL: play_action
|
| 107 |
+
ARGS: {'action': 'south'}
|
| 108 |
+
OBSERVATION: Tunnel go east and west, and there doorway to north and southeast and southwest.
|
| 109 |
+
[Score: 2 | Moves: 8]
|
| 110 |
+
|
| 111 |
+
--- Step 8 ---
|
| 112 |
+
THOUGHT: The Navigator suggests exploring the north door to see what's there. The Interaction Specialist thinks we should try to interact with the pig since it might provide clues or lead us to more items. The Historian notes that we haven't tried the north door yet and it could be a good idea to explore it first.
|
| 113 |
+
TOOL: play_action
|
| 114 |
+
ARGS: {'action': 'north'}
|
| 115 |
+
OBSERVATION:
|
| 116 |
+
Statue Room
|
| 117 |
+
This room have two big picture that face each other. West wall have picture on it and east wall have different picture on it. Grunk think both picture really just part of wall, though. South wall have doorway in it that lots of light come from and north wall not have anything in it at all.
|
| 118 |
+
|
| 119 |
+
Statue of little man stand here, up on big stone block.
|
| 120 |
+
[Score: 2 | Moves: 9]
|
| 121 |
+
|
| 122 |
+
--- Step 9 ---
|
| 123 |
+
THOUGHT: The Navigator suggests exploring further into the cave system, possibly by moving east or west from the current room to discover new areas. However, the Interaction Specialist points out that there's a statue and a hat in the room, which might be useful for solving puzzles. The Historian reminds us that we haven't tried many actions in this room yet, so it might be worth interacting with the objects before moving on.
|
| 124 |
+
TOOL: get_valid_actions
|
| 125 |
+
ARGS: {}
|
| 126 |
+
OBSERVATION: Valid actions: take hat, eat pants, south, put on hat, push torch with pants, put torch across south, put torch across stone, put torch across man, put torch across pie picture, put torch across suit, put torch across north wall, put torch across west, put torch across hat, put torch across coin, put torch across shoes, put torch across hand, put hat on man, put hat on part, push statue head with torch, push torch with hat
|
| 127 |
+
|
| 128 |
+
--- Step 10 ---
|
| 129 |
+
THOUGHT: The Navigator suggests exploring the room further since we haven't tried many actions yet. The Interaction Specialist is curious about the hat and the statue, thinking they might be important. The Historian reminds us to avoid going south and to try something new to progress the story.
|
| 130 |
+
TOOL: play_action
|
| 131 |
+
ARGS: {'action': 'take hat'}
|
| 132 |
+
OBSERVATION: Hat come right off! Grunk guess it not really part of statue after all.
|
| 133 |
+
[Score: 2 | Moves: 10]
|
| 134 |
+
|
| 135 |
+
--- Step 11 ---
|
| 136 |
+
THOUGHT: The Navigator suggests moving to a new area to explore, but the Historian notes that we entered from the south and should avoid going back that way unless necessary. The Interaction Specialist thinks we should interact with the statue or the items in the room to see if there are any puzzles to solve.
|
| 137 |
+
TOOL: get_valid_actions
|
| 138 |
+
ARGS: {}
|
| 139 |
+
OBSERVATION: Valid actions: eat pants, south, put on hat, push torch with pants, put coin in hat, put torch across south, put torch across stone, put torch across man, put torch across pie picture, put torch across suit, put torch across north wall, put torch across west, put torch across hat, put torch across coin, put torch across shoes, put torch across hand, push statue head with torch
|
| 140 |
+
|
| 141 |
+
--- Step 12 ---
|
| 142 |
+
THOUGHT: The Navigator suggests exploring further by moving through the tunnels or doorways available, but we should avoid going south as it leads back to where we came from. The Interaction Specialist is interested in the statue and the items that can be manipulated, such as putting the coin in the hat or pushing the statue's head with the torch. The Historian notes that we've already taken the hat and suggests trying something new to avoid repetition.
|
| 143 |
+
TOOL: play_action
|
| 144 |
+
ARGS: {'action': 'push statue head with torch'}
|
| 145 |
+
OBSERVATION: Grunk rub torch all over statue head. Now statue head all black and sooty too.
|
| 146 |
+
[Score: 2 | Moves: 11]
|
| 147 |
+
|
| 148 |
+
--- Step 13 ---
|
| 149 |
+
THOUGHT: The Navigator suggests exploring further to find new areas, while the Interaction Specialist is interested in interacting with the items in the room. The Historian notes that we should avoid going south to prevent looping. Let's try an action that hasn't been tried yet and might reveal something interesting.
|
| 150 |
+
TOOL: play_action
|
| 151 |
+
ARGS: {'action': 'put coin in hat'}
|
| 152 |
+
OBSERVATION: OK, Grunk put coin into hat.
|
| 153 |
+
[Score: 2 | Moves: 12]
|
| 154 |
+
|
| 155 |
+
--- Step 14 ---
|
| 156 |
+
THOUGHT: The Navigator suggests exploring further to the north to see if there's anything interesting in that direction. However, the Historian reminds us that we've already pushed the statue's head with the torch, and the Interaction Specialist thinks we should try interacting with the statue in a different way, perhaps by pushing another part of it or examining it more closely.
|
| 157 |
+
TOOL: play_action
|
| 158 |
+
ARGS: {'action': 'examine statue'}
|
| 159 |
+
OBSERVATION: Statue look like little man with round nose and big ear and moustache. Grunk think funny little man maybe called "gnome". Wear funny suit and pointy shoe. One hand point north, at wall. Other hand up in air.
|
| 160 |
+
|
| 161 |
+
Gnome stand on big stone block. Maybe block for making gnome look tall. It true that statue look more big than real gnome, but Grunk think that just because it statue. Maybe all thing look more big when it like rock.
|
| 162 |
+
[Score: 2 | Moves: 13]
|
| 163 |
+
|
| 164 |
+
--- Step 15 ---
|
| 165 |
+
THOUGHT: The Navigator suggests exploring the north wall since the statue's hand points north. The Interaction Specialist thinks we should try to interact with the coin, as it might be useful. The Historian reminds us that we haven't tried many actions yet and suggests we avoid south to prevent looping.
|
| 166 |
+
TOOL: play_action
|
| 167 |
+
ARGS: {'action': 'north'}
|
| 168 |
+
OBSERVATION: Grunk only see way to go back south from here.
|
| 169 |
+
[Score: 2 | Moves: 14]
|
| 170 |
+
|
| 171 |
+
--- Step 16 ---
|
| 172 |
+
THOUGHT: The Navigator suggests we should explore further by moving to another area, but the Historian warns us that we came from the south and we should avoid going back unless necessary. The Interaction Specialist notes that there are several valid actions involving the coin and the hat, which might be useful for solving puzzles or gaining points.
|
| 173 |
+
|
| 174 |
+
Given that we've already taken the coin and placed it in the hat, and we're in a room with limited options, it makes sense to try an action that hasn't been tried yet. Let's try putting the hat across the man (statue) to see if it triggers any interesting events or reveals something new.
|
| 175 |
+
TOOL: play_action
|
| 176 |
+
ARGS: {'action': 'put hat across man'}
|
| 177 |
+
OBSERVATION: Grunk put hat full of coin on statue head. Coin fall out on ground.
|
| 178 |
+
[Score: 2 | Moves: 15]
|
| 179 |
+
|
| 180 |
+
--- Step 17 ---
|
| 181 |
+
THOUGHT: The Navigator suggests exploring new areas, but we should avoid going south as it's the direction we came from. The Interaction Specialist thinks we should interact with the items in the room, particularly the coin that fell out of the hat. The Historian notes that we've already taken the hat and examined the statue, so we should focus on new actions to avoid repetition.
|
| 182 |
+
TOOL: play_action
|
| 183 |
+
ARGS: {'action': 'take coin'}
|
| 184 |
+
OBSERVATION: OK, got it.
|
| 185 |
+
[Score: 2 | Moves: 16]
|
| 186 |
+
|
| 187 |
+
--- Step 18 ---
|
| 188 |
+
THOUGHT: The Navigator suggests exploring the room further by trying to interact with the statue in different ways, as we haven't fully explored all the interactions yet. The Interaction Specialist agrees and notes that we should try placing the torch in various positions to see if it triggers something. The Historian reminds us to avoid actions that have already been tried and failed, such as taking the hat or pushing the statue's head with the torch.
|
| 189 |
+
TOOL: play_action
|
| 190 |
+
ARGS: {'action': 'put torch across north wall'}
|
| 191 |
+
OBSERVATION: Grunk rub torch all over north wall. Now north wall all black and sooty too.
|
| 192 |
+
[Score: 2 | Moves: 17]
|
| 193 |
+
|
| 194 |
+
--- Step 19 ---
|
| 195 |
+
THOUGHT: The Navigator suggests exploring further to the north, but the Historian notes that we've already tried going north and it just leads us back south. The Interaction Specialist thinks we should try interacting with the statue again, perhaps in a different way, since we haven't fully explored its potential.
|
| 196 |
+
TOOL: play_action
|
| 197 |
+
ARGS: {'action': 'push head with pants'}
|
| 198 |
+
OBSERVATION: (statue head with Grunk pants)
|
| 199 |
+
(Grunk take pants off first)
|
| 200 |
+
Grunk rub pants all over statue head. Now statue head all clean! But pants get all black and sooty.
|
| 201 |
+
[Score: 2 | Moves: 18]
|
| 202 |
+
|
| 203 |
+
--- Step 20 ---
|
| 204 |
+
THOUGHT: The Navigator suggests exploring further by moving to a new area, but the Historian notes that we've already tried going south and north from this location. The Interaction Specialist thinks we should try interacting with the statue or its components in a different way, possibly solving a puzzle. Since we've already cleaned the statue's head with the pants, let's try something else.
|
| 205 |
+
TOOL: play_action
|
| 206 |
+
ARGS: {'action': 'put on hat'}
|
| 207 |
+
OBSERVATION: (Grunk take hat first)
|
| 208 |
+
OK, Grunk put on hat.
|
| 209 |
+
[Score: 2 | Moves: 19]
|
| 210 |
+
|
| 211 |
+
============================================================
|
| 212 |
+
FINAL RESULTS
|
| 213 |
+
============================================================
|
| 214 |
+
Final Score: 2
|
| 215 |
+
Steps: 20
|
| 216 |
+
Moves: 19
|
| 217 |
+
Locations Visited: 5
|
| 218 |
+
Game Completed: False
|