# `ADK.Plugin.ReflectRetry`
[🔗](https://github.com/zeroasterisk/adk-elixir/blob/main/lib/adk/plugin/reflect_retry.ex#L1)

A plugin that validates LLM responses and retries with reflection feedback
when they don't meet quality criteria.

## Configuration

    # Basic — retries on error events only (default behaviour)
    ADK.Plugin.register({ADK.Plugin.ReflectRetry, max_retries: 3})

    # With custom validation — retries when validator returns {:error, reason}
    ADK.Plugin.register({ADK.Plugin.ReflectRetry,
      max_retries: 3,
      validator: fn events ->
        text = events |> Enum.map_join("\n", &ADK.Event.text/1)
        if String.contains?(text, "I don't know"),
          do: {:error, "Response was evasive — provide a concrete answer"},
          else: :ok
      end
    })

    # With custom reflection template
    ADK.Plugin.register({ADK.Plugin.ReflectRetry,
      max_retries: 2,
      validator: &MyApp.validate_response/1,
      reflection_template: "Attempt {attempt}/{max}: {reason}\n\nPlease revise your response."
    })

## How it works

In `after_run/3`, this plugin:

1. Checks for error events (events with non-nil `:error` field)
2. If no errors and a `:validator` function is configured, calls it with the events
3. If validation fails (or errors found), builds a reflection message and re-runs the agent
4. Repeats up to `:max_retries` times
5. Returns whatever the last attempt produced if retries are exhausted

## Validator function

The validator receives the list of events and must return:
- `:ok` — response is acceptable
- `{:error, reason}` — response failed validation; `reason` is included in reflection

## Reflection template

The template string supports these placeholders:
- `{attempt}` — current attempt number (1-based)
- `{max}` — max retries configured
- `{reason}` — the error/validation failure reason

Default: `"[Reflect & Retry — Attempt {attempt}/{max}] {reason}\n\nPlease try again, adjusting your approach."`

# `config`

```elixir
@type config() :: [
  max_retries: pos_integer(),
  validator: validator() | nil,
  reflection_template: String.t()
]
```

# `state`

```elixir
@type state() :: %{
  max_retries: pos_integer(),
  validator: validator() | nil,
  reflection_template: String.t(),
  retry_counts: %{required(String.t()) =&gt; non_neg_integer()}
}
```

# `validator`

```elixir
@type validator() :: ([ADK.Event.t()] -&gt; :ok | {:error, String.t()})
```

# `build_reflection_events`

```elixir
@spec build_reflection_events([ADK.Event.t()], pos_integer()) :: [ADK.Event.t()]
```

Build reflection events from error events (legacy helper).

# `check_events`

```elixir
@spec check_events([ADK.Event.t()], state()) :: :ok | {:error, String.t()}
```

Check events for errors or validation failures.

# `has_error?`

```elixir
@spec has_error?(ADK.Event.t()) :: boolean()
```

Check if an event has an error.

---

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