@brainbase-labs/cli 0.24.0 → 0.25.0-eng1209.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/dist/index.js +422 -44
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -36008,7 +36008,7 @@ function padStart(s, n) {
|
|
|
36008
36008
|
// package.json
|
|
36009
36009
|
var package_default = {
|
|
36010
36010
|
name: "@brainbase-labs/cli",
|
|
36011
|
-
version: "0.
|
|
36011
|
+
version: "0.25.0-eng1209.1",
|
|
36012
36012
|
description: "Pack, share, and install agent templates across harnesses (Claude Code, Codex, ...).",
|
|
36013
36013
|
type: "module",
|
|
36014
36014
|
bin: {
|
|
@@ -78485,6 +78485,13 @@ var MAX_TRAJECTORY_BYTES = 100 * 1024 * 1024;
|
|
|
78485
78485
|
var MAX_REMOTE_INPUT_BYTES = 2 * 1024 * 1024 * 1024;
|
|
78486
78486
|
var MAX_ARCHIVE_EXTRACTED_BYTES = 2 * 1024 * 1024 * 1024;
|
|
78487
78487
|
var MAX_ARCHIVE_SCAN_BYTES = 2 * 1024 * 1024 * 1024;
|
|
78488
|
+
var MAX_SANDBOX_COMMANDS = 20;
|
|
78489
|
+
var MAX_CRITERIA_PER_EVALUATOR = 100;
|
|
78490
|
+
var MAX_CRITERIA_RESULT_BYTES = 1024 * 1024;
|
|
78491
|
+
var MAX_CRITERION_EXPLANATION_LENGTH = 16384;
|
|
78492
|
+
var MAX_CRITERION_EVIDENCE_IDS = 100;
|
|
78493
|
+
var MAX_CRITERION_EVIDENCE_ID_LENGTH = 256;
|
|
78494
|
+
var MAX_ALLOWED_EVIDENCE_IDS = 1e4;
|
|
78488
78495
|
var RESERVED_WORKSPACE_PATHS = new Set([
|
|
78489
78496
|
".brainbase",
|
|
78490
78497
|
".git",
|
|
@@ -78512,6 +78519,17 @@ var NonSecretEnvironmentValueSchema = exports_external.object({
|
|
|
78512
78519
|
sensitive: exports_external.literal(false)
|
|
78513
78520
|
}).strict();
|
|
78514
78521
|
var RootRelativePathSchema = exports_external.string().min(1).max(1024);
|
|
78522
|
+
var CandidateOutputPatternSchema = RootRelativePathSchema.refine((value) => {
|
|
78523
|
+
if (value.includes("\\") || /[\[\]{}]/.test(value))
|
|
78524
|
+
return false;
|
|
78525
|
+
try {
|
|
78526
|
+
return safeRelPath(value) === value;
|
|
78527
|
+
} catch {
|
|
78528
|
+
return false;
|
|
78529
|
+
}
|
|
78530
|
+
}, {
|
|
78531
|
+
message: "must be a normalized safe relative glob using only *, ?, and ** wildcards"
|
|
78532
|
+
});
|
|
78515
78533
|
var ArchivePathSchema = RootRelativePathSchema.refine((value) => {
|
|
78516
78534
|
try {
|
|
78517
78535
|
return safeRelPath(value) === value;
|
|
@@ -78618,7 +78636,11 @@ var EvaluatorSchema = exports_external.discriminatedUnion("type", [
|
|
|
78618
78636
|
...EvaluatorBase,
|
|
78619
78637
|
type: exports_external.literal("sandbox_command"),
|
|
78620
78638
|
command: CommandSchema.omit({ id: true }),
|
|
78621
|
-
root: exports_external.enum(["workspace", "tests"]).default("tests")
|
|
78639
|
+
root: exports_external.enum(["workspace", "tests"]).default("tests"),
|
|
78640
|
+
criterion_keys: exports_external.array(IdSchema).min(1).max(MAX_CRITERIA_PER_EVALUATOR).optional(),
|
|
78641
|
+
allowed_evidence_ids: exports_external.array(exports_external.string().min(1).max(MAX_CRITERION_EVIDENCE_ID_LENGTH)).max(MAX_ALLOWED_EVIDENCE_IDS).optional(),
|
|
78642
|
+
tests_path: ArchivePathSchema.optional(),
|
|
78643
|
+
workspace_mode: exports_external.enum(["read_only", "isolated_copy"]).default("read_only")
|
|
78622
78644
|
}).strict()
|
|
78623
78645
|
]);
|
|
78624
78646
|
var EvidenceFileSchema = exports_external.object({
|
|
@@ -78638,6 +78660,37 @@ var HydrateSpecSchema = BaseSpecSchema.extend({
|
|
|
78638
78660
|
materials: exports_external.array(MaterialSchema).max(1e4).default([]),
|
|
78639
78661
|
setup_commands: exports_external.array(CommandSchema).max(128).default([])
|
|
78640
78662
|
}).strict();
|
|
78663
|
+
var CandidateOutputSchema = exports_external.object({
|
|
78664
|
+
id: IdSchema,
|
|
78665
|
+
pattern: CandidateOutputPatternSchema,
|
|
78666
|
+
kind: exports_external.enum(["file", "directory"]),
|
|
78667
|
+
required: exports_external.boolean(),
|
|
78668
|
+
min_matches: exports_external.number().int().min(0).max(1e5),
|
|
78669
|
+
max_matches: exports_external.number().int().min(1).max(1e5),
|
|
78670
|
+
max_total_bytes: exports_external.number().int().min(0).max(2 * 1024 * 1024 * 1024)
|
|
78671
|
+
}).strict().superRefine((value, context) => {
|
|
78672
|
+
if (value.min_matches > value.max_matches) {
|
|
78673
|
+
context.addIssue({
|
|
78674
|
+
code: exports_external.ZodIssueCode.custom,
|
|
78675
|
+
path: ["min_matches"],
|
|
78676
|
+
message: "min_matches cannot exceed max_matches"
|
|
78677
|
+
});
|
|
78678
|
+
}
|
|
78679
|
+
if (value.required && value.min_matches === 0) {
|
|
78680
|
+
context.addIssue({
|
|
78681
|
+
code: exports_external.ZodIssueCode.custom,
|
|
78682
|
+
path: ["min_matches"],
|
|
78683
|
+
message: "required candidate outputs must require at least one match"
|
|
78684
|
+
});
|
|
78685
|
+
}
|
|
78686
|
+
if (!value.required && value.min_matches > 0) {
|
|
78687
|
+
context.addIssue({
|
|
78688
|
+
code: exports_external.ZodIssueCode.custom,
|
|
78689
|
+
path: ["min_matches"],
|
|
78690
|
+
message: "optional candidate outputs must allow zero matches"
|
|
78691
|
+
});
|
|
78692
|
+
}
|
|
78693
|
+
});
|
|
78641
78694
|
var EvaluateSpecSchema = BaseSpecSchema.extend({
|
|
78642
78695
|
phase: exports_external.literal("evaluate"),
|
|
78643
78696
|
tests_root: AbsolutePathSchema,
|
|
@@ -78648,6 +78701,7 @@ var EvaluateSpecSchema = BaseSpecSchema.extend({
|
|
|
78648
78701
|
references: exports_external.array(MaterialSchema).max(1e4).default([]),
|
|
78649
78702
|
evaluators: exports_external.array(EvaluatorSchema).min(1).max(1000),
|
|
78650
78703
|
candidate_artifacts: exports_external.array(RootRelativePathSchema).max(1000).default([]),
|
|
78704
|
+
candidate_outputs: exports_external.array(CandidateOutputSchema).max(1000).default([]),
|
|
78651
78705
|
capture_workspace_archive: exports_external.boolean().default(false),
|
|
78652
78706
|
workspace_limits: exports_external.object({
|
|
78653
78707
|
max_file_count: exports_external.number().int().min(1).max(1e6).default(1e5),
|
|
@@ -78727,7 +78781,8 @@ var BenchmarkSpecSchema = exports_external.discriminatedUnion("phase", [
|
|
|
78727
78781
|
{ items: value.setup_commands, path: "setup_commands" }
|
|
78728
78782
|
] : [
|
|
78729
78783
|
{ items: value.references, path: "references" },
|
|
78730
|
-
{ items: value.evaluators, path: "evaluators" }
|
|
78784
|
+
{ items: value.evaluators, path: "evaluators" },
|
|
78785
|
+
{ items: value.candidate_outputs, path: "candidate_outputs" }
|
|
78731
78786
|
];
|
|
78732
78787
|
for (const { items, path: issuePath } of uniqueLists) {
|
|
78733
78788
|
const ids = items.map((item) => item.id);
|
|
@@ -78739,6 +78794,39 @@ var BenchmarkSpecSchema = exports_external.discriminatedUnion("phase", [
|
|
|
78739
78794
|
});
|
|
78740
78795
|
}
|
|
78741
78796
|
}
|
|
78797
|
+
if (value.phase === "evaluate") {
|
|
78798
|
+
value.evaluators.forEach((evaluator, index) => {
|
|
78799
|
+
if (evaluator.type === "sandbox_command" && evaluator.criterion_keys && new Set(evaluator.criterion_keys).size !== evaluator.criterion_keys.length) {
|
|
78800
|
+
context.addIssue({
|
|
78801
|
+
code: exports_external.ZodIssueCode.custom,
|
|
78802
|
+
path: ["evaluators", index, "criterion_keys"],
|
|
78803
|
+
message: "criterion_keys must be unique"
|
|
78804
|
+
});
|
|
78805
|
+
}
|
|
78806
|
+
if (evaluator.type === "sandbox_command" && evaluator.criterion_keys && evaluator.allowed_evidence_ids === undefined) {
|
|
78807
|
+
context.addIssue({
|
|
78808
|
+
code: exports_external.ZodIssueCode.custom,
|
|
78809
|
+
path: ["evaluators", index, "allowed_evidence_ids"],
|
|
78810
|
+
message: "structured criteria require allowed_evidence_ids"
|
|
78811
|
+
});
|
|
78812
|
+
}
|
|
78813
|
+
if (evaluator.type === "sandbox_command" && evaluator.allowed_evidence_ids && new Set(evaluator.allowed_evidence_ids).size !== evaluator.allowed_evidence_ids.length) {
|
|
78814
|
+
context.addIssue({
|
|
78815
|
+
code: exports_external.ZodIssueCode.custom,
|
|
78816
|
+
path: ["evaluators", index, "allowed_evidence_ids"],
|
|
78817
|
+
message: "allowed_evidence_ids must be unique"
|
|
78818
|
+
});
|
|
78819
|
+
}
|
|
78820
|
+
});
|
|
78821
|
+
const candidateOutputBytes = value.candidate_outputs.reduce((total, output) => total + output.max_total_bytes, 0);
|
|
78822
|
+
if (candidateOutputBytes > value.workspace_limits.max_total_bytes) {
|
|
78823
|
+
context.addIssue({
|
|
78824
|
+
code: exports_external.ZodIssueCode.custom,
|
|
78825
|
+
path: ["candidate_outputs"],
|
|
78826
|
+
message: "candidate output byte limits exceed the workspace byte limit"
|
|
78827
|
+
});
|
|
78828
|
+
}
|
|
78829
|
+
}
|
|
78742
78830
|
const materials = value.phase === "hydrate" ? value.materials : value.references;
|
|
78743
78831
|
const archiveOutputBytes = materials.reduce((total, material) => total + (material.kind === "archive_file" ? material.file_size_bytes : 0), 0);
|
|
78744
78832
|
if (archiveOutputBytes > MAX_ARCHIVE_EXTRACTED_BYTES) {
|
|
@@ -78748,11 +78836,11 @@ var BenchmarkSpecSchema = exports_external.discriminatedUnion("phase", [
|
|
|
78748
78836
|
message: "archive-file materials exceed the aggregate extracted byte limit"
|
|
78749
78837
|
});
|
|
78750
78838
|
}
|
|
78751
|
-
if (value.phase === "evaluate" && value.evaluators.filter((evaluator) => evaluator.type === "sandbox_command").length >
|
|
78839
|
+
if (value.phase === "evaluate" && value.evaluators.filter((evaluator) => evaluator.type === "sandbox_command").length > MAX_SANDBOX_COMMANDS) {
|
|
78752
78840
|
context.addIssue({
|
|
78753
78841
|
code: exports_external.ZodIssueCode.custom,
|
|
78754
78842
|
path: ["evaluators"],
|
|
78755
|
-
message:
|
|
78843
|
+
message: `schema version 1 supports at most ${MAX_SANDBOX_COMMANDS} sandbox_command evaluators`
|
|
78756
78844
|
});
|
|
78757
78845
|
}
|
|
78758
78846
|
});
|
|
@@ -78763,7 +78851,12 @@ var BENCHMARK_CAPABILITIES = {
|
|
|
78763
78851
|
phases: ["hydrate", "evaluate"],
|
|
78764
78852
|
features: [
|
|
78765
78853
|
"remote_input_references_v1",
|
|
78766
|
-
"archive_file_materials_v1"
|
|
78854
|
+
"archive_file_materials_v1",
|
|
78855
|
+
"structured_criterion_results_v1",
|
|
78856
|
+
"multiple_sandbox_commands_v1",
|
|
78857
|
+
"sandbox_command_workspace_modes_v1",
|
|
78858
|
+
"candidate_outputs_v1",
|
|
78859
|
+
"criterion_evidence_allowlist_v1"
|
|
78767
78860
|
],
|
|
78768
78861
|
evaluator_types: [
|
|
78769
78862
|
"output_assertion",
|
|
@@ -78774,7 +78867,8 @@ var BENCHMARK_CAPABILITIES = {
|
|
|
78774
78867
|
limits: {
|
|
78775
78868
|
max_secret_bindings: 100,
|
|
78776
78869
|
max_evaluators: 1000,
|
|
78777
|
-
max_sandbox_commands:
|
|
78870
|
+
max_sandbox_commands: MAX_SANDBOX_COMMANDS,
|
|
78871
|
+
max_criteria_per_evaluator: MAX_CRITERIA_PER_EVALUATOR
|
|
78778
78872
|
}
|
|
78779
78873
|
};
|
|
78780
78874
|
|
|
@@ -80126,6 +80220,234 @@ async function workspaceManifest(spec, context) {
|
|
|
80126
80220
|
}
|
|
80127
80221
|
return records.sort((a3, b4) => a3.path.localeCompare(b4.path));
|
|
80128
80222
|
}
|
|
80223
|
+
function candidateGlob(pattern) {
|
|
80224
|
+
let source = "^";
|
|
80225
|
+
for (let index = 0;index < pattern.length; index += 1) {
|
|
80226
|
+
const char = pattern[index];
|
|
80227
|
+
if (char === "*") {
|
|
80228
|
+
if (pattern[index + 1] === "*") {
|
|
80229
|
+
if (pattern[index + 2] === "/") {
|
|
80230
|
+
source += "(?:.*/)?";
|
|
80231
|
+
index += 2;
|
|
80232
|
+
} else {
|
|
80233
|
+
source += ".*";
|
|
80234
|
+
index += 1;
|
|
80235
|
+
}
|
|
80236
|
+
} else {
|
|
80237
|
+
source += "[^/]*";
|
|
80238
|
+
}
|
|
80239
|
+
continue;
|
|
80240
|
+
}
|
|
80241
|
+
if (char === "?") {
|
|
80242
|
+
source += "[^/]";
|
|
80243
|
+
continue;
|
|
80244
|
+
}
|
|
80245
|
+
source += char.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&");
|
|
80246
|
+
}
|
|
80247
|
+
return new RegExp(`${source}$`);
|
|
80248
|
+
}
|
|
80249
|
+
function manifestDirectories(manifest, context) {
|
|
80250
|
+
const directories = new Set;
|
|
80251
|
+
for (const entry of manifest) {
|
|
80252
|
+
assertBudget(context);
|
|
80253
|
+
let current = path88.posix.dirname(entry.path);
|
|
80254
|
+
while (current !== ".") {
|
|
80255
|
+
assertBudget(context);
|
|
80256
|
+
directories.add(current);
|
|
80257
|
+
current = path88.posix.dirname(current);
|
|
80258
|
+
}
|
|
80259
|
+
}
|
|
80260
|
+
return [...directories].sort();
|
|
80261
|
+
}
|
|
80262
|
+
function candidateOutputFiles(output, manifest, context) {
|
|
80263
|
+
const matcher = candidateGlob(output.pattern);
|
|
80264
|
+
if (output.kind === "file") {
|
|
80265
|
+
const matched = [];
|
|
80266
|
+
for (const entry of manifest) {
|
|
80267
|
+
assertBudget(context);
|
|
80268
|
+
if (!matcher.test(entry.path))
|
|
80269
|
+
continue;
|
|
80270
|
+
if (entry.kind === "symlink") {
|
|
80271
|
+
throw new BenchmarkPhaseError("unsafe_path", `candidate output ${output.id} matches a symlink`);
|
|
80272
|
+
}
|
|
80273
|
+
matched.push(entry);
|
|
80274
|
+
}
|
|
80275
|
+
return {
|
|
80276
|
+
matchedCount: matched.length,
|
|
80277
|
+
files: matched
|
|
80278
|
+
};
|
|
80279
|
+
}
|
|
80280
|
+
for (const entry of manifest) {
|
|
80281
|
+
assertBudget(context);
|
|
80282
|
+
if (entry.kind === "symlink" && matcher.test(entry.path)) {
|
|
80283
|
+
throw new BenchmarkPhaseError("unsafe_path", `candidate output ${output.id} matches a symlink`);
|
|
80284
|
+
}
|
|
80285
|
+
}
|
|
80286
|
+
const directories = [];
|
|
80287
|
+
for (const directory of manifestDirectories(manifest, context)) {
|
|
80288
|
+
assertBudget(context);
|
|
80289
|
+
if (matcher.test(directory))
|
|
80290
|
+
directories.push(directory);
|
|
80291
|
+
}
|
|
80292
|
+
const selected = new Map;
|
|
80293
|
+
for (const directory of directories) {
|
|
80294
|
+
assertBudget(context);
|
|
80295
|
+
const prefix = `${directory}/`;
|
|
80296
|
+
for (const entry of manifest) {
|
|
80297
|
+
assertBudget(context);
|
|
80298
|
+
if (!entry.path.startsWith(prefix))
|
|
80299
|
+
continue;
|
|
80300
|
+
if (entry.kind === "symlink") {
|
|
80301
|
+
throw new BenchmarkPhaseError("unsafe_path", `candidate output ${output.id} contains a symlink`);
|
|
80302
|
+
}
|
|
80303
|
+
selected.set(entry.path, entry);
|
|
80304
|
+
}
|
|
80305
|
+
}
|
|
80306
|
+
return {
|
|
80307
|
+
matchedCount: directories.length,
|
|
80308
|
+
files: [...selected.values()].sort((left, right) => left.path.localeCompare(right.path))
|
|
80309
|
+
};
|
|
80310
|
+
}
|
|
80311
|
+
async function copyCandidateOutput(output, manifest, spec, context) {
|
|
80312
|
+
const selected = candidateOutputFiles(output, manifest, context);
|
|
80313
|
+
if (!output.required && selected.matchedCount === 0)
|
|
80314
|
+
return [];
|
|
80315
|
+
const minimumMatches = output.required ? Math.max(1, output.min_matches) : output.min_matches;
|
|
80316
|
+
if (selected.matchedCount < minimumMatches || selected.matchedCount > output.max_matches) {
|
|
80317
|
+
throw new BenchmarkPhaseError("candidate_output_match_count", `candidate output ${output.id} matched ${selected.matchedCount} ${output.kind}s`, {
|
|
80318
|
+
actual: selected.matchedCount,
|
|
80319
|
+
min_matches: minimumMatches,
|
|
80320
|
+
max_matches: output.max_matches
|
|
80321
|
+
});
|
|
80322
|
+
}
|
|
80323
|
+
let totalBytes = 0;
|
|
80324
|
+
for (const file of selected.files) {
|
|
80325
|
+
assertBudget(context);
|
|
80326
|
+
totalBytes += file.size;
|
|
80327
|
+
}
|
|
80328
|
+
if (totalBytes > output.max_total_bytes) {
|
|
80329
|
+
throw new BenchmarkPhaseError("candidate_output_size_exceeded", `candidate output ${output.id} exceeds its byte limit`, { actual: totalBytes, max_total_bytes: output.max_total_bytes });
|
|
80330
|
+
}
|
|
80331
|
+
const copied = [];
|
|
80332
|
+
for (const frozenFile of selected.files) {
|
|
80333
|
+
assertBudget(context);
|
|
80334
|
+
const source = path88.resolve(spec.workspace_root, safeRelPath(frozenFile.path));
|
|
80335
|
+
const destination = path88.resolve(spec.logs_root, "candidate-artifacts", output.id, safeRelPath(frozenFile.path));
|
|
80336
|
+
if (fs81.existsSync(destination)) {
|
|
80337
|
+
throw new BenchmarkPhaseError("destination_conflict", `candidate output destination already exists: ${output.id}/${frozenFile.path}`);
|
|
80338
|
+
}
|
|
80339
|
+
await atomicCopy(source, destination, frozenFile.mode, spec.workspace_root);
|
|
80340
|
+
const record3 = await recordFile(spec.logs_root, destination, "logs");
|
|
80341
|
+
if (record3.sha256 !== frozenFile.sha256 || record3.size !== frozenFile.size || record3.mode !== frozenFile.mode) {
|
|
80342
|
+
throw new BenchmarkPhaseError("evidence_tampered", `candidate output changed after the workspace freeze: ${frozenFile.path}`);
|
|
80343
|
+
}
|
|
80344
|
+
copied.push(record3);
|
|
80345
|
+
}
|
|
80346
|
+
return copied;
|
|
80347
|
+
}
|
|
80348
|
+
async function copyFrozenWorkspace(manifest, spec, context) {
|
|
80349
|
+
for (const entry of manifest) {
|
|
80350
|
+
assertBudget(context);
|
|
80351
|
+
if (entry.kind === "symlink") {
|
|
80352
|
+
throw new BenchmarkPhaseError("unsupported_workspace_symlink", `sandbox evaluator workspace cannot safely reproduce symlink: ${entry.path}`);
|
|
80353
|
+
}
|
|
80354
|
+
}
|
|
80355
|
+
const destinationRoot = fs81.mkdtempSync(path88.join(os16.tmpdir(), "brainbase-benchmark-workspace-"));
|
|
80356
|
+
fs81.chmodSync(destinationRoot, 448);
|
|
80357
|
+
context.temporaryRoots.add(destinationRoot);
|
|
80358
|
+
for (const frozenFile of manifest) {
|
|
80359
|
+
assertBudget(context);
|
|
80360
|
+
const source = path88.resolve(spec.workspace_root, safeRelPath(frozenFile.path));
|
|
80361
|
+
const destination = path88.resolve(destinationRoot, safeRelPath(frozenFile.path));
|
|
80362
|
+
await atomicCopy(source, destination, frozenFile.mode, spec.workspace_root);
|
|
80363
|
+
const copied = await recordFile(destinationRoot, destination, "workspace");
|
|
80364
|
+
if (copied.sha256 !== frozenFile.sha256 || copied.size !== frozenFile.size || copied.mode !== frozenFile.mode) {
|
|
80365
|
+
throw new BenchmarkPhaseError("evidence_tampered", `workspace changed after it was frozen: ${frozenFile.path}`);
|
|
80366
|
+
}
|
|
80367
|
+
}
|
|
80368
|
+
return destinationRoot;
|
|
80369
|
+
}
|
|
80370
|
+
function evaluatorTestsPath(evaluator, spec) {
|
|
80371
|
+
if (!evaluator.tests_path)
|
|
80372
|
+
return spec.tests_root;
|
|
80373
|
+
const relative = normalizedRootRelative(evaluator.tests_path);
|
|
80374
|
+
assertNoSymlinkTraversal(spec.tests_root, relative);
|
|
80375
|
+
const candidate = path88.resolve(spec.tests_root, relative);
|
|
80376
|
+
if (!isWithin(spec.tests_root, candidate) || !fs81.existsSync(candidate)) {
|
|
80377
|
+
throw new BenchmarkPhaseError("invalid_tests_path", `evaluator tests_path does not exist: ${evaluator.tests_path}`);
|
|
80378
|
+
}
|
|
80379
|
+
const stat = fs81.lstatSync(candidate);
|
|
80380
|
+
if (stat.isSymbolicLink() || !stat.isDirectory()) {
|
|
80381
|
+
throw new BenchmarkPhaseError("invalid_tests_path", `evaluator tests_path must be a directory: ${evaluator.tests_path}`);
|
|
80382
|
+
}
|
|
80383
|
+
return candidate;
|
|
80384
|
+
}
|
|
80385
|
+
var CriterionResultSchema = exports_external.object({
|
|
80386
|
+
criterion_key: IdSchema,
|
|
80387
|
+
outcome: exports_external.enum(["satisfied", "not_satisfied", "not_applicable"]),
|
|
80388
|
+
explanation: exports_external.string().min(1).max(MAX_CRITERION_EXPLANATION_LENGTH),
|
|
80389
|
+
evidence_ids: exports_external.array(exports_external.string().min(1).max(MAX_CRITERION_EVIDENCE_ID_LENGTH)).max(MAX_CRITERION_EVIDENCE_IDS)
|
|
80390
|
+
}).strict().superRefine((value, context) => {
|
|
80391
|
+
if (new Set(value.evidence_ids).size !== value.evidence_ids.length) {
|
|
80392
|
+
context.addIssue({
|
|
80393
|
+
code: exports_external.ZodIssueCode.custom,
|
|
80394
|
+
path: ["evidence_ids"],
|
|
80395
|
+
message: "evidence_ids must be unique"
|
|
80396
|
+
});
|
|
80397
|
+
}
|
|
80398
|
+
});
|
|
80399
|
+
var CriteriaResultFileSchema = exports_external.object({
|
|
80400
|
+
criteria: exports_external.array(CriterionResultSchema).max(MAX_CRITERIA_PER_EVALUATOR)
|
|
80401
|
+
}).strict();
|
|
80402
|
+
function readCriterionResults(resultPath, criterionKeys, allowedEvidenceIds) {
|
|
80403
|
+
let opened;
|
|
80404
|
+
try {
|
|
80405
|
+
opened = openRegularFileNoFollow(resultPath, "criterion result", path88.dirname(resultPath));
|
|
80406
|
+
} catch (error2) {
|
|
80407
|
+
if (error2.code === "ENOENT") {
|
|
80408
|
+
throw new BenchmarkPhaseError("missing_criterion_result", "sandbox evaluator did not write its criterion result");
|
|
80409
|
+
}
|
|
80410
|
+
throw error2;
|
|
80411
|
+
}
|
|
80412
|
+
try {
|
|
80413
|
+
if (opened.stat.size > MAX_CRITERIA_RESULT_BYTES) {
|
|
80414
|
+
throw new BenchmarkPhaseError("invalid_criterion_result", "criterion result exceeds the 1 MiB limit");
|
|
80415
|
+
}
|
|
80416
|
+
let raw;
|
|
80417
|
+
try {
|
|
80418
|
+
raw = JSON.parse(readDescriptor(opened.fd).toString("utf8"));
|
|
80419
|
+
} catch {
|
|
80420
|
+
throw new BenchmarkPhaseError("invalid_criterion_result", "criterion result is not valid JSON");
|
|
80421
|
+
}
|
|
80422
|
+
let parsed;
|
|
80423
|
+
try {
|
|
80424
|
+
parsed = CriteriaResultFileSchema.parse(raw);
|
|
80425
|
+
} catch (error2) {
|
|
80426
|
+
throw new BenchmarkPhaseError("invalid_criterion_result", "criterion result does not match the required schema", error2 instanceof exports_external.ZodError ? error2.issues : undefined);
|
|
80427
|
+
}
|
|
80428
|
+
const byKey = new Map;
|
|
80429
|
+
for (const criterion of parsed.criteria) {
|
|
80430
|
+
if (byKey.has(criterion.criterion_key)) {
|
|
80431
|
+
throw new BenchmarkPhaseError("invalid_criterion_result", `criterion result is duplicated: ${criterion.criterion_key}`);
|
|
80432
|
+
}
|
|
80433
|
+
byKey.set(criterion.criterion_key, criterion);
|
|
80434
|
+
}
|
|
80435
|
+
const expected = new Set(criterionKeys);
|
|
80436
|
+
const extra = [...byKey.keys()].filter((key2) => !expected.has(key2));
|
|
80437
|
+
const missing = criterionKeys.filter((key2) => !byKey.has(key2));
|
|
80438
|
+
if (extra.length > 0 || missing.length > 0) {
|
|
80439
|
+
throw new BenchmarkPhaseError("invalid_criterion_result", "criterion result keys do not match the evaluator plan", { missing, extra });
|
|
80440
|
+
}
|
|
80441
|
+
const allowedEvidence = new Set(allowedEvidenceIds);
|
|
80442
|
+
const unknownEvidenceIds = [...new Set(parsed.criteria.flatMap((criterion) => criterion.evidence_ids))].filter((evidenceId) => !allowedEvidence.has(evidenceId));
|
|
80443
|
+
if (unknownEvidenceIds.length > 0) {
|
|
80444
|
+
throw new BenchmarkPhaseError("invalid_criterion_result", "criterion result cites evidence outside the evaluator plan", { unknown_evidence_ids: unknownEvidenceIds });
|
|
80445
|
+
}
|
|
80446
|
+
return criterionKeys.map((key2) => byKey.get(key2));
|
|
80447
|
+
} finally {
|
|
80448
|
+
fs81.closeSync(opened.fd);
|
|
80449
|
+
}
|
|
80450
|
+
}
|
|
80129
80451
|
function trajectoryEvents(value) {
|
|
80130
80452
|
if (Array.isArray(value))
|
|
80131
80453
|
return value;
|
|
@@ -80144,7 +80466,7 @@ function eventType(event) {
|
|
|
80144
80466
|
}
|
|
80145
80467
|
return;
|
|
80146
80468
|
}
|
|
80147
|
-
async function evaluateOne(evaluator, spec, finalOutput, trajectory, frozenEvidence, context) {
|
|
80469
|
+
async function evaluateOne(evaluator, spec, manifest, finalOutput, trajectory, frozenEvidence, context) {
|
|
80148
80470
|
const started = Date.now();
|
|
80149
80471
|
const base2 = {
|
|
80150
80472
|
id: evaluator.id,
|
|
@@ -80156,11 +80478,11 @@ async function evaluateOne(evaluator, spec, finalOutput, trajectory, frozenEvide
|
|
|
80156
80478
|
};
|
|
80157
80479
|
if (evaluator.type === "output_assertion") {
|
|
80158
80480
|
const assertion = evaluator.assertion;
|
|
80159
|
-
let
|
|
80481
|
+
let verdict = false;
|
|
80160
80482
|
if (assertion.operator === "exact")
|
|
80161
|
-
|
|
80483
|
+
verdict = finalOutput === assertion.expected;
|
|
80162
80484
|
if (assertion.operator === "contains")
|
|
80163
|
-
|
|
80485
|
+
verdict = finalOutput.includes(assertion.expected);
|
|
80164
80486
|
if (assertion.operator === "regex") {
|
|
80165
80487
|
const regexResult = await runCommand({
|
|
80166
80488
|
id: `${evaluator.id}.regex`,
|
|
@@ -80186,17 +80508,17 @@ async function evaluateOne(evaluator, spec, finalOutput, trajectory, frozenEvide
|
|
|
80186
80508
|
if (regexResult.exitCode === 2) {
|
|
80187
80509
|
throw new BenchmarkPhaseError("invalid_evaluator", `invalid regex in evaluator: ${evaluator.id}`);
|
|
80188
80510
|
}
|
|
80189
|
-
|
|
80511
|
+
verdict = regexResult.exitCode === 0;
|
|
80190
80512
|
}
|
|
80191
|
-
return { ...base2, status:
|
|
80513
|
+
return { ...base2, status: verdict ? "passed" : "failed", verdict, duration_ms: Date.now() - started };
|
|
80192
80514
|
}
|
|
80193
80515
|
if (evaluator.type === "trajectory_assertion") {
|
|
80194
80516
|
const count = trajectory.filter((event) => eventType(event) === evaluator.event_type).length;
|
|
80195
|
-
const
|
|
80517
|
+
const verdict = count >= evaluator.min_count && (evaluator.max_count === undefined || count <= evaluator.max_count);
|
|
80196
80518
|
return {
|
|
80197
80519
|
...base2,
|
|
80198
|
-
status:
|
|
80199
|
-
verdict
|
|
80520
|
+
status: verdict ? "passed" : "failed",
|
|
80521
|
+
verdict,
|
|
80200
80522
|
duration_ms: Date.now() - started,
|
|
80201
80523
|
details: { count, min_count: evaluator.min_count, max_count: evaluator.max_count }
|
|
80202
80524
|
};
|
|
@@ -80217,16 +80539,16 @@ async function evaluateOne(evaluator, spec, finalOutput, trajectory, frozenEvide
|
|
|
80217
80539
|
throw new BenchmarkPhaseError("unsafe_path", `workspace assertion cannot target a symlink: ${relative}`);
|
|
80218
80540
|
}
|
|
80219
80541
|
const exists2 = stat !== null;
|
|
80220
|
-
let
|
|
80542
|
+
let verdict = false;
|
|
80221
80543
|
if (evaluator.assertion.operator === "exists")
|
|
80222
|
-
|
|
80544
|
+
verdict = exists2;
|
|
80223
80545
|
if (evaluator.assertion.operator === "not_exists")
|
|
80224
|
-
|
|
80546
|
+
verdict = !exists2;
|
|
80225
80547
|
if (evaluator.assertion.operator === "sha256") {
|
|
80226
80548
|
if (stat?.isFile()) {
|
|
80227
80549
|
const opened = openRegularFileNoFollow(candidate, `workspace assertion ${relative}`, spec.workspace_root);
|
|
80228
80550
|
try {
|
|
80229
|
-
|
|
80551
|
+
verdict = await sha256OfDescriptor(opened.fd) === evaluator.assertion.expected;
|
|
80230
80552
|
} finally {
|
|
80231
80553
|
fs81.closeSync(opened.fd);
|
|
80232
80554
|
}
|
|
@@ -80236,35 +80558,78 @@ async function evaluateOne(evaluator, spec, finalOutput, trajectory, frozenEvide
|
|
|
80236
80558
|
if (stat?.isFile()) {
|
|
80237
80559
|
const opened = openRegularFileNoFollow(candidate, `workspace assertion ${relative}`, spec.workspace_root);
|
|
80238
80560
|
try {
|
|
80239
|
-
|
|
80561
|
+
verdict = readDescriptor(opened.fd).toString("utf8").includes(evaluator.assertion.expected);
|
|
80240
80562
|
} finally {
|
|
80241
80563
|
fs81.closeSync(opened.fd);
|
|
80242
80564
|
}
|
|
80243
80565
|
}
|
|
80244
80566
|
}
|
|
80245
|
-
return { ...base2, status:
|
|
80567
|
+
return { ...base2, status: verdict ? "passed" : "failed", verdict, duration_ms: Date.now() - started };
|
|
80568
|
+
}
|
|
80569
|
+
let isolatedWorkspace;
|
|
80570
|
+
let privateResultRoot;
|
|
80571
|
+
try {
|
|
80572
|
+
const evaluatorWorkspace = await copyFrozenWorkspace(manifest, spec, context);
|
|
80573
|
+
isolatedWorkspace = evaluatorWorkspace;
|
|
80574
|
+
const testsPath = evaluatorTestsPath(evaluator, spec);
|
|
80575
|
+
const commandRoot = evaluator.root === "workspace" ? evaluatorWorkspace : spec.tests_root;
|
|
80576
|
+
const command = { id: evaluator.id, ...evaluator.command };
|
|
80577
|
+
const environment = {
|
|
80578
|
+
BRAINBASE_BENCHMARK_WORKSPACE: evaluatorWorkspace,
|
|
80579
|
+
BRAINBASE_BENCHMARK_TESTS: testsPath,
|
|
80580
|
+
BRAINBASE_BENCHMARK_LOGS: spec.logs_root,
|
|
80581
|
+
BRAINBASE_BENCHMARK_FINAL_OUTPUT: frozenEvidence.finalOutputPath,
|
|
80582
|
+
BRAINBASE_BENCHMARK_TRAJECTORY: frozenEvidence.trajectoryPath
|
|
80583
|
+
};
|
|
80584
|
+
let criterionResultPath;
|
|
80585
|
+
if (evaluator.criterion_keys) {
|
|
80586
|
+
privateResultRoot = fs81.mkdtempSync(path88.join(os16.tmpdir(), "brainbase-benchmark-criteria-"));
|
|
80587
|
+
fs81.chmodSync(privateResultRoot, 448);
|
|
80588
|
+
context.temporaryRoots.add(privateResultRoot);
|
|
80589
|
+
criterionResultPath = path88.join(privateResultRoot, "result.json");
|
|
80590
|
+
environment.BRAINBASE_BENCHMARK_CRITERIA_RESULT = criterionResultPath;
|
|
80591
|
+
}
|
|
80592
|
+
const result2 = await runCommand(command, commandRoot, spec, context, environment);
|
|
80593
|
+
const stdout = await writeLog(spec.logs_root, `${evaluator.id}.stdout.log`, result2.stdout, spec);
|
|
80594
|
+
const stderr = await writeLog(spec.logs_root, `${evaluator.id}.stderr.log`, result2.stderr, spec);
|
|
80595
|
+
let criterionResults;
|
|
80596
|
+
try {
|
|
80597
|
+
criterionResults = evaluator.criterion_keys && criterionResultPath ? readCriterionResults(criterionResultPath, evaluator.criterion_keys, evaluator.allowed_evidence_ids ?? []) : undefined;
|
|
80598
|
+
} catch (error2) {
|
|
80599
|
+
const normalized = stableError(error2);
|
|
80600
|
+
return {
|
|
80601
|
+
...base2,
|
|
80602
|
+
status: "errored",
|
|
80603
|
+
verdict: null,
|
|
80604
|
+
duration_ms: result2.durationMs,
|
|
80605
|
+
details: {
|
|
80606
|
+
exit_code: result2.exitCode,
|
|
80607
|
+
error_code: normalized?.code ?? "invalid_criterion_result",
|
|
80608
|
+
error_message: normalized?.message ?? "criterion result validation failed"
|
|
80609
|
+
},
|
|
80610
|
+
stdout,
|
|
80611
|
+
stderr
|
|
80612
|
+
};
|
|
80613
|
+
}
|
|
80614
|
+
const verdict = result2.exitCode === 0;
|
|
80615
|
+
return {
|
|
80616
|
+
...base2,
|
|
80617
|
+
status: verdict ? "passed" : "failed",
|
|
80618
|
+
verdict,
|
|
80619
|
+
duration_ms: result2.durationMs,
|
|
80620
|
+
details: { exit_code: result2.exitCode },
|
|
80621
|
+
stdout,
|
|
80622
|
+
stderr,
|
|
80623
|
+
...criterionResults ? { criterion_results: criterionResults } : {}
|
|
80624
|
+
};
|
|
80625
|
+
} finally {
|
|
80626
|
+
for (const temporary of [privateResultRoot, isolatedWorkspace]) {
|
|
80627
|
+
if (!temporary)
|
|
80628
|
+
continue;
|
|
80629
|
+
fs81.rmSync(temporary, { recursive: true, force: true });
|
|
80630
|
+
context.temporaryRoots.delete(temporary);
|
|
80631
|
+
}
|
|
80246
80632
|
}
|
|
80247
|
-
const commandRoot = evaluator.root === "workspace" ? spec.workspace_root : spec.tests_root;
|
|
80248
|
-
const command = { id: evaluator.id, ...evaluator.command };
|
|
80249
|
-
const result2 = await runCommand(command, commandRoot, spec, context, {
|
|
80250
|
-
BRAINBASE_BENCHMARK_WORKSPACE: spec.workspace_root,
|
|
80251
|
-
BRAINBASE_BENCHMARK_TESTS: spec.tests_root,
|
|
80252
|
-
BRAINBASE_BENCHMARK_LOGS: spec.logs_root,
|
|
80253
|
-
BRAINBASE_BENCHMARK_FINAL_OUTPUT: frozenEvidence.finalOutputPath,
|
|
80254
|
-
BRAINBASE_BENCHMARK_TRAJECTORY: frozenEvidence.trajectoryPath
|
|
80255
|
-
});
|
|
80256
|
-
const stdout = await writeLog(spec.logs_root, `${evaluator.id}.stdout.log`, result2.stdout, spec);
|
|
80257
|
-
const stderr = await writeLog(spec.logs_root, `${evaluator.id}.stderr.log`, result2.stderr, spec);
|
|
80258
|
-
const verdict = result2.exitCode === 0;
|
|
80259
|
-
return {
|
|
80260
|
-
...base2,
|
|
80261
|
-
status: verdict ? "passed" : "failed",
|
|
80262
|
-
verdict,
|
|
80263
|
-
duration_ms: result2.durationMs,
|
|
80264
|
-
details: { exit_code: result2.exitCode },
|
|
80265
|
-
stdout,
|
|
80266
|
-
stderr
|
|
80267
|
-
};
|
|
80268
80633
|
}
|
|
80269
80634
|
async function executeEvaluate(spec, context) {
|
|
80270
80635
|
await downloadInputReference(spec.staging_root, spec.evidence.final_output, context);
|
|
@@ -80336,6 +80701,11 @@ async function executeEvaluate(spec, context) {
|
|
|
80336
80701
|
outputs.push(artifact);
|
|
80337
80702
|
context.outputs.push(artifact);
|
|
80338
80703
|
}
|
|
80704
|
+
for (const candidateOutput of spec.candidate_outputs) {
|
|
80705
|
+
const copied = await copyCandidateOutput(candidateOutput, manifest, spec, context);
|
|
80706
|
+
outputs.push(...copied);
|
|
80707
|
+
context.outputs.push(...copied);
|
|
80708
|
+
}
|
|
80339
80709
|
if (spec.capture_workspace_archive) {
|
|
80340
80710
|
const regularFiles = manifest.filter((entry) => entry.kind !== "symlink").map((entry) => entry.path);
|
|
80341
80711
|
const archive = path88.join(spec.logs_root, "candidate-workspace.tar.gz");
|
|
@@ -80363,8 +80733,9 @@ async function executeEvaluate(spec, context) {
|
|
|
80363
80733
|
for (const evaluator of executionOrder) {
|
|
80364
80734
|
assertBudget(context);
|
|
80365
80735
|
const started = Date.now();
|
|
80736
|
+
let requiredResultError;
|
|
80366
80737
|
try {
|
|
80367
|
-
const evaluated = await evaluateOne(evaluator, spec, finalOutput.buffer.toString("utf8"), trajectory, { finalOutputPath, trajectoryPath }, context);
|
|
80738
|
+
const evaluated = await evaluateOne(evaluator, spec, manifest, finalOutput.buffer.toString("utf8"), trajectory, { finalOutputPath, trajectoryPath }, context);
|
|
80368
80739
|
assertBudget(context);
|
|
80369
80740
|
evaluators.push(evaluated);
|
|
80370
80741
|
context.evaluators.push(evaluated);
|
|
@@ -80376,6 +80747,11 @@ async function executeEvaluate(spec, context) {
|
|
|
80376
80747
|
outputs.push(evaluated.stderr);
|
|
80377
80748
|
context.outputs.push(evaluated.stderr);
|
|
80378
80749
|
}
|
|
80750
|
+
if (evaluated.status === "errored" && evaluator.required) {
|
|
80751
|
+
const errorCode = typeof evaluated.details?.error_code === "string" ? evaluated.details.error_code : "evaluator_execution_failed";
|
|
80752
|
+
const errorMessage2 = typeof evaluated.details?.error_message === "string" ? evaluated.details.error_message : "required evaluator execution failed";
|
|
80753
|
+
requiredResultError = new BenchmarkPhaseError(errorCode, errorMessage2);
|
|
80754
|
+
}
|
|
80379
80755
|
} catch (error2) {
|
|
80380
80756
|
const normalized = stableError(error2);
|
|
80381
80757
|
const errored = {
|
|
@@ -80399,6 +80775,8 @@ async function executeEvaluate(spec, context) {
|
|
|
80399
80775
|
throw error2;
|
|
80400
80776
|
assertBudget(context);
|
|
80401
80777
|
}
|
|
80778
|
+
if (requiredResultError)
|
|
80779
|
+
throw requiredResultError;
|
|
80402
80780
|
}
|
|
80403
80781
|
await verifyRecordsUnchanged([...context.inputs, ...context.outputs.slice(0, frozenOutputCount)], spec);
|
|
80404
80782
|
if (!verifyOwnedDirectory(spec.tests_root, "tests", spec) || !verifyOwnedDirectory(spec.logs_root, "logs", spec)) {
|