2424from trpc_agent_sdk .evaluation import CallAgent
2525from trpc_agent_sdk .evaluation import EvalCaseResult
2626from trpc_agent_sdk .evaluation import EvalSet
27- from trpc_agent_sdk .evaluation import EvalStatus
2827from trpc_agent_sdk .evaluation import OptimizeConfigFile
2928from trpc_agent_sdk .evaluation import TargetPrompt
3029from trpc_agent_sdk .evaluation import load_optimize_config
4140from .config import PipelineConfig
4241from .config import load_pipeline_config
4342from .evaluation_adapter import EvaluationAnalysisError
43+ from .evaluation_adapter import standardize_snapshot
4444from .fake import DeterministicFakeModel
4545from .gate import evaluate_gate
4646from .gate import GateEvaluationError
@@ -473,22 +473,6 @@ def prepare_run(pipeline_config_path: str | Path, *, run_id: str | None = None)
473473 raise
474474
475475
476- def _summarize_results (
477- eval_results_by_eval_id : dict [str , list [EvalCaseResult ]],
478- ) -> tuple [int , int , float | None ]:
479- passed_cases = 0
480- scores : list [float ] = []
481- for runs in eval_results_by_eval_id .values ():
482- if runs and all (getattr (run , "final_eval_status" , None ) == EvalStatus .PASSED for run in runs ):
483- passed_cases += 1
484- for run in runs :
485- for metric in getattr (run , "overall_eval_metric_results" , []):
486- if metric .score is not None :
487- scores .append (float (metric .score ))
488- average_score = sum (scores ) / len (scores ) if scores else None
489- return passed_cases , len (eval_results_by_eval_id ), average_score
490-
491-
492476def _validate_results (
493477 * ,
494478 eval_set : EvalSet ,
@@ -547,18 +531,34 @@ async def _evaluate_split(
547531 phase = phase ,
548532 split = split ,
549533 )
550- passed_cases , total_cases , average_score = _summarize_results (eval_results_by_eval_id )
551- return EvaluationSnapshot (
534+ snapshot = EvaluationSnapshot (
552535 phase = phase ,
553536 split = split ,
554537 eval_set_id = eval_set .eval_set_id ,
555538 failed_summary = failed_summary ,
556539 details_lines = details_lines ,
557540 result_lines = result_lines ,
558541 eval_results_by_eval_id = eval_results_by_eval_id ,
559- passed_case_count = passed_cases ,
560- total_case_count = total_cases ,
561- average_score = average_score ,
542+ passed_case_count = 0 ,
543+ total_case_count = len (eval_results_by_eval_id ),
544+ average_score = None ,
545+ )
546+ try :
547+ standardized = standardize_snapshot (snapshot )
548+ except EvaluationAnalysisError as exc :
549+ raise PipelineStageExecutionError (
550+ f"{ phase } { split } evaluation result standardization failed: { exc } "
551+ ) from exc
552+ return snapshot .model_copy (
553+ update = {
554+ "passed_case_count" : standardized .passed_case_count ,
555+ "total_case_count" : len (standardized .cases ),
556+ "average_score" : (
557+ standardized .average_score .value
558+ if standardized .average_score .status == "available"
559+ else None
560+ ),
561+ }
562562 )
563563
564564
@@ -567,14 +567,34 @@ async def _restore_working_baseline(
567567 baseline_prompts : dict [str , str ],
568568) -> bool :
569569 """Restore optimizer leftovers and prove the isolated baseline is present."""
570+ initial_read_error : Exception | None = None
571+ was_modified = True
570572 try :
571573 current = await prepared .working_target .read_all ()
574+ except Exception as exc :
575+ initial_read_error = exc
576+ else :
572577 was_modified = current != baseline_prompts
573- if was_modified :
578+
579+ if was_modified :
580+ try :
574581 await prepared .working_target .write_all (baseline_prompts )
582+ except Exception as exc :
583+ if initial_read_error is not None :
584+ raise PipelineStageExecutionError (
585+ "failed to restore optimizer working prompts after initial "
586+ f"read failed ({ initial_read_error } ): { exc } "
587+ ) from exc
588+ raise PipelineStageExecutionError (
589+ f"failed to restore optimizer working prompts: { exc } "
590+ ) from exc
591+
592+ try :
575593 restored = await prepared .working_target .read_all ()
576594 except Exception as exc :
577- raise PipelineStageExecutionError (f"failed to restore optimizer working prompts: { exc } " ) from exc
595+ raise PipelineStageExecutionError (
596+ f"failed to verify restored optimizer working prompts: { exc } "
597+ ) from exc
578598 if restored != baseline_prompts :
579599 raise PipelineStageExecutionError ("optimizer working prompts did not match baseline after restoration" )
580600 return was_modified
@@ -592,7 +612,6 @@ async def _execute_offline_stage(
592612 the isolated working target on success or candidate-evaluation failure so
593613 the run can be inspected later.
594614 """
595- progress .enter ("baseline_train" )
596615 if prepared .config .execution .mode != "offline" :
597616 raise PipelineStageExecutionError (
598617 "run_offline_stage requires execution.mode='offline', got "
@@ -756,7 +775,6 @@ async def _execute_real_stage(
756775 progress : _MutableReportProgress ,
757776) -> RealStageResult :
758777 """Generate a real optimizer candidate and run the full guarded regression."""
759- progress .enter ("baseline_train" )
760778 if prepared .config .execution .mode != "real" :
761779 raise PipelineStageExecutionError (
762780 f"run_real_stage requires execution.mode='real', got { prepared .config .execution .mode !r} "
0 commit comments