agentv 4.41.1 → 4.41.4-next.1
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 +3 -1
- package/dist/{artifact-writer-AMV64TWV.js → artifact-writer-GKRPI5WH.js} +4 -4
- package/dist/{chunk-LXXMQSAR.js → chunk-AHQWZGJE.js} +659 -286
- package/dist/chunk-AHQWZGJE.js.map +1 -0
- package/dist/{chunk-JQ6XRG7X.js → chunk-PC33TGIV.js} +22 -20
- package/dist/chunk-PC33TGIV.js.map +1 -0
- package/dist/{chunk-ENHX2CCS.js → chunk-QCF3LUI7.js} +269 -157
- package/dist/chunk-QCF3LUI7.js.map +1 -0
- package/dist/{chunk-A4J456KS.js → chunk-VBEWRK44.js} +429 -12
- package/dist/chunk-VBEWRK44.js.map +1 -0
- package/dist/{chunk-Z45FKRMJ.js → chunk-XDE2ZRII.js} +2 -2
- package/dist/cli.js +5 -5
- package/dist/{dist-X5P5IR65.js → dist-FDVFAGRG.js} +9 -47
- package/dist/index.js +5 -5
- package/dist/{interactive-OPSG4MPD.js → interactive-VNGVNNRF.js} +5 -5
- package/dist/skills/agentv-bench/references/environment-adaptation.md +1 -1
- package/dist/skills/agentv-bench/references/eval-yaml-spec.md +2 -2
- package/dist/skills/agentv-eval-writer/SKILL.md +4 -4
- package/dist/skills/agentv-eval-writer/references/custom-evaluators.md +2 -2
- package/dist/{ts-eval-loader-ZVL6CGTE-TZYZX3QS.js → ts-eval-loader-UPFWPMQO-SKZNUXPB.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-A4J456KS.js.map +0 -1
- package/dist/chunk-ENHX2CCS.js.map +0 -1
- package/dist/chunk-JQ6XRG7X.js.map +0 -1
- package/dist/chunk-LXXMQSAR.js.map +0 -1
- /package/dist/{artifact-writer-AMV64TWV.js.map → artifact-writer-GKRPI5WH.js.map} +0 -0
- /package/dist/{chunk-Z45FKRMJ.js.map → chunk-XDE2ZRII.js.map} +0 -0
- /package/dist/{dist-X5P5IR65.js.map → dist-FDVFAGRG.js.map} +0 -0
- /package/dist/{interactive-OPSG4MPD.js.map → interactive-VNGVNNRF.js.map} +0 -0
- /package/dist/{ts-eval-loader-ZVL6CGTE-TZYZX3QS.js.map → ts-eval-loader-UPFWPMQO-SKZNUXPB.js.map} +0 -0
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
parseYamlValue,
|
|
6
6
|
writeArtifactsFromResults,
|
|
7
7
|
writePerTestArtifacts
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-QCF3LUI7.js";
|
|
9
9
|
|
|
10
10
|
// src/commands/eval/artifact-writer.ts
|
|
11
11
|
import path2 from "node:path";
|
|
@@ -47,6 +47,11 @@ var TASK_EVAL_FILENAME = "EVAL.yaml";
|
|
|
47
47
|
var TASK_TARGETS_FILENAME = "targets.yaml";
|
|
48
48
|
var TASK_FILES_DIRNAME = "files";
|
|
49
49
|
var TASK_GRADERS_DIRNAME = "graders";
|
|
50
|
+
var BUNDLE_EVALS_DIRNAME = "evals";
|
|
51
|
+
var BUNDLE_MANIFEST_FILENAME = "agentv_bundle.json";
|
|
52
|
+
var BUNDLE_TARGETS_FILENAME = "targets.yaml";
|
|
53
|
+
var BUNDLE_WORKSPACES_DIRNAME = "workspaces";
|
|
54
|
+
var BUNDLE_SCRIPTS_DIRNAME = "scripts";
|
|
50
55
|
var REDACTED_SOURCE_VALUE = "[redacted]";
|
|
51
56
|
var SECRET_KEY_PATTERN = /(?:api[_-]?key|authorization|bearer|credential|password|private[_-]?key|secret|token)/i;
|
|
52
57
|
var SOURCE_SECRET_LINE_PATTERN = /^(\s*[\w.-]*(?:api[_-]?key|authorization|bearer|credential|password|private[_-]?key|secret|token)[\w.-]*\s*:\s*).+$/gim;
|
|
@@ -96,7 +101,16 @@ function relativeReferencePath(reference, options) {
|
|
|
96
101
|
return safeRelativePath(reference.displayPath);
|
|
97
102
|
}
|
|
98
103
|
function referenceBucket(reference) {
|
|
99
|
-
|
|
104
|
+
if (reference.kind === "input_file" || reference.kind === "expected_output_file") {
|
|
105
|
+
return TASK_FILES_DIRNAME;
|
|
106
|
+
}
|
|
107
|
+
if (reference.kind === "workspace_template") {
|
|
108
|
+
return BUNDLE_WORKSPACES_DIRNAME;
|
|
109
|
+
}
|
|
110
|
+
if (reference.kind === "workspace_hook_command") {
|
|
111
|
+
return BUNDLE_SCRIPTS_DIRNAME;
|
|
112
|
+
}
|
|
113
|
+
return TASK_GRADERS_DIRNAME;
|
|
100
114
|
}
|
|
101
115
|
function isLikelyBinary(buffer) {
|
|
102
116
|
return buffer.subarray(0, Math.min(buffer.length, 8e3)).includes(0);
|
|
@@ -195,13 +209,23 @@ function shouldCopyDirectory(reference) {
|
|
|
195
209
|
}
|
|
196
210
|
return !path.isAbsolute(reference.displayPath);
|
|
197
211
|
}
|
|
198
|
-
async function
|
|
212
|
+
async function copyReferenceWithFailure(reference, taskDir, options) {
|
|
199
213
|
if (!reference.resolvedPath) {
|
|
200
|
-
return
|
|
214
|
+
return {
|
|
215
|
+
failure: {
|
|
216
|
+
reference,
|
|
217
|
+
reason: `${reference.location ?? reference.kind} has no resolved path: ${reference.displayPath}`
|
|
218
|
+
}
|
|
219
|
+
};
|
|
201
220
|
}
|
|
202
221
|
const relPath = relativeReferencePath(reference, options);
|
|
203
222
|
if (!relPath) {
|
|
204
|
-
return
|
|
223
|
+
return {
|
|
224
|
+
failure: {
|
|
225
|
+
reference,
|
|
226
|
+
reason: `${reference.location ?? reference.kind} could not be assigned a portable path: ${reference.displayPath}`
|
|
227
|
+
}
|
|
228
|
+
};
|
|
205
229
|
}
|
|
206
230
|
const bucket = referenceBucket(reference);
|
|
207
231
|
const localPath = `${bucket}/${relPath}`;
|
|
@@ -209,23 +233,51 @@ async function copyReference(reference, taskDir, options) {
|
|
|
209
233
|
const sourcePath = path.resolve(reference.resolvedPath);
|
|
210
234
|
const sourceStat = await stat(sourcePath).catch(() => void 0);
|
|
211
235
|
if (!sourceStat) {
|
|
212
|
-
return
|
|
236
|
+
return {
|
|
237
|
+
failure: {
|
|
238
|
+
reference,
|
|
239
|
+
reason: `${reference.location ?? reference.kind} not found: ${reference.displayPath} (resolved to ${sourcePath})`
|
|
240
|
+
}
|
|
241
|
+
};
|
|
213
242
|
}
|
|
214
243
|
if (sourceStat.isDirectory()) {
|
|
215
244
|
if (!shouldCopyDirectory(reference)) {
|
|
216
|
-
return
|
|
245
|
+
return {
|
|
246
|
+
failure: {
|
|
247
|
+
reference,
|
|
248
|
+
reason: `${reference.location ?? reference.kind} uses an absolute directory that is not safe to copy automatically: ${reference.displayPath}`
|
|
249
|
+
}
|
|
250
|
+
};
|
|
217
251
|
}
|
|
218
252
|
if (!await copyDirectory(sourcePath, destinationPath)) {
|
|
219
|
-
return
|
|
253
|
+
return {
|
|
254
|
+
failure: {
|
|
255
|
+
reference,
|
|
256
|
+
reason: `${reference.location ?? reference.kind} directory contained no bundleable files: ${reference.displayPath}`
|
|
257
|
+
}
|
|
258
|
+
};
|
|
220
259
|
}
|
|
221
260
|
} else if (sourceStat.isFile()) {
|
|
222
261
|
if (!await copyFileRedactingText(sourcePath, destinationPath)) {
|
|
223
|
-
return
|
|
262
|
+
return {
|
|
263
|
+
failure: {
|
|
264
|
+
reference,
|
|
265
|
+
reason: `${reference.location ?? reference.kind} could not be copied: ${reference.displayPath}`
|
|
266
|
+
}
|
|
267
|
+
};
|
|
224
268
|
}
|
|
225
269
|
} else {
|
|
226
|
-
return
|
|
270
|
+
return {
|
|
271
|
+
failure: {
|
|
272
|
+
reference,
|
|
273
|
+
reason: `${reference.location ?? reference.kind} is not a regular file or directory: ${reference.displayPath}`
|
|
274
|
+
}
|
|
275
|
+
};
|
|
227
276
|
}
|
|
228
|
-
return { reference, localPath: localPath.split(path.sep).join("/"), destinationPath };
|
|
277
|
+
return { copied: { reference, localPath: localPath.split(path.sep).join("/"), destinationPath } };
|
|
278
|
+
}
|
|
279
|
+
async function copyReference(reference, taskDir, options) {
|
|
280
|
+
return (await copyReferenceWithFailure(reference, taskDir, options)).copied;
|
|
229
281
|
}
|
|
230
282
|
async function copyReferences(references, taskDir, options) {
|
|
231
283
|
const copied = [];
|
|
@@ -240,6 +292,31 @@ async function copyReferences(references, taskDir, options) {
|
|
|
240
292
|
}
|
|
241
293
|
return copied;
|
|
242
294
|
}
|
|
295
|
+
async function copyReferencesStrict(references, taskDir, options) {
|
|
296
|
+
const copied = [];
|
|
297
|
+
const failures = [];
|
|
298
|
+
const seenDestinations = /* @__PURE__ */ new Set();
|
|
299
|
+
const seenFailures = /* @__PURE__ */ new Set();
|
|
300
|
+
for (const reference of references) {
|
|
301
|
+
const result = await copyReferenceWithFailure(reference, taskDir, options);
|
|
302
|
+
if (result.copied) {
|
|
303
|
+
if (seenDestinations.has(result.copied.destinationPath)) {
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
seenDestinations.add(result.copied.destinationPath);
|
|
307
|
+
copied.push(result.copied);
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
if (result.failure) {
|
|
311
|
+
const key = `${result.failure.reference.kind}:${result.failure.reference.displayPath}:${result.failure.reason}`;
|
|
312
|
+
if (!seenFailures.has(key)) {
|
|
313
|
+
seenFailures.add(key);
|
|
314
|
+
failures.push(result.failure);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return { copied, failures };
|
|
319
|
+
}
|
|
243
320
|
function addRewrite(rewrites, from, to) {
|
|
244
321
|
if (!from || from.trim().length === 0) {
|
|
245
322
|
return;
|
|
@@ -354,6 +431,279 @@ async function writeYamlFile(filePath, value) {
|
|
|
354
431
|
function hasCopiedBucket(copied, bucket) {
|
|
355
432
|
return copied.some((entry) => entry.localPath.startsWith(`${bucket}/`));
|
|
356
433
|
}
|
|
434
|
+
function bundledEvalFileName(evalFilePath) {
|
|
435
|
+
const basename = path.basename(evalFilePath);
|
|
436
|
+
const withoutKnownExtension = basename.replace(/\.eval\.[cm]?ts$/i, "").replace(/\.eval\.ya?ml$/i, "").replace(/\.[cm]?ts$/i, "").replace(/\.ya?ml$/i, "").replace(/\.jsonl?$/i, "");
|
|
437
|
+
const safeName = withoutKnownExtension.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
438
|
+
return `${safeName || "bundle"}.eval.yaml`;
|
|
439
|
+
}
|
|
440
|
+
function uniqueTargetDefinitions(selections) {
|
|
441
|
+
const selected = [];
|
|
442
|
+
const seen = /* @__PURE__ */ new Set();
|
|
443
|
+
for (const selection of selections) {
|
|
444
|
+
for (const definition of selectTargetDefinitions(selection.targetName, selection.definitions)) {
|
|
445
|
+
if (seen.has(definition.name)) {
|
|
446
|
+
continue;
|
|
447
|
+
}
|
|
448
|
+
seen.add(definition.name);
|
|
449
|
+
selected.push(definition);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
return selected;
|
|
453
|
+
}
|
|
454
|
+
function uniqueTargetNames(selections) {
|
|
455
|
+
const names = [];
|
|
456
|
+
const seen = /* @__PURE__ */ new Set();
|
|
457
|
+
for (const selection of selections) {
|
|
458
|
+
if (seen.has(selection.targetName)) {
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
seen.add(selection.targetName);
|
|
462
|
+
names.push(selection.targetName);
|
|
463
|
+
}
|
|
464
|
+
return names;
|
|
465
|
+
}
|
|
466
|
+
function rewritePathString(value, rewrites) {
|
|
467
|
+
const direct = rewrites.get(value);
|
|
468
|
+
if (direct) {
|
|
469
|
+
return direct.startsWith("file://") ? direct.slice("file://".length) : direct;
|
|
470
|
+
}
|
|
471
|
+
const fileUrl = rewrites.get(`file://${value}`);
|
|
472
|
+
if (fileUrl) {
|
|
473
|
+
return fileUrl.startsWith("file://") ? fileUrl.slice("file://".length) : fileUrl;
|
|
474
|
+
}
|
|
475
|
+
return value;
|
|
476
|
+
}
|
|
477
|
+
function serializeContentValue(value, rewrites) {
|
|
478
|
+
if (typeof value === "string") {
|
|
479
|
+
return value;
|
|
480
|
+
}
|
|
481
|
+
if (Array.isArray(value)) {
|
|
482
|
+
return value.map((item) => serializeContentItem(item, rewrites));
|
|
483
|
+
}
|
|
484
|
+
if (isRecord(value)) {
|
|
485
|
+
return rewritePathsDeep(value, rewrites);
|
|
486
|
+
}
|
|
487
|
+
return value;
|
|
488
|
+
}
|
|
489
|
+
function serializeContentItem(value, rewrites) {
|
|
490
|
+
if (typeof value === "string") {
|
|
491
|
+
return value;
|
|
492
|
+
}
|
|
493
|
+
if (!isRecord(value)) {
|
|
494
|
+
return value;
|
|
495
|
+
}
|
|
496
|
+
const type = value.type;
|
|
497
|
+
if (type === "text") {
|
|
498
|
+
const text = typeof value.value === "string" ? value.value : value.text;
|
|
499
|
+
return { type: "text", value: typeof text === "string" ? text : "" };
|
|
500
|
+
}
|
|
501
|
+
if (type === "file") {
|
|
502
|
+
const source = typeof value.value === "string" ? value.value : typeof value.path === "string" ? value.path : typeof value.resolvedPath === "string" ? value.resolvedPath : void 0;
|
|
503
|
+
return source ? { type: "file", value: rewritePathString(source, rewrites) } : { type: "file", value: "" };
|
|
504
|
+
}
|
|
505
|
+
if (type === "image") {
|
|
506
|
+
const source = typeof value.value === "string" ? value.value : typeof value.path === "string" ? value.path : typeof value.resolvedPath === "string" ? value.resolvedPath : void 0;
|
|
507
|
+
if (source) {
|
|
508
|
+
return { type: "image", value: rewritePathString(source, rewrites) };
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
return rewritePathsDeep(value, rewrites);
|
|
512
|
+
}
|
|
513
|
+
function serializeMessage(message, rewrites) {
|
|
514
|
+
return {
|
|
515
|
+
role: message.role,
|
|
516
|
+
content: serializeContentValue(message.content, rewrites)
|
|
517
|
+
};
|
|
518
|
+
}
|
|
519
|
+
function serializeExpectedMessage(message, rewrites) {
|
|
520
|
+
const serialized = {};
|
|
521
|
+
for (const [key, value] of Object.entries(message)) {
|
|
522
|
+
serialized[key] = key === "content" ? serializeContentValue(value, rewrites) : value;
|
|
523
|
+
}
|
|
524
|
+
return rewritePathsDeep(serialized, rewrites);
|
|
525
|
+
}
|
|
526
|
+
function serializeWorkspace(workspace, rewrites) {
|
|
527
|
+
const {
|
|
528
|
+
workspaceFileDir: _workspaceFileDir,
|
|
529
|
+
path: _path,
|
|
530
|
+
mode,
|
|
531
|
+
...portableWorkspace
|
|
532
|
+
} = workspace;
|
|
533
|
+
const withoutStaticMode = mode === "static" ? portableWorkspace : { ...portableWorkspace, ...mode ? { mode } : {} };
|
|
534
|
+
return rewritePathsDeep(withoutStaticMode, rewrites);
|
|
535
|
+
}
|
|
536
|
+
function buildPortableEvalCase(test, rewrites) {
|
|
537
|
+
const testCase = buildEvalCase(test, rewrites);
|
|
538
|
+
testCase.id = test.id;
|
|
539
|
+
testCase.input = test.input.map((message) => serializeMessage(message, rewrites));
|
|
540
|
+
if (test.criteria.trim().length > 0) {
|
|
541
|
+
testCase.criteria = test.criteria;
|
|
542
|
+
}
|
|
543
|
+
if (test.expected_output.length > 0) {
|
|
544
|
+
testCase.expected_output = test.expected_output.map(
|
|
545
|
+
(message) => serializeExpectedMessage(message, rewrites)
|
|
546
|
+
);
|
|
547
|
+
}
|
|
548
|
+
if (test.workspace) {
|
|
549
|
+
testCase.workspace = serializeWorkspace(test.workspace, rewrites);
|
|
550
|
+
}
|
|
551
|
+
if (test.metadata && Object.keys(test.metadata).length > 0) {
|
|
552
|
+
testCase.metadata = rewritePathsDeep(test.metadata, rewrites);
|
|
553
|
+
}
|
|
554
|
+
if (test.conversation_id) {
|
|
555
|
+
testCase.conversation_id = test.conversation_id;
|
|
556
|
+
}
|
|
557
|
+
if (test.targets && test.targets.length > 0) {
|
|
558
|
+
const existingExecution = isRecord(testCase.execution) ? testCase.execution : {};
|
|
559
|
+
testCase.execution = { ...existingExecution, targets: test.targets };
|
|
560
|
+
}
|
|
561
|
+
if (test.threshold !== void 0) {
|
|
562
|
+
const existingExecution = isRecord(testCase.execution) ? testCase.execution : {};
|
|
563
|
+
testCase.execution = { ...existingExecution, threshold: test.threshold };
|
|
564
|
+
}
|
|
565
|
+
if (test.mode) {
|
|
566
|
+
testCase.mode = test.mode;
|
|
567
|
+
}
|
|
568
|
+
if (test.turns && test.turns.length > 0) {
|
|
569
|
+
testCase.turns = rewritePathsDeep(test.turns, rewrites);
|
|
570
|
+
}
|
|
571
|
+
if (test.aggregation) {
|
|
572
|
+
testCase.aggregation = test.aggregation;
|
|
573
|
+
}
|
|
574
|
+
if (test.on_turn_failure) {
|
|
575
|
+
testCase.on_turn_failure = test.on_turn_failure;
|
|
576
|
+
}
|
|
577
|
+
if (test.window_size !== void 0) {
|
|
578
|
+
testCase.window_size = test.window_size;
|
|
579
|
+
}
|
|
580
|
+
if (test.depends_on && test.depends_on.length > 0) {
|
|
581
|
+
testCase.depends_on = test.depends_on;
|
|
582
|
+
}
|
|
583
|
+
if (test.on_dependency_failure) {
|
|
584
|
+
testCase.on_dependency_failure = test.on_dependency_failure;
|
|
585
|
+
}
|
|
586
|
+
return testCase;
|
|
587
|
+
}
|
|
588
|
+
function isLikelyCommandPath(value) {
|
|
589
|
+
if (value.trim().length === 0 || value.startsWith("-") || value.includes("${{")) {
|
|
590
|
+
return false;
|
|
591
|
+
}
|
|
592
|
+
return value.startsWith(".") || value.includes("/") || value.includes("\\") || path.extname(value).length > 0;
|
|
593
|
+
}
|
|
594
|
+
async function maybeWorkspaceHookCommandReference(options) {
|
|
595
|
+
if (!isLikelyCommandPath(options.arg)) {
|
|
596
|
+
return void 0;
|
|
597
|
+
}
|
|
598
|
+
const resolvedPath = path.isAbsolute(options.arg) ? path.resolve(options.arg) : path.resolve(options.baseDir, options.arg);
|
|
599
|
+
const sourceStat = await stat(resolvedPath).catch(() => void 0);
|
|
600
|
+
if (!sourceStat?.isFile()) {
|
|
601
|
+
return void 0;
|
|
602
|
+
}
|
|
603
|
+
return {
|
|
604
|
+
kind: "workspace_hook_command",
|
|
605
|
+
displayPath: options.arg,
|
|
606
|
+
resolvedPath,
|
|
607
|
+
location: `workspace.hooks.${options.hookName}.command for test "${options.testId}"`
|
|
608
|
+
};
|
|
609
|
+
}
|
|
610
|
+
async function collectWorkspaceReferences(tests, evalFileDir) {
|
|
611
|
+
const references = [];
|
|
612
|
+
const errors = [];
|
|
613
|
+
for (const test of tests) {
|
|
614
|
+
const workspace = test.workspace;
|
|
615
|
+
if (!workspace) {
|
|
616
|
+
continue;
|
|
617
|
+
}
|
|
618
|
+
if (workspace.path || workspace.mode === "static") {
|
|
619
|
+
errors.push(
|
|
620
|
+
`workspace.path for test "${test.id}" cannot be bundled because it points at an existing static workspace. Use workspace.template, workspace.repos, or workspace.hooks for portable bundles.`
|
|
621
|
+
);
|
|
622
|
+
}
|
|
623
|
+
if (workspace.template) {
|
|
624
|
+
references.push({
|
|
625
|
+
kind: "workspace_template",
|
|
626
|
+
displayPath: workspace.template,
|
|
627
|
+
resolvedPath: workspace.template,
|
|
628
|
+
location: `workspace.template for test "${test.id}"`
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
const hooks = workspace.hooks;
|
|
632
|
+
if (!hooks) {
|
|
633
|
+
continue;
|
|
634
|
+
}
|
|
635
|
+
for (const hookName of ["before_all", "before_each", "after_each", "after_all"]) {
|
|
636
|
+
const hook = hooks[hookName];
|
|
637
|
+
const command = hook?.command ?? hook?.script;
|
|
638
|
+
if (!command || command.length === 0) {
|
|
639
|
+
continue;
|
|
640
|
+
}
|
|
641
|
+
if (hook?.cwd) {
|
|
642
|
+
errors.push(
|
|
643
|
+
`workspace.hooks.${hookName}.cwd for test "${test.id}" cannot be bundled safely yet: ${hook.cwd}`
|
|
644
|
+
);
|
|
645
|
+
continue;
|
|
646
|
+
}
|
|
647
|
+
const baseDir = workspace.workspaceFileDir ?? evalFileDir;
|
|
648
|
+
for (const arg of command) {
|
|
649
|
+
const reference = await maybeWorkspaceHookCommandReference({
|
|
650
|
+
arg,
|
|
651
|
+
baseDir,
|
|
652
|
+
testId: test.id,
|
|
653
|
+
hookName
|
|
654
|
+
});
|
|
655
|
+
if (reference) {
|
|
656
|
+
references.push(reference);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
return { references, errors };
|
|
662
|
+
}
|
|
663
|
+
function collectExpectedOutputReferences(tests) {
|
|
664
|
+
const references = [];
|
|
665
|
+
for (const test of tests) {
|
|
666
|
+
for (const message of test.expected_output) {
|
|
667
|
+
const content = message.content;
|
|
668
|
+
if (!Array.isArray(content)) {
|
|
669
|
+
continue;
|
|
670
|
+
}
|
|
671
|
+
for (const segment of content) {
|
|
672
|
+
if (!isRecord(segment) || segment.type !== "file") {
|
|
673
|
+
continue;
|
|
674
|
+
}
|
|
675
|
+
const resolvedPath = typeof segment.resolvedPath === "string" ? path.resolve(segment.resolvedPath) : void 0;
|
|
676
|
+
const displayPath = typeof segment.path === "string" ? segment.path : typeof segment.value === "string" ? segment.value : resolvedPath;
|
|
677
|
+
if (!displayPath) {
|
|
678
|
+
continue;
|
|
679
|
+
}
|
|
680
|
+
references.push({
|
|
681
|
+
kind: "expected_output_file",
|
|
682
|
+
displayPath,
|
|
683
|
+
...resolvedPath ? { resolvedPath } : {},
|
|
684
|
+
location: `expected_output file for test "${test.id}"`
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
return references;
|
|
690
|
+
}
|
|
691
|
+
function bundleManifest(options) {
|
|
692
|
+
const relative = (filePath) => path.relative(options.outputDir, filePath).split(path.sep).join("/");
|
|
693
|
+
return {
|
|
694
|
+
schema_version: 1,
|
|
695
|
+
created_at: options.createdAt,
|
|
696
|
+
source_eval: options.evalFilePath,
|
|
697
|
+
eval_path: relative(options.evalPath),
|
|
698
|
+
targets_path: relative(options.targetsPath),
|
|
699
|
+
test_count: options.tests.length,
|
|
700
|
+
targets: options.targetNames,
|
|
701
|
+
...hasCopiedBucket(options.copiedReferences, "files") ? { files_path: "evals/files" } : {},
|
|
702
|
+
...hasCopiedBucket(options.copiedReferences, "graders") ? { graders_path: "evals/graders" } : {},
|
|
703
|
+
...hasCopiedBucket(options.copiedReferences, "workspaces") ? { workspaces_path: "evals/workspaces" } : {},
|
|
704
|
+
...hasCopiedBucket(options.copiedReferences, "scripts") ? { scripts_path: "evals/scripts" } : {}
|
|
705
|
+
};
|
|
706
|
+
}
|
|
357
707
|
async function materializeTaskBundle(options) {
|
|
358
708
|
if (!options.test.source) {
|
|
359
709
|
return void 0;
|
|
@@ -382,6 +732,72 @@ async function materializeTaskBundle(options) {
|
|
|
382
732
|
...hasCopiedBucket(copiedReferences, "graders") ? { gradersPath: path.join(taskDir, TASK_GRADERS_DIRNAME) } : {}
|
|
383
733
|
};
|
|
384
734
|
}
|
|
735
|
+
async function materializeEvalBundle(options) {
|
|
736
|
+
if (options.tests.length === 0) {
|
|
737
|
+
throw new Error("Cannot bundle eval with no runnable tests.");
|
|
738
|
+
}
|
|
739
|
+
if (options.targetSelections.length === 0) {
|
|
740
|
+
throw new Error("Cannot bundle eval without a selected target.");
|
|
741
|
+
}
|
|
742
|
+
const missingSource = options.tests.find((test) => !test.source);
|
|
743
|
+
if (missingSource) {
|
|
744
|
+
throw new Error(
|
|
745
|
+
`Cannot bundle test "${missingSource.id}" because it has no source metadata. YAML evals are supported; programmatic evals with inline functions are not portable yet.`
|
|
746
|
+
);
|
|
747
|
+
}
|
|
748
|
+
const outputDir = path.resolve(options.outputDir);
|
|
749
|
+
const evalsDir = path.join(outputDir, BUNDLE_EVALS_DIRNAME);
|
|
750
|
+
await mkdir(evalsDir, { recursive: true });
|
|
751
|
+
const evalFileDir = path.dirname(path.resolve(options.evalFilePath));
|
|
752
|
+
const workspaceReferences = await collectWorkspaceReferences(options.tests, evalFileDir);
|
|
753
|
+
const references = [
|
|
754
|
+
...options.tests.flatMap((test) => test.source?.references ?? []),
|
|
755
|
+
...collectExpectedOutputReferences(options.tests),
|
|
756
|
+
...workspaceReferences.references
|
|
757
|
+
];
|
|
758
|
+
const { copied, failures } = await copyReferencesStrict(references, evalsDir, options);
|
|
759
|
+
const errors = [...workspaceReferences.errors, ...failures.map((failure) => failure.reason)];
|
|
760
|
+
if (errors.length > 0) {
|
|
761
|
+
throw new Error(`Cannot bundle eval:
|
|
762
|
+
${errors.map((error) => `- ${error}`).join("\n")}`);
|
|
763
|
+
}
|
|
764
|
+
const rewrites = buildPathRewrites(copied);
|
|
765
|
+
const targetNames = uniqueTargetNames(options.targetSelections);
|
|
766
|
+
const evalPath = path.join(evalsDir, bundledEvalFileName(options.evalFilePath));
|
|
767
|
+
const targetsPath = path.join(outputDir, BUNDLE_TARGETS_FILENAME);
|
|
768
|
+
const manifestPath = path.join(outputDir, BUNDLE_MANIFEST_FILENAME);
|
|
769
|
+
const execution = options.execution ?? (targetNames.length === 1 ? { target: targetNames[0] } : { targets: targetNames });
|
|
770
|
+
await writeYamlFile(evalPath, {
|
|
771
|
+
execution,
|
|
772
|
+
tests: options.tests.map((test) => buildPortableEvalCase(test, rewrites))
|
|
773
|
+
});
|
|
774
|
+
await writeYamlFile(targetsPath, {
|
|
775
|
+
targets: uniqueTargetDefinitions(options.targetSelections)
|
|
776
|
+
});
|
|
777
|
+
const manifest = bundleManifest({
|
|
778
|
+
outputDir,
|
|
779
|
+
evalFilePath: path.resolve(options.evalFilePath),
|
|
780
|
+
evalPath,
|
|
781
|
+
targetsPath,
|
|
782
|
+
copiedReferences: copied,
|
|
783
|
+
tests: options.tests,
|
|
784
|
+
targetNames,
|
|
785
|
+
createdAt: (options.now ?? (() => /* @__PURE__ */ new Date()))().toISOString()
|
|
786
|
+
});
|
|
787
|
+
await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}
|
|
788
|
+
`, "utf8");
|
|
789
|
+
return {
|
|
790
|
+
bundleDir: outputDir,
|
|
791
|
+
evalsDir,
|
|
792
|
+
evalPath,
|
|
793
|
+
targetsPath,
|
|
794
|
+
manifestPath,
|
|
795
|
+
...hasCopiedBucket(copied, "files") ? { filesPath: path.join(evalsDir, TASK_FILES_DIRNAME) } : {},
|
|
796
|
+
...hasCopiedBucket(copied, "graders") ? { gradersPath: path.join(evalsDir, TASK_GRADERS_DIRNAME) } : {},
|
|
797
|
+
...hasCopiedBucket(copied, "workspaces") ? { workspacesPath: path.join(evalsDir, BUNDLE_WORKSPACES_DIRNAME) } : {},
|
|
798
|
+
...hasCopiedBucket(copied, "scripts") ? { scriptsPath: path.join(evalsDir, BUNDLE_SCRIPTS_DIRNAME) } : {}
|
|
799
|
+
};
|
|
800
|
+
}
|
|
385
801
|
|
|
386
802
|
// src/commands/eval/artifact-writer.ts
|
|
387
803
|
function toRelativeArtifactPath(outputDir, filePath) {
|
|
@@ -486,9 +902,10 @@ async function writeArtifactsFromResults2(results, outputDir, options) {
|
|
|
486
902
|
|
|
487
903
|
export {
|
|
488
904
|
toSnakeCaseDeep,
|
|
905
|
+
materializeEvalBundle,
|
|
489
906
|
buildIndexArtifactEntry2 as buildIndexArtifactEntry,
|
|
490
907
|
buildResultIndexArtifact2 as buildResultIndexArtifact,
|
|
491
908
|
writePerTestArtifacts2 as writePerTestArtifacts,
|
|
492
909
|
writeArtifactsFromResults2 as writeArtifactsFromResults
|
|
493
910
|
};
|
|
494
|
-
//# sourceMappingURL=chunk-
|
|
911
|
+
//# sourceMappingURL=chunk-VBEWRK44.js.map
|