@gaunt-sloth/batch 2.0.0-alpha.19 → 2.0.0-alpha.21
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 +140 -0
- package/dist/bin.d.ts +13 -0
- package/dist/bin.js +28 -0
- package/dist/bin.js.map +1 -0
- package/dist/deterministicChecks.d.ts +39 -7
- package/dist/deterministicChecks.js +120 -11
- package/dist/deterministicChecks.js.map +1 -1
- package/dist/evalOutput.d.ts +17 -4
- package/dist/evalOutput.js +40 -5
- package/dist/evalOutput.js.map +1 -1
- package/dist/evalRunner.d.ts +68 -15
- package/dist/evalRunner.js +309 -55
- package/dist/evalRunner.js.map +1 -1
- package/dist/evalSuite.d.ts +32 -11
- package/dist/evalSuite.js +487 -42
- package/dist/evalSuite.js.map +1 -1
- package/dist/evalTypes.d.ts +187 -15
- package/dist/index.d.ts +5 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/pipelineCli.d.ts +102 -0
- package/dist/pipelineCli.js +348 -0
- package/dist/pipelineCli.js.map +1 -0
- package/dist/reporters/drive.d.ts +14 -0
- package/dist/reporters/drive.js +49 -0
- package/dist/reporters/drive.js.map +1 -0
- package/dist/reporters/registry.d.ts +11 -0
- package/dist/reporters/registry.js +26 -0
- package/dist/reporters/registry.js.map +1 -0
- package/dist/reporters/reporterTypes.d.ts +36 -0
- package/dist/reporters/reporterTypes.js +2 -0
- package/dist/reporters/reporterTypes.js.map +1 -0
- package/dist/reporters/textReporter.d.ts +10 -0
- package/dist/reporters/textReporter.js +50 -0
- package/dist/reporters/textReporter.js.map +1 -0
- package/dist/toolChecks.d.ts +21 -0
- package/dist/toolChecks.js +38 -0
- package/dist/toolChecks.js.map +1 -0
- package/package.json +6 -3
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module pipelineCli
|
|
3
|
+
*
|
|
4
|
+
* BATCH-9 — the standalone `gth-batch` pipeline runner. A thin entry point that runs the BATCH-1
|
|
5
|
+
* matrix runtime ({@link buildMatrix} + {@link runBatchMatrix}) directly from a shell pipeline,
|
|
6
|
+
* without pulling in the whole `gaunt-sloth` app. It takes a prompt-executable script + `--over`
|
|
7
|
+
* data (inline JSON/YAML, or piped on stdin), runs the matrix, and streams the **same structured
|
|
8
|
+
* per-cell `CellResult`** that `gth batch` writes — one JSON object per line (JSONL) on stdout.
|
|
9
|
+
*
|
|
10
|
+
* Relationship to `gth batch` (packages/app/src/commands/batchCommand.ts): the two share the exact
|
|
11
|
+
* matrix runtime and the exact per-cell run wiring. The production per-cell adapter
|
|
12
|
+
* (`buildProductionRunCell`) lives in the app; this file mirrors it — its own `createResolvers()`,
|
|
13
|
+
* a lean agent factory, `runSingleShot` in `exec` mode, and `cleanupTools()` on every path — so the
|
|
14
|
+
* standalone bin needs only `@gaunt-sloth/core` + `@gaunt-sloth/agent` (both already dependencies),
|
|
15
|
+
* never the app. The only intentional differences: over-data is inline/stdin (not a file path, which
|
|
16
|
+
* the pipeline shell already handles) and output is JSONL on stdout (not a directory of files).
|
|
17
|
+
*
|
|
18
|
+
* stdout discipline: the run itself is noisy (the runtime's `display()`/`ProgressIndicator`/token
|
|
19
|
+
* streaming all target `process.stdout`). The bin entry ({@link file://./bin.ts}) redirects
|
|
20
|
+
* `process.stdout.write` to stderr for the duration and this module writes the machine JSONL
|
|
21
|
+
* straight to fd 1 (`fs.writeSync`), so stdout stays a clean data channel — the same "protocol
|
|
22
|
+
* channel" discipline `packages/app/cli.js` uses for ACP.
|
|
23
|
+
*/
|
|
24
|
+
import { writeSync } from 'node:fs';
|
|
25
|
+
import { readFileSync } from 'node:fs';
|
|
26
|
+
import { resolve } from 'node:path';
|
|
27
|
+
import { parse as parseYaml } from 'yaml';
|
|
28
|
+
import { initConfig as realInitConfig } from '@gaunt-sloth/core/config.js';
|
|
29
|
+
import { buildSystemMessages, readExecPrompt, wrapContent, } from '@gaunt-sloth/core/utils/llmUtils.js';
|
|
30
|
+
import { displayWarning } from '@gaunt-sloth/core/utils/consoleUtils.js';
|
|
31
|
+
import { buildMatrix } from '#src/matrix.js';
|
|
32
|
+
import { buildBatchSummary, runBatchMatrix } from '#src/BatchRunner.js';
|
|
33
|
+
const USAGE = 'Usage: gth-batch <script> [--over <json|yaml>] [--models a,b,c] [-j <n>] [--retry <n>]\n' +
|
|
34
|
+
' <script> path to the .md prompt-executable to run over the matrix\n' +
|
|
35
|
+
' --over <data> inline JSON/YAML array of row objects (or pipe it on stdin)\n' +
|
|
36
|
+
' --models a,b,c comma-separated model axis (omit to use the configured model)\n' +
|
|
37
|
+
' -j, --concurrency <n> max in-flight cells\n' +
|
|
38
|
+
' --retry <n> retry a failed cell up to n times (default 0)';
|
|
39
|
+
/** Parse `--models a,b,c` into a trimmed, non-empty list; `undefined` when empty/absent. */
|
|
40
|
+
export function parseModels(models) {
|
|
41
|
+
const list = models
|
|
42
|
+
.split(',')
|
|
43
|
+
.map((m) => m.trim())
|
|
44
|
+
.filter((m) => m.length > 0);
|
|
45
|
+
return list.length > 0 ? list : undefined;
|
|
46
|
+
}
|
|
47
|
+
function parseIntArg(raw, flag) {
|
|
48
|
+
const n = Number.parseInt(raw, 10);
|
|
49
|
+
if (!Number.isFinite(n)) {
|
|
50
|
+
throw new Error(`${flag} expects an integer, got "${raw}"`);
|
|
51
|
+
}
|
|
52
|
+
return n;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Parse `gth-batch`'s argv (already sliced past `node <script>`). Pure and dependency-free so the
|
|
56
|
+
* arg surface is trivially unit-testable. Supports `--flag value` and `--flag=value`; throws a
|
|
57
|
+
* clear `Error` (with usage) on an unknown option, a missing value, or a missing `<script>`.
|
|
58
|
+
*/
|
|
59
|
+
export function parseArgs(argv) {
|
|
60
|
+
let script;
|
|
61
|
+
let over;
|
|
62
|
+
let models;
|
|
63
|
+
let concurrency;
|
|
64
|
+
let retry;
|
|
65
|
+
for (let i = 0; i < argv.length; i++) {
|
|
66
|
+
const arg = argv[i];
|
|
67
|
+
// Normalize `--flag=value` into a name + inline value.
|
|
68
|
+
let name = arg;
|
|
69
|
+
let inlineValue;
|
|
70
|
+
if (arg.startsWith('--') && arg.includes('=')) {
|
|
71
|
+
const eq = arg.indexOf('=');
|
|
72
|
+
name = arg.slice(0, eq);
|
|
73
|
+
inlineValue = arg.slice(eq + 1);
|
|
74
|
+
}
|
|
75
|
+
const takeValue = () => {
|
|
76
|
+
if (inlineValue !== undefined)
|
|
77
|
+
return inlineValue;
|
|
78
|
+
const v = argv[++i];
|
|
79
|
+
if (v === undefined)
|
|
80
|
+
throw new Error(`Missing value for ${name}\n\n${USAGE}`);
|
|
81
|
+
return v;
|
|
82
|
+
};
|
|
83
|
+
if (name === '--over') {
|
|
84
|
+
over = takeValue();
|
|
85
|
+
}
|
|
86
|
+
else if (name === '--models') {
|
|
87
|
+
models = parseModels(takeValue());
|
|
88
|
+
}
|
|
89
|
+
else if (name === '-j' || name === '--concurrency') {
|
|
90
|
+
concurrency = parseIntArg(takeValue(), name);
|
|
91
|
+
}
|
|
92
|
+
else if (name === '--retry') {
|
|
93
|
+
retry = parseIntArg(takeValue(), name);
|
|
94
|
+
}
|
|
95
|
+
else if (name === '-h' || name === '--help') {
|
|
96
|
+
throw new Error(USAGE);
|
|
97
|
+
}
|
|
98
|
+
else if (name.startsWith('-')) {
|
|
99
|
+
throw new Error(`Unknown option: ${arg}\n\n${USAGE}`);
|
|
100
|
+
}
|
|
101
|
+
else if (script === undefined) {
|
|
102
|
+
script = arg;
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
throw new Error(`Unexpected extra argument: ${arg}\n\n${USAGE}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (script === undefined) {
|
|
109
|
+
throw new Error(`Missing required <script> argument.\n\n${USAGE}`);
|
|
110
|
+
}
|
|
111
|
+
return { script, over, models, concurrency, retry };
|
|
112
|
+
}
|
|
113
|
+
/** Coerce a parsed row object's values to strings, mirroring `parseOver.ts`'s CSV/JSONL semantics
|
|
114
|
+
* (every field becomes a string that `{{field}}` interpolation binds). */
|
|
115
|
+
function stringifyRowValues(record) {
|
|
116
|
+
const row = {};
|
|
117
|
+
for (const [key, value] of Object.entries(record)) {
|
|
118
|
+
row[key] = typeof value === 'string' ? value : JSON.stringify(value);
|
|
119
|
+
}
|
|
120
|
+
return row;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Parse inline/stdin `--over` data — a JSON or YAML **array of row objects** — into
|
|
124
|
+
* {@link MatrixRow}s. (The app's `parseOverFile` picks CSV vs JSONL by file extension; a shell
|
|
125
|
+
* pipeline has no filename, so this bin standardizes on one self-describing format: JSON, which is
|
|
126
|
+
* also valid YAML.) Throws a descriptive `Error` on malformed input — the one thing that should
|
|
127
|
+
* make the bin exit non-zero.
|
|
128
|
+
*/
|
|
129
|
+
export function parseOverData(text) {
|
|
130
|
+
let parsed;
|
|
131
|
+
try {
|
|
132
|
+
parsed = parseYaml(text);
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
throw new Error(`--over data is not valid JSON/YAML: ${error instanceof Error ? error.message : String(error)}`);
|
|
136
|
+
}
|
|
137
|
+
if (!Array.isArray(parsed)) {
|
|
138
|
+
throw new Error('--over data must be a JSON/YAML array of row objects');
|
|
139
|
+
}
|
|
140
|
+
if (parsed.length === 0) {
|
|
141
|
+
throw new Error('--over data is an empty array (no rows)');
|
|
142
|
+
}
|
|
143
|
+
return parsed.map((row, i) => {
|
|
144
|
+
if (row === null || typeof row !== 'object' || Array.isArray(row)) {
|
|
145
|
+
throw new Error(`--over row ${i} must be an object, got ${JSON.stringify(row)}`);
|
|
146
|
+
}
|
|
147
|
+
return stringifyRowValues(row);
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Resolve the input axis: inline `--over` if present, otherwise piped stdin, otherwise `undefined`
|
|
152
|
+
* (no input axis → a single cell over the script's own content, exactly like `exec`).
|
|
153
|
+
*/
|
|
154
|
+
export async function resolveRows(args, readStdin) {
|
|
155
|
+
if (args.over !== undefined) {
|
|
156
|
+
return parseOverData(args.over);
|
|
157
|
+
}
|
|
158
|
+
const piped = (await readStdin()).trim();
|
|
159
|
+
if (piped.length > 0) {
|
|
160
|
+
return parseOverData(piped);
|
|
161
|
+
}
|
|
162
|
+
return undefined;
|
|
163
|
+
}
|
|
164
|
+
/** Build the exec-mode system preamble the same way `gth batch` does (app's `getExecSystemPrompt`),
|
|
165
|
+
* flattened to a string, using only `@gaunt-sloth/core` prompt builders. */
|
|
166
|
+
export function getExecPreamble(config) {
|
|
167
|
+
const [systemMessage] = buildSystemMessages(config, readExecPrompt(config));
|
|
168
|
+
const content = systemMessage?.content;
|
|
169
|
+
if (typeof content === 'string') {
|
|
170
|
+
return content;
|
|
171
|
+
}
|
|
172
|
+
if (Array.isArray(content)) {
|
|
173
|
+
return content
|
|
174
|
+
.map((item) => (typeof item === 'string' ? item : 'text' in item ? item.text : ''))
|
|
175
|
+
.join('\n');
|
|
176
|
+
}
|
|
177
|
+
return '';
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Build a per-`model` {@link GthConfig} cache — the same idiom as `createCellConfigResolver`
|
|
181
|
+
* (batchCommand.ts) / `createModelConfigResolver` (runWorkflow.ts): `undefined` model → the base
|
|
182
|
+
* config; a named model → one cached `initConfig({ ...overrides, model })` call (cached by Promise
|
|
183
|
+
* so concurrent cells for the same not-yet-resolved model share one in-flight build).
|
|
184
|
+
*/
|
|
185
|
+
function createModelConfigResolver(baseConfig, overrides, initConfig) {
|
|
186
|
+
const configForModel = new Map();
|
|
187
|
+
return (model) => {
|
|
188
|
+
if (!model)
|
|
189
|
+
return Promise.resolve(baseConfig);
|
|
190
|
+
let cached = configForModel.get(model);
|
|
191
|
+
if (!cached) {
|
|
192
|
+
cached = initConfig({ ...overrides, model });
|
|
193
|
+
configForModel.set(model, cached);
|
|
194
|
+
}
|
|
195
|
+
return cached;
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* The production per-cell adapter, mirroring `buildProductionRunCell` (batchCommand.ts) exactly:
|
|
200
|
+
* a fresh `createResolvers()` per cell, a lean agent factory, `runSingleShot` in `exec` mode, and
|
|
201
|
+
* `cleanupTools()` on every path. Kept here (not imported from the app) so the standalone bin
|
|
202
|
+
* depends only on core + agent.
|
|
203
|
+
*/
|
|
204
|
+
async function buildProductionRunCell(baseConfig, preamble, overrides, initConfig) {
|
|
205
|
+
const { runSingleShot } = await import('@gaunt-sloth/core/runtime/singleShot.js');
|
|
206
|
+
const { createResolvers } = await import('@gaunt-sloth/agent/resolvers.js');
|
|
207
|
+
const { resolveAgentFactory } = await import('@gaunt-sloth/agent/core/resolveAgentFactory.js');
|
|
208
|
+
const resolveCellModelConfig = createModelConfigResolver(baseConfig, overrides, initConfig);
|
|
209
|
+
return async (cell) => {
|
|
210
|
+
const modelConfig = await resolveCellModelConfig(cell.model);
|
|
211
|
+
const cellConfig = {
|
|
212
|
+
...modelConfig,
|
|
213
|
+
canInterruptInferenceWithEsc: false,
|
|
214
|
+
writeOutputToFile: false,
|
|
215
|
+
// Non-interactive pipeline: don't stream tokens to the (redirected) stdout; the answer is
|
|
216
|
+
// captured in the cell's JSON record instead.
|
|
217
|
+
streamOutput: false,
|
|
218
|
+
};
|
|
219
|
+
const content = wrapContent(cell.content, 'script', 'prompt-executable script', true);
|
|
220
|
+
const resolvers = createResolvers();
|
|
221
|
+
try {
|
|
222
|
+
const { ok, answer, tokensInput, tokensOutput, tools } = await runSingleShot(`BATCH-${cell.id}`, preamble, content, cellConfig, resolvers, 'exec', resolveAgentFactory(cellConfig, 'lean'));
|
|
223
|
+
return { ok, answer, tokensInput, tokensOutput, tools };
|
|
224
|
+
}
|
|
225
|
+
catch (error) {
|
|
226
|
+
// runSingleShot is documented to not throw for a normal LLM/tool failure; this guards the
|
|
227
|
+
// rare genuinely-unexpected exception so one bad cell never takes the whole batch down.
|
|
228
|
+
return { ok: false, error: error instanceof Error ? error.message : String(error) };
|
|
229
|
+
}
|
|
230
|
+
finally {
|
|
231
|
+
try {
|
|
232
|
+
await resolvers.cleanupTools?.();
|
|
233
|
+
}
|
|
234
|
+
catch (cleanupError) {
|
|
235
|
+
displayWarning(`Failed to clean up tools for cell ${cell.id}: ` +
|
|
236
|
+
`${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Run the matrix and stream one JSON `CellResult` per line (JSONL) to `write`. Returns the
|
|
243
|
+
* aggregate {@link BatchSummary}. Each emitted line is the exact object `gth batch` writes to
|
|
244
|
+
* `<id>.json` (compact rather than pretty-printed) — the "same structured per-cell output".
|
|
245
|
+
*/
|
|
246
|
+
export async function runMatrixToStream(scriptContent, models, rows, options) {
|
|
247
|
+
const cells = buildMatrix(scriptContent, models, rows);
|
|
248
|
+
const results = await runBatchMatrix(cells, {
|
|
249
|
+
runCell: options.runCell,
|
|
250
|
+
concurrency: options.concurrency,
|
|
251
|
+
retry: options.retry,
|
|
252
|
+
});
|
|
253
|
+
for (const result of results) {
|
|
254
|
+
options.write(`${JSON.stringify(result)}\n`);
|
|
255
|
+
}
|
|
256
|
+
return buildBatchSummary(results);
|
|
257
|
+
}
|
|
258
|
+
async function readStdinToEnd() {
|
|
259
|
+
const stdin = process.stdin;
|
|
260
|
+
if (stdin.isTTY)
|
|
261
|
+
return '';
|
|
262
|
+
const chunks = [];
|
|
263
|
+
for await (const chunk of stdin) {
|
|
264
|
+
chunks.push(Buffer.from(chunk));
|
|
265
|
+
}
|
|
266
|
+
return Buffer.concat(chunks).toString('utf8');
|
|
267
|
+
}
|
|
268
|
+
function readScriptFile(scriptPath) {
|
|
269
|
+
try {
|
|
270
|
+
return readFileSync(resolve(scriptPath), 'utf8');
|
|
271
|
+
}
|
|
272
|
+
catch (error) {
|
|
273
|
+
throw new Error(`Cannot read script "${scriptPath}": ${error instanceof Error ? error.message : String(error)}`);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
/** A broken-pipe error — a downstream reader (`head`, `jq 'first'`, a quit pager) closed the pipe. */
|
|
277
|
+
function isEpipe(error) {
|
|
278
|
+
return !!error && typeof error === 'object' && error.code === 'EPIPE';
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* The standalone `gth-batch` entry. Parses argv, resolves the script + input axis, wires the
|
|
282
|
+
* per-cell runtime, runs the matrix, and streams JSONL cell records via `deps.write`.
|
|
283
|
+
*
|
|
284
|
+
* Exit-code contract (identical to `gth batch`): resolves to `0` iff the cells *ran* — a per-cell
|
|
285
|
+
* failure is recorded in that cell's JSON, never reflected in the exit code. A harness-level error
|
|
286
|
+
* (bad args, unreadable script, malformed `--over`, config failure) resolves to `1`. A downstream
|
|
287
|
+
* reader closing the pipe early (`EPIPE` on the stdout channel — e.g. `| head`) is normal pipeline
|
|
288
|
+
* usage and also resolves to `0`: the partial output already written is correct.
|
|
289
|
+
*
|
|
290
|
+
* @returns the process exit code (0 or 1).
|
|
291
|
+
*/
|
|
292
|
+
export async function runBatchCli(argv, deps = {}) {
|
|
293
|
+
// Default stdout sink: once a downstream reader closes the pipe (EPIPE), stop writing and treat
|
|
294
|
+
// it as a clean stop rather than letting the broken-pipe error bubble up as a harness failure.
|
|
295
|
+
let stdoutClosed = false;
|
|
296
|
+
const write = deps.write ??
|
|
297
|
+
((chunk) => {
|
|
298
|
+
if (stdoutClosed)
|
|
299
|
+
return;
|
|
300
|
+
try {
|
|
301
|
+
writeSync(1, chunk);
|
|
302
|
+
}
|
|
303
|
+
catch (error) {
|
|
304
|
+
if (isEpipe(error)) {
|
|
305
|
+
stdoutClosed = true;
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
throw error;
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
const logError = deps.logError ?? ((chunk) => void process.stderr.write(chunk));
|
|
312
|
+
try {
|
|
313
|
+
const args = parseArgs(argv);
|
|
314
|
+
const readScript = deps.readScript ?? readScriptFile;
|
|
315
|
+
const readStdin = deps.readStdin ?? readStdinToEnd;
|
|
316
|
+
const initConfig = deps.initConfig ?? realInitConfig;
|
|
317
|
+
const scriptContent = readScript(args.script);
|
|
318
|
+
const rows = await resolveRows(args, readStdin);
|
|
319
|
+
let runCell = deps.runCell;
|
|
320
|
+
if (!runCell) {
|
|
321
|
+
const overrides = {};
|
|
322
|
+
const baseConfig = await initConfig(overrides);
|
|
323
|
+
const preamble = getExecPreamble(baseConfig);
|
|
324
|
+
runCell = await buildProductionRunCell(baseConfig, preamble, overrides, initConfig);
|
|
325
|
+
}
|
|
326
|
+
const summary = await runMatrixToStream(scriptContent, args.models, rows, {
|
|
327
|
+
concurrency: args.concurrency,
|
|
328
|
+
retry: args.retry,
|
|
329
|
+
runCell,
|
|
330
|
+
write,
|
|
331
|
+
});
|
|
332
|
+
logError(`gth-batch: ${summary.passed}/${summary.total} cell(s) ok` +
|
|
333
|
+
(summary.failed > 0 ? `, ${summary.failed} failed` : '') +
|
|
334
|
+
'\n');
|
|
335
|
+
return 0;
|
|
336
|
+
}
|
|
337
|
+
catch (error) {
|
|
338
|
+
// A broken pipe on the stdout data channel (a downstream reader closed early) is a clean stop,
|
|
339
|
+
// not a harness error: exit 0 and stay silent. Genuine harness errors (bad args, unreadable
|
|
340
|
+
// script, malformed --over, config failure) carry no EPIPE code and still exit non-zero.
|
|
341
|
+
if (isEpipe(error)) {
|
|
342
|
+
return 0;
|
|
343
|
+
}
|
|
344
|
+
logError(`gth-batch: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
345
|
+
return 1;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
//# sourceMappingURL=pipelineCli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipelineCli.js","sourceRoot":"","sources":["../src/pipelineCli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { EvalSuiteSummary } from '#src/evalTypes.js';
|
|
2
|
+
import type { EvalRunContext, NamedReporter } from '#src/reporters/reporterTypes.js';
|
|
3
|
+
/**
|
|
4
|
+
* Drive reporters over one completed run's results, in lifecycle order:
|
|
5
|
+
* onSuiteStart → onCellResult per case (summary.cases order) → onSuiteEnd. A reporter hook that
|
|
6
|
+
* throws is caught and surfaced via displayWarning — a reporter must NEVER change the eval exit code
|
|
7
|
+
* or abort the run (the exit code is classifyEvalExit's job alone). Never throws.
|
|
8
|
+
*
|
|
9
|
+
* The lifecycle is phase-grouped across reporters (every reporter's onSuiteStart, then every
|
|
10
|
+
* reporter's onCellResult per case, then every reporter's onSuiteEnd) so a shared surface like the
|
|
11
|
+
* console is never interleaved out of order. With the single built-in `text` reporter this
|
|
12
|
+
* reproduces the former `printSummary` output byte-for-byte.
|
|
13
|
+
*/
|
|
14
|
+
export declare function driveReporters(reporters: NamedReporter[], summary: EvalSuiteSummary, ctx: EvalRunContext): Promise<void>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { displayWarning } from '@gaunt-sloth/core/utils/consoleUtils.js';
|
|
2
|
+
/** Run one reporter hook, swallowing any error (thrown OR a rejected Promise, the JUnit reporter's
|
|
3
|
+
* real failure mode) into a warning. A reporter must NEVER change the eval exit code or abort the
|
|
4
|
+
* run (the exit code is `classifyEvalExit`'s job alone), so a failing hook is contained here and the
|
|
5
|
+
* run continues. The warning names WHICH reporter's WHICH hook failed — ambiguous once multiple
|
|
6
|
+
* reporters (text + junit + custom) are real. */
|
|
7
|
+
async function runHookQuietly(reporterName, hook, run) {
|
|
8
|
+
try {
|
|
9
|
+
await run();
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
displayWarning(`eval reporter "${reporterName}" ${hook} hook failed: ` +
|
|
13
|
+
(error instanceof Error ? error.message : String(error)));
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Drive reporters over one completed run's results, in lifecycle order:
|
|
18
|
+
* onSuiteStart → onCellResult per case (summary.cases order) → onSuiteEnd. A reporter hook that
|
|
19
|
+
* throws is caught and surfaced via displayWarning — a reporter must NEVER change the eval exit code
|
|
20
|
+
* or abort the run (the exit code is classifyEvalExit's job alone). Never throws.
|
|
21
|
+
*
|
|
22
|
+
* The lifecycle is phase-grouped across reporters (every reporter's onSuiteStart, then every
|
|
23
|
+
* reporter's onCellResult per case, then every reporter's onSuiteEnd) so a shared surface like the
|
|
24
|
+
* console is never interleaved out of order. With the single built-in `text` reporter this
|
|
25
|
+
* reproduces the former `printSummary` output byte-for-byte.
|
|
26
|
+
*/
|
|
27
|
+
export async function driveReporters(reporters, summary, ctx) {
|
|
28
|
+
for (const { name, reporter } of reporters) {
|
|
29
|
+
const onSuiteStart = reporter.onSuiteStart;
|
|
30
|
+
if (onSuiteStart) {
|
|
31
|
+
await runHookQuietly(name, 'onSuiteStart', () => onSuiteStart.call(reporter, ctx));
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
for (const result of summary.cases) {
|
|
35
|
+
for (const { name, reporter } of reporters) {
|
|
36
|
+
const onCellResult = reporter.onCellResult;
|
|
37
|
+
if (onCellResult) {
|
|
38
|
+
await runHookQuietly(name, 'onCellResult', () => onCellResult.call(reporter, result, ctx));
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
for (const { name, reporter } of reporters) {
|
|
43
|
+
const onSuiteEnd = reporter.onSuiteEnd;
|
|
44
|
+
if (onSuiteEnd) {
|
|
45
|
+
await runHookQuietly(name, 'onSuiteEnd', () => onSuiteEnd.call(reporter, summary, ctx));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=drive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drive.js","sourceRoot":"","sources":["../../src/reporters/drive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AAIzE;;;;iDAIiD;AACjD,KAAK,UAAU,cAAc,CAC3B,YAAoB,EACpB,IAAY,EACZ,GAA+B;IAE/B,IAAI,CAAC;QACH,MAAM,GAAG,EAAE,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,cAAc,CACZ,kBAAkB,YAAY,KAAK,IAAI,gBAAgB;YACrD,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAC3D,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,SAA0B,EAC1B,OAAyB,EACzB,GAAmB;IAEnB,KAAK,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,SAAS,EAAE,CAAC;QAC3C,MAAM,YAAY,GAAG,QAAQ,CAAC,YAAY,CAAC;QAC3C,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,cAAc,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;QACrF,CAAC;IACH,CAAC;IAED,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACnC,KAAK,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,SAAS,EAAE,CAAC;YAC3C,MAAM,YAAY,GAAG,QAAQ,CAAC,YAAY,CAAC;YAC3C,IAAI,YAAY,EAAE,CAAC;gBACjB,MAAM,cAAc,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC;YAC7F,CAAC;QACH,CAAC;IACH,CAAC;IAED,KAAK,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,SAAS,EAAE,CAAC;QAC3C,MAAM,UAAU,GAAG,QAAQ,CAAC,UAAU,CAAC;QACvC,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,cAAc,CAAC,IAAI,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;QAC1F,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { EvalReporterFactory, NamedReporter } from '#src/reporters/reporterTypes.js';
|
|
2
|
+
/** Resolve reporter names to named instances ({@link NamedReporter}). `custom` (A2 — the bundled
|
|
3
|
+
* JUnit reporter and any config-declared user reporters) overlays/extends the built-ins through this
|
|
4
|
+
* ONE path; a `custom` key colliding with a built-in name wins (config beats built-in). A name found
|
|
5
|
+
* in neither throws with the available list (the command maps that to exit 2). Reporters are
|
|
6
|
+
* instantiated per call (fresh state per run). Each is paired with the name it was selected under so
|
|
7
|
+
* {@link driveReporters} can name a failing reporter in its contained-error warning. */
|
|
8
|
+
export declare function resolveReporters(names: string[], custom?: Record<string, EvalReporterFactory>): NamedReporter[];
|
|
9
|
+
/** The names `resolveReporters` accepts, given the same `custom` map — used to build the error
|
|
10
|
+
* message on an unknown name (and, in A2, to list reporters in help/errors). */
|
|
11
|
+
export declare function availableReporterNames(custom?: Record<string, EvalReporterFactory>): string[];
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { createTextReporter } from '#src/reporters/textReporter.js';
|
|
2
|
+
/** The built-in reporters, keyed by the name a user (later, A2) selects with `--reporter`. A1 ships
|
|
3
|
+
* only `text` (the former `printSummary`); A2 adds a JUnit reporter and a custom-reporter map. */
|
|
4
|
+
const BUILTIN_REPORTERS = { text: createTextReporter };
|
|
5
|
+
/** Resolve reporter names to named instances ({@link NamedReporter}). `custom` (A2 — the bundled
|
|
6
|
+
* JUnit reporter and any config-declared user reporters) overlays/extends the built-ins through this
|
|
7
|
+
* ONE path; a `custom` key colliding with a built-in name wins (config beats built-in). A name found
|
|
8
|
+
* in neither throws with the available list (the command maps that to exit 2). Reporters are
|
|
9
|
+
* instantiated per call (fresh state per run). Each is paired with the name it was selected under so
|
|
10
|
+
* {@link driveReporters} can name a failing reporter in its contained-error warning. */
|
|
11
|
+
export function resolveReporters(names, custom = {}) {
|
|
12
|
+
const registry = { ...BUILTIN_REPORTERS, ...custom };
|
|
13
|
+
return names.map((name) => {
|
|
14
|
+
const factory = registry[name];
|
|
15
|
+
if (!factory) {
|
|
16
|
+
throw new Error(`unknown reporter "${name}". Available reporters: ${availableReporterNames(custom).join(', ')}`);
|
|
17
|
+
}
|
|
18
|
+
return { name, reporter: factory() };
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
/** The names `resolveReporters` accepts, given the same `custom` map — used to build the error
|
|
22
|
+
* message on an unknown name (and, in A2, to list reporters in help/errors). */
|
|
23
|
+
export function availableReporterNames(custom = {}) {
|
|
24
|
+
return Object.keys({ ...BUILTIN_REPORTERS, ...custom });
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/reporters/registry.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AAEpE;kGACkG;AAClG,MAAM,iBAAiB,GAAwC,EAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC;AAE5F;;;;;wFAKwF;AACxF,MAAM,UAAU,gBAAgB,CAC9B,KAAe,EACf,MAAM,GAAwC,EAAE;IAEhD,MAAM,QAAQ,GAAwC,EAAE,GAAG,iBAAiB,EAAE,GAAG,MAAM,EAAE,CAAC;IAC1F,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACxB,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CACb,qBAAqB,IAAI,2BAA2B,sBAAsB,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAChG,CAAC;QACJ,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC;IACvC,CAAC,CAAC,CAAC;AACL,CAAC;AAED;gFACgF;AAChF,MAAM,UAAU,sBAAsB,CAAC,MAAM,GAAwC,EAAE;IACrF,OAAO,MAAM,CAAC,IAAI,CAAC,EAAE,GAAG,iBAAiB,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC;AAC1D,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { EvalCaseResult, EvalSuiteSummary } from '#src/evalTypes.js';
|
|
2
|
+
/** Immutable per-run context handed to every reporter hook. Carries what a reporter needs beyond the
|
|
3
|
+
* result objects themselves. `suitePath`/`outputDir` are already known to the command; passing them
|
|
4
|
+
* now (unused by the text reporter's console output except outputDir) sets up A2 (JUnit
|
|
5
|
+
* <testsuite name>) and B (per-suite output dirs) without another interface change. */
|
|
6
|
+
export interface EvalRunContext {
|
|
7
|
+
/** The suite file path as given on the CLI. */
|
|
8
|
+
suitePath: string;
|
|
9
|
+
/** The directory this run's structured output (results.json etc.) is written to. */
|
|
10
|
+
outputDir: string;
|
|
11
|
+
/** The BATCH-10-Task-2 self-describing judge line, when a separate judge profile is in effect. */
|
|
12
|
+
judgeNotice?: {
|
|
13
|
+
profile: string;
|
|
14
|
+
model?: string;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/** A reporter renders an eval run. Every hook is optional — a reporter implements only what it needs
|
|
18
|
+
* (the text reporter uses all three; a future file reporter may use only onSuiteEnd). Hooks are
|
|
19
|
+
* driven in lifecycle order by {@link driveReporters}. A reporter MUST NOT be able to fail the run:
|
|
20
|
+
* the driver catches any hook error and surfaces it as a warning (see driveReporters). */
|
|
21
|
+
export interface EvalReporter {
|
|
22
|
+
onSuiteStart?(ctx: EvalRunContext): void | Promise<void>;
|
|
23
|
+
onCellResult?(result: EvalCaseResult, ctx: EvalRunContext): void | Promise<void>;
|
|
24
|
+
onSuiteEnd?(summary: EvalSuiteSummary, ctx: EvalRunContext): void | Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
/** Reporters are created per run (they may accumulate state, e.g. a JUnit doc), so the registry
|
|
27
|
+
* stores factories, not instances. */
|
|
28
|
+
export type EvalReporterFactory = () => EvalReporter;
|
|
29
|
+
/** A resolved reporter paired with the name it was selected under. {@link resolveReporters} returns
|
|
30
|
+
* these (not bare {@link EvalReporter}s) so {@link driveReporters} can name WHICH reporter's hook
|
|
31
|
+
* failed in the contained-error warning — with multiple reporters real (A2: text + junit + custom),
|
|
32
|
+
* a bare "onCellResult hook failed" is ambiguous. */
|
|
33
|
+
export interface NamedReporter {
|
|
34
|
+
name: string;
|
|
35
|
+
reporter: EvalReporter;
|
|
36
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reporterTypes.js","sourceRoot":"","sources":["../../src/reporters/reporterTypes.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { EvalReporter } from '#src/reporters/reporterTypes.js';
|
|
2
|
+
/**
|
|
3
|
+
* The built-in default reporter: the human-readable, `review`-flavored summary — one PASS/FAIL line
|
|
4
|
+
* per cell (failures carry their reasons), then a suite-total line. Doesn't replicate `review`'s
|
|
5
|
+
* exact `REVIEW RATING` block format, just its spirit (a scannable verdict, not a wall of JSON).
|
|
6
|
+
*
|
|
7
|
+
* A1: this is a byte-for-byte port of `evalCommand.ts`'s former `printSummary` onto the reporter
|
|
8
|
+
* lifecycle — same lines, same order, same `display`/`displayWarning`/`displaySuccess` channels.
|
|
9
|
+
*/
|
|
10
|
+
export declare function createTextReporter(): EvalReporter;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { display, displaySuccess, displayWarning } from '@gaunt-sloth/core/utils/consoleUtils.js';
|
|
2
|
+
/**
|
|
3
|
+
* The built-in default reporter: the human-readable, `review`-flavored summary — one PASS/FAIL line
|
|
4
|
+
* per cell (failures carry their reasons), then a suite-total line. Doesn't replicate `review`'s
|
|
5
|
+
* exact `REVIEW RATING` block format, just its spirit (a scannable verdict, not a wall of JSON).
|
|
6
|
+
*
|
|
7
|
+
* A1: this is a byte-for-byte port of `evalCommand.ts`'s former `printSummary` onto the reporter
|
|
8
|
+
* lifecycle — same lines, same order, same `display`/`displayWarning`/`displaySuccess` channels.
|
|
9
|
+
*/
|
|
10
|
+
export function createTextReporter() {
|
|
11
|
+
return {
|
|
12
|
+
onSuiteStart(ctx) {
|
|
13
|
+
// BATCH-10 Task 2: when a separate judge profile is in effect, lead with a single
|
|
14
|
+
// self-describing line so a captured run records which model graded it (reproducibility).
|
|
15
|
+
// Emitted only for a separate judge — the default SUT-as-judge run prints exactly as before.
|
|
16
|
+
if (ctx.judgeNotice) {
|
|
17
|
+
display(`Judge: profile "${ctx.judgeNotice.profile}"` +
|
|
18
|
+
(ctx.judgeNotice.model ? ` (model: ${ctx.judgeNotice.model})` : ''));
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
onCellResult(result) {
|
|
22
|
+
// BATCH-12: an identity-matrix cell tags its line with the identity it ran under, so the two
|
|
23
|
+
// rows a case produces per (case × identity) are distinguishable. A no-identities cell prints
|
|
24
|
+
// exactly as before (just the case id).
|
|
25
|
+
const label = result.identity ? `${result.id} [${result.identity}]` : result.id;
|
|
26
|
+
if (result.verdict === 'PASS') {
|
|
27
|
+
display(`PASS ${label}`);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
displayWarning(`FAIL ${label} — ${result.reasons.join('; ') || 'no reason recorded'}`);
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
onSuiteEnd(summary, ctx) {
|
|
34
|
+
// M1: X/Y counts CELLS in a matrix run (one per case × identity) — e.g. `2/2` for 1 case × 2
|
|
35
|
+
// identities — so a bare "case(s)" would misreport the denominator. Use an identity-aware
|
|
36
|
+
// noun: "case(s)" for a no-identities run (unchanged), "cell(s)" once any cell carries an
|
|
37
|
+
// identity.
|
|
38
|
+
const isMatrix = summary.cases.some((caseResult) => caseResult.identity !== undefined);
|
|
39
|
+
const noun = isMatrix ? 'cell(s)' : 'case(s)';
|
|
40
|
+
const verdictLine = `EVAL RESULT: ${summary.passed}/${summary.total} ${noun} passed`;
|
|
41
|
+
if (summary.failed === 0) {
|
|
42
|
+
displaySuccess(`${verdictLine}. Results written to ${ctx.outputDir}`);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
displayWarning(`${verdictLine}, ${summary.failed} failed. Results written to ${ctx.outputDir}`);
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=textReporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"textReporter.js","sourceRoot":"","sources":["../../src/reporters/textReporter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AAIlG;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO;QACL,YAAY,CAAC,GAAmB;YAC9B,kFAAkF;YAClF,0FAA0F;YAC1F,6FAA6F;YAC7F,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;gBACpB,OAAO,CACL,mBAAmB,GAAG,CAAC,WAAW,CAAC,OAAO,GAAG;oBAC3C,CAAC,GAAG,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,GAAG,CAAC,WAAW,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CACtE,CAAC;YACJ,CAAC;QACH,CAAC;QAED,YAAY,CAAC,MAAsB;YACjC,6FAA6F;YAC7F,8FAA8F;YAC9F,wCAAwC;YACxC,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,EAAE,KAAK,MAAM,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;YAChF,IAAI,MAAM,CAAC,OAAO,KAAK,MAAM,EAAE,CAAC;gBAC9B,OAAO,CAAC,SAAS,KAAK,EAAE,CAAC,CAAC;YAC5B,CAAC;iBAAM,CAAC;gBACN,cAAc,CAAC,SAAS,KAAK,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAC;YAC1F,CAAC;QACH,CAAC;QAED,UAAU,CAAC,OAAyB,EAAE,GAAmB;YACvD,6FAA6F;YAC7F,0FAA0F;YAC1F,0FAA0F;YAC1F,YAAY;YACZ,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC;YACvF,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;YAC9C,MAAM,WAAW,GAAG,gBAAgB,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,KAAK,IAAI,IAAI,SAAS,CAAC;YACrF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACzB,cAAc,CAAC,GAAG,WAAW,wBAAwB,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC;YACxE,CAAC;iBAAM,CAAC;gBACN,cAAc,CACZ,GAAG,WAAW,KAAK,OAAO,CAAC,MAAM,+BAA+B,GAAG,CAAC,SAAS,EAAE,CAChF,CAAC;YACJ,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { EvalExpectation } from '#src/evalTypes.js';
|
|
2
|
+
/**
|
|
3
|
+
* BATCH-10 tool-trace assertions — grade a case against the tool *names* it actually invoked
|
|
4
|
+
* (`cellResult.tools`), rather than grepping the answer text. This "kills the false-positive class
|
|
5
|
+
* structurally": an MCP-only case can prove the server was called instead of a substring that a
|
|
6
|
+
* hallucinated answer could also contain.
|
|
7
|
+
*
|
|
8
|
+
* Kept separate from `runDeterministicChecks` (which reads the *answer*) on purpose — these read the
|
|
9
|
+
* tool trace — so neither signature is muddied. Patterns reuse GS2-61's `toolNameMatchesPattern`
|
|
10
|
+
* (`@gaunt-sloth/core`), the same glob/exact matcher `allowedTools` uses, so `mcp__unimarket__*`
|
|
11
|
+
* behaves identically here.
|
|
12
|
+
*
|
|
13
|
+
* - `mustCall` — for **each** pattern, at least one called tool must match it, else
|
|
14
|
+
* `did not call "<pattern>"`.
|
|
15
|
+
* - `mustNotCall` — **no** called tool may match any forbidden pattern; each offending tool is
|
|
16
|
+
* reported once as `called forbidden tool "<tool>" (matched "<pattern>")`.
|
|
17
|
+
*
|
|
18
|
+
* BATCH-12: grades one {@link EvalExpectation} block's tool-trace assertions (a flat case's single
|
|
19
|
+
* block or a matrix case's identity-scoped block) — same field names, same behavior as before.
|
|
20
|
+
*/
|
|
21
|
+
export declare function runToolCallChecks(tools: string[], expectation: Pick<EvalExpectation, 'mustCall' | 'mustNotCall'>): string[];
|