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: A ModelRetryNormalizedError with boolean flags like is_timeout, is_network_error, is_rate_limit.
  • attempt: The current retry attempt number.
  • provider_advice: Optional ModelRetryAdvice from the provider (e.g., retry_after seconds).
  • 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:

  1. Initial Request: Calls the model with provider-managed retries disabled when necessary.
  2. Error Analysis: On exception, builds a ModelRetryAdviceRequest and queries the model adapter for provider-specific advice.
  3. Policy Evaluation: Invokes _evaluate_retry which normalizes the error (ModelRetryNormalizedError), applies the user's policy, and falls back to default back-off (_default_retry_delay).
  4. 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_policies provide declarative matching for network errors, HTTP statuses, provider advice, and Retry-After headers.
  • Custom policies receive RetryPolicyContext and return bool or RetryDecision, supporting both sync and async implementations.
  • Configuration hierarchy applies settings via RunConfig for global defaults or Agent.model_settings for 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →