33"""
44
55import copy
6- import traceback
76
87from codeclash .agents import get_agent
98from codeclash .agents .abstract import Player
109from codeclash .games import get_game
1110from codeclash .games .abstract import CodeGame
1211from codeclash .tournaments .abstract import AbstractTournament
1312from codeclash .tournaments .utils .git_utils import filter_git_diff
14- from codeclash .utils .environment import assert_zero_exit_code , create_file_on_container
1513from codeclash .utils .log import get_logger
1614
1715
@@ -45,6 +43,7 @@ def run(self):
4543 try :
4644 for round_num in range (1 , self .rounds + 1 ):
4745 self .run_training_round (round_num )
46+ self .evaluate ()
4847 finally :
4948 self .cleanup ()
5049
@@ -65,76 +64,65 @@ def run_training_round(self, round_num: int) -> None:
6564 round_log_path .write_text (log_output )
6665
6766 # Copy log to main agent environment only
68- self ._copy_game_log_to_agent ([ self .agent ] , round_num , log_output )
67+ self ._copy_game_log_to_agent (self .agent , round_num , log_output )
6968
7069 self .run_main_agent (round_num )
71- self .run_mirror_agent (round_num )
70+ mirror_agent_state = round_num - 1 if round_num > 1 else 0
71+ self .set_mirror_state_to_round (mirror_agent_state )
72+
73+ self .logger .info ("Round completed." )
7274
7375 def run_main_agent (self , round_num : int ):
7476 """Run the main agent for the current round."""
7577 self .agent .pre_run_hook (new_round = round_num )
7678 self .agent .run ()
7779 self .agent .post_run_hook (round = round_num )
7880
79- def run_mirror_agent (self , round_num : int ):
81+ def set_mirror_state_to_round (self , round_num : int ):
8082 """Update mirror agent's codebase with the main agent's changes."""
81- if round_num == 1 :
82- self .logger .info ("Skipping updating mirror agent for round 1" )
83- return
84-
85- # Set mirror agent's codebase to the main agent's codebase of the previous round
86- full_diff = self .agent .get_metadata ()["diff" ][round_num - 1 ]
87-
88- full_diff = filter_git_diff (full_diff )
89-
90- if full_diff .strip ():
91- self .logger .debug (
92- assert_zero_exit_code (
93- self .mirror_agent .environment .execute (
94- "git reset --hard && git clean -fd"
95- )
96- )
97- )
98-
99- create_file_on_container (
100- container = self .mirror_agent .environment , # type: ignore
101- content = full_diff ,
102- dest_path = "tmp_patch.txt" ,
103- )
104-
105- self .logger .info ("Applying patch to mirror agent's codebase" )
106- self .logger .debug (f"Full diff: { full_diff } " )
107-
108- commands = ["git status" , "git apply tmp_patch.txt" , "rm -f tmp_patch.txt" ]
109- for cmd in commands :
110- self .logger .debug (f"Executing command: { cmd } " )
111- out = assert_zero_exit_code (
112- self .mirror_agent .environment .execute (cmd ), logger = self .logger
113- )
114- self .logger .debug (out )
83+ if round_num == 0 :
84+ full_diff = ""
11585 else :
116- self .logger .info ("No diff found for mirror agent, skipping update" )
117-
118- def _copy_game_log_to_agent (
119- self , agents : list , round_num : int , log_output : str
120- ) -> None :
121- """Copy round logs to agent environments and local directory."""
122- for agent in agents :
123- try :
124- create_file_on_container (
125- container = agent .environment ,
126- content = log_output ,
127- dest_path = f"logs/round_{ round_num } .log" ,
128- )
129- except Exception :
130- self .logger .error (
131- f"Error creating round log in { agent .name } 's container: { traceback .format_exc ()} "
132- )
133- else :
134- self .logger .info (f"Created round log in { agent .name } 's container." )
86+ full_diff = self .agent .get_metadata ()["diff" ][round_num ]
87+ full_diff = filter_git_diff (full_diff )
13588
136- self .logger . info ( "Round completed." )
89+ self .mirror_agent . reset_and_apply_patch ( full_diff )
13790
13891 def cleanup (self ):
13992 """Clean up game resources."""
14093 self .game .end (self .cleanup_on_end )
94+
95+ def evaluate (self , n_repetitions : int = 3 ):
96+ """Evaluate the agent's performance by
97+ calculating the matrix of every round against each other.
98+ """
99+ p1 = get_agent (self .config ["player" ], self .config ["prompts" ], self .game )
100+ p1 .name = "p1"
101+ p2 = get_agent (self .config ["player" ], self .config ["prompts" ], self .game )
102+ p2 .name = "p2"
103+ matrix = {
104+ p1_round : {p2_round : [] for p2_round in range (0 , self .rounds + 1 )}
105+ for p1_round in range (0 , self .rounds + 1 )
106+ }
107+ for p1_round in range (0 , self .rounds + 1 ):
108+ for p2_round in range (0 , self .rounds + 1 ):
109+ self .logger .info (
110+ f"Evaluating agent at round { p1_round } against agent at round { p2_round } "
111+ )
112+ p1_patch = (
113+ self .agent .get_metadata ()["diff" ][p1_round ] if p1_round > 0 else ""
114+ )
115+ p2_patch = (
116+ self .agent .get_metadata ()["diff" ][p2_round ] if p2_round > 0 else ""
117+ )
118+ p1 .reset_and_apply_patch (p1_patch )
119+ p2 .reset_and_apply_patch (p2_patch )
120+ for i_repetition in range (n_repetitions ):
121+ result = self .game .run_round ([p1 , p2 ])
122+ winner = result ["winner" ]
123+ self .logger .info (
124+ f"Round { p1_round } vs { p2_round } repetition { i_repetition } winner: { winner } "
125+ )
126+ matrix [p1_round ][p2_round ].append (winner )
127+ self .logger .info (f"Evaluation matrix: { matrix } " )
128+ return matrix
0 commit comments