Skip to content

feat: comprehensive agent-readable state export in run_dir#333

Open
LakshyAAAgrawal wants to merge 6 commits into
mainfrom
feat/agent-readable-state
Open

feat: comprehensive agent-readable state export in run_dir#333
LakshyAAAgrawal wants to merge 6 commits into
mainfrom
feat/agent-readable-state

Conversation

@LakshyAAAgrawal

Copy link
Copy Markdown
Contributor

Summary

When run_dir is provided, GEPA now writes gepa_state.json — a comprehensive, agent-readable export of the full optimization state. This is designed for consumption by autonomous agents (e.g. Claude Code) that need the complete picture to propose better candidates.

What's in gepa_state.json

{
  "schema_version": 1,
  "iteration": ...,
  "total_metric_calls": ...,
  "frontier_type": ...,
  "component_names": [...],

  "candidates": [
    {
      "idx": 0,
      "texts": {"system_prompt": "..."},
      "parent_ids": [],
      "avg_val_score": 0.85,
      "num_val_scored": 100,
      "metric_calls_to_discover": 0,
      "val_scores": {"0": 0.9, "1": 0.8, ...},
      "objective_scores": {"accuracy": 0.85}
    }, ...
  ],

  "pareto_front": {
    "instance_front": { "<val_id>": {"best_score": ..., "best_candidates": [...]} },
    "objective_front": { "<metric>": {"best_score": ..., "best_candidates": [...]} }
  },

  "summary": {
    "best_candidate_idx": 7,
    "best_avg_score": 0.92,
    "pareto_front_candidate_idxs": [0, 3, 5, 7],
    "hardest_examples": [{"val_id": "3", "best_score": 0.2, ...}, ...]
  },

  "iteration_log": [...]
}

Side-info capture

Proposal evaluation data (eval_before, eval_after) is now recorded in the iteration trace with:

  • Per-example scores
  • Outputs (best-effort JSON serialization)
  • Trajectories/side_info (best-effort JSON serialization)
  • Whether the proposal was accepted/rejected
  • The proposed candidate text

This gives agents the feedback needed to understand WHY proposals succeeded or failed.

What's still missing (future work)

  • Full valset evaluation outputs/side_info — the full validation eval uses capture_traces=False for performance, so only scores are available per-candidate per-datapoint, not outputs or side_info
  • Rejected candidate texts — only accepted candidates are in program_candidates; rejected proposals are now in the iteration log but weren't before
  • Evaluation cache export — the EvaluationCache is in the pickle but not JSON-exported

Test plan

  • 447 tests pass (1 new test for agent state export)
  • pyright: 0 errors
  • ruff: 0 errors
  • New test verifies JSON structure, candidate data, pareto front, and hardest examples

🤖 Generated with Claude Code

When run_dir is provided, save() now writes `gepa_state.json` alongside
the existing pickle and JSON files. This single file gives autonomous
agents (e.g. Claude Code) the full optimization picture:

- All candidates with their texts, parent lineage, and metric call cost
- Per-candidate per-datapoint scores (prog_candidate_val_subscores)
- Per-candidate multi-objective scores
- Pareto frontier details (instance, objective, hybrid, cartesian)
- Derived analytics: best candidate, hardest examples, frontier members
- Full iteration log including evaluation side_info/trajectories

Also capture proposal evaluation data (eval_before, eval_after with
scores, outputs, and trajectories/side_info) into the iteration trace,
so agents can see WHY proposals were accepted or rejected.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@semanticdiff-com

semanticdiff-com Bot commented Apr 13, 2026

Copy link
Copy Markdown

Review changes with  SemanticDiff

Changed Files
File Status
  src/gepa/proposer/reflective_mutation/reflective_mutation.py  41% smaller
  src/gepa/core/engine.py  9% smaller
  src/gepa/core/state.py  4% smaller
  tests/test_state.py  1% smaller
  .gitignore Unsupported file format
  src/gepa/api.py  0% smaller
  src/gepa/core/adapter.py  0% smaller
  src/gepa/gepa_utils.py  0% smaller
  src/gepa/optimize_anything.py  0% smaller
  tests/test_candidate_selector.py  0% smaller

- Serialize evaluation cache to gepa_state.json: per-candidate per-datapoint
  entries with score, output, and objective_scores (keyed by candidate idx
  and data id)
- Add rejected_proposals section: each rejected proposal includes candidate
  text, parent ids, subsample data ids, before/after scores, and full
  eval_before/eval_after with trajectories/side_info
- Move try_json_serialize to gepa_utils for shared use between engine and
  state export
- Bump schema_version to 2

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@Shangyint Shangyint left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A note to ourselves: currently, the gepa_state JSON will be quite large, which is not agent-friendly. We can possibly build a directory that represents the same information but in different files.

Replaces the monolithic gepa_state.json export with a directory layout
(candidates/, pareto/, iterations/, rejected_proposals/, eval_cache/)
so agents can navigate run state without loading multi-MB blobs.
Gated behind EngineConfig.write_agent_state / gepa.optimize(write_agent_state=),
default off — when off, run_log.json / full_program_trace also stay lean
(no per-iteration eval payloads or proposed_candidate copies). gepa_state.bin
remains the single source of truth for resume; the tree is output-only.
… state

When write_agent_state is enabled, valset evaluation now bypasses the
eval cache and calls the adapter with capture_traces=True so trajectories
come through. Each accepted candidate's outputs and trajectories are
written to candidates/<idx>/outputs/<val_id>.json and
candidates/<idx>/trajectories/<val_id>.json, covering both the seed and
every reflective/merge acceptance.

Drops the eval_cache/ export from the agent directory — the in-memory
cache was not round-tripping trajectories and adds little over the other
per-candidate files. Adds ValsetEvaluation.trajectories_by_val_id as the
optional handoff channel from eval path to writer.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants