ADK.Plugin.ReflectRetry (ADK v0.0.1-alpha.1)

Copy Markdown View Source

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."

Summary

Functions

Build reflection events from error events (legacy helper).

Check events for errors or validation failures.

Check if an event has an error.

Types

config()

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

state()

@type state() :: %{
  max_retries: pos_integer(),
  validator: validator() | nil,
  reflection_template: String.t(),
  retry_counts: %{required(String.t()) => non_neg_integer()}
}

validator()

@type validator() :: ([ADK.Event.t()] -> :ok | {:error, String.t()})

Functions

build_reflection_events(error_events, attempt)

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

Build reflection events from error events (legacy helper).

check_events(events, state)

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

Check events for errors or validation failures.

has_error?(arg1)

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

Check if an event has an error.