agentv 5.1.0-next.1 → 5.3.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +16 -12
  2. package/dist/{artifact-writer-IORG7CW5.js → artifact-writer-JFNIPMKW.js} +5 -5
  3. package/dist/{chunk-ZGPCX334.js → chunk-6ZZCDZPD.js} +4101 -1204
  4. package/dist/chunk-6ZZCDZPD.js.map +1 -0
  5. package/dist/{chunk-CBBBRTQ3.js → chunk-BHKQHG26.js} +64 -3
  6. package/dist/chunk-BHKQHG26.js.map +1 -0
  7. package/dist/{chunk-AM2IPHKS.js → chunk-FVR4RQFK.js} +302 -162
  8. package/dist/chunk-FVR4RQFK.js.map +1 -0
  9. package/dist/{chunk-GIRUNQGP.js → chunk-T32NL3E6.js} +262 -154
  10. package/dist/chunk-T32NL3E6.js.map +1 -0
  11. package/dist/{chunk-GJWPQXHN.js → chunk-V52ATPTT.js} +104 -188
  12. package/dist/chunk-V52ATPTT.js.map +1 -0
  13. package/dist/cli.js +6 -6
  14. package/dist/dashboard/assets/{index-BSHoWrdr.js → index-DNgf3qJ2.js} +1 -1
  15. package/dist/dashboard/assets/{index-zvUKAkKn.css → index-D_bokML8.css} +1 -1
  16. package/dist/dashboard/assets/index-r_jSJmlw.js +121 -0
  17. package/dist/dashboard/index.html +2 -2
  18. package/dist/{dist-2D2GBHZV.js → dist-6Z7U473R.js} +14 -8
  19. package/dist/index.js +6 -6
  20. package/dist/{interactive-V4SEHLNY.js → interactive-RUY3OCBI.js} +6 -6
  21. package/dist/skills/agentv-bench/SKILL.md +17 -13
  22. package/dist/skills/agentv-bench/agents/analyzer.md +1 -1
  23. package/dist/skills/agentv-bench/agents/comparator.md +3 -3
  24. package/dist/skills/agentv-bench/agents/grader.md +4 -2
  25. package/dist/skills/agentv-bench/references/description-optimization.md +5 -6
  26. package/dist/skills/agentv-bench/references/environment-adaptation.md +2 -2
  27. package/dist/skills/agentv-bench/references/eval-yaml-spec.md +35 -19
  28. package/dist/skills/agentv-bench/references/migrating-from-skill-creator.md +1 -1
  29. package/dist/skills/agentv-eval-migrations/references/breaking-changes.md +125 -28
  30. package/dist/skills/agentv-eval-writer/SKILL.md +113 -87
  31. package/dist/skills/agentv-eval-writer/references/eval.schema.json +772 -1367
  32. package/dist/{ts-eval-loader-SSPJVEHD-AL2A3V5Z.js → ts-eval-loader-DQDYRULE-V3377FOL.js} +3 -2
  33. package/package.json +8 -2
  34. package/dist/chunk-AM2IPHKS.js.map +0 -1
  35. package/dist/chunk-CBBBRTQ3.js.map +0 -1
  36. package/dist/chunk-GIRUNQGP.js.map +0 -1
  37. package/dist/chunk-GJWPQXHN.js.map +0 -1
  38. package/dist/chunk-ZGPCX334.js.map +0 -1
  39. package/dist/dashboard/assets/index-BaLLxmVO.js +0 -121
  40. /package/dist/{artifact-writer-IORG7CW5.js.map → artifact-writer-JFNIPMKW.js.map} +0 -0
  41. /package/dist/{dist-2D2GBHZV.js.map → dist-6Z7U473R.js.map} +0 -0
  42. /package/dist/{interactive-V4SEHLNY.js.map → interactive-RUY3OCBI.js.map} +0 -0
  43. /package/dist/{ts-eval-loader-SSPJVEHD-AL2A3V5Z.js.map → ts-eval-loader-DQDYRULE-V3377FOL.js.map} +0 -0
