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.
- package/README.md +112 -66
- package/dist/harness.d.mts +12 -1
- package/dist/harness.d.ts +12 -1
- package/dist/harness.js +8 -0
- package/dist/harness.js.map +1 -1
- package/dist/harness.mjs +7 -0
- package/dist/harness.mjs.map +1 -1
- package/dist/index.d.mts +48 -20
- package/dist/index.d.ts +48 -20
- package/dist/index.js +308 -21
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +304 -21
- package/dist/index.mjs.map +1 -1
- package/dist/internal/scoring.d.mts +3 -3
- package/dist/internal/scoring.d.ts +3 -3
- package/dist/internal/scoring.js.map +1 -1
- package/dist/internal/toolCallScorer.js +42 -2
- package/dist/internal/toolCallScorer.js.map +1 -1
- package/dist/internal/toolCallScorer.mjs +42 -2
- package/dist/internal/toolCallScorer.mjs.map +1 -1
- package/dist/judges/factualityJudge.d.mts +151 -0
- package/dist/judges/factualityJudge.d.ts +151 -0
- package/dist/judges/factualityJudge.js +235 -0
- package/dist/judges/factualityJudge.js.map +1 -0
- package/dist/judges/factualityJudge.mjs +208 -0
- package/dist/judges/factualityJudge.mjs.map +1 -0
- package/dist/judges/index.d.mts +3 -1
- package/dist/judges/index.d.ts +3 -1
- package/dist/judges/index.js +447 -7
- package/dist/judges/index.js.map +1 -1
- package/dist/judges/index.mjs +443 -6
- package/dist/judges/index.mjs.map +1 -1
- package/dist/judges/judgeHarness.d.mts +122 -0
- package/dist/judges/judgeHarness.d.ts +122 -0
- package/dist/judges/judgeHarness.js +303 -0
- package/dist/judges/judgeHarness.js.map +1 -0
- package/dist/judges/judgeHarness.mjs +274 -0
- package/dist/judges/judgeHarness.mjs.map +1 -0
- package/dist/judges/structuredOutputJudge.d.mts +1 -0
- package/dist/judges/structuredOutputJudge.d.ts +1 -0
- package/dist/judges/toolCallJudge.d.mts +1 -0
- package/dist/judges/toolCallJudge.d.ts +1 -0
- package/dist/judges/toolCallJudge.js +42 -2
- package/dist/judges/toolCallJudge.js.map +1 -1
- package/dist/judges/toolCallJudge.mjs +42 -2
- package/dist/judges/toolCallJudge.mjs.map +1 -1
- package/dist/judges/types.d.mts +33 -6
- package/dist/judges/types.d.ts +33 -6
- package/dist/judges/types.js.map +1 -1
- package/dist/legacy/scorers/index.js +42 -2
- package/dist/legacy/scorers/index.js.map +1 -1
- package/dist/legacy/scorers/index.mjs +42 -2
- package/dist/legacy/scorers/index.mjs.map +1 -1
- package/dist/legacy/scorers/toolCallScorer.js +42 -2
- package/dist/legacy/scorers/toolCallScorer.js.map +1 -1
- package/dist/legacy/scorers/toolCallScorer.mjs +42 -2
- package/dist/legacy/scorers/toolCallScorer.mjs.map +1 -1
- package/dist/legacy.js +56 -3
- package/dist/legacy.js.map +1 -1
- package/dist/legacy.mjs +56 -3
- package/dist/legacy.mjs.map +1 -1
- package/dist/replay.js +1 -1
- package/dist/replay.js.map +1 -1
- package/dist/replay.mjs +1 -1
- package/dist/replay.mjs.map +1 -1
- package/dist/reporter.js.map +1 -1
- package/dist/reporter.mjs.map +1 -1
- 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:
|
|
806
|
-
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
|
|
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 ({
|
|
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(
|
|
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
|
|
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
|
-
...
|
|
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 =
|
|
1199
|
-
return assistantContent
|
|
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(
|
|
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,
|