agentv 5.1.0-next.1 → 5.2.0-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.
Files changed (38) hide show
  1. package/README.md +16 -12
  2. package/dist/{artifact-writer-IORG7CW5.js → artifact-writer-SN6UNL5G.js} +5 -5
  3. package/dist/{chunk-ZGPCX334.js → chunk-3S6A2RKR.js} +2803 -959
  4. package/dist/chunk-3S6A2RKR.js.map +1 -0
  5. package/dist/{chunk-GIRUNQGP.js → chunk-3X357HS4.js} +205 -153
  6. package/dist/chunk-3X357HS4.js.map +1 -0
  7. package/dist/{chunk-CBBBRTQ3.js → chunk-46K2OET3.js} +64 -3
  8. package/dist/chunk-46K2OET3.js.map +1 -0
  9. package/dist/{chunk-GJWPQXHN.js → chunk-ALVZQUZP.js} +104 -188
  10. package/dist/chunk-ALVZQUZP.js.map +1 -0
  11. package/dist/{chunk-AM2IPHKS.js → chunk-T4AD3H3Y.js} +236 -154
  12. package/dist/chunk-T4AD3H3Y.js.map +1 -0
  13. package/dist/cli.js +6 -6
  14. package/dist/dashboard/assets/{index-BSHoWrdr.js → index-DNgf3qJ2.js} +1 -1
  15. package/dist/dashboard/assets/{index-zvUKAkKn.css → index-D_bokML8.css} +1 -1
  16. package/dist/dashboard/assets/index-r_jSJmlw.js +121 -0
  17. package/dist/dashboard/index.html +2 -2
  18. package/dist/{dist-2D2GBHZV.js → dist-DEPJOMCA.js} +6 -8
  19. package/dist/index.js +6 -6
  20. package/dist/{interactive-V4SEHLNY.js → interactive-36ZNMQB2.js} +6 -6
  21. package/dist/skills/agentv-bench/SKILL.md +16 -12
  22. package/dist/skills/agentv-bench/references/eval-yaml-spec.md +15 -10
  23. package/dist/skills/agentv-bench/references/migrating-from-skill-creator.md +1 -1
  24. package/dist/skills/agentv-eval-migrations/references/breaking-changes.md +26 -27
  25. package/dist/skills/agentv-eval-writer/SKILL.md +86 -71
  26. package/dist/skills/agentv-eval-writer/references/eval.schema.json +772 -1367
  27. package/dist/{ts-eval-loader-SSPJVEHD-AL2A3V5Z.js → ts-eval-loader-OMG2JBHP-OP5RR7A3.js} +3 -2
  28. package/package.json +8 -2
  29. package/dist/chunk-AM2IPHKS.js.map +0 -1
  30. package/dist/chunk-CBBBRTQ3.js.map +0 -1
  31. package/dist/chunk-GIRUNQGP.js.map +0 -1
  32. package/dist/chunk-GJWPQXHN.js.map +0 -1
  33. package/dist/chunk-ZGPCX334.js.map +0 -1
  34. package/dist/dashboard/assets/index-BaLLxmVO.js +0 -121
  35. /package/dist/{artifact-writer-IORG7CW5.js.map → artifact-writer-SN6UNL5G.js.map} +0 -0
  36. /package/dist/{dist-2D2GBHZV.js.map → dist-DEPJOMCA.js.map} +0 -0
  37. /package/dist/{interactive-V4SEHLNY.js.map → interactive-36ZNMQB2.js.map} +0 -0
  38. /package/dist/{ts-eval-loader-SSPJVEHD-AL2A3V5Z.js.map → ts-eval-loader-OMG2JBHP-OP5RR7A3.js.map} +0 -0
@@ -1,7 +1,7 @@
1
1
  import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);
