Skip to content

v0.4.0

Latest

Choose a tag to compare

@codelion codelion released this 28 Sep 03:29
f7b6339

Highlights

  • Pluggable island selection and population strategies (#493): an optional island selector plus decision-returning hooks for admission, MAP-Elites cell replacement, archive membership, eviction and migration. ProgramDatabase validates the decisions and still owns every mutation. Default behaviour is unchanged.
  • LLM token usage tracking (#490): prompt_tokens, completion_tokens and total_tokens are captured from OpenAI-compatible responses, carried back from workers, stored in program metadata and prompt logs, and reported per iteration and as a run total.
  • GitHub Copilot CLI backend (#482): a copilot_cli provider that drives copilot -p non-interactively, using the CLI's own login, so no API key is needed.
  • Opt-in EVOLVE-BLOCK enforcement (#494): with enforce_evolve_blocks: true, every edit outside the EVOLVE-BLOCK-START/END regions is reverted to the parent code before evaluation, and responses that change or remove the markers are rejected. Markers are now recognised after any comment syntax (#, //, /*, --, %), so evolve blocks work in C, Java and other languages. Default false.
  • Custom embedding endpoint (#494): database.embedding_api_base (or OPENAI_EMBEDDING_BASE_URL) points novelty embeddings at any OpenAI-compatible endpoint, such as OpenRouter or a local server.

Bug fixes

  • Malformed SEARCH/REPLACE diffs are rejected (#494, thanks @brriorda): an extra or unmatched =======, <<<<<<< SEARCH or >>>>>>> REPLACE line used to be written into the candidate program. The whole response is now rejected before anything is applied. Custom diff_pattern values keep their own grammar.
  • Unapplied and no-op diffs are no longer evaluated (#494): a SEARCH block that matched nothing was skipped silently, so the unchanged parent was evaluated again as a "new" child. Responses where no block matches, or where the result equals the parent (including identical full rewrites), are now reported as errors, and partial matches log a warning. SEARCH lines also match when they differ only in trailing whitespace.
  • Timed-out evaluations no longer hang the worker (#485): evaluations run on a dedicated executor, so a timed-out stage returns promptly instead of blocking asyncio.run() shutdown.
  • NOT_NOVEL responses are parsed correctly (#486), including explained and Markdown-wrapped answers.
  • Non-streaming chat completions (#494): requests are sent with stream=False. Endpoints that stream by default no longer fail with 'str' object has no attribute 'choices', and a raw streamed response now raises a clear error.

Security

  • Visualizer debug mode is off by default (#494): the Flask debugger is now opt-in with --debug.

Performance

  • Checkpoints create the programs/ directory once per save instead of once per program (#478).

Docs

  • Corrected the OpenEvolve config usage examples (#479).
  • Documented enforce_evolve_blocks and embedding_api_base.

Behaviour changes to note

  • Diffs that change nothing, and full rewrites identical to the parent, are now rejected instead of evaluated.
  • extract_diffs and apply_diff raise ValueError on malformed delimiters when using the default diff pattern.

Closes #106, #346, #422, #426, #436.

Full changelog: v0.3.2...v0.4.0