# `PtcRunner.SubAgent.Loop.LLMRetry`
[🔗](https://github.com/andreasronge/ptc_runner/blob/main/lib/ptc_runner/sub_agent/loop/llm_retry.ex#L1)

LLM retry logic with configurable backoff strategies.

This module handles retrying failed LLM calls based on error classification
and backoff configuration. It supports exponential, linear, and constant
backoff strategies.

## Configuration

Retry behavior is configured via a map with the following keys:

- `max_attempts` - Maximum number of attempts (default: 1, no retries)
- `backoff` - Backoff strategy: `:exponential`, `:linear`, or `:constant` (default: `:exponential`)
- `base_delay` - Base delay in milliseconds (default: 1000)
- `retryable_errors` - List of error types to retry (default: `[:rate_limit, :timeout, :server_error]`)

## Error Classification

Errors are classified into the following types:

- `:rate_limit` - HTTP 429 errors
- `:server_error` - HTTP 5xx errors
- `:client_error` - HTTP 4xx errors (not retryable by default)
- `:timeout` - Timeout errors
- `:config_error` - LLM configuration errors
- `:unknown` - Unclassified errors

# `calculate_delay`

```elixir
@spec calculate_delay(map(), pos_integer()) :: pos_integer()
```

Calculate delay based on backoff strategy.

## Examples

    iex> PtcRunner.SubAgent.Loop.LLMRetry.calculate_delay(%{backoff: :constant, base_delay: 100}, 3)
    100

    iex> PtcRunner.SubAgent.Loop.LLMRetry.calculate_delay(%{backoff: :linear, base_delay: 100}, 3)
    300

# `call_with_retry`

Call LLM with retry logic based on retry configuration.

## Parameters

- `llm` - LLM callback function or atom reference
- `input` - LLM input map
- `llm_registry` - Registry for resolving atom LLM references
- `retry_config` - Optional retry configuration map

## Returns

- `{:ok, response}` on success
- `{:error, reason}` on failure after all retries exhausted

# `classify_error`

```elixir
@spec classify_error(term()) :: atom()
```

Classify error type for retry decision.

## Examples

    iex> PtcRunner.SubAgent.Loop.LLMRetry.classify_error({:http_error, 429, "rate limited"})
    :rate_limit

    iex> PtcRunner.SubAgent.Loop.LLMRetry.classify_error({:http_error, 500, "server error"})
    :server_error

    iex> PtcRunner.SubAgent.Loop.LLMRetry.classify_error(:timeout)
    :timeout

# `retryable?`

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

Determine if an error should be retried based on configuration.

## Examples

    iex> PtcRunner.SubAgent.Loop.LLMRetry.retryable?({:http_error, 429, "rate limited"}, %{})
    true

    iex> PtcRunner.SubAgent.Loop.LLMRetry.retryable?({:http_error, 400, "bad request"}, %{})
    false

---

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