chivgent 0.12.0 → 0.13.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.
@@ -0,0 +1,175 @@
1
+ import { readFile, stat } from "node:fs/promises";
2
+ import path from "node:path";
3
+ const pass = { passed: true, reason: "" };
4
+ function fail(reason) {
5
+ return { passed: false, reason };
6
+ }
7
+ function requireString(spec, field) {
8
+ const value = spec[field];
9
+ if (typeof value !== "string" || value.length === 0) {
10
+ throw new Error(`${spec.type}: "${field}" must be a non-empty string.`);
11
+ }
12
+ return value;
13
+ }
14
+ async function readWorkspaceFile(workspace, relativePath) {
15
+ try {
16
+ return await readFile(path.join(workspace, relativePath), "utf8");
17
+ }
18
+ catch {
19
+ return undefined;
20
+ }
21
+ }
22
+ /** Tool names that produced a result, in call order, errors included. */
23
+ function toolCalls(events) {
24
+ return events
25
+ .filter((event) => event.type === "tool_execution_end")
26
+ .map((event) => event.toolName);
27
+ }
28
+ function successfulToolCalls(events) {
29
+ return events
30
+ .filter((event) => event.type === "tool_execution_end" &&
31
+ event.isError === false)
32
+ .map((event) => event.toolName);
33
+ }
34
+ const factories = {
35
+ "file-contains": (spec) => {
36
+ const file = requireString(spec, "path");
37
+ const text = requireString(spec, "text");
38
+ return async ({ workspace }) => {
39
+ const contents = await readWorkspaceFile(workspace, file);
40
+ if (contents === undefined) {
41
+ return fail(`${file} does not exist`);
42
+ }
43
+ return contents.includes(text)
44
+ ? pass
45
+ : fail(`${file} does not contain ${JSON.stringify(text)}`);
46
+ };
47
+ },
48
+ "file-excludes": (spec) => {
49
+ const file = requireString(spec, "path");
50
+ const text = requireString(spec, "text");
51
+ return async ({ workspace }) => {
52
+ const contents = await readWorkspaceFile(workspace, file);
53
+ if (contents === undefined) {
54
+ return fail(`${file} does not exist`);
55
+ }
56
+ if (!contents.includes(text)) {
57
+ return pass;
58
+ }
59
+ // Naming the line makes the failure actionable without opening the file.
60
+ const line = contents.slice(0, contents.indexOf(text)).split("\n").length;
61
+ return fail(`${file} still contains ${JSON.stringify(text)} at line ${line}`);
62
+ };
63
+ },
64
+ "file-exists": (spec) => {
65
+ const file = requireString(spec, "path");
66
+ return async ({ workspace }) => {
67
+ try {
68
+ await stat(path.join(workspace, file));
69
+ return pass;
70
+ }
71
+ catch {
72
+ return fail(`${file} was not created`);
73
+ }
74
+ };
75
+ },
76
+ "file-absent": (spec) => {
77
+ const file = requireString(spec, "path");
78
+ return async ({ workspace }) => {
79
+ try {
80
+ await stat(path.join(workspace, file));
81
+ return fail(`${file} still exists`);
82
+ }
83
+ catch {
84
+ return pass;
85
+ }
86
+ };
87
+ },
88
+ "file-equals": (spec) => {
89
+ const file = requireString(spec, "path");
90
+ const text = requireString(spec, "text");
91
+ return async ({ workspace }) => {
92
+ const contents = await readWorkspaceFile(workspace, file);
93
+ if (contents === undefined) {
94
+ return fail(`${file} does not exist`);
95
+ }
96
+ return contents === text
97
+ ? pass
98
+ : fail(`${file} does not match the expected contents byte for byte`);
99
+ };
100
+ },
101
+ "used-tool": (spec) => {
102
+ const name = requireString(spec, "name");
103
+ return async ({ events }) => {
104
+ const used = toolCalls(events);
105
+ return used.includes(name)
106
+ ? pass
107
+ : fail(`never called ${name}; called ${used.length === 0 ? "nothing" : [...new Set(used)].join(", ")}`);
108
+ };
109
+ },
110
+ "not-used-tool": (spec) => {
111
+ const name = requireString(spec, "name");
112
+ return async ({ events }) => {
113
+ const used = toolCalls(events);
114
+ const count = used.filter((tool) => tool === name).length;
115
+ return count === 0
116
+ ? pass
117
+ : fail(`called ${name} ${count} time(s), which this task forbids`);
118
+ };
119
+ },
120
+ "tool-succeeded": (spec) => {
121
+ const name = requireString(spec, "name");
122
+ return async ({ events }) => {
123
+ return successfulToolCalls(events).includes(name)
124
+ ? pass
125
+ : fail(`${name} never returned a successful result`);
126
+ };
127
+ },
128
+ "answer-matches": (spec) => {
129
+ const pattern = requireString(spec, "pattern");
130
+ const flags = typeof spec.flags === "string" ? spec.flags : "i";
131
+ const expression = new RegExp(pattern, flags);
132
+ return async ({ finalAnswer }) => {
133
+ return expression.test(finalAnswer)
134
+ ? pass
135
+ : fail(`the answer did not match /${pattern}/${flags}: ${JSON.stringify(finalAnswer.slice(0, 120))}`);
136
+ };
137
+ },
138
+ "answer-excludes": (spec) => {
139
+ const pattern = requireString(spec, "pattern");
140
+ const flags = typeof spec.flags === "string" ? spec.flags : "i";
141
+ const expression = new RegExp(pattern, flags);
142
+ return async ({ finalAnswer }) => {
143
+ return expression.test(finalAnswer)
144
+ ? fail(`the answer matched /${pattern}/${flags}, which this task forbids`)
145
+ : pass;
146
+ };
147
+ },
148
+ "max-turns-under": (spec) => {
149
+ const limit = spec.turns;
150
+ if (!Number.isSafeInteger(limit) || limit < 1) {
151
+ throw new Error("max-turns-under: \"turns\" must be a positive integer.");
152
+ }
153
+ return async ({ turnCount }) => {
154
+ return turnCount <= limit
155
+ ? pass
156
+ : fail(`took ${turnCount} turns, over the limit of ${limit}`);
157
+ };
158
+ },
159
+ };
160
+ export const GRADER_TYPES = Object.keys(factories);
161
+ export function createGrader(spec) {
162
+ const factory = factories[spec.type];
163
+ if (factory === undefined) {
164
+ throw new Error(`Unknown grader type "${spec.type}". Known types: ${GRADER_TYPES.join(", ")}.`);
165
+ }
166
+ return factory(spec);
167
+ }
168
+ export function describeGrader(spec) {
169
+ const detail = Object.entries(spec)
170
+ .filter(([key]) => key !== "type")
171
+ .map(([key, value]) => `${key}=${JSON.stringify(value)}`)
172
+ .join(" ");
173
+ return detail.length === 0 ? spec.type : `${spec.type} ${detail}`;
174
+ }
175
+ //# sourceMappingURL=graders.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graders.js","sourceRoot":"","sources":["../../src/evals/graders.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { Capability } from "./task.js";
2
+ /**
3
+ * Argument parsing lives apart from the entry point.
4
+ *
5
+ * cli.ts runs main() when imported, so anything that wants to test the parsing
6
+ * would start an eval run just by importing it.
7
+ */
8
+ export interface EvalOptions {
9
+ readonly tasks: readonly string[];
10
+ readonly attempts?: number;
11
+ readonly directory: string;
12
+ readonly jsonPath?: string;
13
+ readonly capabilities: readonly Capability[];
14
+ readonly providerArgs: readonly string[];
15
+ readonly help: boolean;
16
+ }
17
+ export declare function parseEvalArgs(argv: readonly string[]): EvalOptions;
18
+ //# sourceMappingURL=parse-args.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-args.d.ts","sourceRoot":"","sources":["../../src/evals/parse-args.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAE5C;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,EAAE,SAAS,UAAU,EAAE,CAAC;IAC7C,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;CACxB;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,WAAW,CA4DlE"}
@@ -0,0 +1,67 @@
1
+ export function parseEvalArgs(argv) {
2
+ const tasks = [];
3
+ const capabilities = [];
4
+ const providerArgs = [];
5
+ let attempts;
6
+ let directory = "evals";
7
+ let jsonPath;
8
+ let help = false;
9
+ const value = (index, option) => {
10
+ const next = argv[index + 1];
11
+ if (next === undefined || next.startsWith("-")) {
12
+ throw new TypeError(`${option} requires a value.`);
13
+ }
14
+ return next;
15
+ };
16
+ for (let index = 0; index < argv.length; index += 1) {
17
+ const argument = argv[index];
18
+ if (argument === "--help" || argument === "-h") {
19
+ help = true;
20
+ }
21
+ else if (argument === "--task") {
22
+ tasks.push(value(index, "--task"));
23
+ index += 1;
24
+ }
25
+ else if (argument === "--attempts") {
26
+ const parsed = Number(value(index, "--attempts"));
27
+ if (!Number.isSafeInteger(parsed) || parsed < 1 || parsed > 50) {
28
+ throw new TypeError("--attempts must be an integer from 1 to 50.");
29
+ }
30
+ attempts = parsed;
31
+ index += 1;
32
+ }
33
+ else if (argument === "--dir") {
34
+ directory = value(index, "--dir");
35
+ index += 1;
36
+ }
37
+ else if (argument === "--json") {
38
+ jsonPath = value(index, "--json");
39
+ index += 1;
40
+ }
41
+ else if (argument === "--allow-writes") {
42
+ capabilities.push("writes");
43
+ }
44
+ else if (argument === "--allow-shell") {
45
+ capabilities.push("shell");
46
+ }
47
+ else if (argument === "--provider" || argument === "--model") {
48
+ // Passed through so the Provider registry resolves them exactly as the
49
+ // real CLI does, including environment fallbacks.
50
+ providerArgs.push(argument, value(index, argument));
51
+ index += 1;
52
+ }
53
+ else if (argument !== undefined) {
54
+ throw new TypeError(`Unknown option: ${argument}`);
55
+ }
56
+ }
57
+ return {
58
+ tasks,
59
+ ...(attempts === undefined ? {} : { attempts }),
60
+ directory,
61
+ ...(jsonPath === undefined ? {} : { jsonPath }),
62
+ capabilities,
63
+ providerArgs,
64
+ help,
65
+ };
66
+ }
67
+ //# sourceMappingURL=parse-args.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-args.js","sourceRoot":"","sources":["../../src/evals/parse-args.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { TaskResult } from "./runner.js";
2
+ export interface ReportMeta {
3
+ readonly provider: string;
4
+ readonly model: string;
5
+ readonly version: string;
6
+ readonly startedAt: string;
7
+ }
8
+ /**
9
+ * The table always shows the sample size next to the score.
10
+ *
11
+ * "4/5" and "80%" carry different information from "passed": a rate without its
12
+ * denominator invites reading one lucky attempt as a result.
13
+ */
14
+ export declare function formatTable(results: readonly TaskResult[]): string;
15
+ /** Failures, grouped so the same reason across attempts is one line. */
16
+ export declare function formatFailures(results: readonly TaskResult[]): string;
17
+ export declare function toJsonReport(results: readonly TaskResult[], meta: ReportMeta): object;
18
+ //# sourceMappingURL=report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/evals/report.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAwBD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,GAAG,MAAM,CAqClE;AAED,wEAAwE;AACxE,wBAAgB,cAAc,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE,GAAG,MAAM,CAgBrE;AAED,wBAAgB,YAAY,CAC1B,OAAO,EAAE,SAAS,UAAU,EAAE,EAC9B,IAAI,EAAE,UAAU,GACf,MAAM,CA4BR"}
@@ -0,0 +1,103 @@
1
+ function median(values) {
2
+ if (values.length === 0) {
3
+ return 0;
4
+ }
5
+ const sorted = [...values].sort((a, b) => a - b);
6
+ const middle = Math.floor(sorted.length / 2);
7
+ return sorted.length % 2 === 0
8
+ ? Math.round(((sorted[middle - 1] ?? 0) + (sorted[middle] ?? 0)) / 2)
9
+ : (sorted[middle] ?? 0);
10
+ }
11
+ function mean(values) {
12
+ if (values.length === 0) {
13
+ return 0;
14
+ }
15
+ return values.reduce((total, value) => total + value, 0) / values.length;
16
+ }
17
+ function pad(value, width) {
18
+ return value.length >= width ? value : value + " ".repeat(width - value.length);
19
+ }
20
+ /**
21
+ * The table always shows the sample size next to the score.
22
+ *
23
+ * "4/5" and "80%" carry different information from "passed": a rate without its
24
+ * denominator invites reading one lucky attempt as a result.
25
+ */
26
+ export function formatTable(results) {
27
+ if (results.length === 0) {
28
+ return "No tasks ran.\n";
29
+ }
30
+ const rows = results.map((result) => ({
31
+ task: result.task,
32
+ pass: `${result.passed}/${result.total}`,
33
+ turns: mean(result.attempts.map((attempt) => attempt.turnCount)).toFixed(1),
34
+ tools: [
35
+ ...new Set(result.attempts.flatMap((attempt) => attempt.toolsUsed)),
36
+ ].join(","),
37
+ time: `${(median(result.attempts.map((attempt) => attempt.durationMs)) / 1000).toFixed(1)}s`,
38
+ }));
39
+ const widths = {
40
+ task: Math.max(4, ...rows.map((row) => row.task.length)),
41
+ pass: Math.max(4, ...rows.map((row) => row.pass.length)),
42
+ turns: Math.max(5, ...rows.map((row) => row.turns.length)),
43
+ tools: Math.max(5, ...rows.map((row) => row.tools.length)),
44
+ };
45
+ const lines = [
46
+ `${pad("task", widths.task)} ${pad("pass", widths.pass)} ${pad("turns", widths.turns)} ${pad("tools", widths.tools)} p50`,
47
+ ];
48
+ for (const row of rows) {
49
+ lines.push(`${pad(row.task, widths.task)} ${pad(row.pass, widths.pass)} ${pad(row.turns, widths.turns)} ${pad(row.tools, widths.tools)} ${row.time}`);
50
+ }
51
+ const passed = results.reduce((total, result) => total + result.passed, 0);
52
+ const total = results.reduce((sum, result) => sum + result.total, 0);
53
+ const percent = total === 0 ? 0 : Math.round((passed / total) * 100);
54
+ lines.push("");
55
+ lines.push(`overall ${passed}/${total} (${percent}%)`);
56
+ return `${lines.join("\n")}\n`;
57
+ }
58
+ /** Failures, grouped so the same reason across attempts is one line. */
59
+ export function formatFailures(results) {
60
+ const lines = [];
61
+ for (const result of results) {
62
+ const byReason = new Map();
63
+ for (const attempt of result.attempts) {
64
+ for (const failure of attempt.failures) {
65
+ const attempts = byReason.get(failure) ?? [];
66
+ attempts.push(attempt.attempt);
67
+ byReason.set(failure, attempts);
68
+ }
69
+ }
70
+ for (const [reason, attempts] of byReason) {
71
+ lines.push(`${result.task} attempt ${attempts.join(",")}: ${reason}`);
72
+ }
73
+ }
74
+ return lines.length === 0 ? "" : `${lines.join("\n")}\n`;
75
+ }
76
+ export function toJsonReport(results, meta) {
77
+ return {
78
+ schemaVersion: 1,
79
+ ...meta,
80
+ tasks: results.map((result) => ({
81
+ name: result.task,
82
+ passed: result.passed,
83
+ total: result.total,
84
+ passRate: result.total === 0 ? 0 : result.passed / result.total,
85
+ meanTurns: mean(result.attempts.map((attempt) => attempt.turnCount)),
86
+ medianDurationMs: median(result.attempts.map((attempt) => attempt.durationMs)),
87
+ attempts: result.attempts.map((attempt) => ({
88
+ attempt: attempt.attempt,
89
+ passed: attempt.passed,
90
+ status: attempt.status,
91
+ turnCount: attempt.turnCount,
92
+ durationMs: attempt.durationMs,
93
+ toolsUsed: attempt.toolsUsed,
94
+ failures: attempt.failures,
95
+ })),
96
+ })),
97
+ overall: {
98
+ passed: results.reduce((total, result) => total + result.passed, 0),
99
+ total: results.reduce((sum, result) => sum + result.total, 0),
100
+ },
101
+ };
102
+ }
103
+ //# sourceMappingURL=report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../src/evals/report.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import type { LLMClient } from "../llm.js";
2
+ import { type AttemptFacts } from "./graders.js";
3
+ import type { Capability, Task } from "./task.js";
4
+ export interface AttemptResult {
5
+ readonly attempt: number;
6
+ readonly passed: boolean;
7
+ readonly status: AttemptFacts["status"];
8
+ readonly turnCount: number;
9
+ readonly durationMs: number;
10
+ readonly toolsUsed: readonly string[];
11
+ /** One entry per failed grader, in task order. */
12
+ readonly failures: readonly string[];
13
+ }
14
+ export interface TaskResult {
15
+ readonly task: string;
16
+ readonly attempts: readonly AttemptResult[];
17
+ readonly passed: number;
18
+ readonly total: number;
19
+ }
20
+ export interface RunnerOptions {
21
+ /** Built per attempt, so a test can hand out a fresh fake each time. */
22
+ readonly createClient: () => LLMClient;
23
+ readonly systemPrompt: string;
24
+ readonly capabilities: readonly Capability[];
25
+ readonly attempts?: number;
26
+ readonly onAttempt?: (result: AttemptResult, task: Task) => void;
27
+ readonly signal?: AbortSignal;
28
+ }
29
+ export declare class MissingCapabilityError extends Error {
30
+ readonly task: string;
31
+ readonly missing: readonly Capability[];
32
+ constructor(task: string, missing: readonly Capability[]);
33
+ }
34
+ /**
35
+ * Runs one task N times.
36
+ *
37
+ * The result is a pass rate, not a verdict: one attempt against a
38
+ * nondeterministic model says almost nothing, so the runner never reports a
39
+ * single attempt as the task's outcome.
40
+ */
41
+ export declare function runTask(task: Task, options: RunnerOptions): Promise<TaskResult>;
42
+ export declare function runTasks(tasks: readonly Task[], options: RunnerOptions): Promise<readonly TaskResult[]>;
43
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/evals/runner.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAU3C,OAAO,EAAgC,KAAK,YAAY,EAAE,MAAM,cAAc,CAAC;AAC/E,OAAO,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAElD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAC;IACxC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,CAAC;IACtC,kDAAkD;IAClD,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAED,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,SAAS,aAAa,EAAE,CAAC;IAC5C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,wEAAwE;IACxE,QAAQ,CAAC,YAAY,EAAE,MAAM,SAAS,CAAC;IACvC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,YAAY,EAAE,SAAS,UAAU,EAAE,CAAC;IAC7C,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IACjE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B;AAED,qBAAa,sBAAuB,SAAQ,KAAK;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM;IAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,UAAU,EAAE;IAA1E,YAAqB,IAAI,EAAE,MAAM,EAAW,OAAO,EAAE,SAAS,UAAU,EAAE,EAOzE;CACF;AAgHD;;;;;;GAMG;AACH,wBAAsB,OAAO,CAC3B,IAAI,EAAE,IAAI,EACV,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,UAAU,CAAC,CAoBrB;AAED,wBAAsB,QAAQ,CAC5B,KAAK,EAAE,SAAS,IAAI,EAAE,EACtB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,SAAS,UAAU,EAAE,CAAC,CAMhC"}
@@ -0,0 +1,144 @@
1
+ import { Agent as AgentClass } from "../agent.js";
2
+ import { LocalWorkspace } from "../workspace.js";
3
+ import { ListFilesTool } from "../tools/list-files.js";
4
+ import { ReadFileTool } from "../tools/read-file.js";
5
+ import { SearchTextTool } from "../tools/search-text.js";
6
+ import { WriteFileTool } from "../tools/write-file.js";
7
+ import { EditFileTool } from "../tools/edit-file.js";
8
+ import { BashTool } from "../tools/bash.js";
9
+ import { createAttemptWorkspace } from "./fixture.js";
10
+ import { createGrader, describeGrader } from "./graders.js";
11
+ export class MissingCapabilityError extends Error {
12
+ task;
13
+ missing;
14
+ constructor(task, missing) {
15
+ super(`Task "${task}" needs ${missing.join(" and ")}; rerun with ${missing
16
+ .map((capability) => (capability === "writes" ? "--allow-writes" : "--allow-shell"))
17
+ .join(" ")}.`);
18
+ this.task = task;
19
+ this.missing = missing;
20
+ this.name = "MissingCapabilityError";
21
+ }
22
+ }
23
+ function toolsFor(capabilities, cwd) {
24
+ const tools = [
25
+ new ListFilesTool(),
26
+ new SearchTextTool(),
27
+ new ReadFileTool(),
28
+ ];
29
+ if (capabilities.includes("writes")) {
30
+ tools.push(new WriteFileTool(), new EditFileTool());
31
+ }
32
+ if (capabilities.includes("shell")) {
33
+ tools.push(new BashTool({ cwd }));
34
+ }
35
+ return tools;
36
+ }
37
+ function missingCapabilities(task, granted) {
38
+ return task.capabilities.filter((capability) => !granted.includes(capability));
39
+ }
40
+ async function runAttempt(task, attempt, options) {
41
+ const workspace = await createAttemptWorkspace(task.fixtureDirectory);
42
+ const events = [];
43
+ const startedAt = Date.now();
44
+ try {
45
+ const agent = new AgentClass({
46
+ systemPrompt: options.systemPrompt,
47
+ maxTurns: task.maxTurns,
48
+ llm: options.createClient(),
49
+ tools: toolsFor(task.capabilities, workspace.path),
50
+ workspace: new LocalWorkspace(workspace.path, {
51
+ allowWrites: task.capabilities.includes("writes"),
52
+ }),
53
+ streaming: false,
54
+ onEvent: (event) => events.push(event),
55
+ });
56
+ let status = "error";
57
+ let finalAnswer = "";
58
+ let turnCount = 0;
59
+ try {
60
+ const result = await agent.run(task.prompt, {
61
+ ...(options.signal === undefined ? {} : { signal: options.signal }),
62
+ });
63
+ status = result.status;
64
+ turnCount = result.turnCount;
65
+ finalAnswer =
66
+ result.status === "completed" ? result.finalMessage.content : "";
67
+ }
68
+ catch (error) {
69
+ // A crashed run is a failed attempt, not a failed eval run: the point is
70
+ // to measure how often this happens, not to stop at the first one.
71
+ status = "error";
72
+ finalAnswer = error instanceof Error ? error.message : String(error);
73
+ }
74
+ const facts = {
75
+ workspace: workspace.path,
76
+ finalAnswer,
77
+ turnCount,
78
+ status,
79
+ events,
80
+ };
81
+ const failures = [];
82
+ if (status !== "completed") {
83
+ failures.push(status === "max_turns"
84
+ ? `hit the ${task.maxTurns}-turn limit without a final answer`
85
+ : `run ended as ${status}: ${finalAnswer.split("\n", 1)[0] ?? ""}`);
86
+ }
87
+ for (const spec of task.graders) {
88
+ const result = await createGrader(spec)(facts);
89
+ if (!result.passed) {
90
+ failures.push(`${describeGrader(spec)} — ${result.reason}`);
91
+ }
92
+ }
93
+ return {
94
+ attempt,
95
+ passed: failures.length === 0,
96
+ status,
97
+ turnCount,
98
+ durationMs: Date.now() - startedAt,
99
+ toolsUsed: [
100
+ ...new Set(events
101
+ .filter((event) => event.type === "tool_execution_end")
102
+ .map((event) => event.toolName)),
103
+ ],
104
+ failures,
105
+ };
106
+ }
107
+ finally {
108
+ await workspace.dispose();
109
+ }
110
+ }
111
+ /**
112
+ * Runs one task N times.
113
+ *
114
+ * The result is a pass rate, not a verdict: one attempt against a
115
+ * nondeterministic model says almost nothing, so the runner never reports a
116
+ * single attempt as the task's outcome.
117
+ */
118
+ export async function runTask(task, options) {
119
+ const missing = missingCapabilities(task, options.capabilities);
120
+ if (missing.length > 0) {
121
+ throw new MissingCapabilityError(task.name, missing);
122
+ }
123
+ const total = options.attempts ?? task.attempts;
124
+ const attempts = [];
125
+ for (let index = 1; index <= total; index += 1) {
126
+ const result = await runAttempt(task, index, options);
127
+ attempts.push(result);
128
+ options.onAttempt?.(result, task);
129
+ }
130
+ return {
131
+ task: task.name,
132
+ attempts,
133
+ passed: attempts.filter((attempt) => attempt.passed).length,
134
+ total,
135
+ };
136
+ }
137
+ export async function runTasks(tasks, options) {
138
+ const results = [];
139
+ for (const task of tasks) {
140
+ results.push(await runTask(task, options));
141
+ }
142
+ return results;
143
+ }
144
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/evals/runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ export declare class TaskError extends Error {
2
+ constructor(message: string, options?: {
3
+ cause?: unknown;
4
+ });
5
+ }
6
+ /** Capabilities a task needs; the runner refuses to run without them. */
7
+ export type Capability = "writes" | "shell";
8
+ export interface GraderSpec {
9
+ readonly type: string;
10
+ readonly [key: string]: unknown;
11
+ }
12
+ export interface Task {
13
+ readonly name: string;
14
+ readonly prompt: string;
15
+ readonly capabilities: readonly Capability[];
16
+ readonly attempts: number;
17
+ readonly maxTurns: number;
18
+ readonly graders: readonly GraderSpec[];
19
+ /** Directory copied into a fresh workspace for every attempt. */
20
+ readonly fixtureDirectory: string;
21
+ readonly directory: string;
22
+ }
23
+ export declare function parseTask(value: unknown, directory: string, fixtureDirectory: string): Task;
24
+ export declare function loadTask(directory: string): Promise<Task>;
25
+ /** Every subdirectory holding a task.json, in name order. */
26
+ export declare function loadTasks(root: string): Promise<readonly Task[]>;
27
+ //# sourceMappingURL=task.d.ts.map