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/judges/index.mjs
CHANGED
|
@@ -1,3 +1,437 @@
|
|
|
1
|
+
// src/harness.ts
|
|
2
|
+
function isJsonPrimitive(value) {
|
|
3
|
+
return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
4
|
+
}
|
|
5
|
+
function isJsonRecord(value) {
|
|
6
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7
|
+
}
|
|
8
|
+
function normalizeJsonArray(value) {
|
|
9
|
+
return value.map((item) => {
|
|
10
|
+
const normalized = toJsonValue(item);
|
|
11
|
+
return normalized === void 0 ? null : normalized;
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
function normalizeJsonObject(value) {
|
|
15
|
+
const normalized = {};
|
|
16
|
+
for (const [key, entryValue] of Object.entries(value)) {
|
|
17
|
+
const entry = toJsonValue(entryValue);
|
|
18
|
+
if (entry !== void 0) {
|
|
19
|
+
normalized[key] = entry;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return normalized;
|
|
23
|
+
}
|
|
24
|
+
function toJsonValue(value) {
|
|
25
|
+
if (isJsonPrimitive(value)) {
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
if (Array.isArray(value)) {
|
|
29
|
+
return normalizeJsonArray(value);
|
|
30
|
+
}
|
|
31
|
+
if (isJsonRecord(value)) {
|
|
32
|
+
return normalizeJsonObject(value);
|
|
33
|
+
}
|
|
34
|
+
return void 0;
|
|
35
|
+
}
|
|
36
|
+
function normalizeRecord(value) {
|
|
37
|
+
return normalizeJsonObject(value);
|
|
38
|
+
}
|
|
39
|
+
function normalizeMetadata(value) {
|
|
40
|
+
const normalized = normalizeRecord(value);
|
|
41
|
+
return Object.keys(normalized).length > 0 ? normalized : void 0;
|
|
42
|
+
}
|
|
43
|
+
function normalizeContent(value) {
|
|
44
|
+
const normalized = toJsonValue(value);
|
|
45
|
+
return normalized !== void 0 ? normalized : String(value);
|
|
46
|
+
}
|
|
47
|
+
function createHarness(options) {
|
|
48
|
+
const harness = {
|
|
49
|
+
name: options.name,
|
|
50
|
+
run: async (input, context) => {
|
|
51
|
+
const result = await options.run({
|
|
52
|
+
input,
|
|
53
|
+
metadata: context.metadata,
|
|
54
|
+
signal: context.signal,
|
|
55
|
+
artifacts: context.artifacts,
|
|
56
|
+
setArtifact: context.setArtifact
|
|
57
|
+
});
|
|
58
|
+
return normalizeHarnessRun(input, result, context);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
return harness;
|
|
62
|
+
}
|
|
63
|
+
function normalizeHarnessRun(input, result, context) {
|
|
64
|
+
if (isHarnessRun(result)) {
|
|
65
|
+
if (context && Object.keys(context.artifacts).length > 0 && !result.artifacts) {
|
|
66
|
+
return {
|
|
67
|
+
...result,
|
|
68
|
+
artifacts: context.artifacts
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
const output = result.output;
|
|
74
|
+
const toolCalls = normalizeSimpleToolCalls(result.toolCalls);
|
|
75
|
+
const usage = result.usage ?? {};
|
|
76
|
+
const messages = result.messages ?? createDefaultSessionMessages({
|
|
77
|
+
input,
|
|
78
|
+
output,
|
|
79
|
+
toolCalls
|
|
80
|
+
});
|
|
81
|
+
const metadata = result.metadata ? normalizeMetadata(result.metadata) : void 0;
|
|
82
|
+
const artifacts = normalizeMergedArtifacts(
|
|
83
|
+
context?.artifacts,
|
|
84
|
+
result.artifacts
|
|
85
|
+
);
|
|
86
|
+
return {
|
|
87
|
+
session: {
|
|
88
|
+
messages,
|
|
89
|
+
...usage.provider ? { provider: usage.provider } : {},
|
|
90
|
+
...usage.model ? { model: usage.model } : {},
|
|
91
|
+
...metadata ? { metadata } : {}
|
|
92
|
+
},
|
|
93
|
+
...output !== void 0 ? { output } : {},
|
|
94
|
+
usage,
|
|
95
|
+
...result.timings ? { timings: result.timings } : {},
|
|
96
|
+
...artifacts ? { artifacts } : {},
|
|
97
|
+
errors: normalizeSimpleErrors(result.errors)
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
function createDefaultSessionMessages({
|
|
101
|
+
input,
|
|
102
|
+
output,
|
|
103
|
+
toolCalls: normalizedToolCalls
|
|
104
|
+
}) {
|
|
105
|
+
const messages = [
|
|
106
|
+
{
|
|
107
|
+
role: "user",
|
|
108
|
+
content: normalizeContent(input)
|
|
109
|
+
}
|
|
110
|
+
];
|
|
111
|
+
if (output !== void 0 || normalizedToolCalls.length > 0) {
|
|
112
|
+
messages.push({
|
|
113
|
+
role: "assistant",
|
|
114
|
+
...output !== void 0 ? { content: normalizeContent(output) } : {},
|
|
115
|
+
...normalizedToolCalls.length > 0 ? { toolCalls: normalizedToolCalls } : {}
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
return messages;
|
|
119
|
+
}
|
|
120
|
+
function normalizeSimpleToolCalls(calls) {
|
|
121
|
+
return (calls ?? []).map((call) => {
|
|
122
|
+
const {
|
|
123
|
+
arguments: rawArguments,
|
|
124
|
+
result: rawResult,
|
|
125
|
+
error: rawError,
|
|
126
|
+
metadata: rawMetadata,
|
|
127
|
+
...toolCall
|
|
128
|
+
} = call;
|
|
129
|
+
const args = normalizeToolCallArguments(rawArguments);
|
|
130
|
+
const result = toJsonValue(rawResult);
|
|
131
|
+
const error = normalizeToolCallError(rawError);
|
|
132
|
+
const metadata = rawMetadata ? normalizeMetadata(rawMetadata) : void 0;
|
|
133
|
+
return {
|
|
134
|
+
...toolCall,
|
|
135
|
+
...args ? { arguments: args } : {},
|
|
136
|
+
...result !== void 0 ? { result } : {},
|
|
137
|
+
...error ? { error } : {},
|
|
138
|
+
...metadata ? { metadata } : {}
|
|
139
|
+
};
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
function normalizeToolCallArguments(value) {
|
|
143
|
+
if (value === void 0) {
|
|
144
|
+
return void 0;
|
|
145
|
+
}
|
|
146
|
+
const normalized = toJsonValue(value);
|
|
147
|
+
return normalized && typeof normalized === "object" && !Array.isArray(normalized) ? normalized : void 0;
|
|
148
|
+
}
|
|
149
|
+
function normalizeToolCallError(value) {
|
|
150
|
+
if (value === void 0) {
|
|
151
|
+
return void 0;
|
|
152
|
+
}
|
|
153
|
+
const serialized = serializeError(value);
|
|
154
|
+
const { message, type, ...details } = serialized;
|
|
155
|
+
return {
|
|
156
|
+
...details,
|
|
157
|
+
message: typeof message === "string" ? message : String(message),
|
|
158
|
+
...typeof type === "string" ? { type } : {}
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
function normalizeMergedArtifacts(contextArtifacts, resultArtifacts) {
|
|
162
|
+
const artifacts = {
|
|
163
|
+
...contextArtifacts ?? {},
|
|
164
|
+
...resultArtifacts ? normalizeRecord(resultArtifacts) : {}
|
|
165
|
+
};
|
|
166
|
+
return Object.keys(artifacts).length > 0 ? artifacts : void 0;
|
|
167
|
+
}
|
|
168
|
+
function normalizeSimpleErrors(errors) {
|
|
169
|
+
return (errors ?? []).map((error) => {
|
|
170
|
+
const normalized = toJsonValue(error);
|
|
171
|
+
if (normalized && typeof normalized === "object" && !Array.isArray(normalized) && Object.keys(normalized).length > 0) {
|
|
172
|
+
return normalized;
|
|
173
|
+
}
|
|
174
|
+
return serializeError(error);
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
function messagesByRole(session, role) {
|
|
178
|
+
return session.messages.filter((message) => message.role === role);
|
|
179
|
+
}
|
|
180
|
+
function hasNonEmptyMessageContent(message) {
|
|
181
|
+
return message.content !== void 0 && (typeof message.content !== "string" || message.content.trim().length > 0);
|
|
182
|
+
}
|
|
183
|
+
function assistantMessages(session) {
|
|
184
|
+
return messagesByRole(session, "assistant");
|
|
185
|
+
}
|
|
186
|
+
function latestAssistantMessageContent(session) {
|
|
187
|
+
return [...assistantMessages(session)].reverse().find(hasNonEmptyMessageContent)?.content;
|
|
188
|
+
}
|
|
189
|
+
function isHarnessRun(value) {
|
|
190
|
+
if (!value || typeof value !== "object") {
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
const candidate = value;
|
|
194
|
+
return isNormalizedSession(candidate.session) && Boolean(candidate.usage) && typeof candidate.usage === "object" && !Array.isArray(candidate.usage) && Array.isArray(candidate.errors);
|
|
195
|
+
}
|
|
196
|
+
function isNormalizedSession(value) {
|
|
197
|
+
return Boolean(value) && typeof value === "object" && value !== null && "messages" in value && Array.isArray(value.messages);
|
|
198
|
+
}
|
|
199
|
+
function serializeError(error) {
|
|
200
|
+
if (error instanceof Error) {
|
|
201
|
+
return {
|
|
202
|
+
type: error.name,
|
|
203
|
+
message: error.message
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
return {
|
|
207
|
+
type: "Error",
|
|
208
|
+
message: String(error)
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// src/judges/judgeHarness.ts
|
|
213
|
+
function createJudgeHarness(options) {
|
|
214
|
+
return createHarness({
|
|
215
|
+
name: options.name ?? "judge-harness",
|
|
216
|
+
run: async ({ input, signal, metadata }) => {
|
|
217
|
+
return normalizeJudgeHarnessResult(
|
|
218
|
+
await options.run(input, { signal, metadata })
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
async function runJudgeHarness(judgeHarness, input, options = {}) {
|
|
224
|
+
const artifacts = {};
|
|
225
|
+
const run = await judgeHarness.run(input, {
|
|
226
|
+
metadata: options.metadata ?? {},
|
|
227
|
+
signal: options.signal,
|
|
228
|
+
artifacts,
|
|
229
|
+
setArtifact: (name, value) => {
|
|
230
|
+
artifacts[name] = value;
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
return run.output !== void 0 ? run.output : resolveJudgeHarnessAssistantOutput(run);
|
|
234
|
+
}
|
|
235
|
+
function createRunJudge(judgeHarness, signal) {
|
|
236
|
+
if (!judgeHarness) {
|
|
237
|
+
return void 0;
|
|
238
|
+
}
|
|
239
|
+
return (input, options) => runJudgeHarness(judgeHarness, input, {
|
|
240
|
+
metadata: options?.metadata,
|
|
241
|
+
signal
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
function normalizeJudgeHarnessResult(result) {
|
|
245
|
+
if (isHarnessRun(result)) {
|
|
246
|
+
return result;
|
|
247
|
+
}
|
|
248
|
+
if (hasOutputField(result)) {
|
|
249
|
+
return {
|
|
250
|
+
output: normalizeJudgeHarnessOutput(result.output)
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
return {
|
|
254
|
+
output: normalizeJudgeHarnessOutput(result)
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
function hasOutputField(value) {
|
|
258
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length === 1 && "output" in value;
|
|
259
|
+
}
|
|
260
|
+
function normalizeJudgeHarnessOutput(value) {
|
|
261
|
+
if (value === void 0) {
|
|
262
|
+
return void 0;
|
|
263
|
+
}
|
|
264
|
+
return normalizeContent(value);
|
|
265
|
+
}
|
|
266
|
+
function resolveJudgeHarnessAssistantOutput(run) {
|
|
267
|
+
return latestAssistantMessageContent(run.session) ?? "";
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// src/judges/factualityJudge.ts
|
|
271
|
+
var FACTUALITY_CHOICE_SCORES = {
|
|
272
|
+
A: 0.4,
|
|
273
|
+
B: 0.6,
|
|
274
|
+
C: 1,
|
|
275
|
+
D: 0,
|
|
276
|
+
E: 1
|
|
277
|
+
};
|
|
278
|
+
var FACTUALITY_SYSTEM = "You are comparing factual content. Ignore differences in style, grammar, punctuation, and formatting.";
|
|
279
|
+
var FACTUALITY_RESPONSE_SCHEMA = {
|
|
280
|
+
type: "object",
|
|
281
|
+
additionalProperties: false,
|
|
282
|
+
required: ["choice", "rationale"],
|
|
283
|
+
properties: {
|
|
284
|
+
choice: {
|
|
285
|
+
enum: ["A", "B", "C", "D", "E"]
|
|
286
|
+
},
|
|
287
|
+
rationale: {
|
|
288
|
+
type: "string"
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
function FactualityJudge(config = {}) {
|
|
293
|
+
const judgeHarness = config.judgeHarness;
|
|
294
|
+
return {
|
|
295
|
+
name: config.name ?? "FactualityJudge",
|
|
296
|
+
judgeHarness,
|
|
297
|
+
assess: (opts) => assessFactuality(opts, judgeHarness)
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
async function assessFactuality(opts, configuredJudgeHarness) {
|
|
301
|
+
const metadata = opts.metadata;
|
|
302
|
+
const expected = opts.expected === void 0 ? metadata.expected : opts.expected;
|
|
303
|
+
if (isMissingExpectedAnswer(expected)) {
|
|
304
|
+
return {
|
|
305
|
+
score: 0,
|
|
306
|
+
metadata: {
|
|
307
|
+
rationale: "FactualityJudge requires a non-empty expert answer in `expected` or `metadata.expected`."
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
const runJudge = opts.runJudge ?? createRunJudge(
|
|
312
|
+
configuredJudgeHarness,
|
|
313
|
+
opts.signal
|
|
314
|
+
);
|
|
315
|
+
if (!runJudge) {
|
|
316
|
+
throw new Error(
|
|
317
|
+
"FactualityJudge requires a judgeHarness in FactualityJudge(...) config, describeEval(...) options, toSatisfyJudge(...) options, or JudgeContext.runJudge."
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
const verdict = await runJudge({
|
|
321
|
+
system: FACTUALITY_SYSTEM,
|
|
322
|
+
prompt: formatFactualityPrompt({
|
|
323
|
+
input: opts.input,
|
|
324
|
+
expected,
|
|
325
|
+
output: resolveJudgeOutput(opts)
|
|
326
|
+
}),
|
|
327
|
+
responseFormat: {
|
|
328
|
+
type: "json",
|
|
329
|
+
schema: FACTUALITY_RESPONSE_SCHEMA
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
return formatJudgeResult(parseFactualityJudgeVerdict(verdict));
|
|
333
|
+
}
|
|
334
|
+
function isMissingExpectedAnswer(value) {
|
|
335
|
+
return value == null || typeof value === "string" && value.trim().length === 0;
|
|
336
|
+
}
|
|
337
|
+
function resolveJudgeOutput(opts) {
|
|
338
|
+
if (opts.output !== void 0) {
|
|
339
|
+
return opts.output;
|
|
340
|
+
}
|
|
341
|
+
return latestAssistantMessageContent(opts.session) ?? "";
|
|
342
|
+
}
|
|
343
|
+
function parseFactualityJudgeVerdict(value) {
|
|
344
|
+
const parsed = typeof value === "string" ? parseJsonObject(value) : value;
|
|
345
|
+
if (!parsed || typeof parsed !== "object") {
|
|
346
|
+
throw new Error(
|
|
347
|
+
"FactualityJudge judgeHarness must return an object with `choice` and `rationale`."
|
|
348
|
+
);
|
|
349
|
+
}
|
|
350
|
+
const verdict = parsed;
|
|
351
|
+
if (!isFactualityChoice(verdict.choice)) {
|
|
352
|
+
throw new Error(
|
|
353
|
+
"FactualityJudge judgeHarness must return choice A, B, C, D, or E."
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
if (typeof verdict.rationale !== "string") {
|
|
357
|
+
throw new Error(
|
|
358
|
+
"FactualityJudge judgeHarness must return a string `rationale`."
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
return {
|
|
362
|
+
choice: verdict.choice,
|
|
363
|
+
rationale: verdict.rationale
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
function parseJsonObject(value) {
|
|
367
|
+
try {
|
|
368
|
+
return JSON.parse(value);
|
|
369
|
+
} catch {
|
|
370
|
+
const fencedJson = value.match(/```(?:json)?\s*([\s\S]*?)\s*```/i);
|
|
371
|
+
if (!fencedJson) {
|
|
372
|
+
throw new Error(
|
|
373
|
+
"FactualityJudge judgeHarness must return JSON with `choice` and `rationale`."
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
return JSON.parse(fencedJson[1]);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
function isFactualityChoice(value) {
|
|
380
|
+
return value === "A" || value === "B" || value === "C" || value === "D" || value === "E";
|
|
381
|
+
}
|
|
382
|
+
function formatFactualityPrompt({
|
|
383
|
+
input,
|
|
384
|
+
expected,
|
|
385
|
+
output
|
|
386
|
+
}) {
|
|
387
|
+
const comparison = formatJudgeValue({
|
|
388
|
+
question: input ?? "",
|
|
389
|
+
expert_answer: expected,
|
|
390
|
+
submitted_answer: output ?? ""
|
|
391
|
+
});
|
|
392
|
+
return `Compare the submitted answer with the expert answer.
|
|
393
|
+
|
|
394
|
+
Comparison payload:
|
|
395
|
+
${comparison}
|
|
396
|
+
|
|
397
|
+
Select exactly one option:
|
|
398
|
+
A: The submission is a fully consistent subset of the expert answer.
|
|
399
|
+
B: The submission is a fully consistent superset of the expert answer.
|
|
400
|
+
C: The submission contains the same factual details as the expert answer.
|
|
401
|
+
D: The submission disagrees with the expert answer.
|
|
402
|
+
E: The answers differ only in ways that do not affect factuality.
|
|
403
|
+
|
|
404
|
+
Return JSON with exactly these fields:
|
|
405
|
+
{
|
|
406
|
+
"choice": "C",
|
|
407
|
+
"rationale": "Brief explanation for the selected choice"
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
The choice value must be one of A, B, C, D, or E.`;
|
|
411
|
+
}
|
|
412
|
+
function formatJudgeValue(value) {
|
|
413
|
+
if (typeof value === "string") {
|
|
414
|
+
return value;
|
|
415
|
+
}
|
|
416
|
+
if (value === void 0) {
|
|
417
|
+
return "";
|
|
418
|
+
}
|
|
419
|
+
try {
|
|
420
|
+
return JSON.stringify(value, null, 2) ?? String(value);
|
|
421
|
+
} catch {
|
|
422
|
+
return String(value);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
function formatJudgeResult(object) {
|
|
426
|
+
return {
|
|
427
|
+
score: FACTUALITY_CHOICE_SCORES[object.choice],
|
|
428
|
+
metadata: {
|
|
429
|
+
rationale: object.rationale,
|
|
430
|
+
choice: object.choice
|
|
431
|
+
}
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
|
|
1
435
|
// src/internal/matchers.ts
|
|
2
436
|
function isRecord(value) {
|
|
3
437
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -375,8 +809,8 @@ function evaluateOrderedTools(expected, actual, options) {
|
|
|
375
809
|
score: expectedIndex / expected.length,
|
|
376
810
|
metadata: {
|
|
377
811
|
rationale: `Tool '${expectedTool.name}' called with incorrect arguments at position ${expectedIndex + 1} (${expectedIndex}/${expected.length} tools matched correctly)`,
|
|
378
|
-
expected: expectedTool.arguments,
|
|
379
|
-
actual: actualTool.arguments,
|
|
812
|
+
expected: normalizeContent(expectedTool.arguments),
|
|
813
|
+
actual: actualTool.arguments === void 0 ? void 0 : normalizeContent(actualTool.arguments),
|
|
380
814
|
matched: expectedIndex,
|
|
381
815
|
total: expected.length
|
|
382
816
|
}
|
|
@@ -508,8 +942,8 @@ function ToolCallJudge(config = {}) {
|
|
|
508
942
|
const metadata = opts.metadata;
|
|
509
943
|
return scorer({
|
|
510
944
|
...opts,
|
|
511
|
-
input:
|
|
512
|
-
output:
|
|
945
|
+
input: formatJudgeValue2(opts.input),
|
|
946
|
+
output: formatJudgeValue2(opts.output),
|
|
513
947
|
expectedTools: normalizeExpectedTools(
|
|
514
948
|
opts.expectedTools ?? metadata.expectedTools
|
|
515
949
|
)
|
|
@@ -522,7 +956,7 @@ function normalizeExpectedTools(expectedTools) {
|
|
|
522
956
|
(tool) => typeof tool === "string" ? { name: tool } : tool
|
|
523
957
|
);
|
|
524
958
|
}
|
|
525
|
-
function
|
|
959
|
+
function formatJudgeValue2(value) {
|
|
526
960
|
if (typeof value === "string") {
|
|
527
961
|
return value;
|
|
528
962
|
}
|
|
@@ -536,7 +970,10 @@ function formatJudgeValue(value) {
|
|
|
536
970
|
return "";
|
|
537
971
|
}
|
|
538
972
|
export {
|
|
973
|
+
FactualityJudge,
|
|
539
974
|
StructuredOutputJudge,
|
|
540
|
-
ToolCallJudge
|
|
975
|
+
ToolCallJudge,
|
|
976
|
+
createJudgeHarness,
|
|
977
|
+
runJudgeHarness
|
|
541
978
|
};
|
|
542
979
|
//# sourceMappingURL=index.mjs.map
|