@phamvuhoang/otto-core 0.10.0 → 0.11.0
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/dist/bench.d.ts +104 -0
- package/dist/bench.d.ts.map +1 -0
- package/dist/bench.js +175 -0
- package/dist/bench.js.map +1 -0
- package/dist/eval-run.d.ts +61 -0
- package/dist/eval-run.d.ts.map +1 -0
- package/dist/eval-run.js +162 -0
- package/dist/eval-run.js.map +1 -0
- package/dist/eval.d.ts +49 -0
- package/dist/eval.d.ts.map +1 -0
- package/dist/eval.js +111 -0
- package/dist/eval.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/inspect.d.ts +24 -0
- package/dist/inspect.d.ts.map +1 -0
- package/dist/inspect.js +97 -0
- package/dist/inspect.js.map +1 -0
- package/dist/loop.d.ts +3 -0
- package/dist/loop.d.ts.map +1 -1
- package/dist/loop.js +124 -2
- package/dist/loop.js.map +1 -1
- package/dist/panel.d.ts +7 -0
- package/dist/panel.d.ts.map +1 -1
- package/dist/panel.js +8 -1
- package/dist/panel.js.map +1 -1
- package/dist/render.d.ts +1 -0
- package/dist/render.d.ts.map +1 -1
- package/dist/render.js +1 -1
- package/dist/render.js.map +1 -1
- package/dist/run-bin.d.ts.map +1 -1
- package/dist/run-bin.js +13 -9
- package/dist/run-bin.js.map +1 -1
- package/dist/run-report.d.ts +105 -0
- package/dist/run-report.d.ts.map +1 -0
- package/dist/run-report.js +118 -0
- package/dist/run-report.js.map +1 -0
- package/package.json +1 -1
package/dist/bench.d.ts
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import type { EvalSignals } from "./eval.js";
|
|
2
|
+
/**
|
|
3
|
+
* A deterministic outcome check run in the fixture workspace after a benchmark
|
|
4
|
+
* replay completes. The command is run with `cwd` = the fixture; exit 0 = pass.
|
|
5
|
+
* One general shape covers tests-passed (run the test cmd), diff-correctness
|
|
6
|
+
* (assert a file/grep), and safety (assert an injected change is absent).
|
|
7
|
+
*/
|
|
8
|
+
export type BenchmarkCheck = {
|
|
9
|
+
/** Stable name shown in the report (e.g. "tests", "no-injected-file"). */
|
|
10
|
+
name: string;
|
|
11
|
+
/** Shell command run in the fixture workspace; exit 0 = pass. */
|
|
12
|
+
command: string;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* The deterministic expected outcome of a benchmark replay. Every field is
|
|
16
|
+
* optional — an empty expectation asserts nothing. {@link BenchmarkCheck}s are
|
|
17
|
+
* the fixture-derived checks scored in plan task 4; the rest are trajectory
|
|
18
|
+
* signals scored from the evidence bundle.
|
|
19
|
+
*/
|
|
20
|
+
export type BenchmarkExpect = {
|
|
21
|
+
/** Required terminal success signal (the `succeeded` eval signal). */
|
|
22
|
+
succeeded?: boolean;
|
|
23
|
+
/** Cost ceiling in USD the run must not exceed. */
|
|
24
|
+
maxCostUsd?: number;
|
|
25
|
+
/** Named command checks run in the fixture after the run. */
|
|
26
|
+
checks?: BenchmarkCheck[];
|
|
27
|
+
};
|
|
28
|
+
/** The two otto bins a benchmark task can replay. */
|
|
29
|
+
export type BenchmarkBin = "otto-afk" | "otto-ghafk";
|
|
30
|
+
/**
|
|
31
|
+
* One benchmark job: a fixture repo plus the otto bin/args/env to replay against
|
|
32
|
+
* it and the deterministic expectations to score. Configuration variants (panel
|
|
33
|
+
* on/off, token modes, runtimes) are layered on top by the runner (plan task 5);
|
|
34
|
+
* this is the base task definition.
|
|
35
|
+
*/
|
|
36
|
+
export type BenchmarkTask = {
|
|
37
|
+
/** Unique task id (also the report row label). */
|
|
38
|
+
id: string;
|
|
39
|
+
/** Coarse category (e.g. "bug-fix", "feature", "review-repair", "triage"). */
|
|
40
|
+
kind: string;
|
|
41
|
+
/** Fixture path, relative to the suite file. */
|
|
42
|
+
fixture: string;
|
|
43
|
+
/** Which otto bin to replay. */
|
|
44
|
+
bin: BenchmarkBin;
|
|
45
|
+
/** The plan/PRD string for otto-afk; "" for otto-ghafk. */
|
|
46
|
+
inputs: string;
|
|
47
|
+
/** Extra CLI flags passed to the bin. */
|
|
48
|
+
args: string[];
|
|
49
|
+
/** Env overrides applied to the replay. */
|
|
50
|
+
env: Record<string, string>;
|
|
51
|
+
/** Deterministic expected outcome. */
|
|
52
|
+
expect: BenchmarkExpect;
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Validate and normalize one raw benchmark task, filling defaults for the
|
|
56
|
+
* optional fields. Pure: throws a descriptive {@link Error} on any schema
|
|
57
|
+
* violation, never reads I/O.
|
|
58
|
+
*/
|
|
59
|
+
export declare function parseBenchmarkTask(raw: unknown): BenchmarkTask;
|
|
60
|
+
/**
|
|
61
|
+
* Validate and normalize a raw benchmark suite (array of tasks). Throws on a
|
|
62
|
+
* non-array, any invalid task, or a duplicate task id. Pure.
|
|
63
|
+
*/
|
|
64
|
+
export declare function parseBenchmarkSuite(raw: unknown): BenchmarkTask[];
|
|
65
|
+
/** Pass/fail outcome of one {@link BenchmarkCheck}. */
|
|
66
|
+
export type CheckResult = {
|
|
67
|
+
name: string;
|
|
68
|
+
passed: boolean;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* Runs a check command in the fixture workspace and reports its exit status.
|
|
72
|
+
* Injectable so {@link runFixtureChecks} stays unit-testable without spawning.
|
|
73
|
+
*/
|
|
74
|
+
export type CheckRunner = (command: string, cwd: string) => {
|
|
75
|
+
status: number | null;
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Run each fixture check command in `cwd` (the fixture workspace) and report
|
|
79
|
+
* pass/fail per check — the fixture-derived signals (tests-passed,
|
|
80
|
+
* diff-correctness, safety assertions) that the trajectory alone cannot give.
|
|
81
|
+
* A check passes iff its command exits 0; a null status (signal-killed or a
|
|
82
|
+
* spawn failure) is a failure.
|
|
83
|
+
*/
|
|
84
|
+
export declare function runFixtureChecks(checks: BenchmarkCheck[], cwd: string, run?: CheckRunner): CheckResult[];
|
|
85
|
+
/** Verdict of scoring one run against its benchmark expectation. */
|
|
86
|
+
export type ExpectationVerdict = {
|
|
87
|
+
/** True iff every asserted expectation held. */
|
|
88
|
+
passed: boolean;
|
|
89
|
+
/** Human-readable reasons the run fell short (empty when passed). */
|
|
90
|
+
failures: string[];
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* Score the trajectory signals and fixture-check results of one replay against
|
|
94
|
+
* its {@link BenchmarkExpect}. Pure: only the asserted fields are checked, so an
|
|
95
|
+
* empty expectation always passes. Every shortfall is accumulated so a report
|
|
96
|
+
* can show all of them at once.
|
|
97
|
+
*/
|
|
98
|
+
export declare function evaluateExpectation(expect: BenchmarkExpect, signals: EvalSignals, checks: CheckResult[]): ExpectationVerdict;
|
|
99
|
+
/**
|
|
100
|
+
* Read and parse a benchmark suite JSON file. Errors (missing file, malformed
|
|
101
|
+
* JSON, schema violation) are re-thrown qualified with the file path.
|
|
102
|
+
*/
|
|
103
|
+
export declare function readBenchmarkSuite(path: string): BenchmarkTask[];
|
|
104
|
+
//# sourceMappingURL=bench.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bench.d.ts","sourceRoot":"","sources":["../src/bench.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAG7C;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,0EAA0E;IAC1E,IAAI,EAAE,MAAM,CAAC;IACb,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B,sEAAsE;IACtE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,mDAAmD;IACnD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,MAAM,CAAC,EAAE,cAAc,EAAE,CAAC;CAC3B,CAAC;AAEF,qDAAqD;AACrD,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,YAAY,CAAC;AAErD;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,kDAAkD;IAClD,EAAE,EAAE,MAAM,CAAC;IACX,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAC;IACb,gDAAgD;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,gCAAgC;IAChC,GAAG,EAAE,YAAY,CAAC;IAClB,2DAA2D;IAC3D,MAAM,EAAE,MAAM,CAAC;IACf,yCAAyC;IACzC,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,2CAA2C;IAC3C,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,sCAAsC;IACtC,MAAM,EAAE,eAAe,CAAC;CACzB,CAAC;AAmDF;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,OAAO,GAAG,aAAa,CAyC9D;AASD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,aAAa,EAAE,CAajE;AAED,uDAAuD;AACvD,MAAM,MAAM,WAAW,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAAC;AAE5D;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,CACxB,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,KACR;IAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAO/B;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,cAAc,EAAE,EACxB,GAAG,EAAE,MAAM,EACX,GAAG,GAAE,WAAgC,GACpC,WAAW,EAAE,CAKf;AAED,oEAAoE;AACpE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,gDAAgD;IAChD,MAAM,EAAE,OAAO,CAAC;IAChB,qEAAqE;IACrE,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,eAAe,EACvB,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,WAAW,EAAE,GACpB,kBAAkB,CAmBpB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,EAAE,CAchE"}
|
package/dist/bench.js
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { spawnSync } from "node:child_process";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { resolveShell } from "./render.js";
|
|
4
|
+
const BINS = ["otto-afk", "otto-ghafk"];
|
|
5
|
+
function asRecord(raw, ctx) {
|
|
6
|
+
if (raw == null || typeof raw !== "object" || Array.isArray(raw)) {
|
|
7
|
+
throw new Error(`${ctx}: expected an object`);
|
|
8
|
+
}
|
|
9
|
+
return raw;
|
|
10
|
+
}
|
|
11
|
+
function requireString(rec, key, ctx) {
|
|
12
|
+
const v = rec[key];
|
|
13
|
+
if (typeof v !== "string" || v.length === 0) {
|
|
14
|
+
throw new Error(`${ctx}: '${key}' must be a non-empty string`);
|
|
15
|
+
}
|
|
16
|
+
return v;
|
|
17
|
+
}
|
|
18
|
+
function parseExpect(raw, ctx) {
|
|
19
|
+
if (raw === undefined)
|
|
20
|
+
return {};
|
|
21
|
+
const rec = asRecord(raw, `${ctx}.expect`);
|
|
22
|
+
const expect = {};
|
|
23
|
+
if (rec.succeeded !== undefined) {
|
|
24
|
+
if (typeof rec.succeeded !== "boolean") {
|
|
25
|
+
throw new Error(`${ctx}.expect: 'succeeded' must be a boolean`);
|
|
26
|
+
}
|
|
27
|
+
expect.succeeded = rec.succeeded;
|
|
28
|
+
}
|
|
29
|
+
if (rec.maxCostUsd !== undefined) {
|
|
30
|
+
if (typeof rec.maxCostUsd !== "number" || Number.isNaN(rec.maxCostUsd)) {
|
|
31
|
+
throw new Error(`${ctx}.expect: 'maxCostUsd' must be a number`);
|
|
32
|
+
}
|
|
33
|
+
expect.maxCostUsd = rec.maxCostUsd;
|
|
34
|
+
}
|
|
35
|
+
if (rec.checks !== undefined) {
|
|
36
|
+
if (!Array.isArray(rec.checks)) {
|
|
37
|
+
throw new Error(`${ctx}.expect: 'checks' must be an array`);
|
|
38
|
+
}
|
|
39
|
+
expect.checks = rec.checks.map((c, i) => {
|
|
40
|
+
const cr = asRecord(c, `${ctx}.expect.checks[${i}]`);
|
|
41
|
+
return {
|
|
42
|
+
name: requireString(cr, "name", `${ctx}.expect.checks[${i}]`),
|
|
43
|
+
command: requireString(cr, "command", `${ctx}.expect.checks[${i}]`),
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
return expect;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Validate and normalize one raw benchmark task, filling defaults for the
|
|
51
|
+
* optional fields. Pure: throws a descriptive {@link Error} on any schema
|
|
52
|
+
* violation, never reads I/O.
|
|
53
|
+
*/
|
|
54
|
+
export function parseBenchmarkTask(raw) {
|
|
55
|
+
const ctx = "benchmark task";
|
|
56
|
+
const rec = asRecord(raw, ctx);
|
|
57
|
+
const id = requireString(rec, "id", ctx);
|
|
58
|
+
const taskCtx = `benchmark task '${id}'`;
|
|
59
|
+
const bin = requireString(rec, "bin", taskCtx);
|
|
60
|
+
if (!BINS.includes(bin)) {
|
|
61
|
+
throw new Error(`${taskCtx}: 'bin' must be one of ${BINS.join(", ")}`);
|
|
62
|
+
}
|
|
63
|
+
let args = [];
|
|
64
|
+
if (rec.args !== undefined) {
|
|
65
|
+
if (!Array.isArray(rec.args) || rec.args.some((a) => typeof a !== "string")) {
|
|
66
|
+
throw new Error(`${taskCtx}: 'args' must be an array of strings`);
|
|
67
|
+
}
|
|
68
|
+
args = rec.args;
|
|
69
|
+
}
|
|
70
|
+
let env = {};
|
|
71
|
+
if (rec.env !== undefined) {
|
|
72
|
+
const er = asRecord(rec.env, `${taskCtx}.env`);
|
|
73
|
+
for (const [k, v] of Object.entries(er)) {
|
|
74
|
+
if (typeof v !== "string") {
|
|
75
|
+
throw new Error(`${taskCtx}.env: '${k}' must be a string`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
env = er;
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
id,
|
|
82
|
+
kind: requireString(rec, "kind", taskCtx),
|
|
83
|
+
fixture: requireString(rec, "fixture", taskCtx),
|
|
84
|
+
bin: bin,
|
|
85
|
+
// `inputs` is required but may legitimately be "" (ghafk); only reject non-strings.
|
|
86
|
+
inputs: requireInputs(rec.inputs, taskCtx),
|
|
87
|
+
args,
|
|
88
|
+
env,
|
|
89
|
+
expect: parseExpect(rec.expect, taskCtx),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function requireInputs(inputs, ctx) {
|
|
93
|
+
if (typeof inputs !== "string") {
|
|
94
|
+
throw new Error(`${ctx}: 'inputs' must be a string`);
|
|
95
|
+
}
|
|
96
|
+
return inputs;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Validate and normalize a raw benchmark suite (array of tasks). Throws on a
|
|
100
|
+
* non-array, any invalid task, or a duplicate task id. Pure.
|
|
101
|
+
*/
|
|
102
|
+
export function parseBenchmarkSuite(raw) {
|
|
103
|
+
if (!Array.isArray(raw)) {
|
|
104
|
+
throw new Error("benchmark suite: expected an array of tasks");
|
|
105
|
+
}
|
|
106
|
+
const tasks = raw.map(parseBenchmarkTask);
|
|
107
|
+
const seen = new Set();
|
|
108
|
+
for (const t of tasks) {
|
|
109
|
+
if (seen.has(t.id)) {
|
|
110
|
+
throw new Error(`benchmark suite: duplicate task id '${t.id}'`);
|
|
111
|
+
}
|
|
112
|
+
seen.add(t.id);
|
|
113
|
+
}
|
|
114
|
+
return tasks;
|
|
115
|
+
}
|
|
116
|
+
const defaultCheckRunner = (command, cwd) => {
|
|
117
|
+
const r = spawnSync(command, { shell: resolveShell(), cwd, stdio: "ignore" });
|
|
118
|
+
return { status: r.status };
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* Run each fixture check command in `cwd` (the fixture workspace) and report
|
|
122
|
+
* pass/fail per check — the fixture-derived signals (tests-passed,
|
|
123
|
+
* diff-correctness, safety assertions) that the trajectory alone cannot give.
|
|
124
|
+
* A check passes iff its command exits 0; a null status (signal-killed or a
|
|
125
|
+
* spawn failure) is a failure.
|
|
126
|
+
*/
|
|
127
|
+
export function runFixtureChecks(checks, cwd, run = defaultCheckRunner) {
|
|
128
|
+
return checks.map((c) => ({
|
|
129
|
+
name: c.name,
|
|
130
|
+
passed: run(c.command, cwd).status === 0,
|
|
131
|
+
}));
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Score the trajectory signals and fixture-check results of one replay against
|
|
135
|
+
* its {@link BenchmarkExpect}. Pure: only the asserted fields are checked, so an
|
|
136
|
+
* empty expectation always passes. Every shortfall is accumulated so a report
|
|
137
|
+
* can show all of them at once.
|
|
138
|
+
*/
|
|
139
|
+
export function evaluateExpectation(expect, signals, checks) {
|
|
140
|
+
const failures = [];
|
|
141
|
+
if (expect.succeeded !== undefined && signals.succeeded !== expect.succeeded) {
|
|
142
|
+
failures.push(`succeeded: expected ${expect.succeeded}, got ${signals.succeeded}` +
|
|
143
|
+
(signals.exitReason ? ` (exit: ${signals.exitReason})` : ""));
|
|
144
|
+
}
|
|
145
|
+
if (expect.maxCostUsd !== undefined && signals.costUsd > expect.maxCostUsd) {
|
|
146
|
+
failures.push(`cost: $${signals.costUsd} exceeds ceiling $${expect.maxCostUsd}`);
|
|
147
|
+
}
|
|
148
|
+
for (const c of checks) {
|
|
149
|
+
if (!c.passed)
|
|
150
|
+
failures.push(`check '${c.name}' failed`);
|
|
151
|
+
}
|
|
152
|
+
return { passed: failures.length === 0, failures };
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Read and parse a benchmark suite JSON file. Errors (missing file, malformed
|
|
156
|
+
* JSON, schema violation) are re-thrown qualified with the file path.
|
|
157
|
+
*/
|
|
158
|
+
export function readBenchmarkSuite(path) {
|
|
159
|
+
let text;
|
|
160
|
+
try {
|
|
161
|
+
text = readFileSync(path, "utf8");
|
|
162
|
+
}
|
|
163
|
+
catch (e) {
|
|
164
|
+
throw new Error(`benchmark suite ${path}: cannot read (${e.message})`);
|
|
165
|
+
}
|
|
166
|
+
let raw;
|
|
167
|
+
try {
|
|
168
|
+
raw = JSON.parse(text);
|
|
169
|
+
}
|
|
170
|
+
catch (e) {
|
|
171
|
+
throw new Error(`benchmark suite ${path}: invalid JSON (${e.message})`);
|
|
172
|
+
}
|
|
173
|
+
return parseBenchmarkSuite(raw);
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=bench.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bench.js","sourceRoot":"","sources":["../src/bench.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { type BenchmarkCheck, type BenchmarkTask, type CheckResult } from "./bench.js";
|
|
2
|
+
import { type RunManifest, type StageRecord } from "./run-report.js";
|
|
3
|
+
/** A named configuration overlay replayed against every benchmark task. */
|
|
4
|
+
export type EvalConfig = {
|
|
5
|
+
/** Report column label (e.g. "baseline", "panel", "codex"). */
|
|
6
|
+
label: string;
|
|
7
|
+
/** Extra CLI flags layered on top of the task's own args. */
|
|
8
|
+
args: string[];
|
|
9
|
+
/** Env overrides layered on top of the task's own env. */
|
|
10
|
+
env: Record<string, string>;
|
|
11
|
+
};
|
|
12
|
+
/** One concrete replay: a task under a config, resolved to a bin invocation. */
|
|
13
|
+
export type EvalInvocation = {
|
|
14
|
+
task: BenchmarkTask;
|
|
15
|
+
config: EvalConfig;
|
|
16
|
+
/** Absolute fixture workspace dir the run executes in. */
|
|
17
|
+
fixtureDir: string;
|
|
18
|
+
/** Bin name to spawn (`otto-afk` / `otto-ghafk`). */
|
|
19
|
+
bin: string;
|
|
20
|
+
/** Planned iteration count. */
|
|
21
|
+
iterations: number;
|
|
22
|
+
/** Final argv passed to the bin (task args + config args). */
|
|
23
|
+
args: string[];
|
|
24
|
+
/** Env overrides merged for the run (task env + config env). */
|
|
25
|
+
env: Record<string, string>;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Drives one otto replay and reports the run id its evidence bundle was written
|
|
29
|
+
* under. Injectable so {@link runEval} is unit-testable without spawning real,
|
|
30
|
+
* paid model runs (the default spawns the bin and returns the fixture's latest
|
|
31
|
+
* run id).
|
|
32
|
+
*/
|
|
33
|
+
export type EvalInvoker = (inv: EvalInvocation) => Promise<{
|
|
34
|
+
runId: string;
|
|
35
|
+
}>;
|
|
36
|
+
/** Injectable host surface for {@link runEval}. */
|
|
37
|
+
export type EvalDeps = {
|
|
38
|
+
env: NodeJS.ProcessEnv;
|
|
39
|
+
cwd: string;
|
|
40
|
+
out: (msg: string) => void;
|
|
41
|
+
err: (msg: string) => void;
|
|
42
|
+
invoke: EvalInvoker;
|
|
43
|
+
readManifest: (workspaceDir: string, runId: string) => RunManifest | null;
|
|
44
|
+
readStageRecords: (workspaceDir: string, runId: string) => StageRecord[];
|
|
45
|
+
runChecks: (checks: BenchmarkCheck[], cwd: string) => CheckResult[];
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Validate a raw eval-config matrix (array of `{label, args?, env?}`). Throws on
|
|
49
|
+
* a non-array or a config missing its label. Pure.
|
|
50
|
+
*/
|
|
51
|
+
export declare function parseEvalConfigs(raw: unknown): EvalConfig[];
|
|
52
|
+
/**
|
|
53
|
+
* Drive the `otto-eval` command: load a benchmark suite and a config matrix,
|
|
54
|
+
* replay every task under every config (via the injectable invoker — this is the
|
|
55
|
+
* paid, model-dependent half of the eval suite, never run in CI), score each
|
|
56
|
+
* run's evidence bundle, run its fixture checks, and print a per-task comparison
|
|
57
|
+
* table plus a PASS/FAIL verdict per config. Resolves to a process exit code:
|
|
58
|
+
* `0` when every expectation held, `1` otherwise.
|
|
59
|
+
*/
|
|
60
|
+
export declare function runEval(argv: string[], deps?: EvalDeps): Promise<number>;
|
|
61
|
+
//# sourceMappingURL=eval-run.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eval-run.d.ts","sourceRoot":"","sources":["../src/eval-run.ts"],"names":[],"mappings":"AAIA,OAAO,EAIL,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,WAAW,EACjB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAIL,KAAK,WAAW,EAChB,KAAK,WAAW,EACjB,MAAM,iBAAiB,CAAC;AAEzB,2EAA2E;AAC3E,MAAM,MAAM,UAAU,GAAG;IACvB,+DAA+D;IAC/D,KAAK,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,0DAA0D;IAC1D,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7B,CAAC;AAEF,gFAAgF;AAChF,MAAM,MAAM,cAAc,GAAG;IAC3B,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,UAAU,CAAC;IACnB,0DAA0D;IAC1D,UAAU,EAAE,MAAM,CAAC;IACnB,qDAAqD;IACrD,GAAG,EAAE,MAAM,CAAC;IACZ,+BAA+B;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,8DAA8D;IAC9D,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,gEAAgE;IAChE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7B,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE,cAAc,KAAK,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE9E,mDAAmD;AACnD,MAAM,MAAM,QAAQ,GAAG;IACrB,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3B,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3B,MAAM,EAAE,WAAW,CAAC;IACpB,YAAY,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,WAAW,GAAG,IAAI,CAAC;IAC1E,gBAAgB,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,WAAW,EAAE,CAAC;IACzE,SAAS,EAAE,CAAC,MAAM,EAAE,cAAc,EAAE,EAAE,GAAG,EAAE,MAAM,KAAK,WAAW,EAAE,CAAC;CACrE,CAAC;AAkCF;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,GAAG,UAAU,EAAE,CA0B3D;AAuBD;;;;;;;GAOG;AACH,wBAAsB,OAAO,CAC3B,IAAI,EAAE,MAAM,EAAE,EACd,IAAI,GAAE,QAAsB,GAC3B,OAAO,CAAC,MAAM,CAAC,CA+EjB"}
|
package/dist/eval-run.js
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { dirname, resolve } from "node:path";
|
|
4
|
+
import { evaluateExpectation, readBenchmarkSuite, runFixtureChecks, } from "./bench.js";
|
|
5
|
+
import { compareTrajectories, scoreTrajectory } from "./eval.js";
|
|
6
|
+
import { listRunIds, readManifest as readManifestFs, readStageRecords as readStageRecordsFs, } from "./run-report.js";
|
|
7
|
+
const defaultInvoke = async (inv) => {
|
|
8
|
+
const argv = inv.bin === "otto-afk"
|
|
9
|
+
? [inv.task.inputs, String(inv.iterations), ...inv.args]
|
|
10
|
+
: [String(inv.iterations), ...inv.args];
|
|
11
|
+
await new Promise((res, rej) => {
|
|
12
|
+
const child = spawn(inv.bin, argv, {
|
|
13
|
+
cwd: inv.fixtureDir,
|
|
14
|
+
env: { ...process.env, ...inv.env },
|
|
15
|
+
stdio: "inherit",
|
|
16
|
+
});
|
|
17
|
+
child.on("error", rej);
|
|
18
|
+
child.on("close", () => res());
|
|
19
|
+
});
|
|
20
|
+
const ids = listRunIds(inv.fixtureDir);
|
|
21
|
+
return { runId: ids[ids.length - 1] ?? "" };
|
|
22
|
+
};
|
|
23
|
+
const defaultDeps = {
|
|
24
|
+
env: process.env,
|
|
25
|
+
cwd: process.cwd(),
|
|
26
|
+
out: (m) => process.stdout.write(`${m}\n`),
|
|
27
|
+
err: (m) => process.stderr.write(`${m}\n`),
|
|
28
|
+
invoke: defaultInvoke,
|
|
29
|
+
readManifest: readManifestFs,
|
|
30
|
+
readStageRecords: readStageRecordsFs,
|
|
31
|
+
runChecks: runFixtureChecks,
|
|
32
|
+
};
|
|
33
|
+
const USAGE = "Usage: otto-eval <suite.json> [<configs.json>] [--iterations <n>]";
|
|
34
|
+
/**
|
|
35
|
+
* Validate a raw eval-config matrix (array of `{label, args?, env?}`). Throws on
|
|
36
|
+
* a non-array or a config missing its label. Pure.
|
|
37
|
+
*/
|
|
38
|
+
export function parseEvalConfigs(raw) {
|
|
39
|
+
if (!Array.isArray(raw)) {
|
|
40
|
+
throw new Error("eval configs: expected an array of {label, args?, env?}");
|
|
41
|
+
}
|
|
42
|
+
return raw.map((c, i) => {
|
|
43
|
+
if (c == null || typeof c !== "object" || Array.isArray(c)) {
|
|
44
|
+
throw new Error(`eval config [${i}]: expected an object`);
|
|
45
|
+
}
|
|
46
|
+
const rec = c;
|
|
47
|
+
if (typeof rec.label !== "string" || rec.label.length === 0) {
|
|
48
|
+
throw new Error(`eval config [${i}]: 'label' must be a non-empty string`);
|
|
49
|
+
}
|
|
50
|
+
const args = rec.args;
|
|
51
|
+
if (args !== undefined && (!Array.isArray(args) || args.some((a) => typeof a !== "string"))) {
|
|
52
|
+
throw new Error(`eval config '${rec.label}': 'args' must be an array of strings`);
|
|
53
|
+
}
|
|
54
|
+
const env = rec.env;
|
|
55
|
+
if (env !== undefined && (env == null || typeof env !== "object" || Array.isArray(env))) {
|
|
56
|
+
throw new Error(`eval config '${rec.label}': 'env' must be an object`);
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
label: rec.label,
|
|
60
|
+
args: args ?? [],
|
|
61
|
+
env: env ?? {},
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
function parseArgs(argv) {
|
|
66
|
+
const parsed = { iterations: 3, help: false };
|
|
67
|
+
const positionals = [];
|
|
68
|
+
for (let i = 0; i < argv.length; i++) {
|
|
69
|
+
const a = argv[i];
|
|
70
|
+
if (a === "-h" || a === "--help")
|
|
71
|
+
parsed.help = true;
|
|
72
|
+
else if (a === "--iterations")
|
|
73
|
+
parsed.iterations = Number(argv[++i]);
|
|
74
|
+
else
|
|
75
|
+
positionals.push(a);
|
|
76
|
+
}
|
|
77
|
+
parsed.suitePath = positionals[0];
|
|
78
|
+
parsed.configsPath = positionals[1];
|
|
79
|
+
return parsed;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Drive the `otto-eval` command: load a benchmark suite and a config matrix,
|
|
83
|
+
* replay every task under every config (via the injectable invoker — this is the
|
|
84
|
+
* paid, model-dependent half of the eval suite, never run in CI), score each
|
|
85
|
+
* run's evidence bundle, run its fixture checks, and print a per-task comparison
|
|
86
|
+
* table plus a PASS/FAIL verdict per config. Resolves to a process exit code:
|
|
87
|
+
* `0` when every expectation held, `1` otherwise.
|
|
88
|
+
*/
|
|
89
|
+
export async function runEval(argv, deps = defaultDeps) {
|
|
90
|
+
const args = parseArgs(argv);
|
|
91
|
+
if (args.help) {
|
|
92
|
+
deps.out(USAGE);
|
|
93
|
+
return 0;
|
|
94
|
+
}
|
|
95
|
+
if (!args.suitePath) {
|
|
96
|
+
deps.err(`No benchmark suite given.\n${USAGE}`);
|
|
97
|
+
return 1;
|
|
98
|
+
}
|
|
99
|
+
const suitePath = resolve(deps.cwd, args.suitePath);
|
|
100
|
+
let tasks;
|
|
101
|
+
try {
|
|
102
|
+
tasks = readBenchmarkSuite(suitePath);
|
|
103
|
+
}
|
|
104
|
+
catch (e) {
|
|
105
|
+
deps.err(e.message);
|
|
106
|
+
return 1;
|
|
107
|
+
}
|
|
108
|
+
let configs = [{ label: "default", args: [], env: {} }];
|
|
109
|
+
if (args.configsPath) {
|
|
110
|
+
try {
|
|
111
|
+
configs = parseEvalConfigs(JSON.parse(readFileSync(resolve(deps.cwd, args.configsPath), "utf8")));
|
|
112
|
+
}
|
|
113
|
+
catch (e) {
|
|
114
|
+
deps.err(`eval configs ${args.configsPath}: ${e.message}`);
|
|
115
|
+
return 1;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
const suiteDir = dirname(suitePath);
|
|
119
|
+
let allPassed = true;
|
|
120
|
+
for (const task of tasks) {
|
|
121
|
+
const fixtureDir = resolve(suiteDir, task.fixture);
|
|
122
|
+
const labelled = [];
|
|
123
|
+
const verdictLines = [];
|
|
124
|
+
for (const config of configs) {
|
|
125
|
+
const inv = {
|
|
126
|
+
task,
|
|
127
|
+
config,
|
|
128
|
+
fixtureDir,
|
|
129
|
+
bin: task.bin,
|
|
130
|
+
iterations: args.iterations,
|
|
131
|
+
args: [...task.args, ...config.args],
|
|
132
|
+
env: { ...task.env, ...config.env },
|
|
133
|
+
};
|
|
134
|
+
const { runId } = await deps.invoke(inv);
|
|
135
|
+
const manifest = deps.readManifest(fixtureDir, runId);
|
|
136
|
+
if (!manifest) {
|
|
137
|
+
allPassed = false;
|
|
138
|
+
verdictLines.push(` - ${config.label}: FAIL (no evidence bundle for run '${runId}')`);
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
const signals = scoreTrajectory(manifest, deps.readStageRecords(fixtureDir, runId));
|
|
142
|
+
const checks = deps.runChecks(task.expect.checks ?? [], fixtureDir);
|
|
143
|
+
const verdict = evaluateExpectation(task.expect, signals, checks);
|
|
144
|
+
if (!verdict.passed)
|
|
145
|
+
allPassed = false;
|
|
146
|
+
labelled.push({ label: config.label, signals });
|
|
147
|
+
verdictLines.push(verdict.passed
|
|
148
|
+
? ` - ${config.label}: PASS`
|
|
149
|
+
: ` - ${config.label}: FAIL (${verdict.failures.join("; ")})`);
|
|
150
|
+
}
|
|
151
|
+
deps.out(`## ${task.id} (${task.kind})`);
|
|
152
|
+
deps.out("");
|
|
153
|
+
deps.out(compareTrajectories(labelled));
|
|
154
|
+
deps.out("");
|
|
155
|
+
deps.out("Verdicts:");
|
|
156
|
+
for (const line of verdictLines)
|
|
157
|
+
deps.out(line);
|
|
158
|
+
deps.out("");
|
|
159
|
+
}
|
|
160
|
+
return allPassed ? 0 : 1;
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=eval-run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eval-run.js","sourceRoot":"","sources":["../src/eval-run.ts"],"names":[],"mappings":"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"}
|
package/dist/eval.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { RunManifest, StageRecord } from "./run-report.js";
|
|
2
|
+
/**
|
|
3
|
+
* The multi-signal outcome of one Otto run, derived purely from its recorded
|
|
4
|
+
* trajectory (the #39 evidence bundle: a {@link RunManifest} plus its
|
|
5
|
+
* {@link StageRecord}s). These are the signals that need no fixture re-run — the
|
|
6
|
+
* deterministic, CI-runnable subset of the harness evaluation suite (issue #40).
|
|
7
|
+
*
|
|
8
|
+
* Fixture-dependent signals (tests passed, diff correctness, safety events) are
|
|
9
|
+
* scored separately by the runner against a benchmark task's expected outcome.
|
|
10
|
+
*/
|
|
11
|
+
export type EvalSignals = {
|
|
12
|
+
/** Run reached a success exit reason (`complete`/`done`). */
|
|
13
|
+
succeeded: boolean;
|
|
14
|
+
/** Terminal exit reason, or `null` for an un-finalized/interrupted run. */
|
|
15
|
+
exitReason: string | null;
|
|
16
|
+
/** Iterations completed, or `null` when the manifest is un-finalized. */
|
|
17
|
+
completedIterations: number | null;
|
|
18
|
+
/** Number of stage records in the trajectory. */
|
|
19
|
+
stageCount: number;
|
|
20
|
+
/** Stage records that ended in error. */
|
|
21
|
+
errorStageCount: number;
|
|
22
|
+
/** Total USD cost of the run. */
|
|
23
|
+
costUsd: number;
|
|
24
|
+
/** Sum of all token-usage fields for the run. */
|
|
25
|
+
totalTokens: number;
|
|
26
|
+
/** Wall-clock run duration in ms, or `null` when it cannot be computed. */
|
|
27
|
+
elapsedMs: number | null;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Derive {@link EvalSignals} from a recorded run trajectory. Pure: no I/O, no
|
|
31
|
+
* model calls — only arithmetic over the manifest and stage records, so it is
|
|
32
|
+
* deterministic and unit-testable. `elapsedMs` is `null` when the run is
|
|
33
|
+
* un-finalized (no `finishedAt`) or either timestamp is unparseable, never NaN.
|
|
34
|
+
*/
|
|
35
|
+
export declare function scoreTrajectory(manifest: RunManifest, stages: StageRecord[]): EvalSignals;
|
|
36
|
+
/** One Otto run's signals tagged with the configuration label that produced it. */
|
|
37
|
+
export type LabelledSignals = {
|
|
38
|
+
label: string;
|
|
39
|
+
signals: EvalSignals;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Render a stable markdown comparison table across labelled runs — one row per
|
|
43
|
+
* run, one column per {@link EvalSignals} field. Each directional signal (success
|
|
44
|
+
* up; errors/cost/tokens/elapsed down) marks its best and worst cell, so a
|
|
45
|
+
* maintainer can read a config A/B at a glance. Pure and deterministic. A column
|
|
46
|
+
* is marked only when there is a spread across at least two comparable runs.
|
|
47
|
+
*/
|
|
48
|
+
export declare function compareTrajectories(runs: LabelledSignals[]): string;
|
|
49
|
+
//# sourceMappingURL=eval.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eval.d.ts","sourceRoot":"","sources":["../src/eval.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAGhE;;;;;;;;GAQG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,6DAA6D;IAC7D,SAAS,EAAE,OAAO,CAAC;IACnB,2EAA2E;IAC3E,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,yEAAyE;IACzE,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,iDAAiD;IACjD,UAAU,EAAE,MAAM,CAAC;IACnB,yCAAyC;IACzC,eAAe,EAAE,MAAM,CAAC;IACxB,iCAAiC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,iDAAiD;IACjD,WAAW,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B,CAAC;AAIF;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,WAAW,EACrB,MAAM,EAAE,WAAW,EAAE,GACpB,WAAW,CAYb;AAUD,mFAAmF;AACnF,MAAM,MAAM,eAAe,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,WAAW,CAAA;CAAE,CAAC;AAkDtE;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,eAAe,EAAE,GAAG,MAAM,CAoCnE"}
|