diff --git a/ai_diplomacy/agent.py b/ai_diplomacy/agent.py index 2352abb..920af07 100644 --- a/ai_diplomacy/agent.py +++ b/ai_diplomacy/agent.py @@ -435,10 +435,7 @@ class DiplomacyAgent: # Prepare context for the prompt board_state_dict = game.get_state() - # Create readable board state string - units_str = "\n".join([f" {p}: {', '.join(u)}" for p, u in board_state_dict.get('units', {}).items()]) - centers_str = "\n".join([f" {p}: {', '.join(c)}" for p, c in board_state_dict.get('centers', {}).items()]) - board_state_str = f"Units:\n{units_str}\n\nSupply Centers:\n{centers_str}" + board_state_str = f"Units: {board_state_dict.get('units', {})}, Centers: {board_state_dict.get('centers', {})}" messages_this_round = game_history.get_messages_this_round( power_name=self.power_name, @@ -572,7 +569,7 @@ class DiplomacyAgent: # Fix 2: Be more robust about extracting relationship updates new_relationships = None - for key in ['current_relationships', 'relationship_updates', 'updated_relationships', 'relationships']: + for key in ['relationship_updates', 'updated_relationships', 'relationships']: if key in parsed_data and isinstance(parsed_data[key], dict): new_relationships = parsed_data[key] logger.info(f"[{self.power_name}] Successfully extracted '{key}' for relationship updates.") @@ -602,7 +599,7 @@ class DiplomacyAgent: if success_status == "Success: Parsed diary data": # If only parsing was successful before success_status = "Success: Parsed, no valid relationship updates" elif new_relationships is not None: # It was provided but not a dict - logger.warning(f"[{self.power_name}] 'current_relationships' from diary LLM was not a dictionary: {type(new_relationships)}") + logger.warning(f"[{self.power_name}] 'updated_relationships' from diary LLM was not a dictionary: {type(new_relationships)}") # Add the generated (or fallback) diary entry self.add_diary_entry(diary_entry_text, game.current_short_phase) @@ -645,10 +642,7 @@ class DiplomacyAgent: return board_state_dict = game.get_state() - # Create readable board state string - units_str = "\n".join([f" {p}: {', '.join(u)}" for p, u in board_state_dict.get('units', {}).items()]) - centers_str = "\n".join([f" {p}: {', '.join(c)}" for p, c in board_state_dict.get('centers', {}).items()]) - board_state_str = f"Units:\n{units_str}\n\nSupply Centers:\n{centers_str}" + board_state_str = f"Units: {board_state_dict.get('units', {})}, Centers: {board_state_dict.get('centers', {})}" orders_list_str = "\n".join([f"- {o}" for o in orders]) if orders else "No orders submitted." @@ -939,15 +933,12 @@ class DiplomacyAgent: other_powers = [p for p in game.powers if p != power_name] # Create a readable board state string from the board_state dict - board_state_str = "Units:\n" - for p_name, units in board_state.get('units', {}).items(): - units_str = ", ".join(units) if units else "None" - board_state_str += f" {p_name}: {units_str}\n" - - board_state_str += "\nSupply Centers:\n" - for p_name, centers in board_state.get('centers', {}).items(): - centers_str = ", ".join(centers) if centers else "None" - board_state_str += f" {p_name}: {centers_str}\n" + board_state_str = f"Board State:\n" + for p_name, power_data in board_state.get('powers', {}).items(): + # Get units and centers from the board state + units = power_data.get('units', []) + centers = power_data.get('centers', []) + board_state_str += f" {p_name}: Units={units}, Centers={centers}\n" # Extract year from the phase name (e.g., "S1901M" -> "1901") current_year = last_phase_name[1:5] if len(last_phase_name) >= 5 else "unknown" diff --git a/ai_diplomacy/clients.py b/ai_diplomacy/clients.py index 13c77e0..b9df88c 100644 --- a/ai_diplomacy/clients.py +++ b/ai_diplomacy/clients.py @@ -464,49 +464,32 @@ class BaseModelClient: agent_relationships: Optional[Dict[str, str]] = None, agent_private_diary_str: Optional[str] = None, # Added ) -> str: + # MINIMAL CHANGE: Just change to load unformatted version instructions = load_prompt("unformatted/conversation_instructions.txt", prompts_dir=self.prompts_dir) - - # Load conversation-specific context template - context_template = load_prompt("unformatted/conversation_context.txt", prompts_dir=self.prompts_dir) - - # Get phase info - current_phase = game.get_current_phase() - - # Get active powers - active_powers = [p for p in game.powers.keys() if not game.powers[p].is_eliminated()] - eliminated_powers = [p for p in game.powers.keys() if game.powers[p].is_eliminated()] - eliminated_status = f"Eliminated: {', '.join(eliminated_powers)}" if eliminated_powers else "No powers eliminated yet" - - # Get messages this round - messages_this_round = game_history.get_messages_this_round( - power_name=power_name, - current_phase_name=game.current_short_phase - ) - if not messages_this_round.strip(): - messages_this_round = "(No messages exchanged yet this round)" - - # Format the context - context = context_template.format( - power_name=power_name, - current_phase=current_phase, - agent_goals="\n".join(f"- {g}" for g in agent_goals) if agent_goals else "- Survive and expand", - agent_relationships="\n".join(f"- {p}: {r}" for p, r in agent_relationships.items()) if agent_relationships else "- All powers: Neutral", - recent_private_diary=agent_private_diary_str[-500:] if agent_private_diary_str else "(No recent diary entries)", # Last 500 chars - messages_this_round=messages_this_round, - active_powers=", ".join(active_powers), - eliminated_status=eliminated_status + + # KEEP ORIGINAL: Use build_context_prompt as before + context = build_context_prompt( + game, + board_state, + power_name, + possible_orders, + game_history, + agent_goals=agent_goals, + agent_relationships=agent_relationships, + agent_private_diary=agent_private_diary_str, # Pass diary string + prompts_dir=self.prompts_dir, ) - # Get recent messages targeting this power to prioritize responses + # KEEP ORIGINAL: Get recent messages targeting this power to prioritize responses recent_messages_to_power = game_history.get_recent_messages_to_power(power_name, limit=3) - # Debug logging to verify messages + # KEEP ORIGINAL: Debug logging to verify messages logger.info(f"[{power_name}] Found {len(recent_messages_to_power)} high priority messages to respond to") if recent_messages_to_power: for i, msg in enumerate(recent_messages_to_power): logger.info(f"[{power_name}] Priority message {i+1}: From {msg['sender']} in {msg['phase']}: {msg['content'][:50]}...") - # Add a section for unanswered messages + # KEEP ORIGINAL: Add a section for unanswered messages unanswered_messages = "\n\nRECENT MESSAGES REQUIRING YOUR ATTENTION:\n" if recent_messages_to_power: for msg in recent_messages_to_power: diff --git a/ai_diplomacy/formatter.py b/ai_diplomacy/formatter.py index d1b2678..eb6f83a 100644 --- a/ai_diplomacy/formatter.py +++ b/ai_diplomacy/formatter.py @@ -113,15 +113,15 @@ async def format_with_gemini_flash( # Log if requested if log_file_path: - await log_llm_response( + log_llm_response( log_file_path=log_file_path, model_name=model_name, power_name=power_name or "FORMATTER", phase=phase or "N/A", response_type=f"format_{format_type}", - prompt=format_prompt, + raw_input_prompt=format_prompt, raw_response=formatted_response, - temperature=0 + success="Success" ) return formatted_response @@ -131,15 +131,15 @@ async def format_with_gemini_flash( # Log error if requested if log_file_path: - await log_llm_response( + log_llm_response( log_file_path=log_file_path, model_name=model_name, power_name=power_name or "FORMATTER", phase=phase or "N/A", response_type=f"format_{format_type}", - prompt=format_prompt, + raw_input_prompt=format_prompt, raw_response=f"ERROR: {str(e)}", - temperature=0 + success=f"Failure: {type(e).__name__}" ) # Return empty structure based on format type diff --git a/ai_diplomacy/prompts/formatting/format_negotiation_diary.txt b/ai_diplomacy/prompts/formatting/format_negotiation_diary.txt index 3cde88d..2f87fd5 100644 --- a/ai_diplomacy/prompts/formatting/format_negotiation_diary.txt +++ b/ai_diplomacy/prompts/formatting/format_negotiation_diary.txt @@ -6,7 +6,7 @@ Required JSON format: { "negotiation_summary": "Key outcomes from negotiations - what was discussed and agreed", "intent": "Strategic intent for upcoming orders based on negotiations", - "current_relationships": { + "updated_relationships": { "AUSTRIA": "Enemy|Unfriendly|Neutral|Friendly|Ally", "ENGLAND": "Enemy|Unfriendly|Neutral|Friendly|Ally", "FRANCE": "Enemy|Unfriendly|Neutral|Friendly|Ally", @@ -23,7 +23,7 @@ Scenario 1 - Alliance forming: { "negotiation_summary": "Reached agreement with Italy for DMZ in Piedmont and mutual support against Austria. England remains non-committal about channel.", "intent": "Will honor DMZ with Italy and support their move to Trieste while securing Belgium", - "current_relationships": { + "updated_relationships": { "ITALY": "Friendly", "ENGLAND": "Neutral", "AUSTRIA": "Unfriendly" @@ -34,7 +34,7 @@ Scenario 2 - Detecting deception: { "negotiation_summary": "Germany claims they'll support me into Belgium but also told England they'd help them. Russia suspiciously quiet.", "intent": "Assume Germany is unreliable, prepare defensive positions", - "current_relationships": { + "updated_relationships": { "GERMANY": "Unfriendly", "RUSSIA": "Neutral" } @@ -44,7 +44,7 @@ Scenario 3 - Coordinated attack: { "negotiation_summary": "Coordinated joint attack on Turkey with Austria. Russia agrees to DMZ Black Sea.", "intent": "Execute agreed plan: Army Greece to Bulgaria, Fleet Aegean to Eastern Med", - "current_relationships": { + "updated_relationships": { "AUSTRIA": "Ally", "RUSSIA": "Friendly", "TURKEY": "Enemy" @@ -58,7 +58,7 @@ Instructions: - intent: What will the player do based on these negotiations? - Look for: planned moves, strategies, responses to agreements - Common phrases: "I will", "plan to", "intend to", "based on this" -- current_relationships: Your assessment of ALL powers after negotiations +- updated_relationships: Your assessment of ALL powers after negotiations - Include ALL 7 powers (remove yourself from the list) - Reflect any changes from negotiations - Use ONLY: Enemy, Unfriendly, Neutral, Friendly, or Ally diff --git a/ai_diplomacy/prompts/unformatted/conversation_context.txt b/ai_diplomacy/prompts/unformatted/conversation_context.txt deleted file mode 100644 index f3d2953..0000000 --- a/ai_diplomacy/prompts/unformatted/conversation_context.txt +++ /dev/null @@ -1,22 +0,0 @@ -DIPLOMATIC CONTEXT - -You are {power_name} in a game of Diplomacy. -Current Phase: {current_phase} - -YOUR STRATEGIC FRAMEWORK -Goals: -{agent_goals} - -Current Relationships: -{agent_relationships} - -DIPLOMATIC SITUATION -Recent Negotiations: -{recent_private_diary} - -Messages This Round: -{messages_this_round} - -OTHER POWERS' STATUS -Active Powers: {active_powers} -{eliminated_status} \ No newline at end of file diff --git a/ai_diplomacy/prompts_simple/unformatted/conversation_context.txt b/ai_diplomacy/prompts_simple/unformatted/conversation_context.txt deleted file mode 100644 index f3d2953..0000000 --- a/ai_diplomacy/prompts_simple/unformatted/conversation_context.txt +++ /dev/null @@ -1,22 +0,0 @@ -DIPLOMATIC CONTEXT - -You are {power_name} in a game of Diplomacy. -Current Phase: {current_phase} - -YOUR STRATEGIC FRAMEWORK -Goals: -{agent_goals} - -Current Relationships: -{agent_relationships} - -DIPLOMATIC SITUATION -Recent Negotiations: -{recent_private_diary} - -Messages This Round: -{messages_this_round} - -OTHER POWERS' STATUS -Active Powers: {active_powers} -{eliminated_status} \ No newline at end of file diff --git a/lm_game.py b/lm_game.py index bd41a24..4585f22 100644 --- a/lm_game.py +++ b/lm_game.py @@ -25,7 +25,7 @@ from ai_diplomacy.negotiations import conduct_negotiations from ai_diplomacy.planning import planning_phase from ai_diplomacy.game_history import GameHistory from ai_diplomacy.agent import DiplomacyAgent -# import ai_diplomacy.narrative +import ai_diplomacy.narrative from ai_diplomacy.game_logic import ( save_game_state, load_game_state,