2
2
  import {
3
3
  writeArtifactsFromResults
4
- } from "./chunk-CBBBRTQ3.js";
4
+ } from "./chunk-46K2OET3.js";
5
5
  import {
6
6
  RunBudgetTracker,
7
7
  buildWipBranchName,
@@ -18,7 +18,7 @@ import {
18
18
  resolveResultsRepoRunsDir,
19
19
  setupWipWorktree,
20
20
  syncResultsRepoForProject
21
- } from "./chunk-GJWPQXHN.js";
21
+ } from "./chunk-ALVZQUZP.js";
22
22
  import {
23
23
  AGENTV_LOCAL_CONFIG_FILE_NAME,
24
24
  AGENTV_LOCAL_CONFIG_YML_FILE_NAME,
@@ -66,6 +66,7 @@ import {
66
66
  readTargetDefinitions,
67
67
  readTestSuiteMetadata,
68
68
  resolveConfigFieldReferences,
69
+ resolveEnvironmentRecipe,
69
70
  resolveFileReference,
70
71
  resolveResultsConfigForProject,
71
72
  resolveTargetDefinition,
@@ -82,7 +83,7 @@ import {
82
83
  traceEnvelopeToTraceSummary,
83
84
  traceEnvelopeToTranscriptMessages,
84
85
  writeInitialRunSummaryArtifact
85
- } from "./chunk-ZGPCX334.js";
86
+ } from "./chunk-3S6A2RKR.js";
86
87
 
87
88
  // src/commands/eval/shared.ts
88
89
  import { constants } from "node:fs";
@@ -345,7 +346,7 @@ async function findRepoRoot(start) {
345
346
  // package.json
346
347
  var package_default = {
347
348
  name: "agentv",
348
- version: "5.1.0-next.1",
349
+ version: "5.2.0-next.1",
349
350
  description: "CLI entry point for AgentV",
350
351
  type: "module",
351
352
  repository: {
@@ -386,7 +387,7 @@ var package_default = {
386
387
  yaml: "^2.8.3"
387
388
  },
388
389
  peerDependencies: {
389
- "@anthropic-ai/claude-agent-sdk": "^0.2.88",
390
+ "@anthropic-ai/claude-agent-sdk": "^0.2.89",
390
391
  "@github/copilot-sdk": "^1.0.3",
391
392
  "@openai/codex-sdk": "^0.136.0",
392
393
  "@earendil-works/pi-coding-agent": "^0.74.0"
@@ -405,6 +406,12 @@ var package_default = {
405
406
  optional: true
406
407
  }
407
408
  },
409
+ optionalDependencies: {
410
+ "@anthropic-ai/claude-agent-sdk": "^0.2.89",
411
+ "@github/copilot-sdk": "^1.0.3",
412
+ "@openai/codex-sdk": "^0.136.0",
413
+ "@earendil-works/pi-coding-agent": "^0.74.0"
414
+ },
408
415
  devDependencies: {
409
416
  "@agentv/core": "workspace:*",
410
417
  "@agentv/sdk": "workspace:*",
@@ -867,6 +874,9 @@ function readGradingAssertionResults(record) {
867
874
  );
868
875
  }
869
876
  function readNestedGradingScores(record) {
877
+ if (Array.isArray(record.component_results)) {
878
+ return record.component_results;
879
+ }
870
880
  if (Array.isArray(record.scores)) {
871
881
  return record.scores;
872
882
  }
@@ -878,14 +888,56 @@ function readNestedGradingScores(record) {
878
888
  }
879
889
  return void 0;
880
890
  }
891
+ function componentLabel(component) {
892
+ const assertion = component.assertion;
893
+ if (assertion && typeof assertion === "object" && !Array.isArray(assertion)) {
894
+ const record = assertion;
895
+ for (const key of ["value", "name", "id", "type"]) {
896
+ const value = record[key];
897
+ if (typeof value === "string" && value.trim().length > 0) {
898
+ return value;
899
+ }
900
+ }
901
+ }
902
+ return typeof component.reason === "string" ? component.reason : "grading component";
903
+ }
904
+ function mapComponentAssertion(component) {
905
+ return {
906
+ text: componentLabel(component),
907
+ passed: component.pass === true,
908
+ evidence: typeof component.reason === "string" ? component.reason : void 0
909
+ };
910
+ }
911
+ function collectComponentAssertions(value) {
912
+ if (!Array.isArray(value)) {
913
+ return [];
914
+ }
915
+ return value.flatMap((component) => {
916
+ if (!component || typeof component !== "object" || Array.isArray(component)) {
917
+ return [];
918
+ }
919
+ const record = component;
920
+ const nested = collectComponentAssertions(record.component_results);
921
+ return nested.length > 0 ? nested : [mapComponentAssertion(record)];
922
+ });
923
+ }
881
924
  function mapGradingEvaluator(evaluator) {
882
- const verdict = evaluator.verdict === "pass" || evaluator.verdict === "fail" || evaluator.verdict === "skip" ? evaluator.verdict : void 0;
925
+ const pass = typeof evaluator.pass === "boolean" ? evaluator.pass : evaluator.verdict === "pass" || typeof evaluator.score === "number" && evaluator.score >= 0.8;
926
+ const verdict = pass ? "pass" : "fail";
883
927
  const details = evaluator.details && typeof evaluator.details === "object" && !Array.isArray(evaluator.details) ? evaluator.details : void 0;
928
+ const assertion = evaluator.assertion && typeof evaluator.assertion === "object" && !Array.isArray(evaluator.assertion) ? evaluator.assertion : void 0;
884
929
  return {
885
- name: String(evaluator.name ?? ""),
886
- type: String(evaluator.type ?? ""),
930
+ name: String(assertion?.name ?? assertion?.id ?? evaluator.name ?? componentLabel(evaluator)),
931
+ type: String(assertion?.type ?? evaluator.type ?? "llm-grader"),
887
932
  score: typeof evaluator.score === "number" ? evaluator.score : 0,
888
- assertions: readGradingAssertionResults(evaluator) ?? [],
933
+ reason: typeof evaluator.reason === "string" ? evaluator.reason : void 0,
934
+ assertions: (() => {
935
+ const nestedAssertions = collectComponentAssertions(evaluator.component_results);
936
+ if (nestedAssertions.length > 0) {
937
+ return nestedAssertions;
938
+ }
939
+ return readGradingAssertionResults(evaluator) ?? [mapComponentAssertion(evaluator)];
940
+ })(),
889
941
  scores: mapGradingEvaluators(readNestedGradingScores(evaluator)),
890
942
  weight: typeof evaluator.weight === "number" ? evaluator.weight : void 0,
891
943
  verdict,
@@ -1004,9 +1056,10 @@ function hydrateManifestRecord(baseDir, record, options) {
1004
1056
  const metrics = readOptionalJson(baseDir, record.metrics_path);
1005
1057
  const timing = metrics ?? readOptionalJson(baseDir, record.timing_path);
1006
1058
  const testId = record.test_id ?? "unknown";
1007
- const gradingAssertions = grading ? readGradingAssertionResults(grading) : void 0;
1059
+ const gradingAssertions = grading ? collectComponentAssertions(grading.component_results) : void 0;
1060
+ const gradingRecord = grading;
1008
1061
  const gradingScores = mapGradingEvaluators(
1009
- grading?.graders ?? grading?.evaluators
1062
+ gradingRecord?.component_results ?? gradingRecord?.graders ?? gradingRecord?.evaluators
1010
1063
  );
1011
1064
  return {
1012
1065
  timestamp: record.timestamp,
@@ -2837,10 +2890,10 @@ var KNOWN_TOP_LEVEL_FIELDS = /* @__PURE__ */ new Set([
2837
2890
  "input",
2838
2891
  "input_files",
2839
2892
  "prompts",
2840
- "imports",
2841
2893
  "tests",
2842
2894
  "graders",
2843
2895
  "defaults",
2896
+ "environment",
2844
2897
  "target",
2845
2898
  "targets",
2846
2899
  "model",
@@ -2867,7 +2920,6 @@ var KNOWN_TOP_LEVEL_FIELDS = /* @__PURE__ */ new Set([
2867
2920
  "governance"
2868
2921
  ]);
2869
2922
  var KNOWN_INCLUDE_FIELDS = /* @__PURE__ */ new Set(["include", "type", "select", "run"]);
2870
- var KNOWN_IMPORT_FIELDS = /* @__PURE__ */ new Set(["path", "select", "run"]);
2871
2923
  var KNOWN_RUN_OVERRIDE_FIELDS = /* @__PURE__ */ new Set(["threshold", "repeat", "timeout_seconds", "budget_usd"]);
2872
2924
  var KNOWN_DEFAULT_TEST_FIELDS = /* @__PURE__ */ new Set([
2873
2925
  "vars",
@@ -2907,6 +2959,10 @@ var KNOWN_TEST_EXECUTION_FIELDS = /* @__PURE__ */ new Set([
2907
2959
  "workspace"
2908
2960
  ]);
2909
2961
  var REMOVED_TOP_LEVEL_FIELDS = /* @__PURE__ */ new Map([
2962
+ [
2963
+ "imports",
2964
+ "Top-level 'imports' is not supported. Run eval files directly with CLI multi-file selection and tags for grouping. For raw case files, use tests: file://... or string entries under tests. For reusable config, use prompts: file://..., default_test: file://..., and environment: file://... for coding-agent testbeds."
2965
+ ],
2910
2966
  [
2911
2967
  "expected_output",
2912
2968
  "Top-level 'expected_output' has been removed from authored eval YAML. Put reference answers in default_test.vars.expected_output or tests[].vars.expected_output and consume them with an explicit assertion such as { type: 'llm-rubric', value: 'Matches the reference answer: {{ expected_output }}' }."
@@ -2966,6 +3022,7 @@ var KNOWN_TEST_FIELDS = /* @__PURE__ */ new Set([
2966
3022
  "threshold",
2967
3023
  "execution",
2968
3024
  "run",
3025
+ "environment",
2969
3026
  "workspace",
2970
3027
  "metadata",
2971
3028
  "conversation_id",
@@ -2979,6 +3036,17 @@ var KNOWN_TEST_FIELDS = /* @__PURE__ */ new Set([
2979
3036
  "window_size"
2980
3037
  ]);
2981
3038
  var SUPPORTED_WORKSPACE_REPO_FIELDS = /* @__PURE__ */ new Set(["path", "repo", "commit", "ancestor", "sparse"]);
3039
+ var KNOWN_REMOVED_WORKSPACE_FIELDS = /* @__PURE__ */ new Set([
3040
+ "template",
3041
+ "repos",
3042
+ "scope",
3043
+ "docker",
3044
+ "hooks",
3045
+ "env",
3046
+ "mode",
3047
+ "isolation",
3048
+ "path"
3049
+ ]);
2982
3050
  var REMOVED_TEST_FIELDS = /* @__PURE__ */ new Map([]);
2983
3051
  REMOVED_TEST_FIELDS.set(
2984
3052
  "input",
@@ -3108,13 +3176,15 @@ async function validateEvalFile(filePath) {
3108
3176
  });
3109
3177
  }
3110
3178
  }
3179
+ await validateEnvironmentConfig(parsed.environment, absolutePath, errors, "environment");
3111
3180
  await validateSuiteWorkspaceConfigs(parsed, absolutePath, errors);
3181
+ validateTargetTestbedFields(parsed.target, "target", absolutePath, errors);
3182
+ validateTargetsTestbedFields(parsed.targets, "targets", absolutePath, errors);
3112
3183
  validateAuthoredWorkers(parsed, absolutePath, errors);
3113
3184
  validateExecutionPolicy(parsed.execution, "execution", absolutePath, errors);
3114
3185
  validateEvaluateOptions(parsed.evaluate_options, "evaluate_options", absolutePath, errors);
3115
3186
  validateAssertArray(parsed.assert, "assert", absolutePath, errors, customAssertionTypes);
3116
3187
  validateDefaultTest(parsed.default_test, absolutePath, errors, customAssertionTypes);
3117
- await validateImportsField(parsed.imports, absolutePath, errors);
3118
3188
  const cases = parsed.tests;
3119
3189
  const hasImports = collectImportEntries(parsed).length > 0;
3120
3190
  const hasScenarios = Array.isArray(parsed.scenarios);
@@ -3144,7 +3214,7 @@ async function validateEvalFile(filePath) {
3144
3214
  severity: "error",
3145
3215
  filePath: absolutePath,
3146
3216
  location: "tests",
3147
- message: "Missing or invalid 'tests' field (must be an array or a file path string, unless imports are provided)"
3217
+ message: "Missing or invalid 'tests' field (must be an array or a file path string, unless scenarios are provided)"
3148
3218
  });
3149
3219
  return {
3150
3220
  valid: errors.length === 0,
@@ -3264,6 +3334,12 @@ async function validateEvalFile(filePath) {
3264
3334
  );
3265
3335
  validateRunOverride(evalCase.run, `${location}.run`, absolutePath, errors);
3266
3336
  validateTestOptions(evalCase.options, `${location}.options`, absolutePath, errors);
3337
+ await validateEnvironmentConfig(
3338
+ evalCase.environment,
3339
+ absolutePath,
3340
+ errors,
3341
+ `${location}.environment`
3342
+ );
3267
3343
  validateConversationMode(evalCase, location, absolutePath, errors);
3268
3344
  await validateWorkspaceConfig(
3269
3345
  evalCase.workspace,
@@ -3292,6 +3368,43 @@ async function validateSuiteWorkspaceConfigs(parsed, absolutePath, errors) {
3292
3368
  );
3293
3369
  }
3294
3370
  }
3371
+ async function validateEnvironmentConfig(environment, evalFilePath, errors, location) {
3372
+ if (environment === void 0) {
3373
+ return;
3374
+ }
3375
+ try {
3376
+ await resolveEnvironmentRecipe(environment, path22.dirname(evalFilePath), location);
3377
+ } catch (error) {
3378
+ errors.push({
3379
+ severity: "error",
3380
+ filePath: evalFilePath,
3381
+ location,
3382
+ message: error.message
3383
+ });
3384
+ }
3385
+ }
3386
+ function validateTargetTestbedFields(target, location, filePath, errors) {
3387
+ if (!isObject(target)) {
3388
+ return;
3389
+ }
3390
+ for (const field of ["environment", "container", "install"]) {
3391
+ if (target[field] === void 0) {
3392
+ continue;
3393
+ }
3394
+ errors.push({
3395
+ severity: "error",
3396
+ filePath,
3397
+ location: `${location}.${field}`,
3398
+ message: field === "environment" ? "Target definitions cannot include environment; author environment at suite/test/case scope." : `Target definitions cannot include ${field}; use an environment recipe for testbed setup.`
3399
+ });
3400
+ }
3401
+ }
3402
+ function validateTargetsTestbedFields(targets, location, filePath, errors) {
3403
+ const entries = Array.isArray(targets) ? targets : targets === void 0 ? [] : [targets];
3404
+ entries.forEach((entry, index) => {
3405
+ validateTargetTestbedFields(entry, `${location}[${index}]`, filePath, errors);
3406
+ });
3407
+ }
3295
3408
  function validateTestExecutionFields(caseExecution, filePath, errors, location) {
3296
3409
  for (const key of Object.keys(caseExecution)) {
3297
3410
  if (key === "workers") {
@@ -3413,87 +3526,11 @@ function rejectRuntimeWorkspaceConfig(workspace, filePath, errors, location) {
3413
3526
  severity: "error",
3414
3527
  filePath,
3415
3528
  location,
3416
- message: `${location} has been removed from eval YAML. Put machine-local workspace_path in .agentv/config.local.yaml under execution, or pass --workspace-path. Keep portable task setup in top-level workspace.`
3529
+ message: `${location} has been removed from eval YAML. Put machine-local workspace_path in .agentv/config.local.yaml under execution, or pass --workspace-path. Keep portable coding-agent testbed setup in environment.`
3417
3530
  });
3418
3531
  }
3419
- function importEntryPath(value) {
3420
- if (typeof value === "string" && value.trim().length > 0) {
3421
- return value.trim();
3422
- }
3423
- if (!isObject(value)) {
3424
- return void 0;
3425
- }
3426
- return typeof value.path === "string" && value.path.trim().length > 0 ? value.path.trim() : void 0;
3427
- }
3428
- async function validateImportsField(imports, filePath, errors) {
3429
- if (imports === void 0) {
3430
- return;
3431
- }
3432
- if (!isObject(imports)) {
3433
- errors.push({
3434
- severity: "error",
3435
- filePath,
3436
- location: "imports",
3437
- message: "Invalid 'imports' field. Use imports.suites and/or imports.tests."
3438
- });
3439
- return;
3440
- }
3441
- for (const key of Object.keys(imports)) {
3442
- if (key !== "suites" && key !== "tests") {
3443
- errors.push({
3444
- severity: "warning",
3445
- filePath,
3446
- location: `imports.${key}`,
3447
- message: `Unknown imports field '${key}'. Use imports.suites or imports.tests.`
3448
- });
3449
- }
3450
- }
3451
- await validateImportGroup(imports.suites, "suite", "imports.suites", filePath, errors);
3452
- await validateImportGroup(imports.tests, "tests", "imports.tests", filePath, errors);
3453
- }
3454
- async function validateImportGroup(group, type, location, filePath, errors) {
3455
- if (group === void 0) {
3456
- return;
3457
- }
3458
- const entries = Array.isArray(group) ? group : [group];
3459
- for (let i = 0; i < entries.length; i++) {
3460
- const entry = entries[i];
3461
- const entryLocation = `${location}[${i}]`;
3462
- const entryPath = importEntryPath(entry);
3463
- if (!entryPath) {
3464
- errors.push({
3465
- severity: "error",
3466
- filePath,
3467
- location: entryLocation,
3468
- message: "Invalid import entry. Use a path string or an object with a non-empty 'path'."
3469
- });
3470
- continue;
3471
- }
3472
- if (type === "tests" && !/\.eval\.ya?ml$/i.test(entryPath)) {
3473
- await validateRawCaseImportPath(entryPath, filePath, `${entryLocation}.path`, errors);
3474
- }
3475
- if (isObject(entry)) {
3476
- for (const key of Object.keys(entry)) {
3477
- if (!KNOWN_IMPORT_FIELDS.has(key)) {
3478
- errors.push({
3479
- severity: "warning",
3480
- filePath,
3481
- location: `${entryLocation}.${key}`,
3482
- message: `Unknown field '${key}'. This field will be ignored.`
3483
- });
3484
- }
3485
- }
3486
- validateIncludeSelect(entry.select, `${entryLocation}.select`, filePath, errors);
3487
- validateRunOverride(entry.run, `${entryLocation}.run`, filePath, errors);
3488
- }
3489
- }
3490
- }
3491
3532
  function collectImportEntries(parsed) {
3492
3533
  const entries = [];
3493
- if (isObject(parsed.imports)) {
3494
- entries.push(...collectImportGroup(parsed.imports.suites, "suite", "imports.suites"));
3495
- entries.push(...collectImportGroup(parsed.imports.tests, "tests", "imports.tests"));
3496
- }
3497
3534
  const tests = parsed.tests;
3498
3535
  if (Array.isArray(tests)) {
3499
3536
  for (let i = 0; i < tests.length; i++) {
@@ -3516,42 +3553,24 @@ function collectImportEntries(parsed) {
3516
3553
  }
3517
3554
  return entries;
3518
3555
  }
3519
- function collectImportGroup(group, type, location) {
3520
- if (group === void 0) {
3521
- return [];
3522
- }
3523
- const entries = Array.isArray(group) ? group : [group];
3524
- return entries.flatMap((entry, index) => {
3525
- const pathValue = importEntryPath(entry);
3526
- return pathValue ? [
3527
- {
3528
- path: pathValue,
3529
- type,
3530
- location: `${location}[${index}].path`,
3531
- ...isObject(entry) && entry.select !== void 0 ? { select: entry.select } : {},
3532
- ...isObject(entry) && entry.run !== void 0 ? { run: entry.run } : {}
3533
- }
3534
- ] : [];
3535
- });
3536
- }
3537
3556
  async function validateCompositionDiagnostics(filePath, parsed, errors) {
3538
- const imports = collectImportEntries(parsed);
3539
- if (imports.length === 0) {
3557
+ const includeEntries = collectImportEntries(parsed);
3558
+ if (includeEntries.length === 0) {
3540
3559
  return;
3541
3560
  }
3542
3561
  const parentHasRuntime = hasWrapperRuntimeControls(parsed);
3543
- const hasSuiteImport = imports.some((entry) => entry.type === "suite");
3562
+ const hasSuiteImport = includeEntries.some((entry) => entry.type === "suite");
3544
3563
  if (hasSuiteImport) {
3545
3564
  for (const location of parentWorkspaceLocations(parsed)) {
3546
3565
  errors.push({
3547
3566
  severity: "error",
3548
3567
  filePath,
3549
3568
  location,
3550
- message: "Parent workspace is not allowed when an eval imports suites with type: suite. A wrapper eval owns target and run controls, while imported suites own task environment. Move workspace into the child suite, or import raw cases with type: tests when you intentionally want parent workspace context."
3569
+ message: location === "environment" ? "Parent environment is not allowed with legacy tests[].include suite entries. Run eval files directly, or use tests: file://... for raw cases that should use the parent environment." : "Parent workspace is not allowed with legacy tests[].include suite entries. Run eval files directly, or use tests: file://... for raw cases that should use the parent workspace."
3551
3570
  });
3552
3571
  }
3553
3572
  }
3554
- for (const entry of imports) {
3573
+ for (const entry of includeEntries) {
3555
3574
  const resolvedSuites = await resolveSuiteIncludePaths(entry.path, path22.dirname(filePath));
3556
3575
  if (entry.type === "suite") {
3557
3576
  for (const resolvedSuite of resolvedSuites) {
@@ -3567,7 +3586,7 @@ async function validateCompositionDiagnostics(filePath, parsed, errors) {
3567
3586
  severity: "warning",
3568
3587
  filePath,
3569
3588
  location: entry.location,
3570
- message: parentHasRuntime ? `Imported suite '${resolvedSuite.displayPath}' defines ${runtimeFields.join(", ")}, but child target and run controls are ignored for imports.suites. The parent eval owns wrapper target and run controls; move them to the parent eval or use import run overrides for per-case thresholds, timeouts, and budgets.` : `Imported suite '${resolvedSuite.displayPath}' defines ${runtimeFields.join(", ")}, but child target and run controls are ignored for imports.suites. The parent eval owns wrapper target and run controls, and this parent has none, so no child target or run controls are applied. Add parent target/run controls or use import run overrides for per-case thresholds, timeouts, and budgets.`
3589
+ message: parentHasRuntime ? `Imported suite '${resolvedSuite.displayPath}' defines ${runtimeFields.join(", ")}, but child target and run controls are ignored by legacy tests[].include suite imports. Prefer running eval files directly with CLI multi-file selection and tags.` : `Imported suite '${resolvedSuite.displayPath}' defines ${runtimeFields.join(", ")}, but child target and run controls are ignored by legacy tests[].include suite imports. Prefer running eval files directly with CLI multi-file selection and tags.`
3571
3590
  });
3572
3591
  }
3573
3592
  continue;
@@ -3581,7 +3600,7 @@ async function validateCompositionDiagnostics(filePath, parsed, errors) {
3581
3600
  severity: "warning",
3582
3601
  filePath,
3583
3602
  location: entry.location,
3584
- message: `imports.tests imports raw cases from eval suite '${resolvedSuite.displayPath}' and drops suite context, including child workspace, input, assertions, metadata, target, and run controls. Parent suite context applies. Use imports.suites to preserve child test and workspace semantics.`
3603
+ message: `Legacy tests[].include with type: tests imports raw cases from eval suite '${resolvedSuite.displayPath}' and drops suite context, including child environment, workspace, input, assertions, metadata, target, and run controls. Prefer tests: file://... for raw case files.`
3585
3604
  });
3586
3605
  }
3587
3606
  }
@@ -3620,6 +3639,9 @@ function parentWorkspaceLocations(parsed) {
3620
3639
  if (parsed.workspace !== void 0) {
3621
3640
  locations.push("workspace");
3622
3641
  }
3642
+ if (parsed.environment !== void 0) {
3643
+ locations.push("environment");
3644
+ }
3623
3645
  if (isObject(parsed.execution) && parsed.execution.workspace !== void 0) {
3624
3646
  locations.push("execution.workspace");
3625
3647
  }
@@ -3634,12 +3656,11 @@ async function readImportedSuite(filePath) {
3634
3656
  }
3635
3657
  }
3636
3658
  function validateIncludeEntry(entry, location, filePath, errors) {
3637
- const mode = entry.type === "suite" ? "suites" : entry.type === "tests" ? "tests" : void 0;
3638
3659
  errors.push({
3639
3660
  severity: "warning",
3640
3661
  filePath,
3641
3662
  location,
3642
- message: mode ? `tests[].include is deprecated. Use imports.${mode} entries with path instead.` : "tests[].include is deprecated. Use imports.suites or imports.tests entries with path instead."
3663
+ message: entry.type === "suite" ? "tests[].include with type: suite is deprecated. Run eval files directly with CLI multi-file selection and tags instead." : "tests[].include is deprecated. Use tests: file://... or string entries inside tests: for raw case files."
3643
3664
  });
3644
3665
  for (const key of Object.keys(entry)) {
3645
3666
  if (!KNOWN_INCLUDE_FIELDS.has(key)) {
@@ -4041,35 +4062,18 @@ async function validateWorkspaceConfig(workspace, evalFilePath, errors, location
4041
4062
  if (workspace === void 0) {
4042
4063
  return;
4043
4064
  }
4044
- if (isObject(workspace)) {
4045
- validateWorkspaceRepoConfig(workspace, evalFilePath, errors, location);
4046
- return;
4047
- }
4048
- if (typeof workspace !== "string") {
4049
- return;
4050
- }
4051
- const workspacePath = path22.resolve(path22.dirname(evalFilePath), workspace);
4052
- try {
4053
- const workspaceContent = await readFile22(workspacePath, "utf8");
4054
- const parsedWorkspace = interpolateEnv(parseYamlValue(workspaceContent), process.env);
4055
- if (!isObject(parsedWorkspace)) {
4056
- errors.push({
4057
- severity: "error",
4058
- filePath: evalFilePath,
4059
- location,
4060
- message: `External workspace file must contain a YAML object: ${workspace}`
4061
- });
4062
- return;
4063
- }
4064
- validateWorkspaceRepoConfig(parsedWorkspace, workspacePath, errors, location);
4065
- } catch (error) {
4066
- const message = error instanceof Error ? error.message : String(error);
4065
+ if (typeof workspace === "string") {
4067
4066
  errors.push({
4068
4067
  severity: "error",
4069
4068
  filePath: evalFilePath,
4070
4069
  location,
4071
- message: `Failed to load external workspace file '${workspace}': ${message}`
4070
+ message: `${location} has been removed from public eval YAML. Use environment: file://... for reusable coding-agent testbed recipes.`
4072
4071
  });
4072
+ return;
4073
+ }
4074
+ if (isObject(workspace)) {
4075
+ validateWorkspaceRepoConfig(workspace, evalFilePath, errors, location);
4076
+ return;
4073
4077
  }
4074
4078
  }
4075
4079
  function validateWorkspaceRepoConfig(workspace, filePath, errors, location) {
@@ -4078,12 +4082,79 @@ function validateWorkspaceRepoConfig(workspace, filePath, errors, location) {
4078
4082
  const afterEachHook = isObject(hooks) ? hooks.after_each : void 0;
4079
4083
  const scope = workspace.scope;
4080
4084
  const docker = workspace.docker;
4085
+ let hasRemovedTestbedField = false;
4086
+ if (Object.keys(workspace).length === 0) {
4087
+ errors.push({
4088
+ severity: "error",
4089
+ filePath,
4090
+ location,
4091
+ message: "workspace has been removed from public eval YAML. Use environment for coding-agent testbed setup."
4092
+ });
4093
+ return;
4094
+ }
4095
+ if ("template" in workspace) {
4096
+ hasRemovedTestbedField = true;
4097
+ errors.push({
4098
+ severity: "error",
4099
+ filePath,
4100
+ location: `${location}.template`,
4101
+ message: "workspace.template has been removed from public eval YAML. Use environment.workdir and environment.setup for authored testbed setup."
4102
+ });
4103
+ }
4104
+ if ("repos" in workspace) {
4105
+ hasRemovedTestbedField = true;
4106
+ errors.push({
4107
+ severity: "error",
4108
+ filePath,
4109
+ location: `${location}.repos`,
4110
+ message: "workspace.repos has been removed from public eval YAML. Use environment.setup.command argv to materialize repositories."
4111
+ });
4112
+ }
4113
+ if ("scope" in workspace) {
4114
+ hasRemovedTestbedField = true;
4115
+ errors.push({
4116
+ severity: "error",
4117
+ filePath,
4118
+ location: `${location}.scope`,
4119
+ message: "workspace.scope has been removed from public eval YAML. Use environment at suite/test scope and let runtime manage workspace lifetime."
4120
+ });
4121
+ }
4122
+ if ("docker" in workspace) {
4123
+ hasRemovedTestbedField = true;
4124
+ errors.push({
4125
+ severity: "error",
4126
+ filePath,
4127
+ location: `${location}.docker`,
4128
+ message: "workspace.docker has been removed from public eval YAML. Use environment.type: docker with image or context."
4129
+ });
4130
+ }
4131
+ if ("hooks" in workspace) {
4132
+ hasRemovedTestbedField = true;
4133
+ errors.push({
4134
+ severity: "error",
4135
+ filePath,
4136
+ location: `${location}.hooks`,
4137
+ message: "workspace.hooks has been removed from public eval YAML. Use environment.setup for testbed setup and extensions for lifecycle instrumentation."
4138
+ });
4139
+ }
4140
+ if ("env" in workspace) {
4141
+ hasRemovedTestbedField = true;
4142
+ errors.push({
4143
+ severity: "error",
4144
+ filePath,
4145
+ location: `${location}.env`,
4146
+ message: "workspace.env has been removed from public eval YAML. Use top-level env for provider/eval variables or environment.env for environment-scoped variables."
4147
+ });
4148
+ }
4149
+ if (hasRemovedTestbedField) {
4150
+ return;
4151
+ }
4081
4152
  if ("mode" in workspace) {
4082
4153
  errors.push({
4083
4154
  severity: "error",
4084
4155
  filePath,
4085
4156
  location: `${location}.mode`,
4086
- message: "workspace.mode has been removed from eval YAML. Use workspace.scope: suite|attempt."
4157
+ message: "workspace.mode has been removed from eval YAML. Use --workspace-path or execution.workspace_path for machine-local existing directories, and environment for portable testbed setup."
4087
4158
  });
4088
4159
  }
4089
4160
  if ("isolation" in workspace) {
@@ -4091,7 +4162,7 @@ function validateWorkspaceRepoConfig(workspace, filePath, errors, location) {
4091
4162
  severity: "error",
4092
4163
  filePath,
4093
4164
  location: `${location}.isolation`,
4094
- message: "workspace.isolation has been removed. Use workspace.scope: suite|attempt."
4165
+ message: "workspace.isolation has been removed from eval YAML. Use environment at suite/test scope and let AgentV manage runtime isolation."
4095
4166
  });
4096
4167
  }
4097
4168
  if ("path" in workspace) {
@@ -4099,7 +4170,18 @@ function validateWorkspaceRepoConfig(workspace, filePath, errors, location) {
4099
4170
  severity: "error",
4100
4171
  filePath,
4101
4172
  location: `${location}.path`,
4102
- message: "workspace.path has been removed from eval YAML. Put existing workspace paths in .agentv/config.local.yaml execution.workspace_path or pass --workspace-path."
4173
+ message: "workspace.path has been removed from eval YAML. Use environment.workdir for portable testbed cwd; put existing machine-local workspace paths in .agentv/config.local.yaml execution.workspace_path or pass --workspace-path."
4174
+ });
4175
+ }
4176
+ for (const key of Object.keys(workspace)) {
4177
+ if (KNOWN_REMOVED_WORKSPACE_FIELDS.has(key)) {
4178
+ continue;
4179
+ }
4180
+ errors.push({
4181
+ severity: "error",
4182
+ filePath,
4183
+ location: `${location}.${key}`,
4184
+ message: `${location}.${key} has been removed from public eval YAML. Use environment for portable coding-agent testbed setup.`
4103
4185
  });
4104
4186
  }
4105
4187
  if (scope !== void 0 && scope !== "suite" && scope !== "attempt") {
@@ -4412,11 +4494,11 @@ async function validateSuiteImportCycles(filePath, parsed, errors) {
4412
4494
  await validateSuiteImportCyclesFromParsed(filePath, parsed, [root], errors);
4413
4495
  }
4414
4496
  async function validateSuiteImportCyclesFromParsed(currentFilePath, parsed, stack, errors) {
4415
- const imports = collectImportEntries(parsed);
4416
- if (imports.length === 0) {
4497
+ const includeEntries = collectImportEntries(parsed);
4498
+ if (includeEntries.length === 0) {
4417
4499
  return;
4418
4500
  }
4419
- for (const entry of imports) {
4501
+ for (const entry of includeEntries) {
4420
4502
  if (entry.type !== "suite") {
4421
4503
  continue;
4422
4504
  }
@@ -5092,7 +5174,7 @@ function validateUnknownSettings(target, provider, absolutePath, location, error
5092
5174
  severity: "warning",
5093
5175
  filePath: absolutePath,
5094
5176
  location: `${location}.${key}`,
5095
- message: "workspace_template has been removed from targets. Use eval-level workspace.template instead."
5177
+ message: "workspace_template has been removed from targets. Use eval-level environment.workdir and environment.setup instead."
5096
5178
  });
5097
5179
  continue;
5098
5180
  }
@@ -7445,7 +7527,7 @@ async function runEvalCommand(input) {
7445
7527
  const resolvedExperiment = resolveExperimentForRun(options.experiment);
7446
7528
  const evalPathInputs = input.testFiles.length > 0 ? [...input.testFiles] : [];
7447
7529
  if (evalPathInputs.length === 0 && process.stdin.isTTY) {
7448
- const { launchInteractiveWizard } = await import("./interactive-V4SEHLNY.js");
7530
+ const { launchInteractiveWizard } = await import("./interactive-36ZNMQB2.js");
7449
7531
  await launchInteractiveWizard();
7450
7532
  return void 0;
7451
7533
  }
@@ -7785,7 +7867,7 @@ async function runEvalCommand(input) {
7785
7867
  });
7786
7868
  let transcriptProviderFactory;
7787
7869
  if (options.transcript) {
7788
- const { TranscriptProvider } = await import("./dist-2D2GBHZV.js");
7870
+ const { TranscriptProvider } = await import("./dist-DEPJOMCA.js");
7789
7871
  const transcriptProvider = await TranscriptProvider.fromFile(options.transcript);
7790
7872
  const totalTests = [...fileMetadata.values()].reduce(
7791
7873
  (sum, meta) => sum + meta.testCases.length,
@@ -8051,7 +8133,7 @@ ${formatRequiredVersionFailureNote(requiredVersionCheck)}`);
8051
8133
  const sourceTests = activeSourceTests;
8052
8134
  const taskBundleTargets = buildTaskBundleTargetSelections(activeTestFiles, fileMetadata);
8053
8135
  if (isResumeAppend) {
8054
- const { writePerTestArtifacts } = await import("./artifact-writer-IORG7CW5.js");
8136
+ const { writePerTestArtifacts } = await import("./artifact-writer-SN6UNL5G.js");
8055
8137
  await writePerTestArtifacts(allResults, runDir, {
8056
8138
  experiment: normalizeExperimentName(options.experiment),
8057
8139
  runId: path12.basename(runDir),
@@ -8269,4 +8351,4 @@ export {
8269
8351
  filterByCategory,
8270
8352
  runEvalCommand
8271
8353
  };
8272
- //# sourceMappingURL=chunk-AM2IPHKS.js.map
8354
+ //# sourceMappingURL=chunk-T4AD3H3Y.js.map