amogus/tests/test_llm_integration.py
Antigravity 071906df59 feat: Complete LLM agent framework with fog-of-war, meeting flow, and prompt assembly
- Core engine: simulator, game mechanics, triggers (138 tests)
- Fog-of-war per-player state tracking
- Meeting flow: interrupt, discussion, voting, consolidation
- Prompt assembler with strategy injection tiers
- LLM client with fallbacks for models without JSON/system support
- Prompt templates: action, discussion, voting, reflection
- Full integration in main.py orchestrator
- Verified working with free OpenRouter models (Gemma)
2026-02-01 00:00:34 -05:00

294 lines
7.9 KiB
Python

"""
The Glass Box League — LLM Integration Test
Tests the full LLM integration with OpenRouter using free models.
"""
import sys
import json
sys.path.insert(0, '.')
from src.llm.client import OpenRouterClient, get_client
from src.agents.agent import Agent, AgentConfig
from src.agents.prompt_assembler import PromptAssembler, PromptConfig
from src.main import GameOrchestrator
from src.engine.types import Role
def test_basic_llm_call():
"""Test basic LLM API call."""
print("\n=== Test 1: Basic LLM Call ===")
client = get_client()
response = client.generate(
system_prompt="You are a helpful assistant. Respond with valid JSON only.",
user_prompt='Say hello in JSON format: {"greeting": "..."}',
model="google/gemma-3-4b-it:free"
)
print(f"Raw response: {response[:200] if response else 'None'}...")
if response:
try:
parsed = json.loads(response)
print(f"✓ Parsed JSON: {parsed}")
return True
except:
print(f"✗ Failed to parse JSON")
return False
return False
def test_action_prompt():
"""Test action phase prompt generation and LLM response."""
print("\n=== Test 2: Action Phase Prompt ===")
# Build prompt
config = PromptConfig(
model_name="Gemini-Flash",
persona="You are a cautious crewmate who trusts no one.",
strategy_level="basic",
meta_level="direct",
is_impostor=False
)
assembler = PromptAssembler(config)
game_settings = {"num_impostors": 1, "kill_cooldown": 25}
system_prompt = assembler.build_system_prompt(
phase="action",
game_settings=game_settings,
map_name="The Skeld",
learned={}
)
player_state = {
"id": "red",
"name": "Red",
"role": "CREWMATE",
"location": "cafeteria",
"tasks_total": 3,
"tasks_completed": 0
}
vision = {
"room": "cafeteria",
"players_visible": [
{"id": "blue", "name": "Blue", "color": "blue"}
],
"bodies_visible": [],
"exits": ["weapons", "admin", "medbay"]
}
available_actions = {
"can_move_to": ["weapons", "admin", "medbay"],
"can_interact": ["emergency_button"]
}
user_prompt = assembler.build_action_prompt(
player_state=player_state,
recent_history=[],
vision=vision,
available_actions=available_actions,
trigger={"type": "GAME_START", "t": 0}
)
print(f"System prompt: {len(system_prompt)} chars")
print(f"User prompt: {len(user_prompt)} chars")
# Call LLM
client = get_client()
response = client.generate_json(
system_prompt=system_prompt,
user_prompt=user_prompt,
model="google/gemma-3-4b-it:free"
)
if response:
print(f"✓ LLM response: {json.dumps(response, indent=2)[:500]}...")
# Check response structure
has_action = "action" in response
has_thought = "internal_thought" in response
print(f" Has action: {has_action}")
print(f" Has internal_thought: {has_thought}")
return has_action
else:
print("✗ No response from LLM")
return False
def test_discussion_prompt():
"""Test discussion phase prompt and LLM response."""
print("\n=== Test 3: Discussion Phase Prompt ===")
config = PromptConfig(
model_name="Gemini-Flash",
persona="You are suspicious of everyone.",
is_impostor=False
)
assembler = PromptAssembler(config)
game_settings = {"num_impostors": 1}
system_prompt = assembler.build_system_prompt(
phase="discussion",
game_settings=game_settings,
map_name="The Skeld"
)
player_state = {
"id": "red",
"name": "Red",
"role": "CREWMATE",
"location": "cafeteria"
}
transcript = [
{"speaker": "Blue", "message": "I found the body in electrical!"},
{"speaker": "Green", "message": "Where was everyone?"}
]
user_prompt = assembler.build_discussion_prompt(
player_state=player_state,
transcript=transcript,
meeting_scratchpad={}
)
print(f"System prompt: {len(system_prompt)} chars")
print(f"User prompt: {len(user_prompt)} chars")
client = get_client()
response = client.generate_json(
system_prompt=system_prompt,
user_prompt=user_prompt,
model="google/gemma-3-4b-it:free"
)
if response:
print(f"✓ LLM response: {json.dumps(response, indent=2)[:500]}...")
has_desire = "desire_to_speak" in response
has_message = "message" in response
print(f" Has desire_to_speak: {has_desire}")
print(f" Has message: {has_message}")
return has_desire and has_message
else:
print("✗ No response from LLM")
return False
def test_impostor_action():
"""Test impostor action with kill available."""
print("\n=== Test 4: Impostor Action ===")
config = PromptConfig(
model_name="Gemini-Flash",
persona="You are a ruthless impostor.",
is_impostor=True,
fellow_impostors=["Purple"],
strategy_level="intermediate"
)
assembler = PromptAssembler(config)
system_prompt = assembler.build_system_prompt(
phase="action",
game_settings={"num_impostors": 2},
map_name="The Skeld"
)
player_state = {
"id": "red",
"name": "Red",
"role": "IMPOSTOR",
"location": "electrical",
"kill_cooldown": 0
}
vision = {
"room": "electrical",
"players_visible": [
{"id": "blue", "name": "Blue", "color": "blue", "action": "doing_task"}
],
"bodies_visible": [],
"exits": ["security"]
}
available_actions = {
"can_move_to": ["security"],
"can_interact": ["vent_elec"],
"can_kill": ["blue"],
"can_sabotage": ["lights", "o2", "reactor"]
}
user_prompt = assembler.build_action_prompt(
player_state=player_state,
recent_history=[],
vision=vision,
available_actions=available_actions,
trigger={"type": "PERIODIC", "t": 30.0}
)
client = get_client()
response = client.generate_json(
system_prompt=system_prompt,
user_prompt=user_prompt,
model="google/gemma-3-4b-it:free"
)
if response:
print(f"✓ LLM response: {json.dumps(response, indent=2)[:600]}...")
action = response.get("action", {})
action_type = action.get("type")
print(f" Action type: {action_type}")
print(f" Thought: {response.get('internal_thought', '')[:100]}...")
return True
else:
print("✗ No response from LLM")
return False
def main():
"""Run all LLM integration tests."""
print("=" * 60)
print("THE GLASS BOX LEAGUE — LLM INTEGRATION TESTS")
print("Using free Gemini model via OpenRouter")
print("=" * 60)
results = []
# Run tests
results.append(("Basic LLM Call", test_basic_llm_call()))
results.append(("Action Phase", test_action_prompt()))
results.append(("Discussion Phase", test_discussion_prompt()))
results.append(("Impostor Action", test_impostor_action()))
# Summary
print("\n" + "=" * 60)
print("RESULTS")
print("=" * 60)
passed = 0
for name, result in results:
status = "✓ PASS" if result else "✗ FAIL"
print(f" {status}: {name}")
if result:
passed += 1
print(f"\nTotal: {passed}/{len(results)} tests passed")
return passed == len(results)
if __name__ == "__main__":
success = main()
sys.exit(0 if success else 1)