vitest-evals 0.9.0 → 0.10.0

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 (68) hide show
  1. package/README.md +112 -66
  2. package/dist/harness.d.mts +12 -1
  3. package/dist/harness.d.ts +12 -1
  4. package/dist/harness.js +8 -0
  5. package/dist/harness.js.map +1 -1
  6. package/dist/harness.mjs +7 -0
  7. package/dist/harness.mjs.map +1 -1
  8. package/dist/index.d.mts +48 -20
  9. package/dist/index.d.ts +48 -20
  10. package/dist/index.js +308 -21
  11. package/dist/index.js.map +1 -1
  12. package/dist/index.mjs +304 -21
  13. package/dist/index.mjs.map +1 -1
  14. package/dist/internal/scoring.d.mts +3 -3
  15. package/dist/internal/scoring.d.ts +3 -3
  16. package/dist/internal/scoring.js.map +1 -1
  17. package/dist/internal/toolCallScorer.js +42 -2
  18. package/dist/internal/toolCallScorer.js.map +1 -1
  19. package/dist/internal/toolCallScorer.mjs +42 -2
  20. package/dist/internal/toolCallScorer.mjs.map +1 -1
  21. package/dist/judges/factualityJudge.d.mts +151 -0
  22. package/dist/judges/factualityJudge.d.ts +151 -0
  23. package/dist/judges/factualityJudge.js +235 -0
  24. package/dist/judges/factualityJudge.js.map +1 -0
  25. package/dist/judges/factualityJudge.mjs +208 -0
  26. package/dist/judges/factualityJudge.mjs.map +1 -0
  27. package/dist/judges/index.d.mts +3 -1
  28. package/dist/judges/index.d.ts +3 -1
  29. package/dist/judges/index.js +447 -7
  30. package/dist/judges/index.js.map +1 -1
  31. package/dist/judges/index.mjs +443 -6
  32. package/dist/judges/index.mjs.map +1 -1
  33. package/dist/judges/judgeHarness.d.mts +122 -0
  34. package/dist/judges/judgeHarness.d.ts +122 -0
  35. package/dist/judges/judgeHarness.js +303 -0
  36. package/dist/judges/judgeHarness.js.map +1 -0
  37. package/dist/judges/judgeHarness.mjs +274 -0
  38. package/dist/judges/judgeHarness.mjs.map +1 -0
  39. package/dist/judges/structuredOutputJudge.d.mts +1 -0
  40. package/dist/judges/structuredOutputJudge.d.ts +1 -0
  41. package/dist/judges/toolCallJudge.d.mts +1 -0
  42. package/dist/judges/toolCallJudge.d.ts +1 -0
  43. package/dist/judges/toolCallJudge.js +42 -2
  44. package/dist/judges/toolCallJudge.js.map +1 -1
  45. package/dist/judges/toolCallJudge.mjs +42 -2
  46. package/dist/judges/toolCallJudge.mjs.map +1 -1
  47. package/dist/judges/types.d.mts +33 -6
  48. package/dist/judges/types.d.ts +33 -6
  49. package/dist/judges/types.js.map +1 -1
  50. package/dist/legacy/scorers/index.js +42 -2
  51. package/dist/legacy/scorers/index.js.map +1 -1
  52. package/dist/legacy/scorers/index.mjs +42 -2
  53. package/dist/legacy/scorers/index.mjs.map +1 -1
  54. package/dist/legacy/scorers/toolCallScorer.js +42 -2
  55. package/dist/legacy/scorers/toolCallScorer.js.map +1 -1
  56. package/dist/legacy/scorers/toolCallScorer.mjs +42 -2
  57. package/dist/legacy/scorers/toolCallScorer.mjs.map +1 -1
  58. package/dist/legacy.js +56 -3
  59. package/dist/legacy.js.map +1 -1
  60. package/dist/legacy.mjs +56 -3
  61. package/dist/legacy.mjs.map +1 -1
  62. package/dist/replay.js +1 -1
  63. package/dist/replay.js.map +1 -1
  64. package/dist/replay.mjs +1 -1
  65. package/dist/replay.mjs.map +1 -1
  66. package/dist/reporter.js.map +1 -1
  67. package/dist/reporter.mjs.map +1 -1
  68. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -20,17 +20,21 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ FactualityJudge: () => FactualityJudge,
