Spaces:
Sleeping
Sleeping
change
Browse files- agents.py +13 -11
- app.py +6 -7
- utils/agent_factory.py +14 -13
- utils/pokemon_utils.py +6 -5
agents.py
CHANGED
|
@@ -30,10 +30,14 @@ class MaxDamagePlayer(Player):
|
|
| 30 |
best_move = max(battle.available_moves, key=lambda move: move.base_power)
|
| 31 |
# Creating an order for the selected move
|
| 32 |
return self.create_order(best_move)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
else:
|
| 34 |
-
#
|
| 35 |
-
|
| 36 |
-
return self.choose_random_move(battle)
|
| 37 |
|
| 38 |
# --- Helper Function & Base Class ---
|
| 39 |
def normalize_name(name: str) -> str:
|
|
@@ -236,13 +240,11 @@ class LLMAgentBase(Player):
|
|
| 236 |
else:
|
| 237 |
fallback_reason = "Unknown error processing LLM decision."
|
| 238 |
|
| 239 |
-
print(f"Warning: {fallback_reason}
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
print("AI Fallback: No moves or switches available. Using Struggle/Default.")
|
| 245 |
-
return self.choose_default_move(battle)
|
| 246 |
|
| 247 |
async def _get_llm_decision(self, battle_state: str) -> Dict[str, Any]:
|
| 248 |
raise NotImplementedError("Subclasses must implement _get_llm_decision")
|
|
@@ -254,7 +256,7 @@ class GeminiAgent(LLMAgentBase):
|
|
| 254 |
kwargs['avatar'] = avatar
|
| 255 |
super().__init__(*args, **kwargs)
|
| 256 |
self.model_name = model
|
| 257 |
-
|
| 258 |
if not used_api_key:
|
| 259 |
raise ValueError("Google API key not provided or found in GOOGLE_API_KEY env var.")
|
| 260 |
|
|
|
|
| 30 |
best_move = max(battle.available_moves, key=lambda move: move.base_power)
|
| 31 |
# Creating an order for the selected move
|
| 32 |
return self.create_order(best_move)
|
| 33 |
+
elif battle.available_switches:
|
| 34 |
+
# If no attacking moves available, switch to first available Pokemon
|
| 35 |
+
# Don't choose randomly - pick first available switch
|
| 36 |
+
first_switch = battle.available_switches[0]
|
| 37 |
+
return self.create_order(first_switch)
|
| 38 |
else:
|
| 39 |
+
# No moves or switches available - this shouldn't happen in normal gameplay
|
| 40 |
+
raise ValueError("MaxDamagePlayer: No moves or switches available")
|
|
|
|
| 41 |
|
| 42 |
# --- Helper Function & Base Class ---
|
| 43 |
def normalize_name(name: str) -> str:
|
|
|
|
| 240 |
else:
|
| 241 |
fallback_reason = "Unknown error processing LLM decision."
|
| 242 |
|
| 243 |
+
print(f"Warning: {fallback_reason} Cannot proceed without valid move.")
|
| 244 |
+
|
| 245 |
+
# Instead of choosing random move, raise an exception or wait
|
| 246 |
+
# This prevents automatic random actions
|
| 247 |
+
raise ValueError(f"LLM Agent could not make a valid decision: {fallback_reason}")
|
|
|
|
|
|
|
| 248 |
|
| 249 |
async def _get_llm_decision(self, battle_state: str) -> Dict[str, Any]:
|
| 250 |
raise NotImplementedError("Subclasses must implement _get_llm_decision")
|
|
|
|
| 256 |
kwargs['avatar'] = avatar
|
| 257 |
super().__init__(*args, **kwargs)
|
| 258 |
self.model_name = model
|
| 259 |
+
used_api_change = api_key or os.environ.get("GOOGLE_API_KEY")
|
| 260 |
if not used_api_key:
|
| 261 |
raise ValueError("Google API key not provided or found in GOOGLE_API_KEY env var.")
|
| 262 |
|
app.py
CHANGED
|
@@ -354,11 +354,10 @@ def get_supported_agents() -> dict:
|
|
| 354 |
"supported_agents": get_supported_agent_types(),
|
| 355 |
"default_models": get_default_models(),
|
| 356 |
"description": {
|
| 357 |
-
"openai": "OpenAI GPT models (requires API key)",
|
| 358 |
-
"gemini": "Google Gemini models (requires API key)",
|
| 359 |
-
"mistral": "Mistral AI models (requires API key)",
|
| 360 |
-
"maxdamage": "Simple agent that chooses moves with highest base power"
|
| 361 |
-
"random": "Random move selection agent"
|
| 362 |
}
|
| 363 |
}
|
| 364 |
|
|
@@ -567,10 +566,10 @@ async def wait_30_seconds() -> dict:
|
|
| 567 |
|
| 568 |
# --- Server Execution ---
|
| 569 |
if __name__ == "__main__":
|
| 570 |
-
print(f"Pokemon Battle MCP Server starting on port
|
| 571 |
print("Available battle types:")
|
| 572 |
print("- Ladder battles")
|
| 573 |
-
print("- AI agent battles (OpenAI, Gemini, Mistral, MaxDamage
|
| 574 |
print("- Human player battles")
|
| 575 |
print("Running Pokemon Battle MCP server with SSE transport")
|
| 576 |
mcp.run(transport="sse")
|
|
|
|
| 354 |
"supported_agents": get_supported_agent_types(),
|
| 355 |
"default_models": get_default_models(),
|
| 356 |
"description": {
|
| 357 |
+
"openai": "OpenAI GPT models (requires API key) - Deterministic decisions",
|
| 358 |
+
"gemini": "Google Gemini models (requires API key) - Deterministic decisions",
|
| 359 |
+
"mistral": "Mistral AI models (requires API key) - Deterministic decisions",
|
| 360 |
+
"maxdamage": "Simple agent that chooses moves with highest base power - Deterministic decisions"
|
|
|
|
| 361 |
}
|
| 362 |
}
|
| 363 |
|
|
|
|
| 566 |
|
| 567 |
# --- Server Execution ---
|
| 568 |
if __name__ == "__main__":
|
| 569 |
+
print(f"Pokemon Battle MCP Server starting on port 7860...")
|
| 570 |
print("Available battle types:")
|
| 571 |
print("- Ladder battles")
|
| 572 |
+
print("- AI agent battles (OpenAI, Gemini, Mistral, MaxDamage) - NO RANDOM FALLBACKS")
|
| 573 |
print("- Human player battles")
|
| 574 |
print("Running Pokemon Battle MCP server with SSE transport")
|
| 575 |
mcp.run(transport="sse")
|
utils/agent_factory.py
CHANGED
|
@@ -104,20 +104,21 @@ def create_agent(agent_type: str, api_key: str = None, model: str = None, userna
|
|
| 104 |
avatar=avatar,
|
| 105 |
)
|
| 106 |
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
|
|
|
| 118 |
|
| 119 |
else:
|
| 120 |
-
raise ValueError(f"Unknown agent type: {agent_type}. Supported types: openai, gemini, mistral, maxdamage
|
| 121 |
|
| 122 |
def get_supported_agent_types():
|
| 123 |
"""
|
|
@@ -126,7 +127,7 @@ def get_supported_agent_types():
|
|
| 126 |
Returns:
|
| 127 |
list: List of supported agent type strings
|
| 128 |
"""
|
| 129 |
-
return ['openai', 'gemini', 'mistral', 'maxdamage'
|
| 130 |
|
| 131 |
def get_default_models():
|
| 132 |
"""
|
|
|
|
| 104 |
avatar=avatar,
|
| 105 |
)
|
| 106 |
|
| 107 |
+
# Random agents removed to prevent automatic random move selection
|
| 108 |
+
# elif agent_type == 'random':
|
| 109 |
+
# username = f"Random-{username_suffix}"
|
| 110 |
+
# avatar = random.choice(AGENT_AVATARS['random'])
|
| 111 |
+
#
|
| 112 |
+
# return RandomPlayer(
|
| 113 |
+
# account_configuration=AccountConfiguration(username, None),
|
| 114 |
+
# server_configuration=custom_config,
|
| 115 |
+
# max_concurrent_battles=1,
|
| 116 |
+
# save_replays="battle_replays",
|
| 117 |
+
# avatar=avatar,
|
| 118 |
+
# )
|
| 119 |
|
| 120 |
else:
|
| 121 |
+
raise ValueError(f"Unknown agent type: {agent_type}. Supported types: openai, gemini, mistral, maxdamage")
|
| 122 |
|
| 123 |
def get_supported_agent_types():
|
| 124 |
"""
|
|
|
|
| 127 |
Returns:
|
| 128 |
list: List of supported agent type strings
|
| 129 |
"""
|
| 130 |
+
return ['openai', 'gemini', 'mistral', 'maxdamage']
|
| 131 |
|
| 132 |
def get_default_models():
|
| 133 |
"""
|
utils/pokemon_utils.py
CHANGED
|
@@ -52,19 +52,20 @@ class MCPPokemonAgent(LLMAgentBase):
|
|
| 52 |
active_battles[battle.battle_tag]['available_switches'] = [pkmn.species for pkmn in battle.available_switches]
|
| 53 |
|
| 54 |
try:
|
| 55 |
-
# Wait for external move selection (
|
| 56 |
-
move_order = await
|
| 57 |
|
| 58 |
# Update battle state
|
| 59 |
if battle.battle_tag in active_battles:
|
| 60 |
active_battles[battle.battle_tag]['waiting_for_move'] = False
|
| 61 |
|
| 62 |
return move_order
|
| 63 |
-
except
|
| 64 |
-
print(f"
|
| 65 |
if battle.battle_tag in active_battles:
|
| 66 |
active_battles[battle.battle_tag]['waiting_for_move'] = False
|
| 67 |
-
|
|
|
|
| 68 |
|
| 69 |
async def submit_move(self, move_name: str = None, pokemon_name: str = None, battle: Battle = None):
|
| 70 |
"""Submit a move or switch externally"""
|
|
|
|
| 52 |
active_battles[battle.battle_tag]['available_switches'] = [pkmn.species for pkmn in battle.available_switches]
|
| 53 |
|
| 54 |
try:
|
| 55 |
+
# Wait for external move selection (no timeout - wait indefinitely)
|
| 56 |
+
move_order = await self.external_move_queue.get()
|
| 57 |
|
| 58 |
# Update battle state
|
| 59 |
if battle.battle_tag in active_battles:
|
| 60 |
active_battles[battle.battle_tag]['waiting_for_move'] = False
|
| 61 |
|
| 62 |
return move_order
|
| 63 |
+
except Exception as e:
|
| 64 |
+
print(f"Error in move selection for battle {battle.battle_tag}: {e}")
|
| 65 |
if battle.battle_tag in active_battles:
|
| 66 |
active_battles[battle.battle_tag]['waiting_for_move'] = False
|
| 67 |
+
# Don't choose random move - raise the exception to handle gracefully
|
| 68 |
+
raise
|
| 69 |
|
| 70 |
async def submit_move(self, move_name: str = None, pokemon_name: str = None, battle: Battle = None):
|
| 71 |
"""Submit a move or switch externally"""
|