agentv 5.3.1-next.1 → 5.3.2-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 (66) hide show
  1. package/README.md +52 -44
  2. package/dist/{artifact-writer-7NBCOAYC.js → artifact-writer-KJEOROKQ.js} +5 -5
  3. package/dist/{chunk-ELCJ23K4.js → chunk-6262OKXM.js} +2856 -2404
  4. package/dist/chunk-6262OKXM.js.map +1 -0
  5. package/dist/chunk-AQ5BIAXF.js +604 -0
  6. package/dist/chunk-AQ5BIAXF.js.map +1 -0
  7. package/dist/chunk-BV5VQLI2.js +2 -0
  8. package/dist/{chunk-LXBI3SPX.js → chunk-JGSRUJZQ.js} +46 -20
  9. package/dist/chunk-JGSRUJZQ.js.map +1 -0
  10. package/dist/chunk-MMDLXYBX.js +721 -0
  11. package/dist/chunk-MMDLXYBX.js.map +1 -0
  12. package/dist/{chunk-LKGARI3W.js → chunk-QSK3PC44.js} +812 -570
  13. package/dist/chunk-QSK3PC44.js.map +1 -0
  14. package/dist/chunk-TEEXVJWM.js +2 -0
  15. package/dist/{chunk-RKE7SSET.js → chunk-WIAJ7JAV.js} +186 -64
  16. package/dist/chunk-WIAJ7JAV.js.map +1 -0
  17. package/dist/cli.d.ts +1 -0
  18. package/dist/cli.js +17517 -10
  19. package/dist/cli.js.map +1 -1
  20. package/dist/config.d.ts +2 -0
  21. package/dist/config.js +14 -0
  22. package/dist/config.js.map +1 -0
  23. package/dist/contracts-DsZmZLl8.d.ts +742 -0
  24. package/dist/contracts.d.ts +2 -0
  25. package/dist/contracts.js +28 -0
  26. package/dist/contracts.js.map +1 -0
  27. package/dist/dashboard/assets/{index-CbEMiJSb.js → index-BfqOlLOF.js} +1 -1
  28. package/dist/dashboard/assets/index-Bh8lpGce.css +1 -0
  29. package/dist/dashboard/assets/index-oPR3ywQb.js +121 -0
  30. package/dist/dashboard/index.html +2 -2
  31. package/dist/{dist-NMXMI5SK.js → dist-A3SGR7TW.js} +16 -16
  32. package/dist/dist-A3SGR7TW.js.map +1 -0
  33. package/dist/index.d.ts +4 -0
  34. package/dist/index.js +137 -18
  35. package/dist/{interactive-BN527UV3.js → interactive-DL7N2C7K.js} +24 -24
  36. package/dist/interactive-DL7N2C7K.js.map +1 -0
  37. package/dist/provider.d.ts +2 -0
  38. package/dist/provider.js +24 -0
  39. package/dist/provider.js.map +1 -0
  40. package/dist/sdk.d.ts +802 -0
  41. package/dist/sdk.js +145 -0
  42. package/dist/sdk.js.map +1 -0
  43. package/dist/skills/agentv-eval-migrations/references/breaking-changes.md +17 -18
  44. package/dist/skills/agentv-eval-writer/SKILL.md +27 -15
  45. package/dist/skills/agentv-eval-writer/references/custom-evaluators.md +5 -5
  46. package/dist/skills/agentv-eval-writer/references/eval.schema.json +5402 -4639
  47. package/dist/skills/agentv-eval-writer/references/python-helpers.md +2 -2
  48. package/dist/skills/agentv-eval-writer/references/rubric-evaluator.md +19 -2
  49. package/dist/templates/.agentv/providers.yaml +42 -0
  50. package/dist/templates/.env.example +2 -2
  51. package/dist/{ts-eval-loader-2RFVZHCT-7CZ3DCDD.js → ts-eval-loader-3G5GEAEC-6F52JLPP.js} +3 -3
  52. package/dist/ts-eval-loader-3G5GEAEC-6F52JLPP.js.map +1 -0
  53. package/package.json +29 -4
  54. package/dist/chunk-ASIGJIOJ.js +0 -17993
  55. package/dist/chunk-ASIGJIOJ.js.map +0 -1
  56. package/dist/chunk-ELCJ23K4.js.map +0 -1
  57. package/dist/chunk-LKGARI3W.js.map +0 -1
  58. package/dist/chunk-LXBI3SPX.js.map +0 -1
  59. package/dist/chunk-RKE7SSET.js.map +0 -1
  60. package/dist/dashboard/assets/index-DTA6-l7q.js +0 -121
  61. package/dist/dashboard/assets/index-D_bokML8.css +0 -1
  62. package/dist/interactive-BN527UV3.js.map +0 -1
  63. package/dist/templates/.agentv/targets.yaml +0 -97
  64. /package/dist/{artifact-writer-7NBCOAYC.js.map → artifact-writer-KJEOROKQ.js.map} +0 -0
  65. /package/dist/{dist-NMXMI5SK.js.map → chunk-BV5VQLI2.js.map} +0 -0
  66. /package/dist/{ts-eval-loader-2RFVZHCT-7CZ3DCDD.js.map → chunk-TEEXVJWM.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-RKE7SSET.js";
4
+ } from "./chunk-WIAJ7JAV.js";
5
5
  import {
6
6
  RunBudgetTracker,
7
7
  buildWipBranchName,
@@ -18,12 +18,12 @@ import {
18
18
  resolveResultsRepoRunsDir,
19
19
  setupWipWorktree,
20
20
  syncResultsRepoForProject
21
- } from "./chunk-LXBI3SPX.js";
21
+ } from "./chunk-JGSRUJZQ.js";
22
22
  import {
23
23
  AGENTV_LOCAL_CONFIG_FILE_NAME,
24
24
  AGENTV_LOCAL_CONFIG_YML_FILE_NAME,
25
25
  CLI_PLACEHOLDERS,
26
- COMMON_TARGET_SETTINGS,
26
+ COMMON_PROVIDER_SETTINGS,
27
27
  DEFAULT_EVAL_PATTERNS,
28
28
  DEFAULT_THRESHOLD,
29
29
  KNOWN_PROVIDERS,
@@ -51,8 +51,9 @@ import {
51
51
  interpolateEnv,
52
52
  isAgentVConfigFileName,
53
53
  isGraderKind,
54
+ isScenarioFileReference,
54
55
  isTypeScriptEvalConfigFileName,
55
- listTargetNames,
56
+ listProviderLabels,
56
57
  loadCasesFromDirectory,
57
58
  loadCasesFromFile,
58
59
  loadConfig,
@@ -61,17 +62,19 @@ import {
61
62
  loadTestSuiteFromYamlObject,
62
63
  normalizeComposableConfigGraph,
63
64
  normalizeMetricsArtifactWire,
65
+ normalizeProviderDefinition,
64
66
  normalizeResultRow,
65
- normalizeTargetDefinition,
66
67
  parseJsonlResults,
67
68
  parseYamlValue,
68
- readTargetDefinitions,
69
+ readProviderDefinitions,
69
70
  readTestSuiteMetadata,
70
71
  resolveConfigFieldReferences,
71
72
  resolveEnvironmentRecipe,
72
73
  resolveFileReference,
74
+ resolveProviderDefinition,
75
+ resolveProviderDefinitionEnvironments,
73
76
  resolveResultsConfigForProject,
74
- resolveTargetDefinition,
77
+ resolveScenarioFileReference,
75
78
  runEvaluation,
76
79
  serializeEvaluationResultWire,
77
80
  shouldEnableCache,
@@ -86,7 +89,7 @@ import {
86
89
  traceEnvelopeToTranscriptMessages,
87
90
  typeScriptEvalConfigGlob,
88
91
  writeInitialRunSummaryArtifact
89
- } from "./chunk-ELCJ23K4.js";
92
+ } from "./chunk-6262OKXM.js";
90
93
 
91
94
  // src/commands/eval/shared.ts
92
95
  import { constants } from "node:fs";
@@ -346,83 +349,6 @@ async function findRepoRoot(start) {
346
349
  return fallback;
347
350
  }
348
351
 
349
- // package.json
350
- var package_default = {
351
- name: "agentv",
352
- version: "5.3.1-next.1",
353
- description: "CLI entry point for AgentV",
354
- type: "module",
355
- repository: {
356
- type: "git",
357
- url: "https://github.com/EntityProcess/agentv.git"
358
- },
359
- homepage: "https://agentv.dev",
360
- bugs: {
361
- url: "https://github.com/EntityProcess/agentv/issues"
362
- },
363
- bin: {
364
- agentv: "./dist/cli.js"
365
- },
366
- files: ["dist", "README.md"],
367
- scripts: {
368
- dev: "bun src/cli.ts",
369
- build: "(cd ../../packages/sdk && bun run build) && tsup && bun run copy-readme",
370
- "copy-readme": `bun -e "import { cpSync } from 'fs'; cpSync('../../README.md', 'README.md')"`,
371
- prepublishOnly: `node -e "if(process.env.ALLOW_PUBLISH!=='1'){console.error('ERROR: Use bun run publish:next, then bun run promote:latest');process.exit(1)}"`,
372
- typecheck: "(cd ../../packages/sdk && bun run build) && tsc --noEmit",
373
- lint: "biome check .",
374
- format: "biome format --write .",
375
- fix: "biome check --write .",
376
- test: "(cd ../../packages/sdk && bun run build) && bun test",
377
- "test:watch": "bun test --watch"
378
- },
379
- dependencies: {
380
- "@hono/node-server": "^1.19.11",
381
- "@inquirer/prompts": "^8.2.1",
382
- "@earendil-works/pi-ai": "^0.74.0",
383
- "cmd-ts": "^0.14.3",
384
- dotenv: "^16.4.5",
385
- "fast-glob": "^3.3.3",
386
- hono: "^4.12.9",
387
- json5: "^2.2.3",
388
- micromatch: "^4.0.8",
389
- semver: "^7.7.4",
390
- yaml: "^2.8.3"
391
- },
392
- peerDependencies: {
393
- "@anthropic-ai/claude-agent-sdk": "^0.2.89",
394
- "@github/copilot-sdk": "^1.0.3",
395
- "@openai/codex-sdk": "^0.136.0",
396
- "@earendil-works/pi-coding-agent": "^0.74.0"
397
- },
398
- peerDependenciesMeta: {
399
- "@anthropic-ai/claude-agent-sdk": {
400
- optional: true
401
- },
402
- "@github/copilot-sdk": {
403
- optional: true
404
- },
405
- "@openai/codex-sdk": {
406
- optional: true
407
- },
408
- "@earendil-works/pi-coding-agent": {
409
- optional: true
410
- }
411
- },
412
- optionalDependencies: {
413
- "@anthropic-ai/claude-agent-sdk": "^0.2.89",
414
- "@github/copilot-sdk": "^1.0.3",
415
- "@openai/codex-sdk": "^0.136.0",
416
- "@earendil-works/pi-coding-agent": "^0.74.0"
417
- },
418
- devDependencies: {
419
- "@agentv/core": "workspace:*",
420
- "@agentv/sdk": "workspace:*",
421
- "@types/semver": "^7.7.1",
422
- execa: "^9.3.0"
423
- }
424
- };
425
-
426
352
  // src/commands/eval/result-layout.ts
427
353
  import { existsSync, readdirSync, statSync } from "node:fs";
428
354
  import path2 from "node:path";
@@ -560,11 +486,17 @@ function relativeRunPathFromCwd(cwd, runDir) {
560
486
  return parts.join(path2.posix.sep);
561
487
  }
562
488
 
563
- // src/utils/targets.ts
489
+ // src/utils/providers.ts
564
490
  import { constants as constants2 } from "node:fs";
565
- import { access as access2 } from "node:fs/promises";
491
+ import { access as access2, stat as stat2 } from "node:fs/promises";
566
492
  import path3 from "node:path";
567
- var TARGET_FILE_CANDIDATES = [
493
+ var PROVIDER_FILE_CANDIDATES = [
494
+ "providers.yaml",
495
+ "providers.yml",
496
+ path3.join(".agentv", "providers.yaml"),
497
+ path3.join(".agentv", "providers.yml")
498
+ ];
499
+ var LEGACY_TARGET_FILE_CANDIDATES = [
568
500
  "targets.yaml",
569
501
  "targets.yml",
570
502
  path3.join(".agentv", "targets.yaml"),
@@ -578,20 +510,71 @@ async function fileExists(filePath) {
578
510
  return false;
579
511
  }
580
512
  }
581
- async function discoverTargetsFile(options) {
582
- const { explicitPath, testFilePath, repoRoot, cwd } = options;
513
+ async function pathKind(filePath) {
514
+ try {
515
+ const info = await stat2(filePath);
516
+ if (info.isDirectory()) {
517
+ return "directory";
518
+ }
519
+ if (info.isFile()) {
520
+ return "file";
521
+ }
522
+ return void 0;
523
+ } catch {
524
+ return void 0;
525
+ }
526
+ }
527
+ function isLegacyTargetFile(filePath) {
528
+ return /^targets\.ya?ml$/i.test(path3.basename(filePath));
529
+ }
530
+ function removedTargetsFileError(filePath) {
531
+ return new Error(
532
+ `Authored targets.yaml files were removed. Rename ${filePath} to providers.yaml and use --providers to specify it explicitly.`
533
+ );
534
+ }
535
+ async function findProviderFileInDirectory(directory) {
536
+ for (const candidate of PROVIDER_FILE_CANDIDATES) {
537
+ const fullPath = path3.join(directory, candidate);
538
+ if (await pathKind(fullPath) === "file") {
539
+ return fullPath;
540
+ }
541
+ }
542
+ return void 0;
543
+ }
544
+ async function findLegacyGeneratedTargetFileInDirectory(directory) {
545
+ for (const candidate of LEGACY_TARGET_FILE_CANDIDATES) {
546
+ const fullPath = path3.join(directory, candidate);
547
+ if (await pathKind(fullPath) === "file") {
548
+ return fullPath;
549
+ }
550
+ }
551
+ return void 0;
552
+ }
553
+ async function discoverProvidersFile(options) {
554
+ const { explicitPath, testFilePath, repoRoot, cwd, allowLegacyTargetFiles = false } = options;
583
555
  if (explicitPath) {
584
556
  const resolvedExplicit = path3.resolve(explicitPath);
585
- if (await fileExists(resolvedExplicit)) {
557
+ const kind = await pathKind(resolvedExplicit);
558
+ if (kind === "file") {
559
+ if (!allowLegacyTargetFiles && isLegacyTargetFile(resolvedExplicit)) {
560
+ throw removedTargetsFileError(resolvedExplicit);
561
+ }
586
562
  return resolvedExplicit;
587
563
  }
588
- for (const candidate of TARGET_FILE_CANDIDATES) {
589
- const nested = path3.join(resolvedExplicit, candidate);
590
- if (await fileExists(nested)) {
591
- return nested;
564
+ if (kind === "directory") {
565
+ const providerFile = await findProviderFileInDirectory(resolvedExplicit);
566
+ if (providerFile) {
567
+ return providerFile;
568
+ }
569
+ const legacyTargetFile = await findLegacyGeneratedTargetFileInDirectory(resolvedExplicit);
570
+ if (legacyTargetFile) {
571
+ if (allowLegacyTargetFiles) {
572
+ return legacyTargetFile;
573
+ }
574
+ throw removedTargetsFileError(legacyTargetFile);
592
575
  }
593
576
  }
594
- throw new Error(`targets.yaml not found at provided path: ${resolvedExplicit}`);
577
+ throw new Error(`providers.yaml not found at provided path: ${resolvedExplicit}`);
595
578
  }
596
579
  const directories = [...buildDirectoryChain(testFilePath, repoRoot)];
597
580
  const resolvedCwd = path3.resolve(cwd);
@@ -599,14 +582,23 @@ async function discoverTargetsFile(options) {
599
582
  directories.push(resolvedCwd);
600
583
  }
601
584
  for (const directory of directories) {
602
- for (const candidate of TARGET_FILE_CANDIDATES) {
603
- const fullPath = path3.join(directory, candidate);
604
- if (await fileExists(fullPath)) {
605
- return fullPath;
585
+ const providerFile = await findProviderFileInDirectory(directory);
586
+ if (providerFile) {
587
+ return providerFile;
588
+ }
589
+ }
590
+ for (const directory of directories) {
591
+ const legacyTargetFile = await findLegacyGeneratedTargetFileInDirectory(directory);
592
+ if (legacyTargetFile) {
593
+ if (allowLegacyTargetFiles) {
594
+ return legacyTargetFile;
606
595
  }
596
+ throw removedTargetsFileError(legacyTargetFile);
607
597
  }
608
598
  }
609
- throw new Error("Unable to locate targets.yaml. Use --targets to specify the file explicitly.");
599
+ throw new Error(
600
+ "Unable to locate providers.yaml. Use --providers to specify the file explicitly."
601
+ );
610
602
  }
611
603
 
612
604
  // src/commands/eval/discover.ts
@@ -650,7 +642,7 @@ function filterByCategory(files, category) {
650
642
  import { constants as constants4, existsSync as existsSync5, mkdirSync } from "node:fs";
651
643
  import { access as access5, readFile as readFile8 } from "node:fs/promises";
652
644
  import { createRequire as createNodeRequire } from "node:module";
653
- import path12 from "node:path";
645
+ import path13 from "node:path";
654
646
  import { pathToFileURL } from "node:url";
655
647
 
656
648
  // ../../node_modules/.bun/yocto-queue@1.2.2/node_modules/yocto-queue/index.js
@@ -794,6 +786,110 @@ function validateConcurrency(concurrency) {
794
786
 
795
787
  // src/version-check.ts
796
788
  import { coerce, satisfies, validRange } from "semver";
789
+
790
+ // package.json
791
+ var package_default = {
792
+ name: "agentv",
793
+ version: "5.3.2-next.1",
794
+ description: "CLI entry point for AgentV",
795
+ type: "module",
796
+ repository: {
797
+ type: "git",
798
+ url: "https://github.com/EntityProcess/agentv.git"
799
+ },
800
+ homepage: "https://agentv.dev",
801
+ bugs: {
802
+ url: "https://github.com/EntityProcess/agentv/issues"
803
+ },
804
+ bin: {
805
+ agentv: "./dist/cli.js"
806
+ },
807
+ main: "./dist/index.js",
808
+ types: "./dist/index.d.ts",
809
+ exports: {
810
+ ".": {
811
+ types: "./dist/index.d.ts",
812
+ import: "./dist/index.js"
813
+ },
814
+ "./sdk": {
815
+ types: "./dist/sdk.d.ts",
816
+ import: "./dist/sdk.js"
817
+ },
818
+ "./provider": {
819
+ types: "./dist/provider.d.ts",
820
+ import: "./dist/provider.js"
821
+ },
822
+ "./contracts": {
823
+ types: "./dist/contracts.d.ts",
824
+ import: "./dist/contracts.js"
825
+ },
826
+ "./config": {
827
+ types: "./dist/config.d.ts",
828
+ import: "./dist/config.js"
829
+ },
830
+ "./package.json": "./package.json"
831
+ },
832
+ files: ["dist", "README.md"],
833
+ scripts: {
834
+ dev: "bun src/cli.ts",
835
+ build: "tsup && bun run copy-readme",
836
+ "copy-readme": `bun -e "import { cpSync } from 'fs'; cpSync('../../README.md', 'README.md')"`,
837
+ prepublishOnly: `node -e "if(process.env.ALLOW_PUBLISH!=='1'){console.error('ERROR: Use bun run publish:next, then bun run promote:latest');process.exit(1)}"`,
838
+ typecheck: "tsc --noEmit",
839
+ lint: "biome check .",
840
+ format: "biome format --write .",
841
+ fix: "biome check --write .",
842
+ test: "bun test",
843
+ "test:watch": "bun test --watch"
844
+ },
845
+ dependencies: {
846
+ "@hono/node-server": "^1.19.11",
847
+ "@inquirer/prompts": "^8.2.1",
848
+ "@earendil-works/pi-ai": "^0.74.0",
849
+ "cmd-ts": "^0.14.3",
850
+ dotenv: "^16.4.5",
851
+ "fast-glob": "^3.3.3",
852
+ hono: "^4.12.9",
853
+ json5: "^2.2.3",
854
+ micromatch: "^4.0.8",
855
+ semver: "^7.7.4",
856
+ yaml: "^2.8.3"
857
+ },
858
+ peerDependencies: {
859
+ "@anthropic-ai/claude-agent-sdk": "^0.2.89",
860
+ "@github/copilot-sdk": "^1.0.3",
861
+ "@openai/codex-sdk": "^0.136.0",
862
+ "@earendil-works/pi-coding-agent": "^0.74.0"
863
+ },
864
+ peerDependenciesMeta: {
865
+ "@anthropic-ai/claude-agent-sdk": {
866
+ optional: true
867
+ },
868
+ "@github/copilot-sdk": {
869
+ optional: true
870
+ },
871
+ "@openai/codex-sdk": {
872
+ optional: true
873
+ },
874
+ "@earendil-works/pi-coding-agent": {
875
+ optional: true
876
+ }
877
+ },
878
+ optionalDependencies: {
879
+ "@anthropic-ai/claude-agent-sdk": "^0.2.89",
880
+ "@github/copilot-sdk": "^1.0.3",
881
+ "@openai/codex-sdk": "^0.136.0",
882
+ "@earendil-works/pi-coding-agent": "^0.74.0"
883
+ },
884
+ devDependencies: {
885
+ "@agentv/core": "workspace:*",
886
+ "@agentv/sdk": "workspace:*",
887
+ "@types/semver": "^7.7.1",
888
+ execa: "^9.3.0"
889
+ }
890
+ };
891
+
892
+ // src/version-check.ts
797
893
  var ANSI_YELLOW = "\x1B[33m";
798
894
  var ANSI_RED = "\x1B[31m";
799
895
  var ANSI_RESET = "\x1B[0m";
@@ -858,24 +954,6 @@ function manifestBaseDir(indexPath) {
858
954
  const dir = path5.dirname(indexPath);
859
955
  return path5.basename(dir) === ".internal" ? path5.dirname(dir) : dir;
860
956
  }
861
- function mapGradingAssertions(value) {
862
- if (!Array.isArray(value)) {
863
- return void 0;
864
- }
865
- return value.map((assertion) => {
866
- const record = assertion;
867
- return {
868
- text: String(record.text ?? ""),
869
- passed: Boolean(record.passed),
870
- evidence: typeof record.evidence === "string" ? record.evidence : void 0
871
- };
872
- });
873
- }
874
- function readGradingAssertionResults(record) {
875
- return mapGradingAssertions(
876
- Array.isArray(record.assertion_results) ? record.assertion_results : record.assertions
877
- );
878
- }
879
957
  function readNestedGradingScores(record) {
880
958
  if (Array.isArray(record.component_results)) {
881
959
  return record.component_results;
@@ -883,12 +961,6 @@ function readNestedGradingScores(record) {
883
961
  if (Array.isArray(record.scores)) {
884
962
  return record.scores;
885
963
  }
886
- if (Array.isArray(record.graders)) {
887
- return record.graders;
888
- }
889
- if (Array.isArray(record.evaluators)) {
890
- return record.evaluators;
891
- }
892
964
  return void 0;
893
965
  }
894
966
  function componentLabel(component) {
@@ -925,7 +997,7 @@ function collectComponentAssertions(value) {
925
997
  });
926
998
  }
927
999
  function mapGradingEvaluator(evaluator) {
928
- const pass = typeof evaluator.pass === "boolean" ? evaluator.pass : evaluator.verdict === "pass" || typeof evaluator.score === "number" && evaluator.score >= 0.8;
1000
+ const pass = evaluator.pass === true;
929
1001
  const verdict = pass ? "pass" : "fail";
930
1002
  const details = evaluator.details && typeof evaluator.details === "object" && !Array.isArray(evaluator.details) ? evaluator.details : void 0;
931
1003
  const assertion = evaluator.assertion && typeof evaluator.assertion === "object" && !Array.isArray(evaluator.assertion) ? evaluator.assertion : void 0;
@@ -939,7 +1011,7 @@ function mapGradingEvaluator(evaluator) {
939
1011
  if (nestedAssertions.length > 0) {
940
1012
  return nestedAssertions;
941
1013
  }
942
- return readGradingAssertionResults(evaluator) ?? [mapComponentAssertion(evaluator)];
1014
+ return [mapComponentAssertion(evaluator)];
943
1015
  })(),
944
1016
  scores: mapGradingEvaluators(readNestedGradingScores(evaluator)),
945
1017
  weight: typeof evaluator.weight === "number" ? evaluator.weight : void 0,
@@ -1063,9 +1135,7 @@ function hydrateManifestRecord(baseDir, record, options) {
1063
1135
  const testId = record.test_id ?? "unknown";
1064
1136
  const gradingAssertions = grading ? collectComponentAssertions(grading.component_results) : void 0;
1065
1137
  const gradingRecord = grading;
1066
- const gradingScores = mapGradingEvaluators(
1067
- gradingRecord?.component_results ?? gradingRecord?.graders ?? gradingRecord?.evaluators
1068
- );
1138
+ const gradingScores = mapGradingEvaluators(gradingRecord?.component_results);
1069
1139
  return {
1070
1140
  timestamp: record.timestamp,
1071
1141
  testId,
@@ -1081,11 +1151,7 @@ function hydrateManifestRecord(baseDir, record, options) {
1081
1151
  passed: assertion.passed,
1082
1152
  evidence: assertion.evidence
1083
1153
  })),
1084
- scores: (
1085
- // `evaluators` was renamed to `graders` in v4.13 — read both for backwards compat with old artifacts.
1086
- // TODO: remove `evaluators` fallback once old run directories are no longer in use.
1087
- gradingScores ?? record.scores
1088
- ),
1154
+ scores: gradingScores ?? record.scores,
1089
1155
  tokenUsage: metrics?.tokens ? {
1090
1156
  input: metrics.tokens.input,
1091
1157
  output: metrics.tokens.output,
@@ -1149,8 +1215,16 @@ function loadLightweightResults(sourceFile) {
1149
1215
  executionStatus: record.execution_status,
1150
1216
  error: record.error,
1151
1217
  costUsd: record.cost_usd,
1218
+ durationMs: record.duration_ms,
1219
+ tokenUsage: record.token_usage,
1152
1220
  timestamp: record.timestamp,
1153
- runtimeSource: record.runtime_source
1221
+ runtimeSource: record.runtime_source,
1222
+ resultDir: record.result_dir,
1223
+ outputPath: record.output_path,
1224
+ answerPath: record.answer_path,
1225
+ gradingPath: record.grading_path,
1226
+ transcriptPath: record.transcript_path,
1227
+ metricsPath: record.metrics_path
1154
1228
  }));
1155
1229
  }
1156
1230
 
@@ -1890,6 +1964,16 @@ function relativeRunPathFromManifestPath(relativeManifestPath) {
1890
1964
  const manifestDir = path7.posix.dirname(relativeManifestPath);
1891
1965
  return path7.posix.basename(manifestDir) === ".internal" ? path7.posix.dirname(manifestDir) : manifestDir;
1892
1966
  }
1967
+ function formatPendingMergeWarnings(pendingMerge) {
1968
+ if (!pendingMerge) {
1969
+ return [];
1970
+ }
1971
+ const { temp_branch, target_branch, compare_url } = pendingMerge;
1972
+ const mergeSuffix = compare_url ? `: ${compare_url}` : ".";
1973
+ return [
1974
+ `Warning: results were pushed to '${temp_branch}' instead \u2014 they are not lost. Merge that branch into ${target_branch} with a pull request${mergeSuffix}`
1975
+ ];
1976
+ }
1893
1977
  async function maybeAutoExportRunArtifacts(payload) {
1894
1978
  const config = await loadNormalizedResultsConfig(
1895
1979
  payload.cwd,
@@ -1914,6 +1998,9 @@ async function maybeAutoExportRunArtifacts(payload) {
1914
1998
  throw new Error(pushResult.block_reason ?? "Results branch push conflict");
1915
1999
  }
1916
2000
  console.warn(`Warning: skipping results export: ${pushResult.block_reason}`);
2001
+ for (const line of formatPendingMergeWarnings(pushResult.pending_merge)) {
2002
+ console.warn(line);
2003
+ }
1917
2004
  return "failed";
1918
2005
  }
1919
2006
  if (!pushResult.changed) {
@@ -2716,10 +2803,13 @@ function formatMatrixSummary(results) {
2716
2803
  return lines.join("\n");
2717
2804
  }
2718
2805
 
2806
+ // src/commands/eval/targets.ts
2807
+ import path12 from "node:path";
2808
+
2719
2809
  // ../../packages/core/dist/evaluation/validation/index.js
2720
2810
  import { readFile as readFile2 } from "node:fs/promises";
2721
2811
  import path11 from "node:path";
2722
- import { readFile as readFile22, readdir, realpath, stat as stat2 } from "node:fs/promises";
2812
+ import { readFile as readFile22, readdir, realpath, stat as stat3 } from "node:fs/promises";
2723
2813
  import path22 from "node:path";
2724
2814
  import fg3 from "fast-glob";
2725
2815
  import { readFile as readFile3 } from "node:fs/promises";
@@ -2740,6 +2830,10 @@ async function detectFileType(filePath) {
2740
2830
  const content = await readFile2(filePath, "utf8");
2741
2831
  const parsed = parseYamlValue(content);
2742
2832
  if (Array.isArray(parsed)) {
2833
+ const inferred = inferFileTypeFromPath(filePath);
2834
+ if (inferred === "targets") {
2835
+ return inferred;
2836
+ }
2743
2837
  return "cases";
2744
2838
  }
2745
2839
  if (typeof parsed !== "object" || parsed === null) {
@@ -2774,7 +2868,7 @@ function inferFileTypeFromPath(filePath) {
2774
2868
  if (isAgentVConfigFileName(basename)) {
2775
2869
  return "config";
2776
2870
  }
2777
- if (basename === "targets.yaml" || basename === "targets.yml") {
2871
+ if (basename === "providers.yaml" || basename === "providers.yml") {
2778
2872
  return "targets";
2779
2873
  }
2780
2874
  }
@@ -2801,6 +2895,7 @@ var ASSERTION_TYPES_WITH_ARRAY_VALUE = /* @__PURE__ */ new Set([
2801
2895
  var PROMPTFOO_ASSERTION_TYPES = /* @__PURE__ */ new Set([
2802
2896
  "assert-set",
2803
2897
  "llm-rubric",
2898
+ "agent-rubric",
2804
2899
  "javascript",
2805
2900
  "python",
2806
2901
  "webhook",
@@ -2814,11 +2909,9 @@ var REMOVED_ASSERTION_TYPE_REPLACEMENTS = /* @__PURE__ */ new Map([
2814
2909
  ["rubrics", "llm-rubric with value"],
2815
2910
  ["rubric", "llm-rubric with value"],
2816
2911
  ["script-grader", "script"],
2817
- ["code-judge", "script"],
2818
- ["llm-judge", "llm-grader"]
2912
+ ["code-judge", "script"]
2819
2913
  ]);
2820
2914
  var UNSUPPORTED_PROMPTFOO_ASSERTION_TYPES = /* @__PURE__ */ new Set([
2821
- "agent-rubric",
2822
2915
  "answer-relevance",
2823
2916
  "bleu",
2824
2917
  "classifier",
@@ -2911,6 +3004,9 @@ function staleToolTrajectoryMessage(value) {
2911
3004
  function staleAuthoredAssertionMessage(value) {
2912
3005
  if (typeof value.type !== "string") return void 0;
2913
3006
  const type = value.type.replace(/_/g, "-");
3007
+ if (type === "llm-grader" || type === "llm-judge") {
3008
+ return "Authored assertion type 'llm-grader' has been removed. Use 'llm-rubric' for free-form rubric checks or 'agent-rubric' for agentic rubric checks.";
3009
+ }
2914
3010
  if (type === "skill-trigger") return staleSkillTriggerMessage(value);
2915
3011
  if (type === "tool-trajectory") return staleToolTrajectoryMessage(value);
2916
3012
  return void 0;
@@ -2941,6 +3037,7 @@ var KNOWN_TOP_LEVEL_FIELDS = /* @__PURE__ */ new Set([
2941
3037
  "input_files",
2942
3038
  "prompts",
2943
3039
  "tests",
3040
+ "providers",
2944
3041
  "graders",
2945
3042
  "defaults",
2946
3043
  "environment",
@@ -2976,7 +3073,6 @@ var KNOWN_DEFAULT_TEST_FIELDS = /* @__PURE__ */ new Set([
2976
3073
  "provider",
2977
3074
  "providers",
2978
3075
  "prompts",
2979
- "provider_output",
2980
3076
  "assert",
2981
3077
  "assert_scoring_function",
2982
3078
  "options",
@@ -2994,8 +3090,6 @@ var KNOWN_EVALUATE_OPTION_FIELDS = /* @__PURE__ */ new Set([
2994
3090
  "max_eval_time_ms",
2995
3091
  "filter_range"
2996
3092
  ]);
2997
- var KNOWN_REPEAT_FIELDS = /* @__PURE__ */ new Set(["count", "strategy", "early_exit", "cost_limit_usd"]);
2998
- var KNOWN_REPEAT_STRATEGIES = /* @__PURE__ */ new Set(["pass_any", "pass_all", "mean", "confidence_interval"]);
2999
3093
  var KNOWN_TEST_EXECUTION_FIELDS = /* @__PURE__ */ new Set([
3000
3094
  "assert",
3001
3095
  "skip_defaults",
@@ -3009,9 +3103,13 @@ var KNOWN_TEST_EXECUTION_FIELDS = /* @__PURE__ */ new Set([
3009
3103
  "workspace"
3010
3104
  ]);
3011
3105
  var REMOVED_TOP_LEVEL_FIELDS = /* @__PURE__ */ new Map([
3106
+ [
3107
+ "experiment",
3108
+ "Top-level 'experiment' has been removed from authored eval YAML. Use tags.experiment in the eval file or CLI --experiment at run time."
3109
+ ],
3012
3110
  [
3013
3111
  "imports",
3014
- "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."
3112
+ "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 scenarios, use scenarios: [file://...]. For reusable config, use prompts: file://..., default_test: file://..., and environment: file://... for coding-agent testbeds."
3015
3113
  ],
3016
3114
  [
3017
3115
  "expected_output",
@@ -3025,14 +3123,15 @@ var REMOVED_TOP_LEVEL_FIELDS = /* @__PURE__ */ new Map([
3025
3123
  "workers",
3026
3124
  "'workers' has been removed from eval YAML. Set authored eval concurrency with evaluate_options.max_concurrency."
3027
3125
  ],
3028
- ["model", "Top-level 'model' is not part of eval YAML. Put model inside the target object."],
3126
+ ["model", "Top-level 'model' is not part of eval YAML. Put model inside providers[].config."],
3029
3127
  [
3030
3128
  "policy",
3031
3129
  "Top-level 'policy' is not part of eval YAML. Put repeat under evaluate_options.repeat, timeout_seconds and threshold at the top level, and budget_usd under evaluate_options."
3032
3130
  ],
3131
+ ["target", "Top-level 'target' has been removed. Use top-level 'providers' instead."],
3033
3132
  [
3034
- "providers",
3035
- "Top-level 'providers' is not a runtime alias in AgentV eval YAML. Use 'targets' for systems under test; provider names backend kind inside each target."
3133
+ "targets",
3134
+ "Top-level 'targets' has been removed. Use 'providers'; map targets[].id to providers[].label and targets[].provider to providers[].id."
3036
3135
  ],
3037
3136
  [
3038
3137
  "eval_cases",
@@ -3043,10 +3142,10 @@ var REMOVED_TOP_LEVEL_FIELDS = /* @__PURE__ */ new Map([
3043
3142
  "Top-level 'evalcases' has been removed from authored eval YAML. Use 'tests' instead."
3044
3143
  ],
3045
3144
  ["repeat", "Top-level 'repeat' has been removed. Use evaluate_options.repeat instead."],
3046
- ["runs", "Top-level 'runs' has been removed. Use evaluate_options.repeat.count instead."],
3145
+ ["runs", "Top-level 'runs' has been removed. Use a positive integer evaluate_options.repeat."],
3047
3146
  [
3048
3147
  "early_exit",
3049
- "Top-level 'early_exit' has been removed. Use evaluate_options.repeat.early_exit instead."
3148
+ "Top-level 'early_exit' has been removed. Use a positive integer evaluate_options.repeat."
3050
3149
  ],
3051
3150
  ["budget_usd", "Top-level 'budget_usd' has been removed. Use evaluate_options.budget_usd."],
3052
3151
  [
@@ -3057,8 +3156,8 @@ var REMOVED_TOP_LEVEL_FIELDS = /* @__PURE__ */ new Map([
3057
3156
  "preprocessors",
3058
3157
  "Top-level 'preprocessors' has been removed from authored eval YAML. Use default_test.options.transform or assertion-level transform instead."
3059
3158
  ],
3060
- ["providerPromptMap", "Top-level 'providerPromptMap' is not supported. Use 'targets'."],
3061
- ["provider_prompt_map", "Top-level 'provider_prompt_map' is not supported. Use 'targets'."]
3159
+ ["providerPromptMap", "Top-level 'providerPromptMap' is not supported. Use 'providers'."],
3160
+ ["provider_prompt_map", "Top-level 'provider_prompt_map' is not supported. Use 'providers'."]
3062
3161
  ]);
3063
3162
  var DEPRECATED_TOP_LEVEL_FIELDS = /* @__PURE__ */ new Map([
3064
3163
  ["evaluator", "'evaluator' is deprecated. Use 'assert' instead."]
@@ -3071,7 +3170,6 @@ var KNOWN_TEST_FIELDS = /* @__PURE__ */ new Set([
3071
3170
  "provider",
3072
3171
  "providers",
3073
3172
  "prompts",
3074
- "provider_output",
3075
3173
  "input",
3076
3174
  "input_files",
3077
3175
  "assert",
@@ -3111,6 +3209,10 @@ REMOVED_TEST_FIELDS.set(
3111
3209
  "input",
3112
3210
  "tests[].input has been removed from authored eval YAML. Put prompt text or chat/system/user messages in top-level 'prompts' and put row-specific data in tests[].vars."
3113
3211
  );
3212
+ REMOVED_TEST_FIELDS.set(
3213
+ "provider_output",
3214
+ "tests[].provider_output is not supported in authored AgentV YAML. Use an explicit deterministic target such as provider: cli for fixed outputs, or use a replay/fixture target for captured provider responses."
3215
+ );
3114
3216
  REMOVED_TEST_FIELDS.set(
3115
3217
  "preprocessors",
3116
3218
  "tests[].preprocessors has been removed from authored eval YAML. Use tests[].options.transform or assertion-level transform instead."
@@ -3215,14 +3317,6 @@ async function validateEvalFile(filePath) {
3215
3317
  };
3216
3318
  }
3217
3319
  validateMetadata(parsed, absolutePath, errors);
3218
- if (parsed.experiment !== void 0 && typeof parsed.experiment !== "string") {
3219
- errors.push({
3220
- severity: "error",
3221
- filePath: absolutePath,
3222
- location: "experiment",
3223
- message: "Top-level 'experiment' must be a string run/result grouping label."
3224
- });
3225
- }
3226
3320
  for (const key of Object.keys(parsed)) {
3227
3321
  const removedMessage = REMOVED_TOP_LEVEL_FIELDS.get(key);
3228
3322
  if (removedMessage) {
@@ -3252,6 +3346,7 @@ async function validateEvalFile(filePath) {
3252
3346
  }
3253
3347
  }
3254
3348
  await validateEnvironmentConfig(parsed.environment, absolutePath, errors, "environment");
3349
+ await validateProviderEnvironmentFields(parsed.providers, "providers", absolutePath, errors);
3255
3350
  await validateSuiteWorkspaceConfigs(parsed, absolutePath, errors);
3256
3351
  validateTargetTestbedFields(parsed.target, "target", absolutePath, errors);
3257
3352
  validateTargetsTestbedFields(parsed.targets, "targets", absolutePath, errors);
@@ -3260,10 +3355,15 @@ async function validateEvalFile(filePath) {
3260
3355
  validateEvaluateOptions(parsed.evaluate_options, "evaluate_options", absolutePath, errors);
3261
3356
  validateAssertArray(parsed.assert, "assert", absolutePath, errors, customAssertionTypes);
3262
3357
  validateDefaultTest(parsed.default_test, absolutePath, errors, customAssertionTypes);
3263
- await validateScenarios(parsed.scenarios, parsed, absolutePath, errors, customAssertionTypes);
3358
+ const expandedScenarios = await expandScenariosForValidation(
3359
+ parsed.scenarios,
3360
+ absolutePath,
3361
+ errors
3362
+ );
3363
+ await validateScenarios(expandedScenarios, parsed, absolutePath, errors, customAssertionTypes);
3264
3364
  const cases = parsed.tests;
3265
3365
  const hasImports = collectImportEntries(parsed).length > 0;
3266
- const hasScenarios = Array.isArray(parsed.scenarios);
3366
+ const hasScenarios = Array.isArray(expandedScenarios);
3267
3367
  if (typeof cases === "string") {
3268
3368
  await validateRawCaseImportPath(cases, absolutePath, "tests", errors);
3269
3369
  await validateCompositionDiagnostics(absolutePath, parsed, errors);
@@ -3390,7 +3490,7 @@ async function validateEvalFile(filePath) {
3390
3490
  suiteInputFiles: skipDefaults ? void 0 : parsed.input_files
3391
3491
  }) !== void 0 : false;
3392
3492
  validateInputField(evalCase.input, `${location}.input`, absolutePath, errors, {
3393
- required: !hasPromptMdFallback && evalCase.prompts === void 0 && parsed.prompts === void 0 && evalCase.provider_output === void 0
3493
+ required: !hasPromptMdFallback && evalCase.prompts === void 0 && parsed.prompts === void 0
3394
3494
  });
3395
3495
  const expectedOutputField = evalCase.expected_output;
3396
3496
  if (expectedOutputField !== void 0) {
@@ -3436,7 +3536,7 @@ async function validateEvalFile(filePath) {
3436
3536
  async function validateTypeScriptEvalConfigFile(filePath) {
3437
3537
  const absolutePath = path22.resolve(filePath);
3438
3538
  try {
3439
- const { loadTsEvalSuite } = await import("./ts-eval-loader-2RFVZHCT-7CZ3DCDD.js");
3539
+ const { loadTsEvalSuite } = await import("./ts-eval-loader-3G5GEAEC-6F52JLPP.js");
3440
3540
  await loadTsEvalSuite(absolutePath, process.cwd());
3441
3541
  return {
3442
3542
  valid: true,
@@ -3501,6 +3601,31 @@ function validateTargetTestbedFields(target, location, filePath, errors) {
3501
3601
  });
3502
3602
  }
3503
3603
  }
3604
+ async function validateProviderEnvironmentFields(providers, location, filePath, errors) {
3605
+ const entries = Array.isArray(providers) ? providers : providers === void 0 ? [] : [providers];
3606
+ for (let index = 0; index < entries.length; index++) {
3607
+ const entry = entries[index];
3608
+ if (!isObject(entry)) {
3609
+ continue;
3610
+ }
3611
+ await validateEnvironmentConfig(
3612
+ entry.environment,
3613
+ filePath,
3614
+ errors,
3615
+ `${location}[${index}].environment`
3616
+ );
3617
+ for (const field of ["container", "install"]) {
3618
+ if (entry[field] !== void 0) {
3619
+ errors.push({
3620
+ severity: "error",
3621
+ filePath,
3622
+ location: `${location}[${index}].${field}`,
3623
+ message: `Provider definitions cannot include ${field}; use an environment recipe for testbed setup.`
3624
+ });
3625
+ }
3626
+ }
3627
+ }
3628
+ }
3504
3629
  function validateTargetsTestbedFields(targets, location, filePath, errors) {
3505
3630
  const entries = Array.isArray(targets) ? targets : targets === void 0 ? [] : [targets];
3506
3631
  entries.forEach((entry, index) => {
@@ -3688,7 +3813,7 @@ async function validateCompositionDiagnostics(filePath, parsed, errors) {
3688
3813
  severity: "warning",
3689
3814
  filePath,
3690
3815
  location: entry.location,
3691
- 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.`
3816
+ message: parentHasRuntime ? `Imported suite '${resolvedSuite.displayPath}' defines ${runtimeFields.join(", ")}, but child providers 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 providers and run controls are ignored by legacy tests[].include suite imports. Prefer running eval files directly with CLI multi-file selection and tags.`
3692
3817
  });
3693
3818
  }
3694
3819
  continue;
@@ -3710,7 +3835,9 @@ async function validateCompositionDiagnostics(filePath, parsed, errors) {
3710
3835
  }
3711
3836
  var WRAPPER_RUNTIME_CONTROL_FIELDS = [
3712
3837
  "experiment",
3838
+ "providers",
3713
3839
  "target",
3840
+ "targets",
3714
3841
  "repeat",
3715
3842
  "timeout_seconds",
3716
3843
  "evaluate_options",
@@ -3906,10 +4033,18 @@ function validateDefaultTest(defaultTest, filePath, errors, customAssertionTypes
3906
4033
  severity: "error",
3907
4034
  filePath,
3908
4035
  location: `default_test.${key}`,
3909
- message: "Invalid default_test field. Supported fields: vars, provider, providers, prompts, provider_output, assert, assert_scoring_function, options, threshold, metadata."
4036
+ message: "Invalid default_test field. Supported fields: vars, provider, providers, prompts, assert, assert_scoring_function, options, threshold, metadata."
3910
4037
  });
3911
4038
  }
3912
4039
  }
4040
+ if (defaultTest.provider_output !== void 0) {
4041
+ errors.push({
4042
+ severity: "error",
4043
+ filePath,
4044
+ location: "default_test.provider_output",
4045
+ message: "default_test.provider_output is not supported in authored AgentV YAML. Use an explicit deterministic target such as provider: cli for fixed outputs, or use a replay/fixture target for captured provider responses."
4046
+ });
4047
+ }
3913
4048
  if (defaultTest.expected_output !== void 0) {
3914
4049
  errors.push({
3915
4050
  severity: "error",
@@ -4011,10 +4146,8 @@ async function validateScenarios(scenarios, parsed, filePath, errors, customAsse
4011
4146
  }
4012
4147
  for (let testIndex = 0; testIndex < scenario.tests.length; testIndex++) {
4013
4148
  const test = scenario.tests[testIndex];
4014
- const everyConfigProvidesInput = scenarioConfigs.length > 0 && scenarioConfigs.every(
4015
- (config) => isObject(config) && (config.prompts !== void 0 || config.provider_output !== void 0)
4016
- );
4017
- const requireInput = isObject(test) && parsed.prompts === void 0 && test.prompts === void 0 && test.provider_output === void 0 && !everyConfigProvidesInput;
4149
+ const everyConfigProvidesInput = scenarioConfigs.length > 0 && scenarioConfigs.every((config) => isObject(config) && config.prompts !== void 0);
4150
+ const requireInput = isObject(test) && parsed.prompts === void 0 && test.prompts === void 0 && !everyConfigProvidesInput;
4018
4151
  await validateScenarioTestLikeRow(
4019
4152
  test,
4020
4153
  `${scenarioLocation}.tests[${testIndex}]`,
@@ -4026,6 +4159,35 @@ async function validateScenarios(scenarios, parsed, filePath, errors, customAsse
4026
4159
  }
4027
4160
  }
4028
4161
  }
4162
+ async function expandScenariosForValidation(scenarios, filePath, errors) {
4163
+ if (!Array.isArray(scenarios)) {
4164
+ return scenarios;
4165
+ }
4166
+ const expanded = [];
4167
+ for (let scenarioIndex = 0; scenarioIndex < scenarios.length; scenarioIndex++) {
4168
+ const scenario = scenarios[scenarioIndex];
4169
+ if (!isScenarioFileReference(scenario)) {
4170
+ expanded.push(scenario);
4171
+ continue;
4172
+ }
4173
+ try {
4174
+ const externalScenarios = await resolveScenarioFileReference(
4175
+ scenario,
4176
+ path22.dirname(filePath)
4177
+ );
4178
+ expanded.push(...externalScenarios);
4179
+ } catch (error) {
4180
+ const message = error instanceof Error ? error.message : String(error);
4181
+ errors.push({
4182
+ severity: "error",
4183
+ filePath,
4184
+ location: `scenarios[${scenarioIndex}]`,
4185
+ message
4186
+ });
4187
+ }
4188
+ }
4189
+ return expanded;
4190
+ }
4029
4191
  async function validateScenarioTestLikeRow(row, location, filePath, errors, customAssertionTypes, options) {
4030
4192
  if (!isObject(row)) {
4031
4193
  errors.push({
@@ -4118,7 +4280,7 @@ async function validateScenarioTestLikeRow(row, location, filePath, errors, cust
4118
4280
  }
4119
4281
  const targets = row.providers !== void 0 ? row.providers : row.provider;
4120
4282
  if (targets !== void 0) {
4121
- validateTargetTestbedFields(targets, `${location}.providers`, filePath, errors);
4283
+ await validateProviderEnvironmentFields(targets, `${location}.providers`, filePath, errors);
4122
4284
  }
4123
4285
  }
4124
4286
  function validateEvaluateOptions(evaluateOptions, location, filePath, errors) {
@@ -4208,7 +4370,12 @@ function validateEvaluateOptionsRepeat(repeat, location, filePath, errors) {
4208
4370
  }
4209
4371
  return;
4210
4372
  }
4211
- validateRepeatOverride(repeat, location, filePath, errors);
4373
+ errors.push({
4374
+ severity: "error",
4375
+ filePath,
4376
+ location,
4377
+ message: `Invalid '${location}' field (must be a positive integer). The repeat object shape has been removed; use ${location}: 2.`
4378
+ });
4212
4379
  }
4213
4380
  function validateFilterRange(filterRange, location, filePath, errors) {
4214
4381
  if (filterRange === void 0 || typeof filterRange === "string") {
@@ -4227,57 +4394,12 @@ function validateRepeatOverride(repeat, location, filePath, errors) {
4227
4394
  if (repeat === void 0) {
4228
4395
  return;
4229
4396
  }
4230
- if (!isObject(repeat)) {
4397
+ if (typeof repeat !== "number" || !Number.isInteger(repeat) || repeat < 1) {
4231
4398
  errors.push({
4232
4399
  severity: "error",
4233
4400
  filePath,
4234
4401
  location,
4235
- message: "Invalid 'repeat' field (must be an object)"
4236
- });
4237
- return;
4238
- }
4239
- for (const key of Object.keys(repeat)) {
4240
- if (!KNOWN_REPEAT_FIELDS.has(key)) {
4241
- errors.push({
4242
- severity: "error",
4243
- filePath,
4244
- location: `${location}.${key}`,
4245
- message: "Invalid repeat field. Supported fields: count, strategy, early_exit, cost_limit_usd."
4246
- });
4247
- }
4248
- }
4249
- if (typeof repeat.count !== "number" || !Number.isInteger(repeat.count) || repeat.count < 1) {
4250
- errors.push({
4251
- severity: "error",
4252
- filePath,
4253
- location: `${location}.count`,
4254
- message: "Invalid 'count' field (must be a positive integer)"
4255
- });
4256
- }
4257
- if (repeat.strategy !== void 0 && (typeof repeat.strategy !== "string" || !KNOWN_REPEAT_STRATEGIES.has(repeat.strategy))) {
4258
- errors.push({
4259
- severity: "error",
4260
- filePath,
4261
- location: `${location}.strategy`,
4262
- message: "Invalid 'strategy' field (must be pass_any, pass_all, mean, or confidence_interval; use pass_any instead of removed pass_at_k)"
4263
- });
4264
- }
4265
- const earlyExit = repeat.early_exit;
4266
- if (earlyExit !== void 0 && typeof earlyExit !== "boolean") {
4267
- errors.push({
4268
- severity: "error",
4269
- filePath,
4270
- location: `${location}.early_exit`,
4271
- message: "Invalid 'early_exit' field (must be a boolean)"
4272
- });
4273
- }
4274
- const costLimit = repeat.cost_limit_usd;
4275
- if (costLimit !== void 0 && (typeof costLimit !== "number" || costLimit < 0)) {
4276
- errors.push({
4277
- severity: "error",
4278
- filePath,
4279
- location: `${location}.cost_limit_usd`,
4280
- message: "Invalid 'cost_limit_usd' field (must be a non-negative number)"
4402
+ message: "Invalid 'repeat' field (must be a positive integer). The repeat object shape has been removed; use repeat: 2."
4281
4403
  });
4282
4404
  }
4283
4405
  }
@@ -4719,7 +4841,7 @@ async function validateRawCaseImportPath(testsPath, filePath, location, errors)
4719
4841
  let caseIndex = 0;
4720
4842
  for (const casePath of caseFiles) {
4721
4843
  const statPath = casePath.match(/\.(?:mjs|cjs|js|py):[^/\\:]+$/i) ? casePath.slice(0, casePath.lastIndexOf(":")) : casePath;
4722
- const pathStat = await stat2(statPath).catch(() => void 0);
4844
+ const pathStat = await stat3(statPath).catch(() => void 0);
4723
4845
  const externalCases = pathStat?.isDirectory() ? await loadCasesFromDirectory(casePath) : await loadCasesFromFile(casePath);
4724
4846
  for (const externalCase of externalCases) {
4725
4847
  await validateWorkspaceConfig(
@@ -5155,6 +5277,11 @@ async function validateCasesFile(filePath) {
5155
5277
  };
5156
5278
  }
5157
5279
  var LEGACY_ENV_PATTERN = /\$\{\{\s*([A-Z_][A-Z0-9_]*)\s*\}\}/g;
5280
+ var REMOVED_RUNNER_BATCHING_FIELDS = /* @__PURE__ */ new Set([
5281
+ "batch_requests",
5282
+ "provider_batching",
5283
+ "providerBatching"
5284
+ ]);
5158
5285
  function isObject3(value) {
5159
5286
  return typeof value === "object" && value !== null && !Array.isArray(value);
5160
5287
  }
@@ -5189,7 +5316,7 @@ function validateLegacyEnvTemplates(value, filePath, location, errors) {
5189
5316
  }
5190
5317
  }
5191
5318
  }
5192
- var COMMON_SETTINGS = new Set(COMMON_TARGET_SETTINGS);
5319
+ var COMMON_SETTINGS = new Set(COMMON_PROVIDER_SETTINGS);
5193
5320
  var RETRY_SETTINGS = /* @__PURE__ */ new Set([
5194
5321
  "max_retries",
5195
5322
  "retry_initial_delay_ms",
@@ -5435,6 +5562,7 @@ function validateUnknownSettings(target, provider, absolutePath, location, error
5435
5562
  "name",
5436
5563
  "label",
5437
5564
  "provider",
5565
+ "provider_spec",
5438
5566
  "config",
5439
5567
  "prompts",
5440
5568
  "transform",
@@ -5458,6 +5586,9 @@ function validateUnknownSettings(target, provider, absolutePath, location, error
5458
5586
  };
5459
5587
  const removedForProvider = removedPerProvider[provider];
5460
5588
  for (const key of Object.keys(target)) {
5589
+ if (REMOVED_RUNNER_BATCHING_FIELDS.has(key)) {
5590
+ continue;
5591
+ }
5461
5592
  if (removedFields.has(key)) {
5462
5593
  errors.push({
5463
5594
  severity: "warning",
@@ -5476,15 +5607,6 @@ function validateUnknownSettings(target, provider, absolutePath, location, error
5476
5607
  });
5477
5608
  continue;
5478
5609
  }
5479
- if (key === "provider_batching") {
5480
- errors.push({
5481
- severity: "error",
5482
- filePath: absolutePath,
5483
- location: `${location}.${key}`,
5484
- message: "The 'provider_batching' field has been removed. Use 'batch_requests' instead."
5485
- });
5486
- continue;
5487
- }
5488
5610
  if (removedForProvider?.has(key)) {
5489
5611
  errors.push({
5490
5612
  severity: "error",
@@ -5504,6 +5626,22 @@ function validateUnknownSettings(target, provider, absolutePath, location, error
5504
5626
  }
5505
5627
  }
5506
5628
  }
5629
+ function buildRemovedRunnerBatchingMessage(field) {
5630
+ return `The '${field}' field has been removed. Runner-level batching was removed; providers should implement internal queueing/batching behind per-request invocation.`;
5631
+ }
5632
+ function validateRemovedRunnerBatchingFields(target, absolutePath, location, errors) {
5633
+ for (const key of Object.keys(target)) {
5634
+ if (!REMOVED_RUNNER_BATCHING_FIELDS.has(key)) {
5635
+ continue;
5636
+ }
5637
+ errors.push({
5638
+ severity: "error",
5639
+ filePath: absolutePath,
5640
+ location: `${location}.${key}`,
5641
+ message: buildRemovedRunnerBatchingMessage(key)
5642
+ });
5643
+ }
5644
+ }
5507
5645
  async function validateTargetsFile(filePath) {
5508
5646
  const errors = [];
5509
5647
  const absolutePath = path42.resolve(filePath);
@@ -5619,11 +5757,11 @@ async function validateTargetsFile(filePath) {
5619
5757
  }
5620
5758
  return result;
5621
5759
  }
5622
- if (!isObject3(parsed)) {
5760
+ if (!Array.isArray(parsed) && !isObject3(parsed)) {
5623
5761
  errors.push({
5624
5762
  severity: "error",
5625
5763
  filePath: absolutePath,
5626
- message: "File must contain a YAML object"
5764
+ message: "File must contain a YAML array or an object with a providers array"
5627
5765
  });
5628
5766
  return {
5629
5767
  valid: false,
@@ -5632,22 +5770,22 @@ async function validateTargetsFile(filePath) {
5632
5770
  errors
5633
5771
  };
5634
5772
  }
5635
- if (Array.isArray(parsed.providers)) {
5773
+ if (isObject3(parsed) && Array.isArray(parsed.targets)) {
5636
5774
  errors.push({
5637
5775
  severity: "error",
5638
5776
  filePath: absolutePath,
5639
- location: "providers",
5640
- message: "Top-level 'providers' is not a runtime alias in targets.yaml. Use 'targets' for systems under test; provider names backend kind inside each target."
5777
+ location: "targets",
5778
+ message: "Top-level 'targets' has been removed. Use 'providers'; map targets[].id to providers[].label and targets[].provider to providers[].id."
5641
5779
  });
5642
5780
  }
5643
- const targets = parsed.targets;
5644
- const rawTargets = isObject3(rawParsed) && Array.isArray(rawParsed.targets) ? rawParsed.targets : [];
5645
- if (!Array.isArray(targets)) {
5781
+ const providers = Array.isArray(parsed) ? parsed : parsed.providers;
5782
+ const rawTargets = Array.isArray(rawParsed) ? rawParsed : isObject3(rawParsed) && Array.isArray(rawParsed.providers) ? rawParsed.providers : [];
5783
+ if (!Array.isArray(providers)) {
5646
5784
  errors.push({
5647
5785
  severity: "error",
5648
5786
  filePath: absolutePath,
5649
- location: "targets",
5650
- message: "Missing or invalid 'targets' field (must be an array)"
5787
+ location: "providers",
5788
+ message: "Missing or invalid 'providers' field (must be an array)"
5651
5789
  });
5652
5790
  return {
5653
5791
  valid: errors.length === 0,
@@ -5657,22 +5795,24 @@ async function validateTargetsFile(filePath) {
5657
5795
  };
5658
5796
  }
5659
5797
  const knownProviders = [...KNOWN_PROVIDERS];
5660
- for (let i = 0; i < targets.length; i++) {
5661
- const target = targets[i];
5662
- const location = `targets[${i}]`;
5663
- if (!isObject3(target)) {
5798
+ for (let i = 0; i < providers.length; i++) {
5799
+ const providerEntry = providers[i];
5800
+ const location = `providers[${i}]`;
5801
+ if (!isObject3(providerEntry)) {
5664
5802
  errors.push({
5665
5803
  severity: "error",
5666
5804
  filePath: absolutePath,
5667
5805
  location,
5668
- message: "Target must be an object"
5806
+ message: "Provider must be an object"
5669
5807
  });
5670
5808
  continue;
5671
5809
  }
5672
- validateLegacyEnvTemplates(rawTargets[i] ?? target, absolutePath, location, errors);
5810
+ validateLegacyEnvTemplates(rawTargets[i] ?? providerEntry, absolutePath, location, errors);
5673
5811
  let normalizedTarget;
5674
5812
  try {
5675
- normalizedTarget = normalizeTargetDefinition(target);
5813
+ normalizedTarget = normalizeProviderDefinition(providerEntry, {
5814
+ location
5815
+ });
5676
5816
  } catch (error) {
5677
5817
  errors.push({
5678
5818
  severity: "error",
@@ -5682,7 +5822,7 @@ async function validateTargetsFile(filePath) {
5682
5822
  });
5683
5823
  }
5684
5824
  for (const warning of findDeprecatedCamelCaseTargetWarnings(
5685
- normalizedTarget ?? target,
5825
+ normalizedTarget ?? providerEntry,
5686
5826
  location
5687
5827
  )) {
5688
5828
  const fieldMatch = warning.message.match(/field '([^']+)'/);
@@ -5693,10 +5833,10 @@ async function validateTargetsFile(filePath) {
5693
5833
  severity: "error",
5694
5834
  filePath: absolutePath,
5695
5835
  location: warning.location,
5696
- message: `camelCase field '${field}' is no longer supported in targets.yaml. Use '${replacement}' instead.`
5836
+ message: `camelCase field '${field}' is no longer supported in providers.yaml. Use '${replacement}' instead.`
5697
5837
  });
5698
5838
  }
5699
- const id = target.id;
5839
+ const id = providerEntry.id;
5700
5840
  if (typeof id !== "string" || id.trim().length === 0) {
5701
5841
  errors.push({
5702
5842
  severity: "error",
@@ -5705,23 +5845,15 @@ async function validateTargetsFile(filePath) {
5705
5845
  message: "Missing or invalid 'id' field (must be a non-empty string)"
5706
5846
  });
5707
5847
  }
5708
- if (typeof target.label === "string" && target.label.trim().length > 0) {
5709
- errors.push({
5710
- severity: "error",
5711
- filePath: absolutePath,
5712
- location: `${location}.label`,
5713
- message: "The target 'label' field has been removed. Use 'id' instead."
5714
- });
5715
- }
5716
- if (typeof target.name === "string" && target.name.trim().length > 0) {
5848
+ if (typeof providerEntry.name === "string" && providerEntry.name.trim().length > 0) {
5717
5849
  errors.push({
5718
5850
  severity: "error",
5719
5851
  filePath: absolutePath,
5720
5852
  location: `${location}.name`,
5721
- message: "The target 'name' field has been removed. Use 'id' instead."
5853
+ message: "The provider 'name' field has been removed. Use 'label' instead."
5722
5854
  });
5723
5855
  }
5724
- const effectiveTarget = normalizedTarget ?? target;
5856
+ const effectiveTarget = normalizedTarget ?? providerEntry;
5725
5857
  const provider = effectiveTarget.provider;
5726
5858
  const rawTarget = rawTargets[i];
5727
5859
  const rawUseTarget = isObject3(rawTarget) ? rawTarget.use_target : void 0;
@@ -5730,7 +5862,7 @@ async function validateTargetsFile(filePath) {
5730
5862
  severity: "error",
5731
5863
  filePath: absolutePath,
5732
5864
  location: `${location}.use_target`,
5733
- message: "The 'use_target' field has been removed from authored targets.yaml target definitions. Define a concrete target with 'provider' instead."
5865
+ message: "The 'use_target' field has been removed from authored providers.yaml definitions. Define a concrete provider entry instead."
5734
5866
  });
5735
5867
  }
5736
5868
  const providerValue = typeof provider === "string" ? provider.trim().toLowerCase() : void 0;
@@ -5739,24 +5871,25 @@ async function validateTargetsFile(filePath) {
5739
5871
  errors.push({
5740
5872
  severity: "error",
5741
5873
  filePath: absolutePath,
5742
- location: `${location}.provider`,
5743
- message: "Missing or invalid 'provider' field (must be a non-empty string)"
5874
+ location: `${location}.id`,
5875
+ message: "Missing or invalid 'id' field (must be a non-empty provider backend string)"
5744
5876
  });
5745
5877
  } else if (!isTemplated && (providerValue === "claude" || providerValue === "copilot")) {
5746
5878
  errors.push({
5747
5879
  severity: "error",
5748
5880
  filePath: absolutePath,
5749
- location: `${location}.provider`,
5881
+ location: `${location}.id`,
5750
5882
  message: `Ambiguous provider '${providerValue}' is not supported. Choose an explicit provider such as '${providerValue}-cli' or '${providerValue}-sdk'.`
5751
5883
  });
5752
5884
  } else if (typeof provider === "string" && !isTemplated && !knownProviders.includes(provider)) {
5753
5885
  errors.push({
5754
5886
  severity: "warning",
5755
5887
  filePath: absolutePath,
5756
- location: `${location}.provider`,
5888
+ location: `${location}.id`,
5757
5889
  message: `Unknown provider '${provider}'. Known providers: ${knownProviders.join(", ")}`
5758
5890
  });
5759
5891
  }
5892
+ validateRemovedRunnerBatchingFields(effectiveTarget, absolutePath, location, errors);
5760
5893
  if (providerValue === "cli") {
5761
5894
  validateCliSettings(effectiveTarget, absolutePath, location, errors);
5762
5895
  }
@@ -5906,6 +6039,7 @@ async function validateConfigFile(filePath, options = {}) {
5906
6039
  "results",
5907
6040
  "repo_resolvers",
5908
6041
  "refs",
6042
+ "providers",
5909
6043
  "targets",
5910
6044
  "graders",
5911
6045
  "tests",
@@ -5942,7 +6076,7 @@ async function validateConfigFile(filePath, options = {}) {
5942
6076
  }
5943
6077
  function validateComposableGraph(errors, filePath, config) {
5944
6078
  try {
5945
- normalizeComposableConfigGraph(config, filePath);
6079
+ normalizeComposableConfigGraph(config, filePath, { allowExecutionDefaultFields: true });
5946
6080
  } catch (error) {
5947
6081
  addError(errors, filePath, void 0, error.message);
5948
6082
  }
@@ -6453,13 +6587,13 @@ var ANSI_RESET3 = "\x1B[0m";
6453
6587
  function isTTY() {
6454
6588
  return process.stdout.isTTY ?? false;
6455
6589
  }
6456
- function resolveUseTarget(name, definitions, env, targetsFilePath) {
6590
+ function resolveUseTarget(name, definitions, env, providersFilePath) {
6457
6591
  const maxDepth = 5;
6458
6592
  let current = definitions.find((d) => d.name === name);
6459
6593
  if (!current) {
6460
- const available = listTargetNames(definitions).join(", ");
6594
+ const available = listProviderLabels(definitions).join(", ");
6461
6595
  throw new Error(
6462
- `Target '${name}' not found in ${targetsFilePath}. Available targets: ${available}`
6596
+ `Provider '${name}' not found in ${providersFilePath}. Available providers: ${available}`
6463
6597
  );
6464
6598
  }
6465
6599
  for (let depth = 0; depth < maxDepth; depth++) {
@@ -6470,27 +6604,82 @@ function resolveUseTarget(name, definitions, env, targetsFilePath) {
6470
6604
  const envMatch = raw.match(/^\$\{\{\s*([A-Z0-9_]+)\s*\}\}$/i);
6471
6605
  const resolved = envMatch ? env[envMatch[1]] ?? "" : raw;
6472
6606
  if (resolved.trim().length === 0) break;
6473
- const next = definitions.find((d) => d.name === resolved.trim());
6607
+ const next = definitions.find(
6608
+ (d) => d.name === resolved.trim()
6609
+ );
6474
6610
  if (!next) {
6475
- const available = listTargetNames(definitions).join(", ");
6611
+ const available = listProviderLabels(definitions).join(", ");
6476
6612
  throw new Error(
6477
- `Target '${name}' use_target '${resolved.trim()}' not found in ${targetsFilePath}. Available targets: ${available}`
6613
+ `Provider '${name}' use_target '${resolved.trim()}' not found in ${providersFilePath}. Available providers: ${available}`
6478
6614
  );
6479
6615
  }
6480
6616
  current = next;
6481
6617
  }
6482
6618
  return current;
6483
6619
  }
6484
- async function readTestSuiteTarget(testFilePath) {
6620
+ async function readTestSuiteProvider(testFilePath) {
6485
6621
  const metadata = await readTestSuiteMetadata(testFilePath);
6486
6622
  return metadata.target;
6487
6623
  }
6488
- function pickTargetName(options) {
6489
- const cliName = options.cliTargetName?.trim();
6624
+ async function readProviderCatalog(options) {
6625
+ if (!options.explicitProvidersPath && options.providerDefinitions) {
6626
+ return {
6627
+ definitions: options.providerDefinitions,
6628
+ sourcePath: options.providerDefinitionsSource ?? ".agentv/config.yaml:providers"
6629
+ };
6630
+ }
6631
+ if (!options.explicitProvidersPath && options.requireExplicitProviderCatalog) {
6632
+ throw new Error(
6633
+ "No provider catalog configured. Add `providers:` to .agentv/config.yaml, use `providers: file://providers.yaml`, or pass --providers <path>."
6634
+ );
6635
+ }
6636
+ const providersFilePath = await discoverProvidersFile({
6637
+ explicitPath: options.explicitProvidersPath,
6638
+ testFilePath: options.testFilePath,
6639
+ repoRoot: options.repoRoot,
6640
+ cwd: options.cwd,
6641
+ allowLegacyTargetFiles: options.allowLegacyTargetFiles
6642
+ });
6643
+ await validateProviderCatalogFile(providersFilePath);
6644
+ return {
6645
+ definitions: await readProviderDefinitions(providersFilePath),
6646
+ sourcePath: providersFilePath
6647
+ };
6648
+ }
6649
+ async function validateProviderCatalogFile(providersFilePath) {
6650
+ const validationResult = await validateTargetsFile(providersFilePath);
6651
+ const warnings = validationResult.errors.filter((e) => e.severity === "warning");
6652
+ const useColors2 = isTTY();
6653
+ if (warnings.length > 0) {
6654
+ console.warn(`
6655
+ Warnings in ${providersFilePath}:`);
6656
+ for (const warning of warnings) {
6657
+ const location = warning.location ? ` [${warning.location}]` : "";
6658
+ const prefix = useColors2 ? `${ANSI_YELLOW3} \u26A0${ANSI_RESET3}` : " \u26A0";
6659
+ const message = useColors2 ? `${ANSI_YELLOW3}${warning.message}${ANSI_RESET3}` : warning.message;
6660
+ console.warn(`${prefix}${location} ${message}`);
6661
+ }
6662
+ console.warn("");
6663
+ }
6664
+ const errors = validationResult.errors.filter((e) => e.severity === "error");
6665
+ if (errors.length > 0) {
6666
+ console.error(`
6667
+ Errors in ${providersFilePath}:`);
6668
+ for (const error of errors) {
6669
+ const location = error.location ? ` [${error.location}]` : "";
6670
+ const prefix = useColors2 ? `${ANSI_RED3} \u2717${ANSI_RESET3}` : " \u2717";
6671
+ const message = useColors2 ? `${ANSI_RED3}${error.message}${ANSI_RESET3}` : error.message;
6672
+ console.error(`${prefix}${location} ${message}`);
6673
+ }
6674
+ throw new Error(`Providers file validation failed with ${errors.length} error(s)`);
6675
+ }
6676
+ }
6677
+ function pickProviderLabel(options) {
6678
+ const cliName = options.cliProviderLabel?.trim();
6490
6679
  if (cliName && cliName !== "default") {
6491
6680
  return { name: cliName, source: "cli" };
6492
6681
  }
6493
- const fileName = options.fileTargetName?.trim();
6682
+ const fileName = options.fileProviderLabel?.trim();
6494
6683
  if (fileName && fileName.length > 0) {
6495
6684
  return { name: fileName, source: "test-file" };
6496
6685
  }
@@ -6501,12 +6690,12 @@ function withModelOverride(target, modelOverride) {
6501
6690
  return model && model.length > 0 ? { ...target, model } : target;
6502
6691
  }
6503
6692
  function overlayTargetDefinition(params) {
6504
- const { spec, definitions, env, targetsFilePath } = params;
6693
+ const { spec, definitions, env, providersFilePath } = params;
6505
6694
  if (!spec?.definition) {
6506
6695
  return void 0;
6507
6696
  }
6508
6697
  if (spec.extends) {
6509
- const base = resolveUseTarget(spec.extends, definitions, env, targetsFilePath);
6698
+ const base = resolveUseTarget(spec.extends, definitions, env, providersFilePath);
6510
6699
  return {
6511
6700
  ...base,
6512
6701
  ...spec.definition,
@@ -6518,82 +6707,86 @@ function overlayTargetDefinition(params) {
6518
6707
  function definitionsWithEffectiveTarget(definitions, effective) {
6519
6708
  return [effective, ...definitions.filter((definition) => definition.name !== effective.name)];
6520
6709
  }
6521
- async function selectTarget(options) {
6522
- const { testFilePath, repoRoot, cwd, explicitTargetsPath, cliTargetName, modelOverride, env } = options;
6523
- const targetsFilePath = await discoverTargetsFile({
6524
- explicitPath: explicitTargetsPath,
6710
+ async function resolveInlineDefinitionEnvironment(definition, testFilePath, location) {
6711
+ const [resolved] = await resolveProviderDefinitionEnvironments(
6712
+ [definition],
6713
+ path12.dirname(path12.resolve(testFilePath)),
6714
+ { location }
6715
+ );
6716
+ return resolved ?? definition;
6717
+ }
6718
+ async function selectProvider(options) {
6719
+ const {
6525
6720
  testFilePath,
6526
6721
  repoRoot,
6527
- cwd
6722
+ cwd,
6723
+ explicitProvidersPath,
6724
+ providerDefinitions,
6725
+ providerDefinitionsSource,
6726
+ requireExplicitProviderCatalog,
6727
+ allowLegacyTargetFiles,
6728
+ cliProviderLabel,
6729
+ modelOverride,
6730
+ env
6731
+ } = options;
6732
+ const providerCatalog = await readProviderCatalog({
6733
+ explicitProvidersPath,
6734
+ providerDefinitions,
6735
+ providerDefinitionsSource,
6736
+ requireExplicitProviderCatalog,
6737
+ testFilePath,
6738
+ repoRoot,
6739
+ cwd,
6740
+ allowLegacyTargetFiles
6528
6741
  });
6529
- const validationResult = await validateTargetsFile(targetsFilePath);
6530
- const warnings = validationResult.errors.filter((e) => e.severity === "warning");
6531
- const useColors2 = isTTY();
6532
- if (warnings.length > 0) {
6533
- console.warn(`
6534
- Warnings in ${targetsFilePath}:`);
6535
- for (const warning of warnings) {
6536
- const location = warning.location ? ` [${warning.location}]` : "";
6537
- const prefix = useColors2 ? `${ANSI_YELLOW3} \u26A0${ANSI_RESET3}` : " \u26A0";
6538
- const message = useColors2 ? `${ANSI_YELLOW3}${warning.message}${ANSI_RESET3}` : warning.message;
6539
- console.warn(`${prefix}${location} ${message}`);
6540
- }
6541
- console.warn("");
6542
- }
6543
- const errors = validationResult.errors.filter((e) => e.severity === "error");
6544
- if (errors.length > 0) {
6545
- console.error(`
6546
- Errors in ${targetsFilePath}:`);
6547
- for (const error of errors) {
6548
- const location = error.location ? ` [${error.location}]` : "";
6549
- const prefix = useColors2 ? `${ANSI_RED3} \u2717${ANSI_RESET3}` : " \u2717";
6550
- const message = useColors2 ? `${ANSI_RED3}${error.message}${ANSI_RESET3}` : error.message;
6551
- console.error(`${prefix}${location} ${message}`);
6552
- }
6553
- throw new Error(`Targets file validation failed with ${errors.length} error(s)`);
6554
- }
6555
- const definitions = await readTargetDefinitions(targetsFilePath);
6742
+ const definitions = providerCatalog.definitions;
6743
+ const providersFilePath = providerCatalog.sourcePath;
6556
6744
  const fileTargetSpec = options.fileTargetSpec;
6557
- const fileTargetName = options.fileTargetName ?? fileTargetSpec?.name ?? await readTestSuiteTarget(testFilePath);
6558
- const targetChoice = pickTargetName({ cliTargetName, fileTargetName });
6559
- const overlayDefinition = targetChoice.source === "test-file" ? overlayTargetDefinition({ spec: fileTargetSpec, definitions, env, targetsFilePath }) : void 0;
6745
+ const fileProviderLabel = options.fileProviderLabel ?? fileTargetSpec?.name ?? await readTestSuiteProvider(testFilePath);
6746
+ const providerChoice = pickProviderLabel({ cliProviderLabel, fileProviderLabel });
6747
+ const rawOverlayDefinition = providerChoice.source === "test-file" ? overlayTargetDefinition({ spec: fileTargetSpec, definitions, env, providersFilePath }) : void 0;
6748
+ const overlayDefinition = rawOverlayDefinition ? await resolveInlineDefinitionEnvironment(rawOverlayDefinition, testFilePath, "providers") : void 0;
6560
6749
  const targetDefinition = withModelOverride(
6561
- overlayDefinition ?? resolveUseTarget(targetChoice.name, definitions, env, targetsFilePath),
6750
+ overlayDefinition ?? resolveUseTarget(providerChoice.name, definitions, env, providersFilePath),
6562
6751
  modelOverride
6563
6752
  );
6564
6753
  const effectiveDefinitions = overlayDefinition !== void 0 ? definitionsWithEffectiveTarget(definitions, targetDefinition) : definitions;
6565
6754
  try {
6566
- const resolvedTarget = resolveTargetDefinition(targetDefinition, env, testFilePath, {
6755
+ const resolvedProvider = resolveProviderDefinition(targetDefinition, env, testFilePath, {
6567
6756
  emitDeprecationWarnings: false
6568
6757
  });
6569
6758
  return {
6570
6759
  definitions: effectiveDefinitions,
6571
- resolvedTarget,
6572
- targetName: targetChoice.name,
6573
- targetSource: targetChoice.source,
6574
- targetsFilePath,
6575
- ...targetChoice.source === "test-file" && fileTargetSpec?.hooks ? { targetHooks: fileTargetSpec.hooks } : {}
6760
+ resolvedProvider,
6761
+ providerLabel: providerChoice.name,
6762
+ providerSource: providerChoice.source,
6763
+ providersFilePath,
6764
+ ...providerChoice.source === "test-file" && fileTargetSpec?.hooks ? { providerHooks: fileTargetSpec.hooks } : {}
6576
6765
  };
6577
6766
  } catch (error) {
6578
6767
  const message = error instanceof Error ? error.message : String(error);
6579
- throw new Error(`Failed to resolve target '${targetChoice.name}': ${message}`);
6768
+ throw new Error(`Failed to resolve provider '${providerChoice.name}': ${message}`);
6580
6769
  }
6581
6770
  }
6582
- async function selectMultipleTargets(options) {
6771
+ async function selectMultipleProviders(options) {
6583
6772
  const {
6584
6773
  testFilePath,
6585
6774
  repoRoot,
6586
6775
  cwd,
6587
- explicitTargetsPath,
6776
+ explicitProvidersPath,
6777
+ providerDefinitions,
6778
+ providerDefinitionsSource,
6779
+ requireExplicitProviderCatalog,
6780
+ allowLegacyTargetFiles,
6588
6781
  env,
6589
- targetNames,
6590
- targetRefs,
6782
+ providerLabels,
6783
+ providerRefs,
6591
6784
  modelOverride
6592
6785
  } = options;
6593
6786
  const hooksMap = /* @__PURE__ */ new Map();
6594
6787
  const labelsMap = /* @__PURE__ */ new Map();
6595
- if (targetRefs) {
6596
- for (const ref of targetRefs) {
6788
+ if (providerRefs) {
6789
+ for (const ref of providerRefs) {
6597
6790
  if (ref.hooks) {
6598
6791
  hooksMap.set(ref.name, ref.hooks);
6599
6792
  }
@@ -6602,73 +6795,54 @@ async function selectMultipleTargets(options) {
6602
6795
  }
6603
6796
  }
6604
6797
  }
6605
- const targetsFilePath = await discoverTargetsFile({
6606
- explicitPath: explicitTargetsPath,
6798
+ const providerCatalog = await readProviderCatalog({
6799
+ explicitProvidersPath,
6800
+ providerDefinitions,
6801
+ providerDefinitionsSource,
6802
+ requireExplicitProviderCatalog,
6607
6803
  testFilePath,
6608
6804
  repoRoot,
6609
- cwd
6805
+ cwd,
6806
+ allowLegacyTargetFiles
6610
6807
  });
6611
- const validationResult = await validateTargetsFile(targetsFilePath);
6612
- const warnings = validationResult.errors.filter((e) => e.severity === "warning");
6613
- const useColors2 = isTTY();
6614
- if (warnings.length > 0) {
6615
- console.warn(`
6616
- Warnings in ${targetsFilePath}:`);
6617
- for (const warning of warnings) {
6618
- const location = warning.location ? ` [${warning.location}]` : "";
6619
- const prefix = useColors2 ? `${ANSI_YELLOW3} \u26A0${ANSI_RESET3}` : " \u26A0";
6620
- const message = useColors2 ? `${ANSI_YELLOW3}${warning.message}${ANSI_RESET3}` : warning.message;
6621
- console.warn(`${prefix}${location} ${message}`);
6622
- }
6623
- console.warn("");
6624
- }
6625
- const errors = validationResult.errors.filter((e) => e.severity === "error");
6626
- if (errors.length > 0) {
6627
- console.error(`
6628
- Errors in ${targetsFilePath}:`);
6629
- for (const error of errors) {
6630
- const location = error.location ? ` [${error.location}]` : "";
6631
- const prefix = useColors2 ? `${ANSI_RED3} \u2717${ANSI_RESET3}` : " \u2717";
6632
- const message = useColors2 ? `${ANSI_RED3}${error.message}${ANSI_RESET3}` : error.message;
6633
- console.error(`${prefix}${location} ${message}`);
6634
- }
6635
- throw new Error(`Targets file validation failed with ${errors.length} error(s)`);
6636
- }
6637
- const fileDefinitions = await readTargetDefinitions(targetsFilePath);
6808
+ const providersFilePath = providerCatalog.sourcePath;
6809
+ const fileDefinitions = providerCatalog.definitions;
6638
6810
  const definitions = [...fileDefinitions];
6639
- if (targetRefs) {
6640
- for (const ref of targetRefs) {
6811
+ if (providerRefs) {
6812
+ for (const ref of providerRefs) {
6641
6813
  if (ref.definition && !fileDefinitions.some((d) => d.name === ref.name)) {
6642
- definitions.push(ref.definition);
6814
+ definitions.push(
6815
+ await resolveInlineDefinitionEnvironment(ref.definition, testFilePath, "providers")
6816
+ );
6643
6817
  } else if (ref.use_target && !fileDefinitions.some((d) => d.name === ref.name)) {
6644
6818
  definitions.push({ name: ref.name, use_target: ref.use_target });
6645
6819
  }
6646
6820
  }
6647
6821
  }
6648
6822
  const results = [];
6649
- for (const name of targetNames) {
6823
+ for (const name of providerLabels) {
6650
6824
  const targetDefinition = withModelOverride(
6651
- resolveUseTarget(name, definitions, env, targetsFilePath),
6825
+ resolveUseTarget(name, definitions, env, providersFilePath),
6652
6826
  modelOverride
6653
6827
  );
6654
6828
  const hooks = hooksMap.get(name);
6655
- const targetLabel = labelsMap.get(name);
6829
+ const providerDisplayLabel = labelsMap.get(name);
6656
6830
  try {
6657
- const resolvedTarget = resolveTargetDefinition(targetDefinition, env, testFilePath, {
6831
+ const resolvedProvider = resolveProviderDefinition(targetDefinition, env, testFilePath, {
6658
6832
  emitDeprecationWarnings: false
6659
6833
  });
6660
6834
  results.push({
6661
6835
  definitions,
6662
- resolvedTarget,
6663
- targetName: name,
6664
- ...targetLabel ? { targetLabel } : {},
6665
- targetSource: options.targetSource ?? "cli",
6666
- targetsFilePath,
6667
- ...hooks && { targetHooks: hooks }
6836
+ resolvedProvider,
6837
+ providerLabel: name,
6838
+ ...providerDisplayLabel ? { providerDisplayLabel } : {},
6839
+ providerSource: options.providerSource ?? "cli",
6840
+ providersFilePath,
6841
+ ...hooks && { providerHooks: hooks }
6668
6842
  });
6669
6843
  } catch (error) {
6670
6844
  const message = error instanceof Error ? error.message : String(error);
6671
- throw new Error(`Failed to resolve target '${name}': ${message}`);
6845
+ throw new Error(`Failed to resolve provider '${name}': ${message}`);
6672
6846
  }
6673
6847
  }
6674
6848
  return results;
@@ -6767,7 +6941,7 @@ var DEFAULT_WORKERS = 3;
6767
6941
  var loadCjsModule = createNodeRequire(import.meta.url);
6768
6942
  var micromatch = loadCjsModule("micromatch");
6769
6943
  async function loadCliEvalSuite(testFilePath, repoRoot, options) {
6770
- if (path12.extname(testFilePath).toLowerCase() === ".json") {
6944
+ if (path13.extname(testFilePath).toLowerCase() === ".json") {
6771
6945
  const adapterSuite = readAgentSkillsEvalsFile(testFilePath);
6772
6946
  return loadTestSuiteFromYamlObject(
6773
6947
  testFilePath,
@@ -6883,8 +7057,8 @@ function resultsRepoOverride(value) {
6883
7057
  if (!value) {
6884
7058
  return {};
6885
7059
  }
6886
- if (value === "current" || value === "." || value.startsWith("./") || value.startsWith("../") || value.startsWith("/") || value.startsWith("~/") || value.startsWith("~\\") || /^[A-Za-z]:[/\\]/.test(value)) {
6887
- return { repo_path: value === "current" ? "." : value };
7060
+ if (value === "current" || value === "current/." || value === "." || value.startsWith("./") || value.startsWith("../") || value.startsWith("/") || value.startsWith("~/") || value.startsWith("~\\") || /^[A-Za-z]:[/\\]/.test(value)) {
7061
+ return { repo_path: value === "current" || value === "current/." ? "." : value };
6888
7062
  }
6889
7063
  return { repo: value };
6890
7064
  }
@@ -6921,13 +7095,32 @@ function normalizeSourceMetadataByEvalFile(value) {
6921
7095
  const entries = [...value.entries()].filter(
6922
7096
  (entry) => typeof entry[0] === "string" && typeof entry[1] === "object" && entry[1] !== null && !Array.isArray(entry[1])
6923
7097
  );
6924
- return entries.length > 0 ? new Map(entries.map(([key, metadata]) => [path12.resolve(key), metadata])) : void 0;
7098
+ return entries.length > 0 ? new Map(entries.map(([key, metadata]) => [path13.resolve(key), metadata])) : void 0;
6925
7099
  }
6926
7100
  if (typeof value === "object" && value !== null && !Array.isArray(value)) {
6927
7101
  const entries = Object.entries(value).filter(
6928
7102
  (entry) => typeof entry[1] === "object" && entry[1] !== null && !Array.isArray(entry[1])
6929
7103
  );
6930
- return entries.length > 0 ? new Map(entries.map(([key, metadata]) => [path12.resolve(key), metadata])) : void 0;
7104
+ return entries.length > 0 ? new Map(entries.map(([key, metadata]) => [path13.resolve(key), metadata])) : void 0;
7105
+ }
7106
+ return void 0;
7107
+ }
7108
+ function normalizeProviderCatalogPathByEvalFile(value) {
7109
+ if (value instanceof Map) {
7110
+ const entries = [...value.entries()].filter(
7111
+ (entry) => typeof entry[0] === "string" && typeof entry[1] === "string" && entry[1].trim().length > 0
7112
+ );
7113
+ return entries.length > 0 ? new Map(
7114
+ entries.map(([key, providerPath]) => [path13.resolve(key), path13.resolve(providerPath)])
7115
+ ) : void 0;
7116
+ }
7117
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
7118
+ const entries = Object.entries(value).filter(
7119
+ (entry) => typeof entry[1] === "string" && entry[1].trim().length > 0
7120
+ );
7121
+ return entries.length > 0 ? new Map(
7122
+ entries.map(([key, providerPath]) => [path13.resolve(key), path13.resolve(providerPath)])
7123
+ ) : void 0;
6931
7124
  }
6932
7125
  return void 0;
6933
7126
  }
@@ -6941,10 +7134,10 @@ var LEGACY_OUTPUT_FILE_EXTENSIONS = /* @__PURE__ */ new Set([
6941
7134
  ".htm"
6942
7135
  ]);
6943
7136
  function looksLikeLegacyOutputFilePath(value) {
6944
- return LEGACY_OUTPUT_FILE_EXTENSIONS.has(path12.extname(value).toLowerCase());
7137
+ return LEGACY_OUTPUT_FILE_EXTENSIONS.has(path13.extname(value).toLowerCase());
6945
7138
  }
6946
7139
  function outputFileMigrationMessage(value) {
6947
- const ext = path12.extname(value).toLowerCase();
7140
+ const ext = path13.extname(value).toLowerCase();
6948
7141
  const removalHint = ext === ".xml" ? "JUnit XML export from agentv eval has been removed." : "Flat result file export from agentv eval has been removed.";
6949
7142
  return `--output expects a run directory, not a file path: ${value}
6950
7143
  ${removalHint} Set --output <dir> for the canonical run artifacts; AgentV always writes <dir>/${RESULT_INDEX_FILENAME}.`;
@@ -6952,7 +7145,7 @@ ${removalHint} Set --output <dir> for the canonical run artifacts; AgentV always
6952
7145
  function artifactsMigrationMessage(artifactsDir, outputDir) {
6953
7146
  const lines = [`--artifacts was removed from agentv eval. Use --output ${artifactsDir} instead.`];
6954
7147
  if (outputDir && looksLikeLegacyOutputFilePath(outputDir)) {
6955
- const ext = path12.extname(outputDir).toLowerCase();
7148
+ const ext = path13.extname(outputDir).toLowerCase();
6956
7149
  lines.push(
6957
7150
  ext === ".xml" ? "JUnit XML export from agentv eval has been removed." : "Flat result file export from agentv eval has been removed."
6958
7151
  );
@@ -7045,17 +7238,19 @@ function normalizeOptions(rawOptions, config, yamlExecution) {
7045
7238
  const configWorkers = config?.execution?.maxConcurrency ?? yamlExecution?.max_concurrency;
7046
7239
  const workers = cliWorkers ?? configWorkers ?? 0;
7047
7240
  const cliOutputDir = normalizeString(rawOptions.output);
7048
- const rawTarget = rawOptions.target;
7049
- let cliTargets = [];
7050
- let singleTarget;
7051
- if (Array.isArray(rawTarget)) {
7052
- cliTargets = rawTarget.filter((v) => typeof v === "string" && v.trim().length > 0);
7053
- singleTarget = cliTargets.length === 1 ? cliTargets[0] : void 0;
7054
- } else if (typeof rawTarget === "string") {
7055
- const trimmed = rawTarget.trim();
7241
+ const rawProvider = rawOptions.provider;
7242
+ let cliProviderLabels = [];
7243
+ let singleProvider;
7244
+ if (Array.isArray(rawProvider)) {
7245
+ cliProviderLabels = rawProvider.filter(
7246
+ (v) => typeof v === "string" && v.trim().length > 0
7247
+ );
7248
+ singleProvider = cliProviderLabels.length === 1 ? cliProviderLabels[0] : void 0;
7249
+ } else if (typeof rawProvider === "string") {
7250
+ const trimmed = rawProvider.trim();
7056
7251
  if (trimmed.length > 0 && trimmed !== "default") {
7057
- cliTargets = [trimmed];
7058
- singleTarget = trimmed;
7252
+ cliProviderLabels = [trimmed];
7253
+ singleProvider = trimmed;
7059
7254
  }
7060
7255
  }
7061
7256
  const cliAgentTimeout = normalizeOptionalNumber(rawOptions.agentTimeout);
@@ -7091,9 +7286,13 @@ function normalizeOptions(rawOptions, config, yamlExecution) {
7091
7286
  };
7092
7287
  const cliTags = splitCliTags(rawOptions.tag);
7093
7288
  return {
7094
- target: singleTarget,
7095
- cliTargets,
7096
- targetsPath: normalizeString(rawOptions.targets),
7289
+ provider: singleProvider,
7290
+ cliProviderLabels,
7291
+ providersPath: normalizeString(rawOptions.providers),
7292
+ allowLegacyTargetFiles: normalizeBoolean(rawOptions.allowLegacyTargetFiles),
7293
+ providerCatalogPathByEvalFile: normalizeProviderCatalogPathByEvalFile(
7294
+ rawOptions.providerCatalogPathByEvalFile
7295
+ ),
7097
7296
  filter: normalizeFilter(rawOptions.filter),
7098
7297
  workers: workers > 0 ? workers : void 0,
7099
7298
  outputDir: cliOutputDir ?? configOutputDir,
@@ -7140,7 +7339,7 @@ function normalizeOptions(rawOptions, config, yamlExecution) {
7140
7339
  };
7141
7340
  }
7142
7341
  function withSourceMetadata(result, testFilePath, options) {
7143
- const sourceMetadata = options.sourceMetadataByEvalFile?.get(path12.resolve(testFilePath));
7342
+ const sourceMetadata = options.sourceMetadataByEvalFile?.get(path13.resolve(testFilePath));
7144
7343
  if (!sourceMetadata) {
7145
7344
  return result;
7146
7345
  }
@@ -7163,11 +7362,11 @@ function deriveEvalResultGroupName(evalFilePath) {
7163
7362
  if (!evalFilePath) {
7164
7363
  return "eval";
7165
7364
  }
7166
- return path12.basename(evalFilePath).replace(/\.eval\.ya?ml$/i, "").replace(/\.ya?ml$/i, "").replace(/[^A-Za-z0-9._-]/g, "-") || "eval";
7365
+ return path13.basename(evalFilePath).replace(/\.eval\.ya?ml$/i, "").replace(/\.ya?ml$/i, "").replace(/[^A-Za-z0-9._-]/g, "-") || "eval";
7167
7366
  }
7168
7367
  var CLI_RUNTIME_SOURCE_OPTION_KEYS = [
7169
- "target",
7170
- "targets",
7368
+ "provider",
7369
+ "providers",
7171
7370
  "filter",
7172
7371
  "tag",
7173
7372
  "excludeTag",
@@ -7210,10 +7409,10 @@ function toRuntimeSourcePath(cwd, filePath) {
7210
7409
  if (!trimmed) {
7211
7410
  return void 0;
7212
7411
  }
7213
- const resolved = path12.isAbsolute(trimmed) ? trimmed : path12.resolve(cwd, trimmed);
7214
- const relative = path12.relative(cwd, resolved);
7215
- const displayPath = relative && !relative.startsWith("..") && !path12.isAbsolute(relative) ? relative : trimmed;
7216
- return displayPath.split(path12.sep).join("/");
7412
+ const resolved = path13.isAbsolute(trimmed) ? trimmed : path13.resolve(cwd, trimmed);
7413
+ const relative = path13.relative(cwd, resolved);
7414
+ const displayPath = relative && !relative.startsWith("..") && !path13.isAbsolute(relative) ? relative : trimmed;
7415
+ return displayPath.split(path13.sep).join("/");
7217
7416
  }
7218
7417
  function uniqueRuntimeSourcePaths(values) {
7219
7418
  return [...new Set([...values].filter((value) => Boolean(value)))].sort();
@@ -7223,7 +7422,7 @@ function testSourceEvalPath(cwd, test) {
7223
7422
  }
7224
7423
  function testSourceEvalPathForComparison(test) {
7225
7424
  const sourcePath = test.source?.evalFileAbsolutePath ?? test.source?.evalFilePath;
7226
- return sourcePath ? path12.resolve(sourcePath) : void 0;
7425
+ return sourcePath ? path13.resolve(sourcePath) : void 0;
7227
7426
  }
7228
7427
  function buildRuntimeConfigSource(params) {
7229
7428
  const inlineFingerprints = /* @__PURE__ */ new Set();
@@ -7254,7 +7453,7 @@ function buildRuntimeSourceMetadata(params) {
7254
7453
  params.activeTestFiles.map((filePath) => toRuntimeSourcePath(params.cwd, filePath))
7255
7454
  );
7256
7455
  const activeResolvedFiles = new Set(
7257
- params.activeTestFiles.map((filePath) => path12.resolve(filePath))
7456
+ params.activeTestFiles.map((filePath) => path13.resolve(filePath))
7258
7457
  );
7259
7458
  const sourceEvalFiles = uniqueRuntimeSourcePaths(
7260
7459
  params.sourceTests.map((test) => testSourceEvalPath(params.cwd, test))
@@ -7285,22 +7484,21 @@ function applyExperimentOptions(options, experiment) {
7285
7484
  if (!experiment) {
7286
7485
  return options;
7287
7486
  }
7288
- const experimentTargetRefs = buildExperimentTargetRefs(experiment);
7289
- const experimentTargetNames = experimentTargetRefs?.map((target) => target.name) ?? [];
7487
+ const experimentProviderRefs = buildExperimentTargetRefs(experiment);
7488
+ const experimentProviderLabels = experimentProviderRefs?.map((target) => target.name) ?? [];
7290
7489
  const experimentTarget = experiment.target && experiment.target.trim().length > 0 ? experiment.target : void 0;
7291
- const experimentTargets = options.cliTargets.length === 0 ? experimentTargetNames.length > 0 ? experimentTargetNames : experimentTarget ? [experimentTarget] : void 0 : void 0;
7490
+ const experimentProviders = options.cliProviderLabels.length === 0 ? experimentProviderLabels.length > 0 ? experimentProviderLabels : experimentTarget ? [experimentTarget] : void 0 : void 0;
7292
7491
  return {
7293
7492
  ...options,
7294
- target: options.target,
7295
7493
  agentTimeoutSeconds: options.agentTimeoutSeconds ?? experiment.timeoutSeconds,
7296
7494
  workspacePath: options.workspacePath,
7297
7495
  budgetUsd: options.budgetUsd ?? experiment.budgetUsd,
7298
7496
  threshold: options.threshold ?? experiment.threshold,
7299
7497
  experimentConfig: experiment,
7300
7498
  experimentMetadata: buildExperimentArtifactMetadata(experiment),
7301
- experimentTargets,
7302
- experimentTargetRefs: options.cliTargets.length === 0 ? experimentTargetRefs : void 0,
7303
- targetModelOverride: options.targetModelOverride ?? experiment.model,
7499
+ experimentProviderLabels: experimentProviders,
7500
+ experimentProviderRefs: options.cliProviderLabels.length === 0 ? experimentProviderRefs : void 0,
7501
+ providerModelOverride: options.providerModelOverride ?? experiment.model,
7304
7502
  experimentTrialsConfig: buildExperimentTrialsConfig(experiment)
7305
7503
  };
7306
7504
  }
@@ -7328,11 +7526,7 @@ function buildExperimentTrialsConfig(experiment) {
7328
7526
  }
7329
7527
  return {
7330
7528
  count: experiment.repeat.count,
7331
- strategy: experiment.repeat.strategy,
7332
- ...experiment.repeat.costLimitUsd !== void 0 && {
7333
- costLimitUsd: experiment.repeat.costLimitUsd
7334
- },
7335
- ...experiment.repeat.earlyExit !== void 0 && { earlyExit: experiment.repeat.earlyExit }
7529
+ strategy: experiment.repeat.strategy
7336
7530
  };
7337
7531
  }
7338
7532
  return void 0;
@@ -7344,9 +7538,7 @@ function buildRunOverrideTrialsConfig(run) {
7344
7538
  }
7345
7539
  return {
7346
7540
  count: repeat.count,
7347
- strategy: repeat.strategy,
7348
- ...repeat.costLimitUsd !== void 0 && { costLimitUsd: repeat.costLimitUsd },
7349
- ...repeat.earlyExit !== void 0 && { earlyExit: repeat.earlyExit }
7541
+ strategy: repeat.strategy
7350
7542
  };
7351
7543
  }
7352
7544
  function resolveEffectiveRunPolicy(params) {
@@ -7408,7 +7600,7 @@ function createProgressReporter(maxWorkers, options) {
7408
7600
  };
7409
7601
  }
7410
7602
  function makeTestCaseKey(testFilePath, testId) {
7411
- return `${path12.resolve(testFilePath)}::${testId}`;
7603
+ return `${path13.resolve(testFilePath)}::${testId}`;
7412
7604
  }
7413
7605
  function resolveTargetLabel(requestedName, resolvedName) {
7414
7606
  if (resolvedName !== requestedName) {
@@ -7447,23 +7639,23 @@ function buildTargetLabelSuffix(providerLabel, target) {
7447
7639
  return `[${parts.join(", ")}]`;
7448
7640
  }
7449
7641
  function applyVerboseOverride(selection, cliVerbose) {
7450
- const { resolvedTarget } = selection;
7451
- if (resolvedTarget.kind !== "cli") {
7642
+ const { resolvedProvider } = selection;
7643
+ if (resolvedProvider.kind !== "cli") {
7452
7644
  return selection;
7453
7645
  }
7454
7646
  return {
7455
7647
  ...selection,
7456
- resolvedTarget: {
7457
- ...resolvedTarget,
7648
+ resolvedProvider: {
7649
+ ...resolvedProvider,
7458
7650
  config: {
7459
- ...resolvedTarget.config,
7651
+ ...resolvedProvider.config,
7460
7652
  verbose: cliVerbose
7461
7653
  }
7462
7654
  }
7463
7655
  };
7464
7656
  }
7465
7657
  function targetVariantForSelection(selection) {
7466
- const target = selection.resolvedTarget;
7658
+ const target = selection.resolvedProvider;
7467
7659
  if (target.kind === "replay") {
7468
7660
  return target.config.variant;
7469
7661
  }
@@ -7505,20 +7697,24 @@ async function readExistingResultsFromRunDir(runDir) {
7505
7697
  }
7506
7698
  return results;
7507
7699
  }
7700
+ async function collectTerminalSummaryResults(params) {
7701
+ const rawResults = params.isResumeAppend ? await (params.readExistingResults ?? readExistingResultsFromRunDir)(params.runDir) : params.allResults;
7702
+ return deduplicateByTestIdTarget(rawResults);
7703
+ }
7508
7704
  async function resolveRerunFailedRunDir(cwd, source) {
7509
7705
  const trimmed = source.trim();
7510
7706
  if (!trimmed) {
7511
7707
  throw new Error("--rerun-failed requires a run ID, run workspace, or index.jsonl path.");
7512
7708
  }
7513
- const candidate = path12.isAbsolute(trimmed) ? trimmed : path12.resolve(cwd, trimmed);
7709
+ const candidate = path13.isAbsolute(trimmed) ? trimmed : path13.resolve(cwd, trimmed);
7514
7710
  if (existsSync5(candidate)) {
7515
- if (path12.basename(candidate) !== RESULT_INDEX_FILENAME) {
7711
+ if (path13.basename(candidate) !== RESULT_INDEX_FILENAME) {
7516
7712
  return candidate;
7517
7713
  }
7518
- const manifestDir = path12.dirname(candidate);
7519
- return path12.basename(manifestDir) === ".internal" ? path12.dirname(manifestDir) : manifestDir;
7714
+ const manifestDir = path13.dirname(candidate);
7715
+ return path13.basename(manifestDir) === ".internal" ? path13.dirname(manifestDir) : manifestDir;
7520
7716
  }
7521
- const runIdCandidate = path12.join(cwd, ".agentv", "results", trimmed);
7717
+ const runIdCandidate = path13.join(cwd, ".agentv", "results", trimmed);
7522
7718
  if (existsSync5(runIdCandidate)) {
7523
7719
  return runIdCandidate;
7524
7720
  }
@@ -7527,14 +7723,23 @@ async function resolveRerunFailedRunDir(cwd, source) {
7527
7723
  );
7528
7724
  }
7529
7725
  async function prepareFileMetadata(params) {
7530
- const { testFilePath, repoRoot, cwd, options, suiteFilter } = params;
7726
+ const {
7727
+ testFilePath,
7728
+ repoRoot,
7729
+ cwd,
7730
+ options,
7731
+ providerCatalogPath,
7732
+ providerDefinitions,
7733
+ providerDefinitionsSource,
7734
+ suiteFilter
7735
+ } = params;
7531
7736
  await ensureFileExists(testFilePath, "Test file");
7532
7737
  await loadEnvFromHierarchy({
7533
7738
  testFilePath,
7534
7739
  repoRoot,
7535
7740
  verbose: options.verbose
7536
7741
  });
7537
- const relativePath = path12.relative(cwd, testFilePath);
7742
+ const relativePath = path13.relative(cwd, testFilePath);
7538
7743
  const category = deriveCategory(relativePath);
7539
7744
  const suite = await loadCliEvalSuite(testFilePath, repoRoot, {
7540
7745
  verbose: options.verbose,
@@ -7543,21 +7748,24 @@ async function prepareFileMetadata(params) {
7543
7748
  });
7544
7749
  const experimentOptions = applyExperimentOptions(options, suite.experimentConfig);
7545
7750
  const effectiveOptions = experimentOptions.workers === void 0 && suite.workers !== void 0 ? { ...experimentOptions, workers: suite.workers } : experimentOptions;
7751
+ const effectiveProviderCatalogPath = effectiveOptions.providersPath ?? providerCatalogPath;
7546
7752
  const testCases = suiteFilter && effectiveOptions.filter ? suite.tests.filter(
7547
7753
  (testCase) => matchesTestFilter(testCase.id, effectiveOptions.filter ?? "")
7548
7754
  ) : suite.tests;
7549
7755
  const testIds = testCases.map((value) => value.id);
7550
7756
  const suiteTargetSpec = suite.targetSpec;
7757
+ const suiteDefaults = suite.defaults;
7551
7758
  const suiteTargets = suiteTargetSpec ? [suiteTargetSpec.name] : suite.targets;
7759
+ const fileOptions = suiteDefaults?.grader && !effectiveOptions.graderTarget ? { ...effectiveOptions, defaultGraderTarget: suiteDefaults.grader } : effectiveOptions;
7552
7760
  const defaultBudgetUsd = effectiveOptions.cliBudgetUsd === void 0 ? effectiveOptions.budgetUsd ?? suite.budgetUsd : void 0;
7553
7761
  const suiteDefaultThreshold = suite.defaultTest?.threshold ?? suite.threshold;
7554
7762
  if (testCases.length === 0) {
7555
7763
  return {
7556
- options: effectiveOptions,
7764
+ options: fileOptions,
7557
7765
  testIds,
7558
7766
  testCases,
7559
7767
  selections: [],
7560
- trialsConfig: effectiveOptions.experimentTrialsConfig,
7768
+ trialsConfig: fileOptions.experimentTrialsConfig,
7561
7769
  suiteTargets,
7562
7770
  yamlCache: suite.cacheConfig?.enabled,
7563
7771
  yamlCachePath: suite.cacheConfig?.cachePath,
@@ -7569,42 +7777,47 @@ async function prepareFileMetadata(params) {
7569
7777
  };
7570
7778
  }
7571
7779
  let selections;
7572
- if (effectiveOptions.transcript) {
7780
+ if (fileOptions.transcript) {
7573
7781
  const transcriptSelection = {
7574
7782
  definitions: [],
7575
- resolvedTarget: {
7783
+ resolvedProvider: {
7576
7784
  kind: "transcript",
7577
7785
  name: "transcript",
7578
7786
  config: {}
7579
7787
  },
7580
- targetName: "transcript",
7581
- targetSource: "cli",
7582
- targetsFilePath: effectiveOptions.transcript
7788
+ providerLabel: "transcript",
7789
+ providerSource: "cli",
7790
+ providersFilePath: fileOptions.transcript
7583
7791
  };
7584
7792
  selections = [
7585
7793
  {
7586
7794
  selection: transcriptSelection,
7587
- inlineTargetLabel: `transcript (${path12.basename(effectiveOptions.transcript)})`
7795
+ inlineTargetLabel: `transcript (${path13.basename(fileOptions.transcript)})`
7588
7796
  }
7589
7797
  ];
7590
- } else if (suite.inlineTarget && effectiveOptions.cliTargets.length === 0) {
7798
+ } else if (suite.inlineTarget && fileOptions.cliProviderLabels.length === 0) {
7591
7799
  const targetDefinition = suite.inlineTarget;
7592
- const resolvedTarget = resolveTargetDefinition(targetDefinition, process.env, testFilePath, {
7593
- emitDeprecationWarnings: false
7594
- });
7800
+ const resolvedProvider = resolveProviderDefinition(
7801
+ targetDefinition,
7802
+ process.env,
7803
+ testFilePath,
7804
+ {
7805
+ emitDeprecationWarnings: false
7806
+ }
7807
+ );
7595
7808
  selections = [
7596
7809
  {
7597
7810
  selection: {
7598
7811
  definitions: [targetDefinition],
7599
- resolvedTarget,
7600
- targetName: targetDefinition.name,
7601
- targetSource: "test-file",
7602
- targetsFilePath: testFilePath
7812
+ resolvedProvider,
7813
+ providerLabel: targetDefinition.name,
7814
+ providerSource: "test-file",
7815
+ providersFilePath: testFilePath
7603
7816
  },
7604
- inlineTargetLabel: resolveTargetLabel(targetDefinition.name, resolvedTarget.name)
7817
+ inlineTargetLabel: resolveTargetLabel(targetDefinition.name, resolvedProvider.name)
7605
7818
  }
7606
7819
  ];
7607
- } else if (suite.providerFactory && effectiveOptions.cliTargets.length === 0) {
7820
+ } else if (suite.providerFactory && fileOptions.cliProviderLabels.length === 0) {
7608
7821
  const taskTarget = {
7609
7822
  kind: "mock",
7610
7823
  name: "custom-task",
@@ -7615,89 +7828,100 @@ async function prepareFileMetadata(params) {
7615
7828
  {
7616
7829
  selection: {
7617
7830
  definitions: [],
7618
- resolvedTarget: taskTarget,
7619
- targetName: "custom-task",
7620
- targetSource: "test-file",
7621
- targetsFilePath: testFilePath
7831
+ resolvedProvider: taskTarget,
7832
+ providerLabel: "custom-task",
7833
+ providerSource: "test-file",
7834
+ providersFilePath: testFilePath
7622
7835
  },
7623
7836
  inlineTargetLabel: "custom-task"
7624
7837
  }
7625
7838
  ];
7626
7839
  } else {
7627
- const cliTargets = effectiveOptions.cliTargets;
7628
- const experimentTargets = effectiveOptions.experimentTargets ?? [];
7840
+ const cliProviderLabels = fileOptions.cliProviderLabels;
7841
+ const experimentProviderLabels = fileOptions.experimentProviderLabels ?? [];
7629
7842
  const suiteTargetSpec2 = suite.targetSpec;
7630
- const suiteTargets2 = suiteTargetSpec2 ? [suiteTargetSpec2.name] : suite.targets;
7631
- const suiteTargetRefs = suite.targetRefs;
7632
- const experimentTargetRefs = effectiveOptions.experimentTargetRefs;
7633
- let targetNames;
7634
- let targetRefs;
7635
- let targetSource = "test-file";
7636
- if (cliTargets.length > 0) {
7637
- targetNames = cliTargets;
7638
- targetRefs = experimentTargetRefs;
7639
- targetSource = "cli";
7640
- } else if (experimentTargets.length > 0) {
7641
- targetNames = experimentTargets;
7642
- targetRefs = experimentTargetRefs;
7643
- } else if (suiteTargets2 && suiteTargets2.length > 0) {
7644
- targetNames = suiteTargets2;
7645
- targetRefs = suiteTargetRefs;
7843
+ const suiteProviderLabels = suiteTargetSpec2 ? [suiteTargetSpec2.name] : suite.targets;
7844
+ const suiteProviderRefs = suite.targetRefs;
7845
+ const experimentProviderRefs = fileOptions.experimentProviderRefs;
7846
+ let providerLabels;
7847
+ let providerRefs;
7848
+ let providerSource = "test-file";
7849
+ if (cliProviderLabels.length > 0) {
7850
+ providerLabels = cliProviderLabels;
7851
+ providerRefs = experimentProviderRefs;
7852
+ providerSource = "cli";
7853
+ } else if (experimentProviderLabels.length > 0) {
7854
+ providerLabels = experimentProviderLabels;
7855
+ providerRefs = experimentProviderRefs;
7856
+ } else if (suiteProviderLabels && suiteProviderLabels.length > 0) {
7857
+ providerLabels = suiteProviderLabels;
7858
+ providerRefs = suiteProviderRefs;
7859
+ } else if (suiteDefaults?.provider) {
7860
+ providerLabels = [suiteDefaults.provider];
7861
+ providerRefs = void 0;
7646
7862
  } else {
7647
- targetNames = [];
7648
- targetRefs = void 0;
7863
+ providerLabels = [];
7864
+ providerRefs = void 0;
7649
7865
  }
7650
- if (targetNames.length > 1 || targetNames.length === 1 && targetRefs) {
7651
- const multiSelections = await selectMultipleTargets({
7866
+ if (providerLabels.length > 1 || providerLabels.length === 1 && providerRefs) {
7867
+ const multiSelections = await selectMultipleProviders({
7652
7868
  testFilePath,
7653
7869
  repoRoot,
7654
7870
  cwd,
7655
- explicitTargetsPath: effectiveOptions.targetsPath,
7871
+ explicitProvidersPath: effectiveProviderCatalogPath,
7872
+ providerDefinitions,
7873
+ providerDefinitionsSource,
7874
+ requireExplicitProviderCatalog: true,
7875
+ allowLegacyTargetFiles: fileOptions.allowLegacyTargetFiles,
7656
7876
  env: process.env,
7657
- targetNames,
7658
- targetRefs,
7659
- targetSource,
7660
- modelOverride: effectiveOptions.targetModelOverride
7877
+ providerLabels,
7878
+ providerRefs,
7879
+ providerSource,
7880
+ modelOverride: fileOptions.providerModelOverride
7661
7881
  });
7662
7882
  selections = multiSelections.map((sel) => ({
7663
7883
  selection: sel,
7664
- inlineTargetLabel: sel.targetLabel ?? resolveTargetLabel(sel.targetName, sel.resolvedTarget.name)
7884
+ inlineTargetLabel: sel.providerDisplayLabel ?? resolveTargetLabel(sel.providerLabel, sel.resolvedProvider.name)
7665
7885
  }));
7666
7886
  } else {
7667
- const selection = await selectTarget({
7887
+ const selection = await selectProvider({
7668
7888
  testFilePath,
7669
7889
  repoRoot,
7670
7890
  cwd,
7671
- explicitTargetsPath: effectiveOptions.targetsPath,
7672
- cliTargetName: targetSource === "cli" ? targetNames.length === 1 ? targetNames[0] : effectiveOptions.target : effectiveOptions.target,
7673
- fileTargetName: targetSource === "test-file" && targetNames.length === 1 ? targetNames[0] : void 0,
7674
- fileTargetSpec: targetSource === "test-file" && targetNames.length === 1 ? suiteTargetSpec2 : void 0,
7675
- modelOverride: effectiveOptions.targetModelOverride,
7891
+ explicitProvidersPath: effectiveProviderCatalogPath,
7892
+ providerDefinitions,
7893
+ providerDefinitionsSource,
7894
+ requireExplicitProviderCatalog: true,
7895
+ allowLegacyTargetFiles: fileOptions.allowLegacyTargetFiles,
7896
+ cliProviderLabel: providerSource === "cli" ? providerLabels.length === 1 ? providerLabels[0] : fileOptions.provider : fileOptions.provider,
7897
+ fileProviderLabel: providerSource === "test-file" && providerLabels.length === 1 ? providerLabels[0] : void 0,
7898
+ fileTargetSpec: providerSource === "test-file" && providerLabels.length === 1 ? suiteTargetSpec2 : void 0,
7899
+ modelOverride: fileOptions.providerModelOverride,
7676
7900
  env: process.env
7677
7901
  });
7678
- const singleTargetRef = targetRefs?.find((ref) => ref.name === selection.targetName);
7902
+ const singleProviderRef = providerRefs?.find((ref) => ref.name === selection.providerLabel);
7679
7903
  const augmentedSelection = {
7680
7904
  ...selection,
7681
- ...singleTargetRef?.label ? { targetLabel: singleTargetRef.label } : {},
7682
- ...singleTargetRef?.hooks ? { targetHooks: singleTargetRef.hooks } : {}
7905
+ ...singleProviderRef?.label ? { providerDisplayLabel: singleProviderRef.label } : {},
7906
+ ...singleProviderRef?.hooks ? { providerHooks: singleProviderRef.hooks } : {}
7683
7907
  };
7684
7908
  selections = [
7685
7909
  {
7686
7910
  selection: augmentedSelection,
7687
- inlineTargetLabel: augmentedSelection.targetLabel ?? resolveTargetLabel(
7688
- augmentedSelection.targetName,
7689
- augmentedSelection.resolvedTarget.name
7911
+ inlineTargetLabel: augmentedSelection.providerDisplayLabel ?? resolveTargetLabel(
7912
+ augmentedSelection.providerLabel,
7913
+ augmentedSelection.resolvedProvider.name
7690
7914
  )
7691
7915
  }
7692
7916
  ];
7693
7917
  }
7694
7918
  }
7695
7919
  return {
7696
- options: effectiveOptions,
7920
+ options: fileOptions,
7697
7921
  testIds,
7698
7922
  testCases,
7699
7923
  selections,
7700
- trialsConfig: effectiveOptions.experimentTrialsConfig,
7924
+ trialsConfig: fileOptions.experimentTrialsConfig,
7701
7925
  suiteTargets,
7702
7926
  yamlCache: suite.cacheConfig?.enabled,
7703
7927
  yamlCachePath: suite.cacheConfig?.cachePath,
@@ -7708,7 +7932,7 @@ async function prepareFileMetadata(params) {
7708
7932
  providerFactory: suite.providerFactory
7709
7933
  };
7710
7934
  }
7711
- function buildTaskBundleTargetSelections(activeTestFiles, fileMetadata) {
7935
+ function buildTaskBundleProviderSelections(activeTestFiles, fileMetadata) {
7712
7936
  return activeTestFiles.flatMap((testFilePath) => {
7713
7937
  const meta = fileMetadata.get(testFilePath);
7714
7938
  if (!meta) {
@@ -7716,8 +7940,8 @@ function buildTaskBundleTargetSelections(activeTestFiles, fileMetadata) {
7716
7940
  }
7717
7941
  return meta.selections.map(({ selection }) => ({
7718
7942
  evalFileAbsolutePath: testFilePath,
7719
- targetName: selection.targetName,
7720
- resolvedTargetName: selection.resolvedTarget.name,
7943
+ providerLabel: selection.providerLabel,
7944
+ resolvedProviderName: selection.resolvedProvider.name,
7721
7945
  definitions: selection.definitions
7722
7946
  }));
7723
7947
  });
@@ -7746,22 +7970,22 @@ async function runSingleEvalFile(params) {
7746
7970
  failOnError,
7747
7971
  providerFactory
7748
7972
  } = params;
7749
- const targetName = selection.targetName;
7973
+ const providerLabel = selection.providerLabel;
7750
7974
  const replayRecording = options.recordReplay ? {
7751
- fixturesPath: path12.resolve(options.recordReplay),
7752
- sourceTarget: targetName,
7975
+ fixturesPath: path13.resolve(options.recordReplay),
7976
+ sourceTarget: providerLabel,
7753
7977
  variant: options.recordReplayVariant
7754
7978
  } : void 0;
7755
7979
  await ensureFileExists(testFilePath, "Test file");
7756
- const resolvedTargetSelection = applyVerboseOverride(selection, options.verbose);
7757
- const explicitVariant = targetVariantForSelection(resolvedTargetSelection);
7758
- const providerLabel = resolvedTargetSelection.resolvedTarget.kind;
7759
- const targetMessage = options.verbose ? `Using target (${resolvedTargetSelection.targetSource}): ${resolvedTargetSelection.targetName} ${buildTargetLabelSuffix(providerLabel, resolvedTargetSelection.resolvedTarget)} via ${resolvedTargetSelection.targetsFilePath}` : `Using target: ${inlineTargetLabel}`;
7980
+ const resolvedProviderSelection = applyVerboseOverride(selection, options.verbose);
7981
+ const explicitVariant = targetVariantForSelection(resolvedProviderSelection);
7982
+ const providerId = resolvedProviderSelection.resolvedProvider.kind;
7983
+ const targetMessage = options.verbose ? `Using provider (${resolvedProviderSelection.providerSource}): ${resolvedProviderSelection.providerLabel} ${buildTargetLabelSuffix(providerId, resolvedProviderSelection.resolvedProvider)} via ${resolvedProviderSelection.providersFilePath}` : `Using provider: ${inlineTargetLabel}`;
7760
7984
  if (!progressReporter.isInteractive || options.verbose) {
7761
7985
  console.log(`${targetMessage}`);
7762
7986
  }
7763
- const targetKind = resolvedTargetSelection.resolvedTarget.kind;
7764
- if (targetKind === "claude-cli" || targetKind === "copilot-cli") {
7987
+ const providerKind = resolvedProviderSelection.resolvedProvider.kind;
7988
+ if (providerKind === "claude-cli" || providerKind === "copilot-cli") {
7765
7989
  console.log("");
7766
7990
  console.log(" TIP: For subagent-mode evals, use `agentv pipeline` instead of `eval run`.");
7767
7991
  console.log(" The agent orchestrates executor + grader subagents directly.");
@@ -7770,12 +7994,12 @@ async function runSingleEvalFile(params) {
7770
7994
  }
7771
7995
  const agentTimeoutMs = agentTimeoutSeconds != null ? Math.max(0, agentTimeoutSeconds) * 1e3 : void 0;
7772
7996
  const workerPreference = workersOverride ?? options.workers;
7773
- let resolvedWorkers = workerPreference ?? resolvedTargetSelection.resolvedTarget.workers ?? DEFAULT_WORKERS;
7997
+ let resolvedWorkers = workerPreference ?? resolvedProviderSelection.resolvedProvider.workers ?? DEFAULT_WORKERS;
7774
7998
  if (resolvedWorkers < 1 || resolvedWorkers > 50) {
7775
7999
  throw new Error(`Workers must be between 1 and 50, got: ${resolvedWorkers}`);
7776
8000
  }
7777
8001
  const isVSCodeProvider = ["vscode", "vscode-insiders"].includes(
7778
- resolvedTargetSelection.resolvedTarget.kind
8002
+ resolvedProviderSelection.resolvedProvider.kind
7779
8003
  );
7780
8004
  if (isVSCodeProvider && resolvedWorkers > 1) {
7781
8005
  console.warn(
@@ -7784,9 +8008,9 @@ async function runSingleEvalFile(params) {
7784
8008
  resolvedWorkers = 1;
7785
8009
  }
7786
8010
  if (isVSCodeProvider) {
7787
- const vsConfig = resolvedTargetSelection.resolvedTarget.config;
8011
+ const vsConfig = resolvedProviderSelection.resolvedProvider.config;
7788
8012
  await ensureVSCodeSubagents({
7789
- kind: resolvedTargetSelection.resolvedTarget.kind,
8013
+ kind: resolvedProviderSelection.resolvedProvider.kind,
7790
8014
  count: resolvedWorkers,
7791
8015
  verbose: options.verbose,
7792
8016
  vscodeCmd: vsConfig.executable
@@ -7795,15 +8019,15 @@ async function runSingleEvalFile(params) {
7795
8019
  const results = await evaluationRunner({
7796
8020
  testFilePath,
7797
8021
  repoRoot,
7798
- target: resolvedTargetSelection.resolvedTarget,
7799
- targets: resolvedTargetSelection.definitions,
8022
+ target: resolvedProviderSelection.resolvedProvider,
8023
+ targets: resolvedProviderSelection.definitions,
7800
8024
  env: process.env,
7801
8025
  maxRetries: Math.max(0, options.maxRetries),
7802
8026
  agentTimeoutMs,
7803
8027
  cache,
7804
8028
  useCache: (() => {
7805
8029
  if (!cache) return false;
7806
- const targetConfig = resolvedTargetSelection.resolvedTarget.config;
8030
+ const targetConfig = resolvedProviderSelection.resolvedProvider.config;
7807
8031
  if (shouldSkipCacheForTemperature(targetConfig)) {
7808
8032
  if (options.verbose) {
7809
8033
  console.log("Cache skipped: target temperature > 0");
@@ -7823,9 +8047,10 @@ async function runSingleEvalFile(params) {
7823
8047
  runBudgetTracker,
7824
8048
  failOnError,
7825
8049
  graderTarget: options.graderTarget,
8050
+ defaultGraderTarget: options.defaultGraderTarget,
7826
8051
  model: options.model,
7827
8052
  threshold: params.threshold,
7828
- targetHooks: resolvedTargetSelection.targetHooks,
8053
+ targetHooks: resolvedProviderSelection.providerHooks,
7829
8054
  replayRecording,
7830
8055
  providerFactory,
7831
8056
  onResult: async (result) => {
@@ -7835,7 +8060,7 @@ async function runSingleEvalFile(params) {
7835
8060
  await outputWriter.append(trimmedResult);
7836
8061
  },
7837
8062
  onProgress: async (event) => {
7838
- const testCaseKeyId = matrixMode ? `${event.testId}@${targetName}` : event.testId;
8063
+ const testCaseKeyId = matrixMode ? `${event.testId}@${providerLabel}` : event.testId;
7839
8064
  const testCaseKey = makeTestCaseKey(testFilePath, testCaseKeyId);
7840
8065
  if (event.status === "pending" && !seenTestCases.has(testCaseKey)) {
7841
8066
  seenTestCases.add(testCaseKey);
@@ -7848,7 +8073,7 @@ async function runSingleEvalFile(params) {
7848
8073
  else if (event.executionStatus === "execution_error") verdict = "ERROR";
7849
8074
  progressReporter.update(displayId, {
7850
8075
  workerId: displayId,
7851
- testId: matrixMode ? `${event.testId}@${targetName}` : event.testId,
8076
+ testId: matrixMode ? `${event.testId}@${providerLabel}` : event.testId,
7852
8077
  status: event.status,
7853
8078
  startedAt: event.startedAt,
7854
8079
  completedAt: event.completedAt,
@@ -7882,7 +8107,7 @@ async function runEvalCommand(input) {
7882
8107
  );
7883
8108
  }
7884
8109
  const repoRoot = await findRepoRoot(cwd);
7885
- const yamlConfig = await loadConfig(path12.join(cwd, "_"), repoRoot);
8110
+ const yamlConfig = await loadConfig(path13.join(cwd, "_"), repoRoot);
7886
8111
  let requiredVersionCheck;
7887
8112
  if (yamlConfig?.required_version) {
7888
8113
  requiredVersionCheck = await enforceRequiredVersion(yamlConfig.required_version, {
@@ -7890,10 +8115,19 @@ async function runEvalCommand(input) {
7890
8115
  });
7891
8116
  }
7892
8117
  let options = normalizeOptions(input.rawOptions, config, yamlConfig?.execution);
8118
+ if (yamlConfig?.defaults?.provider && options.cliProviderLabels.length === 0 && !options.provider) {
8119
+ options = { ...options, provider: yamlConfig.defaults.provider };
8120
+ }
8121
+ if (yamlConfig?.defaults?.grader) {
8122
+ options = { ...options, defaultGraderTarget: yamlConfig.defaults.grader };
8123
+ }
8124
+ const providerCatalogPath = yamlConfig?.providerCatalogPath;
8125
+ const providerDefinitions = yamlConfig?.providerDefinitions;
8126
+ const providerDefinitionsSource = providerDefinitions ? providerCatalogPath ?? ".agentv/config.yaml:providers" : void 0;
7893
8127
  const resolvedExperiment = resolveExperimentForRun(options.experiment);
7894
8128
  const evalPathInputs = input.testFiles.length > 0 ? [...input.testFiles] : [];
7895
8129
  if (evalPathInputs.length === 0 && process.stdin.isTTY) {
7896
- const { launchInteractiveWizard } = await import("./interactive-BN527UV3.js");
8130
+ const { launchInteractiveWizard } = await import("./interactive-DL7N2C7K.js");
7897
8131
  await launchInteractiveWizard();
7898
8132
  return void 0;
7899
8133
  }
@@ -7904,7 +8138,7 @@ async function runEvalCommand(input) {
7904
8138
  const primarySuite = resolvedTestFiles.length > 0 ? await loadCliEvalSuite(resolvedTestFiles[0], repoRoot, {
7905
8139
  verbose: options.verbose,
7906
8140
  filter: options.filter,
7907
- category: deriveCategory(path12.relative(cwd, resolvedTestFiles[0]))
8141
+ category: deriveCategory(path13.relative(cwd, resolvedTestFiles[0]))
7908
8142
  }) : void 0;
7909
8143
  const resultGroupName = resolvedTestFiles.length === 1 ? primarySuite?.metadata?.name ?? fallbackResultGroupName : fallbackResultGroupName;
7910
8144
  const resolvedTags = resolveEffectiveTags({
@@ -7933,7 +8167,7 @@ async function runEvalCommand(input) {
7933
8167
  process.env.AGENTV_EXPERIMENT = normalizedExperiment;
7934
8168
  }
7935
8169
  if (options.graderTarget === "agentv" && !options.model) {
7936
- throw new Error("--grader-target agentv requires --model (e.g., --model openai:gpt-5-mini)");
8170
+ throw new Error("--grader-provider agentv requires --model (e.g., --model openai:gpt-5-mini)");
7937
8171
  }
7938
8172
  if (options.removedOut) {
7939
8173
  throw new Error(
@@ -7957,7 +8191,7 @@ async function runEvalCommand(input) {
7957
8191
  }
7958
8192
  let retryNonErrorResults;
7959
8193
  if (options.retryErrors) {
7960
- const retryPath = path12.resolve(options.retryErrors);
8194
+ const retryPath = path13.resolve(options.retryErrors);
7961
8195
  await ensureFileExists(retryPath, "Retry-errors JSONL file");
7962
8196
  const completedIds = await loadFullyCompletedTestIds(retryPath);
7963
8197
  const errorIds = await loadErrorTestIds(retryPath);
@@ -7974,7 +8208,7 @@ async function runEvalCommand(input) {
7974
8208
  const cachedDir = await resolveCachedRunDir(cwd);
7975
8209
  if (cachedDir) {
7976
8210
  options = { ...options, outputDir: cachedDir };
7977
- const displayDir = path12.relative(cwd, cachedDir) || cachedDir;
8211
+ const displayDir = path13.relative(cwd, cachedDir) || cachedDir;
7978
8212
  console.log(`Auto-detected last run dir for --resume: ${displayDir}`);
7979
8213
  }
7980
8214
  }
@@ -7982,7 +8216,7 @@ async function runEvalCommand(input) {
7982
8216
  let rerunIncludeKeys;
7983
8217
  let isResumeAppend = false;
7984
8218
  if (options.resume && !options.retryErrors) {
7985
- const sourceRunDir = options.rerunFailedSource ? await resolveRerunFailedRunDir(cwd, options.rerunFailedSource) : options.outputDir ? path12.resolve(options.outputDir) : void 0;
8219
+ const sourceRunDir = options.rerunFailedSource ? await resolveRerunFailedRunDir(cwd, options.rerunFailedSource) : options.outputDir ? path13.resolve(options.outputDir) : void 0;
7986
8220
  if (sourceRunDir) {
7987
8221
  if (options.rerunFailedSource && !options.outputDir) {
7988
8222
  options = { ...options, outputDir: sourceRunDir };
@@ -8001,7 +8235,7 @@ async function runEvalCommand(input) {
8001
8235
  addResumeIdentityEntry(rerunIncludeKeys, entry);
8002
8236
  }
8003
8237
  }
8004
- isResumeAppend = options.outputDir !== void 0 && path12.resolve(options.outputDir) === path12.resolve(sourceRunDir);
8238
+ isResumeAppend = options.outputDir !== void 0 && path13.resolve(options.outputDir) === path13.resolve(sourceRunDir);
8005
8239
  const modeLabel = options.rerunFailed ? "Rerun-failed" : "Resume";
8006
8240
  console.log(
8007
8241
  `${modeLabel}: found ${existingResults.length} existing result(s), skipping ${completedResultCount} completed.`
@@ -8019,10 +8253,10 @@ async function runEvalCommand(input) {
8019
8253
  }
8020
8254
  }
8021
8255
  if (options.workspacePath) {
8022
- const resolvedWorkspace = path12.resolve(options.workspacePath);
8256
+ const resolvedWorkspace = path13.resolve(options.workspacePath);
8023
8257
  try {
8024
- const { stat: stat3 } = await import("node:fs/promises");
8025
- const stats = await stat3(resolvedWorkspace);
8258
+ const { stat: stat4 } = await import("node:fs/promises");
8259
+ const stats = await stat4(resolvedWorkspace);
8026
8260
  if (!stats.isDirectory()) {
8027
8261
  throw new Error(`--workspace-path is not a directory: ${resolvedWorkspace}`);
8028
8262
  }
@@ -8042,7 +8276,7 @@ async function runEvalCommand(input) {
8042
8276
  let outputPath;
8043
8277
  let runDirName = process.env.AGENTV_RUN_TIMESTAMP?.trim() || createRunDirName();
8044
8278
  if (explicitDir) {
8045
- runDir = path12.resolve(explicitDir);
8279
+ runDir = path13.resolve(explicitDir);
8046
8280
  mkdirSync(runDir, { recursive: true });
8047
8281
  outputPath = runDir;
8048
8282
  } else {
@@ -8057,7 +8291,7 @@ async function runEvalCommand(input) {
8057
8291
  outputPath = runDir;
8058
8292
  }
8059
8293
  if (!process.env.AGENTV_RUN_TIMESTAMP) {
8060
- process.env.AGENTV_RUN_TIMESTAMP = path12.basename(runDir);
8294
+ process.env.AGENTV_RUN_TIMESTAMP = path13.basename(runDir);
8061
8295
  }
8062
8296
  process.env.AGENTV_RUN_DIR = runDir;
8063
8297
  console.log(`Artifact directory: ${runDir}`);
@@ -8072,11 +8306,15 @@ async function runEvalCommand(input) {
8072
8306
  }
8073
8307
  const fileMetadata = /* @__PURE__ */ new Map();
8074
8308
  for (const testFilePath of resolvedTestFiles) {
8309
+ const fileProviderCatalogPath = options.providerCatalogPathByEvalFile?.get(path13.resolve(testFilePath)) ?? providerCatalogPath;
8075
8310
  const meta = await prepareFileMetadata({
8076
8311
  testFilePath,
8077
8312
  repoRoot,
8078
8313
  cwd,
8079
8314
  options,
8315
+ providerCatalogPath: fileProviderCatalogPath,
8316
+ providerDefinitions,
8317
+ providerDefinitionsSource: fileProviderCatalogPath ? fileProviderCatalogPath === providerCatalogPath ? providerDefinitionsSource : void 0 : providerDefinitionsSource,
8080
8318
  suiteFilter: void 0
8081
8319
  });
8082
8320
  fileMetadata.set(testFilePath, meta);
@@ -8087,7 +8325,7 @@ async function runEvalCommand(input) {
8087
8325
  for (const [testFilePath, meta] of fileMetadata.entries()) {
8088
8326
  if (!matchesTagFilters(meta.tags, options.tags, options.excludeTags)) {
8089
8327
  fileMetadata.delete(testFilePath);
8090
- skippedFiles.push(path12.relative(cwd, testFilePath));
8328
+ skippedFiles.push(path13.relative(cwd, testFilePath));
8091
8329
  }
8092
8330
  }
8093
8331
  if (skippedFiles.length > 0 && options.verbose) {
@@ -8110,12 +8348,12 @@ async function runEvalCommand(input) {
8110
8348
  tsConfigCache: options.tsConfigCache
8111
8349
  });
8112
8350
  const activeCachePath = options.cachePath ?? yamlCachePath ?? options.tsConfigCachePath;
8113
- const cache = cacheEnabled ? new ResponseCache(activeCachePath ? path12.resolve(activeCachePath) : void 0) : void 0;
8351
+ const cache = cacheEnabled ? new ResponseCache(activeCachePath ? path13.resolve(activeCachePath) : void 0) : void 0;
8114
8352
  if (cache) {
8115
8353
  console.log(`Response cache: enabled (${cache.cachePath})`);
8116
8354
  }
8117
8355
  if (options.recordReplay) {
8118
- console.log(`Replay recording: ${path12.resolve(options.recordReplay)}`);
8356
+ console.log(`Replay recording: ${path13.resolve(options.recordReplay)}`);
8119
8357
  }
8120
8358
  const yamlThreshold = firstMeta?.threshold;
8121
8359
  const resolvedThreshold = options.threshold ?? yamlThreshold;
@@ -8129,7 +8367,7 @@ async function runEvalCommand(input) {
8129
8367
  for (const meta of fileMetadata.values()) {
8130
8368
  for (const test of meta.testCases) {
8131
8369
  for (const { selection } of meta.selections) {
8132
- const target = selection.targetName;
8370
+ const target = selection.providerLabel;
8133
8371
  const variant = targetVariantForSelection(selection);
8134
8372
  if (rerunIncludeKeys) {
8135
8373
  if (resumeIdentityMatches(rerunIncludeKeys, test, target, variant)) {
@@ -8201,13 +8439,13 @@ async function runEvalCommand(input) {
8201
8439
  for (const testId of meta.testIds) {
8202
8440
  const testCaseKey = makeTestCaseKey(
8203
8441
  testFilePath,
8204
- meta.selections.length > 1 ? `${testId}@${selection.targetName}` : testId
8442
+ meta.selections.length > 1 ? `${testId}@${selection.providerLabel}` : testId
8205
8443
  );
8206
8444
  seenTestCases.add(testCaseKey);
8207
8445
  const displayId = displayIdTracker.getOrAssign(testCaseKey);
8208
8446
  progressReporter.update(displayId, {
8209
8447
  workerId: displayId,
8210
- testId: meta.selections.length > 1 ? `${testId}@${selection.targetName}` : testId,
8448
+ testId: meta.selections.length > 1 ? `${testId}@${selection.providerLabel}` : testId,
8211
8449
  status: "pending",
8212
8450
  targetLabel: inlineTargetLabel
8213
8451
  });
@@ -8233,7 +8471,7 @@ async function runEvalCommand(input) {
8233
8471
  });
8234
8472
  let transcriptProviderFactory;
8235
8473
  if (options.transcript) {
8236
- const { TranscriptProvider } = await import("./dist-NMXMI5SK.js");
8474
+ const { TranscriptProvider } = await import("./dist-A3SGR7TW.js");
8237
8475
  const transcriptProvider = await TranscriptProvider.fromFile(options.transcript);
8238
8476
  const totalTests = [...fileMetadata.values()].reduce(
8239
8477
  (sum, meta) => sum + meta.testCases.length,
@@ -8266,12 +8504,12 @@ async function runEvalCommand(input) {
8266
8504
  );
8267
8505
  }
8268
8506
  if (!isResumeAppend && totalEvalCount > 0) {
8269
- const evalFile = activeTestFiles.length === 1 ? activeTestFiles[0] : "";
8507
+ const evalFile = activeTestFiles.length === 1 ? path13.relative(cwd, activeTestFiles[0]) : "";
8270
8508
  await writeInitialRunSummaryArtifact(runDir, {
8271
8509
  evalFile,
8272
8510
  plannedTestCount: totalEvalCount,
8273
8511
  experiment: normalizeExperimentName(options.experiment),
8274
- runId: path12.basename(runDir),
8512
+ runId: path13.basename(runDir),
8275
8513
  experimentMetadata: runExperimentMetadata,
8276
8514
  runtimeSource: runtimeSourceMetadata,
8277
8515
  tags: emittedTags
@@ -8307,7 +8545,7 @@ async function runEvalCommand(input) {
8307
8545
  if (fileBudgetTracker?.isExceeded()) {
8308
8546
  const budgetMsg = `Run budget exceeded ($${fileBudgetTracker.currentCostUsd.toFixed(4)} / $${fileBudgetTracker.budgetCapUsd.toFixed(4)})`;
8309
8547
  console.log(`
8310
- \u26A0 ${budgetMsg} \u2014 skipping ${path12.basename(testFilePath)}`);
8548
+ \u26A0 ${budgetMsg} \u2014 skipping ${path13.basename(testFilePath)}`);
8311
8549
  for (const { selection } of targetPrep.selections) {
8312
8550
  const explicitVariant = targetVariantForSelection(selection);
8313
8551
  const skippedResults = targetPrep.testCases.map((testCase) => ({
@@ -8321,7 +8559,7 @@ async function runEvalCommand(input) {
8321
8559
  input: testCase.input,
8322
8560
  output: [{ role: "assistant", content: budgetMsg }],
8323
8561
  finalOutput: budgetMsg,
8324
- target: selection.targetName,
8562
+ target: selection.providerLabel,
8325
8563
  testId: testCase.testId ?? testCase.id,
8326
8564
  conversationId: testCase.conversation_id,
8327
8565
  error: budgetMsg
@@ -8332,7 +8570,7 @@ async function runEvalCommand(input) {
8332
8570
  failureStage: "setup",
8333
8571
  failureReasonCode: "budget_exceeded",
8334
8572
  executionError: { message: budgetMsg, stage: "setup" },
8335
- target: selection.targetName,
8573
+ target: selection.providerLabel,
8336
8574
  variant: explicitVariant
8337
8575
  }));
8338
8576
  for (const r of skippedResults) {
@@ -8351,18 +8589,18 @@ async function runEvalCommand(input) {
8351
8589
  const targetResults = await Promise.all(
8352
8590
  targetPrep.selections.map(
8353
8591
  ({ selection, inlineTargetLabel }) => limitTarget(async () => {
8354
- const targetName = selection.targetName;
8592
+ const providerLabel = selection.providerLabel;
8355
8593
  const applicableTestCases = targetPrep.testCases;
8356
8594
  const filteredTestCases = rerunIncludeKeys ? applicableTestCases.filter(
8357
8595
  (test) => resumeIdentityMatches(
8358
8596
  rerunIncludeKeys,
8359
8597
  test,
8360
- targetName,
8598
+ providerLabel,
8361
8599
  targetVariantForSelection(selection)
8362
8600
  )
8363
8601
  ) : resumeSkipKeys ? applicableTestCases.filter((test) => {
8364
8602
  const variant = targetVariantForSelection(selection);
8365
- return !resumeIdentityMatches(resumeSkipKeys, test, targetName, variant);
8603
+ return !resumeIdentityMatches(resumeSkipKeys, test, providerLabel, variant);
8366
8604
  }) : applicableTestCases;
8367
8605
  if (filteredTestCases.length === 0) {
8368
8606
  return [];
@@ -8405,7 +8643,7 @@ async function runEvalCommand(input) {
8405
8643
  });
8406
8644
  groupResults.push(...result.results);
8407
8645
  }
8408
- const evalFile = path12.relative(cwd, testFilePath);
8646
+ const evalFile = path13.relative(cwd, testFilePath);
8409
8647
  const existingSummary = remoteEvalSummaries.find(
8410
8648
  (summary2) => summary2.evalFile === evalFile
8411
8649
  );
@@ -8422,7 +8660,7 @@ async function runEvalCommand(input) {
8422
8660
  const message = fileError instanceof Error ? fileError.message : String(fileError);
8423
8661
  console.error(
8424
8662
  `
8425
- [ERROR] \u26A0 Eval file failed: ${path12.basename(testFilePath)} \u2014 ${message}
8663
+ [ERROR] \u26A0 Eval file failed: ${path13.basename(testFilePath)} \u2014 ${message}
8426
8664
  `
8427
8665
  );
8428
8666
  const explicitVariant = targetVariantForSelection(selection);
@@ -8439,7 +8677,7 @@ async function runEvalCommand(input) {
8439
8677
  input: testCase.input,
8440
8678
  output: [{ role: "assistant", content: message }],
8441
8679
  finalOutput: message,
8442
- target: selection.targetName,
8680
+ target: selection.providerLabel,
8443
8681
  testId: testCase.testId ?? testCase.id,
8444
8682
  conversationId: testCase.conversation_id,
8445
8683
  error: message
@@ -8451,7 +8689,7 @@ async function runEvalCommand(input) {
8451
8689
  failureReasonCode: "setup_error",
8452
8690
  durationMs: 0,
8453
8691
  tokenUsage: { input: 0, output: 0 },
8454
- target: selection.targetName,
8692
+ target: selection.providerLabel,
8455
8693
  variant: explicitVariant
8456
8694
  },
8457
8695
  testFilePath,
@@ -8481,7 +8719,11 @@ async function runEvalCommand(input) {
8481
8719
  );
8482
8720
  }
8483
8721
  await outputWriter.close().catch(() => void 0);
8484
- const summaryResults = deduplicateByTestIdTarget(await readExistingResultsFromRunDir(runDir));
8722
+ const summaryResults = await collectTerminalSummaryResults({
8723
+ allResults,
8724
+ isResumeAppend,
8725
+ runDir
8726
+ });
8485
8727
  const thresholdOpts = hasScopedRunPolicies || hasPerFileRuntimeThresholds ? { thresholdLabel: "configured threshold(s)", useExecutionStatus: true } : resolvedThreshold !== void 0 ? { threshold: resolvedThreshold } : void 0;
8486
8728
  const summary = calculateEvaluationSummary(summaryResults, thresholdOpts);
8487
8729
  console.log(formatEvaluationSummary(summary, thresholdOpts));
@@ -8495,14 +8737,14 @@ ${formatRequiredVersionFailureNote(requiredVersionCheck)}`);
8495
8737
  console.log(formatMatrixSummary(summaryResults));
8496
8738
  }
8497
8739
  if (allResults.length > 0) {
8498
- const evalFile = activeTestFiles.length === 1 ? activeTestFiles[0] : "";
8740
+ const evalFile = activeTestFiles.length === 1 ? path13.relative(cwd, activeTestFiles[0]) : "";
8499
8741
  const sourceTests = activeSourceTests;
8500
- const taskBundleTargets = buildTaskBundleTargetSelections(activeTestFiles, fileMetadata);
8742
+ const taskBundleTargets = buildTaskBundleProviderSelections(activeTestFiles, fileMetadata);
8501
8743
  if (isResumeAppend) {
8502
- const { writePerTestArtifacts } = await import("./artifact-writer-7NBCOAYC.js");
8744
+ const { writePerTestArtifacts } = await import("./artifact-writer-KJEOROKQ.js");
8503
8745
  await writePerTestArtifacts(allResults, runDir, {
8504
8746
  experiment: normalizeExperimentName(options.experiment),
8505
- runId: path12.basename(runDir),
8747
+ runId: path13.basename(runDir),
8506
8748
  resultGroup: resultGroupName,
8507
8749
  cwd,
8508
8750
  repoRoot,
@@ -8514,7 +8756,7 @@ ${formatRequiredVersionFailureNote(requiredVersionCheck)}`);
8514
8756
  const { summaryPath } = await aggregateRunDir(runDir, {
8515
8757
  evalFile,
8516
8758
  experiment: normalizeExperimentName(options.experiment),
8517
- runId: path12.basename(runDir),
8759
+ runId: path13.basename(runDir),
8518
8760
  experimentMetadata: runExperimentMetadata,
8519
8761
  runtimeSource: runtimeSourceMetadata,
8520
8762
  tags: emittedTags
@@ -8531,7 +8773,7 @@ ${formatRequiredVersionFailureNote(requiredVersionCheck)}`);
8531
8773
  {
8532
8774
  evalFile,
8533
8775
  experiment: normalizeExperimentName(options.experiment),
8534
- runId: path12.basename(runDir),
8776
+ runId: path13.basename(runDir),
8535
8777
  experimentMetadata: runExperimentMetadata,
8536
8778
  resultGroup: resultGroupName,
8537
8779
  cwd,
@@ -8594,9 +8836,9 @@ Results written under: ${runDir}`);
8594
8836
  });
8595
8837
  }
8596
8838
  if (summary.executionErrorCount > 0 && !options.retryErrors && !options.resume) {
8597
- const evalFileArgs = activeTestFiles.map((f) => path12.relative(cwd, f)).join(" ");
8598
- const targetFlag = options.target ? ` --target ${options.target}` : "";
8599
- const relativeRunDir = path12.relative(cwd, runDir);
8839
+ const evalFileArgs = activeTestFiles.map((f) => path13.relative(cwd, f)).join(" ");
8840
+ const targetFlag = options.provider ? ` --provider ${options.provider}` : "";
8841
+ const relativeRunDir = path13.relative(cwd, runDir);
8600
8842
  console.log(
8601
8843
  `
8602
8844
  Tip: ${summary.executionErrorCount} execution error(s) detected. Re-run failed tests with:
@@ -8618,7 +8860,7 @@ Tip: ${summary.executionErrorCount} execution error(s) detected. Re-run failed t
8618
8860
  executionErrorCount: summary.executionErrorCount,
8619
8861
  outputPath,
8620
8862
  testFiles: activeTestFiles,
8621
- target: options.target,
8863
+ provider: options.provider,
8622
8864
  thresholdFailed,
8623
8865
  allExecutionErrors,
8624
8866
  budgetExceeded: runBudgetExceeded || void 0
@@ -8639,7 +8881,7 @@ async function resolveEvaluationRunner() {
8639
8881
  if (!overridePath) {
8640
8882
  return runEvaluation;
8641
8883
  }
8642
- const resolved = path12.isAbsolute(overridePath) ? overridePath : path12.resolve(process.cwd(), overridePath);
8884
+ const resolved = path13.isAbsolute(overridePath) ? overridePath : path13.resolve(process.cwd(), overridePath);
8643
8885
  const moduleUrl = pathToFileURL(resolved).href;
8644
8886
  const mod = await import(moduleUrl);
8645
8887
  const candidate = mod.runEvaluation;
@@ -8673,9 +8915,9 @@ export {
8673
8915
  normalizeTagMap,
8674
8916
  loadLightweightResults,
8675
8917
  Mutex,
8676
- TARGET_FILE_CANDIDATES,
8918
+ PROVIDER_FILE_CANDIDATES,
8677
8919
  fileExists,
8678
- discoverTargetsFile,
8920
+ discoverProvidersFile,
8679
8921
  loadEnvFromHierarchy,
8680
8922
  detectFileType,
8681
8923
  validateEvalFile,
@@ -8685,9 +8927,9 @@ export {
8685
8927
  validateConfigFile,
8686
8928
  validateFileReferences,
8687
8929
  validateWorkspacePaths,
8688
- readTestSuiteTarget,
8689
- selectTarget,
8690
- selectMultipleTargets,
8930
+ readTestSuiteProvider,
8931
+ selectProvider,
8932
+ selectMultipleProviders,
8691
8933
  enforceRequiredVersion,
8692
8934
  c,
8693
8935
  padRight,
@@ -8718,4 +8960,4 @@ export {
8718
8960
  filterByCategory,
8719
8961
  runEvalCommand
8720
8962
  };
8721
- //# sourceMappingURL=chunk-LKGARI3W.js.map
8963
+ //# sourceMappingURL=chunk-QSK3PC44.js.map