@@ -230,6 +230,19 @@ async def _log_redteam_results_to_mlflow(
230230 f .write (json .dumps ({"conversations" : redteam_output .redteaming_data or []}))
231231 elif redteam_output .red_team_result :
232232 json .dump (redteam_output .red_team_result , f )
233+
234+ eval_info_name = "redteam_info.json"
235+ eval_info_path = os .path .join (self .scan_output_dir , eval_info_name )
236+ self .logger .debug (f"Saving evaluation info to scan output directory: { eval_info_path } " )
237+ with open (eval_info_path , "w" , encoding = DefaultOpenEncoding .WRITE ) as f :
238+ # Remove evaluation_result from red_team_info before logging
239+ red_team_info_logged = {}
240+ for strategy , harms_dict in self .red_team_info .items ():
241+ red_team_info_logged [strategy ] = {}
242+ for harm , info_dict in harms_dict .items ():
243+ info_dict .pop ("evaluation_result" , None )
244+ red_team_info_logged [strategy ][harm ] = info_dict
245+ f .write (json .dumps (red_team_info_logged ))
233246
234247 # Also save a human-readable scorecard if available
235248 if not data_only and redteam_output .red_team_result :
@@ -270,6 +283,7 @@ async def _log_redteam_results_to_mlflow(
270283 # Log the entire directory to MLFlow
271284 try :
272285 eval_run .log_artifact (tmpdir , artifact_name )
286+ eval_run .log_artifact (tmpdir , eval_info_name )
273287 self .logger .debug (f"Successfully logged artifacts directory to MLFlow" )
274288 except Exception as e :
275289 self .logger .warning (f"Failed to log artifacts to MLFlow: { str (e )} " )
@@ -675,11 +689,13 @@ async def _prompt_sending_orchestrator(
675689 # Set task status to TIMEOUT
676690 batch_task_key = f"{ strategy_name } _{ risk_category } _batch_{ batch_idx + 1 } "
677691 self .task_statuses [batch_task_key ] = TASK_STATUS ["TIMEOUT" ]
692+ self .red_team_info [strategy_name ][risk_category ]["status" ] = TASK_STATUS ["INCOMPLETE" ]
678693 # Continue with partial results rather than failing completely
679694 continue
680695 except Exception as e :
681696 log_error (self .logger , f"Error processing batch { batch_idx + 1 } " , e , f"{ strategy_name } /{ risk_category } " )
682697 self .logger .debug (f"ERROR: Strategy { strategy_name } , Risk { risk_category } , Batch { batch_idx + 1 } : { str (e )} " )
698+ self .red_team_info [strategy_name ][risk_category ]["status" ] = TASK_STATUS ["INCOMPLETE" ]
683699 # Continue with other batches even if one fails
684700 continue
685701 else :
@@ -699,9 +715,11 @@ async def _prompt_sending_orchestrator(
699715 # Set task status to TIMEOUT
700716 single_batch_task_key = f"{ strategy_name } _{ risk_category } _single_batch"
701717 self .task_statuses [single_batch_task_key ] = TASK_STATUS ["TIMEOUT" ]
718+ self .red_team_info [strategy_name ][risk_category ]["status" ] = TASK_STATUS ["INCOMPLETE" ]
702719 except Exception as e :
703720 log_error (self .logger , "Error processing prompts" , e , f"{ strategy_name } /{ risk_category } " )
704721 self .logger .debug (f"ERROR: Strategy { strategy_name } , Risk { risk_category } : { str (e )} " )
722+ self .red_team_info [strategy_name ][risk_category ]["status" ] = TASK_STATUS ["INCOMPLETE" ]
705723
706724 self .task_statuses [task_key ] = TASK_STATUS ["COMPLETED" ]
707725 return orchestrator
@@ -1266,7 +1284,6 @@ def filter(self, record):
12661284 output_path = result_path ,
12671285 )
12681286 eval_logger .debug (f"Completed evaluation for { risk_category .value } /{ strategy_name } " )
1269-
12701287 finally :
12711288 # Restore original stdout and stderr
12721289 sys .stdout = original_stdout
@@ -1299,6 +1316,7 @@ def filter(self, record):
12991316 self .logger .warning (f"Failed to clean up logger: { str (e )} " )
13001317 self .red_team_info [self ._get_strategy_name (strategy )][risk_category .value ]["evaluation_result_file" ] = str (result_path )
13011318 self .red_team_info [self ._get_strategy_name (strategy )][risk_category .value ]["evaluation_result" ] = evaluate_outputs
1319+ self .red_team_info [self ._get_strategy_name (strategy )][risk_category .value ]["status" ] = TASK_STATUS ["COMPLETED" ]
13021320 self .logger .debug (f"Evaluation complete for { strategy_name } /{ risk_category .value } , results stored in red_team_info" )
13031321
13041322 async def _process_attack (
@@ -1341,6 +1359,8 @@ async def _process_attack(
13411359 converter = self ._get_converter_for_strategy (strategy )
13421360 try :
13431361 self .logger .debug (f"Calling orchestrator for { strategy_name } strategy" )
1362+ if isinstance (self .chat_target ,OpenAIChatTarget ) and not self .chat_target ._headers .get ("Api-Key" , None ):
1363+ self .chat_target ._headers ["Authorization" ] = f"Bearer { self .chat_target ._token_provider ()} "
13441364 orchestrator = await call_orchestrator (self .chat_target , all_prompts , converter , strategy_name , risk_category .value , timeout )
13451365 except PyritException as e :
13461366 log_error (self .logger , f"Error calling orchestrator for { strategy_name } strategy" , e )
@@ -1370,6 +1390,7 @@ async def _process_attack(
13701390 except Exception as e :
13711391 log_error (self .logger , f"Error during evaluation for { strategy_name } /{ risk_category .value } " , e )
13721392 print (f"⚠️ Evaluation error for { strategy_name } /{ risk_category .value } : { str (e )} " )
1393+ self .red_team_info [strategy_name ][risk_category .value ]["status" ] = TASK_STATUS ["FAILED" ]
13731394 # Continue processing even if evaluation fails
13741395
13751396 async with progress_bar_lock :
0 commit comments