Skip to content

Commit 9582cd5

Browse files
authored
Merge pull request #45 from scaleapi/pr2-add-vero
2 parents de55f20 + 6c333cf commit 9582cd5

256 files changed

Lines changed: 49427 additions & 87 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Python-generated files
22
__pycache__/
3+
.pytest_cache/
34
*.py[oc]
45
build/
56
dist/
@@ -9,3 +10,11 @@ wheels/
910
# Virtual environments
1011
.venv
1112
.env*
13+
14+
# Run secrets loaded via `vero harbor run --env-file` (keep only *.example)
15+
secrets.env
16+
*.secrets.env
17+
!*.example
18+
19+
# Local benchmark scoping notes (paper planning; not tracked)
20+
harness-engineering-bench/benchmark-scoping.md

README.md

Lines changed: 77 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,122 +1,112 @@
1-
# VeRO: Versioning Rewards and Observations
1+
# VeRO: a harness for agents to optimize programs, text, and agents
2+
> **Looking for the code from the VeRO paper?** See
3+
> [Paper reproduction](#paper-reproduction) — reproduce from the `paper-v1`
4+
> tag, or read the same code in place under [`legacy/`](legacy/).
25
36
[![Paper](https://img.shields.io/badge/arXiv-2602.22480-b31b1b.svg)](https://arxiv.org/abs/2602.22480)
47
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
8+
[![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](https://www.python.org/)
59

6-
VeRO is an evaluation harness for using coding agents to optimize LLM-based agents and workflows. It treats agent code as a versioned artifact — making changes, evaluating results, and hill-climbing toward better performance using git version control.
7-
8-
> **Paper**: [VeRO: An Evaluation Harness for Agents to Optimize Agents](https://arxiv.org/abs/2602.22480)
9-
10-
## Repository Structure
10+
VeRO gives a coding agent something to edit, an evaluation boundary, and durable
11+
memory of every candidate it tried. The target is anything you can put under Git
12+
and score — a **program** (a single function up to a whole codebase), **text**
13+
(a prompt, spec, or config), or an **agent** (its scaffold, tools, and prompts).
14+
VeRO was introduced to optimize agents, and the same version / evaluate / select
15+
loop applies to any of these.
1116

1217
```
13-
vero/
14-
├── vero/ # Core library (scale-vero)
15-
├── vero-agents/ # Agent implementations (benchmarking targets)
16-
├── vero-benchmarking/ # Benchmarking scripts and analysis
17-
└── LICENSE
18+
┌─────────────────────────┐ submit candidate ┌─────────────────────────┐
19+
│ candidate production ├──────────────────────►│ evaluation service │
20+
│ │ │ │
21+
│ coding agent, command, │◄──────────────────────┤ owns cases + scoring │
22+
│ or custom strategy; │ score + diagnostics │ │
23+
│ edits its own Git │ │ development: may ask │
24+
│ worktree per candidate │ │ validation: aggregate │
25+
└───────────┬─────────────┘ │ test: withheld │
26+
│ commit └───────────┬─────────────┘
27+
▼ │ report
28+
┌─────────────────────────┐ next round ┌───────────────▼─────────────┐
29+
│ candidate history: │◄──────────────────┤ selection: keep the best │
30+
│ every version kept, │ │ feasible candidate │
31+
│ each one re-selectable │ └─────────────────────────────┘
32+
└─────────────────────────┘
33+
34+
Every model call on both sides goes through the inference gateway, which holds
35+
the provider key and meters spend in tokens against a per-scope budget.
1836
```
1937

20-
### [vero/](vero/)
21-
22-
The core optimization framework. Provides:
23-
24-
- **Policy** — orchestrates the optimization loop (agent + evaluator + git)
25-
- **Agents** — VeroAgent (OpenAI Agents SDK) and ClaudeCodeAgent (Claude Agent SDK)
26-
- **Evaluator** — runs task evaluations in isolated subprocess environments
27-
- **Tools** — MCP-based tools for agents (bash, file I/O, experiment runner, dataset viewer, etc.)
28-
- **Traces** — session analysis and LLM-based trace interpretation
29-
30-
```bash
31-
cd vero && uv sync --extra optimize
32-
```
33-
34-
See [vero/README.md](vero/README.md) for full documentation.
35-
36-
### [vero-agents/](vero-agents/)
38+
The target and evaluator do not need to be Python. External evaluators and
39+
candidate producers connect through command protocols; Python benchmarks can
40+
use the optional, optimizer-independent `scale-vero-tasks` package.
3741

38-
Agent implementations used as optimization targets:
42+
Targets may live locally or in an isolated sandbox. VeRO keeps optimization
43+
state and experiment tracking on the host while running Git worktrees, producer
44+
commands, builds, and evaluation commands in the target sandbox. The core guide
45+
includes a no-bind-mount `DockerSandbox` example.
3946

40-
| Agent | Description |
41-
|-------|-------------|
42-
| **generic-agent** | General-purpose agent for MATH, GPQA, GAIA, GSM8K, etc. |
43-
| **web_search_agent** | Web search agent for SimpleQA, Facts Search |
44-
| **KIRA** | Terminal task agent for Terminal Bench 2.0 |
45-
| **tau-bench** | Customer service tool-use agent |
46-
| **pharma_summarizer** | Document summarization agent |
47+
## Repository layout
4748

48-
See [vero-agents/README.md](vero-agents/README.md) for details.
49+
| Directory | Purpose |
50+
| --- | --- |
51+
| [`vero/`](vero/) | The `scale-vero` optimization kernel, runtime, CLI, and coding-agent adapters |
52+
| [`vero-tasks/`](vero-tasks/) | Narrow Python task types and schema-v1 evaluation runner |
53+
| [`harness-engineering-bench/`](harness-engineering-bench/) | Harbor-native target programs and end-to-end optimization benchmarks |
54+
| [`legacy/`](legacy/) | The pre-v0.5 tree, i.e. the original VeRO paper code — reference only, not used by the current system |
4955

50-
### [vero-benchmarking/](vero-benchmarking/)
56+
Start with the [generic C matrix-multiplication quickstart](vero/examples/c-matmul/),
57+
try the [26-circle packing benchmark](vero/examples/circle-packing/), or read the
58+
[core guide](vero/README.md). The C example demonstrates the language-neutral
59+
command protocol without model credentials. Circle packing is a substantive
60+
coding-agent benchmark with exact geometry checks and inspectable search
61+
artifacts.
5162

52-
Scripts and infrastructure for running optimization experiments:
63+
For a full agent-optimization example, the [GAIA benchmark](harness-engineering-bench/gaia/)
64+
pairs a tool-using GPT-5.4 mini target with Harbor's canonical GAIA verifier and
65+
an immutable 20% / 40% / 40% development, validation, and test split.
5366

5467
```bash
55-
cd vero-benchmarking && uv sync --all-extras
56-
57-
# Run an optimization experiment
58-
uv run python scripts/run_benchmark.py --scaffold claude-code-vmf --model sonnet --task math
59-
60-
# Build datasets
61-
./scripts/build_datasets.sh
68+
cd vero
69+
uv sync --all-extras
70+
uv run vero --help
6271
```
6372

64-
See [vero-benchmarking/README.md](vero-benchmarking/README.md) for full documentation.
73+
## Paper reproduction
6574

66-
## Quick Start
75+
VeRO was introduced in [*VeRO: A Harness for Agents to Optimize
76+
Agents*](https://arxiv.org/abs/2602.22480), accepted at ICML 2026. The current
77+
library generalizes that version/evaluate/select loop from agents to programs.
6778

68-
### Prerequisites
79+
The paper-era code is available two ways, and they hold the same code:
6980

70-
- Python 3.11+
71-
- [uv](https://docs.astral.sh/uv/getting-started/installation/)
72-
- Git
73-
- Access to an LLM provider (via LiteLLM, OpenAI, Anthropic, etc.)
74-
75-
### Install
81+
**To reproduce the paper, use the frozen ref.** It is the repository exactly as
82+
it stood at publication, with the original paths intact:
7683

7784
```bash
78-
git clone <repo-url> && cd vero
79-
80-
# Install core library
81-
cd vero && uv sync --extra optimize
82-
83-
# Install benchmarking tools
84-
cd ../vero-benchmarking && uv sync --all-extras
85+
git checkout paper-v1 # tag; the paper/v1 branch points at the same commit
8586
```
8687

87-
### Run Your First Optimization
88-
89-
```python
90-
from agents import Agent as OAIAgent
91-
from vero.policy import Policy
92-
from vero.agents.vero import VeroAgent
93-
94-
policy = Policy(
95-
project_path="/path/to/my-agent",
96-
dataset="/path/to/my-dataset",
97-
agent=VeroAgent(
98-
oai_agent=OAIAgent(name="VeroAgent", model="anthropic/claude-sonnet-4-5-20250929"),
99-
),
100-
task="main",
101-
train_budget=10,
102-
max_turns=200,
103-
)
104-
105-
best = await policy.run()
106-
print(f"Best commit: {best.commit}, score: {best.score}")
107-
```
88+
**To read that code alongside the current system, use [`legacy/`](legacy/).** The
89+
v0.5 redesign relocated the paper-era tree into that directory rather than
90+
deleting it, so it sits in this branch next to the code that replaced it. Both
91+
the frozen ref and `legacy/` include the paper-era `vero-agents` and
92+
`vero-benchmarking` directories; their Harbor-native replacement is
93+
[`harness-engineering-bench/`](harness-engineering-bench/).
94+
95+
Prefer the frozen ref for reproduction, since it is the state that was actually
96+
published. Either way, note that both packages are named `scale-vero` and both
97+
import as `vero` (0.4.7 in `legacy/vero`, 0.5.0 in `vero/`), so **they cannot be
98+
installed into the same environment** — give the legacy package its own
99+
virtualenv. Development of the current system continues on `main`.
108100

109101
## Citation
110102

111103
```bibtex
112104
@article{ursekar2026vero,
113-
title={VeRO: An Evaluation Harness for Agents to Optimize Agents},
105+
title={VeRO: A Harness for Agents to Optimize Agents},
114106
author={Ursekar, Varun and Shanker, Apaar and Chatrath, Veronica and Xue, Yuan (Emily) and Denton, Sam},
115107
journal={arXiv preprint arXiv:2602.22480},
116108
year={2026}
117109
}
118110
```
119111

120-
## License
121-
122-
[MIT](LICENSE)
112+
VeRO is licensed under the [MIT License](LICENSE).

legacy/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,14 @@ This directory archives the codebase as it existed before the v0.5 redesign —
44
it is the code for the **original VeRO paper**. It is kept for reference and
55
reproducibility only; it is not used by the current system, whose code lives at
66
the repository root (`vero/`, `harness-engineering-bench/`).
7+
8+
**Reproducing the paper?** Prefer the frozen ref, which is the repository exactly
9+
as it stood at publication rather than relocated under this directory:
10+
11+
```bash
12+
git checkout paper-v1 # tag; the paper/v1 branch points at the same commit
13+
```
14+
15+
**Installing anything from here?** Give it its own virtualenv. `legacy/vero` is
16+
`scale-vero` 0.4.7 and the current `vero/` is `scale-vero` 0.5.0; both import as
17+
`vero`, so they cannot share an environment.

runs/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Local GAIA/harbor run outputs — inspectable, not committed.
2+
*
3+
!.gitignore

vero-tasks/README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# scale-vero-tasks
2+
3+
`scale-vero-tasks` is the optional Python task protocol used by VeRO benchmark
4+
targets. It contains no optimizer, workspace, session, dataset-store, or
5+
experiment-database code.
6+
7+
```python
8+
from vero_tasks import TaskOutput, TaskResult, create_task
9+
10+
task = create_task("exact_match")
11+
12+
@task.inference()
13+
async def infer(case, context):
14+
return TaskOutput(output=case["question"].upper())
15+
16+
@task.evaluation()
17+
async def evaluate(case, output, context):
18+
return TaskResult.from_task_output(
19+
output,
20+
score=float(output.output == case["answer"]),
21+
)
22+
```
23+
24+
The runner accepts a VeRO command-evaluation request and an external JSON/JSONL
25+
case file, imports a task module, and writes a schema-v1 evaluation report. The
26+
standard VeRO adapter runs this package in a trusted evaluator project while
27+
overlaying the candidate package as an editable dependency. This keeps Python
28+
benchmark ergonomics separate from both the target program and VeRO's
29+
language-neutral evaluation kernel.
30+
31+
The runner applies VeRO's retry policy independently to each non-batch
32+
inference and evaluation call. Provider rate limits, configured HTTP status
33+
codes or messages, and timeouts can be retried with bounded exponential
34+
backoff. Earlier failed attempts are retained in the canonical case error list;
35+
they are non-terminal when a later attempt succeeds.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[project]
2+
name = "matmul-eval"
3+
version = "0.1.0"
4+
description = "Evaluation task for the matmul kernel — measures correctness and speed"
5+
requires-python = ">=3.11"
6+
dependencies = ["scale-vero-tasks>=0.2.0"]
7+
8+
[build-system]
9+
requires = ["hatchling"]
10+
build-backend = "hatchling.build"
11+
12+
[tool.hatch.build.targets.wheel]
13+
packages = ["src/matmul_eval"]
14+
15+
[tool.uv.sources]
16+
scale-vero-tasks = { path = "../..", editable = true }

vero-tasks/examples/matmul-eval/src/matmul_eval/__init__.py

Whitespace-only changes.
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
"""Matrix multiply evaluation task.
2+
3+
Measures correctness and execution speed of a matmul kernel.
4+
Score = average time per multiply (lower is better).
5+
Incorrect results get a penalty score of 999999.0.
6+
"""
7+
8+
import time
9+
10+
from vero_tasks import (
11+
TaskContext,
12+
TaskOutput,
13+
TaskParameters,
14+
TaskResult,
15+
create_task,
16+
)
17+
18+
19+
class MatmulParameters(TaskParameters):
20+
n_repeats: int = 100
21+
22+
23+
matmul_task = create_task("matmul", task_parameters_type=MatmulParameters)
24+
25+
26+
@matmul_task.inference()
27+
async def run_inference(task: dict, context: TaskContext) -> TaskOutput:
28+
from matmul_kernel import multiply
29+
30+
a = task["matrix_a"]
31+
b = task["matrix_b"]
32+
33+
parameters = context.parse_task_params(MatmulParameters)
34+
35+
# Warmup
36+
multiply(a, b)
37+
38+
# Timed runs (like timeit)
39+
start = time.perf_counter()
40+
for _ in range(parameters.n_repeats):
41+
result = multiply(a, b)
42+
elapsed_ms = (time.perf_counter() - start) / parameters.n_repeats * 1000
43+
44+
return TaskOutput(output={"result": result, "time_ms": elapsed_ms})
45+
46+
47+
@matmul_task.evaluation()
48+
async def run_evaluation(
49+
task: dict, output: TaskOutput, context: TaskContext
50+
) -> TaskResult:
51+
expected = task["expected"]
52+
actual = output.output["result"]
53+
time_ms = output.output["time_ms"]
54+
55+
# Check correctness (within floating point tolerance)
56+
correct = all(
57+
abs(a_val - e_val) < 1e-6
58+
for a_row, e_row in zip(actual, expected)
59+
for a_val, e_val in zip(a_row, e_row)
60+
)
61+
62+
# Score = time if correct, penalty if wrong (lower is better)
63+
score = time_ms if correct else 999999.0
64+
65+
return TaskResult.from_task_output(
66+
output,
67+
score=score,
68+
metrics={"time_ms": time_ms, "correct": 1.0 if correct else 0.0},
69+
feedback=f"{'Correct' if correct else 'Wrong'}. Time: {time_ms:.2f}ms",
70+
)

0 commit comments

Comments
 (0)