agent: Retry on critical error

linuztx committed Nov 18, 2025 at 18:49 UTC dbebd4114505ec46e628595705e9d4c0888e65c3
2 files changed +36 -3
agent.py
+35 -3
@@ -354,6 +354,7 @@ class Agent:
354 asyncio.run(self.call_extensions("agent_init"))
355
356 async def monologue(self):
357 + error_retries = 0 # counter for critical error retries
358 while True:
359 try:
360 # loop data dictionary to pass to extensions
@@ -453,6 +454,7 @@ class Agent:
454
455 # exceptions inside message loop:
456 except InterventionException as e:
457 + error_retries = 0 # reset retry counter on user intervention
458 pass # intervention message has been handled in handle_intervention(), proceed with conversation loop
459 except RepairableException as e:
460 # Forward repairable errors to the LLM, maybe it can fix them
@@ -462,8 +464,10 @@ class Agent:
464 PrintStyle(font_color="red", padding=True).print(msg["message"])
465 self.context.log.log(type="error", content=msg["message"])
466 except Exception as e:
465 - # Other exception kill the loop
466 - self.handle_critical_exception(e)
467 + # Retry critical exceptions before failing
468 + error_retries = await self.retry_critical_exception(
469 + e, error_retries
470 + )
471
472 finally:
473 # call message_loop_end extensions
@@ -473,9 +477,13 @@ class Agent:
477
478 # exceptions outside message loop:
479 except InterventionException as e:
480 + error_retries = 0 # reset retry counter on user intervention
481 pass # just start over
482 except Exception as e:
478 - self.handle_critical_exception(e)
483 + # Retry critical exceptions before failing
484 + error_retries = await self.retry_critical_exception(
485 + e, error_retries
486 + )
487 finally:
488 self.context.streaming_agent = None # unset current streamer
489 # call monologue_end extensions
@@ -532,6 +540,30 @@ class Agent:
540
541 return full_prompt
542
543 + async def retry_critical_exception(
544 + self, e: Exception, error_retries: int, delay: int = 3, max_retries: int = 1
545 + ) -> int:
546 + if error_retries >= max_retries:
547 + self.handle_critical_exception(e)
548 +
549 + error_message = errors.format_error(e)
550 +
551 + self.context.log.log(
552 + type="warning", content="Critical error occurred, retrying..."
553 + )
554 + PrintStyle(font_color="orange", padding=True).print(
555 + "Critical error occurred, retrying..."
556 + )
557 + await asyncio.sleep(delay)
558 + agent_facing_error = self.read_prompt(
559 + "fw.msg_critical_error.md", error_message=error_message
560 + )
561 + self.hist_add_warning(message=agent_facing_error)
562 + PrintStyle(font_color="orange", padding=True).print(
563 + agent_facing_error
564 + )
565 + return error_retries + 1
566 +
567 def handle_critical_exception(self, exception: Exception):
568 if isinstance(exception, HandledException):
569 raise exception # Re-raise the exception to kill the loop
prompts/fw.msg_critical_error.md new
+1
@@ -0,0 +1 @@
1 +This error has occurred: {{error_message}}. Proceed with your original task if possible.
\ No newline at end of file