@ikarmic/forge-eval 0.0.0-stage → 4.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/LICENSE +21 -0
- package/README.md +95 -2
- package/dist/bin/forge-eval.d.ts +3 -0
- package/dist/bin/forge-eval.d.ts.map +1 -0
- package/dist/bin/forge-eval.js +138 -0
- package/dist/bin/forge-eval.js.map +1 -0
- package/dist/graders/behavior.d.ts +57 -0
- package/dist/graders/behavior.d.ts.map +1 -0
- package/dist/graders/behavior.js +154 -0
- package/dist/graders/behavior.js.map +1 -0
- package/dist/graders/content.d.ts +59 -0
- package/dist/graders/content.d.ts.map +1 -0
- package/dist/graders/content.js +135 -0
- package/dist/graders/content.js.map +1 -0
- package/dist/graders/fs.d.ts +24 -0
- package/dist/graders/fs.d.ts.map +1 -0
- package/dist/graders/fs.js +134 -0
- package/dist/graders/fs.js.map +1 -0
- package/dist/graders/index.d.ts +15 -0
- package/dist/graders/index.d.ts.map +1 -0
- package/dist/graders/index.js +19 -0
- package/dist/graders/index.js.map +1 -0
- package/dist/graders/metrics.d.ts +59 -0
- package/dist/graders/metrics.d.ts.map +1 -0
- package/dist/graders/metrics.js +70 -0
- package/dist/graders/metrics.js.map +1 -0
- package/dist/graders/schema.d.ts +87 -0
- package/dist/graders/schema.d.ts.map +1 -0
- package/dist/graders/schema.js +157 -0
- package/dist/graders/schema.js.map +1 -0
- package/dist/graders/shell.d.ts +36 -0
- package/dist/graders/shell.d.ts.map +1 -0
- package/dist/graders/shell.js +72 -0
- package/dist/graders/shell.js.map +1 -0
- package/dist/graders/text.d.ts +28 -0
- package/dist/graders/text.d.ts.map +1 -0
- package/dist/graders/text.js +70 -0
- package/dist/graders/text.js.map +1 -0
- package/dist/graders/types.d.ts +81 -0
- package/dist/graders/types.d.ts.map +1 -0
- package/dist/graders/types.js +2 -0
- package/dist/graders/types.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/report.d.ts +39 -0
- package/dist/report.d.ts.map +1 -0
- package/dist/report.js +120 -0
- package/dist/report.js.map +1 -0
- package/dist/runner.d.ts +59 -0
- package/dist/runner.d.ts.map +1 -0
- package/dist/runner.js +217 -0
- package/dist/runner.js.map +1 -0
- package/dist/tasks/edit.remove-section.d.ts +15 -0
- package/dist/tasks/edit.remove-section.d.ts.map +1 -0
- package/dist/tasks/edit.remove-section.js +31 -0
- package/dist/tasks/edit.remove-section.js.map +1 -0
- package/dist/tasks/edit.rename-symbol.d.ts +16 -0
- package/dist/tasks/edit.rename-symbol.d.ts.map +1 -0
- package/dist/tasks/edit.rename-symbol.js +34 -0
- package/dist/tasks/edit.rename-symbol.js.map +1 -0
- package/dist/tasks/edit.replace-greeting.d.ts +16 -0
- package/dist/tasks/edit.replace-greeting.d.ts.map +1 -0
- package/dist/tasks/edit.replace-greeting.js +29 -0
- package/dist/tasks/edit.replace-greeting.js.map +1 -0
- package/dist/tasks/edit.write-hello.d.ts +15 -0
- package/dist/tasks/edit.write-hello.d.ts.map +1 -0
- package/dist/tasks/edit.write-hello.js +22 -0
- package/dist/tasks/edit.write-hello.js.map +1 -0
- package/dist/tasks/index.d.ts +9 -0
- package/dist/tasks/index.d.ts.map +1 -0
- package/dist/tasks/index.js +37 -0
- package/dist/tasks/index.js.map +1 -0
- package/dist/tasks/memory.recall-relevant.d.ts +19 -0
- package/dist/tasks/memory.recall-relevant.d.ts.map +1 -0
- package/dist/tasks/memory.recall-relevant.js +36 -0
- package/dist/tasks/memory.recall-relevant.js.map +1 -0
- package/dist/tasks/multi.refactor-move.d.ts +16 -0
- package/dist/tasks/multi.refactor-move.d.ts.map +1 -0
- package/dist/tasks/multi.refactor-move.js +37 -0
- package/dist/tasks/multi.refactor-move.js.map +1 -0
- package/dist/tasks/multi.run-and-report.d.ts +16 -0
- package/dist/tasks/multi.run-and-report.d.ts.map +1 -0
- package/dist/tasks/multi.run-and-report.js +26 -0
- package/dist/tasks/multi.run-and-report.js.map +1 -0
- package/dist/tasks/multi.summarize.d.ts +16 -0
- package/dist/tasks/multi.summarize.d.ts.map +1 -0
- package/dist/tasks/multi.summarize.js +35 -0
- package/dist/tasks/multi.summarize.js.map +1 -0
- package/dist/tasks/read.list-files.d.ts +15 -0
- package/dist/tasks/read.list-files.d.ts.map +1 -0
- package/dist/tasks/read.list-files.js +28 -0
- package/dist/tasks/read.list-files.js.map +1 -0
- package/dist/tasks/read.package-version.d.ts +15 -0
- package/dist/tasks/read.package-version.d.ts.map +1 -0
- package/dist/tasks/read.package-version.js +25 -0
- package/dist/tasks/read.package-version.js.map +1 -0
- package/dist/tasks/read.search-todos.d.ts +16 -0
- package/dist/tasks/read.search-todos.d.ts.map +1 -0
- package/dist/tasks/read.search-todos.js +30 -0
- package/dist/tasks/read.search-todos.js.map +1 -0
- package/package.json +57 -3
package/dist/report.js
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/** Pretty-print a model identifier the same way the CLI does it. */
|
|
2
|
+
function modelLabel(model) {
|
|
3
|
+
return `${model.provider}/${model.model}`;
|
|
4
|
+
}
|
|
5
|
+
/** Render a human-friendly markdown table for a suite run. */
|
|
6
|
+
export function formatMarkdownReport(suite) {
|
|
7
|
+
const lines = [];
|
|
8
|
+
lines.push(`# Forge eval: ${modelLabel(suite.model)}`);
|
|
9
|
+
lines.push('');
|
|
10
|
+
lines.push(`Started: ${suite.startedAt}`);
|
|
11
|
+
lines.push(`Finished: ${suite.finishedAt}`);
|
|
12
|
+
lines.push('');
|
|
13
|
+
lines.push(`**${suite.summary.passed}/${suite.summary.total}** tasks passed ` +
|
|
14
|
+
`(${pct(suite.summary.passRate)}%) in ${(suite.summary.totalDurationMs / 1000).toFixed(1)}s.`);
|
|
15
|
+
if (suite.summary.totalCostUsd > 0) {
|
|
16
|
+
lines.push(`Total cost: $${suite.summary.totalCostUsd.toFixed(4)}`);
|
|
17
|
+
}
|
|
18
|
+
lines.push('');
|
|
19
|
+
// Per-task table.
|
|
20
|
+
lines.push('| # | Task | Category | Result | Duration | Graders |');
|
|
21
|
+
lines.push('|---|------|----------|--------|----------|---------|');
|
|
22
|
+
for (const [i, r] of suite.results.entries()) {
|
|
23
|
+
const idx = String(i + 1).padStart(2, ' ');
|
|
24
|
+
const result = r.error
|
|
25
|
+
? `error: ${truncate(r.error, 40)}`
|
|
26
|
+
: r.passed
|
|
27
|
+
? 'pass'
|
|
28
|
+
: `fail (${r.graderResults.filter((g) => !g.passed).length}/${r.graderResults.length})`;
|
|
29
|
+
const dur = `${(r.durationMs / 1000).toFixed(1)}s`;
|
|
30
|
+
const passedCount = r.graderResults.filter((g) => g.passed).length;
|
|
31
|
+
const graderStr = r.graderResults.length === 0 ? '-' : `${passedCount}/${r.graderResults.length}`;
|
|
32
|
+
lines.push(`| ${idx} | ${r.task.id} | ${r.task.category} | ${result} | ${dur} | ${graderStr} |`);
|
|
33
|
+
}
|
|
34
|
+
lines.push('');
|
|
35
|
+
// Failing-task detail blocks: only the ones worth reading.
|
|
36
|
+
for (const r of suite.results) {
|
|
37
|
+
if (r.passed && !r.error)
|
|
38
|
+
continue;
|
|
39
|
+
lines.push(`## ${r.task.id}: ${r.task.name}`);
|
|
40
|
+
if (r.error) {
|
|
41
|
+
lines.push('');
|
|
42
|
+
lines.push(`Run error: \`${r.error}\``);
|
|
43
|
+
lines.push('');
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
lines.push('');
|
|
47
|
+
lines.push(`Reason: \`${r.agentResult.reason}\` · iterations: ${r.agentResult.iterations}`);
|
|
48
|
+
lines.push('');
|
|
49
|
+
lines.push('Graders:');
|
|
50
|
+
lines.push('');
|
|
51
|
+
for (const [i, g] of r.graderResults.entries()) {
|
|
52
|
+
const mark = g.passed ? '✓' : '✗';
|
|
53
|
+
lines.push(`- ${mark} **[${i + 1}]** ${g.message}`);
|
|
54
|
+
if (!g.passed && g.details) {
|
|
55
|
+
for (const dl of g.details.split('\n'))
|
|
56
|
+
lines.push(` ${dl}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
lines.push('');
|
|
60
|
+
lines.push('<details><summary>Final text</summary>');
|
|
61
|
+
lines.push('');
|
|
62
|
+
lines.push('```');
|
|
63
|
+
lines.push(truncate(r.agentResult.finalText, 1200));
|
|
64
|
+
lines.push('```');
|
|
65
|
+
lines.push('</details>');
|
|
66
|
+
lines.push('');
|
|
67
|
+
}
|
|
68
|
+
return lines.join('\n');
|
|
69
|
+
}
|
|
70
|
+
/** Render a compact single-line summary for the terminal. */
|
|
71
|
+
export function formatTerminalSummary(suite) {
|
|
72
|
+
const s = suite.summary;
|
|
73
|
+
const lines = [
|
|
74
|
+
`forge-eval: ${s.passed}/${s.total} passed (${pct(s.passRate)}%) in ${(s.totalDurationMs / 1000).toFixed(1)}s`,
|
|
75
|
+
` model: ${modelLabel(suite.model)}`,
|
|
76
|
+
];
|
|
77
|
+
if (s.totalCostUsd > 0) {
|
|
78
|
+
lines.push(` cost: $${s.totalCostUsd.toFixed(4)}`);
|
|
79
|
+
}
|
|
80
|
+
for (const r of suite.results) {
|
|
81
|
+
const mark = r.passed ? '✓' : '✗';
|
|
82
|
+
const dur = `${(r.durationMs / 1000).toFixed(1)}s`.padStart(6, ' ');
|
|
83
|
+
lines.push(` ${mark} ${r.task.id.padEnd(34, ' ')} ${dur}`);
|
|
84
|
+
}
|
|
85
|
+
return lines.join('\n');
|
|
86
|
+
}
|
|
87
|
+
export function formatJsonReport(suite) {
|
|
88
|
+
return {
|
|
89
|
+
model: suite.model,
|
|
90
|
+
startedAt: suite.startedAt,
|
|
91
|
+
finishedAt: suite.finishedAt,
|
|
92
|
+
summary: suite.summary,
|
|
93
|
+
tasks: suite.results.map((r) => ({
|
|
94
|
+
id: r.task.id,
|
|
95
|
+
name: r.task.name,
|
|
96
|
+
category: r.task.category,
|
|
97
|
+
passed: r.passed,
|
|
98
|
+
durationMs: r.durationMs,
|
|
99
|
+
iterations: r.agentResult.iterations,
|
|
100
|
+
reason: r.agentResult.reason,
|
|
101
|
+
graderResults: r.graderResults,
|
|
102
|
+
toolInvocations: r.toolInvocations.map((t) => ({
|
|
103
|
+
name: t.name,
|
|
104
|
+
args: t.args,
|
|
105
|
+
isError: t.isError,
|
|
106
|
+
})),
|
|
107
|
+
finalText: r.agentResult.finalText,
|
|
108
|
+
...(r.error ? { error: r.error } : {}),
|
|
109
|
+
})),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function pct(rate) {
|
|
113
|
+
return (rate * 100).toFixed(0);
|
|
114
|
+
}
|
|
115
|
+
function truncate(s, max) {
|
|
116
|
+
if (s.length <= max)
|
|
117
|
+
return s;
|
|
118
|
+
return s.slice(0, max) + '…';
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"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"}
|
package/dist/runner.d.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { createLanguageModel } from '@ikarmic/forge-core';
|
|
2
|
+
import type { AgentEvent, AgentRunResult, LanguageModelFactory, ModelConfig } from '@ikarmic/forge-core';
|
|
3
|
+
import type { GraderResult, TaskDefinition, TaskInfo, ToolInvocation } from './graders/index.js';
|
|
4
|
+
/** What a single task run produced: passed to the report formatter. */
|
|
5
|
+
export interface TaskRunResult {
|
|
6
|
+
task: TaskInfo;
|
|
7
|
+
passed: boolean;
|
|
8
|
+
/** Per-grader results, in the order the task defined them. */
|
|
9
|
+
graderResults: GraderResult[];
|
|
10
|
+
/** The agent's raw run result (kept for the JSON report). */
|
|
11
|
+
agentResult: AgentRunResult;
|
|
12
|
+
/** Tool invocations the agent made (also embedded in grader context). */
|
|
13
|
+
toolInvocations: ToolInvocation[];
|
|
14
|
+
/** Total wall-clock time for setup + run + grading. */
|
|
15
|
+
durationMs: number;
|
|
16
|
+
/** The cwd the task ran in: useful for debugging a failing run. */
|
|
17
|
+
cwd: string;
|
|
18
|
+
/** Error message if the run itself blew up (vs. just one grader failing). */
|
|
19
|
+
error?: string;
|
|
20
|
+
}
|
|
21
|
+
/** What a whole batch run produced. */
|
|
22
|
+
export interface SuiteRunResult {
|
|
23
|
+
model: ModelConfig;
|
|
24
|
+
startedAt: string;
|
|
25
|
+
finishedAt: string;
|
|
26
|
+
/** One entry per task that ran (skipped tasks are not included). */
|
|
27
|
+
results: TaskRunResult[];
|
|
28
|
+
/** Summary numbers: precomputed so the CLI doesn't re-iterate. */
|
|
29
|
+
summary: {
|
|
30
|
+
total: number;
|
|
31
|
+
passed: number;
|
|
32
|
+
failed: number;
|
|
33
|
+
passRate: number;
|
|
34
|
+
totalDurationMs: number;
|
|
35
|
+
totalCostUsd: number;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/** Options for {@link runTask}. */
|
|
39
|
+
export interface RunTaskOptions {
|
|
40
|
+
/** Override the model factory (defaults to `createLanguageModel`). */
|
|
41
|
+
modelFactory?: LanguageModelFactory;
|
|
42
|
+
/** Override the per-task cwd (otherwise a fresh temp dir is created). */
|
|
43
|
+
cwd?: string;
|
|
44
|
+
/** Stream events for this run (used by the CLI to mirror to stdout). */
|
|
45
|
+
onEvent?: (event: AgentEvent) => void;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Run a single task end-to-end: create cwd, run setup, execute the agent,
|
|
49
|
+
* grade the result, return everything. Always cleans up the temp dir on
|
|
50
|
+
* exit (success or failure): the CLI uses the cwd only during the run.
|
|
51
|
+
*/
|
|
52
|
+
export declare function runTask(task: TaskDefinition, model: ModelConfig, options?: RunTaskOptions): Promise<TaskRunResult>;
|
|
53
|
+
/** Run every task in `tasks` (or the whole catalog if omitted) sequentially. */
|
|
54
|
+
export declare function runSuite(tasks: readonly TaskDefinition[], model: ModelConfig, options?: RunTaskOptions): Promise<SuiteRunResult>;
|
|
55
|
+
/** Resolve a ModelConfig using the same precedence as the CLI. */
|
|
56
|
+
export declare function resolveModel(override?: string): ModelConfig;
|
|
57
|
+
/** Re-export for the CLI to use directly. */
|
|
58
|
+
export { createLanguageModel };
|
|
59
|
+
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"AAIA,OAAO,EAAS,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,KAAK,EAEV,UAAU,EACV,cAAc,EACd,oBAAoB,EACpB,WAAW,EACZ,MAAM,qBAAqB,CAAC;AAE7B,OAAO,KAAK,EAEV,YAAY,EACZ,cAAc,EACd,QAAQ,EACR,cAAc,EACf,MAAM,oBAAoB,CAAC;AAE5B,uEAAuE;AACvE,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,8DAA8D;IAC9D,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B,6DAA6D;IAC7D,WAAW,EAAE,cAAc,CAAC;IAC5B,yEAAyE;IACzE,eAAe,EAAE,cAAc,EAAE,CAAC;IAClC,uDAAuD;IACvD,UAAU,EAAE,MAAM,CAAC;IACnB,mEAAmE;IACnE,GAAG,EAAE,MAAM,CAAC;IACZ,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,uCAAuC;AACvC,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,WAAW,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,oEAAoE;IACpE,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB,kEAAkE;IAClE,OAAO,EAAE;QACP,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,eAAe,EAAE,MAAM,CAAC;QACxB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;CACH;AAED,mCAAmC;AACnC,MAAM,WAAW,cAAc;IAC7B,sEAAsE;IACtE,YAAY,CAAC,EAAE,oBAAoB,CAAC;IACpC,yEAAyE;IACzE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,wEAAwE;IACxE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CACvC;AAED;;;;GAIG;AACH,wBAAsB,OAAO,CAC3B,IAAI,EAAE,cAAc,EACpB,KAAK,EAAE,WAAW,EAClB,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,aAAa,CAAC,CA8GxB;AAED,gFAAgF;AAChF,wBAAsB,QAAQ,CAC5B,KAAK,EAAE,SAAS,cAAc,EAAE,EAChC,KAAK,EAAE,WAAW,EAClB,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,cAAc,CAAC,CAgCzB;AAED,kEAAkE;AAClE,wBAAgB,YAAY,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,WAAW,CAW3D;AAED,6CAA6C;AAC7C,OAAO,EAAE,mBAAmB,EAAE,CAAC"}
|
package/dist/runner.js
ADDED
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { mkdtemp, rm } from 'node:fs/promises';
|
|
2
|
+
import { tmpdir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { Agent, createLanguageModel } from '@ikarmic/forge-core';
|
|
5
|
+
/**
|
|
6
|
+
* Run a single task end-to-end: create cwd, run setup, execute the agent,
|
|
7
|
+
* grade the result, return everything. Always cleans up the temp dir on
|
|
8
|
+
* exit (success or failure): the CLI uses the cwd only during the run.
|
|
9
|
+
*/
|
|
10
|
+
export async function runTask(task, model, options = {}) {
|
|
11
|
+
const start = Date.now();
|
|
12
|
+
const ownsCwd = options.cwd === undefined;
|
|
13
|
+
const cwd = options.cwd ?? (await mkdtemp(join(tmpdir(), `forge-eval-${task.id}-`)));
|
|
14
|
+
const toolInvocations = [];
|
|
15
|
+
const pendingCalls = new Map();
|
|
16
|
+
let agentResult;
|
|
17
|
+
let error;
|
|
18
|
+
let graderResults = [];
|
|
19
|
+
let passed = false;
|
|
20
|
+
// A memory task must not read the host's ~/.forge/MEMORY.md.
|
|
21
|
+
const prevGlobalMemory = process.env.FORGE_GLOBAL_MEMORY_DIR;
|
|
22
|
+
if (task.memory)
|
|
23
|
+
process.env.FORGE_GLOBAL_MEMORY_DIR = join(cwd, '.no-global-memory');
|
|
24
|
+
try {
|
|
25
|
+
// Setup the fixture files (if any).
|
|
26
|
+
if (task.setup) {
|
|
27
|
+
await task.setup(cwd);
|
|
28
|
+
}
|
|
29
|
+
// Build an Agent with everything disabled that would add noise: cost
|
|
30
|
+
// tracking (we sum it ourselves), memory (per-task temp dir makes
|
|
31
|
+
// persistent state confusing; a task can opt back in), cache (each task is unique).
|
|
32
|
+
const config = {
|
|
33
|
+
model,
|
|
34
|
+
cwd,
|
|
35
|
+
auto: true, // evals are autonomous: no interactive approval prompts
|
|
36
|
+
allowDestructive: true, // same reason
|
|
37
|
+
disableCost: true,
|
|
38
|
+
disableMemory: task.memory !== true,
|
|
39
|
+
disableCache: true,
|
|
40
|
+
...(options.modelFactory ? { modelFactory: options.modelFactory } : {}),
|
|
41
|
+
};
|
|
42
|
+
const agent = new Agent(config);
|
|
43
|
+
agentResult = await agent.run({
|
|
44
|
+
task: task.task,
|
|
45
|
+
onEvent: (event) => {
|
|
46
|
+
if (event.type === 'tool_call') {
|
|
47
|
+
pendingCalls.set(event.id, { name: event.name, args: event.args, result: undefined, isError: false });
|
|
48
|
+
}
|
|
49
|
+
else if (event.type === 'tool_result') {
|
|
50
|
+
const pending = pendingCalls.get(event.id);
|
|
51
|
+
if (pending) {
|
|
52
|
+
pending.result = event.result;
|
|
53
|
+
pending.isError = event.isError;
|
|
54
|
+
toolInvocations.push(pending);
|
|
55
|
+
pendingCalls.delete(event.id);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
options.onEvent?.(event);
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
// Run graders *before* cleaning up the temp dir so filesystem graders
|
|
62
|
+
// can inspect files the agent created.
|
|
63
|
+
const ctx = {
|
|
64
|
+
cwd,
|
|
65
|
+
task: taskInfo(task),
|
|
66
|
+
result: agentResult,
|
|
67
|
+
toolInvocations,
|
|
68
|
+
};
|
|
69
|
+
passed = true;
|
|
70
|
+
for (const grader of task.graders) {
|
|
71
|
+
try {
|
|
72
|
+
const r = await grader(ctx);
|
|
73
|
+
graderResults.push(r);
|
|
74
|
+
if (!r.passed)
|
|
75
|
+
passed = false;
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
79
|
+
graderResults.push({ passed: false, message: 'grader threw', details: message });
|
|
80
|
+
passed = false;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
error = err instanceof Error ? err.message : String(err);
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
if (task.memory) {
|
|
89
|
+
if (prevGlobalMemory === undefined)
|
|
90
|
+
delete process.env.FORGE_GLOBAL_MEMORY_DIR;
|
|
91
|
+
else
|
|
92
|
+
process.env.FORGE_GLOBAL_MEMORY_DIR = prevGlobalMemory;
|
|
93
|
+
}
|
|
94
|
+
if (ownsCwd) {
|
|
95
|
+
await rm(cwd, { recursive: true, force: true });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (error) {
|
|
99
|
+
return {
|
|
100
|
+
task: taskInfo(task),
|
|
101
|
+
passed: false,
|
|
102
|
+
graderResults,
|
|
103
|
+
agentResult: agentResult ?? emptyAgentResult(),
|
|
104
|
+
toolInvocations,
|
|
105
|
+
durationMs: Date.now() - start,
|
|
106
|
+
cwd,
|
|
107
|
+
error,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
return {
|
|
111
|
+
task: taskInfo(task),
|
|
112
|
+
passed,
|
|
113
|
+
graderResults,
|
|
114
|
+
agentResult,
|
|
115
|
+
toolInvocations,
|
|
116
|
+
durationMs: Date.now() - start,
|
|
117
|
+
cwd,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
/** Run every task in `tasks` (or the whole catalog if omitted) sequentially. */
|
|
121
|
+
export async function runSuite(tasks, model, options = {}) {
|
|
122
|
+
const startedAt = new Date().toISOString();
|
|
123
|
+
const results = [];
|
|
124
|
+
let totalCostUsd = 0;
|
|
125
|
+
for (const task of tasks) {
|
|
126
|
+
const result = await runTask(task, model, options);
|
|
127
|
+
results.push(result);
|
|
128
|
+
if (result.agentResult.costKnown) {
|
|
129
|
+
totalCostUsd += result.agentResult.costUsd;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const finishedAt = new Date().toISOString();
|
|
133
|
+
const passed = results.filter((r) => r.passed).length;
|
|
134
|
+
const failed = results.length - passed;
|
|
135
|
+
const totalDurationMs = results.reduce((sum, r) => sum + r.durationMs, 0);
|
|
136
|
+
return {
|
|
137
|
+
model,
|
|
138
|
+
startedAt,
|
|
139
|
+
finishedAt,
|
|
140
|
+
results,
|
|
141
|
+
summary: {
|
|
142
|
+
total: results.length,
|
|
143
|
+
passed,
|
|
144
|
+
failed,
|
|
145
|
+
passRate: results.length === 0 ? 0 : passed / results.length,
|
|
146
|
+
totalDurationMs,
|
|
147
|
+
totalCostUsd,
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
/** Resolve a ModelConfig using the same precedence as the CLI. */
|
|
152
|
+
export function resolveModel(override) {
|
|
153
|
+
if (override) {
|
|
154
|
+
const [provider, model] = override.split('/');
|
|
155
|
+
if (!provider || !model) {
|
|
156
|
+
throw new Error(`Invalid --model "${override}". Expected "<provider>/<model>" e.g. "anthropic/claude-3-5-haiku-latest".`);
|
|
157
|
+
}
|
|
158
|
+
return { provider: provider, model };
|
|
159
|
+
}
|
|
160
|
+
return createLanguageModelFallback();
|
|
161
|
+
}
|
|
162
|
+
/** Re-export for the CLI to use directly. */
|
|
163
|
+
export { createLanguageModel };
|
|
164
|
+
/**
|
|
165
|
+
* A tiny wrapper around `createLanguageModel` so we don't have to import the
|
|
166
|
+
* core types directly here. Keeps the runner decoupled from the provider
|
|
167
|
+
* implementation.
|
|
168
|
+
*/
|
|
169
|
+
function createLanguageModelFallback() {
|
|
170
|
+
// Same precedence as the CLI: env vars, then Ollama probe.
|
|
171
|
+
// We delegate to the core helper when available; fall back to a hard error.
|
|
172
|
+
const provider = process.env.FORGE_DEFAULT_PROVIDER;
|
|
173
|
+
if (provider === 'ollama') {
|
|
174
|
+
return { provider: 'ollama', model: process.env.FORGE_DEFAULT_MODEL ?? 'llama3.1' };
|
|
175
|
+
}
|
|
176
|
+
const envModel = process.env.FORGE_DEFAULT_MODEL;
|
|
177
|
+
if (envModel && envModel.includes('/')) {
|
|
178
|
+
const [p, m] = envModel.split('/');
|
|
179
|
+
if (!p || !m) {
|
|
180
|
+
throw new Error(`Invalid FORGE_DEFAULT_MODEL "${envModel}". Expected "<provider>/<model>".`);
|
|
181
|
+
}
|
|
182
|
+
return { provider: p, model: m };
|
|
183
|
+
}
|
|
184
|
+
// Try Anthropic, OpenAI, Google, OpenRouter in that order: same as core.
|
|
185
|
+
if (process.env.ANTHROPIC_API_KEY)
|
|
186
|
+
return { provider: 'anthropic', model: envModel ?? 'claude-3-5-sonnet-latest' };
|
|
187
|
+
if (process.env.OPENAI_API_KEY)
|
|
188
|
+
return { provider: 'openai', model: envModel ?? 'gpt-4o-mini' };
|
|
189
|
+
if (process.env.GOOGLE_GENERATIVE_AI_API_KEY)
|
|
190
|
+
return { provider: 'google', model: envModel ?? 'gemini-2.0-flash-exp' };
|
|
191
|
+
if (process.env.OPENROUTER_API_KEY)
|
|
192
|
+
return { provider: 'openrouter', model: envModel ?? 'anthropic/claude-3.5-haiku' };
|
|
193
|
+
throw new Error('No model resolved. Pass --model <provider>/<model> or set FORGE_DEFAULT_MODEL and a provider API key ' +
|
|
194
|
+
'(ANTHROPIC_API_KEY, OPENAI_API_KEY, GOOGLE_GENERATIVE_AI_API_KEY, OPENROUTER_API_KEY) or run `ollama serve`.');
|
|
195
|
+
}
|
|
196
|
+
function taskInfo(task) {
|
|
197
|
+
return {
|
|
198
|
+
id: task.id,
|
|
199
|
+
name: task.name,
|
|
200
|
+
category: task.category,
|
|
201
|
+
description: task.description,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
function emptyAgentResult() {
|
|
205
|
+
return {
|
|
206
|
+
finalText: '',
|
|
207
|
+
iterations: 0,
|
|
208
|
+
inputTokens: 0,
|
|
209
|
+
outputTokens: 0,
|
|
210
|
+
durationMs: 0,
|
|
211
|
+
reason: 'error',
|
|
212
|
+
costUsd: 0,
|
|
213
|
+
costKnown: false,
|
|
214
|
+
messages: [],
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
//# sourceMappingURL=runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../src/runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* edit / remove-section: two-step task: identify a section by name, then
|
|
3
|
+
* remove it. Verifies the model handles multiple edits coherently.
|
|
4
|
+
*/
|
|
5
|
+
declare const _default: {
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
category: "edit";
|
|
9
|
+
description: string;
|
|
10
|
+
task: string;
|
|
11
|
+
setup: (cwd: string) => Promise<void>;
|
|
12
|
+
graders: import("../index.js").Grader[];
|
|
13
|
+
};
|
|
14
|
+
export default _default;
|
|
15
|
+
//# sourceMappingURL=edit.remove-section.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit.remove-section.d.ts","sourceRoot":"","sources":["../../src/tasks/edit.remove-section.ts"],"names":[],"mappings":"AAKA;;;GAGG;;;;;;;;;;AACH,wBA8BG"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { defineTask, fileMatches, fileMissing, toolWasCalled, completed } from '../graders/index.js';
|
|
4
|
+
/**
|
|
5
|
+
* edit / remove-section: two-step task: identify a section by name, then
|
|
6
|
+
* remove it. Verifies the model handles multiple edits coherently.
|
|
7
|
+
*/
|
|
8
|
+
export default defineTask({
|
|
9
|
+
id: 'edit-remove-section',
|
|
10
|
+
name: 'Remove a section from config.json',
|
|
11
|
+
category: 'edit',
|
|
12
|
+
description: 'Agent removes a named section from a JSON config file.',
|
|
13
|
+
task: 'The file `config.json` exists in the current directory. It has two top-level ' +
|
|
14
|
+
'keys: `keep` and `stale`. Remove the entire `stale` key (and its value) using ' +
|
|
15
|
+
'edit_file. Keep `keep` untouched. Then verify the file is still valid JSON.',
|
|
16
|
+
setup: async (cwd) => {
|
|
17
|
+
await mkdir(cwd, { recursive: true });
|
|
18
|
+
await writeFile(join(cwd, 'config.json'), JSON.stringify({ keep: { value: 42 }, stale: { value: 'old', note: 'remove me' } }, null, 2));
|
|
19
|
+
},
|
|
20
|
+
graders: [
|
|
21
|
+
completed(),
|
|
22
|
+
toolWasCalled('edit_file'),
|
|
23
|
+
fileMatches('config.json', '"value": 42'),
|
|
24
|
+
fileMatches('config.json', 'keep'),
|
|
25
|
+
// The `stale` key should be gone: we check that the substring "stale"
|
|
26
|
+
// (which only appears inside the key) is absent.
|
|
27
|
+
fileMatches('config.json', { equals: JSON.stringify({ keep: { value: 42 } }, null, 2) }),
|
|
28
|
+
fileMissing('stale-backup.json'),
|
|
29
|
+
],
|
|
30
|
+
});
|
|
31
|
+
//# sourceMappingURL=edit.remove-section.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit.remove-section.js","sourceRoot":"","sources":["../../src/tasks/edit.remove-section.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAErG;;;GAGG;AACH,eAAe,UAAU,CAAC;IACxB,EAAE,EAAE,qBAAqB;IACzB,IAAI,EAAE,mCAAmC;IACzC,QAAQ,EAAE,MAAM;IAChB,WAAW,EAAE,wDAAwD;IACrE,IAAI,EACF,+EAA+E;QAC/E,gFAAgF;QAChF,6EAA6E;IAC/E,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QACnB,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtC,MAAM,SAAS,CACb,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,EACxB,IAAI,CAAC,SAAS,CACZ,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,EACnE,IAAI,EACJ,CAAC,CACF,CACF,CAAC;IACJ,CAAC;IACD,OAAO,EAAE;QACP,SAAS,EAAE;QACX,aAAa,CAAC,WAAW,CAAC;QAC1B,WAAW,CAAC,aAAa,EAAE,aAAa,CAAC;QACzC,WAAW,CAAC,aAAa,EAAE,MAAM,CAAC;QAClC,sEAAsE;QACtE,iDAAiD;QACjD,WAAW,CAAC,aAAa,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;QACxF,WAAW,CAAC,mBAAmB,CAAC;KACjC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* edit / rename-symbol: multi-file rename. Agent must find files containing
|
|
3
|
+
* the symbol `foo` and rename it to `bar` consistently. This is a real-world
|
|
4
|
+
* refactor that touches multiple files and demands care.
|
|
5
|
+
*/
|
|
6
|
+
declare const _default: {
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
category: "edit";
|
|
10
|
+
description: string;
|
|
11
|
+
task: string;
|
|
12
|
+
setup: (cwd: string) => Promise<void>;
|
|
13
|
+
graders: import("../index.js").Grader[];
|
|
14
|
+
};
|
|
15
|
+
export default _default;
|
|
16
|
+
//# sourceMappingURL=edit.rename-symbol.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit.rename-symbol.d.ts","sourceRoot":"","sources":["../../src/tasks/edit.rename-symbol.ts"],"names":[],"mappings":"AAKA;;;;GAIG;;;;;;;;;;AACH,wBAyBG"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { defineTask, fileMatches, toolWasCalled, completed } from '../graders/index.js';
|
|
4
|
+
/**
|
|
5
|
+
* edit / rename-symbol: multi-file rename. Agent must find files containing
|
|
6
|
+
* the symbol `foo` and rename it to `bar` consistently. This is a real-world
|
|
7
|
+
* refactor that touches multiple files and demands care.
|
|
8
|
+
*/
|
|
9
|
+
export default defineTask({
|
|
10
|
+
id: 'edit-rename-symbol',
|
|
11
|
+
name: 'Rename symbol foo -> bar',
|
|
12
|
+
category: 'edit',
|
|
13
|
+
description: 'Agent renames a symbol across multiple files.',
|
|
14
|
+
task: 'Search the current directory for files that contain the JavaScript variable ' +
|
|
15
|
+
'name `foo`. Rename every occurrence to `bar` in each file using edit_file. ' +
|
|
16
|
+
'Do not change any other words. Leave any file that does not contain `foo` ' +
|
|
17
|
+
'untouched.',
|
|
18
|
+
setup: async (cwd) => {
|
|
19
|
+
await mkdir(cwd, { recursive: true });
|
|
20
|
+
await writeFile(join(cwd, 'a.ts'), 'export const foo = 1;\nexport function useFoo() { return foo; }\n');
|
|
21
|
+
await writeFile(join(cwd, 'b.ts'), 'import { foo } from "./a";\nexport const doubled = foo * 2;\n');
|
|
22
|
+
await writeFile(join(cwd, 'c.ts'), '// no relevant symbols here\nexport const baz = 9;\n');
|
|
23
|
+
},
|
|
24
|
+
graders: [
|
|
25
|
+
completed(),
|
|
26
|
+
toolWasCalled('search_files'),
|
|
27
|
+
toolWasCalled('edit_file'),
|
|
28
|
+
fileMatches('a.ts', 'bar'),
|
|
29
|
+
fileMatches('b.ts', 'bar'),
|
|
30
|
+
// c.ts didn't have foo, must be untouched.
|
|
31
|
+
fileMatches('c.ts', 'baz'),
|
|
32
|
+
],
|
|
33
|
+
});
|
|
34
|
+
//# sourceMappingURL=edit.rename-symbol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit.rename-symbol.js","sourceRoot":"","sources":["../../src/tasks/edit.rename-symbol.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAExF;;;;GAIG;AACH,eAAe,UAAU,CAAC;IACxB,EAAE,EAAE,oBAAoB;IACxB,IAAI,EAAE,0BAA0B;IAChC,QAAQ,EAAE,MAAM;IAChB,WAAW,EAAE,+CAA+C;IAC5D,IAAI,EACF,8EAA8E;QAC9E,6EAA6E;QAC7E,4EAA4E;QAC5E,YAAY;IACd,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QACnB,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtC,MAAM,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,mEAAmE,CAAC,CAAC;QACxG,MAAM,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,+DAA+D,CAAC,CAAC;QACpG,MAAM,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,sDAAsD,CAAC,CAAC;IAC7F,CAAC;IACD,OAAO,EAAE;QACP,SAAS,EAAE;QACX,aAAa,CAAC,cAAc,CAAC;QAC7B,aAAa,CAAC,WAAW,CAAC;QAC1B,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC;QAC1B,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC;QAC1B,2CAA2C;QAC3C,WAAW,CAAC,MAAM,EAAE,KAAK,CAAC;KAC3B;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* edit / replace-greeting: agent modifies an existing file in place.
|
|
3
|
+
* Verifies the model uses edit_file (precise replacement) rather than
|
|
4
|
+
* rewriting the whole file with write_file.
|
|
5
|
+
*/
|
|
6
|
+
declare const _default: {
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
category: "edit";
|
|
10
|
+
description: string;
|
|
11
|
+
task: string;
|
|
12
|
+
setup: (cwd: string) => Promise<void>;
|
|
13
|
+
graders: import("../index.js").Grader[];
|
|
14
|
+
};
|
|
15
|
+
export default _default;
|
|
16
|
+
//# sourceMappingURL=edit.replace-greeting.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit.replace-greeting.d.ts","sourceRoot":"","sources":["../../src/tasks/edit.replace-greeting.ts"],"names":[],"mappings":"AAKA;;;;GAIG;;;;;;;;;;AACH,wBAoBG"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { defineTask, fileMatches, toolWasCalled, completed } from '../graders/index.js';
|
|
4
|
+
/**
|
|
5
|
+
* edit / replace-greeting: agent modifies an existing file in place.
|
|
6
|
+
* Verifies the model uses edit_file (precise replacement) rather than
|
|
7
|
+
* rewriting the whole file with write_file.
|
|
8
|
+
*/
|
|
9
|
+
export default defineTask({
|
|
10
|
+
id: 'edit-replace-greeting',
|
|
11
|
+
name: 'Replace greeting in file',
|
|
12
|
+
category: 'edit',
|
|
13
|
+
description: 'Agent edits greeting.txt to swap the greeting word.',
|
|
14
|
+
task: 'The file `greeting.txt` exists in the current directory and contains the word ' +
|
|
15
|
+
'"Hello". Change just that one word to "Bonjour" using the edit_file tool: do ' +
|
|
16
|
+
'not rewrite the whole file.',
|
|
17
|
+
setup: async (cwd) => {
|
|
18
|
+
await mkdir(cwd, { recursive: true });
|
|
19
|
+
await writeFile(join(cwd, 'greeting.txt'), 'Hello, world!\nA second line.\n');
|
|
20
|
+
},
|
|
21
|
+
graders: [
|
|
22
|
+
completed(),
|
|
23
|
+
toolWasCalled('edit_file'),
|
|
24
|
+
fileMatches('greeting.txt', 'Bonjour'),
|
|
25
|
+
// Make sure the model didn't nuke the rest of the file.
|
|
26
|
+
fileMatches('greeting.txt', 'A second line.'),
|
|
27
|
+
],
|
|
28
|
+
});
|
|
29
|
+
//# sourceMappingURL=edit.replace-greeting.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit.replace-greeting.js","sourceRoot":"","sources":["../../src/tasks/edit.replace-greeting.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAExF;;;;GAIG;AACH,eAAe,UAAU,CAAC;IACxB,EAAE,EAAE,uBAAuB;IAC3B,IAAI,EAAE,0BAA0B;IAChC,QAAQ,EAAE,MAAM;IAChB,WAAW,EAAE,qDAAqD;IAClE,IAAI,EACF,gFAAgF;QAChF,+EAA+E;QAC/E,6BAA6B;IAC/B,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;QACnB,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtC,MAAM,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,EAAE,iCAAiC,CAAC,CAAC;IAChF,CAAC;IACD,OAAO,EAAE;QACP,SAAS,EAAE;QACX,aAAa,CAAC,WAAW,CAAC;QAC1B,WAAW,CAAC,cAAc,EAAE,SAAS,CAAC;QACtC,wDAAwD;QACxD,WAAW,CAAC,cAAc,EAAE,gBAAgB,CAAC;KAC9C;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* edit / write-hello: agent creates a fresh file with specific content.
|
|
3
|
+
* Verifies the model uses write_file (not edit_file on a non-existent file).
|
|
4
|
+
*/
|
|
5
|
+
declare const _default: {
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
category: "edit";
|
|
9
|
+
description: string;
|
|
10
|
+
task: string;
|
|
11
|
+
setup: () => Promise<void>;
|
|
12
|
+
graders: import("../index.js").Grader[];
|
|
13
|
+
};
|
|
14
|
+
export default _default;
|
|
15
|
+
//# sourceMappingURL=edit.write-hello.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit.write-hello.d.ts","sourceRoot":"","sources":["../../src/tasks/edit.write-hello.ts"],"names":[],"mappings":"AAEA;;;GAGG;;;;;;;;;;AACH,wBAgBG"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { defineTask, fileMatches, toolWasCalled, completed } from '../graders/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* edit / write-hello: agent creates a fresh file with specific content.
|
|
4
|
+
* Verifies the model uses write_file (not edit_file on a non-existent file).
|
|
5
|
+
*/
|
|
6
|
+
export default defineTask({
|
|
7
|
+
id: 'edit-write-hello',
|
|
8
|
+
name: 'Write hello.txt',
|
|
9
|
+
category: 'edit',
|
|
10
|
+
description: 'Agent creates hello.txt with a specific greeting.',
|
|
11
|
+
task: 'Create a new file called `hello.txt` in the current directory whose entire ' +
|
|
12
|
+
'contents are exactly the text: `Hello, Forge!` (one line, no trailing newline needed).',
|
|
13
|
+
setup: async () => {
|
|
14
|
+
// No fixtures: fresh dir.
|
|
15
|
+
},
|
|
16
|
+
graders: [
|
|
17
|
+
completed(),
|
|
18
|
+
toolWasCalled('write_file'),
|
|
19
|
+
fileMatches('hello.txt', { equals: 'Hello, Forge!' }),
|
|
20
|
+
],
|
|
21
|
+
});
|
|
22
|
+
//# sourceMappingURL=edit.write-hello.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"edit.write-hello.js","sourceRoot":"","sources":["../../src/tasks/edit.write-hello.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAExF;;;GAGG;AACH,eAAe,UAAU,CAAC;IACxB,EAAE,EAAE,kBAAkB;IACtB,IAAI,EAAE,iBAAiB;IACvB,QAAQ,EAAE,MAAM;IAChB,WAAW,EAAE,mDAAmD;IAChE,IAAI,EACF,6EAA6E;QAC7E,wFAAwF;IAC1F,KAAK,EAAE,KAAK,IAAI,EAAE;QAChB,0BAA0B;IAC5B,CAAC;IACD,OAAO,EAAE;QACP,SAAS,EAAE;QACX,aAAa,CAAC,YAAY,CAAC;QAC3B,WAAW,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;KACtD;CACF,CAAC,CAAC"}
|