|
16 | 16 | LOG_BASE_DIR = Path.cwd() / "logs" |
17 | 17 |
|
18 | 18 |
|
| 19 | +@dataclass |
| 20 | +class AgentInfo: |
| 21 | + """Information about a single agent""" |
| 22 | + |
| 23 | + name: str |
| 24 | + model_name: str | None = None |
| 25 | + agent_class: str | None = None |
| 26 | + |
| 27 | + |
19 | 28 | def set_log_base_directory(directory: str | Path): |
20 | 29 | """Set the logs directory directly""" |
21 | 30 | global LOG_BASE_DIR |
@@ -73,6 +82,33 @@ def get_models_from_metadata(log_dir: Path) -> list[str]: |
73 | 82 | return [] |
74 | 83 |
|
75 | 84 |
|
| 85 | +def get_agent_info_from_metadata(metadata: dict[str, Any]) -> list[AgentInfo]: |
| 86 | + """Extract detailed agent information from metadata""" |
| 87 | + agents = [] |
| 88 | + players_config = metadata.get("config", {}).get("players", {}) |
| 89 | + |
| 90 | + # Handle both list and dict formats |
| 91 | + if isinstance(players_config, list): |
| 92 | + # If players is a list, iterate through each player |
| 93 | + for i, player_config in enumerate(players_config): |
| 94 | + if isinstance(player_config, dict): |
| 95 | + name = f"p{i + 1}" # Default naming p1, p2, etc. |
| 96 | + config = player_config.get("config", {}) |
| 97 | + model_name = config.get("model", {}).get("model_name") |
| 98 | + agent_class = config.get("agent_class") |
| 99 | + agents.append(AgentInfo(name=name, model_name=model_name, agent_class=agent_class)) |
| 100 | + elif isinstance(players_config, dict): |
| 101 | + # If players is a dict, iterate through player keys (p1, p2, etc.) |
| 102 | + for player_key, player_config in sorted(players_config.items()): |
| 103 | + if isinstance(player_config, dict): |
| 104 | + config = player_config.get("config", {}) |
| 105 | + model_name = config.get("model", {}).get("model_name") |
| 106 | + agent_class = config.get("agent_class") |
| 107 | + agents.append(AgentInfo(name=player_key, model_name=model_name, agent_class=agent_class)) |
| 108 | + |
| 109 | + return agents |
| 110 | + |
| 111 | + |
76 | 112 | def find_all_game_folders(base_dir: Path) -> list[dict[str, Any]]: |
77 | 113 | """Recursively find all folders and mark which ones contain metadata.json""" |
78 | 114 | all_folders = [] |
@@ -152,6 +188,40 @@ class GameMetadata: |
152 | 188 | main_log_path: str |
153 | 189 | metadata_file_path: str |
154 | 190 | rounds: list[dict[str, Any]] |
| 191 | + agent_info: list[AgentInfo] | None = None |
| 192 | + |
| 193 | + |
| 194 | +def process_round_results(round_results: dict[str, Any] | None) -> dict[str, Any] | None: |
| 195 | + """Process round results to add computed fields and sort scores""" |
| 196 | + if not round_results or not round_results.get("scores"): |
| 197 | + return round_results |
| 198 | + |
| 199 | + # Create a copy to avoid modifying original data |
| 200 | + processed = round_results.copy() |
| 201 | + |
| 202 | + # Sort scores alphabetically by key |
| 203 | + scores = dict(sorted(round_results["scores"].items())) |
| 204 | + processed["scores"] = scores |
| 205 | + processed["sorted_scores"] = list(scores.items()) |
| 206 | + |
| 207 | + # Calculate winner percentage |
| 208 | + winner = round_results.get("winner") |
| 209 | + if winner and scores: |
| 210 | + total_games = sum(scores.values()) |
| 211 | + if total_games > 0: |
| 212 | + if winner != "Tie": |
| 213 | + winner_wins = scores.get(winner, 0) |
| 214 | + ties = scores.get("Tie", 0) |
| 215 | + win_percentage = round(((winner_wins + 0.5 * ties) / total_games) * 100, 1) |
| 216 | + processed["winner_percentage"] = win_percentage |
| 217 | + else: |
| 218 | + processed["winner_percentage"] = None # No percentage for ties |
| 219 | + else: |
| 220 | + processed["winner_percentage"] = None |
| 221 | + else: |
| 222 | + processed["winner_percentage"] = None |
| 223 | + |
| 224 | + return processed |
155 | 225 |
|
156 | 226 |
|
157 | 227 | @dataclass |
@@ -225,15 +295,20 @@ def parse_game_metadata(self) -> GameMetadata: |
225 | 295 | round_results = None |
226 | 296 | if results_file.exists(): |
227 | 297 | round_results = json.loads(results_file.read_text()) |
| 298 | + round_results = process_round_results(round_results) |
228 | 299 |
|
229 | 300 | rounds.append({"round_num": round_num, "sim_logs": sim_logs, "results": round_results}) |
230 | 301 |
|
| 302 | + # Extract agent information |
| 303 | + agent_info = get_agent_info_from_metadata(results) if results else [] |
| 304 | + |
231 | 305 | return GameMetadata( |
232 | 306 | results=results, |
233 | 307 | main_log=main_log, |
234 | 308 | main_log_path=main_log_path, |
235 | 309 | metadata_file_path=metadata_file_path, |
236 | 310 | rounds=rounds, |
| 311 | + agent_info=agent_info, |
237 | 312 | ) |
238 | 313 |
|
239 | 314 | def parse_trajectory(self, player_id: int, round_num: int) -> TrajectoryInfo | None: |
|
0 commit comments