@cef-ai/eval 0.0.0-stage → 0.1.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/README.md +202 -2
- package/dist/capture.d.ts +37 -0
- package/dist/capture.d.ts.map +1 -0
- package/dist/capture.js +70 -0
- package/dist/capture.js.map +1 -0
- package/dist/conformance.d.ts +6 -0
- package/dist/conformance.d.ts.map +1 -0
- package/dist/conformance.js +257 -0
- package/dist/conformance.js.map +1 -0
- package/dist/contract.d.ts +18 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +176 -0
- package/dist/contract.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -0
- package/dist/layout.d.ts +112 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +222 -0
- package/dist/layout.js.map +1 -0
- package/dist/migrate.d.ts +30 -0
- package/dist/migrate.d.ts.map +1 -0
- package/dist/migrate.js +113 -0
- package/dist/migrate.js.map +1 -0
- package/dist/pool.d.ts +13 -0
- package/dist/pool.d.ts.map +1 -0
- package/dist/pool.js +34 -0
- package/dist/pool.js.map +1 -0
- package/dist/result.d.ts +11 -0
- package/dist/result.d.ts.map +1 -0
- package/dist/result.js +72 -0
- package/dist/result.js.map +1 -0
- package/dist/run.d.ts +86 -0
- package/dist/run.d.ts.map +1 -0
- package/dist/run.js +240 -0
- package/dist/run.js.map +1 -0
- package/dist/score.d.ts +102 -0
- package/dist/score.d.ts.map +1 -0
- package/dist/score.js +433 -0
- package/dist/score.js.map +1 -0
- package/dist/storage.d.ts +218 -0
- package/dist/storage.d.ts.map +1 -0
- package/dist/storage.js +577 -0
- package/dist/storage.js.map +1 -0
- package/dist/summary.d.ts +105 -0
- package/dist/summary.d.ts.map +1 -0
- package/dist/summary.js +219 -0
- package/dist/summary.js.map +1 -0
- package/dist/types.d.ts +265 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +14 -0
- package/dist/types.js.map +1 -0
- package/package.json +27 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../src/migrate.ts"],"names":[],"mappings":"AAyBA,OAAO,EAAiB,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAE7D,MAAM,WAAW,eAAe;IAC9B,iEAAiE;IACjE,eAAe,EAAE,OAAO,CAAC;IACzB,QAAQ,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC5F,4BAA4B;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,wFAAwF;IACxF,QAAQ,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,OAAO,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrD;AAKD,8EAA8E;AAC9E,wBAAsB,oBAAoB,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,CAG7E;AAYD;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,GAAE;IAAE,GAAG,CAAC,EAAE,IAAI,CAAA;CAAO,GAAG,OAAO,CAAC,eAAe,CAAC,CAkE/G"}
|
package/dist/migrate.js
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Moving v1 storage (`evals/datasets/<dataset>/…`, experiments nested in their
|
|
3
|
+
* dataset) to the v2 layout grouped by workflow (see layout.ts).
|
|
4
|
+
*
|
|
5
|
+
* COPY, NEVER MOVE. Every legacy key is copied byte for byte with
|
|
6
|
+
* `putIfAbsent` and left where it was: the store has no delete, a half-done
|
|
7
|
+
* migration must be safe to rerun, and an older ROC or CLI still reading the
|
|
8
|
+
* legacy keys keeps working until it is upgraded. A key already at its target
|
|
9
|
+
* is counted, not overwritten — whatever a v2 writer put there since wins.
|
|
10
|
+
*
|
|
11
|
+
* THE MARKER is written last, and only when every legacy dataset was copied.
|
|
12
|
+
* A dataset whose header cannot be read is reported and leaves the marker
|
|
13
|
+
* unwritten, so the next run tries again.
|
|
14
|
+
*/
|
|
15
|
+
import { LEGACY_EVALS_PREFIX, MIGRATION_MARKER_KEY, canonicalJson, datasetPrefix, experimentsPrefix, headerKey, isDatasetName, isWorkflowId, } from "./layout.js";
|
|
16
|
+
import { isObject, parseHeader } from "./contract.js";
|
|
17
|
+
import { childPrefixes } from "./storage.js";
|
|
18
|
+
/** The baseline ROC kept beside a v1 header before `Header.baselineId` existed. */
|
|
19
|
+
const LEGACY_BASELINE_FILE = "baseline.json";
|
|
20
|
+
/** Whether this store has v1 keys and no marker saying they were migrated. */
|
|
21
|
+
export async function needsLegacyMigration(store) {
|
|
22
|
+
if ((await store.get(MIGRATION_MARKER_KEY)) !== null)
|
|
23
|
+
return false;
|
|
24
|
+
return (await childPrefixes(store, LEGACY_EVALS_PREFIX)).length > 0;
|
|
25
|
+
}
|
|
26
|
+
function legacyBaseline(raw) {
|
|
27
|
+
if (raw === null)
|
|
28
|
+
return undefined;
|
|
29
|
+
try {
|
|
30
|
+
const v = JSON.parse(raw);
|
|
31
|
+
return isObject(v) && typeof v.baselineId === "string" && v.baselineId ? v.baselineId : undefined;
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Copy every v1 dataset — header, cases, flags, versions and its experiments —
|
|
39
|
+
* into `workflows/<header.workflowId>/…`. Idempotent; see the file comment.
|
|
40
|
+
*/
|
|
41
|
+
export async function migrateLegacyLayout(store, opts = {}) {
|
|
42
|
+
const report = { alreadyMigrated: false, datasets: [], copied: 0, existing: 0, skipped: [] };
|
|
43
|
+
if ((await store.get(MIGRATION_MARKER_KEY)) !== null)
|
|
44
|
+
return { ...report, alreadyMigrated: true };
|
|
45
|
+
for (const prefix of await childPrefixes(store, LEGACY_EVALS_PREFIX)) {
|
|
46
|
+
const dataset = prefix.slice(LEGACY_EVALS_PREFIX.length, -1);
|
|
47
|
+
if (!isDatasetName(dataset)) {
|
|
48
|
+
// v1 enforced the same name rule, so this should not occur; if it does, it is reported, not silently dropped.
|
|
49
|
+
report.skipped.push({ dataset, reason: "the name is not a valid dataset name, so it cannot be a storage key segment" });
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
const rawHeader = await store.get(`${prefix}header.json`);
|
|
53
|
+
if (rawHeader === null) {
|
|
54
|
+
report.skipped.push({ dataset, reason: "no header.json" });
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
let header;
|
|
58
|
+
try {
|
|
59
|
+
header = parseHeader(JSON.parse(rawHeader));
|
|
60
|
+
}
|
|
61
|
+
catch (e) {
|
|
62
|
+
report.skipped.push({ dataset, reason: `header.json unreadable: ${e.message}` });
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const workflowId = header.workflowId;
|
|
66
|
+
if (!isWorkflowId(workflowId)) {
|
|
67
|
+
report.skipped.push({ dataset, reason: `workflowId "${workflowId}" cannot be a storage key segment` });
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const baselineId = header.baselineId ?? legacyBaseline(await store.get(`${prefix}${LEGACY_BASELINE_FILE}`));
|
|
71
|
+
const experiments = new Set();
|
|
72
|
+
let keys = 0;
|
|
73
|
+
for (const key of await store.list(prefix)) {
|
|
74
|
+
const rest = key.slice(prefix.length);
|
|
75
|
+
let target;
|
|
76
|
+
let body;
|
|
77
|
+
if (rest === LEGACY_BASELINE_FILE)
|
|
78
|
+
continue;
|
|
79
|
+
if (rest === "header.json") {
|
|
80
|
+
target = headerKey(workflowId, dataset);
|
|
81
|
+
// The header carries the ROC baseline from now on; otherwise the bytes are kept.
|
|
82
|
+
body = baselineId && !header.baselineId ? canonicalJson({ ...header, baselineId }) : rawHeader;
|
|
83
|
+
}
|
|
84
|
+
else if (rest.startsWith("experiments/")) {
|
|
85
|
+
const tail = rest.slice("experiments/".length);
|
|
86
|
+
experiments.add(tail.split("/")[0]);
|
|
87
|
+
target = `${experimentsPrefix(workflowId)}${tail}`;
|
|
88
|
+
body = await store.get(key);
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
target = `${datasetPrefix(workflowId, dataset)}${rest}`;
|
|
92
|
+
body = await store.get(key);
|
|
93
|
+
}
|
|
94
|
+
if (body === null)
|
|
95
|
+
continue;
|
|
96
|
+
keys++;
|
|
97
|
+
if (await store.putIfAbsent(target, body))
|
|
98
|
+
report.copied++;
|
|
99
|
+
else
|
|
100
|
+
report.existing++;
|
|
101
|
+
}
|
|
102
|
+
report.datasets.push({ dataset, workflowId, keys, experiments: experiments.size });
|
|
103
|
+
}
|
|
104
|
+
if (report.skipped.length === 0) {
|
|
105
|
+
await store.put(MIGRATION_MARKER_KEY, canonicalJson({
|
|
106
|
+
migratedAt: (opts.now ?? new Date()).toISOString(),
|
|
107
|
+
datasets: report.datasets.map(({ dataset, workflowId }) => ({ dataset, workflowId })),
|
|
108
|
+
copied: report.copied,
|
|
109
|
+
}));
|
|
110
|
+
}
|
|
111
|
+
return report;
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=migrate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate.js","sourceRoot":"","sources":["../src/migrate.ts"],"names":[],"mappings":"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"}
|
package/dist/pool.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded-concurrency for-each, shared by `runExperiment` and the store
|
|
3
|
+
* conformance suite. Dependency-free and browser-safe.
|
|
4
|
+
*
|
|
5
|
+
* IT FAILS SAFELY. When one item throws, no further item is started, every
|
|
6
|
+
* item already in flight is awaited, and only then does the pool reject, with
|
|
7
|
+
* the first error. `Promise.all` over the workers would reject at the first
|
|
8
|
+
* throw while its siblings kept running — so a caller's cleanup (releasing a
|
|
9
|
+
* version pin, writing the final summary) would run under work that was still
|
|
10
|
+
* writing, and land before it.
|
|
11
|
+
*/
|
|
12
|
+
export declare function pool<T>(items: readonly T[], limit: number, fn: (item: T) => Promise<void>): Promise<void>;
|
|
13
|
+
//# sourceMappingURL=pool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../src/pool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,wBAAsB,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAmB/G"}
|
package/dist/pool.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bounded-concurrency for-each, shared by `runExperiment` and the store
|
|
3
|
+
* conformance suite. Dependency-free and browser-safe.
|
|
4
|
+
*
|
|
5
|
+
* IT FAILS SAFELY. When one item throws, no further item is started, every
|
|
6
|
+
* item already in flight is awaited, and only then does the pool reject, with
|
|
7
|
+
* the first error. `Promise.all` over the workers would reject at the first
|
|
8
|
+
* throw while its siblings kept running — so a caller's cleanup (releasing a
|
|
9
|
+
* version pin, writing the final summary) would run under work that was still
|
|
10
|
+
* writing, and land before it.
|
|
11
|
+
*/
|
|
12
|
+
export async function pool(items, limit, fn) {
|
|
13
|
+
let next = 0;
|
|
14
|
+
let failed = false;
|
|
15
|
+
let first;
|
|
16
|
+
const worker = async () => {
|
|
17
|
+
while (!failed && next < items.length) {
|
|
18
|
+
const item = items[next++];
|
|
19
|
+
try {
|
|
20
|
+
await fn(item);
|
|
21
|
+
}
|
|
22
|
+
catch (e) {
|
|
23
|
+
if (!failed) {
|
|
24
|
+
failed = true;
|
|
25
|
+
first = e;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
await Promise.all(Array.from({ length: Math.max(1, Math.min(limit, items.length)) }, worker));
|
|
31
|
+
if (failed)
|
|
32
|
+
throw first;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=pool.js.map
|
package/dist/pool.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pool.js","sourceRoot":"","sources":["../src/pool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,IAAI,CAAI,KAAmB,EAAE,KAAa,EAAE,EAA8B;IAC9F,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,IAAI,MAAM,GAAG,KAAK,CAAC;IACnB,IAAI,KAAc,CAAC;IACnB,MAAM,MAAM,GAAG,KAAK,IAAmB,EAAE;QACvC,OAAO,CAAC,MAAM,IAAI,IAAI,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;YACtC,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,CAAE,CAAC;YAC5B,IAAI,CAAC;gBACH,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC;YACjB,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,IAAI,CAAC,MAAM,EAAE,CAAC;oBACZ,MAAM,GAAG,IAAI,CAAC;oBACd,KAAK,GAAG,CAAC,CAAC;gBACZ,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IACF,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC;IAC9F,IAAI,MAAM;QAAE,MAAM,KAAK,CAAC;AAC1B,CAAC"}
|
package/dist/result.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ResultField } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* The fields the graph's `output` node(s) declare. A graph with several
|
|
4
|
+
* outputs (branches ending differently) yields the union; a field two outputs
|
|
5
|
+
* type differently is reported untyped, since either type can come back.
|
|
6
|
+
*
|
|
7
|
+
* undefined when no output declares a result — the Result is unknown, and
|
|
8
|
+
* scoring then judges every expected field as before.
|
|
9
|
+
*/
|
|
10
|
+
export declare function resultFieldsFromGraph(graph: unknown): ResultField[] | undefined;
|
|
11
|
+
//# sourceMappingURL=result.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result.d.ts","sourceRoot":"","sources":["../src/result.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AA0B9C;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,WAAW,EAAE,GAAG,SAAS,CAmB/E"}
|
package/dist/result.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reading a workflow version's declared Result off its graph — what ROC and
|
|
3
|
+
* the CLI record as `Experiment.resultFields`.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors the runner's own reading (`@cef-ai/agent-sdk` `readResultSpec`)
|
|
6
|
+
* without depending on it: this package is zero-dependency and browser-safe.
|
|
7
|
+
* An `output` node declares `params.result` (`{ field: value }`, or that object
|
|
8
|
+
* as JSON text — what a builder text field saves) and optionally
|
|
9
|
+
* `params.resultTypes` (`{ field: type }`, object or JSON text).
|
|
10
|
+
*/
|
|
11
|
+
import { isObject } from "./contract.js";
|
|
12
|
+
/** An object, or JSON text that parses to one; anything else is undefined. */
|
|
13
|
+
function objectOf(raw) {
|
|
14
|
+
if (isObject(raw))
|
|
15
|
+
return raw;
|
|
16
|
+
if (typeof raw !== "string" || !raw.trim().startsWith("{"))
|
|
17
|
+
return undefined;
|
|
18
|
+
try {
|
|
19
|
+
const parsed = JSON.parse(raw);
|
|
20
|
+
return isObject(parsed) ? parsed : undefined;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The graph itself, from any of the forms it travels in: the object, its JSON
|
|
28
|
+
* text, or a manifest param (`params.graph` = `{ type: "string", default: "<json>" }`).
|
|
29
|
+
*/
|
|
30
|
+
function graphOf(raw) {
|
|
31
|
+
const g = objectOf(raw);
|
|
32
|
+
if (!g)
|
|
33
|
+
return undefined;
|
|
34
|
+
if (Array.isArray(g.nodes))
|
|
35
|
+
return g;
|
|
36
|
+
if ("default" in g)
|
|
37
|
+
return graphOf(g.default);
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* The fields the graph's `output` node(s) declare. A graph with several
|
|
42
|
+
* outputs (branches ending differently) yields the union; a field two outputs
|
|
43
|
+
* type differently is reported untyped, since either type can come back.
|
|
44
|
+
*
|
|
45
|
+
* undefined when no output declares a result — the Result is unknown, and
|
|
46
|
+
* scoring then judges every expected field as before.
|
|
47
|
+
*/
|
|
48
|
+
export function resultFieldsFromGraph(graph) {
|
|
49
|
+
const g = graphOf(graph);
|
|
50
|
+
if (!g)
|
|
51
|
+
return undefined;
|
|
52
|
+
const types = new Map();
|
|
53
|
+
let declared = false;
|
|
54
|
+
for (const node of g.nodes) {
|
|
55
|
+
if (!isObject(node) || (node.kind ?? node.type) !== "output" || !isObject(node.params))
|
|
56
|
+
continue;
|
|
57
|
+
const result = objectOf(node.params.result);
|
|
58
|
+
if (!result)
|
|
59
|
+
continue;
|
|
60
|
+
declared = true;
|
|
61
|
+
const typed = objectOf(node.params.resultTypes) ?? {};
|
|
62
|
+
for (const name of Object.keys(result)) {
|
|
63
|
+
const t = typeof typed[name] === "string" && typed[name] ? typed[name] : undefined;
|
|
64
|
+
// First sighting sets the type; any disagreement (typed vs untyped included) drops it.
|
|
65
|
+
types.set(name, types.has(name) && types.get(name) !== t ? undefined : t);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (!declared)
|
|
69
|
+
return undefined;
|
|
70
|
+
return [...types].sort(([a], [b]) => a.localeCompare(b)).map(([name, type]) => (type ? { name, type } : { name }));
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=result.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"result.js","sourceRoot":"","sources":["../src/result.ts"],"names":[],"mappings":"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"}
|
package/dist/run.d.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Running an experiment: one dataset version × one workflow version × N
|
|
3
|
+
* repeats, against an injected {@link WorkflowTarget}.
|
|
4
|
+
*
|
|
5
|
+
* WHAT IS WRITTEN, AND WHEN. The meta first, `running`, so an experiment that
|
|
6
|
+
* dies half way is still visible as one. Each run record as its run finishes,
|
|
7
|
+
* write-once, so a long experiment is resumable: rerun with the same
|
|
8
|
+
* `experimentId` and every run already on file is reused rather than repeated.
|
|
9
|
+
* The summary last, with the final status.
|
|
10
|
+
*
|
|
11
|
+
* A NON-LIVE VERSION is run through `target.pinVersion`, which routes only this
|
|
12
|
+
* experiment's contexts (`eval-<expId>-…`) to the candidate and is released
|
|
13
|
+
* however the experiment ends.
|
|
14
|
+
*/
|
|
15
|
+
import { type EvalStore } from "./storage.js";
|
|
16
|
+
import type { Case, Experiment, Header, ResultField, RunRecord, WorkflowTarget } from "./types.js";
|
|
17
|
+
export interface ExperimentProgress {
|
|
18
|
+
/** Runs finished (or reused) so far, including this one. */
|
|
19
|
+
done: number;
|
|
20
|
+
total: number;
|
|
21
|
+
run: RunRecord;
|
|
22
|
+
/** True when the run was already on file from an earlier attempt. */
|
|
23
|
+
reused: boolean;
|
|
24
|
+
}
|
|
25
|
+
export interface RunExperimentOptions {
|
|
26
|
+
store: EvalStore;
|
|
27
|
+
dataset: string;
|
|
28
|
+
/**
|
|
29
|
+
* The dataset version to run. Absent: `ensureDatasetVersion` — the latest,
|
|
30
|
+
* or a new one cut automatically when the cases changed since.
|
|
31
|
+
*/
|
|
32
|
+
datasetVersion?: number;
|
|
33
|
+
workflowId: string;
|
|
34
|
+
/** The version being evaluated. With `live`, the version the live deployment runs (recorded only). */
|
|
35
|
+
workflowVersion: string;
|
|
36
|
+
/** Run against the live deployment (no pin). False requires `target.pinVersion`. */
|
|
37
|
+
live: boolean;
|
|
38
|
+
/** How many times each case runs. Default 1. */
|
|
39
|
+
repeats?: number;
|
|
40
|
+
/**
|
|
41
|
+
* The Result the workflow version declares (`resultFieldsFromGraph`).
|
|
42
|
+
* Recorded on the experiment; expected fields it rules out score n/a.
|
|
43
|
+
*/
|
|
44
|
+
resultFields?: ResultField[];
|
|
45
|
+
/** Runs in flight at once. Default 4. */
|
|
46
|
+
concurrency?: number;
|
|
47
|
+
/** How long one run may take to end. Default 300 000 ms. */
|
|
48
|
+
timeoutMs?: number;
|
|
49
|
+
target: WorkflowTarget;
|
|
50
|
+
onProgress?: (p: ExperimentProgress) => void;
|
|
51
|
+
baselineId?: string;
|
|
52
|
+
/** Resume this experiment instead of starting a new one. */
|
|
53
|
+
experimentId?: string;
|
|
54
|
+
origin?: "roc" | "cli";
|
|
55
|
+
createdBy?: string;
|
|
56
|
+
note?: string;
|
|
57
|
+
/** Stops dispatching new runs; the experiment ends `cancelled`. */
|
|
58
|
+
signal?: AbortSignal;
|
|
59
|
+
/** Clock, for tests. */
|
|
60
|
+
now?: () => number;
|
|
61
|
+
/** Waits between retries of a run record's write; for tests. */
|
|
62
|
+
sleep?: (ms: number) => Promise<void>;
|
|
63
|
+
}
|
|
64
|
+
export declare const DEFAULT_TIMEOUT_MS = 300000;
|
|
65
|
+
export declare const DEFAULT_CONCURRENCY = 4;
|
|
66
|
+
/** Backoff before each retry of a run record whose write-once lost to nothing. */
|
|
67
|
+
export declare const RECORD_WRITE_BACKOFF_MS: readonly [250, 1000, 4000];
|
|
68
|
+
/** Run one case × repeat against the target, and score it. Never throws. */
|
|
69
|
+
export declare function runOne(opts: {
|
|
70
|
+
target: WorkflowTarget;
|
|
71
|
+
header?: Pick<Header, "limits">;
|
|
72
|
+
case: Case;
|
|
73
|
+
caseRev: number;
|
|
74
|
+
/** 1-based. */
|
|
75
|
+
repeat: number;
|
|
76
|
+
/** Recorded on the run; the context already carries it. */
|
|
77
|
+
attempt?: number;
|
|
78
|
+
context: string;
|
|
79
|
+
timeoutMs: number;
|
|
80
|
+
now?: () => number;
|
|
81
|
+
/** The version's declared Result; see {@link scoreFields}. */
|
|
82
|
+
resultFields?: readonly ResultField[];
|
|
83
|
+
}): Promise<RunRecord>;
|
|
84
|
+
/** Run an experiment end to end. Resolves with the final meta (summary included). */
|
|
85
|
+
export declare function runExperiment(opts: RunExperimentOptions): Promise<Experiment>;
|
|
86
|
+
//# sourceMappingURL=run.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,EASL,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAMtB,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAiB,WAAW,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAElH,MAAM,WAAW,kBAAkB;IACjC,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,SAAS,CAAC;IACf,qEAAqE;IACrE,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,SAAS,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,sGAAsG;IACtG,eAAe,EAAE,MAAM,CAAC;IACxB,oFAAoF;IACpF,IAAI,EAAE,OAAO,CAAC;IACd,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,YAAY,CAAC,EAAE,WAAW,EAAE,CAAC;IAC7B,yCAAyC;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,cAAc,CAAC;IACvB,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC7C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4DAA4D;IAC5D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,wBAAwB;IACxB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,gEAAgE;IAChE,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAED,eAAO,MAAM,kBAAkB,SAAU,CAAC;AAC1C,eAAO,MAAM,mBAAmB,IAAI,CAAC;AACrC,kFAAkF;AAClF,eAAO,MAAM,uBAAuB,4BAA6B,CAAC;AAKlE,4EAA4E;AAC5E,wBAAsB,MAAM,CAAC,IAAI,EAAE;IACjC,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAChC,IAAI,EAAE,IAAI,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,eAAe;IACf,MAAM,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,8DAA8D;IAC9D,YAAY,CAAC,EAAE,SAAS,WAAW,EAAE,CAAC;CACvC,GAAG,OAAO,CAAC,SAAS,CAAC,CAuErB;AAED,qFAAqF;AACrF,wBAAsB,aAAa,CAAC,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,UAAU,CAAC,CA0InF"}
|
package/dist/run.js
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Running an experiment: one dataset version × one workflow version × N
|
|
3
|
+
* repeats, against an injected {@link WorkflowTarget}.
|
|
4
|
+
*
|
|
5
|
+
* WHAT IS WRITTEN, AND WHEN. The meta first, `running`, so an experiment that
|
|
6
|
+
* dies half way is still visible as one. Each run record as its run finishes,
|
|
7
|
+
* write-once, so a long experiment is resumable: rerun with the same
|
|
8
|
+
* `experimentId` and every run already on file is reused rather than repeated.
|
|
9
|
+
* The summary last, with the final status.
|
|
10
|
+
*
|
|
11
|
+
* A NON-LIVE VERSION is run through `target.pinVersion`, which routes only this
|
|
12
|
+
* experiment's contexts (`eval-<expId>-…`) to the candidate and is released
|
|
13
|
+
* however the experiment ends.
|
|
14
|
+
*/
|
|
15
|
+
import { claimAttempt, ensureDatasetVersion, getExperiment, getRunRecord, loadVersion, putExperiment, putRunRecord, requireHeader, } from "./storage.js";
|
|
16
|
+
import { experimentContextPrefix, newExperimentId, runContext, runIdOf } from "./layout.js";
|
|
17
|
+
import { casePass, effectiveLimits, scoreFields, scoreLimits } from "./score.js";
|
|
18
|
+
import { emptyMetrics, summarize } from "./summary.js";
|
|
19
|
+
import { EvalContractError } from "./contract.js";
|
|
20
|
+
import { pool } from "./pool.js";
|
|
21
|
+
export const DEFAULT_TIMEOUT_MS = 300_000;
|
|
22
|
+
export const DEFAULT_CONCURRENCY = 4;
|
|
23
|
+
/** Backoff before each retry of a run record whose write-once lost to nothing. */
|
|
24
|
+
export const RECORD_WRITE_BACKOFF_MS = [250, 1000, 4000];
|
|
25
|
+
const iso = (ms) => new Date(ms).toISOString();
|
|
26
|
+
const message = (e) => (e instanceof Error ? e.message : String(e));
|
|
27
|
+
/** Run one case × repeat against the target, and score it. Never throws. */
|
|
28
|
+
export async function runOne(opts) {
|
|
29
|
+
const now = opts.now ?? Date.now;
|
|
30
|
+
const c = opts.case;
|
|
31
|
+
const started = now();
|
|
32
|
+
const base = {
|
|
33
|
+
caseId: c.id,
|
|
34
|
+
caseRev: opts.caseRev,
|
|
35
|
+
repeat: opts.repeat,
|
|
36
|
+
...(opts.attempt !== undefined ? { attempt: opts.attempt } : {}),
|
|
37
|
+
context: opts.context,
|
|
38
|
+
runId: runIdOf(opts.context),
|
|
39
|
+
startedAt: iso(started),
|
|
40
|
+
};
|
|
41
|
+
try {
|
|
42
|
+
await opts.target.start(c.input, opts.context);
|
|
43
|
+
}
|
|
44
|
+
catch (e) {
|
|
45
|
+
return {
|
|
46
|
+
...base, status: "error", output: null, error: `could not start the run: ${message(e)}`,
|
|
47
|
+
endedAt: null, metrics: emptyMetrics(), scores: [], pass: null,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
let end;
|
|
51
|
+
try {
|
|
52
|
+
end = await opts.target.waitForEnd(opts.context, opts.timeoutMs);
|
|
53
|
+
}
|
|
54
|
+
catch (e) {
|
|
55
|
+
return {
|
|
56
|
+
...base, status: "error", output: null, error: `could not read how the run ended: ${message(e)}`,
|
|
57
|
+
endedAt: null, metrics: emptyMetrics(), scores: [], pass: null,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const endedMs = end.endedAt ? Date.parse(end.endedAt) : NaN;
|
|
61
|
+
const startedMs = end.startedAt ? Date.parse(end.startedAt) : NaN;
|
|
62
|
+
let metrics;
|
|
63
|
+
let metricsError;
|
|
64
|
+
try {
|
|
65
|
+
metrics = await opts.target.metrics(opts.context);
|
|
66
|
+
}
|
|
67
|
+
catch (e) {
|
|
68
|
+
metrics = emptyMetrics();
|
|
69
|
+
metricsError = `metrics unavailable: ${message(e)}`;
|
|
70
|
+
}
|
|
71
|
+
/*
|
|
72
|
+
* ONE CLOCK. Duration is the end event's timestamp minus the start event's,
|
|
73
|
+
* both stamped by the server. When the target could not read both, whatever
|
|
74
|
+
* it measured itself (also server-side — the CLI target uses the jobs'
|
|
75
|
+
* createdAt/completedAt) stands, and otherwise there is no duration. This
|
|
76
|
+
* machine's clock is never subtracted from the server's: their skew would
|
|
77
|
+
* land in every number and differ between the CLI and ROC.
|
|
78
|
+
*/
|
|
79
|
+
if (Number.isFinite(endedMs) && Number.isFinite(startedMs)) {
|
|
80
|
+
metrics = { ...metrics, durationMs: Math.max(0, endedMs - startedMs) };
|
|
81
|
+
}
|
|
82
|
+
const output = end.status === "done" ? (end.output ?? null) : null;
|
|
83
|
+
const fieldScores = scoreFields(c.expected, end.status === "done" ? (end.output ?? null) : undefined, opts.resultFields);
|
|
84
|
+
const scores = [...fieldScores, ...scoreLimits(effectiveLimits(opts.header, c), metrics)];
|
|
85
|
+
// A run that did not complete has no Result to judge; it is a failure of the
|
|
86
|
+
// workflow, whether or not the case states expectations.
|
|
87
|
+
const pass = end.status === "done" ? casePass(scores) : false;
|
|
88
|
+
const error = [end.error, metricsError].filter(Boolean).join("; ");
|
|
89
|
+
return {
|
|
90
|
+
...base,
|
|
91
|
+
...(Number.isFinite(startedMs) ? { startedAt: iso(startedMs) } : {}),
|
|
92
|
+
status: end.status,
|
|
93
|
+
output,
|
|
94
|
+
...(end.outcome ? { outcome: end.outcome } : {}),
|
|
95
|
+
...(error ? { error } : {}),
|
|
96
|
+
endedAt: Number.isFinite(endedMs) ? iso(endedMs) : null,
|
|
97
|
+
metrics,
|
|
98
|
+
scores,
|
|
99
|
+
pass,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/** Run an experiment end to end. Resolves with the final meta (summary included). */
|
|
103
|
+
export async function runExperiment(opts) {
|
|
104
|
+
const now = opts.now ?? Date.now;
|
|
105
|
+
const repeats = opts.repeats ?? 1;
|
|
106
|
+
const concurrency = opts.concurrency ?? DEFAULT_CONCURRENCY;
|
|
107
|
+
const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
108
|
+
if (!Number.isInteger(repeats) || repeats < 1)
|
|
109
|
+
throw new EvalContractError("repeats must be a whole number ≥ 1");
|
|
110
|
+
if (!Number.isInteger(concurrency) || concurrency < 1)
|
|
111
|
+
throw new EvalContractError("concurrency must be a whole number ≥ 1");
|
|
112
|
+
if (!opts.live && !opts.target.pinVersion) {
|
|
113
|
+
throw new EvalContractError(`running workflow version ${opts.workflowVersion} that is not live needs a target that can pin a version`);
|
|
114
|
+
}
|
|
115
|
+
await requireHeader(opts.store, opts.workflowId, opts.dataset);
|
|
116
|
+
const existing = opts.experimentId ? await getExperiment(opts.store, opts.workflowId, opts.experimentId) : null;
|
|
117
|
+
if (opts.experimentId && (!existing || existing.dataset !== opts.dataset)) {
|
|
118
|
+
throw new EvalContractError(`experiment "${opts.experimentId}" not found for dataset "${opts.dataset}"`);
|
|
119
|
+
}
|
|
120
|
+
// A resume runs the version it started with; a new experiment the chosen one, or the working set's.
|
|
121
|
+
const datasetVersion = opts.datasetVersion
|
|
122
|
+
?? existing?.datasetVersion
|
|
123
|
+
?? (await ensureDatasetVersion(opts.store, opts.workflowId, opts.dataset, { now: new Date(now()) })).version;
|
|
124
|
+
const { manifest, cases } = await loadVersion(opts.store, opts.workflowId, opts.dataset, datasetVersion);
|
|
125
|
+
let experiment;
|
|
126
|
+
if (existing) {
|
|
127
|
+
if (existing.datasetVersion !== datasetVersion || existing.workflowVersion !== opts.workflowVersion
|
|
128
|
+
|| existing.repeats !== repeats) {
|
|
129
|
+
throw new EvalContractError(`experiment "${existing.id}" ran dataset v${existing.datasetVersion} × workflow ${existing.workflowVersion} × ${existing.repeats}; `
|
|
130
|
+
+ "resume it with the same settings");
|
|
131
|
+
}
|
|
132
|
+
// A new attempt, claimed write-once before anything is published: runs the
|
|
133
|
+
// dead one may have started — or a concurrent resumer is starting — keep
|
|
134
|
+
// their contexts to themselves.
|
|
135
|
+
const attempt = await claimAttempt(opts.store, opts.workflowId, existing.id, {
|
|
136
|
+
atLeast: (existing.attempt ?? 1) + 1, claimedAt: iso(now()),
|
|
137
|
+
});
|
|
138
|
+
experiment = { ...existing, status: "running", attempt };
|
|
139
|
+
delete experiment.finishedAt;
|
|
140
|
+
delete experiment.error;
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
const id = newExperimentId(now());
|
|
144
|
+
await claimAttempt(opts.store, opts.workflowId, id, { atLeast: 1, claimedAt: iso(now()) });
|
|
145
|
+
experiment = {
|
|
146
|
+
id,
|
|
147
|
+
dataset: opts.dataset,
|
|
148
|
+
datasetVersion: manifest.version,
|
|
149
|
+
workflowId: opts.workflowId,
|
|
150
|
+
workflowVersion: opts.workflowVersion,
|
|
151
|
+
live: opts.live,
|
|
152
|
+
repeats,
|
|
153
|
+
...(opts.resultFields ? { resultFields: opts.resultFields } : {}),
|
|
154
|
+
attempt: 1,
|
|
155
|
+
startedAt: iso(now()),
|
|
156
|
+
status: "running",
|
|
157
|
+
origin: opts.origin ?? "cli",
|
|
158
|
+
...(opts.createdBy ? { createdBy: opts.createdBy } : {}),
|
|
159
|
+
...(opts.baselineId ? { baselineId: opts.baselineId } : {}),
|
|
160
|
+
...(opts.note ? { note: opts.note } : {}),
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
await putExperiment(opts.store, experiment);
|
|
164
|
+
const sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
165
|
+
/*
|
|
166
|
+
* Write-once, and honest about what happened. `putIfAbsent` answering false
|
|
167
|
+
* means "not written", which is two different things: the key EXISTS (a
|
|
168
|
+
* concurrent resumer got there first — its record is the one kept, and this
|
|
169
|
+
* run is reported as reused) or it does NOT (the store refused for another
|
|
170
|
+
* reason, e.g. a 409 from a colliding write). The second is retried with
|
|
171
|
+
* backoff and, if it never sticks, fails the experiment loudly — a record
|
|
172
|
+
* that was never stored must not be reported as reused.
|
|
173
|
+
*/
|
|
174
|
+
const storeRecord = async (record) => {
|
|
175
|
+
for (let attempt = 0;; attempt++) {
|
|
176
|
+
if (await putRunRecord(opts.store, opts.workflowId, experiment.id, record))
|
|
177
|
+
return { kept: record, reused: false };
|
|
178
|
+
const there = await getRunRecord(opts.store, opts.workflowId, experiment.id, record.caseId, record.repeat);
|
|
179
|
+
if (there)
|
|
180
|
+
return { kept: there, reused: true };
|
|
181
|
+
const wait = RECORD_WRITE_BACKOFF_MS[attempt];
|
|
182
|
+
if (wait === undefined) {
|
|
183
|
+
throw new EvalContractError(`could not store the run record for ${record.caseId}#${record.repeat}: the store refused the write `
|
|
184
|
+
+ `${attempt + 1} times and the key is still empty`);
|
|
185
|
+
}
|
|
186
|
+
await sleep(wait);
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
const work = cases.flatMap(({ case: c, rev }) => Array.from({ length: repeats }, (_, i) => ({ c, rev, repeat: i + 1 })));
|
|
190
|
+
const records = [];
|
|
191
|
+
let done = 0;
|
|
192
|
+
let release;
|
|
193
|
+
let failure;
|
|
194
|
+
try {
|
|
195
|
+
if (!opts.live)
|
|
196
|
+
release = await opts.target.pinVersion(opts.workflowVersion, experimentContextPrefix(experiment.id));
|
|
197
|
+
await pool(work, concurrency, async ({ c, rev, repeat }) => {
|
|
198
|
+
const onFile = await getRunRecord(opts.store, opts.workflowId, experiment.id, c.id, repeat);
|
|
199
|
+
if (onFile) {
|
|
200
|
+
records.push(onFile);
|
|
201
|
+
opts.onProgress?.({ done: ++done, total: work.length, run: onFile, reused: true });
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
if (opts.signal?.aborted)
|
|
205
|
+
return;
|
|
206
|
+
const record = await runOne({
|
|
207
|
+
target: opts.target, header: manifest.header, case: c, caseRev: rev, repeat,
|
|
208
|
+
attempt: experiment.attempt ?? 1,
|
|
209
|
+
context: runContext(experiment.id, c.id, repeat, experiment.attempt ?? 1), timeoutMs, now,
|
|
210
|
+
...(experiment.resultFields ? { resultFields: experiment.resultFields } : {}),
|
|
211
|
+
});
|
|
212
|
+
const { kept, reused } = await storeRecord(record);
|
|
213
|
+
records.push(kept);
|
|
214
|
+
opts.onProgress?.({ done: ++done, total: work.length, run: kept, reused });
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
catch (e) {
|
|
218
|
+
failure = e;
|
|
219
|
+
}
|
|
220
|
+
finally {
|
|
221
|
+
if (release) {
|
|
222
|
+
try {
|
|
223
|
+
await release();
|
|
224
|
+
}
|
|
225
|
+
catch (e) {
|
|
226
|
+
failure ??= new Error(`could not release the version pin: ${message(e)}`);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
const finished = {
|
|
231
|
+
...experiment,
|
|
232
|
+
finishedAt: iso(now()),
|
|
233
|
+
status: failure ? "error" : opts.signal?.aborted ? "cancelled" : "done",
|
|
234
|
+
...(failure ? { error: message(failure) } : {}),
|
|
235
|
+
summary: summarize(records),
|
|
236
|
+
};
|
|
237
|
+
await putExperiment(opts.store, finished);
|
|
238
|
+
return finished;
|
|
239
|
+
}
|
|
240
|
+
//# sourceMappingURL=run.js.map
|
package/dist/run.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":"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"}
|