Skip to content

symfonic.capabilities.tools.execution.retry

retry

Retry scheduling for tool dispatch (T3.1.3).

Retrying is only ever correct for a failure whose next attempt could differ. A transport hiccup qualifies; a ValueError from bad arguments does not — retrying that burns latency and money for a result that cannot change, and every extra hop is another chance to trip the loop cut. retry_on is therefore a declared set, not a catch-all.

The default schedule is one attempt: existing dispatch behaviour, stated rather than implied.

RetrySchedule dataclass

RetrySchedule(max_attempts: int = 1, backoff_seconds: float = 0.0, multiplier: float = 2.0, retry_on: tuple[type[BaseException], ...] = (Exception,))

How many attempts a tool call gets, and how long between them.

delay_for

delay_for(attempt: int) -> float

Seconds to wait before attempt attempt + 1 (1-based).

Source code in src/symfonic/capabilities/tools/execution/retry.py
def delay_for(self, attempt: int) -> float:
    """Seconds to wait before attempt ``attempt + 1`` (1-based)."""
    if self.backoff_seconds <= 0:
        return 0.0
    return self.backoff_seconds * (self.multiplier ** max(0, attempt - 1))

should_retry

should_retry(attempt: int, exc: BaseException) -> bool

Is attempt (1-based) allowed another try after exc?

Source code in src/symfonic/capabilities/tools/execution/retry.py
def should_retry(self, attempt: int, exc: BaseException) -> bool:
    """Is ``attempt`` (1-based) allowed another try after ``exc``?"""
    if attempt >= max(1, self.max_attempts):
        return False
    return isinstance(exc, self.retry_on)