v0.3.1
Bug fixes
llm.providerwas silently dropped (#472):LLMConfigpropagates shared settings to each per-modelLLMModelConfigvia ashared_configdict, but that dict omittedprovider. Every model keptprovider=None, soLLMEnsemblerouted them all to the OpenAI backend regardless of the config — a config withprovider: claude_codecrashed with a missing-OPENAI_API_KEYerror, makingexamples/claude_code_quickstartunusable. An explicit per-modelproviderstill takes precedence.
Features
run_evolution()acceptstarget_scoreandcheckpoint_path(#457): both already existed oncontroller.run()but were not exposed, so library users could not resume from a checkpoint or stop at a target score.
New example
-
examples/background_blur: evolving a hot function behind a hard quality gate — the score is a speedup, but fidelity is pass/fail, so a fast-but-wrong candidate scores zero. Deterministic and numpy-only (no webcam, GPU, model or dataset). Demonstrates cascade evaluation (cheap smoke → quality gate → benchmark, so timing is only spent on candidates that are already correct), artifacts that tell the model why it was rejected, and a(complexity, ssim)MAP-Elites grid.It documents two traps worth knowing about:
- The obvious quality gate is exploitable. Grading mean and worst-frame SSIM lets a "blur frame 0's background and reuse it forever" candidate score 47x while leaving a visible person-shaped ghost — it damages one region and the frame average hides it. Grading the worst 16×16 region catches it. The cheats are encoded as tests so they must lose.
- Timing-as-fitness needs care. Caching a single baseline measurement lets a transiently loaded machine inflate every later speedup.
Full changelog: v0.3.0...v0.3.1