23
24
  StructuredOutputJudge: () => StructuredOutputJudge,
24
25
  ToolCallJudge: () => ToolCallJudge,
25
26
  assistantMessages: () => assistantMessages,
26
27
  attachHarnessRunToError: () => attachHarnessRunToError,
27
28
  createHarness: () => createHarness,
28
29
  createJudge: () => createJudge,
30
+ createJudgeHarness: () => createJudgeHarness,
29
31
  describeEval: () => describeEval,
30
32
  formatScores: () => formatScores,
31
33
  getHarnessRunFromError: () => getHarnessRunFromError,
34
+ latestAssistantMessageContent: () => latestAssistantMessageContent,
32
35
  messagesByRole: () => messagesByRole,
33
36
  normalizeHarnessRun: () => normalizeHarnessRun,
37
+ runJudgeHarness: () => runJudgeHarness,
34
38
  systemMessages: () => systemMessages,
35
39
  toolCalls: () => toolCalls,
36
40
  toolMessages: () => toolMessages,
@@ -223,6 +227,9 @@ function toolCalls(session) {
223
227
  function messagesByRole(session, role) {
224
228
  return session.messages.filter((message) => message.role === role);
225
229
  }
230
+ function hasNonEmptyMessageContent(message) {
231
+ return message.content !== void 0 && (typeof message.content !== "string" || message.content.trim().length > 0);
232
+ }
226
233
  function systemMessages(session) {
227
234
  return messagesByRole(session, "system");
228
235
  }
@@ -232,6 +239,9 @@ function userMessages(session) {
232
239
  function assistantMessages(session) {
233
240
  return messagesByRole(session, "assistant");
234
241
  }
242
+ function latestAssistantMessageContent(session) {
243
+ return [...assistantMessages(session)].reverse().find(hasNonEmptyMessageContent)?.content;
244
+ }
235
245
  function toolMessages(session) {
236
246
  return messagesByRole(session, "tool");
237
247
  }
@@ -270,6 +280,64 @@ function serializeError(error) {
270
280
  };
271
281
  }
272
282
 
283
+ // src/judges/judgeHarness.ts
284
+ function createJudgeHarness(options) {
285
+ return createHarness({
286
+ name: options.name ?? "judge-harness",
287
+ run: async ({ input, signal, metadata }) => {
288
+ return normalizeJudgeHarnessResult(
289
+ await options.run(input, { signal, metadata })
290
+ );
291
+ }
292
+ });
293
+ }
294
+ async function runJudgeHarness(judgeHarness, input, options = {}) {
295
+ const artifacts = {};
296
+ const run = await judgeHarness.run(input, {
297
+ metadata: options.metadata ?? {},
298
+ signal: options.signal,
299
+ artifacts,
300
+ setArtifact: (name, value) => {
301
+ artifacts[name] = value;
302
+ }
303
+ });
304
+ return run.output !== void 0 ? run.output : resolveJudgeHarnessAssistantOutput(run);
305
+ }
306
+ function createRunJudge(judgeHarness, signal) {
307
+ if (!judgeHarness) {
308
+ return void 0;
309
+ }
310
+ return (input, options) => runJudgeHarness(judgeHarness, input, {
311
+ metadata: options?.metadata,
312
+ signal
313
+ });
314
+ }
315
+ function normalizeJudgeHarnessResult(result) {
316
+ if (isHarnessRun(result)) {
317
+ return result;
318
+ }
319
+ if (hasOutputField(result)) {
320
+ return {
321
+ output: normalizeJudgeHarnessOutput(result.output)
322
+ };
323
+ }
324
+ return {
325
+ output: normalizeJudgeHarnessOutput(result)
326
+ };
327
+ }
328
+ function hasOutputField(value) {
329
+ return value !== null && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === 1 && "output" in value;
330
+ }
331
+ function normalizeJudgeHarnessOutput(value) {
332
+ if (value === void 0) {
333
+ return void 0;
334
+ }
335
+ return normalizeContent(value);
336
+ }
337
+ function resolveJudgeHarnessAssistantOutput(run) {
338
+ return latestAssistantMessageContent(run.session) ?? "";
339
+ }
340
+
273
341
  // src/wrapText.ts
274
342
  function wrapText(text, width = 80) {
275
343
  if (!text || text.length <= width) {
@@ -292,6 +360,171 @@ function wrapText(text, width = 80) {
292
360
  return lines.join("\n");
293
361
  }
294
362
 
363
+ // src/judges/factualityJudge.ts
364
+ var FACTUALITY_CHOICE_SCORES = {
365
+ A: 0.4,
366
+ B: 0.6,
367
+ C: 1,
368
+ D: 0,
369
+ E: 1
370
+ };
371
+ var FACTUALITY_SYSTEM = "You are comparing factual content. Ignore differences in style, grammar, punctuation, and formatting.";
372
+ var FACTUALITY_RESPONSE_SCHEMA = {
373
+ type: "object",
374
+ additionalProperties: false,
375
+ required: ["choice", "rationale"],
376
+ properties: {
377
+ choice: {
378
+ enum: ["A", "B", "C", "D", "E"]
379
+ },
380
+ rationale: {
381
+ type: "string"
382
+ }
383
+ }
384
+ };
385
+ function FactualityJudge(config = {}) {
386
+ const judgeHarness = config.judgeHarness;
387
+ return {
388
+ name: config.name ?? "FactualityJudge",
389
+ judgeHarness,
390
+ assess: (opts) => assessFactuality(opts, judgeHarness)
391
+ };
392
+ }
393
+ async function assessFactuality(opts, configuredJudgeHarness) {
394
+ const metadata = opts.metadata;
395
+ const expected = opts.expected === void 0 ? metadata.expected : opts.expected;
396
+ if (isMissingExpectedAnswer(expected)) {
397
+ return {
398
+ score: 0,
399
+ metadata: {
400
+ rationale: "FactualityJudge requires a non-empty expert answer in `expected` or `metadata.expected`."
401
+ }
402
+ };
403
+ }
404
+ const runJudge = opts.runJudge ?? createRunJudge(
405
+ configuredJudgeHarness,
406
+ opts.signal
407
+ );
408
+ if (!runJudge) {
409
+ throw new Error(
410
+ "FactualityJudge requires a judgeHarness in FactualityJudge(...) config, describeEval(...) options, toSatisfyJudge(...) options, or JudgeContext.runJudge."
411
+ );
412
+ }
413
+ const verdict = await runJudge({
414
+ system: FACTUALITY_SYSTEM,
415
+ prompt: formatFactualityPrompt({
416
+ input: opts.input,
417
+ expected,
418
+ output: resolveJudgeOutput(opts)
419
+ }),
420
+ responseFormat: {
421
+ type: "json",
422
+ schema: FACTUALITY_RESPONSE_SCHEMA
423
+ }
424
+ });
425
+ return formatJudgeResult(parseFactualityJudgeVerdict(verdict));
426
+ }
427
+ function isMissingExpectedAnswer(value) {
428
+ return value == null || typeof value === "string" && value.trim().length === 0;
429
+ }
430
+ function resolveJudgeOutput(opts) {
431
+ if (opts.output !== void 0) {
432
+ return opts.output;
433
+ }
434
+ return latestAssistantMessageContent(opts.session) ?? "";
435
+ }
436
+ function parseFactualityJudgeVerdict(value) {
437
+ const parsed = typeof value === "string" ? parseJsonObject(value) : value;
438
+ if (!parsed || typeof parsed !== "object") {
439
+ throw new Error(
440
+ "FactualityJudge judgeHarness must return an object with `choice` and `rationale`."
441
+ );
442
+ }
443
+ const verdict = parsed;
444
+ if (!isFactualityChoice(verdict.choice)) {
445
+ throw new Error(
446
+ "FactualityJudge judgeHarness must return choice A, B, C, D, or E."
447
+ );
448
+ }
449
+ if (typeof verdict.rationale !== "string") {
450
+ throw new Error(
451
+ "FactualityJudge judgeHarness must return a string `rationale`."
452
+ );
453
+ }
454
+ return {
455
+ choice: verdict.choice,
456
+ rationale: verdict.rationale
457
+ };
458
+ }
459
+ function parseJsonObject(value) {
460
+ try {
461
+ return JSON.parse(value);
462
+ } catch {
463
+ const fencedJson = value.match(/```(?:json)?\s*([\s\S]*?)\s*```/i);
464
+ if (!fencedJson) {
465
+ throw new Error(
466
+ "FactualityJudge judgeHarness must return JSON with `choice` and `rationale`."
467
+ );
468
+ }
469
+ return JSON.parse(fencedJson[1]);
470
+ }
471
+ }
472
+ function isFactualityChoice(value) {
473
+ return value === "A" || value === "B" || value === "C" || value === "D" || value === "E";
474
+ }
475
+ function formatFactualityPrompt({
476
+ input,
477
+ expected,
478
+ output
479
+ }) {
480
+ const comparison = formatJudgeValue({
481
+ question: input ?? "",
482
+ expert_answer: expected,
483
+ submitted_answer: output ?? ""
484
+ });
485
+ return `Compare the submitted answer with the expert answer.
486
+
487
+ Comparison payload:
488
+ ${comparison}
489
+
490
+ Select exactly one option:
491
+ A: The submission is a fully consistent subset of the expert answer.
492
+ B: The submission is a fully consistent superset of the expert answer.
493
+ C: The submission contains the same factual details as the expert answer.
494
+ D: The submission disagrees with the expert answer.
495
+ E: The answers differ only in ways that do not affect factuality.
496
+
497
+ Return JSON with exactly these fields:
498
+ {
499
+ "choice": "C",
500
+ "rationale": "Brief explanation for the selected choice"
501
+ }
502
+
503
+ The choice value must be one of A, B, C, D, or E.`;
504
+ }
505
+ function formatJudgeValue(value) {
506
+ if (typeof value === "string") {
507
+ return value;
508
+ }
509
+ if (value === void 0) {
510
+ return "";
511
+ }
512
+ try {
513
+ return JSON.stringify(value, null, 2) ?? String(value);
514
+ } catch {
515
+ return String(value);
516
+ }
517
+ }
518
+ function formatJudgeResult(object) {
519
+ return {
520
+ score: FACTUALITY_CHOICE_SCORES[object.choice],
521
+ metadata: {
522
+ rationale: object.rationale,
523
+ choice: object.choice
524
+ }
525
+ };
526
+ }
527
+
295
528
  // src/internal/matchers.ts
296
529
  function isRecord(value) {
297
530
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -669,8 +902,8 @@ function evaluateOrderedTools(expected, actual, options) {
669
902
  score: expectedIndex / expected.length,
670
903
  metadata: {
671
904
  rationale: `Tool '${expectedTool.name}' called with incorrect arguments at position ${expectedIndex + 1} (${expectedIndex}/${expected.length} tools matched correctly)`,
672
- expected: expectedTool.arguments,
673
- actual: actualTool.arguments,
905
+ expected: normalizeContent(expectedTool.arguments),
906
+ actual: actualTool.arguments === void 0 ? void 0 : normalizeContent(actualTool.arguments),
674
907
  matched: expectedIndex,
675
908
  total: expected.length
676
909
  }
@@ -802,8 +1035,8 @@ function ToolCallJudge(config = {}) {
802
1035
  const metadata = opts.metadata;
803
1036
  return scorer({
804
1037
  ...opts,
805
- input: formatJudgeValue(opts.input),
806
- output: formatJudgeValue(opts.output),
1038
+ input: formatJudgeValue2(opts.input),
1039
+ output: formatJudgeValue2(opts.output),
807
1040
  expectedTools: normalizeExpectedTools(
808
1041
  opts.expectedTools ?? metadata.expectedTools
809
1042
  )
@@ -816,7 +1049,7 @@ function normalizeExpectedTools(expectedTools) {
816
1049
  (tool) => typeof tool === "string" ? { name: tool } : tool
817
1050
  );
818
1051
  }
819
- function formatJudgeValue(value) {
1052
+ function formatJudgeValue2(value) {
820
1053
  if (typeof value === "string") {
821
1054
  return value;
822
1055
  }
@@ -839,9 +1072,17 @@ var evalTest = import_vitest.test.extend("harness", async () => {
839
1072
  }).extend(
840
1073
  "automaticJudges",
841
1074
  []
842
- ).extend("judgeThreshold", void 0).extend(
1075
+ ).extend("judgeThreshold", void 0).extend("judgeHarness", void 0).extend("explicitJudgeHarness", void 0).extend(
843
1076
  "run",
844
- async ({ automaticJudges, harness, judgeThreshold, signal, task }) => {
1077
+ async ({
1078
+ automaticJudges,
1079
+ explicitJudgeHarness,
1080
+ harness,
1081
+ judgeHarness,
1082
+ judgeThreshold,
1083
+ signal,
1084
+ task
1085
+ }) => {
845
1086
  return async (input, options) => {
846
1087
  const resolvedHarness = harness;
847
1088
  const metadata = createMetadata(options?.metadata);
@@ -869,6 +1110,7 @@ var evalTest = import_vitest.test.extend("harness", async () => {
869
1110
  partialRun,
870
1111
  resolvedHarness,
871
1112
  input,
1113
+ explicitJudgeHarness,
872
1114
  metadata,
873
1115
  signal
874
1116
  );
@@ -879,7 +1121,14 @@ var evalTest = import_vitest.test.extend("harness", async () => {
879
1121
  run.artifacts = artifacts;
880
1122
  }
881
1123
  setHarnessMeta(task, resolvedHarness.name, run);
882
- recordJudgeRunContext(run, resolvedHarness, input, metadata, signal);
1124
+ recordJudgeRunContext(
1125
+ run,
1126
+ resolvedHarness,
1127
+ input,
1128
+ explicitJudgeHarness,
1129
+ metadata,
1130
+ signal
1131
+ );
883
1132
  if (automaticJudges.length > 0) {
884
1133
  await applyAutomaticJudges(
885
1134
  task,
@@ -887,6 +1136,7 @@ var evalTest = import_vitest.test.extend("harness", async () => {
887
1136
  judgeThreshold,
888
1137
  resolvedHarness,
889
1138
  input,
1139
+ judgeHarness,
890
1140
  metadata,
891
1141
  run,
892
1142
  signal
@@ -901,6 +1151,7 @@ import_vitest.expect.extend({
901
1151
  const { threshold = 1, ...context } = options ?? {};
902
1152
  const judgeOptions = buildJudgeAssertionOptions(
903
1153
  received,
1154
+ judge,
904
1155
  context,
905
1156
  isEvalTaskLike(this.task) ? this.task : void 0
906
1157
  );
@@ -941,9 +1192,13 @@ function formatJudgeOutputForMessage(output) {
941
1192
  function describeEval(name, options, define) {
942
1193
  const suite = options.skipIf ? import_vitest.describe.skipIf(options.skipIf()) : import_vitest.describe;
943
1194
  return suite(name, () => {
1195
+ const automaticJudges = options.judges ?? [];
1196
+ const explicitJudgeHarness = options.judgeHarness ?? resolveDefaultJudgeHarness(automaticJudges);
944
1197
  const it = evalTest.override({
945
1198
  harness: options.harness,
946
- automaticJudges: options.judges ?? [],
1199
+ automaticJudges,
1200
+ judgeHarness: options.judgeHarness,
1201
+ explicitJudgeHarness,
947
1202
  judgeThreshold: options.judgeThreshold
948
1203
  });
949
1204
  define(it);
@@ -952,10 +1207,14 @@ function describeEval(name, options, define) {
952
1207
  function createMetadata(metadata) {
953
1208
  return { ...metadata ?? {} };
954
1209
  }
955
- async function applyAutomaticJudges(task, judges, threshold, harness, input, metadata, run, signal) {
1210
+ async function applyAutomaticJudges(task, judges, threshold, harness, input, judgeHarness, metadata, run, signal) {
956
1211
  const runToolCalls = toolCalls(run.session);
957
1212
  const scores = await Promise.all(
958
1213
  judges.map((judge) => {
1214
+ const runJudge = createRunJudge(
1215
+ resolveJudgeHarnessForJudge(judge, judgeHarness),
1216
+ signal
1217
+ );
959
1218
  const judgeOptions = {
960
1219
  input,
961
1220
  output: run.output,
@@ -964,7 +1223,8 @@ async function applyAutomaticJudges(task, judges, threshold, harness, input, met
964
1223
  run,
965
1224
  session: run.session,
966
1225
  signal,
967
- harness
1226
+ harness,
1227
+ runJudge
968
1228
  };
969
1229
  return Promise.resolve(judge.assess(judgeOptions));
970
1230
  })
@@ -1004,10 +1264,11 @@ function setHarnessMeta(task, name, run) {
1004
1264
  run
1005
1265
  };
1006
1266
  }
1007
- function recordJudgeRunContext(run, harness, input, metadata, signal) {
1267
+ function recordJudgeRunContext(run, harness, input, judgeHarness, metadata, signal) {
1008
1268
  const context = {
1009
1269
  harness,
1010
1270
  input,
1271
+ judgeHarness,
1011
1272
  metadata,
1012
1273
  run,
1013
1274
  signal
@@ -1068,13 +1329,15 @@ function formatJudgeTextOutput(run) {
1068
1329
  }
1069
1330
  return typeof assistantOutput === "string" ? assistantOutput : JSON.stringify(assistantOutput);
1070
1331
  }
1071
- function buildJudgeAssertionOptions(received, options, task) {
1332
+ function buildJudgeAssertionOptions(received, judge, options, task) {
1072
1333
  const registeredContext = resolveRegisteredJudgeRunContext(
1073
1334
  received,
1074
1335
  options,
1075
1336
  task
1076
1337
  );
1077
1338
  const harness = options.harness ?? registeredContext?.harness;
1339
+ const judgeHarness = options.judgeHarness ?? resolveJudgeHarnessForJudge(judge, registeredContext?.judgeHarness);
1340
+ const runJudge = createRunJudge(judgeHarness, registeredContext?.signal);
1078
1341
  const signal = registeredContext?.signal;
1079
1342
  const metadata = options.metadata ?? registeredContext?.metadata ?? {};
1080
1343
  const input = options.input ?? registeredContext?.input ?? void 0;
@@ -1094,8 +1357,9 @@ function buildJudgeAssertionOptions(received, options, task) {
1094
1357
  options.output
1095
1358
  );
1096
1359
  const resolvedToolCalls = options.toolCalls ?? toolCalls(run.session);
1360
+ const { judgeHarness: _judgeHarness, ...judgeParams } = options;
1097
1361
  return {
1098
- ...options,
1362
+ ...judgeParams,
1099
1363
  input: resolvedInput,
1100
1364
  output,
1101
1365
  metadata,
@@ -1103,9 +1367,23 @@ function buildJudgeAssertionOptions(received, options, task) {
1103
1367
  session: options.session ?? run.session,
1104
1368
  signal,
1105
1369
  toolCalls: resolvedToolCalls,
1106
- harness
1370
+ harness,
1371
+ runJudge
1107
1372
  };
1108
1373
  }
1374
+ function resolveJudgeHarnessForJudge(judge, fallback) {
1375
+ return judge.judgeHarness ?? fallback;
1376
+ }
1377
+ function resolveDefaultJudgeHarness(judges) {
1378
+ const configured = judges.map((judge) => judge.judgeHarness).filter(
1379
+ (judgeHarness) => Boolean(judgeHarness)
1380
+ );
1381
+ const [first] = configured;
1382
+ if (!first || configured.some((judgeHarness) => judgeHarness !== first)) {
1383
+ return void 0;
1384
+ }
1385
+ return first;
1386
+ }
1109
1387
  function resolveRegisteredJudgeRunContext(received, options, task) {
1110
1388
  if (options.run) {
1111
1389
  return getRegisteredJudgeRunContext(options.run);
@@ -1195,11 +1473,8 @@ function inferJudgeOutputValue(received, session) {
1195
1473
  return normalizeJudgeJsonValue(received);
1196
1474
  }
1197
1475
  function resolveAssistantOutput(session) {
1198
- const assistantContent = [...assistantMessages(session)].reverse().find(hasAssistantOutputContent);
1199
- return assistantContent?.content !== void 0 ? normalizeContent(assistantContent.content) : void 0;
1200
- }
1201
- function hasAssistantOutputContent(message) {
1202
- return message.content !== void 0 && (typeof message.content !== "string" || message.content.trim().length > 0);
1476
+ const assistantContent = latestAssistantMessageContent(session);
1477
+ return assistantContent !== void 0 ? normalizeContent(assistantContent) : void 0;
1203
1478
  }
1204
1479
  function normalizeJudgeJsonValue(value) {
1205
1480
  if (value === void 0) {
@@ -1228,7 +1503,15 @@ reason ${wrapText(s.metadata.rationale)}` : ""}${formattedOutput}`;
1228
1503
  return scoreLine;
1229
1504
  }).join("\n\n");
1230
1505
  }
1231
- function createJudge(name, assessOrAssessor, assess) {
1506
+ function createJudge(nameOrConfig, assessOrAssessor, assess) {
1507
+ if (typeof nameOrConfig !== "string") {
1508
+ return {
1509
+ name: nameOrConfig.name,
1510
+ judgeHarness: nameOrConfig.judgeHarness,
1511
+ assess: nameOrConfig.assess
1512
+ };
1513
+ }
1514
+ const name = nameOrConfig;
1232
1515
  if (!assess) {
1233
1516
  return {
1234
1517
  name,
@@ -1249,17 +1532,21 @@ function createJudge(name, assessOrAssessor, assess) {
1249
1532
  }
1250
1533
  // Annotate the CommonJS export names for ESM import in node:
1251
1534
  0 && (module.exports = {
1535
+ FactualityJudge,
1252
1536
  StructuredOutputJudge,
1253
1537
  ToolCallJudge,
1254
1538
  assistantMessages,
1255
1539
  attachHarnessRunToError,
1256
1540
  createHarness,
1257
1541
  createJudge,
1542
+ createJudgeHarness,
1258
1543
  describeEval,
1259
1544
  formatScores,
1260
1545
  getHarnessRunFromError,
1546
+ latestAssistantMessageContent,
1261
1547
  messagesByRole,
1262
1548
  normalizeHarnessRun,
1549
+ runJudgeHarness,
1263
1550
  systemMessages,
1264
1551
  toolCalls,
1265
1552
  toolMessages,