@@ -486,6 +486,27 @@ def failure_prompt(self, error):
486486 """Ask the agent to summarize remaining issues after retries."""
487487 return _failure_prompt (error )
488488
489+ def _estimate_progress (self , agent_output , check_output ):
490+ """Run a progress estimate and return parsed data or an error string."""
491+ try :
492+ return (
493+ estimate (
494+ self .prompt ,
495+ agent_output or "" ,
496+ check_output or "" ,
497+ self .cwd ,
498+ self ._yolo ,
499+ self ._flags ,
500+ self ._progress_total ,
501+ ),
502+ None ,
503+ )
504+ except Exception as exc :
505+ error = _single_line (str (exc ))
506+ if not error :
507+ error = exc .__class__ .__name__
508+ return None , error
509+
489510 def __call__ (self , debug = False , progress = False ):
490511 """Run the task with checker-driven retries.
491512 If debug is True, log debug messages.
@@ -499,29 +520,24 @@ def __call__(self, debug=False, progress=False):
499520
500521 progress_updates = progress or self ._progress_updates
501522 self ._progress_enabled = progress
523+ start_time = time .monotonic ()
524+ self ._progress_start = start_time
502525 if progress_updates :
503- remaining , _summary = estimate (
504- self .prompt ,
505- "" ,
506- "" ,
507- self .cwd ,
508- self ._yolo ,
509- self ._flags ,
510- None ,
511- )
512- self ._progress_total = remaining
513- start_time = time .monotonic ()
514- self ._progress_start = start_time
515- self .on_progress (
516- 0 ,
517- self .max_iterations ,
518- self ._progress_total ,
519- remaining ,
520- None ,
521- )
522- else :
523- start_time = time .monotonic ()
524- self ._progress_start = start_time
526+ estimate_result , estimate_error = self ._estimate_progress ("" , "" )
527+ if estimate_result is not None :
528+ remaining , _summary = estimate_result
529+ self ._progress_total = remaining
530+ self .on_progress (
531+ 0 ,
532+ self .max_iterations ,
533+ self ._progress_total ,
534+ remaining ,
535+ None ,
536+ )
537+ elif debug :
538+ _logger .debug (
539+ "Skipping initial progress update: %s" , estimate_error
540+ )
525541
526542 # Start with the initial prompt
527543 output = self .agent (self .prompt )
@@ -541,37 +557,52 @@ def __call__(self, debug=False, progress=False):
541557 check_output = self .last_check_output
542558 if self .check_skipped :
543559 check_output = "Verification skipped."
544- remaining , summary = estimate (
545- self .prompt ,
560+ progress_data = None
561+ estimate_result , estimate_error = self ._estimate_progress (
546562 self .last_output or "" ,
547563 check_output or "" ,
548- self .cwd ,
549- self ._yolo ,
550- self ._flags ,
551- self ._progress_total ,
552- )
553- total_estimate = self ._progress_total
554- if total_estimate is None or remaining > total_estimate :
555- total_estimate = remaining
556- self ._progress_total = total_estimate
557- elapsed = _format_elapsed (time .monotonic () - start_time )
558- status_prefix = (
559- f"[{ _format_turns (iteration , self .max_iterations )} @ { elapsed } ]"
560- )
561- is_final = not error or (
562- self .max_iterations and iteration >= self .max_iterations
563- )
564- if is_final :
565- marker = "✅" if not error else "❌"
566- summary = f"{ marker } { summary } " .strip ()
567- status_line = f"{ status_prefix } : { summary } " .rstrip ()
568- self .on_progress (
569- iteration ,
570- self .max_iterations ,
571- total_estimate ,
572- remaining ,
573- status_line ,
574564 )
565+ if estimate_result is not None :
566+ remaining , summary = estimate_result
567+ total_estimate = self ._progress_total
568+ if total_estimate is None or remaining > total_estimate :
569+ total_estimate = remaining
570+ self ._progress_total = total_estimate
571+ progress_data = (total_estimate , remaining , summary )
572+ else :
573+ total_estimate = self ._progress_total
574+ if total_estimate is None :
575+ if debug :
576+ _logger .debug (
577+ "Skipping progress update: %s" , estimate_error
578+ )
579+ else :
580+ summary = f"Progress estimate unavailable: { estimate_error } "
581+ progress_data = (
582+ total_estimate ,
583+ total_estimate ,
584+ summary ,
585+ )
586+ if progress_data is not None :
587+ total_estimate , remaining , summary = progress_data
588+ elapsed = _format_elapsed (time .monotonic () - start_time )
589+ status_prefix = (
590+ f"[{ _format_turns (iteration , self .max_iterations )} @ { elapsed } ]"
591+ )
592+ is_final = not error or (
593+ self .max_iterations and iteration >= self .max_iterations
594+ )
595+ if is_final :
596+ marker = "✅" if not error else "❌"
597+ summary = f"{ marker } { summary } " .strip ()
598+ status_line = f"{ status_prefix } : { summary } " .rstrip ()
599+ self .on_progress (
600+ iteration ,
601+ self .max_iterations ,
602+ total_estimate ,
603+ remaining ,
604+ status_line ,
605+ )
575606 if not error :
576607 summary = self .agent (self .success_prompt ())
577608 if debug :
0 commit comments