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.mjs
CHANGED
|
@@ -184,6 +184,9 @@ function toolCalls(session) {
|
|
|
184
184
|
function messagesByRole(session, role) {
|
|
185
185
|
return session.messages.filter((message) => message.role === role);
|
|
186
186
|
}
|
|
187
|
+
function hasNonEmptyMessageContent(message) {
|
|
188
|
+
return message.content !== void 0 && (typeof message.content !== "string" || message.content.trim().length > 0);
|
|
189
|
+
}
|
|
187
190
|
function systemMessages(session) {
|
|
188
191
|
return messagesByRole(session, "system");
|
|
189
192
|
}
|
|
@@ -193,6 +196,9 @@ function userMessages(session) {
|
|
|
193
196
|
function assistantMessages(session) {
|
|
194
197
|
return messagesByRole(session, "assistant");
|
|
195
198
|
}
|
|
199
|
+
function latestAssistantMessageContent(session) {
|
|
200
|
+
return [...assistantMessages(session)].reverse().find(hasNonEmptyMessageContent)?.content;
|
|
201
|
+
}
|
|
196
202
|
function toolMessages(session) {
|
|
197
203
|
return messagesByRole(session, "tool");
|
|
198
204
|
}
|
|
@@ -231,6 +237,64 @@ function serializeError(error) {
|
|
|
231
237
|
};
|
|
232
238
|
}
|
|
233
239
|
|
|
240
|
+
// src/judges/judgeHarness.ts
|
|
241
|
+
function createJudgeHarness(options) {
|
|
242
|
+
return createHarness({
|
|
243
|
+
name: options.name ?? "judge-harness",
|
|
244
|
+
run: async ({ input, signal, metadata }) => {
|
|
245
|
+
return normalizeJudgeHarnessResult(
|
|
246
|
+
await options.run(input, { signal, metadata })
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
async function runJudgeHarness(judgeHarness, input, options = {}) {
|
|
252
|
+
const artifacts = {};
|
|
253
|
+
const run = await judgeHarness.run(input, {
|
|
254
|
+
metadata: options.metadata ?? {},
|
|
255
|
+
signal: options.signal,
|
|
256
|
+
artifacts,
|
|
257
|
+
setArtifact: (name, value) => {
|
|
258
|
+
artifacts[name] = value;
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
return run.output !== void 0 ? run.output : resolveJudgeHarnessAssistantOutput(run);
|
|
262
|
+
}
|
|
263
|
+
function createRunJudge(judgeHarness, signal) {
|
|
264
|
+
if (!judgeHarness) {
|
|
265
|
+
return void 0;
|
|
266
|
+
}
|
|
267
|
+
return (input, options) => runJudgeHarness(judgeHarness, input, {
|
|
268
|
+
metadata: options?.metadata,
|
|
269
|
+
signal
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
function normalizeJudgeHarnessResult(result) {
|
|
273
|
+
if (isHarnessRun(result)) {
|
|
274
|
+
return result;
|
|
275
|
+
}
|
|
276
|
+
if (hasOutputField(result)) {
|
|
277
|
+
return {
|
|
278
|
+
output: normalizeJudgeHarnessOutput(result.output)
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
return {
|
|
282
|
+
output: normalizeJudgeHarnessOutput(result)
|
|
283
|
+
};
|
|
284
|
+
}
|
|
285
|
+
function hasOutputField(value) {
|
|
286
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === 1 && "output" in value;
|
|
287
|
+
}
|
|
288
|
+
function normalizeJudgeHarnessOutput(value) {
|
|
289
|
+
if (value === void 0) {
|
|
290
|
+
return void 0;
|
|
291
|
+
}
|
|
292
|
+
return normalizeContent(value);
|
|
293
|
+
}
|
|
294
|
+
function resolveJudgeHarnessAssistantOutput(run) {
|
|
295
|
+
return latestAssistantMessageContent(run.session) ?? "";
|
|
296
|
+
}
|
|
297
|
+
|
|
234
298
|
// src/wrapText.ts
|
|
235
299
|
function wrapText(text, width = 80) {
|
|
236
300
|
if (!text || text.length <= width) {
|
|
@@ -253,6 +317,171 @@ function wrapText(text, width = 80) {
|
|
|
253
317
|
return lines.join("\n");
|
|
254
318
|
}
|
|
255
319
|
|
|
320
|
+
// src/judges/factualityJudge.ts
|
|
321
|
+
var FACTUALITY_CHOICE_SCORES = {
|
|
322
|
+
A: 0.4,
|
|
323
|
+
B: 0.6,
|
|
324
|
+
C: 1,
|
|
325
|
+
D: 0,
|
|
326
|
+
E: 1
|
|
327
|
+
};
|
|
328
|
+
var FACTUALITY_SYSTEM = "You are comparing factual content. Ignore differences in style, grammar, punctuation, and formatting.";
|
|
329
|
+
var FACTUALITY_RESPONSE_SCHEMA = {
|
|
330
|
+
type: "object",
|
|
331
|
+
additionalProperties: false,
|
|
332
|
+
required: ["choice", "rationale"],
|
|
333
|
+
properties: {
|
|
334
|
+
choice: {
|
|
335
|
+
enum: ["A", "B", "C", "D", "E"]
|
|
336
|
+
},
|
|
337
|
+
rationale: {
|
|
338
|
+
type: "string"
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
function FactualityJudge(config = {}) {
|
|
343
|
+
const judgeHarness = config.judgeHarness;
|
|
344
|
+
return {
|
|
345
|
+
name: config.name ?? "FactualityJudge",
|
|
346
|
+
judgeHarness,
|
|
347
|
+
assess: (opts) => assessFactuality(opts, judgeHarness)
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
async function assessFactuality(opts, configuredJudgeHarness) {
|
|
351
|
+
const metadata = opts.metadata;
|
|
352
|
+
const expected = opts.expected === void 0 ? metadata.expected : opts.expected;
|
|
353
|
+
if (isMissingExpectedAnswer(expected)) {
|
|
354
|
+
return {
|
|
355
|
+
score: 0,
|
|
356
|
+
metadata: {
|
|
357
|
+
rationale: "FactualityJudge requires a non-empty expert answer in `expected` or `metadata.expected`."
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
const runJudge = opts.runJudge ?? createRunJudge(
|
|
362
|
+
configuredJudgeHarness,
|
|
363
|
+
opts.signal
|
|
364
|
+
);
|
|
365
|
+
if (!runJudge) {
|
|
366
|
+
throw new Error(
|
|
367
|
+
"FactualityJudge requires a judgeHarness in FactualityJudge(...) config, describeEval(...) options, toSatisfyJudge(...) options, or JudgeContext.runJudge."
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
const verdict = await runJudge({
|
|
371
|
+
system: FACTUALITY_SYSTEM,
|
|
372
|
+
prompt: formatFactualityPrompt({
|
|
373
|
+
input: opts.input,
|
|
374
|
+
expected,
|
|
375
|
+
output: resolveJudgeOutput(opts)
|
|
376
|
+
}),
|
|
377
|
+
responseFormat: {
|
|
378
|
+
type: "json",
|
|
379
|
+
schema: FACTUALITY_RESPONSE_SCHEMA
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
return formatJudgeResult(parseFactualityJudgeVerdict(verdict));
|
|
383
|
+
}
|
|
384
|
+
function isMissingExpectedAnswer(value) {
|
|
385
|
+
return value == null || typeof value === "string" && value.trim().length === 0;
|
|
386
|
+
}
|
|
387
|
+
function resolveJudgeOutput(opts) {
|
|
388
|
+
if (opts.output !== void 0) {
|
|
389
|
+
return opts.output;
|
|
390
|
+
}
|
|
391
|
+
return latestAssistantMessageContent(opts.session) ?? "";
|
|
392
|
+
}
|
|
393
|
+
function parseFactualityJudgeVerdict(value) {
|
|
394
|
+
const parsed = typeof value === "string" ? parseJsonObject(value) : value;
|
|
395
|
+
if (!parsed || typeof parsed !== "object") {
|
|
396
|
+
throw new Error(
|
|
397
|
+
"FactualityJudge judgeHarness must return an object with `choice` and `rationale`."
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
const verdict = parsed;
|
|
401
|
+
if (!isFactualityChoice(verdict.choice)) {
|
|
402
|
+
throw new Error(
|
|
403
|
+
"FactualityJudge judgeHarness must return choice A, B, C, D, or E."
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
if (typeof verdict.rationale !== "string") {
|
|
407
|
+
throw new Error(
|
|
408
|
+
"FactualityJudge judgeHarness must return a string `rationale`."
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
return {
|
|
412
|
+
choice: verdict.choice,
|
|
413
|
+
rationale: verdict.rationale
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
function parseJsonObject(value) {
|
|
417
|
+
try {
|
|
418
|
+
return JSON.parse(value);
|
|
419
|
+
} catch {
|
|
420
|
+
const fencedJson = value.match(/```(?:json)?\s*([\s\S]*?)\s*```/i);
|
|
421
|
+
if (!fencedJson) {
|
|
422
|
+
throw new Error(
|
|
423
|
+
"FactualityJudge judgeHarness must return JSON with `choice` and `rationale`."
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
return JSON.parse(fencedJson[1]);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
function isFactualityChoice(value) {
|
|
430
|
+
return value === "A" || value === "B" || value === "C" || value === "D" || value === "E";
|
|
431
|
+
}
|
|
432
|
+
function formatFactualityPrompt({
|
|
433
|
+
input,
|
|
434
|
+
expected,
|
|
435
|
+
output
|
|
436
|
+
}) {
|
|
437
|
+
const comparison = formatJudgeValue({
|
|
438
|
+
question: input ?? "",
|
|
439
|
+
expert_answer: expected,
|
|
440
|
+
submitted_answer: output ?? ""
|
|
441
|
+
});
|
|
442
|
+
return `Compare the submitted answer with the expert answer.
|
|
443
|
+
|
|
444
|
+
Comparison payload:
|
|
445
|
+
${comparison}
|
|
446
|
+
|
|
447
|
+
Select exactly one option:
|
|
448
|
+
A: The submission is a fully consistent subset of the expert answer.
|
|
449
|
+
B: The submission is a fully consistent superset of the expert answer.
|
|
450
|
+
C: The submission contains the same factual details as the expert answer.
|
|
451
|
+
D: The submission disagrees with the expert answer.
|
|
452
|
+
E: The answers differ only in ways that do not affect factuality.
|
|
453
|
+
|
|
454
|
+
Return JSON with exactly these fields:
|
|
455
|
+
{
|
|
456
|
+
"choice": "C",
|
|
457
|
+
"rationale": "Brief explanation for the selected choice"
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
The choice value must be one of A, B, C, D, or E.`;
|
|
461
|
+
}
|
|
462
|
+
function formatJudgeValue(value) {
|
|
463
|
+
if (typeof value === "string") {
|
|
464
|
+
return value;
|
|
465
|
+
}
|
|
466
|
+
if (value === void 0) {
|
|
467
|
+
return "";
|
|
468
|
+
}
|
|
469
|
+
try {
|
|
470
|
+
return JSON.stringify(value, null, 2) ?? String(value);
|
|
471
|
+
} catch {
|
|
472
|
+
return String(value);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
function formatJudgeResult(object) {
|
|
476
|
+
return {
|
|
477
|
+
score: FACTUALITY_CHOICE_SCORES[object.choice],
|
|
478
|
+
metadata: {
|
|
479
|
+
rationale: object.rationale,
|
|
480
|
+
choice: object.choice
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
}
|
|
484
|
+
|
|
256
485
|
// src/internal/matchers.ts
|
|
257
486
|
function isRecord(value) {
|
|
258
487
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -630,8 +859,8 @@ function evaluateOrderedTools(expected, actual, options) {
|
|
|
630
859
|
score: expectedIndex / expected.length,
|
|
631
860
|
metadata: {
|
|
632
861
|
rationale: `Tool '${expectedTool.name}' called with incorrect arguments at position ${expectedIndex + 1} (${expectedIndex}/${expected.length} tools matched correctly)`,
|
|
633
|
-
expected: expectedTool.arguments,
|
|
634
|
-
actual: actualTool.arguments,
|
|
862
|
+
expected: normalizeContent(expectedTool.arguments),
|
|
863
|
+
actual: actualTool.arguments === void 0 ? void 0 : normalizeContent(actualTool.arguments),
|
|
635
864
|
matched: expectedIndex,
|
|
636
865
|
total: expected.length
|
|
637
866
|
}
|
|
@@ -763,8 +992,8 @@ function ToolCallJudge(config = {}) {
|
|
|
763
992
|
const metadata = opts.metadata;
|
|
764
993
|
return scorer({
|
|
765
994
|
...opts,
|
|
766
|
-
input:
|
|
767
|
-
output:
|
|
995
|
+
input: formatJudgeValue2(opts.input),
|
|
996
|
+
output: formatJudgeValue2(opts.output),
|
|
768
997
|
expectedTools: normalizeExpectedTools(
|
|
769
998
|
opts.expectedTools ?? metadata.expectedTools
|
|
770
999
|
)
|
|
@@ -777,7 +1006,7 @@ function normalizeExpectedTools(expectedTools) {
|
|
|
777
1006
|
(tool) => typeof tool === "string" ? { name: tool } : tool
|
|
778
1007
|
);
|
|
779
1008
|
}
|
|
780
|
-
function
|
|
1009
|
+
function formatJudgeValue2(value) {
|
|
781
1010
|
if (typeof value === "string") {
|
|
782
1011
|
return value;
|
|
783
1012
|
}
|
|
@@ -800,9 +1029,17 @@ var evalTest = test.extend("harness", async () => {
|
|
|
800
1029
|
}).extend(
|
|
801
1030
|
"automaticJudges",
|
|
802
1031
|
[]
|
|
803
|
-
).extend("judgeThreshold", void 0).extend(
|
|
1032
|
+
).extend("judgeThreshold", void 0).extend("judgeHarness", void 0).extend("explicitJudgeHarness", void 0).extend(
|
|
804
1033
|
"run",
|
|
805
|
-
async ({
|
|
1034
|
+
async ({
|
|
1035
|
+
automaticJudges,
|
|
1036
|
+
explicitJudgeHarness,
|
|
1037
|
+
harness,
|
|
1038
|
+
judgeHarness,
|
|
1039
|
+
judgeThreshold,
|
|
1040
|
+
signal,
|
|
1041
|
+
task
|
|
1042
|
+
}) => {
|
|
806
1043
|
return async (input, options) => {
|
|
807
1044
|
const resolvedHarness = harness;
|
|
808
1045
|
const metadata = createMetadata(options?.metadata);
|
|
@@ -830,6 +1067,7 @@ var evalTest = test.extend("harness", async () => {
|
|
|
830
1067
|
partialRun,
|
|
831
1068
|
resolvedHarness,
|
|
832
1069
|
input,
|
|
1070
|
+
explicitJudgeHarness,
|
|
833
1071
|
metadata,
|
|
834
1072
|
signal
|
|
835
1073
|
);
|
|
@@ -840,7 +1078,14 @@ var evalTest = test.extend("harness", async () => {
|
|
|
840
1078
|
run.artifacts = artifacts;
|
|
841
1079
|
}
|
|
842
1080
|
setHarnessMeta(task, resolvedHarness.name, run);
|
|
843
|
-
recordJudgeRunContext(
|
|
1081
|
+
recordJudgeRunContext(
|
|
1082
|
+
run,
|
|
1083
|
+
resolvedHarness,
|
|
1084
|
+
input,
|
|
1085
|
+
explicitJudgeHarness,
|
|
1086
|
+
metadata,
|
|
1087
|
+
signal
|
|
1088
|
+
);
|
|
844
1089
|
if (automaticJudges.length > 0) {
|
|
845
1090
|
await applyAutomaticJudges(
|
|
846
1091
|
task,
|
|
@@ -848,6 +1093,7 @@ var evalTest = test.extend("harness", async () => {
|
|
|
848
1093
|
judgeThreshold,
|
|
849
1094
|
resolvedHarness,
|
|
850
1095
|
input,
|
|
1096
|
+
judgeHarness,
|
|
851
1097
|
metadata,
|
|
852
1098
|
run,
|
|
853
1099
|
signal
|
|
@@ -862,6 +1108,7 @@ expect.extend({
|
|
|
862
1108
|
const { threshold = 1, ...context } = options ?? {};
|
|
863
1109
|
const judgeOptions = buildJudgeAssertionOptions(
|
|
864
1110
|
received,
|
|
1111
|
+
judge,
|
|
865
1112
|
context,
|
|
866
1113
|
isEvalTaskLike(this.task) ? this.task : void 0
|
|
867
1114
|
);
|
|
@@ -902,9 +1149,13 @@ function formatJudgeOutputForMessage(output) {
|
|
|
902
1149
|
function describeEval(name, options, define) {
|
|
903
1150
|
const suite = options.skipIf ? describe.skipIf(options.skipIf()) : describe;
|
|
904
1151
|
return suite(name, () => {
|
|
1152
|
+
const automaticJudges = options.judges ?? [];
|
|
1153
|
+
const explicitJudgeHarness = options.judgeHarness ?? resolveDefaultJudgeHarness(automaticJudges);
|
|
905
1154
|
const it = evalTest.override({
|
|
906
1155
|
harness: options.harness,
|
|
907
|
-
automaticJudges
|
|
1156
|
+
automaticJudges,
|
|
1157
|
+
judgeHarness: options.judgeHarness,
|
|
1158
|
+
explicitJudgeHarness,
|
|
908
1159
|
judgeThreshold: options.judgeThreshold
|
|
909
1160
|
});
|
|
910
1161
|
define(it);
|
|
@@ -913,10 +1164,14 @@ function describeEval(name, options, define) {
|
|
|
913
1164
|
function createMetadata(metadata) {
|
|
914
1165
|
return { ...metadata ?? {} };
|
|
915
1166
|
}
|
|
916
|
-
async function applyAutomaticJudges(task, judges, threshold, harness, input, metadata, run, signal) {
|
|
1167
|
+
async function applyAutomaticJudges(task, judges, threshold, harness, input, judgeHarness, metadata, run, signal) {
|
|
917
1168
|
const runToolCalls = toolCalls(run.session);
|
|
918
1169
|
const scores = await Promise.all(
|
|
919
1170
|
judges.map((judge) => {
|
|
1171
|
+
const runJudge = createRunJudge(
|
|
1172
|
+
resolveJudgeHarnessForJudge(judge, judgeHarness),
|
|
1173
|
+
signal
|
|
1174
|
+
);
|
|
920
1175
|
const judgeOptions = {
|
|
921
1176
|
input,
|
|
922
1177
|
output: run.output,
|
|
@@ -925,7 +1180,8 @@ async function applyAutomaticJudges(task, judges, threshold, harness, input, met
|
|
|
925
1180
|
run,
|
|
926
1181
|
session: run.session,
|
|
927
1182
|
signal,
|
|
928
|
-
harness
|
|
1183
|
+
harness,
|
|
1184
|
+
runJudge
|
|
929
1185
|
};
|
|
930
1186
|
return Promise.resolve(judge.assess(judgeOptions));
|
|
931
1187
|
})
|
|
@@ -965,10 +1221,11 @@ function setHarnessMeta(task, name, run) {
|
|
|
965
1221
|
run
|
|
966
1222
|
};
|
|
967
1223
|
}
|
|
968
|
-
function recordJudgeRunContext(run, harness, input, metadata, signal) {
|
|
1224
|
+
function recordJudgeRunContext(run, harness, input, judgeHarness, metadata, signal) {
|
|
969
1225
|
const context = {
|
|
970
1226
|
harness,
|
|
971
1227
|
input,
|
|
1228
|
+
judgeHarness,
|
|
972
1229
|
metadata,
|
|
973
1230
|
run,
|
|
974
1231
|
signal
|
|
@@ -1029,13 +1286,15 @@ function formatJudgeTextOutput(run) {
|
|
|
1029
1286
|
}
|
|
1030
1287
|
return typeof assistantOutput === "string" ? assistantOutput : JSON.stringify(assistantOutput);
|
|
1031
1288
|
}
|
|
1032
|
-
function buildJudgeAssertionOptions(received, options, task) {
|
|
1289
|
+
function buildJudgeAssertionOptions(received, judge, options, task) {
|
|
1033
1290
|
const registeredContext = resolveRegisteredJudgeRunContext(
|
|
1034
1291
|
received,
|
|
1035
1292
|
options,
|
|
1036
1293
|
task
|
|
1037
1294
|
);
|
|
1038
1295
|
const harness = options.harness ?? registeredContext?.harness;
|
|
1296
|
+
const judgeHarness = options.judgeHarness ?? resolveJudgeHarnessForJudge(judge, registeredContext?.judgeHarness);
|
|
1297
|
+
const runJudge = createRunJudge(judgeHarness, registeredContext?.signal);
|
|
1039
1298
|
const signal = registeredContext?.signal;
|
|
1040
1299
|
const metadata = options.metadata ?? registeredContext?.metadata ?? {};
|
|
1041
1300
|
const input = options.input ?? registeredContext?.input ?? void 0;
|
|
@@ -1055,8 +1314,9 @@ function buildJudgeAssertionOptions(received, options, task) {
|
|
|
1055
1314
|
options.output
|
|
1056
1315
|
);
|
|
1057
1316
|
const resolvedToolCalls = options.toolCalls ?? toolCalls(run.session);
|
|
1317
|
+
const { judgeHarness: _judgeHarness, ...judgeParams } = options;
|
|
1058
1318
|
return {
|
|
1059
|
-
...
|
|
1319
|
+
...judgeParams,
|
|
1060
1320
|
input: resolvedInput,
|
|
1061
1321
|
output,
|
|
1062
1322
|
metadata,
|
|
@@ -1064,9 +1324,23 @@ function buildJudgeAssertionOptions(received, options, task) {
|
|
|
1064
1324
|
session: options.session ?? run.session,
|
|
1065
1325
|
signal,
|
|
1066
1326
|
toolCalls: resolvedToolCalls,
|
|
1067
|
-
harness
|
|
1327
|
+
harness,
|
|
1328
|
+
runJudge
|
|
1068
1329
|
};
|
|
1069
1330
|
}
|
|
1331
|
+
function resolveJudgeHarnessForJudge(judge, fallback) {
|
|
1332
|
+
return judge.judgeHarness ?? fallback;
|
|
1333
|
+
}
|
|
1334
|
+
function resolveDefaultJudgeHarness(judges) {
|
|
1335
|
+
const configured = judges.map((judge) => judge.judgeHarness).filter(
|
|
1336
|
+
(judgeHarness) => Boolean(judgeHarness)
|
|
1337
|
+
);
|
|
1338
|
+
const [first] = configured;
|
|
1339
|
+
if (!first || configured.some((judgeHarness) => judgeHarness !== first)) {
|
|
1340
|
+
return void 0;
|
|
1341
|
+
}
|
|
1342
|
+
return first;
|
|
1343
|
+
}
|
|
1070
1344
|
function resolveRegisteredJudgeRunContext(received, options, task) {
|
|
1071
1345
|
if (options.run) {
|
|
1072
1346
|
return getRegisteredJudgeRunContext(options.run);
|
|
@@ -1156,11 +1430,8 @@ function inferJudgeOutputValue(received, session) {
|
|
|
1156
1430
|
return normalizeJudgeJsonValue(received);
|
|
1157
1431
|
}
|
|
1158
1432
|
function resolveAssistantOutput(session) {
|
|
1159
|
-
const assistantContent =
|
|
1160
|
-
return assistantContent
|
|
1161
|
-
}
|
|
1162
|
-
function hasAssistantOutputContent(message) {
|
|
1163
|
-
return message.content !== void 0 && (typeof message.content !== "string" || message.content.trim().length > 0);
|
|
1433
|
+
const assistantContent = latestAssistantMessageContent(session);
|
|
1434
|
+
return assistantContent !== void 0 ? normalizeContent(assistantContent) : void 0;
|
|
1164
1435
|
}
|
|
1165
1436
|
function normalizeJudgeJsonValue(value) {
|
|
1166
1437
|
if (value === void 0) {
|
|
@@ -1189,7 +1460,15 @@ reason ${wrapText(s.metadata.rationale)}` : ""}${formattedOutput}`;
|
|
|
1189
1460
|
return scoreLine;
|
|
1190
1461
|
}).join("\n\n");
|
|
1191
1462
|
}
|
|
1192
|
-
function createJudge(
|
|
1463
|
+
function createJudge(nameOrConfig, assessOrAssessor, assess) {
|
|
1464
|
+
if (typeof nameOrConfig !== "string") {
|
|
1465
|
+
return {
|
|
1466
|
+
name: nameOrConfig.name,
|
|
1467
|
+
judgeHarness: nameOrConfig.judgeHarness,
|
|
1468
|
+
assess: nameOrConfig.assess
|
|
1469
|
+
};
|
|
1470
|
+
}
|
|
1471
|
+
const name = nameOrConfig;
|
|
1193
1472
|
if (!assess) {
|
|
1194
1473
|
return {
|
|
1195
1474
|
name,
|
|
@@ -1209,17 +1488,21 @@ function createJudge(name, assessOrAssessor, assess) {
|
|
|
1209
1488
|
};
|
|
1210
1489
|
}
|
|
1211
1490
|
export {
|
|
1491
|
+
FactualityJudge,
|
|
1212
1492
|
StructuredOutputJudge,
|
|
1213
1493
|
ToolCallJudge,
|
|
1214
1494
|
assistantMessages,
|
|
1215
1495
|
attachHarnessRunToError,
|
|
1216
1496
|
createHarness,
|
|
1217
1497
|
createJudge,
|
|
1498
|
+
createJudgeHarness,
|
|
1218
1499
|
describeEval,
|
|
1219
1500
|
formatScores,
|
|
1220
1501
|
getHarnessRunFromError,
|
|
1502
|
+
latestAssistantMessageContent,
|
|
1221
1503
|
messagesByRole,
|
|
1222
1504
|
normalizeHarnessRun,
|
|
1505
|
+
runJudgeHarness,
|
|
1223
1506
|
systemMessages,
|
|
1224
1507
|
toolCalls,
|
|
1225
1508
|
toolMessages,
|