Immutable
release. Only release title and notes can be modified.
This release ships the reflection-LM protocol and batch-based parallel proposals ([RFC #329](#329), Phases 1 & 4) — the largest change to GEPA's proposal machinery since the project started, contributed by @Benzhang2004 in #369 and hardened through five review rounds. One breaking change is called out under Breaking & upgrade notes.
pip install -U gepaHighlights
- Multi-proposal iterations via composable strategies (#369): each iteration can now sample and evaluate many candidate proposals instead of one.
sampling_strategy=chooses the (parent, minibatch) tasks —SingleMutationSampling(default, classic GEPA),SameParentSampling(n),IndependentSampling(n),PxNSampling(p, n)— andselection_strategy=decides which improvements enter the pool:AllImprovements(default),BestImprovement,TopKImprovements(k). Defaults reproduce previous behavior exactly (pinned by replay tests against a recorded pre-change run). Full guide: [Parallel Proposals](https://gepa-ai.github.io/gepa/guides/parallel-proposals/). - The
ReflectionLMprotocol +reflection_strategy=(#369, RFC #329 Phase 1): the reflection step is now a seam. Pass a customReflectionLMimplementation togepa.optimize(reflection_strategy=...)orReflectionConfig(reflection_strategy=...)to own how reflective mutation calls the reflection model — the entry point for session-based, aggregating (ComBEE-style, #307), and coding-agent reflectors. Stateful implementations return a successor fromreflect(); chaining semantics are documented in [RFC #329](#329 (comment)). Multi-call reflectors get aReflectionProposal.metadatadiagnostics channel that flows through to callbacks, trackers, and proposal metadata. batch_evaluator=— one external call for all pending evaluations (optimize_anything): hand GEPA a function that receives every pending(candidate, example)pair in a single call (provider batch APIs, Slurm/Ray, your own cluster) and return one result per pair. Parity with the standard evaluator path: shared evaluation caching (only misses reach your function, still as one call), per-pairopt_stateswarm-start injection,raise_on_exceptionpolicy with a documented_gepa_transient_failurecontract (failures are never cached), str-candidate unwrapping, and identical output packaging.evaluator=is now optional whenbatch_evaluator=is provided — everything routes through your batch function, including refiner steps as singleton batches.- Adapters can batch: the optional
GEPAAdapter.batch_evaluateseam lets adapters parallelize multi-proposal evaluations however they like; adapters that only implementevaluate()keep working unchanged (sequential fallback). - Selection is the authority, and rejection reasons are truthful: selection strategies receive all evaluated proposals plus the acceptance criterion (built-ins filter; custom strategies may deliberately surface criterion-rejected proposals). Everything unselected fires
on_candidate_rejectedwith an accurate reason — acceptance failure, dropped-by-selection, or duplicate — and acceptance criteria may provide areject_reason(proposal, state)hook for custom messages. Criteria are judged exactly once per proposal (memoized), so stateful or stochastic criteria behave correctly. Identical child candidates within an iteration are deduplicated before valset evaluation. - Per-task run traces:
full_program_traceentries now record every task in multi-task iterations (n_tasks,taskswith per-task ids and before/after scores) and every accepted program index (new_program_indices); each proposal carries a stablemetadata["proposal_id"]. Legacy keys are preserved for existing tooling. - Finer budget events:
on_budget_updatednow fires per evaluation stage (parent minibatch, child minibatch, valset) with self-consistent deltas — totals unchanged. New tracker metricssubsample/beforeandsubsample/afterjoin the existingsubsample_score/new_subsample_scorekeys.
Fixed
optimize_anythingmerge proposals now fireGEPACallbackevents — the known issue from the v0.1.2 notes (#290 gap).TrackingLMno longer hidesbatch_completefrom wrapped callables that provide it, so batched reflection is not silently downgraded.- CI: matrix jobs no longer fail-fast, so a single-interpreter dependency failure can't masquerade as a five-version test failure.
Breaking & upgrade notes
EngineConfig.num_parallel_proposalsis removed. The v0.1.2 notes anticipated a one-release deprecation shim; we're removing the parameter outright instead — it was experimental, shipped in only two patch releases, and the replacement is strictly more expressive. Migration:num_parallel_proposals=n→EngineConfig(sampling_strategy=SameParentSampling(n))(orPxNSampling(p, n)to vary parents too), optionally withselection_strategy=.- Silent no-ops are now errors:
reflection_strategycombined withadapter.propose_new_textsorcustom_candidate_proposerraisesValueError(previously such conflicting configuration would be silently ignored);max_reflection_costwith areflection_strategythat doesn't exposetotal_costraises instead of silently never stopping. - Budget event granularity: if you aggregate
on_budget_updatedevents, summetric_calls_deltarather than counting events (counts per iteration increased; totals and monotonicity are unchanged). - Budget overshoot scales with proposal count: stop conditions are checked between iterations, so e.g.
PxNSampling(4, 4)can overrunmax_metric_callsby up to one full iteration's evaluations. See the guide's budget section. - Run directories from v0.1.3 load and resume normally; v0.1.4 adds only new trace keys.
Docs
- New guide: [Parallel Proposals](https://gepa-ai.github.io/gepa/guides/parallel-proposals/) — strategies, the evaluation-tier table (sequential /
parallel=True/batch_evaluator), the fullbatch_evaluatorcontract, budget semantics, and custom reflection strategies. - LanceDB handwritten-OCR use case added to the showcase (#393).
Thanks
@Benzhang2004 (Jialin Zhang) authored #369 and carried it through five rounds of review — and makes his first contribution to GEPA with the largest feature PR in the project's history. Thanks also to @Shangyint for design review on RFC #329, and to everyone whose issues shaped the strategy interfaces (#61, #116, #298, #324).
What's Changed
- docs: add LanceDB handwritten-OCR blog to use-cases by @LakshyAAAgrawal in #393
- feat: ReflectionLM protocol + batch-based parallel proposals (#329 Phases 1 & 4) by @Benzhang2004 in #369
New Contributors
- @Benzhang2004 made their first contribution in #369
Full Changelog: v0.1.3...v0.1.4