# `MingaAgent.Retry`
[🔗](https://github.com/jsmestad/minga/blob/main/lib/minga_agent/retry.ex#L1)

Exponential backoff retry logic for transient API errors.

Wraps an LLM call with automatic retries for rate limits (429),
server errors (500, 502, 503, 529), network timeouts, and connection
resets. Non-retryable errors (400, 401, 403) fail immediately.

Uses exponential backoff with jitter: base delays of 1s, 2s, 4s, 8s
plus random jitter up to 50% of the delay. Respects `Retry-After`
headers when present.

# `opts`

```elixir
@type opts() :: [
  max_retries: non_neg_integer(),
  base_delay_ms: pos_integer(),
  on_retry: (non_neg_integer(), non_neg_integer(), String.t() -&gt; :ok) | nil
]
```

Options for retry behavior.

# `retryable?`

```elixir
@spec retryable?(term()) :: boolean()
```

Returns true if the given error reason is retryable.

# `with_retry`

```elixir
@spec with_retry((-&gt; {:ok, term()} | {:error, term()}), opts()) ::
  {:ok, term()} | {:error, term()}
```

Calls the given function with retry logic on transient errors.

The function should return `{:ok, result}` or `{:error, reason}`.

Options:
- `:max_retries` - maximum number of retry attempts (default: 3)
- `:base_delay_ms` - initial backoff delay in milliseconds (default: 1000)
- `:on_retry` - callback `(attempt, delay_ms, reason)` called before each retry

## Examples

    Retry.with_retry(fn -> api_call() end, max_retries: 3)

---

*Consult [api-reference.md](api-reference.md) for complete listing*
