# `GEPA`
[🔗](https://github.com/nshkrdotcom/gepa_ex/blob/v0.3.0/lib/gepa.ex#L1)

GEPA: Genetic-Pareto optimizer for text-based system components.

## Basic Example

    trainset = [%{input: "What is 2+2?", answer: "4"}, ...]
    valset = [%{input: "What is 5+5?", answer: "10"}]

    {:ok, result} = GEPA.optimize(
      seed_candidate: %{"instruction" => "You are a helpful assistant."},
      trainset: trainset,
      valset: valset,
      adapter: GEPA.Adapters.Basic.new(),
      max_metric_calls: 100
    )

    IO.puts("Best score: #{GEPA.Result.best_score(result)}")
    IO.inspect(GEPA.Result.best_candidate(result))

## With LLM-based Reflection

    llm = GEPA.LLM.req_llm(:openai, model: "gpt-5.4-mini")

    {:ok, result} = GEPA.optimize(
      seed_candidate: %{"instruction" => "You are a helpful assistant."},
      trainset: trainset,
      valset: valset,
      adapter: GEPA.Adapters.Basic.new(),
      max_metric_calls: 100,
      reflection_llm: llm
    )

This uses the LLM to propose improved instructions based on execution feedback,
rather than using a simple placeholder improvement.

# `default_adapter`

```elixir
@spec default_adapter(keyword()) :: GEPA.Adapters.Default.t()
```

Build the official-style default adapter.

This is a top-level convenience for callers coming from the upstream Python
surface. It delegates to `GEPA.Adapters.Default.new/1`.

# `optimize`

```elixir
@spec optimize(Keyword.t()) :: {:ok, GEPA.Result.t()}
```

Run GEPA optimization.

## Options

### Required
- `:seed_candidate` - Initial program as map of component -> text
- `:trainset` - Training data (list or DataLoader)
- `:adapter` - Adapter module/struct implementing GEPA.Adapter

If `:adapter` is omitted, provide `:task_lm` or `:model` and GEPA will build
the default adapter. If `:valset` is omitted, GEPA reuses `:trainset`.

At least one stopping path is required: `:max_metric_calls`,
`:max_reflection_cost`, `:max_candidate_proposals`, `:stop_conditions`,
`:stop_callbacks`, or `:run_dir` (which adds a `gepa.stop` file stopper).

### Optional
- `:valset` - Validation data (list or DataLoader, default: `:trainset`)
- `:candidate_selection_strategy` / `:candidate_selector` - `:pareto`,
  `:current_best`, `:epsilon_greedy`, `:top_k_pareto`, or a custom selector
  (default: `:pareto`)
- `:batch_sampler` - Batch sampler or `:epoch_shuffled` (default:
  `:epoch_shuffled`)
- `:module_selector` - `:round_robin`, `:all`, or a custom component selector
  (default: `:round_robin`)
- `:val_evaluation_policy` - `:full_eval` or a custom evaluation policy
  (default: `:full_eval`)
- `:reflection_minibatch_size` - Minibatch size (default: 3)
- `:perfect_score` - Perfect score value (default: 1.0)
- `:skip_perfect_score` - Skip if perfect (default: true)
- `:seed` - Random seed (default: 0)
- `:run_dir` - Directory for state persistence (default: nil)
- `:reflection_llm` - LLM for generating improved instructions (default: nil)
- `:custom_candidate_proposer` - Function used when no reflection LLM or adapter proposer is available
- `:proposal_template` - Custom template for instruction proposal (default: built-in)
- `:structured_output` - Use tool_use / function calling for instruction proposals (default: false)
- `:acceptance_criterion` - Candidate acceptance criterion (default: `:strict_improvement`)
- `:cache_evaluation` - Build an evaluation cache automatically (default: `false`)
- `:raise_on_exception` - Propagate proposer/evaluator exceptions (default: `true`)
- `:use_merge` - Enable merge proposer construction (default: `false`)
- `:max_merge_invocations` - Maximum merge attempts when merge is enabled (default: 5)
- `:merge_val_overlap_floor` - Minimum shared validation IDs for merge subsamples (default: 5)
- `:callbacks` - Synchronous observational callbacks (default: `[]`)
- `:track_best_outputs` - Track best validation outputs in state/result (default: `false`)
- `:frontier_type` - Pareto frontier mode: `:instance`, `:objective`, `:hybrid`, or `:cartesian`
  (default: `:instance`)
- `:progress` - Enable progress display (default: false). Can be `true` or a keyword
  list with options: `[width: 60, color: true]`

## Returns

`{:ok, result}` where result is a `GEPA.Result` struct

## LLM-based Reflection

When `:reflection_llm` is provided, GEPA uses the LLM to propose improved
instruction texts based on feedback from execution traces. This is the
recommended mode for production use.

Without `:reflection_llm`, the adapter must implement `propose_new_texts/4`
or `/3`, or you must pass `:custom_candidate_proposer`. GEPA does not use a
placeholder production mutation path.

## Custom Templates

When using `:reflection_llm`, you can customize the prompt template with
`:proposal_template`. The template must include these placeholders:

- `<curr_param>` - Current instruction text
- `<side_info>` - Formatted examples with feedback

Legacy `{component_name}`, `{current_instruction}`, and
`{reflective_dataset}` templates are still accepted for existing Elixir
callers.

Example:

    custom_template = """
    Improve this instruction:
    Current: <curr_param>
    Examples: <side_info>
    New instruction:
    """

    GEPA.optimize(..., reflection_llm: llm, proposal_template: custom_template)

# `optimize_anything`

```elixir
@spec optimize_anything(keyword() | map() | GEPA.OptimizeAnything.Config.t()) ::
  {:ok, GEPA.Result.t()} | {:error, term()}
```

Optimize an arbitrary candidate/evaluator pair.

This top-level entrypoint mirrors upstream `gepa.optimize_anything` while the
implementation lives in `GEPA.OptimizeAnything.optimize_anything/1`.

---

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