@gaunt-sloth/batch 2.0.0-alpha.19 → 2.0.0-alpha.20
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 +1 -1
- 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/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,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[];
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { toolNameMatchesPattern } from '@gaunt-sloth/core/utils/toolMatching.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 function runToolCallChecks(tools, expectation) {
|
|
22
|
+
const failures = [];
|
|
23
|
+
for (const pattern of expectation.mustCall) {
|
|
24
|
+
if (!tools.some((tool) => toolNameMatchesPattern(tool, pattern))) {
|
|
25
|
+
failures.push(`did not call "${pattern}"`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
// De-duplicate: a tool called N times (traces realistically repeat names) is one violation, not
|
|
29
|
+
// N identical failure lines. `Set` preserves first-seen order.
|
|
30
|
+
for (const tool of new Set(tools)) {
|
|
31
|
+
const matched = expectation.mustNotCall.find((pattern) => toolNameMatchesPattern(tool, pattern));
|
|
32
|
+
if (matched !== undefined) {
|
|
33
|
+
failures.push(`called forbidden tool "${tool}" (matched "${matched}")`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return failures;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=toolChecks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolChecks.js","sourceRoot":"","sources":["../src/toolChecks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AAIjF;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAAe,EACf,WAA8D;IAE9D,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,KAAK,MAAM,OAAO,IAAI,WAAW,CAAC,QAAQ,EAAE,CAAC;QAC3C,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,sBAAsB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC;YACjE,QAAQ,CAAC,IAAI,CAAC,iBAAiB,OAAO,GAAG,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IAED,gGAAgG;IAChG,+DAA+D;IAC/D,KAAK,MAAM,IAAI,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QAClC,MAAM,OAAO,GAAG,WAAW,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CACvD,sBAAsB,CAAC,IAAI,EAAE,OAAO,CAAC,CACtC,CAAC;QACF,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,QAAQ,CAAC,IAAI,CAAC,0BAA0B,IAAI,eAAe,OAAO,IAAI,CAAC,CAAC;QAC1E,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gaunt-sloth/batch",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.20",
|
|
4
4
|
"description": "Batch matrix runtime for Gaunt Sloth (BATCH-1): run a prompt-executable over a matrix of models and/or content-bound inputs",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Andrew Kondratev",
|
|
@@ -23,6 +23,9 @@
|
|
|
23
23
|
"type": "module",
|
|
24
24
|
"main": "dist/index.js",
|
|
25
25
|
"types": "dist/index.d.ts",
|
|
26
|
+
"bin": {
|
|
27
|
+
"gth-batch": "dist/bin.js"
|
|
28
|
+
},
|
|
26
29
|
"exports": {
|
|
27
30
|
".": "./dist/index.js",
|
|
28
31
|
"./*.js": "./dist/*.js"
|
|
@@ -34,8 +37,8 @@
|
|
|
34
37
|
"@langchain/core": "^1.2.3",
|
|
35
38
|
"yaml": "^2.9.0",
|
|
36
39
|
"zod": "^4.4.3",
|
|
37
|
-
"@gaunt-sloth/agent": "2.0.0-alpha.
|
|
38
|
-
"@gaunt-sloth/core": "2.0.0-alpha.
|
|
40
|
+
"@gaunt-sloth/agent": "2.0.0-alpha.20",
|
|
41
|
+
"@gaunt-sloth/core": "2.0.0-alpha.20"
|
|
39
42
|
},
|
|
40
43
|
"files": [
|
|
41
44
|
"./dist/*"
|