eval-harness 0.2.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1046 -0
- package/README.zh-CN.md +597 -0
- package/bin/eval-harness.js +65 -0
- package/config/eval.example.json +70 -0
- package/docs/agent-runner-compatibility.md +47 -0
- package/docs/runners.md +82 -0
- package/package.json +43 -0
- package/prompts/judge.md +27 -0
- package/pyproject.toml +48 -0
- package/schemas/batch-comparison.schema.json +64 -0
- package/schemas/batch-summary.schema.json +85 -0
- package/schemas/evaluation.schema.json +81 -0
- package/schemas/experiment.schema.json +63 -0
- package/schemas/history-index.schema.json +37 -0
- package/schemas/history-record.schema.json +56 -0
- package/schemas/model-report.schema.json +38 -0
- package/schemas/next-action.schema.json +62 -0
- package/schemas/skill-improvement-input.schema.json +65 -0
- package/src/eval/__init__.py +3 -0
- package/src/eval/__main__.py +5 -0
- package/src/eval/cli.py +11150 -0
- package/src/eval/runners/__init__.py +0 -0
- package/src/eval/runners/base.py +197 -0
- package/src/eval/runners/claude.py +516 -0
- package/src/eval/runners/codex.py +412 -0
- package/src/eval/runners/mimocode.py +676 -0
- package/src/eval/runners/opencode.py +554 -0
- package/src/eval/schema.py +151 -0
package/README.md
ADDED
|
@@ -0,0 +1,1046 @@
|
|
|
1
|
+
# Eval Harness
|
|
2
|
+
|
|
3
|
+
[中文文档](README.zh-CN.md)
|
|
4
|
+
|
|
5
|
+
Release: `v0.2.18`
|
|
6
|
+
|
|
7
|
+
Configurable evaluation harness for runner `work/` packages.
|
|
8
|
+
|
|
9
|
+
Eval Harness is not bound to OpenCode. It is a runner-based evaluation platform
|
|
10
|
+
for CodeX/Codex CLI, OpenCode, MiMo Code, Claude Code, and future runner
|
|
11
|
+
adapters. See [Runner Adapters](docs/runners.md) for the
|
|
12
|
+
runner model and extension points.
|
|
13
|
+
|
|
14
|
+
The checked-in default config is a generic template. You can point it at any
|
|
15
|
+
task repository and any submitted work repository through
|
|
16
|
+
`config/eval.local.json`, Jenkins parameters, or a generated
|
|
17
|
+
`eval.effective.json`.
|
|
18
|
+
|
|
19
|
+
Jenkins setup links:
|
|
20
|
+
|
|
21
|
+
- [Jenkins usage guide](docs/jenkins.md)
|
|
22
|
+
- [Jenkins parameter comparison](docs/jenkins-parameter-comparison.md)
|
|
23
|
+
- [Agent runner compatibility](docs/agent-runner-compatibility.md)
|
|
24
|
+
|
|
25
|
+
This project turns a one-off runner submission into a reproducible,
|
|
26
|
+
evidence-driven evolution loop. Instead of asking whether an agent "looked
|
|
27
|
+
smart" in one console session, it asks whether the whole agent system can
|
|
28
|
+
consistently understand the task, modify the work package, produce required
|
|
29
|
+
artifacts, pass validation, and explain the next improvement.
|
|
30
|
+
|
|
31
|
+
It is designed to let CodeX/Codex drive repeated agent runs, inspect deterministic
|
|
32
|
+
evidence, compare models under the same task/work inputs, and feed the next
|
|
33
|
+
smallest Skill, Agent, knowledge-pack, or Instruction improvement back into the
|
|
34
|
+
work package.
|
|
35
|
+
|
|
36
|
+
The intended loop is:
|
|
37
|
+
|
|
38
|
+
```text
|
|
39
|
+
prepare clean task workspace
|
|
40
|
+
-> run selected runner with submitted work/INSTRUCTION.md
|
|
41
|
+
-> collect work/result, reports, logs, validation, and code diff
|
|
42
|
+
-> deterministic score
|
|
43
|
+
-> deterministic accept/investigate/reject decision
|
|
44
|
+
-> next-step recommendations and Codex/LLM judge report
|
|
45
|
+
-> propose one small skill change
|
|
46
|
+
-> rerun and compare
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
This repository starts with a deterministic runner/evaluator and Jenkins
|
|
50
|
+
pipeline. It writes machine-readable advice for the next iteration, but it does
|
|
51
|
+
not mutate skills automatically yet.
|
|
52
|
+
|
|
53
|
+
## What You Configure
|
|
54
|
+
|
|
55
|
+
The evaluator separates three concerns so it can be shared with other teams:
|
|
56
|
+
|
|
57
|
+
- **Task repository**: the original project or problem package that the selected agent
|
|
58
|
+
must modify. Jenkins calls this `TASK_REPO_*`; config calls it
|
|
59
|
+
`source_repo`.
|
|
60
|
+
- **Work repository**: the submitted `work` package that contains
|
|
61
|
+
`INSTRUCTION.md`, Skills, Agents, helper scripts, and result/report
|
|
62
|
+
contracts. Jenkins calls this `WORK_REPO_*`; config calls it
|
|
63
|
+
`submission_repo`.
|
|
64
|
+
- **Execution matrix**: runner/model routes, concurrency, timeout, idle
|
|
65
|
+
timeout, provider failure grace, validation mode, and optional container
|
|
66
|
+
execution.
|
|
67
|
+
|
|
68
|
+
For reproducibility, every Jenkins build writes the actual resolved values to
|
|
69
|
+
`eval.effective.json` and exports it under `runs/eval.effective.json`.
|
|
70
|
+
|
|
71
|
+
## Project Value
|
|
72
|
+
|
|
73
|
+
`Eval Harness` is valuable because it makes agent improvement
|
|
74
|
+
observable, comparable, and repeatable across configurable task/work inputs:
|
|
75
|
+
|
|
76
|
+
- **From subjective logs to hard evidence**: every run is judged from concrete
|
|
77
|
+
artifacts such as `work/result/output.md`, `work/logs/trace/**`,
|
|
78
|
+
validation summaries, code diff, final result markers, and evaluator output.
|
|
79
|
+
- **From single-run luck to convergence**: each run produces
|
|
80
|
+
`evaluation.json`, `judge-input.md`, `recommendations.md`,
|
|
81
|
+
`next-action.json`, and `skill-improvement-input.json`, so CodeX/Codex can turn
|
|
82
|
+
failures into the next targeted Skill, Agent, helper, or Instruction change.
|
|
83
|
+
- **From model anecdotes to model comparison**: Jenkins can run any configured
|
|
84
|
+
runner/model matrix against the same task and work
|
|
85
|
+
package, then compare score, validation ratio, status, and recovery evidence.
|
|
86
|
+
- **From shared workspace risk to isolated workers**: every agent worker gets
|
|
87
|
+
its own task copy, work copy, HOME, TEMP, cache, config, logs, and result
|
|
88
|
+
space, which makes parallel runs safe and failures attributable.
|
|
89
|
+
- **From local demo to real judging shape**: the evaluator assumes the task
|
|
90
|
+
directory is dynamic, keeps paths platform-neutral, preflights external tools
|
|
91
|
+
on `PATH`, and separates task fetch, work fetch, prepare, execute, score,
|
|
92
|
+
aggregate, and export stages.
|
|
93
|
+
- **From stuck jobs to fast feedback**: provider/model configuration errors,
|
|
94
|
+
unreachable providers, invalid credentials, rate limits, retry exhaustion, and
|
|
95
|
+
idle agent workers are detected early, recorded, cleaned up, and surfaced
|
|
96
|
+
in Jenkins.
|
|
97
|
+
- **From vague failures to repair inputs**: validation logs are recovered into
|
|
98
|
+
evaluator-readable summaries when configured, while provider/runtime,
|
|
99
|
+
final-artifact, trace, protected-path, validation, semantic-memory,
|
|
100
|
+
agent-handoff, and judge-review failures are classified separately from
|
|
101
|
+
work-package quality.
|
|
102
|
+
- **From prompt tweaking to Skill versioning**: the intended optimization unit
|
|
103
|
+
is small and reviewable: update one Skill, subagent, helper, or Instruction
|
|
104
|
+
concern, bump its version, rerun the harness, and keep the change only when
|
|
105
|
+
evidence improves.
|
|
106
|
+
|
|
107
|
+
In short, this repository is the control plane for evolving a runner
|
|
108
|
+
submission: Jenkins provides the execution surface, the selected runner performs
|
|
109
|
+
the autonomous coding work, Agent Inspector provides model/proxy evidence, and
|
|
110
|
+
the evaluator converts all of that into a repeatable score and next-step advice.
|
|
111
|
+
|
|
112
|
+
## Current Defaults
|
|
113
|
+
|
|
114
|
+
- Task repository: placeholder URL in `config/eval.example.json`.
|
|
115
|
+
- Submitted work repository: placeholder URL in `config/eval.example.json`, `work/`.
|
|
116
|
+
- Copy `config/eval.example.json` to `config/eval.local.json` or pass Jenkins `TASK_REPO_*` and `WORK_REPO_*` parameters for a real build.
|
|
117
|
+
- Clone mode: prefer configured SSH URLs when present, fallback to HTTPS
|
|
118
|
+
- Agent model route: no checked-in default; set it in config or Jenkins `MODEL_MATRIX`
|
|
119
|
+
- Jenkins reasoning variant: `high`, applied only when the selected runner exposes a variant/agent flag
|
|
120
|
+
- Agent Inspector proxy: optional, enabled only by config, `AGENT_INSPECTOR=true`, or `agent-inspector/*` model routes
|
|
121
|
+
- Worker timeout: `90` minutes by default, configurable per run or Jenkins build
|
|
122
|
+
- Worker execution contract: default runner commands expose `AGENT_EVAL_TIMEOUT_MINUTES`, reserve `AGENT_EVAL_FINALIZE_BEFORE_MINUTES=5`, and require `work/result/output.md`, `work/reports/FINAL_RESULT.json`, `work/reports/FINAL_RESULT.md`, and a real `work/reports/final-consistency-report.md` even for blocked or partial runs
|
|
123
|
+
- Fetch timeout: `15` minutes by default for task/work clone
|
|
124
|
+
- Idle timeout: `10` minutes without child agent output or watched artifact activity
|
|
125
|
+
- Jenkins concurrency: default `1`, configurable from `1` to `5`
|
|
126
|
+
- Jenkins runner matrix: comma/newline separated runner adapters, assigned by worker index; empty uses `agent.type` from config for every worker
|
|
127
|
+
- Jenkins model matrix: comma/newline separated agent model routes, assigned by worker index
|
|
128
|
+
- Jenkins tool paths: use Jenkins global `OEVAL_PYTHON_CMD`, `OEVAL_EXTRA_PATHS`, `Maven_Home`/`MAVEN_HOME`, or one-build override parameters; the pipeline does not commit host-specific tool paths
|
|
129
|
+
- Jenkins config file: `EVAL_CONFIG` is optional; empty uses local `OEVAL_CONFIG`, then `config/eval.example.json`
|
|
130
|
+
- Jenkins schedule: no checked-in cron trigger; add a Jenkins timer or branch-specific trigger in the deployment environment when scheduled runs are desired
|
|
131
|
+
- Work version gate: `REQUIRE_WORK_VERSION=true` by default for traceable runs; set it to `false` for simple work packages without `versions.json`
|
|
132
|
+
- Runtime isolation: enabled by default for HOME, TEMP, caches, and runner config
|
|
133
|
+
|
|
134
|
+
## Input Contract
|
|
135
|
+
|
|
136
|
+
To reuse this evaluator for another problem, provide two independent inputs:
|
|
137
|
+
|
|
138
|
+
| Input | Required shape | Notes |
|
|
139
|
+
| --- | --- | --- |
|
|
140
|
+
| Task repository | A Git repository containing the project/problem to be repaired. | It is copied to each worker as `workspace/project`. Git metadata is preserved when available so the evaluator can produce diffs. |
|
|
141
|
+
| Work repository | A Git repository containing the submitted work package. | `submission_repo.work_dir` or Jenkins `WORK_REPO_WORK_DIR` must point to the directory that contains `INSTRUCTION.md`. |
|
|
142
|
+
| Work assets | Skills, Agents, helper scripts, and result/report conventions under the work directory. | The default installer supports nested `work/work/skills/*` and flat `work/skills/*` layouts, then installs them into the selected runner's local asset directories, such as `.opencode/*`, `.mimocode/*`, `.codex/*`, or `.claude/*`. |
|
|
143
|
+
| Result artifacts | `work/result/output.md`, `work/reports/FINAL_RESULT.json`, `work/reports/FINAL_RESULT.md`, `work/reports/final-consistency-report.md`, and trace logs. | Missing artifacts are scored as evidence gaps instead of being hidden by console output. |
|
|
144
|
+
|
|
145
|
+
Local directories can replace either Git clone through `PROJECT_SOURCE` and
|
|
146
|
+
`WORK_SOURCE`. That is useful for debugging, while Git URL parameters are better
|
|
147
|
+
for shared Jenkins jobs.
|
|
148
|
+
|
|
149
|
+
## Quick Start
|
|
150
|
+
|
|
151
|
+
The runner is platform-neutral. Use Python 3.10+ including Python 3.12, and keep external tools such as
|
|
152
|
+
`git`, the selected agent CLI (`opencode`, `mimo`, `codex`, or `claude`), `agent-inspector`,
|
|
153
|
+
`mvn`, and Java available on `PATH` or in the Jenkins `EXTRA_PATHS`/`OEVAL_EXTRA_PATHS` configuration.
|
|
154
|
+
|
|
155
|
+
The expected real scoring baseline is Ubuntu 24.04.4 with Python 3.12, Node
|
|
156
|
+
v24.13.0, OpenJDK 21, Maven 3.9.11, and Maven home at `/usr/local/maven3`
|
|
157
|
+
when exposed as `Maven_Home`, `MAVEN_HOME`, or Jenkins `MAVEN_HOME_OVERRIDE`.
|
|
158
|
+
|
|
159
|
+
Linux/macOS:
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
python3 -m venv .venv
|
|
163
|
+
. .venv/bin/activate
|
|
164
|
+
python -m pip install -e .
|
|
165
|
+
eval-harness --help
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Windows PowerShell:
|
|
169
|
+
|
|
170
|
+
```powershell
|
|
171
|
+
python -m venv .venv
|
|
172
|
+
.\.venv\Scripts\python -m pip install -e .
|
|
173
|
+
.\.venv\Scripts\eval-harness --help
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
NPM wrapper:
|
|
177
|
+
|
|
178
|
+
```bash
|
|
179
|
+
npx eval-harness --help
|
|
180
|
+
npx eval-harness runner-presets
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
The npm package is a thin Node.js launcher around the bundled Python source. It
|
|
184
|
+
still requires Python 3.10+ on `PATH`, or set `EVAL_HARNESS_PYTHON` to the
|
|
185
|
+
Python executable to use. When run outside this repository, it falls back to the
|
|
186
|
+
package's bundled `config/eval.example.json` and `schemas/` directory.
|
|
187
|
+
|
|
188
|
+
Without installation:
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
PYTHONPATH=src python -m eval --help
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
```powershell
|
|
195
|
+
$env:PYTHONPATH = "src"
|
|
196
|
+
python -m eval --help
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Copy the example config:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
cp config/eval.example.json config/eval.local.json
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
```powershell
|
|
206
|
+
Copy-Item config/eval.example.json config/eval.local.json
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
Customize the task and submitted work repositories in `config/eval.local.json`:
|
|
210
|
+
|
|
211
|
+
```json
|
|
212
|
+
{
|
|
213
|
+
"source_repo": {
|
|
214
|
+
"url": "https://example.com/course/task.git",
|
|
215
|
+
"ssh_url": "git@example.com:course/task.git",
|
|
216
|
+
"ref": "main",
|
|
217
|
+
"fallback_urls": []
|
|
218
|
+
},
|
|
219
|
+
"submission_repo": {
|
|
220
|
+
"url": "https://example.com/team/work.git",
|
|
221
|
+
"ssh_url": "git@example.com:team/work.git",
|
|
222
|
+
"ref": "main",
|
|
223
|
+
"work_dir": "work",
|
|
224
|
+
"fallback_urls": []
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
For a one-off run without editing a checked-in file, generate an effective config:
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
PYTHONPATH=src python -m eval write-effective-config \
|
|
233
|
+
--config config/eval.example.json \
|
|
234
|
+
--output /tmp/oeval/eval.effective.json \
|
|
235
|
+
--task-repo-url https://example.com/course/task.git \
|
|
236
|
+
--task-repo-ref main \
|
|
237
|
+
--work-repo-url https://example.com/team/work.git \
|
|
238
|
+
--work-repo-ref main \
|
|
239
|
+
--work-repo-work-dir work
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
The command also accepts `--task-repo-ssh-url`, `--task-repo-fallback-urls`, `--work-repo-ssh-url`, and `--work-repo-fallback-urls`. Fallback URLs can be comma-separated or newline-separated.
|
|
243
|
+
|
|
244
|
+
Then use the generated file exactly like a normal config:
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
PYTHONPATH=src python -m eval fetch-task --config /tmp/oeval/eval.effective.json --output /tmp/oeval/inputs/task --replace-existing
|
|
248
|
+
PYTHONPATH=src python -m eval fetch-work --config /tmp/oeval/eval.effective.json --output /tmp/oeval/inputs/work --replace-existing
|
|
249
|
+
PYTHONPATH=src python -m eval prepare --config /tmp/oeval/eval.effective.json --run-id demo-01 --project-source /tmp/oeval/inputs/task --work-source /tmp/oeval/inputs/work --replace-existing
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
For a real local run, make sure these tools are available on `PATH`:
|
|
253
|
+
|
|
254
|
+
- `python3`, `python`, or another Python 3 command
|
|
255
|
+
- `git`
|
|
256
|
+
- `node`
|
|
257
|
+
- the selected agent CLI: `opencode`, `mimo`, `codex`, or `claude`
|
|
258
|
+
- `agent-inspector` when Agent Inspector is enabled
|
|
259
|
+
- `mvn` and Java when validation is enabled
|
|
260
|
+
|
|
261
|
+
When Agent Inspector is enabled, its configured provider/model must be healthy. The evaluator fails fast for unknown provider/model, unreachable provider, invalid credentials, rate limits, and retry exhaustion so Jenkins does not sit on a stuck worker.
|
|
262
|
+
|
|
263
|
+
Prepare a run:
|
|
264
|
+
|
|
265
|
+
```powershell
|
|
266
|
+
python -m eval prepare --config config/eval.local.json
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
Execute the configured agent runner:
|
|
270
|
+
|
|
271
|
+
```powershell
|
|
272
|
+
python -m eval execute --run runs/<run-id>
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
Score a run:
|
|
276
|
+
|
|
277
|
+
```powershell
|
|
278
|
+
python -m eval score --run runs/<run-id>
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Prepare, execute, and score:
|
|
282
|
+
|
|
283
|
+
```powershell
|
|
284
|
+
python -m eval run --config config/eval.local.json
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Override the per-worker timeout when needed:
|
|
288
|
+
|
|
289
|
+
```powershell
|
|
290
|
+
python -m eval run --config config/eval.local.json --timeout-minutes 30
|
|
291
|
+
python -m eval batch --config config/eval.local.json --count 5 --parallel 5 --timeout-minutes 30
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
If the selected agent CLI is not available yet, validate the harness with dry-run:
|
|
295
|
+
|
|
296
|
+
```powershell
|
|
297
|
+
python -m eval run --config config/eval.local.json --dry-run
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
Run five workers in parallel:
|
|
301
|
+
|
|
302
|
+
```powershell
|
|
303
|
+
python -m eval batch --config config/eval.local.json --count 5 --parallel 5
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
Run a Jenkins-like local pipeline once. This writes an effective config, fetches
|
|
307
|
+
task/work inputs, runs workers in parallel, aggregates the batch, exports
|
|
308
|
+
artifacts, and optionally validates the exported JSON:
|
|
309
|
+
|
|
310
|
+
```powershell
|
|
311
|
+
python -m eval run-once `
|
|
312
|
+
--config config/eval.local.json `
|
|
313
|
+
--batch-id local-three-model `
|
|
314
|
+
--count 3 `
|
|
315
|
+
--parallel 3 `
|
|
316
|
+
--prefer-ssh `
|
|
317
|
+
--model agent-inspector/MiniMax-M3 `
|
|
318
|
+
--model agent-inspector/deepseek-v4-pro `
|
|
319
|
+
--model agent-inspector/glm-5.2 `
|
|
320
|
+
--timeout-minutes 90 `
|
|
321
|
+
--idle-timeout-minutes deepseek-v4-pro=30,default=10 `
|
|
322
|
+
--variant high `
|
|
323
|
+
--replace-existing `
|
|
324
|
+
--validate-artifacts
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
Use `--task-repo-url`, `--task-repo-ref`, `--work-repo-url`,
|
|
328
|
+
`--work-repo-ref`, and `--work-repo-work-dir` to override repositories for a
|
|
329
|
+
single local run without committing private config. Add `--dry-run` to validate
|
|
330
|
+
the flow without requiring a working agent CLI.
|
|
331
|
+
|
|
332
|
+
Use `--smoke` for a short real dispatch check. It forces `DRY_RUN=false`,
|
|
333
|
+
`timeout=5`, `idle_timeout=2`, disables validation/work-version/release gates,
|
|
334
|
+
and is useful for proving the selected runner, model route, and Agent Inspector
|
|
335
|
+
chain before a longer evaluation:
|
|
336
|
+
|
|
337
|
+
```powershell
|
|
338
|
+
python -m eval run-once `
|
|
339
|
+
--config config/eval.local.json `
|
|
340
|
+
--smoke `
|
|
341
|
+
--count 3 `
|
|
342
|
+
--parallel 3 `
|
|
343
|
+
--model agent-inspector/MiniMax-M3 `
|
|
344
|
+
--model agent-inspector/deepseek-v4-pro `
|
|
345
|
+
--model agent-inspector/glm-5.2
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
For `agent-inspector/*` model routes, make sure Agent Inspector is running
|
|
349
|
+
before the local run:
|
|
350
|
+
|
|
351
|
+
```powershell
|
|
352
|
+
agent-inspector
|
|
353
|
+
Invoke-RestMethod http://127.0.0.1:25947/api/health
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
The expected health response is `{"status":"ok"}`. The proxy URL
|
|
357
|
+
`http://127.0.0.1:25947/proxy` is the API base URL injected into OpenCode/MiMo-like
|
|
358
|
+
runners as `LLM_BASE_URL` and into Claude Code as `ANTHROPIC_BASE_URL`; it is
|
|
359
|
+
not a browser UI page. Use `http://127.0.0.1:25947/` for the local UI. A
|
|
360
|
+
successful dispatch can be confirmed in the selected runner log directory, such
|
|
361
|
+
as `runs/<run-id>/<agent-log-dir>/opencode.log`.
|
|
362
|
+
|
|
363
|
+
For troubleshooting, the same lifecycle is still available as separate commands.
|
|
364
|
+
This runs one real 90-minute worker through the split stages:
|
|
365
|
+
|
|
366
|
+
```bash
|
|
367
|
+
export AGENT_EVAL_RUNS_DIR="${TMPDIR:-/tmp}/oeval/manual"
|
|
368
|
+
python -m eval fetch-task --config config/eval.local.json --output "$AGENT_EVAL_RUNS_DIR/inputs/task" --replace-existing
|
|
369
|
+
python -m eval fetch-work --config config/eval.local.json --output "$AGENT_EVAL_RUNS_DIR/inputs/work" --replace-existing
|
|
370
|
+
python -m eval prepare --config config/eval.local.json --run-id manual-01 --project-source "$AGENT_EVAL_RUNS_DIR/inputs/task" --work-source "$AGENT_EVAL_RUNS_DIR/inputs/work" --replace-existing
|
|
371
|
+
python -m eval execute --config config/eval.local.json --run "$AGENT_EVAL_RUNS_DIR/manual-01" --timeout-minutes 90 --idle-timeout-minutes 10
|
|
372
|
+
python -m eval score --config config/eval.local.json --run "$AGENT_EVAL_RUNS_DIR/manual-01"
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
```powershell
|
|
376
|
+
$env:AGENT_EVAL_RUNS_DIR = Join-Path $env:TEMP 'oeval/manual'
|
|
377
|
+
python -m eval fetch-task --config config/eval.local.json --output "$env:AGENT_EVAL_RUNS_DIR/inputs/task" --replace-existing
|
|
378
|
+
python -m eval fetch-work --config config/eval.local.json --output "$env:AGENT_EVAL_RUNS_DIR/inputs/work" --replace-existing
|
|
379
|
+
python -m eval prepare --config config/eval.local.json --run-id manual-01 --project-source "$env:AGENT_EVAL_RUNS_DIR/inputs/task" --work-source "$env:AGENT_EVAL_RUNS_DIR/inputs/work" --replace-existing
|
|
380
|
+
python -m eval execute --config config/eval.local.json --run "$env:AGENT_EVAL_RUNS_DIR/manual-01" --timeout-minutes 90 --idle-timeout-minutes 10
|
|
381
|
+
python -m eval score --config config/eval.local.json --run "$env:AGENT_EVAL_RUNS_DIR/manual-01"
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
Dry-run the five-worker scheduler:
|
|
385
|
+
|
|
386
|
+
```powershell
|
|
387
|
+
python -m eval batch --config config/eval.local.json --count 5 --parallel 5 --dry-run
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
List and compare runs:
|
|
391
|
+
|
|
392
|
+
```powershell
|
|
393
|
+
python -m eval list
|
|
394
|
+
python -m eval advise --run runs/<run-id>
|
|
395
|
+
python -m eval compare --baseline runs/<old-run> --candidate runs/<new-run>
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
Useful platform maintenance helpers:
|
|
399
|
+
|
|
400
|
+
```powershell
|
|
401
|
+
python -m eval runner-presets
|
|
402
|
+
python -m eval runner-version-check --config config/eval.local.json --markdown-output runs/preflight/runner-version-check.md
|
|
403
|
+
python -m eval clean-runs --config config/eval.local.json --keep 10 --dry-run
|
|
404
|
+
python -m eval release-notes --from-ref <previous-tag> --to-ref HEAD --output docs/release-notes-draft.md
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
Aggregate runs launched by an external scheduler:
|
|
408
|
+
|
|
409
|
+
```bash
|
|
410
|
+
export AGENT_EVAL_RUNS_DIR="${TMPDIR:-/tmp}/eval-harness-runs/batch-1"
|
|
411
|
+
python -m eval run --config config/eval.local.json --run-id batch-1-01 --replace-existing
|
|
412
|
+
python -m eval run --config config/eval.local.json --run-id batch-1-02 --replace-existing
|
|
413
|
+
python -m eval aggregate --config config/eval.local.json --batch-id batch-1 --count 2 --parallel 2
|
|
414
|
+
python -m eval export --config config/eval.local.json --batch-id batch-1 --count 2 --output runs --clean-output
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
```powershell
|
|
418
|
+
$env:AGENT_EVAL_RUNS_DIR = Join-Path $env:TEMP 'eval-harness-runs/batch-1'
|
|
419
|
+
python -m eval run --config config/eval.local.json --run-id batch-1-01 --replace-existing
|
|
420
|
+
python -m eval run --config config/eval.local.json --run-id batch-1-02 --replace-existing
|
|
421
|
+
python -m eval aggregate --config config/eval.local.json --batch-id batch-1 --count 2 --parallel 2
|
|
422
|
+
python -m eval export --config config/eval.local.json --batch-id batch-1 --count 2 --output runs --clean-output
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
Run five workers through the configured container image:
|
|
426
|
+
|
|
427
|
+
```powershell
|
|
428
|
+
python -m eval batch --config config/eval.local.json --count 5 --parallel 5 --container
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
## Directory Model
|
|
432
|
+
|
|
433
|
+
Each evaluation creates an isolated run directory:
|
|
434
|
+
|
|
435
|
+
```text
|
|
436
|
+
runs/<run-id>/
|
|
437
|
+
manifest.json
|
|
438
|
+
workspace/
|
|
439
|
+
project/ # clean clone of the original task repository
|
|
440
|
+
work/ # submitted work directory
|
|
441
|
+
evaluation/
|
|
442
|
+
evaluation.json
|
|
443
|
+
changed-files.md
|
|
444
|
+
judge-input.md
|
|
445
|
+
recommendations.md
|
|
446
|
+
next-action.json
|
|
447
|
+
skill-improvement-input.json
|
|
448
|
+
project.diff
|
|
449
|
+
project.diffstat
|
|
450
|
+
validation/
|
|
451
|
+
<agent-log-dir>/
|
|
452
|
+
opencode.log
|
|
453
|
+
sessions.json
|
|
454
|
+
sessions.md
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
The selected agent runs from `runs/<run-id>/workspace`. This matches the real grading shape: `work/INSTRUCTION.md` is stable, while the task project directory is dynamic.
|
|
458
|
+
|
|
459
|
+
By default, `prepare` removes copied runtime artifacts such as `work/result/output.md`, `work/reports/FINAL_RESULT.*`, and `work/logs/trace/**`. This prevents stale logs from a previous run from influencing the current score.
|
|
460
|
+
|
|
461
|
+
## Scoring
|
|
462
|
+
|
|
463
|
+
The deterministic score checks hard evidence:
|
|
464
|
+
|
|
465
|
+
- `work/result/output.md` exists.
|
|
466
|
+
- `work/reports/FINAL_RESULT.json` and `FINAL_RESULT.md` exist.
|
|
467
|
+
- The final result says `FINAL_RESULT_FINAL: true` or JSON `is_final: true`.
|
|
468
|
+
- Configured protected paths were not changed.
|
|
469
|
+
- Trace evidence exists under `work/logs/trace/`.
|
|
470
|
+
- Validation summaries exist and pass.
|
|
471
|
+
- Optional external validation commands can be run from the evaluator.
|
|
472
|
+
|
|
473
|
+
Validation evidence can use either supported helper summary shape:
|
|
474
|
+
command-oriented `results[]` entries or phase-oriented `phases[]` entries with
|
|
475
|
+
a top-level `status`. A `phases[]` summary with all `PASS` phases is counted as
|
|
476
|
+
machine-readable validation evidence. Output-only success claims in
|
|
477
|
+
`work/result/output.md` are still treated as weak evidence until a
|
|
478
|
+
`work/logs/trace/validation/**/summary.json` file exists.
|
|
479
|
+
|
|
480
|
+
Final report quality is also checked. If
|
|
481
|
+
`work/reports/final-consistency-report.md` is still the helper-created
|
|
482
|
+
placeholder, scoring records a final-artifact finding and routes the next
|
|
483
|
+
action toward finalization/report repair instead of treating a `PASS` marker as
|
|
484
|
+
complete evidence.
|
|
485
|
+
|
|
486
|
+
The 100-point score is also exposed as explicit dimensions so Jenkins, Codex,
|
|
487
|
+
and downstream dashboards can diagnose convergence without reverse-engineering
|
|
488
|
+
the total:
|
|
489
|
+
|
|
490
|
+
- `artifacts` `/30`: required result files, trace files, final markers, and report artifacts.
|
|
491
|
+
- `boundary` `/20`: protected task/design/test paths remain untouched.
|
|
492
|
+
- `validation` `/30`: evaluator-readable validation summaries and pass evidence.
|
|
493
|
+
- `final_status` `/20`: the declared final execution status and finality markers.
|
|
494
|
+
|
|
495
|
+
Generated build outputs such as `target/`, `build/`, `.gradle/`, `__pycache__/`, and compiled archives/classes are recorded in `ignored_generated_changed_paths` but are not treated as protected-path violations. Real source changes under protected paths still fail the boundary check.
|
|
496
|
+
|
|
497
|
+
The evaluator writes:
|
|
498
|
+
|
|
499
|
+
```text
|
|
500
|
+
runs/<run-id>/evaluation/evaluation.json
|
|
501
|
+
runs/<run-id>/evaluation/changed-files.md
|
|
502
|
+
runs/<run-id>/evaluation/judge-input.md
|
|
503
|
+
runs/<run-id>/evaluation/recommendations.md
|
|
504
|
+
runs/<run-id>/evaluation/next-action.json
|
|
505
|
+
runs/<run-id>/evaluation/skill-improvement-input.json
|
|
506
|
+
runs/batches/<batch-id>/summary.json
|
|
507
|
+
runs/batches/<batch-id>/summary.md
|
|
508
|
+
runs/batches/<batch-id>/model-report.json
|
|
509
|
+
runs/batches/<batch-id>/model-report.md
|
|
510
|
+
runs/batches/<batch-id>/experiment.json
|
|
511
|
+
runs/batches/<batch-id>/comparison.json
|
|
512
|
+
runs/batches/<batch-id>/comparison.md
|
|
513
|
+
runs/history/batches.jsonl
|
|
514
|
+
runs/history/index.json
|
|
515
|
+
runs/history/index.md
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
`evaluation.json` contains the numeric score, `subscores`, `score_dimensions`, hard findings, final status, decision, structured recommendations, `failure_taxonomy`, `skill_improvement_input`, `changed_file_summary`, and `final_report_evidence`. `changed-files.md` is the Jenkins scoring-side changed-file report: it lists evaluator-detected project diffs, changed test files, ignored generated outputs, and the agent-reported changed files in `work/reports/FINAL_RESULT.json` when available. `recommendations.md` is the human-readable advice file, while `next-action.json` is the machine-readable next smallest change for Codex or another controller to apply. `skill-improvement-input.json` is the stronger controller input for the next Skill/Agent/Instruction edit: it names the primary failure category, target candidates, evidence paths, next action, and recommended change scope. The judge input is designed for Codex or another LLM reviewer to inspect evidence when the deterministic next action is too broad.
|
|
519
|
+
|
|
520
|
+
Before scoring, the evaluator also checks for artifacts accidentally written at the workspace root, such as `reports/FINAL_RESULT.json`, `result/output.md`, or `logs/trace/**`. When those root-level artifacts are more complete than the required `work/...` artifacts, the evaluator copies them into `work/reports`, `work/result`, and `work/logs/trace`, records `artifact_recovery.root_workspace`, and leaves a trace under `work/logs/trace/evaluator-recovery/`. This preserves scoring correctness without changing the reusable work package; findings still note that root-level artifacts were recovered, and recommendations classify the issue as `artifact-path-contract`.
|
|
521
|
+
|
|
522
|
+
The failure taxonomy deliberately separates environment/model/runtime defects from work-package defects. Current categories include provider/runtime, final artifacts, trace logging, artifact path contract, protected paths, validation failure, validation evidence, semantic memory, agent handoffs, changed-test review, coverage matrix, and judge-review fallback. This keeps a provider outage or missing final artifact from being mistaken for a design-repair weakness.
|
|
523
|
+
|
|
524
|
+
Jenkins exports `runs/eval.effective.json` when an effective config exists. This file records the task repository, submitted work repository, refs, work directory, and fallback URLs used for that build, so shared evaluator runs remain reproducible without checking machine-specific config into Git.
|
|
525
|
+
|
|
526
|
+
Batch summaries also expose convergence evidence:
|
|
527
|
+
|
|
528
|
+
- `model`: the actual agent model route used by the worker.
|
|
529
|
+
- `agent_runner` and `agent_log_dir`: the selected runner and exported log directory for the worker.
|
|
530
|
+
- `opencode_primary_session` and `opencode_session_count`: legacy-compatible fields for the main agent session id and total agent/subagent session count extracted from the agent log.
|
|
531
|
+
- `inspector_backfill_status` and `inspector_log_count`: best-effort Agent Inspector `/api/logs` evidence recovery when the agent log does not expose enough session data.
|
|
532
|
+
- `failure_digest`: batch-level root-cause rows with run id, runner, model, outcome, reason, evidence, and next action.
|
|
533
|
+
- `score_dimensions`, `subscores`, `best_subscores`, and `subscore_summary`: the score split used by the evaluator and the best run/model in the batch.
|
|
534
|
+
- `validation_pass_ratio`: passed validation targets over scored validation targets after evaluator recovery.
|
|
535
|
+
- `weak_validation_summary`: output-only validation claims found in `work/result/output.md` when the required machine-readable `work/logs/trace/validation/**/summary.json` evidence is missing. These claims are useful next-iteration input, but they do not replace formal validation summaries in the score.
|
|
536
|
+
- `artifact_recovery`: recovered validation summaries or normalized final status markers, such as `status:SUCCESS->PASS`.
|
|
537
|
+
- `best_by_model`: the best run for each model route in the same batch.
|
|
538
|
+
- `model-report.md/json`: per-model average score, average dimensions, best run dimensions, decision distribution, validation ratio, and top next-action types.
|
|
539
|
+
- `experiment.json`: batch-level comparability metadata such as models, source/work inputs, run ids, and best run.
|
|
540
|
+
- `comparison.md/json`: regression comparison against the latest compatible historical batch, or a named `--baseline-batch-id`.
|
|
541
|
+
- `history/index.md/json` and `history/batches.jsonl`: batch memory used to see score, decision, model, and recommendation trends across Jenkins builds.
|
|
542
|
+
|
|
543
|
+
Use these fields to separate model quality from process quality. For example, a high score with artifact recovery suggests the model fixed code but ignored the finalization protocol, while `0/0` validation evidence plus a non-empty weak validation summary suggests the model probably ran checks but failed to write evaluator-readable summaries.
|
|
544
|
+
|
|
545
|
+
Validate archived JSON contracts with:
|
|
546
|
+
|
|
547
|
+
```powershell
|
|
548
|
+
python -m eval validate-artifacts --root runs --batch-id <batch-id> --count <count>
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
The validator uses the checked-in `schemas/` directory and has no external Python package dependency.
|
|
552
|
+
|
|
553
|
+
## Jenkins Parallel Mode
|
|
554
|
+
|
|
555
|
+
Setup references:
|
|
556
|
+
|
|
557
|
+
- [Jenkins usage guide](docs/jenkins.md)
|
|
558
|
+
- [Jenkins parameter comparison](docs/jenkins-parameter-comparison.md)
|
|
559
|
+
|
|
560
|
+
The included `Jenkinsfile` exposes a `CONCURRENCY` choice parameter for the number of concurrent agent workers. The default is `1`, and the allowed range is `1` through `5`. Jenkins first resolves a build-specific config, then materializes shared read-only inputs in separate nodes:
|
|
561
|
+
|
|
562
|
+
```powershell
|
|
563
|
+
python -m eval write-effective-config --config <EVAL_CONFIG> --output <external-runs>/eval.effective.json [repo overrides]
|
|
564
|
+
python -m eval fetch-task --config <external-runs>/eval.effective.json --output <external-runs>/inputs/task --replace-existing
|
|
565
|
+
python -m eval fetch-work --config <external-runs>/eval.effective.json --output <external-runs>/inputs/work --replace-existing
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
`EVAL_CONFIG` selects the config file to use for the build. Leave it empty to
|
|
569
|
+
use a Jenkins-local `OEVAL_CONFIG` environment variable, then
|
|
570
|
+
`config/eval.example.json` as the public fallback. Keep private files such as
|
|
571
|
+
`config/eval.local.json` out of Git. `TASK_REPO_URL`, `TASK_REPO_SSH_URL`,
|
|
572
|
+
`TASK_REPO_REF`, and
|
|
573
|
+
`TASK_REPO_FALLBACK_URLS` override the task repository for one Jenkins build.
|
|
574
|
+
`WORK_REPO_URL`, `WORK_REPO_SSH_URL`, `WORK_REPO_REF`,
|
|
575
|
+
`WORK_REPO_WORK_DIR`, and `WORK_REPO_FALLBACK_URLS` do the same for the
|
|
576
|
+
submitted work repository. Empty values keep the defaults from the selected
|
|
577
|
+
config file.
|
|
578
|
+
|
|
579
|
+
`SMOKE_MODE=true` is the fastest real-chain Jenkins check. It forces
|
|
580
|
+
`DRY_RUN=false`, `TIMEOUT_MINUTES=5`, `IDLE_TIMEOUT_MINUTES=2`,
|
|
581
|
+
`RUN_VALIDATION=false`, `REQUIRE_WORK_VERSION=false`, and disables release
|
|
582
|
+
gates, while still executing the selected runner/model/Inspector path.
|
|
583
|
+
|
|
584
|
+
`Resolve Effective Config` prints the exact task/work URLs, refs, work
|
|
585
|
+
directory, and fallback URLs used by the build. `Export Artifacts` copies the
|
|
586
|
+
same file to `runs/eval.effective.json`, so another person can inspect or rerun
|
|
587
|
+
the batch with the same input definition.
|
|
588
|
+
|
|
589
|
+
`PROJECT_SOURCE` can still point at a local task/project directory instead of cloning the task repository; `WORK_SOURCE` can point at a local submitted `work` directory instead of cloning the submitted work repository. Local source parameters take precedence at fetch time. Fetching the original task and fetching the submitted work are intentionally separate Jenkins phases, so a repository/network/configuration failure is visible before any agent worker starts.
|
|
590
|
+
|
|
591
|
+
The Jenkins stage graph is grouped by the main lifecycle so long runs are easier
|
|
592
|
+
to inspect:
|
|
593
|
+
|
|
594
|
+
- `Environment Preparation`: tool path setup, Python/Git/evaluator checks, optional Agent Inspector health/model validation, and evaluator unit tests.
|
|
595
|
+
- `Run Planning`: concurrency, timeout, provider-grace, regression, batch-id, run directory, optional Agent Inspector group declaration, and history seed resolution.
|
|
596
|
+
- `Input Materialization`: input directory planning plus task/work source fetch and work-version reporting.
|
|
597
|
+
- `Agent Execution`: the parallel worker group; each branch is labeled with worker index and model name, while prepare, optional Inspector run declaration, asset install, execute, optional Inspector session attach, score, and optional Inspector completion are printed as branch log sections.
|
|
598
|
+
- `Validation And Reporting`: aggregate, optional Agent Inspector evidence export, artifact export, schema validation, run listing, and HTML report publishing.
|
|
599
|
+
|
|
600
|
+
Each worker runs as a Jenkins `parallel` branch and no longer hides multiple actions behind one `python -m eval run` call:
|
|
601
|
+
|
|
602
|
+
```powershell
|
|
603
|
+
python -m eval prepare --run-id <run-id> --project-source <inputs/task> --work-source <inputs/work>
|
|
604
|
+
python -m eval inspector-run --run <external-runs>/<run-id> --batch-id <batch-id> --phase create
|
|
605
|
+
python -m eval install-agent-assets --run <external-runs>/<run-id>
|
|
606
|
+
python -m eval execute --run <external-runs>/<run-id> --timeout-minutes <TIMEOUT_MINUTES>
|
|
607
|
+
python -m eval inspector-run --run <external-runs>/<run-id> --batch-id <batch-id> --phase attach
|
|
608
|
+
python -m eval score --run <external-runs>/<run-id>
|
|
609
|
+
python -m eval inspector-run --run <external-runs>/<run-id> --batch-id <batch-id> --phase complete
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
The parallel branch name includes the worker index and short model name, such as `01 model-a`, so Jenkins Stage View shows which model each worker is running without a wall of per-step nodes.
|
|
613
|
+
|
|
614
|
+
The external run root is passed through `AGENT_EVAL_RUNS_DIR`, so agent workspaces stay outside the evaluator checkout and cannot accidentally treat this repository as the task project root.
|
|
615
|
+
|
|
616
|
+
Every branch gets its own isolated run space:
|
|
617
|
+
|
|
618
|
+
```text
|
|
619
|
+
<external-runs>/<run-id>/
|
|
620
|
+
inputs/task/ # shared or prefetched original task baseline, outside the worker
|
|
621
|
+
inputs/work/ # shared or prefetched submitted work baseline, outside the worker
|
|
622
|
+
workspace/project/ # independent copy of the prefetched task repository
|
|
623
|
+
workspace/work/ # independent copy of the submitted work directory
|
|
624
|
+
runtime/home/ # per-run HOME and USERPROFILE
|
|
625
|
+
runtime/tmp/ # per-run TEMP, TMP, and TMPDIR
|
|
626
|
+
runtime/cache/ # per-run XDG cache
|
|
627
|
+
runtime/config/ # per-run XDG config
|
|
628
|
+
runtime/npm-cache/ # per-run npm cache
|
|
629
|
+
control/timeout.json # live timeout control file watched during execution
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
Scoring treats `workspace/project/` as the task project modified by the selected agent. It does not diff the evaluator checkout or the whole Jenkins workspace. If `workspace/project/` remains a Git worktree, project changes are collected with Git. If the copy loses `.git`, the scorer falls back to a tree comparison between the separately fetched task input (`inputs/task`, recorded as `task_input.origin` or `project_source`) and `workspace/project/`.
|
|
633
|
+
|
|
634
|
+
`ISOLATED_ENV` is enabled by default in Jenkins. The evaluator seeds known runner config locations into each run's runtime home before execution so that workers can stay isolated without sharing writable global state.
|
|
635
|
+
|
|
636
|
+
After `Prepare`, every worker runs a separate `Install Agent Assets` stage. Default target directories depend on `agent.type`: OpenCode uses `.opencode/*`, MiMo Code uses `.mimocode/*`, Codex CLI uses `.codex/*`, and Claude Code uses `.claude/*`. A flat `work/skills` fallback is also checked for other package layouts. The install report is written under the selected runner log directory.
|
|
637
|
+
|
|
638
|
+
Before workers start, Jenkins runs `Report Work Version` against the materialized submitted work directory. The console prints the resolved `versions.json`, `work package version`, all registered Skill/Agent versions, and any skill-pack versions discovered from `pack.json` files. With `REQUIRE_WORK_VERSION=true`, missing or unreadable version metadata fails before agent execution, which keeps real test logs tied to the exact work package under evaluation. Set it to `false` when onboarding a simple work package that has not adopted version metadata yet.
|
|
639
|
+
|
|
640
|
+
Use the Jenkins `AGENT_ASSET_INSTALLS` text parameter to add more mappings after the default install, one per line:
|
|
641
|
+
|
|
642
|
+
```text
|
|
643
|
+
work/commands=>.opencode/command
|
|
644
|
+
work/references=>.opencode/references
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
Recommended Jenkins parameters for a first real run:
|
|
648
|
+
|
|
649
|
+
```text
|
|
650
|
+
EVAL_CONFIG=
|
|
651
|
+
CONCURRENCY=1
|
|
652
|
+
TIMEOUT_MINUTES=90
|
|
653
|
+
IDLE_TIMEOUT_MINUTES=10
|
|
654
|
+
DRY_RUN=false
|
|
655
|
+
SMOKE_MODE=false
|
|
656
|
+
ISOLATED_ENV=true
|
|
657
|
+
STREAM_OUTPUT=true
|
|
658
|
+
CONSOLE_LOG_MODE=important
|
|
659
|
+
MODEL_MATRIX=
|
|
660
|
+
REASONING_VARIANT=high
|
|
661
|
+
PROVIDER_API_FAILURE_GRACE=5
|
|
662
|
+
REQUIRE_WORK_VERSION=true
|
|
663
|
+
AGENT_INSPECTOR=false
|
|
664
|
+
AGENT_INSPECTOR_CONFIG_DIR=<agent-inspector-data-dir-if-used>
|
|
665
|
+
TASK_REPO_URL=<task repository https url>
|
|
666
|
+
TASK_REPO_REF=main
|
|
667
|
+
WORK_REPO_URL=<submitted work repository https url>
|
|
668
|
+
WORK_REPO_REF=main
|
|
669
|
+
WORK_REPO_WORK_DIR=work
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
For DeepSeek model routes that spend long periods in quiet subagent or subprocess phases, prefer a model-keyed idle timeout while keeping other workers at the default:
|
|
673
|
+
|
|
674
|
+
```text
|
|
675
|
+
IDLE_TIMEOUT_MINUTES=deepseek-v4-pro=30,default=10
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
For exploration, raise `CONCURRENCY` up to `5`. Each worker receives an independent task copy, work copy, HOME, TEMP, cache, config, optional Maven local repository, agent log, score output, and final work artifacts.
|
|
679
|
+
|
|
680
|
+
`TIMEOUT_MINUTES` is the initial per-worker timeout. It accepts a single value (`90`), a worker-position list (`90,120,90`; the last value is reused), or model-keyed entries (`model-a=120,model-b=90,default=90`). Model keys can use the full route such as `agent-inspector/model-a` or the short model name. Jenkins prints the resolved timeout plan before workers start.
|
|
681
|
+
|
|
682
|
+
`IDLE_TIMEOUT_MINUTES` follows the same single/list/model-keyed shape and also allows `0` to disable idle protection for the matching worker.
|
|
683
|
+
|
|
684
|
+
Use an OS-local Agent Inspector data directory, for example `~/.agent-inspector` on Linux/macOS or a Jenkins service-account directory on Windows. Do not commit that machine path into this repository.
|
|
685
|
+
|
|
686
|
+
Use Jenkins global `OEVAL_PYTHON_CMD` and `OEVAL_EXTRA_PATHS` to solidify service-account tools instead of repeating paths on every build. Use `PYTHON_CMD` only when auto-detection is not enough. Empty means Jenkins tries `OEVAL_PYTHON_CMD`, then `python3`/`python` on Linux/macOS and `python`/`python3`/`py -3` on Windows. Python 3.12 is supported; the evaluator avoids runtime dependencies and version-specific schema libraries. Use `MAVEN_HOME_OVERRIDE`, `Maven_Home`, and `MAVEN_HOME` only for configs whose validation commands need Maven. Use `EXTRA_PATHS` for one build or controller-level `OEVAL_EXTRA_PATHS` for scheduled builds when the Jenkins agent does not already expose required tools on `PATH`. The value is interpreted with the current node's path separator at runtime, so Windows, Linux, and macOS jobs can use the same Jenkinsfile without committed host paths. `PREFER_SSH_CLONE=true` tries configured SSH URLs first and falls back to HTTPS when SSH is unavailable; fetch stages also honor `FETCH_TIMEOUT_MINUTES`. For formal regression, enable `REQUIRE_ACCEPT=true` so the aggregate stage returns non-zero when every worker remains below `ACCEPT`; leave it disabled while exploring model behavior. Enable `REQUIRE_NO_REGRESSION=true` when a batch must not regress against `runs/history`; use `BASELINE_BATCH_ID` to compare against a specific batch and `REGRESSION_TOLERANCE` to allow a small best-score drop.
|
|
687
|
+
|
|
688
|
+
When Agent Inspector is enabled, Jenkins runs `<python> -m eval check-inspector-models` against every entry in `MODEL_MATRIX`. This fails fast when Agent Inspector is unhealthy, a provider is unreachable, or a model name is not registered, instead of discovering the mistake in separate worker branches. Jenkins also runs `<python> -m eval check-inspector-mcp --batch-id <batch-id>` before declaring the Inspector group, so missing Streamable HTTP MCP tools are recorded as `runs/batches/<batch-id>/inspector-mcp-check.json` and `.md` with an `error_kind`.
|
|
689
|
+
|
|
690
|
+
For non-dry real runs, Jenkins also runs `<python> -m eval check-tools` for executables listed in `WORKER_TOOLS`; leave it empty to use the selected runner default. Add `java,mvn` when the selected config uses Maven validation. `DRY_RUN=true` skips this worker-tool gate unless evaluator-side validation is enabled, so scheduler smoke tests can run on a lighter controller node.
|
|
691
|
+
|
|
692
|
+
To compare two model routes in one real batch:
|
|
693
|
+
|
|
694
|
+
```text
|
|
695
|
+
CONCURRENCY=2
|
|
696
|
+
MODEL_MATRIX=agent-inspector/model-a,agent-inspector/model-b
|
|
697
|
+
DRY_RUN=false
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
The first worker uses `model-a` and the second worker uses `model-b`. If `CONCURRENCY` is larger than the number of entries, Jenkins reuses the last model entry for remaining workers.
|
|
701
|
+
|
|
702
|
+
To compare multiple runner adapters in one Jenkins job, set `RUNNER_MATRIX` by worker index and keep `MODEL_MATRIX` aligned by worker index:
|
|
703
|
+
|
|
704
|
+
```text
|
|
705
|
+
CONCURRENCY=4
|
|
706
|
+
RUNNER_MATRIX=codex,opencode,mimocode,claude
|
|
707
|
+
MODEL_MATRIX=agent-inspector/MiniMax-M3,agent-inspector/deepseek-v4-pro,agent-inspector/glm-5.2,agent-inspector/MiniMax-M3
|
|
708
|
+
DRY_RUN=false
|
|
709
|
+
```
|
|
710
|
+
|
|
711
|
+
Each worker writes a runner-specific effective config before `prepare`, but all workers reuse the same fetched task/work input snapshot. If `CONCURRENCY` is larger than the number of runner entries, Jenkins reuses the last runner entry for remaining workers.
|
|
712
|
+
|
|
713
|
+
The Jenkinsfile ships without an active cron trigger. If you want scheduled
|
|
714
|
+
runs, add a Jenkins timer in the job or add a branch-local trigger such as:
|
|
715
|
+
|
|
716
|
+
```text
|
|
717
|
+
trigger: H 22 * * *
|
|
718
|
+
CONCURRENCY=3
|
|
719
|
+
DRY_RUN=false
|
|
720
|
+
MODEL_MATRIX=agent-inspector/model-a,agent-inspector/model-b,agent-inspector/model-c
|
|
721
|
+
```
|
|
722
|
+
|
|
723
|
+
`H 22 * * *` runs once during the Jenkins controller's local 22:00 hour and lets Jenkins choose a stable minute. Manual builds use the submitted parameters; timer-triggered builds, when you configure one in your environment, switch to the scheduled execution mode and reuse the configured `MODEL_MATRIX`. The nightly batch id uses the `nightly-<build-number>` prefix unless `BATCH_ID` is explicitly provided.
|
|
724
|
+
|
|
725
|
+
`STREAM_OUTPUT` is enabled by default, but Jenkins uses `CONSOLE_LOG_MODE=important` by default. In this mode the controller console mirrors start, heartbeat, timeout, provider failure, error, build result, score, and session summary lines while the full stdout/stderr transcript is still written to `runs/<run-id>/<agent-log-dir>/opencode.log`. Use `CONSOLE_LOG_MODE=full` only for short single-worker debugging because high-volume agent JSON streams can put pressure on the Jenkins controller. Use `CONSOLE_LOG_MODE=off` when the archived agent log and HTML report are enough.
|
|
726
|
+
|
|
727
|
+
Each isolated worker also receives its own Maven local repository under `<run>/runtime/m2-repository` via `MAVEN_OPTS=-Dmaven.repo.local=...`. This avoids concurrent workers corrupting or locking a shared service-account `.m2` repository while still letting project-declared Maven commands run normally.
|
|
728
|
+
|
|
729
|
+
Runner commands are resolved from each worker's `agent.type`; `RUNNER_MATRIX` overrides that value per worker. OpenCode maps `REASONING_VARIANT` to `--variant`; Codex CLI and Claude Code ignore it. MiMo Code defaults to the harness-managed `harness-build` agent and ignores reasoning-style values such as `high`, `max`, `medium`, and `low` so Jenkins reasoning settings do not accidentally become MiMo agent names. Use `agent.variant` or a MiMo-specific command only when you intentionally want a MiMo agent such as `build`, `plan`, or `compose`. The default MiMo command passes `--dangerously-skip-permissions`, `--dir={workspace}`, and writes an isolated `harness-build` agent config with `external_directory=*` allowed for non-interactive Jenkins runs. Claude Code's own `--agent` flag selects a named Claude agent rather than a reasoning level, so configure it only in a Claude-specific command when needed. Codex and Claude strip the `agent-inspector/` route prefix before passing `--model`; Codex also normalizes display names such as `MiniMax M3` to `MiniMax-M3`. For OpenCode and MiMo Code, the same selected route is written into the isolated runtime config as `model`; MiMo Code also pins both `harness-build` and built-in `build` to that route so internal sessions do not fall back to `mimo-auto`. For Claude Code, the same resolved model is also pinned through `ANTHROPIC_MODEL`, `CLAUDE_CODE_SUBAGENT_MODEL`, alias model env vars, and isolated `.claude/settings.json`, so Claude subagents do not fall back to a default Haiku/Sonnet route during Inspector runs. Agent Inspector is optional: Jenkins prepares it only when `AGENT_INSPECTOR=true` or a model route uses `agent-inspector/*`. When enabled, the evaluator injects `LLM_BASE_URL=http://127.0.0.1:25947/proxy` before launching OpenCode/MiMo-compatible runners, can write isolated provider config for Codex/OpenCode/MiMo, and injects `ANTHROPIC_BASE_URL` plus `ANTHROPIC_API_KEY` before launching Claude Code. Runs that request `agent-inspector/*` also record an `inspector_route` check in `manifest.json` and `evaluation/evaluation.json`; runtime evidence such as `mimo/mimo-auto` during an Inspector run is reported as `inspector route mismatch`. Jenkins and local runs record runner version evidence through `runner-version-check` and each run's `manifest.json`. The shared runner prompt also asks workers to write full helper/finalization output to `work/logs/trace` before previewing it, instead of executing helpers through truncating pipes such as `Select-Object -First` or `head`.
|
|
730
|
+
|
|
731
|
+
For Windows service deployments, do not leave the Jenkins controller at tiny defaults such as `-Xmx256m` when running three or more agent workers. A practical local baseline is `-Xmx2g`; use `-Xmx4g` when publishing full reports or retaining many active builds.
|
|
732
|
+
|
|
733
|
+
After each agent worker exits, the evaluator parses `<agent-log-dir>/opencode.log` and writes `<agent-log-dir>/sessions.json` plus `sessions.md`. These files list the primary session, subagent sessions, parent-child relationships, agent names, model routes, token totals, error counts, and a best-effort Agent Inspector UI link such as `http://127.0.0.1:25947/?sessionId=<session-id>`. If the log does not expose enough session data, the evaluator attempts an Agent Inspector `/api/logs` backfill. Backfill now prefers the worker's `sessionId` or `clientPid` before model-wide queries, writes the full compact evidence set to `<agent-log-dir>/inspector-logs.json`, and keeps a preview table plus count/query metadata in `sessions.md`. The Jenkinsfile also uses Agent Inspector's Streamable HTTP MCP endpoint at `/api/mcp` to declare a batch group before workers start, declare each run after prepare, attach the discovered primary session after execute, update run status after score, and export group evidence before artifacts are copied back. MCP failures are classified as `mcp-unreachable`, `mcp-tool-missing`, `mcp-timeout`, `mcp-protocol`, or `mcp-error` and recorded as Inspector evidence under `<agent-log-dir>/inspector-*.json`, `runs/batches/<batch-id>/inspector-mcp-check.json`, or `runs/batches/<batch-id>/inspector-evidence.json`; they do not change the evaluator score because the agent log remains the source of truth.
|
|
734
|
+
|
|
735
|
+
Heartbeat means the evaluator wrapper and child process are still alive; it does not prove the agent is making useful progress. `IDLE_TIMEOUT_MINUTES` is enabled by default at 10 minutes: if a worker produces no child output or watched artifact activity for that long, the evaluator writes `<agent-log-dir>/process-diagnostics-*.json` and `.md`, terminates it, records an `IDLE TIMEOUT` marker in the agent log, scores whatever partial artifacts exist, and lets the batch aggregate continue. The same process diagnostics are written before total timeout, provider fail-fast, and manual interrupt cleanup. They include the process tree, command lines, elapsed/idle timings, watched artifact paths, recent session/subagent activity, and recent log tail, so quiet subagent or subprocess hangs can be inspected after Jenkins archives `runs/**`. Watched artifact activity is checked by the Python runner, not by platform shell tools, and defaults to `workspace/work/logs/trace`, `workspace/work/reports`, and `workspace/work/result`. When those files change during a quiet subagent phase, Jenkins prints `[artifact-activity] ...` and the idle timer is reset. When Agent Inspector is enabled, the evaluator also polls `/api/logs` for the worker's known OpenCode session ids every `SESSION_ACTIVITY_CHECK_SECONDS` / `execution.session_activity_check_seconds` seconds, prints `[session-activity] ...`, and resets the idle timer only when that worker's own session has new Inspector evidence. `SUBAGENT_IDLE_GRACE_WINDOWS` and `execution.subagent_idle_grace_windows` default to `1`, granting one extra idle window when recent agent log activity shows a subagent was active; set it to `0` for strict fail-fast idle behavior.
|
|
736
|
+
|
|
737
|
+
The total worker timeout can also be adjusted while a worker is already running. Each execute step writes and watches `<external-runs>/<run-id>/control/timeout.json`; the runner checks it every few seconds and records `TIMEOUT CONTROL UPDATED` in the agent log when the value changes. From another terminal or Jenkins helper job, update a running batch with:
|
|
738
|
+
|
|
739
|
+
```bash
|
|
740
|
+
python -m eval update-timeout --runs-dir <external-runs> --batch-id <batch-id> --count <workers> --timeout-minutes 120
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
Use `--workers 1,3` to update selected workers, or `--run <external-runs>/<run-id>` when you know the exact run directory. This changes the live timeout used by the evaluator wrapper; Jenkins build parameters remain immutable for the already-started build.
|
|
744
|
+
|
|
745
|
+
If the agent reports a fatal model/provider setup problem, for example rate limiting, invalid API credentials, unknown model/provider, or provider connection failure, the evaluator writes a `PROVIDER FAILURE DETECTED` marker, terminates the agent process tree, and returns exit code `125`. Generic provider API stream failures are treated as transient by default: `PROVIDER_API_FAILURE_GRACE` and `execution.provider_api_failure_grace` default to `5`, so the evaluator writes `PROVIDER FAILURE WARNING` markers and lets the worker continue until the grace count is exceeded. Set the value to `0` for fail-fast behavior. This keeps Jenkins from waiting for the full idle timeout when the external model provider is clearly unavailable, while still giving models a chance to recover from temporary stream interruptions. Agent Inspector startup/health failures stop before the worker starts when Inspector is enabled. The pipeline still scores and exports partial artifacts so the failure reason remains visible in the agent log and the batch summary. If the worker is interrupted after producing validation logs but before writing final artifacts, scoring first tries helpers listed in `execution.final_result_recovery_helpers`, including a legacy helper argument set for older work packages. If helper recovery is unavailable or incompatible, the harness writes built-in `PARTIAL` final artifacts and records `final-result` in the recovery column; recovered artifacts do not hide failing validation.
|
|
746
|
+
|
|
747
|
+
Provider failure detection is runner-aware. For structured JSON/JSONL streams, the harness scans only explicit error carriers such as top-level `error`, `request/response/session/turn failed`, Claude `result` events with `is_error=true` or an error subtype, `system` API error events, `level=ERROR/FATAL/CRITICAL`, and explicit runtime error payloads. It deliberately ignores assistant/model analysis, user tool results, tool-use events, Codex `command_execution` output, and agent messages, so business-domain text such as `401`, `403`, `FORBIDDEN`, `UNAUTHORIZED`, `/api/v1`, or `errorCode` in generated code, tests, validation logs, or reports is treated as task evidence rather than a provider outage. Plain stderr/stdout is still scanned for real provider tokens such as connection failures, invalid credentials, rate limits, unknown models, and retry exhaustion.
|
|
748
|
+
|
|
749
|
+
After all branches finish, Jenkins runs these as separate nodes:
|
|
750
|
+
|
|
751
|
+
```text
|
|
752
|
+
<python> -m eval aggregate --batch-id <batch-id> --count <CONCURRENCY> --parallel <CONCURRENCY>
|
|
753
|
+
<python> -m eval inspector-export-group --batch-id <batch-id>
|
|
754
|
+
<python> -m eval export --batch-id <batch-id> --count <CONCURRENCY> --output runs --clean-output
|
|
755
|
+
<python> -m eval validate-artifacts --root runs --batch-id <batch-id> --count <CONCURRENCY>
|
|
756
|
+
<python> -m eval list
|
|
757
|
+
```
|
|
758
|
+
|
|
759
|
+
Before aggregation, Jenkins seeds the temporary external run directory from the previous workspace `runs/history` when it exists. If the workspace was wiped, the seed step is skipped and the current batch becomes a new baseline. `aggregate` writes `summary.json`, `summary.md`, `model-report.json`, `model-report.md`, `experiment.json`, `comparison.json`, `comparison.md`, and `history/**` under the external runs directory. `export` copies the consumable artifacts back into the Jenkins workspace `runs/` directory for archiving:
|
|
760
|
+
|
|
761
|
+
- `runs/batches/<batch-id>/summary.json`
|
|
762
|
+
- `runs/batches/<batch-id>/summary.md`
|
|
763
|
+
- `runs/batches/<batch-id>/model-report.json`
|
|
764
|
+
- `runs/batches/<batch-id>/model-report.md`
|
|
765
|
+
- `runs/batches/<batch-id>/experiment.json`
|
|
766
|
+
- `runs/batches/<batch-id>/comparison.json`
|
|
767
|
+
- `runs/batches/<batch-id>/comparison.md`
|
|
768
|
+
- `runs/batches/<batch-id>/inspector-mcp-check.json`
|
|
769
|
+
- `runs/batches/<batch-id>/inspector-group.json`
|
|
770
|
+
- `runs/batches/<batch-id>/inspector-evidence.json`
|
|
771
|
+
- `runs/history/**`
|
|
772
|
+
- `runs/<run-id>/manifest.json`
|
|
773
|
+
- `runs/<run-id>/evaluation/**`
|
|
774
|
+
- `runs/<run-id>/<agent-log-dir>/**`
|
|
775
|
+
- `runs/<run-id>/workspace/work/result/**`
|
|
776
|
+
- `runs/<run-id>/workspace/work/reports/**`
|
|
777
|
+
- `runs/<run-id>/workspace/work/logs/trace/**`
|
|
778
|
+
- `runs/index.md`
|
|
779
|
+
- `runs/index.html`
|
|
780
|
+
|
|
781
|
+
Input snapshots are exported with heavy generated folders filtered out (`.git`, `target`, `build`, `node_modules`, `.m2`, and similar cache/build directories). The copied `runs/inputs/task` and `runs/inputs/work` remain usable for reruns, but Jenkins artifacts stay small enough for the UI and API to load comfortably.
|
|
782
|
+
|
|
783
|
+
Codex should read the archived `runs/batches/<batch-id>/summary.md` first, then inspect `comparison.md`, `history/index.md`, `model-report.md`, `experiment.json`, `inspector-mcp-check.md`, `inspector-evidence.md`, and the best run's `evaluation/skill-improvement-input.json`, `evaluation/next-action.json`, `evaluation/recommendations.md`, `evaluation/judge-input.md`, `<agent-log-dir>/sessions.md`, `<agent-log-dir>/inspector-*.md`, and agent log for the next skill, agent, or Instruction improvement. The summary and model report also expose the work package's semantic-memory score, which is derived from `work/logs/trace/memory/semantic-memory-events.jsonl` and helps identify runs that scored similarly but differed in rule/flow/route/final-checklist evidence.
|
|
784
|
+
|
|
785
|
+
Jenkins does not natively render runner messages as a chat UI. The evaluator therefore exports `runs/index.html`, which renders the batch table, score dimensions and semantic-memory score for each run, agent session summaries, raw artifact links, log/output previews, evaluator recommendations, and next-action JSON. Full logs and result artifacts remain available as links instead of being fully embedded in the HTML. If the Jenkins HTML Publisher plugin is installed, the `Jenkinsfile` publishes this as `Eval Harness Report`; otherwise the same file is still archived under build artifacts.
|
|
786
|
+
|
|
787
|
+
Recommended Jenkins plugins for this job:
|
|
788
|
+
|
|
789
|
+
- Already required by the current pipeline shape: Pipeline, Git, Timestamper, Build Timeout, Workspace Cleanup, Pipeline Stage View.
|
|
790
|
+
- Strongly recommended: HTML Publisher for the structured report page, AnsiColor for readable colored console output, Log Parser for highlighting timeout/error markers.
|
|
791
|
+
- Optional: Pipeline Utility Steps for richer Jenkinsfile-side JSON summaries, Blue Ocean for a different parallel pipeline view.
|
|
792
|
+
|
|
793
|
+
Default decisions:
|
|
794
|
+
|
|
795
|
+
- `ACCEPT`: score is at or above `scoring.thresholds.accept_score`, final status is `PASS`, and no hard evidence is missing.
|
|
796
|
+
- `INVESTIGATE`: enough evidence exists to inspect or compare, but the run is not ready to accept.
|
|
797
|
+
- `REJECT`: final artifacts, trace logs, status, or protected-path boundaries are broken.
|
|
798
|
+
|
|
799
|
+
## Agent Runners
|
|
800
|
+
|
|
801
|
+
The harness currently supports these `agent.type` values:
|
|
802
|
+
|
|
803
|
+
- `codex` or `codex-cli`: CodeX/Codex CLI runner.
|
|
804
|
+
- `opencode`: OpenCode CLI runner.
|
|
805
|
+
- `mimocode` or `mimo`: MiMo Code runner.
|
|
806
|
+
- `claude` or `claude-code`: Claude Code runner.
|
|
807
|
+
|
|
808
|
+
Each runner has its own default command, log directory, runtime profile seeding, and default work asset install targets. Use `execution.agent.command`, `execution.<runner>.command`, or `execution.<runner>_command` to override the default command without changing Python code.
|
|
809
|
+
|
|
810
|
+
Default runner commands include the harness execution contract: respect `AGENT_EVAL_TIMEOUT_MINUTES`, leave time for finalization, write the required final artifacts, and avoid UTF-8 BOM output for Windows source edits. If you override a runner command, keep those requirements in the prompt.
|
|
811
|
+
|
|
812
|
+
MiMo Code default runs are non-interactive by design. The harness writes an isolated `harness-build` MiMo agent that allows all tool permissions, including `external_directory=*`, and launches `mimo run` with `--dangerously-skip-permissions`, `--dir={workspace}`, and `--agent harness-build`. MiMo's built-in `build` agent leaves `external_directory=*` as `ask`, which becomes an auto-reject under Jenkins; the harness-managed agent avoids that approval prompt without modifying the user's global MiMo profile.
|
|
813
|
+
|
|
814
|
+
CodeX/Codex CLI example:
|
|
815
|
+
|
|
816
|
+
```json
|
|
817
|
+
{
|
|
818
|
+
"agent": {
|
|
819
|
+
"type": "codex",
|
|
820
|
+
"executable": "C:\\Users\\you\\AppData\\Local\\OpenAI\\Codex\\bin\\<version>\\codex.exe"
|
|
821
|
+
},
|
|
822
|
+
"execution": {
|
|
823
|
+
"codex_command": [
|
|
824
|
+
"{agent_executable}",
|
|
825
|
+
"exec",
|
|
826
|
+
"--json",
|
|
827
|
+
"--skip-git-repo-check",
|
|
828
|
+
"--dangerously-bypass-approvals-and-sandbox",
|
|
829
|
+
"--cd",
|
|
830
|
+
"{workspace}",
|
|
831
|
+
"Read and execute work/INSTRUCTION.md. Work autonomously, do not ask for human input, and write all required result artifacts."
|
|
832
|
+
]
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
```
|
|
836
|
+
|
|
837
|
+
On Windows Jenkins service accounts, Codex CLI resolution first honors `agent.executable`, `codex.executable`, `execution.codex_executable`, `execution.codex.executable`, or `OEVAL_CODEX_EXECUTABLE`, then auto-discovers the current user's `%LOCALAPPDATA%\OpenAI\Codex\bin\*\codex.exe` before falling back to `PATH`. Prefer a runner-specific local override when the service account uses a nonstandard install; do not commit machine paths into shared config.
|
|
838
|
+
|
|
839
|
+
The common `--model` override works for CodeX/Codex CLI as well:
|
|
840
|
+
|
|
841
|
+
```powershell
|
|
842
|
+
python -m eval execute --run runs/<run-id> --model gpt-5
|
|
843
|
+
```
|
|
844
|
+
|
|
845
|
+
Claude Code example:
|
|
846
|
+
|
|
847
|
+
```json
|
|
848
|
+
{
|
|
849
|
+
"agent": {
|
|
850
|
+
"type": "claude-code",
|
|
851
|
+
"executable": "claude"
|
|
852
|
+
},
|
|
853
|
+
"execution": {
|
|
854
|
+
"claude_command": [
|
|
855
|
+
"{agent_executable}",
|
|
856
|
+
"-p",
|
|
857
|
+
"--output-format",
|
|
858
|
+
"stream-json",
|
|
859
|
+
"--verbose",
|
|
860
|
+
"--dangerously-skip-permissions",
|
|
861
|
+
"Read and execute work/INSTRUCTION.md. Work autonomously, do not ask for human input, and write all required result artifacts."
|
|
862
|
+
]
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
```
|
|
866
|
+
|
|
867
|
+
For Agent Inspector routes, `agent-inspector/MiniMax-M3` is passed to Claude Code
|
|
868
|
+
as `--model MiniMax-M3`, and the runner injects `ANTHROPIC_BASE_URL` plus
|
|
869
|
+
`ANTHROPIC_API_KEY` into the isolated worker environment. The same model is
|
|
870
|
+
also pinned for Claude subagents with `CLAUDE_CODE_SUBAGENT_MODEL`; for example
|
|
871
|
+
`agent-inspector/glm-5.2` becomes `--model glm-5.2` and
|
|
872
|
+
`CLAUDE_CODE_SUBAGENT_MODEL=glm-5.2`.
|
|
873
|
+
|
|
874
|
+
Claude Code subagent model routing is intentionally pinned by the harness. Claude
|
|
875
|
+
Code can spawn internal `Agent` / `Explore` subagents, and those subagents may
|
|
876
|
+
have their own model defaults. During an Agent Inspector run, the harness writes
|
|
877
|
+
the resolved worker model into the isolated worker's environment and
|
|
878
|
+
`.claude/settings.json`:
|
|
879
|
+
|
|
880
|
+
- `ANTHROPIC_MODEL=<resolved model>` for the main Claude Code session.
|
|
881
|
+
- `CLAUDE_CODE_SUBAGENT_MODEL=<resolved model>` for spawned subagents.
|
|
882
|
+
- Claude alias model environment variables, including the Haiku/Sonnet aliases,
|
|
883
|
+
so agent frontmatter defaults do not drift to another provider route.
|
|
884
|
+
|
|
885
|
+
If a Claude worker fails with `PROVIDER FAILURE DETECTED: auth-config` and the
|
|
886
|
+
agent log contains `Failed to authenticate. API Error: 403 Request not allowed`,
|
|
887
|
+
check whether subagent log entries show a `resolvedModel` different from the
|
|
888
|
+
requested Inspector model. For example, a run launched with
|
|
889
|
+
`agent-inspector/glm-5.2` should not show subagents resolved as
|
|
890
|
+
`claude-haiku-*`. After this pinning behavior is active, the same run should show
|
|
891
|
+
the main worker and subagents using the same resolved model route.
|
|
892
|
+
|
|
893
|
+
## Agent Command
|
|
894
|
+
|
|
895
|
+
The selected runner command is normally supplied by the runner adapter.
|
|
896
|
+
`config/eval.example.json` intentionally does not pin `opencode_command`,
|
|
897
|
+
`codex_command`, `mimocode_command`, or `claude_command`. Override the command
|
|
898
|
+
only when the default runner command is not suitable for your environment.
|
|
899
|
+
|
|
900
|
+
Supported placeholders:
|
|
901
|
+
|
|
902
|
+
- `{workspace}`: absolute workspace directory.
|
|
903
|
+
- `{instruction}`: workspace-relative `work/INSTRUCTION.md`.
|
|
904
|
+
- `{run_id}`: run identifier.
|
|
905
|
+
- `{timeout_minutes}`: timeout minutes.
|
|
906
|
+
|
|
907
|
+
Prefer these override locations:
|
|
908
|
+
|
|
909
|
+
- `execution.agent.command` for a private single-runner config.
|
|
910
|
+
- `execution.<runner>.command` or `execution.<runner>_command` for shared configs that may switch `agent.type`.
|
|
911
|
+
|
|
912
|
+
Override shape:
|
|
913
|
+
|
|
914
|
+
```json
|
|
915
|
+
{
|
|
916
|
+
"agent": {
|
|
917
|
+
"type": "opencode"
|
|
918
|
+
},
|
|
919
|
+
"execution": {
|
|
920
|
+
"timeout_minutes": 90,
|
|
921
|
+
"agent": {
|
|
922
|
+
"command": [
|
|
923
|
+
"opencode",
|
|
924
|
+
"run",
|
|
925
|
+
"Read and execute the attached INSTRUCTION.md. Work autonomously, do not ask for human input, and write all required result artifacts.",
|
|
926
|
+
"--format",
|
|
927
|
+
"json",
|
|
928
|
+
"--print-logs",
|
|
929
|
+
"--log-level",
|
|
930
|
+
"INFO",
|
|
931
|
+
"--dangerously-skip-permissions",
|
|
932
|
+
"--file={instruction}"
|
|
933
|
+
]
|
|
934
|
+
},
|
|
935
|
+
"agent_inspector": {
|
|
936
|
+
"enabled": false,
|
|
937
|
+
"port": 25947,
|
|
938
|
+
"base_url": "http://127.0.0.1:25947",
|
|
939
|
+
"proxy_url": "http://127.0.0.1:25947/proxy",
|
|
940
|
+
"health_url": "http://127.0.0.1:25947/api/health",
|
|
941
|
+
"providers_url": "http://127.0.0.1:25947/api/providers",
|
|
942
|
+
"mcp_url": "http://127.0.0.1:25947/api/mcp",
|
|
943
|
+
"mcp_enabled": false,
|
|
944
|
+
"mcp_required_tools": [],
|
|
945
|
+
"required_model": "",
|
|
946
|
+
"start_command": ["agent-inspector", "--background", "--no-open", "--port", "25947"],
|
|
947
|
+
"restart_command": ["agent-inspector", "--background", "--no-open", "--port", "25947", "--force-restart"],
|
|
948
|
+
"doctor_command": ["agent-inspector", "doctor", "--port", "25947"],
|
|
949
|
+
"startup_timeout_seconds": 15
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
```
|
|
954
|
+
|
|
955
|
+
The command runs from `runs/<run-id>/workspace`. The evaluator resolves tools with `shutil.which()` before execution, so Windows command shims such as `opencode.cmd` work with Python `subprocess(shell=False)`.
|
|
956
|
+
Legacy `execution.opencode_command` is still accepted for existing OpenCode configs, but new shared configs should use the generic or runner-specific keys above.
|
|
957
|
+
|
|
958
|
+
The CLI can override the configured agent model without rewriting the whole command:
|
|
959
|
+
|
|
960
|
+
```powershell
|
|
961
|
+
python -m eval execute --run runs/<run-id> --model agent-inspector/model-a
|
|
962
|
+
python -m eval batch --config config/eval.local.json --count 2 --parallel 2 --model agent-inspector/model-a --model agent-inspector/model-b
|
|
963
|
+
```
|
|
964
|
+
|
|
965
|
+
The CLI can also inject a runner-specific reasoning or agent variant without rewriting the command:
|
|
966
|
+
|
|
967
|
+
```powershell
|
|
968
|
+
python -m eval execute --run runs/<run-id> --variant high
|
|
969
|
+
python -m eval batch --config config/eval.local.json --count 5 --parallel 5 --variant high
|
|
970
|
+
```
|
|
971
|
+
|
|
972
|
+
Provider API stream failure tolerance is also configurable without rewriting `config/eval.local.json`:
|
|
973
|
+
|
|
974
|
+
```powershell
|
|
975
|
+
python -m eval execute --run runs/<run-id> --provider-api-failure-grace 5
|
|
976
|
+
python -m eval batch --config config/eval.local.json --count 3 --parallel 3 --provider-api-failure-grace 5
|
|
977
|
+
```
|
|
978
|
+
|
|
979
|
+
To route through Agent Inspector, configure an OpenCode provider named `agent-inspector`, set `execution.agent_inspector.enabled=true`, or pass Jenkins `AGENT_INSPECTOR=true` with `MODEL_MATRIX=agent-inspector/<model>`. Agent Inspector is expected on `PATH` as `agent-inspector`. Jenkins checks `http://127.0.0.1:25947/api/health` only when Inspector is enabled or inferred from a model route. Set the Jenkins `AGENT_INSPECTOR_CONFIG_DIR` parameter when the service account should use an existing provider directory, for example `~/.agent-inspector` on Linux/macOS or an equivalent service-account data directory on Windows. If container mode is enabled, update `execution.agent_inspector.proxy_url` to a host-reachable URL such as `http://host.docker.internal:25947/proxy`.
|
|
980
|
+
|
|
981
|
+
## Container Mode
|
|
982
|
+
|
|
983
|
+
Container mode keeps each agent execution isolated while the host evaluator still owns prepare and score.
|
|
984
|
+
|
|
985
|
+
Enable it with CLI:
|
|
986
|
+
|
|
987
|
+
```powershell
|
|
988
|
+
python -m eval execute --run runs/<run-id> --container
|
|
989
|
+
python -m eval batch --config config/eval.local.json --count 5 --parallel 5 --container
|
|
990
|
+
```
|
|
991
|
+
|
|
992
|
+
Or enable it in config:
|
|
993
|
+
|
|
994
|
+
```json
|
|
995
|
+
{
|
|
996
|
+
"container": {
|
|
997
|
+
"enabled": true,
|
|
998
|
+
"engine": "docker",
|
|
999
|
+
"image": "eval-harness-worker:latest",
|
|
1000
|
+
"workspace_mount": "/workspace",
|
|
1001
|
+
"extra_args": []
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
```
|
|
1005
|
+
|
|
1006
|
+
The wrapper command is:
|
|
1007
|
+
|
|
1008
|
+
```text
|
|
1009
|
+
docker run --rm -v <host-workspace>:/workspace -w /workspace <image> <opencode-command>
|
|
1010
|
+
```
|
|
1011
|
+
|
|
1012
|
+
Use `--no-container` to force local execution even when the config enables containers.
|
|
1013
|
+
|
|
1014
|
+
See `containers/opencode-worker.Dockerfile.example` for a starting point. The image must contain Python 3.12-compatible runtime, Git, the selected agent runner, and any extra validators or credentials needed by the selected config.
|
|
1015
|
+
|
|
1016
|
+
## Tests
|
|
1017
|
+
|
|
1018
|
+
Run unit tests without external services:
|
|
1019
|
+
|
|
1020
|
+
```bash
|
|
1021
|
+
python -m unittest
|
|
1022
|
+
```
|
|
1023
|
+
|
|
1024
|
+
```powershell
|
|
1025
|
+
python -m unittest
|
|
1026
|
+
```
|
|
1027
|
+
|
|
1028
|
+
For the optional development tools:
|
|
1029
|
+
|
|
1030
|
+
```bash
|
|
1031
|
+
python -m pip install -e ".[dev]"
|
|
1032
|
+
python -m pytest
|
|
1033
|
+
python -m coverage run -m unittest
|
|
1034
|
+
python -m ruff check .
|
|
1035
|
+
```
|
|
1036
|
+
|
|
1037
|
+
## Evolution Policy
|
|
1038
|
+
|
|
1039
|
+
Recommended later automation:
|
|
1040
|
+
|
|
1041
|
+
- Change only one skill, subagent, or helper concern per iteration.
|
|
1042
|
+
- Use `evaluation/next-action.json`, `evaluation/recommendations.md`, `runs/batches/<batch-id>/summary.md`, and `runs/batches/<batch-id>/model-report.md` to choose the smallest next change.
|
|
1043
|
+
- Bump skill versions after every behavior change.
|
|
1044
|
+
- Sync `.opencode/skills` for directory skills and `.opencode/agents` for top-level subagents.
|
|
1045
|
+
- Rerun this evaluator.
|
|
1046
|
+
- Keep the change only when the score, decision, and hard-failure pattern improve.
|