How to Configure ModelRetrySettings and Custom Retry Policies in openai-agents-python
Configure ModelRetrySettings with max_retries, backoff, and a custom policy callback to control how the OpenAI Agents Python SDK handles failed model calls.
The openai-agents-python SDK provides a declarative retry system that lets you define both the timing and the logic for re-attempting failed model requests. Understanding how to configure ModelRetrySettings and implement custom retry policies ensures your agents remain resilient against transient failures without overwhelming the API.
Understanding the Retry Architecture
The retry system operates in two distinct layers orchestrated by the runner.
Runner-Managed Retry Settings
The first layer defines how many retries occur and the back-off timing between attempts. This is configured via ModelRetrySettings in src/agents/retry.py, which supports an optional policy callback that determines if a retry should be performed at all.
Policy Evaluation Layer
The second layer provides the decision logic. The runtime evaluates errors—examining status codes, Retry-After headers, network failures, and provider-suggested advice—to return a RetryDecision. This logic resides in src/agents/retry.py and is applied at runtime in src/agents/run_internal/model_retry.py.
Configuring ModelRetrySettings
ModelRetrySettings accepts three key parameters that control retry behavior.
| Field | Type | Description | Default |
|---|---|---|---|
max_retries |
int | None |
Additional attempts after the initial request. None means no limit. |
None |
backoff |
ModelRetryBackoffSettings | dict | None |
Controls delay between retries when the policy does not supply an explicit delay. |
None (SDK defaults: 0.25s initial, 2s max, multiplier 2, jitter True) |
policy |
Callable[[RetryPolicyContext], bool | RetryDecision] |
User-defined callback inspecting the error and deciding whether to retry. Runtime-only, not serialized. | None |
Fine-Tuning Backoff Behavior
Use ModelRetryBackoffSettings to customize exponential back-off parameters.
from agents import ModelRetryBackoffSettings
backoff = ModelRetryBackoffSettings(
initial_delay=0.5, # seconds before first retry
max_delay=5.0, # ceiling for the delay
multiplier=2.0, # exponential factor
jitter=True, # random ±25% jitter
)
Implementation reference: src/agents/retry.py lines 15-31 and the to_json_dict helper.
Using Built-in Retry Policies
The SDK provides a retry_policies DSL in src/agents/retry.py for constructing composable policies without writing custom logic.
| Policy | Description |
|---|---|
never() |
Never retry failed requests. |
provider_suggested() |
Follow the provider's ModelRetryAdvice (e.g., x-should-retry header). |
network_error() |
Match network-level failures (APIConnectionError, APITimeoutError, etc.). |
retry_after() |
Respect Retry-After headers or provider advice delays. |
http_status(codes) |
Target specific HTTP status codes (e.g., 429, 503). |
any(*policies) |
Succeed if any policy indicates retry (short-circuit). |
all(*policies) |
Require all policies to agree on retrying. |
Combining Multiple Policies
Use retry_policies.any() to create a fallback chain that checks multiple conditions.
from agents import ModelRetrySettings, retry_policies
retry = ModelRetrySettings(
max_retries=3,
policy=retry_policies.any(
retry_policies.provider_suggested(),
retry_policies.retry_after(),
retry_policies.network_error(),
retry_policies.http_status([408, 409, 429, 500, 502, 503, 504]),
),
)
Reference: retry_policies DSL implementation in src/agents/retry.py lines 31-60.
Implementing Custom Retry Policies
For fine-grained control, implement a custom policy callback that receives a RetryPolicyContext and returns a bool or RetryDecision.
Understanding the Policy Context
The RetryPolicyContext provides rich information about the failure:
normalized: AModelRetryNormalizedErrorwith boolean flags likeis_timeout,is_network_error,is_rate_limit.attempt: The current retry attempt number.provider_advice: OptionalModelRetryAdvicefrom the provider (e.g.,retry_afterseconds).http_status: The HTTP status code if applicable.
Writing a Custom Policy
from agents import ModelRetrySettings, RetryDecision, RetryPolicyContext
def timeout_only_policy(context: RetryPolicyContext) -> RetryDecision:
"""Only retry on timeout errors with a fixed 2-second delay."""
if context.normalized.is_timeout:
return RetryDecision(retry=True, delay=2.0, reason="timeout")
return RetryDecision(retry=False, reason="non-timeout")
retry = ModelRetrySettings(
max_retries=5,
policy=timeout_only_policy,
)
Supporting Async Policies
The runner automatically detects async callbacks in _call_retry_policy (src/agents/run_internal/model_retry.py lines 51-58). You can use async def for policies that require asynchronous operations (e.g., fetching dynamic back-off values from an external service).
async def async_policy(context: RetryPolicyContext) -> RetryDecision:
# Perform async work here if needed
if context.attempt > 3:
return RetryDecision(retry=False, reason="Too many attempts")
return RetryDecision(retry=True, delay=1.0)
Complete Configuration Example
Combine built-in policies with a custom wrapper to enforce application-specific constraints.
from agents import (
ModelRetrySettings,
RetryDecision,
retry_policies,
ModelSettings,
RunConfig,
)
# 1. Combine built-in policies
base_policy = retry_policies.any(
retry_policies.provider_suggested(),
retry_policies.retry_after(),
retry_policies.network_error(),
retry_policies.http_status([408, 409, 429, 500, 502, 503, 504]),
)
# 2. Wrap with custom logic to cap delays and log attempts
async def policy_wrapper(context):
raw = base_policy(context)
decision = await raw if hasattr(raw, "__await__") else raw
if isinstance(decision, RetryDecision) and decision.delay:
# Cap backoff at 4 seconds
decision.delay = min(decision.delay, 4.0)
print(f"Retry {context.attempt}: waiting {decision.delay}s due to {decision.reason}")
return decision
# 3. Configure settings
retry_cfg = ModelRetrySettings(
max_retries=4,
backoff={"initial_delay": 0.5, "max_delay": 5.0, "multiplier": 2.0, "jitter": True},
policy=policy_wrapper,
)
run_config = RunConfig(model_settings=ModelSettings(retry=retry_cfg))
Apply retry_cfg globally via RunConfig or override per-agent via Agent.model_settings. The SDK merges configurations with per-agent values taking precedence.
Reference implementation: examples/basic/retry.py lines 21-84.
Runtime Implementation
When executing model requests, get_response_with_retry and stream_response_with_retry in src/agents/run_internal/model_retry.py orchestrate the retry flow:
- Initial Request: Calls the model with provider-managed retries disabled when necessary.
- Error Analysis: On exception, builds a
ModelRetryAdviceRequestand queries the model adapter for provider-specific advice. - Policy Evaluation: Invokes
_evaluate_retrywhich normalizes the error (ModelRetryNormalizedError), applies the user'spolicy, and falls back to default back-off (_default_retry_delay). - State Reset: If retrying, rewinds conversation state and sleeps for the computed delay before re-attempting.
See the core loop around lines 31-71 in src/agents/run_internal/model_retry.py.
Summary
- ModelRetrySettings controls retry count, back-off timing, and policy logic in
src/agents/retry.py. - Built-in policies via
retry_policiesprovide declarative matching for network errors, HTTP statuses, provider advice, andRetry-Afterheaders. - Custom policies receive
RetryPolicyContextand returnboolorRetryDecision, supporting both sync and async implementations. - Configuration hierarchy applies settings via
RunConfigfor global defaults orAgent.model_settingsfor per-agent overrides. - Runtime execution occurs in
src/agents/run_internal/model_retry.py, which normalizes errors and applies your policy before each retry attempt.
Frequently Asked Questions
What is the default retry behavior if I don't configure ModelRetrySettings?
If you do not provide ModelRetrySettings, the SDK uses an unlimited retry count (max_retries=None) with default back-off parameters (0.25s initial delay, 2s maximum, multiplier of 2, and jitter enabled). The default policy defers to the provider's suggestion via retry_policies.provider_suggested(), falling back to standard back-off for rate limits and transient errors.
How do I disable retries entirely for a specific agent?
Pass ModelRetrySettings with max_retries=0 and policy=retry_policies.never() to ensure the runner makes only a single attempt. Attach this to the agent's model_settings parameter: Agent(..., model_settings=ModelSettings(retry=ModelRetrySettings(max_retries=0, policy=retry_policies.never()))).
Can I use async functions for custom retry policies?
Yes, the runner automatically detects async callbacks in _call_retry_policy within src/agents/run_internal/model_retry.py (lines 51-58). You can define async def my_policy(context: RetryPolicyContext) -> RetryDecision to perform asynchronous operations like fetching dynamic back-off values from external configuration services.
Where can I find working examples of retry configuration?
The repository includes a complete runnable example at examples/basic/retry.py (lines 21-84). This script demonstrates combining multiple built-in policies with retry_policies.any(), overriding back-off values via dictionary syntax, and logging each retry attempt. Additionally, the reference documentation in docs/ref/retry.md provides auto-generated API details for all retry-related classes.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →