""" 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)