@workos/quickstudy 0.3.0 → 0.5.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 +4 -0
- package/package.json +1 -1
- package/src/adapters/echo.ts +2 -0
- package/src/adapters/oracle.ts +69 -0
- package/src/adapters/types.ts +27 -0
- package/src/build-info.generated.ts +1 -1
- package/src/cli.ts +26 -3
- package/src/diagnose/excerpt.ts +19 -8
- package/src/diagnose/select.ts +1 -1
- package/src/diagnose/types.ts +5 -2
- package/src/evals/discovery.ts +32 -2
- package/src/evals/result.ts +1 -1
- package/src/evals/types.ts +12 -0
- package/src/export-types.ts +7 -0
- package/src/export.ts +15 -4
- package/src/manifest.ts +6 -0
- package/src/report/aggregate.ts +136 -0
- package/src/report/report.ts +175 -8
- package/src/report/scorer-health.ts +129 -0
- package/src/runner/context.ts +19 -2
- package/src/runner/execute.ts +160 -61
- package/src/runner/oracle-validate.ts +109 -0
- package/src/runner/workspace-source.ts +34 -0
- package/src/store/db.ts +65 -2
- package/src/store/schema.ts +7 -1
- package/ui/dist/index.html +11 -11
package/src/store/db.ts
CHANGED
|
@@ -18,8 +18,29 @@ import { SCHEMA_SQL } from "./schema.ts";
|
|
|
18
18
|
|
|
19
19
|
export type AttemptStatus = "completed" | "incomplete" | "error";
|
|
20
20
|
|
|
21
|
+
/** Which stage failed when an attempt's status is "error". */
|
|
22
|
+
export const ERROR_KINDS = ["environment", "agent", "scorer", "harness"] as const;
|
|
23
|
+
export type ErrorKind = (typeof ERROR_KINDS)[number];
|
|
24
|
+
/** Which limit an attempt hit; the tree it left behind was still graded. */
|
|
25
|
+
export type LimitKind = "timeout";
|
|
26
|
+
|
|
27
|
+
function toErrorKind(value: string | null): ErrorKind | null {
|
|
28
|
+
return value !== null && (ERROR_KINDS as readonly string[]).includes(value) ? (value as ErrorKind) : null;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function toLimitKind(value: string | null): LimitKind | null {
|
|
32
|
+
return value === "timeout" ? value : null;
|
|
33
|
+
}
|
|
34
|
+
|
|
21
35
|
/** The run-level configuration recorded in `runs.config_json`. */
|
|
22
36
|
export interface RunConfig {
|
|
37
|
+
/**
|
|
38
|
+
* Each experiment's role, from the adapter that actually ran it (a scripted
|
|
39
|
+
* container command is always "agent"). Recorded here — NOT in the manifest —
|
|
40
|
+
* like `groups`, so it never perturbs run identity. Absent on older runs: every
|
|
41
|
+
* experiment then reads as "agent".
|
|
42
|
+
*/
|
|
43
|
+
roles?: Record<string, import("../adapters/types.ts").AdapterRole>;
|
|
23
44
|
scheduler?: { concurrency: number; seed: string; policy: "seeded-hash-v1"; order: import("../plan.ts").AttemptPlan[] };
|
|
24
45
|
trials: number;
|
|
25
46
|
evalIds: string[];
|
|
@@ -82,6 +103,13 @@ export interface NewAttempt {
|
|
|
82
103
|
startedAt?: number | null;
|
|
83
104
|
finishedAt?: number | null;
|
|
84
105
|
error?: string | null;
|
|
106
|
+
/** "timeout" = the agent hit its wall-clock limit and the tree it left was graded (column limit_hit). */
|
|
107
|
+
limitHit?: LimitKind | null;
|
|
108
|
+
/** Which stage failed; set only when status = "error". */
|
|
109
|
+
errorKind?: ErrorKind | null;
|
|
110
|
+
/** Agent phase only, epoch ms; null = not recorded. */
|
|
111
|
+
agentStartedAt?: number | null;
|
|
112
|
+
agentFinishedAt?: number | null;
|
|
85
113
|
}
|
|
86
114
|
|
|
87
115
|
export interface AttemptRecord {
|
|
@@ -106,6 +134,13 @@ export interface AttemptRecord {
|
|
|
106
134
|
startedAt: number | null;
|
|
107
135
|
finishedAt: number | null;
|
|
108
136
|
error: string | null;
|
|
137
|
+
/** "timeout" = the agent hit its wall-clock limit and the tree it left was graded (column limit_hit). */
|
|
138
|
+
limitHit?: LimitKind | null;
|
|
139
|
+
/** Which stage failed; set only when status = "error". */
|
|
140
|
+
errorKind?: ErrorKind | null;
|
|
141
|
+
/** Agent phase only, epoch ms; null = not recorded. */
|
|
142
|
+
agentStartedAt?: number | null;
|
|
143
|
+
agentFinishedAt?: number | null;
|
|
109
144
|
}
|
|
110
145
|
|
|
111
146
|
interface RunRow {
|
|
@@ -139,6 +174,10 @@ interface AttemptRow {
|
|
|
139
174
|
started_at: number | null;
|
|
140
175
|
finished_at: number | null;
|
|
141
176
|
error: string | null;
|
|
177
|
+
limit_hit: string | null;
|
|
178
|
+
error_kind: string | null;
|
|
179
|
+
agent_started_at: number | null;
|
|
180
|
+
agent_finished_at: number | null;
|
|
142
181
|
}
|
|
143
182
|
|
|
144
183
|
function toRunRecord(row: RunRow): RunRecord {
|
|
@@ -175,6 +214,10 @@ function toAttemptRecord(row: AttemptRow): AttemptRecord {
|
|
|
175
214
|
startedAt: row.started_at,
|
|
176
215
|
finishedAt: row.finished_at,
|
|
177
216
|
error: row.error,
|
|
217
|
+
limitHit: toLimitKind(row.limit_hit ?? null),
|
|
218
|
+
errorKind: toErrorKind(row.error_kind ?? null),
|
|
219
|
+
agentStartedAt: row.agent_started_at ?? null,
|
|
220
|
+
agentFinishedAt: row.agent_finished_at ?? null,
|
|
178
221
|
};
|
|
179
222
|
}
|
|
180
223
|
|
|
@@ -226,6 +269,21 @@ export class ResultsStore {
|
|
|
226
269
|
}
|
|
227
270
|
if (!attemptColumns.includes("judge_usage_json")) this.db.exec("ALTER TABLE attempts ADD COLUMN judge_usage_json TEXT;");
|
|
228
271
|
if (!attemptColumns.includes("retry_of")) this.db.exec("ALTER TABLE attempts ADD COLUMN retry_of TEXT;");
|
|
272
|
+
// Outcome taxonomy + agent-phase timing (nullable; NULL = unavailable).
|
|
273
|
+
for (const [name, type] of [
|
|
274
|
+
["limit_hit", "TEXT"],
|
|
275
|
+
["error_kind", "TEXT"],
|
|
276
|
+
["agent_started_at", "INTEGER"],
|
|
277
|
+
["agent_finished_at", "INTEGER"],
|
|
278
|
+
] as const) {
|
|
279
|
+
if (attemptColumns.includes(name)) continue;
|
|
280
|
+
try {
|
|
281
|
+
this.db.exec(`ALTER TABLE attempts ADD COLUMN ${name} ${type};`);
|
|
282
|
+
} catch (err) {
|
|
283
|
+
// A concurrent opener may have added it between the read and the ALTER.
|
|
284
|
+
if (!/duplicate column/i.test(err instanceof Error ? err.message : String(err))) throw err;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
229
287
|
this.db.exec("PRAGMA user_version = 3;");
|
|
230
288
|
}
|
|
231
289
|
|
|
@@ -264,8 +322,9 @@ export class ResultsStore {
|
|
|
264
322
|
`INSERT INTO attempts (
|
|
265
323
|
id, run_id, eval_id, experiment_id, suite, trial_index, attempt_identity_hash, status,
|
|
266
324
|
result_json, surface_usage_json, transcript_ref, diff_ref, cost_usd, tokens_in, tokens_out,
|
|
267
|
-
turns, started_at, finished_at, error, retry_of, judge_usage_json
|
|
268
|
-
|
|
325
|
+
turns, started_at, finished_at, error, retry_of, judge_usage_json,
|
|
326
|
+
limit_hit, error_kind, agent_started_at, agent_finished_at
|
|
327
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
269
328
|
)
|
|
270
329
|
.run(
|
|
271
330
|
attempt.id,
|
|
@@ -289,6 +348,10 @@ export class ResultsStore {
|
|
|
289
348
|
attempt.error ?? null,
|
|
290
349
|
attempt.retryOf ?? null,
|
|
291
350
|
attempt.judgeRecords ? JSON.stringify(attempt.judgeRecords) : null,
|
|
351
|
+
attempt.limitHit ?? null,
|
|
352
|
+
attempt.errorKind ?? null,
|
|
353
|
+
attempt.agentStartedAt ?? null,
|
|
354
|
+
attempt.agentFinishedAt ?? null,
|
|
292
355
|
);
|
|
293
356
|
}
|
|
294
357
|
|
package/src/store/schema.ts
CHANGED
|
@@ -32,7 +32,13 @@ CREATE TABLE IF NOT EXISTS attempts (
|
|
|
32
32
|
tokens_in INTEGER, tokens_out INTEGER,
|
|
33
33
|
turns INTEGER, -- agent steps; NULL = no adapter stream (scripted commands)
|
|
34
34
|
started_at INTEGER, finished_at INTEGER,
|
|
35
|
-
error TEXT
|
|
35
|
+
error TEXT, -- only when status = 'error'
|
|
36
|
+
-- Outcome taxonomy + agent-phase timing. NULL = unavailable / not applicable
|
|
37
|
+
-- (rows written before these columns existed read NULL; never backfilled).
|
|
38
|
+
limit_hit TEXT, -- 'timeout' when the agent hit its wall-clock limit and the tree it left was graded
|
|
39
|
+
error_kind TEXT, -- 'environment' | 'agent' | 'scorer' | 'harness' (status = 'error' only)
|
|
40
|
+
agent_started_at INTEGER, -- epoch ms; agent phase only
|
|
41
|
+
agent_finished_at INTEGER -- epoch ms; agent phase only
|
|
36
42
|
);
|
|
37
43
|
|
|
38
44
|
CREATE INDEX IF NOT EXISTS idx_attempts_run_pair ON attempts(run_id, eval_id, experiment_id);
|