-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathquick_start_inline.py
More file actions
143 lines (117 loc) · 6.67 KB
/
Copy pathquick_start_inline.py
File metadata and controls
143 lines (117 loc) · 6.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
"""Quick start — evolve a coding harness with the PyTorch-like ``Trainer`` API (inline variant).
The mental model mirrors ``torch``'s *model / optimizer / dataloader → ``trainer.fit(...)``*:
evolvee the harness being optimized (θ — like the ``nn.Module``)
evolver the coding agent that edits it (the mutation operator)
algorithm the evolution strategy (the optimizer, e.g. DarwinX)
dataset the tasks candidates are scored on (like the ``DataLoader``)
You compose those four as plain Python objects and hand them to a ``Trainer`` — no YAML. (The
identical run driven from a single ``config.yaml`` is ``beagle evolve --config config.yaml``.)
The evolvee (repo / ref / local checkout) is read from an **onboarded-agent manifest**
(``.beagle/agents/<name>.json``, produced by ``python -m beagle.tools.onboard``).
Usage
-----
python examples/evolution/quick_start_inline.py --runtime local --dry-run # preview, NO spend
python examples/evolution/quick_start_inline.py --runtime local # launch (spends)
"""
from __future__ import annotations
import argparse
from pathlib import Path
import beagle as bgl
from beagle.algorithms import DarwinXConfig
from beagle.config import (
AgentConfig,
AgentSourceConfig,
BenchmarkConfig,
ModelConfig,
)
from beagle.tools.onboard import load_manifest
REPO_ROOT = Path(__file__).resolve().parents[2] # the beagle repo (examples/evolution/<this>)
# Portable run knobs — edit to taste (these are benchmark-side, not machine-specific).
BENCHMARK = "terminal_bench_2_1"
TASKS = ["gcode-to-text"] # keep it to 1 task for a cheap smoke
EVOLVEE_TYPE = "opencode" # the agent adapter the onboarded repo is built with
EVOLVEE_MODEL = "gpt-5.5"
EVOLVEE_EFFORT = "high" # opencode reasoning effort (→ --variant; default is weak)
EVOLVEE_PROVIDER = "openai" # direct provider name (use "anthropic" for Claude)
EVOLVEE_KEY_ENV = "OPENAI_API_KEY" # your provider key, forwarded into the run container
EVOLVER = "cursor"
#: `auto` is portable; replace it with a value from `cursor-agent models` to pin a campaign.
EVOLVER_MODEL = "auto"
def _evolvee_agent_config(m: dict) -> AgentConfig:
"""θ (the harness under evolution) as a declarative :class:`AgentConfig`, pinned to the
manifest's experiment copy @ its baseline ref. Bring your own API key: opencode routes to the
provider directly, reading ``EVOLVEE_KEY_ENV`` (forwarded into the container via ``forward_env``)."""
config: dict = {
"effort": EVOLVEE_EFFORT,
"provider": {"type": "direct", "name": EVOLVEE_PROVIDER},
"forward_env": [EVOLVEE_KEY_ENV], # your provider key, forwarded into the run container
}
if m.get("token_env"):
config["token_env"] = m["token_env"] # clone credential for the private experiment copy
return AgentConfig(
name=EVOLVEE_TYPE,
model=ModelConfig(name=EVOLVEE_MODEL),
source=AgentSourceConfig(repo=m["repo"], ref=m["ref"]),
config=config,
)
def build_trainer(agent: str, *, runtime: str, run_dir: Path, runname: str) -> bgl.Trainer:
"""Compose the four pieces from the declarative **Config** classes (what a YAML would hold —
here inline). The evolvee is read from the onboarded-agent manifest."""
m = load_manifest(agent, root=REPO_ROOT) # {repo, ref, token_env?, dir}
evolvee = bgl.agents.build(_evolvee_agent_config(m))
# the mutation operator — the cursor CLI, driven as a black-box Editor. cursor bakes reasoning
# effort into the slug (EVOLVER_MODEL, e.g. "gpt-5.5-high"), so a plain ModelConfig is right.
evolver = bgl.agents.build(AgentConfig(name=EVOLVER, model=ModelConfig(name=EVOLVER_MODEL)))
# the optimizer — DarwinX, configured by its typed DarwinXConfig (every field validated).
# repo_root the run home (<dir>/<runname>): worktrees + the genealogy DB + config
# evolvee_checkout the manifest's local clone, linked in under <repo_root>
# campaign the run's id (= runname), namespacing the genealogy DB
# evolvee_effort opencode --variant on the DarwinX eval path (else the driver's default)
algorithm = bgl.algorithms.build(DarwinXConfig(
repo_root=str(run_dir),
evolvee_checkout=str((REPO_ROOT / m["dir"]).resolve()),
campaign=runname,
max_loop_iters=1,
n_failure_tasks=1,
mini_eval_k_samples=1,
fullset_eval_n_attempts=1,
fullset_metric="best",
guard_enabled=True,
anti_cheat=True,
evolvee_effort=EVOLVEE_EFFORT,
))
return bgl.Trainer(
evolvee=evolvee, evolver=evolver, algorithm=algorithm,
trainer_config={"runtime": {"kind": runtime}},
)
def main() -> int:
p = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
p.add_argument("--agent", default="opencode_v1.18.16",
help="onboarded manifest under .beagle/agents/ (default: opencode_v1.18.16)")
p.add_argument("--dir", default=None,
help="base directory to host run results (default: <repo>/.beagle/runs)")
p.add_argument("--runname", default=None,
help="run name; results land in <dir>/<runname>/ (default: the agent name)")
p.add_argument("--runtime", default="local", choices=["local", "xrlenv-cluster"])
p.add_argument("--dry-run", action="store_true",
help="resolve + print the plan and exit — no spend (default: launch the loop)")
args = p.parse_args()
# Bucket-1 facts/secrets (xrlenv topology + your provider API key + benchmark cache) from .env.
bgl.load_dotenv()
agent = args.agent
base_dir = Path(args.dir) if args.dir else REPO_ROOT / ".beagle" / "runs"
runname = args.runname or agent
run_dir = base_dir / runname # results land here: <dir>/<runname>/
print(f"[quick-start] run dir: {run_dir}")
trainer = build_trainer(agent, runtime=args.runtime, run_dir=run_dir, runname=runname)
# the data — the dataset carries its benchmark spec, so the Trainer derives the eval config
# from it (the native harness loads the tasks in-trial). Loads from the .env benchmark cache.
train_ds = bgl.TaskDataset.from_benchmark(BenchmarkConfig(name=BENCHMARK, task_ids=TASKS))
if args.dry_run:
trainer.dry_run(train_dataset=train_ds) # resolve + print, no spend
return 0
best = trainer.fit(train_dataset=train_ds) # launch the loop → the best evolved harness
print(f"\nbest candidate: {best}")
return 0
if __name__ == "__main__":
raise SystemExit(main())