@@ -61,11 +61,11 @@ import {
61
61
  validateFileReferences,
62
62
  validateTargetsFile,
63
63
  validateWorkspacePaths
64
- } from "./chunk-AM2IPHKS.js";
64
+ } from "./chunk-FVR4RQFK.js";
65
65
  import {
66
66
  materializeEvalBundle,
67
67
  writeArtifactsFromResults as writeArtifactsFromResults2
68
- } from "./chunk-CBBBRTQ3.js";
68
+ } from "./chunk-BHKQHG26.js";
69
69
  import {
70
70
  discoverClaudeSessions,
71
71
  discoverCodexSessions,
@@ -77,16 +77,17 @@ import {
77
77
  prepareEvalWorkspace,
78
78
  readGitResultArtifact,
79
79
  runBeforeSessionHook,
80
- scanRepoDeps,
81
80
  syncProjects,
82
81
  transpileEvalYamlFile,
83
82
  trimBaselineResult
84
- } from "./chunk-GJWPQXHN.js";
83
+ } from "./chunk-V52ATPTT.js";
85
84
  import {
86
85
  AGENTV_RESULTS_ARTIFACTS_REF,
87
86
  DEFAULT_CATEGORY,
88
87
  DEFAULT_THRESHOLD,
89
88
  EXECUTION_TRACE_SCHEMA_VERSION,
89
+ LEGACY_METRICS_SCHEMA_VERSION,
90
+ METRICS_SCHEMA_VERSION,
90
91
  RESULT_INDEX_FILENAME,
91
92
  addProject,
92
93
  aggregateRunDir,
@@ -111,6 +112,7 @@ import {
111
112
  loadTestSuite,
112
113
  mergeConfigObjects,
113
114
  normalizeCategoryPath,
115
+ normalizeMetricsArtifactWire,
114
116
  normalizeResultRow,
115
117
  omitExternalTraceMetadataKeys,
116
118
  parseYamlValue,
@@ -140,7 +142,7 @@ import {
140
142
  traceEnvelopeToTranscriptMessages,
141
143
  traceFromTranscriptJsonLines,
142
144
  writeArtifactsFromResults
143
- } from "./chunk-ZGPCX334.js";
145
+ } from "./chunk-6ZZCDZPD.js";
144
146
  import {
145
147
  __commonJS,
146
148
  __require,
@@ -901,7 +903,7 @@ var require_src = __commonJS({
901
903
  });
902
904
 
903
905
  // src/index.ts
904
- import path33 from "node:path";
906
+ import path32 from "node:path";
905
907
 
906
908
  // ../../node_modules/.bun/chalk@5.6.2/node_modules/chalk/source/vendor/ansi-styles/index.js
907
909
  var ANSI_BACKGROUND_OFFSET = 10;
@@ -3975,7 +3977,8 @@ export default defineAssertion(({ output }) => {
3975
3977
  const pass = text.length > 0;
3976
3978
  return {
3977
3979
  pass,
3978
- assertions: [{ text: pass ? 'Output has content' : 'Output is empty', passed: pass }],
3980
+ score: pass ? 1 : 0,
3981
+ reason: pass ? 'Output has content' : 'Output is empty',
3979
3982
  };
3980
3983
  });
3981
3984
  `,
@@ -3989,7 +3992,14 @@ export default defineAssertion(({ output }) => {
3989
3992
  return {
3990
3993
  pass: score >= 0.5,
3991
3994
  score,
3992
- assertions: [{ text: 'Output has content', passed: score === 1.0 }],
3995
+ reason: score === 1.0 ? 'Output has content' : 'Output is empty',
3996
+ checks: [
3997
+ {
3998
+ text: 'Output has content',
3999
+ pass: score === 1.0,
4000
+ reason: score === 1.0 ? 'Output is non-empty' : 'Output is empty',
4001
+ },
4002
+ ],
3993
4003
  };
3994
4004
  });
3995
4005
  `
@@ -5042,15 +5052,19 @@ var ScriptGraderInputSchema = external_exports.object({
5042
5052
  workspacePath: external_exports.string().nullable().optional(),
5043
5053
  config: external_exports.record(external_exports.unknown()).nullable().optional()
5044
5054
  });
5055
+ var ScriptGraderCheckSchema = external_exports.object({
5056
+ id: external_exports.string().optional(),
5057
+ text: external_exports.string(),
5058
+ pass: external_exports.boolean(),
5059
+ score: external_exports.number().min(0).max(1).optional(),
5060
+ reason: external_exports.string(),
5061
+ evidence: external_exports.string().optional()
5062
+ });
5045
5063
  var ScriptGraderResultSchema = external_exports.object({
5064
+ pass: external_exports.boolean(),
5046
5065
  score: external_exports.number().min(0).max(1),
5047
- assertions: external_exports.array(
5048
- external_exports.object({
5049
- text: external_exports.string(),
5050
- passed: external_exports.boolean(),
5051
- evidence: external_exports.string().optional()
5052
- })
5053
- ).optional().default([]),
5066
+ reason: external_exports.string(),
5067
+ checks: external_exports.array(ScriptGraderCheckSchema).optional().default([]),
5054
5068
  /** Optional structured details for domain-specific metrics (e.g., TP/TN/FP/FN counts, alignments). */
5055
5069
  details: external_exports.record(external_exports.unknown()).optional()
5056
5070
  });
@@ -5192,14 +5206,26 @@ async function runScriptGrader(handler) {
5192
5206
  const rawResult = await handler(input);
5193
5207
  const result = ScriptGraderResultSchema.parse({
5194
5208
  ...rawResult,
5195
- score: clampScore(rawResult.score)
5209
+ score: clampScore(rawResult.score),
5210
+ checks: rawResult.checks?.map((check2) => ({
5211
+ ...check2,
5212
+ ...check2.score !== void 0 ? { score: clampScore(check2.score) } : {}
5213
+ }))
5196
5214
  });
5197
5215
  console.log(JSON.stringify(result, null, 2));
5198
5216
  } catch (error) {
5199
5217
  const errorMessage = formatError(error);
5200
5218
  const errorResult = {
5219
+ pass: false,
5201
5220
  score: 0,
5202
- assertions: [{ text: `Evaluation failed: ${errorMessage}`, passed: false }]
5221
+ reason: `Evaluation failed: ${errorMessage}`,
5222
+ checks: [
5223
+ {
5224
+ text: "Script grader execution",
5225
+ pass: false,
5226
+ reason: errorMessage
5227
+ }
5228
+ ]
5203
5229
  };
5204
5230
  console.log(JSON.stringify(errorResult, null, 2));
5205
5231
  process.exit(1);
@@ -5267,27 +5293,36 @@ function parseJsonObjectFromText(text) {
5267
5293
  function isVitestJsonReport(value) {
5268
5294
  return typeof value === "object" && value !== null && Array.isArray(value.testResults);
5269
5295
  }
5270
- function assertionText(file, assertion2) {
5271
- const title = assertion2.fullName ?? [...assertion2.ancestorTitles ?? [], assertion2.title].filter(Boolean).join(" ");
5296
+ function assertionText(file, assertion) {
5297
+ const title = assertion.fullName ?? [...assertion.ancestorTitles ?? [], assertion.title].filter(Boolean).join(" ");
5272
5298
  return title || file.name || "Vitest assertion";
5273
5299
  }
5274
5300
  function vitestReportToScriptGraderResult(report, options = {}) {
5275
- const assertions = (report.testResults ?? []).flatMap(
5301
+ const checks = (report.testResults ?? []).flatMap(
5276
5302
  (file) => (file.assertionResults ?? []).map((item) => {
5277
- const passed = item.status === "passed";
5303
+ const pass2 = item.status === "passed";
5278
5304
  const evidence = item.failureMessages && item.failureMessages.length > 0 ? truncate(item.failureMessages.join("\n\n")) : void 0;
5279
5305
  return {
5280
5306
  text: assertionText(file, item),
5281
- passed,
5307
+ pass: pass2,
5308
+ reason: pass2 ? "Vitest test passed." : "Vitest test failed.",
5282
5309
  ...evidence !== void 0 ? { evidence } : {}
5283
5310
  };
5284
5311
  })
5285
5312
  );
5286
- if (assertions.length === 0) {
5287
- const passed = options.passWithNoTests === true;
5313
+ if (checks.length === 0) {
5314
+ const pass2 = options.passWithNoTests === true;
5288
5315
  return ScriptGraderResultSchema.parse({
5289
- score: passed ? 1 : 0,
5290
- assertions: [{ text: "Vitest reported no tests", passed }],
5316
+ pass: pass2,
5317
+ score: pass2 ? 1 : 0,
5318
+ reason: pass2 ? "Vitest reported no tests; configured to pass." : "Vitest reported no tests.",
5319
+ checks: [
5320
+ {
5321
+ text: "Vitest reported no tests",
5322
+ pass: pass2,
5323
+ reason: pass2 ? "passWithNoTests is enabled." : "No Vitest tests were discovered."
5324
+ }
5325
+ ],
5291
5326
  details: {
5292
5327
  vitest_success: report.success ?? false,
5293
5328
  num_total_tests: report.numTotalTests ?? 0,
@@ -5298,15 +5333,18 @@ function vitestReportToScriptGraderResult(report, options = {}) {
5298
5333
  }
5299
5334
  });
5300
5335
  }
5301
- const passedCount = assertions.filter((item) => item.passed).length;
5336
+ const passedCount = checks.filter((item) => item.pass).length;
5337
+ const pass = passedCount === checks.length;
5302
5338
  return ScriptGraderResultSchema.parse({
5303
- score: passedCount / assertions.length,
5304
- assertions,
5339
+ pass,
5340
+ score: passedCount / checks.length,
5341
+ reason: `${passedCount}/${checks.length} Vitest tests passed.`,
5342
+ checks,
5305
5343
  details: {
5306
- vitest_success: report.success ?? passedCount === assertions.length,
5307
- num_total_tests: report.numTotalTests ?? assertions.length,
5344
+ vitest_success: report.success ?? pass,
5345
+ num_total_tests: report.numTotalTests ?? checks.length,
5308
5346
  num_passed_tests: report.numPassedTests ?? passedCount,
5309
- num_failed_tests: report.numFailedTests ?? assertions.length - passedCount,
5347
+ num_failed_tests: report.numFailedTests ?? checks.length - passedCount,
5310
5348
  num_pending_tests: report.numPendingTests ?? 0,
5311
5349
  num_todo_tests: report.numTodoTests ?? 0
5312
5350
  }
@@ -5384,12 +5422,14 @@ async function runVitestWorkspaceGrader(options, input) {
5384
5422
  const workspacePath = workspacePathFrom2(input);
5385
5423
  if (!workspacePath) {
5386
5424
  return {
5425
+ pass: false,
5387
5426
  score: 0,
5388
- assertions: [
5427
+ reason: "Vitest workspace verifier requires workspace_path.",
5428
+ checks: [
5389
5429
  {
5390
5430
  text: "Vitest workspace verifier requires workspace_path",
5391
- passed: false,
5392
- evidence: "Configure workspace in the eval YAML so AgentV can pass workspace_path."
5431
+ pass: false,
5432
+ reason: "Configure an environment recipe in the eval YAML so AgentV can pass workspace_path."
5393
5433
  }
5394
5434
  ]
5395
5435
  };
@@ -5423,13 +5463,16 @@ async function runVitestWorkspaceGrader(options, input) {
5423
5463
  const report = await readVitestReport(result, outputFile);
5424
5464
  return vitestReportToScriptGraderResult(report, options);
5425
5465
  } catch (error) {
5466
+ const reason = error instanceof Error ? error.message : String(error);
5426
5467
  return {
5468
+ pass: false,
5427
5469
  score: 0,
5428
- assertions: [
5470
+ reason: "Vitest workspace verifier failed to run.",
5471
+ checks: [
5429
5472
  {
5430
5473
  text: "Vitest workspace verifier failed to run",
5431
- passed: false,
5432
- evidence: error instanceof Error ? error.message : String(error)
5474
+ pass: false,
5475
+ reason
5433
5476
  }
5434
5477
  ]
5435
5478
  };
@@ -7970,13 +8013,31 @@ var inspectCommand = subcommands({
7970
8013
  import { existsSync as existsSync6 } from "node:fs";
7971
8014
  import { mkdir as mkdir6, readFile as readFile4, readdir, writeFile as writeFile6 } from "node:fs/promises";
7972
8015
  import { join } from "node:path";
7973
- function toAssertionResult(assertion) {
8016
+ function toComponentResult(assertion, evaluator) {
7974
8017
  return {
7975
- text: assertion.text,
7976
- passed: assertion.passed,
7977
- evidence: assertion.evidence ?? "",
8018
+ pass: assertion.passed,
7978
8019
  score: assertion.passed ? 1 : 0,
7979
- verdict: assertion.passed ? "pass" : "fail"
8020
+ reason: assertion.evidence ?? assertion.text,
8021
+ assertion: {
8022
+ ...evaluator ? { name: evaluator.name, type: evaluator.type } : {},
8023
+ value: assertion.text
8024
+ }
8025
+ };
8026
+ }
8027
+ function evaluatorComponent(evaluator) {
8028
+ const pass = evaluator.score >= DEFAULT_THRESHOLD;
8029
+ return {
8030
+ pass,
8031
+ score: evaluator.score,
8032
+ reason: pass ? "Grader passed." : "Grader failed.",
8033
+ assertion: {
8034
+ name: evaluator.name,
8035
+ type: evaluator.type,
8036
+ weight: evaluator.weight
8037
+ },
8038
+ component_results: evaluator.assertions.map(
8039
+ (assertion) => toComponentResult(assertion, evaluator)
8040
+ )
7980
8041
  };
7981
8042
  }
7982
8043
  var evalBenchCommand = command({
@@ -8055,20 +8116,18 @@ var evalBenchCommand = command({
8055
8116
  const failed = allAssertions.filter((a) => !a.passed).length;
8056
8117
  const passRate = allAssertions.length > 0 ? Math.round(passed / allAssertions.length * 1e3) / 1e3 : weightedScore >= 0.5 ? 1 : 0;
8057
8118
  allPassRates.push(passRate);
8119
+ const pass = weightedScore >= DEFAULT_THRESHOLD;
8058
8120
  const grading = {
8121
+ pass,
8059
8122
  score: Math.round(weightedScore * 1e3) / 1e3,
8060
- verdict: weightedScore >= DEFAULT_THRESHOLD ? "pass" : "fail",
8061
- assertion_results: allAssertions.map(toAssertionResult),
8062
- summary: { passed, failed, total: allAssertions.length, pass_rate: passRate },
8063
- graders: evaluators.map((e) => ({
8064
- name: e.name,
8065
- type: e.type,
8066
- score: e.score,
8067
- verdict: e.score >= DEFAULT_THRESHOLD ? "pass" : "fail",
8068
- reasoning: "",
8069
- weight: e.weight,
8070
- assertion_results: e.assertions.map(toAssertionResult)
8071
- }))
8123
+ reason: pass ? "All grading components passed." : "One or more grading components failed.",
8124
+ component_results: evaluators.length > 0 ? evaluators.map(evaluatorComponent) : allAssertions.map((assertion) => toComponentResult(assertion)),
8125
+ metadata: {
8126
+ pass_count: passed,
8127
+ fail_count: failed,
8128
+ sample_count: allAssertions.length,
8129
+ pass_rate: passRate
8130
+ }
8072
8131
  };
8073
8132
  await writeFile6(
8074
8133
  join(testDir, "grading.json"),
@@ -8079,14 +8138,10 @@ var evalBenchCommand = command({
8079
8138
  const scores = evaluators.map((e) => ({
8080
8139
  name: e.name,
8081
8140
  type: e.type,
8141
+ pass: e.score >= DEFAULT_THRESHOLD,
8082
8142
  score: e.score,
8083
8143
  weight: e.weight,
8084
- verdict: e.score >= 0.5 ? "pass" : "fail",
8085
- assertions: e.assertions.map((a) => ({
8086
- text: a.text,
8087
- passed: a.passed,
8088
- evidence: a.evidence ?? ""
8089
- }))
8144
+ reason: e.score >= DEFAULT_THRESHOLD ? "Grader passed." : "Grader failed."
8090
8145
  }));
8091
8146
  let executionStatus = "ok";
8092
8147
  const metricsPath = join(testDir, "metrics.json");
@@ -12783,9 +12838,10 @@ function formatSummary(results, grading) {
12783
12838
  let failed;
12784
12839
  let passRate;
12785
12840
  if (grading) {
12786
- passed = grading.summary.passed;
12787
- failed = grading.summary.failed;
12788
- passRate = grading.summary.pass_rate;
12841
+ const metadata = grading.metadata ?? {};
12842
+ passed = typeof metadata.pass_count === "number" ? metadata.pass_count : grading.pass ? total : 0;
12843
+ failed = typeof metadata.sample_count === "number" && typeof metadata.pass_count === "number" ? metadata.sample_count - metadata.pass_count : total - passed;
12844
+ passRate = typeof metadata.pass_rate === "number" ? metadata.pass_rate : total > 0 ? Math.round(passed / total * 1e3) / 1e3 : 0;
12789
12845
  } else {
12790
12846
  passed = results.filter((r) => r.score >= 1).length;
12791
12847
  failed = total - passed;
@@ -12844,6 +12900,94 @@ var resultsSummaryCommand = command({
12844
12900
  // src/commands/results/validate.ts
12845
12901
  import { existsSync as existsSync14, readFileSync as readFileSync12, statSync as statSync5 } from "node:fs";
12846
12902
  import path24 from "node:path";
12903
+ var LEGACY_GRADING_FIELDS = [
12904
+ "assertion_results",
12905
+ "assertions",
12906
+ "passed",
12907
+ "evidence",
12908
+ "verdict",
12909
+ "graders",
12910
+ "checks"
12911
+ ];
12912
+ function isRecord2(value) {
12913
+ return typeof value === "object" && value !== null && !Array.isArray(value);
12914
+ }
12915
+ function validateGradingNode(value, pathLabel) {
12916
+ if (!isRecord2(value)) {
12917
+ return [`${pathLabel} must be an object`];
12918
+ }
12919
+ const errors = [];
12920
+ if (typeof value.pass !== "boolean" || typeof value.score !== "number" || typeof value.reason !== "string") {
12921
+ errors.push(`${pathLabel} must include pass, score, and reason`);
12922
+ }
12923
+ if (value.component_results !== void 0) {
12924
+ if (!Array.isArray(value.component_results)) {
12925
+ errors.push(`${pathLabel}.component_results must be an array when present`);
12926
+ } else {
12927
+ value.component_results.forEach((component, index) => {
12928
+ errors.push(...validateGradingNode(component, `${pathLabel}.component_results[${index}]`));
12929
+ });
12930
+ }
12931
+ }
12932
+ return errors;
12933
+ }
12934
+ function validateNoLegacyGradingFields(value, pathLabel) {
12935
+ if (Array.isArray(value)) {
12936
+ return value.flatMap(
12937
+ (entry, index) => validateNoLegacyGradingFields(entry, `${pathLabel}[${index}]`)
12938
+ );
12939
+ }
12940
+ if (!isRecord2(value)) {
12941
+ return [];
12942
+ }
12943
+ const errors = [];
12944
+ const legacyFields = LEGACY_GRADING_FIELDS.filter((field) => Object.hasOwn(value, field));
12945
+ if (legacyFields.length > 0) {
12946
+ errors.push(`${pathLabel} uses legacy field(s): ${legacyFields.join(", ")}`);
12947
+ }
12948
+ for (const [key, entry] of Object.entries(value)) {
12949
+ errors.push(...validateNoLegacyGradingFields(entry, `${pathLabel}.${key}`));
12950
+ }
12951
+ return errors;
12952
+ }
12953
+ function validateMetricsArtifact(value) {
12954
+ if (!isRecord2(value)) {
12955
+ return [{ severity: "error", message: "metrics.json must be an object" }];
12956
+ }
12957
+ const diagnostics = [];
12958
+ const schemaVersion = value.schema_version;
12959
+ const isCurrentSchema = schemaVersion === METRICS_SCHEMA_VERSION;
12960
+ const isLegacySchema = schemaVersion === LEGACY_METRICS_SCHEMA_VERSION;
12961
+ if (isCurrentSchema && Object.hasOwn(value, "trace")) {
12962
+ diagnostics.push({
12963
+ severity: "error",
12964
+ message: "metrics.json must not include trace in agentv.metrics.v2"
12965
+ });
12966
+ } else if (isLegacySchema && Object.hasOwn(value, "trace")) {
12967
+ diagnostics.push({
12968
+ severity: "warning",
12969
+ message: "metrics.json uses legacy trace identity; readers ignore it"
12970
+ });
12971
+ }
12972
+ if (isCurrentSchema && Object.hasOwn(value, "metrics")) {
12973
+ diagnostics.push({
12974
+ severity: "error",
12975
+ message: "metrics.json must not include nested metrics in agentv.metrics.v2"
12976
+ });
12977
+ } else if (isLegacySchema && Object.hasOwn(value, "metrics")) {
12978
+ diagnostics.push({
12979
+ severity: "warning",
12980
+ message: "metrics.json uses legacy nested metrics; readers flatten it"
12981
+ });
12982
+ }
12983
+ if (!normalizeMetricsArtifactWire(value)) {
12984
+ diagnostics.push({
12985
+ severity: "error",
12986
+ message: "metrics.json does not match a supported metrics artifact shape"
12987
+ });
12988
+ }
12989
+ return diagnostics;
12990
+ }
12847
12991
  function checkDirectoryNaming(runDir) {
12848
12992
  const dirName = path24.basename(runDir);
12849
12993
  const pathSegments = path24.normalize(runDir).split(path24.sep).filter(Boolean);
@@ -12962,7 +13106,8 @@ function checkIndexJsonl(runDir) {
12962
13106
  if (typeof s.name !== "string") missing.push("name");
12963
13107
  if (typeof s.type !== "string") missing.push("type");
12964
13108
  if (typeof s.score !== "number") missing.push("score");
12965
- if (typeof s.verdict !== "string") missing.push("verdict");
13109
+ if (typeof s.pass !== "boolean") missing.push("pass");
13110
+ if (typeof s.reason !== "string") missing.push("reason");
12966
13111
  if (missing.length > 0) {
12967
13112
  diagnostics.push({
12968
13113
  severity: "warning",
@@ -13035,22 +13180,13 @@ function checkArtifactFiles(runDir, entries2) {
13035
13180
  } else {
13036
13181
  try {
13037
13182
  const grading = JSON.parse(readFileSync12(gradingPath, "utf8"));
13038
- if (Array.isArray(grading.assertion_results)) {
13039
- } else if (Array.isArray(grading.assertions)) {
13040
- diagnostics.push({
13041
- severity: "warning",
13042
- message: `${testId}: grading.json uses legacy 'assertions' array; rewrite the run to emit 'assertion_results'`
13043
- });
13044
- } else {
13183
+ for (const error of [
13184
+ ...validateGradingNode(grading, "grading.json"),
13185
+ ...validateNoLegacyGradingFields(grading, "grading.json")
13186
+ ]) {
13045
13187
  diagnostics.push({
13046
13188
  severity: "error",
13047
- message: `${testId}: grading.json missing 'assertion_results' array`
13048
- });
13049
- }
13050
- if (!grading.summary) {
13051
- diagnostics.push({
13052
- severity: "warning",
13053
- message: `${testId}: grading.json missing 'summary' object`
13189
+ message: `${testId}: ${error}`
13054
13190
  });
13055
13191
  }
13056
13192
  } catch {
@@ -13068,6 +13204,21 @@ function checkArtifactFiles(runDir, entries2) {
13068
13204
  severity: "warning",
13069
13205
  message: `${testId}: metrics.json not found at '${entry.metrics_path}'`
13070
13206
  });
13207
+ } else {
13208
+ try {
13209
+ const metrics = JSON.parse(readFileSync12(metricsPath, "utf8"));
13210
+ for (const diagnostic of validateMetricsArtifact(metrics)) {
13211
+ diagnostics.push({
13212
+ severity: diagnostic.severity,
13213
+ message: `${testId}: ${diagnostic.message}`
13214
+ });
13215
+ }
13216
+ } catch {
13217
+ diagnostics.push({
13218
+ severity: "error",
13219
+ message: `${testId}: metrics.json is not valid JSON`
13220
+ });
13221
+ }
13071
13222
  }
13072
13223
  }
13073
13224
  }
@@ -13964,7 +14115,7 @@ function inferRawContentType(filePath) {
13964
14115
  function contentDispositionFilename(filePath) {
13965
14116
  return path27.basename(filePath).replace(/["\\\r\n]/g, "_");
13966
14117
  }
13967
- function isRecord2(value) {
14118
+ function isRecord3(value) {
13968
14119
  return typeof value === "object" && value !== null && !Array.isArray(value);
13969
14120
  }
13970
14121
  function nonEmptyString(value) {
@@ -13972,12 +14123,12 @@ function nonEmptyString(value) {
13972
14123
  }
13973
14124
  function artifactPointerPath(pointer) {
13974
14125
  if (typeof pointer === "string") return nonEmptyString(pointer);
13975
- if (!isRecord2(pointer)) return void 0;
14126
+ if (!isRecord3(pointer)) return void 0;
13976
14127
  return nonEmptyString(pointer.path) ?? nonEmptyString(pointer.artifact_path) ?? nonEmptyString(pointer.relative_path);
13977
14128
  }
13978
14129
  function artifactPointerDescription(pointer) {
13979
14130
  if (typeof pointer === "string") return pointer;
13980
- if (!isRecord2(pointer)) return void 0;
14131
+ if (!isRecord3(pointer)) return void 0;
13981
14132
  const ref = nonEmptyString(pointer.ref);
13982
14133
  const storage = nonEmptyString(pointer.storage);
13983
14134
  const uri = nonEmptyString(pointer.uri) ?? nonEmptyString(pointer.href);
@@ -13991,19 +14142,19 @@ function artifactPointerDescription(pointer) {
13991
14142
  return parts.length > 0 ? parts.join(", ") : void 0;
13992
14143
  }
13993
14144
  function artifactPointerRef(pointer) {
13994
- return isRecord2(pointer) ? nonEmptyString(pointer.ref) : void 0;
14145
+ return isRecord3(pointer) ? nonEmptyString(pointer.ref) : void 0;
13995
14146
  }
13996
14147
  function artifactPointerKey(pointer) {
13997
- return isRecord2(pointer) ? nonEmptyString(pointer.key) : void 0;
14148
+ return isRecord3(pointer) ? nonEmptyString(pointer.key) : void 0;
13998
14149
  }
13999
14150
  function artifactPointerSha256(pointer) {
14000
- return isRecord2(pointer) ? nonEmptyString(pointer.sha256) : void 0;
14151
+ return isRecord3(pointer) ? nonEmptyString(pointer.sha256) : void 0;
14001
14152
  }
14002
14153
  function artifactPointerMediaType(pointer) {
14003
- return isRecord2(pointer) ? nonEmptyString(pointer.media_type) : void 0;
14154
+ return isRecord3(pointer) ? nonEmptyString(pointer.media_type) : void 0;
14004
14155
  }
14005
14156
  function artifactPointerObjectVersion(pointer) {
14006
- return isRecord2(pointer) ? nonEmptyString(pointer.object_version) : void 0;
14157
+ return isRecord3(pointer) ? nonEmptyString(pointer.object_version) : void 0;
14007
14158
  }
14008
14159
  function resolveRecordArtifactPointer(record, kind) {
14009
14160
  const legacyArtifactPointers = record.artifact_pointers;
@@ -14350,6 +14501,12 @@ async function readArtifactCatalogEntryText(searchDir, projectId, meta, entry) {
14350
14501
  });
14351
14502
  return { content };
14352
14503
  }
14504
+ function readableLocalCatalogEntry(meta, entry) {
14505
+ if (!entry || entry.storage !== "local") return entry;
14506
+ const baseDir = runWorkspaceDirFromManifestPath(meta.path);
14507
+ const resolved = resolveReadableRunArtifactFile(baseDir, entry.displayPath);
14508
+ return resolved.absolutePath ? entry : void 0;
14509
+ }
14353
14510
  function artifactFileContentResponse(c4, filePath, fileContent) {
14354
14511
  if (c4.req.query("raw") === "1" || c4.req.query("download") === "1") {
14355
14512
  c4.header("Content-Type", inferRawContentType(filePath));
@@ -14449,7 +14606,7 @@ function buildRepeatTrialReadModels(baseDir, record) {
14449
14606
  const answerPath = caseTrialArtifactPath(resultDir, runPath, "outputs/answer.md");
14450
14607
  const resultPath = caseTrialArtifactPath(resultDir, runPath, "result.json");
14451
14608
  const runResult = readArtifactJsonObject(baseDir, resultPath);
14452
- const metrics = readArtifactJsonObject(baseDir, metricsPath);
14609
+ const metrics = normalizeMetricsArtifactWire(readArtifactJsonObject(baseDir, metricsPath));
14453
14610
  const timing = readArtifactJsonObject(baseDir, timingPath);
14454
14611
  const toolCalls = objectField(metrics, "tool_calls");
14455
14612
  const tokenUsage = objectField(metrics, "tokens") ?? objectField(timing, "token_usage");
@@ -15199,6 +15356,10 @@ async function handleEvalTranscript(c4, { searchDir, projectId }) {
15199
15356
  runPath
15200
15357
  );
15201
15358
  const answerEntry = findPointerArtifactCatalogEntry(catalog, answer, "answer", runPath);
15359
+ const transcriptRawEntry = readableLocalCatalogEntry(
15360
+ meta,
15361
+ record.transcript_raw_path ? findArtifactCatalogEntry(catalog, record.transcript_raw_path) : void 0
15362
+ );
15202
15363
  if (!transcriptEntry && !transcript.path) {
15203
15364
  return c4.json({
15204
15365
  status: transcript.unsupportedReason ? "unsupported" : "missing",
@@ -15242,6 +15403,7 @@ async function handleEvalTranscript(c4, { searchDir, projectId }) {
15242
15403
  return c4.json({
15243
15404
  status: "ok",
15244
15405
  transcript_path: transcriptEntry.displayPath,
15406
+ ...transcriptRawEntry && { transcript_raw_path: transcriptRawEntry.displayPath },
15245
15407
  content,
15246
15408
  language: inferLanguage(transcriptEntry.displayPath),
15247
15409
  ...answerEntry && { answer_path: answerEntry.displayPath },
@@ -16326,7 +16488,7 @@ import { config as loadDotenv } from "dotenv";
16326
16488
  var TASK_EVAL_FILENAME = "EVAL.yaml";
16327
16489
  var TASK_TARGETS_FILENAME = "targets.yaml";
16328
16490
  var ENV_REF_PATTERN = /\$\{\{\s*([A-Za-z_][A-Za-z0-9_]*)\s*\}\}/g;
16329
- function isRecord3(value) {
16491
+ function isRecord4(value) {
16330
16492
  return typeof value === "object" && value !== null && !Array.isArray(value);
16331
16493
  }
16332
16494
  function displayRecord(record) {
@@ -16368,11 +16530,11 @@ function stringArray(value) {
16368
16530
  return Array.isArray(value) ? value.filter((entry) => typeof entry === "string" && entry.length > 0) : [];
16369
16531
  }
16370
16532
  function readExecutionTarget(parsedEval) {
16371
- if (!isRecord3(parsedEval)) {
16533
+ if (!isRecord4(parsedEval)) {
16372
16534
  return void 0;
16373
16535
  }
16374
16536
  const execution = parsedEval.execution;
16375
- if (isRecord3(execution) && typeof execution.target === "string" && execution.target.length > 0) {
16537
+ if (isRecord4(execution) && typeof execution.target === "string" && execution.target.length > 0) {
16376
16538
  return execution.target;
16377
16539
  }
16378
16540
  return typeof parsedEval.target === "string" && parsedEval.target.length > 0 ? parsedEval.target : void 0;
@@ -16383,10 +16545,10 @@ async function readTaskTarget(evalPath, fallback) {
16383
16545
  }
16384
16546
  async function readTargetDefinitions2(targetsPath) {
16385
16547
  const parsed = parseYamlValue(await readFile8(targetsPath, "utf8"));
16386
- if (!isRecord3(parsed) || !Array.isArray(parsed.targets)) {
16548
+ if (!isRecord4(parsed) || !Array.isArray(parsed.targets)) {
16387
16549
  throw new Error(`Targets file is missing a top-level targets array: ${targetsPath}`);
16388
16550
  }
16389
- return parsed.targets.filter(isRecord3);
16551
+ return parsed.targets.filter(isRecord4);
16390
16552
  }
16391
16553
  function targetName(definition) {
16392
16554
  if (typeof definition.id === "string" && definition.id.trim().length > 0) {
@@ -16442,7 +16604,7 @@ function collectEnvRefs(value, names = /* @__PURE__ */ new Set()) {
16442
16604
  }
16443
16605
  return names;
16444
16606
  }
16445
- if (isRecord3(value)) {
16607
+ if (isRecord4(value)) {
16446
16608
  for (const [key, entry] of Object.entries(value)) {
16447
16609
  if (key === "required_env") {
16448
16610
  for (const required of stringArray(entry)) {
@@ -17595,58 +17757,6 @@ var validateCommand = command({
17595
17757
  }
17596
17758
  });
17597
17759
 
17598
- // src/commands/workspace/deps.ts
17599
- import path32 from "node:path";
17600
- var depsCommand = command({
17601
- name: "deps",
17602
- description: "Scan eval files and list git repo dependencies needed by workspaces",
17603
- args: {
17604
- evalPaths: restPositionals({
17605
- type: string,
17606
- displayName: "eval-paths",
17607
- description: "Path(s) or glob(s) to evaluation .yaml file(s)"
17608
- }),
17609
- usedBy: flag({
17610
- long: "used-by",
17611
- description: "Include list of eval files that reference each repo"
17612
- })
17613
- },
17614
- handler: async ({ evalPaths, usedBy }) => {
17615
- if (evalPaths.length === 0) {
17616
- console.error("Usage: agentv workspace deps <eval-paths...>");
17617
- process.exit(1);
17618
- }
17619
- const cwd = process.cwd();
17620
- const resolvedPaths = await resolveEvalPaths(evalPaths, cwd);
17621
- const result = await scanRepoDeps(resolvedPaths);
17622
- for (const err2 of result.errors) {
17623
- console.error(`error: ${path32.relative(cwd, err2.file)}: ${err2.message}`);
17624
- }
17625
- if (result.errors.length > 0) {
17626
- process.exit(1);
17627
- }
17628
- const output = {
17629
- repos: result.repos.map((r) => ({
17630
- url: r.url,
17631
- ...r.ref !== void 0 && { ref: r.ref },
17632
- ...r.sparse !== void 0 && { sparse: r.sparse },
17633
- ...r.ancestor !== void 0 && { ancestor: r.ancestor },
17634
- ...usedBy && { used_by: r.usedBy.map((p) => path32.relative(cwd, p)) }
17635
- }))
17636
- };
17637
- console.log(JSON.stringify(output, null, 2));
17638
- }
17639
- });
17640
-
17641
- // src/commands/workspace/index.ts
17642
- var workspaceCommand = subcommands({
17643
- name: "workspace",
17644
- description: "Inspect workspace dependencies",
17645
- cmds: {
17646
- deps: depsCommand
17647
- }
17648
- });
17649
-
17650
17760
  // src/update-check.ts
17651
17761
  import { spawn as spawn4 } from "node:child_process";
17652
17762
  import { readFile as readFile9 } from "node:fs/promises";
@@ -17655,8 +17765,8 @@ var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
17655
17765
  var CONFIG_DIR = getAgentvConfigDir();
17656
17766
  var CACHE_FILE = "version-check.json";
17657
17767
  var NPM_REGISTRY_BASE2 = "https://registry.npmjs.org/agentv/";
17658
- async function getCachedUpdateInfo(path34) {
17659
- const filePath = path34 ?? join6(CONFIG_DIR, CACHE_FILE);
17768
+ async function getCachedUpdateInfo(path33) {
17769
+ const filePath = path33 ?? join6(CONFIG_DIR, CACHE_FILE);
17660
17770
  try {
17661
17771
  const raw = await readFile9(filePath, "utf-8");
17662
17772
  const data = JSON.parse(raw);
@@ -17761,8 +17871,7 @@ var app = subcommands({
17761
17871
  trend: trendCommand,
17762
17872
  transpile: transpileCommand,
17763
17873
  trim: trimCommand,
17764
- validate: validateCommand,
17765
- workspace: workspaceCommand
17874
+ validate: validateCommand
17766
17875
  }
17767
17876
  });
17768
17877
  var EVAL_SUBCOMMANDS = /* @__PURE__ */ new Set(["run", "assert", "aggregate", "bundle", "vitest"]);
@@ -17788,8 +17897,7 @@ var TOP_LEVEL_COMMANDS = /* @__PURE__ */ new Set([
17788
17897
  "trend",
17789
17898
  "transpile",
17790
17899
  "trim",
17791
- "validate",
17792
- "workspace"
17900
+ "validate"
17793
17901
  ]);
17794
17902
  function usesDeprecatedStudioAlias(argv) {
17795
17903
  return argv[2] === "studio";
@@ -17845,7 +17953,7 @@ ${updateNotice}
17845
17953
  if (shouldRunBeforeSessionHook(processedArgv)) {
17846
17954
  const cwd = process.cwd();
17847
17955
  const repoRoot = await findRepoRoot(cwd);
17848
- const sessionConfig = await loadConfig(path33.join(cwd, "_"), repoRoot);
17956
+ const sessionConfig = await loadConfig(path32.join(cwd, "_"), repoRoot);
17849
17957
  const beforeSessionCommand = sessionConfig?.hooks?.before_session;
17850
17958
  if (beforeSessionCommand) {
17851
17959
  runBeforeSessionHook(beforeSessionCommand);
@@ -17862,4 +17970,4 @@ export {
17862
17970
  preprocessArgv,
17863
17971
  runCli
17864
17972
  };
17865
- //# sourceMappingURL=chunk-GIRUNQGP.js.map
17973
+ //# sourceMappingURL=chunk-T32NL3E6.js.map