@@ -230,6 +230,19 @@ async def _log_redteam_results_to_mlflow(
230
230
f .write (json .dumps ({"conversations" : redteam_output .redteaming_data or []}))
231
231
elif redteam_output .red_team_result :
232
232
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 ))
233
246
234
247
# Also save a human-readable scorecard if available
235
248
if not data_only and redteam_output .red_team_result :
@@ -270,6 +283,7 @@ async def _log_redteam_results_to_mlflow(
270
283
# Log the entire directory to MLFlow
271
284
try :
272
285
eval_run .log_artifact (tmpdir , artifact_name )
286
+ eval_run .log_artifact (tmpdir , eval_info_name )
273
287
self .logger .debug (f"Successfully logged artifacts directory to MLFlow" )
274
288
except Exception as e :
275
289
self .logger .warning (f"Failed to log artifacts to MLFlow: { str (e )} " )
@@ -675,11 +689,13 @@ async def _prompt_sending_orchestrator(
675
689
# Set task status to TIMEOUT
676
690
batch_task_key = f"{ strategy_name } _{ risk_category } _batch_{ batch_idx + 1 } "
677
691
self .task_statuses [batch_task_key ] = TASK_STATUS ["TIMEOUT" ]
692
+ self .red_team_info [strategy_name ][risk_category ]["status" ] = TASK_STATUS ["INCOMPLETE" ]
678
693
# Continue with partial results rather than failing completely
679
694
continue
680
695
except Exception as e :
681
696
log_error (self .logger , f"Error processing batch { batch_idx + 1 } " , e , f"{ strategy_name } /{ risk_category } " )
682
697
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" ]
683
699
# Continue with other batches even if one fails
684
700
continue
685
701
else :
@@ -699,9 +715,11 @@ async def _prompt_sending_orchestrator(
699
715
# Set task status to TIMEOUT
700
716
single_batch_task_key = f"{ strategy_name } _{ risk_category } _single_batch"
701
717
self .task_statuses [single_batch_task_key ] = TASK_STATUS ["TIMEOUT" ]
718
+ self .red_team_info [strategy_name ][risk_category ]["status" ] = TASK_STATUS ["INCOMPLETE" ]
702
719
except Exception as e :
703
720
log_error (self .logger , "Error processing prompts" , e , f"{ strategy_name } /{ risk_category } " )
704
721
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" ]
705
723
706
724
self .task_statuses [task_key ] = TASK_STATUS ["COMPLETED" ]
707
725
return orchestrator
@@ -1266,7 +1284,6 @@ def filter(self, record):
1266
1284
output_path = result_path ,
1267
1285
)
1268
1286
eval_logger .debug (f"Completed evaluation for { risk_category .value } /{ strategy_name } " )
1269
-
1270
1287
finally :
1271
1288
# Restore original stdout and stderr
1272
1289
sys .stdout = original_stdout
@@ -1299,6 +1316,7 @@ def filter(self, record):
1299
1316
self .logger .warning (f"Failed to clean up logger: { str (e )} " )
1300
1317
self .red_team_info [self ._get_strategy_name (strategy )][risk_category .value ]["evaluation_result_file" ] = str (result_path )
1301
1318
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" ]
1302
1320
self .logger .debug (f"Evaluation complete for { strategy_name } /{ risk_category .value } , results stored in red_team_info" )
1303
1321
1304
1322
async def _process_attack (
@@ -1341,6 +1359,8 @@ async def _process_attack(
1341
1359
converter = self ._get_converter_for_strategy (strategy )
1342
1360
try :
1343
1361
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 ()} "
1344
1364
orchestrator = await call_orchestrator (self .chat_target , all_prompts , converter , strategy_name , risk_category .value , timeout )
1345
1365
except PyritException as e :
1346
1366
log_error (self .logger , f"Error calling orchestrator for { strategy_name } strategy" , e )
@@ -1370,6 +1390,7 @@ async def _process_attack(
1370
1390
except Exception as e :
1371
1391
log_error (self .logger , f"Error during evaluation for { strategy_name } /{ risk_category .value } " , e )
1372
1392
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" ]
1373
1394
# Continue processing even if evaluation fails
1374
1395
1375
1396
async with progress_bar_lock :
0 commit comments