Agent calls tool via _execute_tool_with_circuit_breaker (sync) or execute_tool_async (async)
2
On error, _classify_error_type tags it: timeout, rate_limit, connection_error, or unknown
3
_get_tool_retry_policy resolves the active policy (tool > agent > default)
4
If policy.should_retry(error_type, attempt) is true, wait policy.get_delay_ms(attempt) ms and retry
5
HookEvent.ON_RETRY fires before each retry with the new OnRetryInput fields
An error is tagged rate_limit when its message contains either "rate…limit" or "too many requests" — the latter catches HTTP 429 responses whose bodies use the standard phrasing without the word “limit”:
# Both of these classify as rate_limit and are retried by default:raise Exception("Rate limit exceeded")raise Exception("HTTP 429: Too Many Requests")
retry_policy=None on @tool(...) means use the fallback — the tool-level slot is treated as empty, not as “no retries”. To disable retries for a specific tool, pass an explicit RetryPolicy(max_attempts=1) instead.Tool-level (highest priority):
Do NOT pass retry_policy=None to disable retries.@tool(retry_policy=None) is treated as “no policy set here” and falls through to the agent-level or default RetryPolicy. To actually disable retries for a specific tool, pass RetryPolicy(max_attempts=1).
# ✅ Disable retries for a specific tool@tool(retry_policy=RetryPolicy(max_attempts=1))def one_shot_only(): ...# ⚠️ retry_policy=None falls through to agent/default policy — NOT "no retries"@tool(retry_policy=None)def uses_agent_or_default(): ...
In YAML the field name is still tool_retry_policy:; in Python pass retry settings through tool_config=ToolConfig(retry_policy=…). The standalone tool_retry_policy kwarg on Agent(...) was removed and raises TypeError.
Large retry counts mask real failures. If a tool fails 10+ times, there’s likely a deeper issue that retrying won’t solve. Use monitoring instead.
Always set jitter=True for rate-limited APIs
Without jitter, multiple agents retrying simultaneously create a “thundering herd” that can overwhelm rate-limited services. Jitter spreads out retry attempts.
Set narrower retry_on for expensive tools
Don’t retry LLM tools on connection_error if every attempt costs money. Use specific error types that indicate transient failures.
expensive_llm_tool_policy = RetryPolicy( max_attempts=2, retry_on={"timeout"} # Only timeout, not connection errors)
Use tool-level override sparingly
Agent-level retry policy keeps configuration DRY. Only override at the tool level for genuinely special cases like unreliable third-party APIs.