@cogitator-ai/evals 0.13.2 → 0.14.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 +94 -14
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/plugin-evals/execute.d.ts +45 -0
- package/dist/plugin-evals/execute.d.ts.map +1 -0
- package/dist/plugin-evals/execute.js +508 -0
- package/dist/plugin-evals/execute.js.map +1 -0
- package/dist/plugin-evals/files.d.ts +17 -0
- package/dist/plugin-evals/files.d.ts.map +1 -0
- package/dist/plugin-evals/files.js +46 -0
- package/dist/plugin-evals/files.js.map +1 -0
- package/dist/plugin-evals/glob.d.ts +8 -0
- package/dist/plugin-evals/glob.d.ts.map +1 -0
- package/dist/plugin-evals/glob.js +63 -0
- package/dist/plugin-evals/glob.js.map +1 -0
- package/dist/plugin-evals/graders.d.ts +21 -0
- package/dist/plugin-evals/graders.d.ts.map +1 -0
- package/dist/plugin-evals/graders.js +198 -0
- package/dist/plugin-evals/graders.js.map +1 -0
- package/dist/plugin-evals/index.d.ts +4 -0
- package/dist/plugin-evals/index.d.ts.map +1 -0
- package/dist/plugin-evals/index.js +3 -0
- package/dist/plugin-evals/index.js.map +1 -0
- package/dist/plugin-evals/judge.d.ts +33 -0
- package/dist/plugin-evals/judge.d.ts.map +1 -0
- package/dist/plugin-evals/judge.js +73 -0
- package/dist/plugin-evals/judge.js.map +1 -0
- package/dist/plugin-evals/mocks.d.ts +34 -0
- package/dist/plugin-evals/mocks.d.ts.map +1 -0
- package/dist/plugin-evals/mocks.js +373 -0
- package/dist/plugin-evals/mocks.js.map +1 -0
- package/dist/plugin-evals/report.d.ts +4 -0
- package/dist/plugin-evals/report.d.ts.map +1 -0
- package/dist/plugin-evals/report.js +177 -0
- package/dist/plugin-evals/report.js.map +1 -0
- package/dist/plugin-evals/runner.d.ts +23 -0
- package/dist/plugin-evals/runner.d.ts.map +1 -0
- package/dist/plugin-evals/runner.js +582 -0
- package/dist/plugin-evals/runner.js.map +1 -0
- package/dist/plugin-evals/schema.d.ts +179 -0
- package/dist/plugin-evals/schema.d.ts.map +1 -0
- package/dist/plugin-evals/schema.js +194 -0
- package/dist/plugin-evals/schema.js.map +1 -0
- package/dist/plugin-evals/suite.d.ts +40 -0
- package/dist/plugin-evals/suite.d.ts.map +1 -0
- package/dist/plugin-evals/suite.js +476 -0
- package/dist/plugin-evals/suite.js.map +1 -0
- package/dist/plugin-evals/tools.d.ts +42 -0
- package/dist/plugin-evals/tools.d.ts.map +1 -0
- package/dist/plugin-evals/tools.js +136 -0
- package/dist/plugin-evals/tools.js.map +1 -0
- package/dist/plugin-evals/transcript.d.ts +35 -0
- package/dist/plugin-evals/transcript.d.ts.map +1 -0
- package/dist/plugin-evals/transcript.js +149 -0
- package/dist/plugin-evals/transcript.js.map +1 -0
- package/dist/plugin-evals/types.d.ts +378 -0
- package/dist/plugin-evals/types.d.ts.map +1 -0
- package/dist/plugin-evals/types.js +2 -0
- package/dist/plugin-evals/types.js.map +1 -0
- package/dist/reporters/html-format.d.ts +5 -2
- package/dist/reporters/html-format.d.ts.map +1 -1
- package/dist/reporters/html-format.js +6 -3
- package/dist/reporters/html-format.js.map +1 -1
- package/package.json +5 -3
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
const SPECIAL = /[\\^$.*+?()[\]{}|/]/;
|
|
2
|
+
/**
|
|
3
|
+
* A glob as a regular expression over a whole string: `*` matches within a path segment, `**`
|
|
4
|
+
* across segments, `?` one character, `[...]` a class and `{a,b}` alternatives
|
|
5
|
+
*/
|
|
6
|
+
export function globToRegExp(glob) {
|
|
7
|
+
let source = '';
|
|
8
|
+
let depth = 0;
|
|
9
|
+
for (let at = 0; at < glob.length; at++) {
|
|
10
|
+
const char = glob[at];
|
|
11
|
+
if (char === '*') {
|
|
12
|
+
if (glob[at + 1] === '*') {
|
|
13
|
+
at++;
|
|
14
|
+
if (glob[at + 1] === '/') {
|
|
15
|
+
at++;
|
|
16
|
+
source += '(?:.*/)?';
|
|
17
|
+
}
|
|
18
|
+
else
|
|
19
|
+
source += '.*';
|
|
20
|
+
}
|
|
21
|
+
else
|
|
22
|
+
source += '[^/]*';
|
|
23
|
+
}
|
|
24
|
+
else if (char === '?')
|
|
25
|
+
source += '[^/]';
|
|
26
|
+
else if (char === '[') {
|
|
27
|
+
const end = glob.indexOf(']', at + 2);
|
|
28
|
+
if (end === -1)
|
|
29
|
+
source += '\\[';
|
|
30
|
+
else {
|
|
31
|
+
const body = glob.slice(at + 1, end).replace(/\\/g, '\\\\');
|
|
32
|
+
source += `[${body.startsWith('!') ? `^${body.slice(1)}` : body}]`;
|
|
33
|
+
at = end;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
else if (char === '{') {
|
|
37
|
+
depth++;
|
|
38
|
+
source += '(?:';
|
|
39
|
+
}
|
|
40
|
+
else if (char === '}' && depth > 0) {
|
|
41
|
+
depth--;
|
|
42
|
+
source += ')';
|
|
43
|
+
}
|
|
44
|
+
else if (char === ',' && depth > 0)
|
|
45
|
+
source += '|';
|
|
46
|
+
else if (char === '\\' && at + 1 < glob.length) {
|
|
47
|
+
at++;
|
|
48
|
+
source += escapeChar(glob[at]);
|
|
49
|
+
}
|
|
50
|
+
else
|
|
51
|
+
source += escapeChar(char);
|
|
52
|
+
}
|
|
53
|
+
source += ')'.repeat(depth);
|
|
54
|
+
return new RegExp(`^${source}$`);
|
|
55
|
+
}
|
|
56
|
+
function escapeChar(char) {
|
|
57
|
+
return SPECIAL.test(char) ? `\\${char}` : char;
|
|
58
|
+
}
|
|
59
|
+
/** Whether `value` matches `glob` as a whole */
|
|
60
|
+
export function globMatches(glob, value) {
|
|
61
|
+
return globToRegExp(glob).test(value);
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=glob.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"glob.js","sourceRoot":"","sources":["../../src/plugin-evals/glob.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,GAAG,qBAAqB,CAAC;AAEtC;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC;QACxC,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC;QACtB,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACjB,IAAI,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;gBACzB,EAAE,EAAE,CAAC;gBACL,IAAI,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;oBACzB,EAAE,EAAE,CAAC;oBACL,MAAM,IAAI,UAAU,CAAC;gBACvB,CAAC;;oBAAM,MAAM,IAAI,IAAI,CAAC;YACxB,CAAC;;gBAAM,MAAM,IAAI,OAAO,CAAC;QAC3B,CAAC;aAAM,IAAI,IAAI,KAAK,GAAG;YAAE,MAAM,IAAI,MAAM,CAAC;aACrC,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACtB,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC;YACtC,IAAI,GAAG,KAAK,CAAC,CAAC;gBAAE,MAAM,IAAI,KAAK,CAAC;iBAC3B,CAAC;gBACJ,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;gBAC5D,MAAM,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;gBACnE,EAAE,GAAG,GAAG,CAAC;YACX,CAAC;QACH,CAAC;aAAM,IAAI,IAAI,KAAK,GAAG,EAAE,CAAC;YACxB,KAAK,EAAE,CAAC;YACR,MAAM,IAAI,KAAK,CAAC;QAClB,CAAC;aAAM,IAAI,IAAI,KAAK,GAAG,IAAI,KAAK,GAAG,CAAC,EAAE,CAAC;YACrC,KAAK,EAAE,CAAC;YACR,MAAM,IAAI,GAAG,CAAC;QAChB,CAAC;aAAM,IAAI,IAAI,KAAK,GAAG,IAAI,KAAK,GAAG,CAAC;YAAE,MAAM,IAAI,GAAG,CAAC;aAC/C,IAAI,IAAI,KAAK,IAAI,IAAI,EAAE,GAAG,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;YAC/C,EAAE,EAAE,CAAC;YACL,MAAM,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;QACjC,CAAC;;YAAM,MAAM,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5B,OAAO,IAAI,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,UAAU,CAAC,IAAY;IAC9B,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AACjD,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,KAAa;IACrD,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACxC,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { type PluginEvalJudge } from './judge.js';
|
|
2
|
+
import { type TranscriptEntry } from './transcript.js';
|
|
3
|
+
import type { PluginEvalGrader, PluginEvalGraderResult, PluginEvalMockCall, PluginEvalToolCall } from './types.js';
|
|
4
|
+
/** What one run left for its graders */
|
|
5
|
+
export interface RunCapture {
|
|
6
|
+
prompt: string;
|
|
7
|
+
lastMessage: string;
|
|
8
|
+
entries: TranscriptEntry[];
|
|
9
|
+
toolCalls: PluginEvalToolCall[];
|
|
10
|
+
mockCalls: PluginEvalMockCall[];
|
|
11
|
+
filesCreated: string[];
|
|
12
|
+
workspaceRoot: string;
|
|
13
|
+
caseDir: string;
|
|
14
|
+
}
|
|
15
|
+
type Verdict = Pick<PluginEvalGraderResult, 'passed' | 'explanation'> & Partial<Pick<PluginEvalGraderResult, 'votes' | 'evidence' | 'costUsd'>>;
|
|
16
|
+
/** Whether a grader calls the judge, and so costs something */
|
|
17
|
+
export declare function isPaidGrader(grader: PluginEvalGrader): boolean;
|
|
18
|
+
/** Applies one grader to a run */
|
|
19
|
+
export declare function grade(grader: PluginEvalGrader, capture: RunCapture, judge: PluginEvalJudge, signal?: AbortSignal): Promise<Verdict>;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=graders.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graders.d.ts","sourceRoot":"","sources":["../../src/plugin-evals/graders.ts"],"names":[],"mappings":"AAIA,OAAO,EAAe,KAAK,eAAe,EAAE,MAAM,SAAS,CAAC;AAE5D,OAAO,EAIL,KAAK,eAAe,EACrB,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EACV,gBAAgB,EAChB,sBAAsB,EACtB,kBAAkB,EAElB,kBAAkB,EAGnB,MAAM,SAAS,CAAC;AAEjB,wCAAwC;AACxC,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,SAAS,EAAE,kBAAkB,EAAE,CAAC;IAChC,SAAS,EAAE,kBAAkB,EAAE,CAAC;IAChC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAsED,KAAK,OAAO,GAAG,IAAI,CAAC,sBAAsB,EAAE,QAAQ,GAAG,aAAa,CAAC,GACnE,OAAO,CAAC,IAAI,CAAC,sBAAsB,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,CAAC,CAAC,CAAC;AAE1E,+DAA+D;AAC/D,wBAAgB,YAAY,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAE9D;AAED,kCAAkC;AAClC,wBAAsB,KAAK,CACzB,MAAM,EAAE,gBAAgB,EACxB,OAAO,EAAE,UAAU,EACnB,KAAK,EAAE,eAAe,EACtB,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,OAAO,CAAC,CA8HlB"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { join, resolve } from 'node:path';
|
|
3
|
+
import { isFile, isInside } from './files.js';
|
|
4
|
+
import { globMatches } from './glob.js';
|
|
5
|
+
import { JUDGE_VOTES } from './judge.js';
|
|
6
|
+
import { namesCall } from './tools.js';
|
|
7
|
+
import { parseTranscript, readableTranscript, traceLines, } from './transcript.js';
|
|
8
|
+
/** How many messages of a trace an `llm` judge sees from its start and from its end */
|
|
9
|
+
const JUDGED_TRACE_ENDS = 12;
|
|
10
|
+
const BINARY_SNIFF = 8192;
|
|
11
|
+
function targetLabel(target) {
|
|
12
|
+
return typeof target === 'string' ? target : `file ${target.path}`;
|
|
13
|
+
}
|
|
14
|
+
function contentOf(target, capture, forJudge) {
|
|
15
|
+
if (typeof target === 'object') {
|
|
16
|
+
const path = resolve(capture.workspaceRoot, target.path);
|
|
17
|
+
if (!isInside(capture.workspaceRoot, path) || !isFile(path)) {
|
|
18
|
+
return { missing: `the file ${target.path} does not exist in the workspace` };
|
|
19
|
+
}
|
|
20
|
+
const bytes = readFileSync(path);
|
|
21
|
+
const binary = bytes.subarray(0, BINARY_SNIFF).includes(0);
|
|
22
|
+
return { text: bytes.toString('utf8'), ...(binary && { binary: true }) };
|
|
23
|
+
}
|
|
24
|
+
switch (target) {
|
|
25
|
+
case 'last_message':
|
|
26
|
+
return { text: capture.lastMessage };
|
|
27
|
+
case 'files':
|
|
28
|
+
return { text: capture.filesCreated.join('\n') };
|
|
29
|
+
case 'mock_calls':
|
|
30
|
+
return { text: capture.mockCalls.map((call) => JSON.stringify(call)).join('\n') };
|
|
31
|
+
case 'trace': {
|
|
32
|
+
const lines = traceLines(capture.entries);
|
|
33
|
+
if (!forJudge || lines.length <= JUDGED_TRACE_ENDS * 2)
|
|
34
|
+
return { text: lines.join('\n') };
|
|
35
|
+
const left = lines.length - JUDGED_TRACE_ENDS * 2;
|
|
36
|
+
return {
|
|
37
|
+
text: [
|
|
38
|
+
...lines.slice(0, JUDGED_TRACE_ENDS),
|
|
39
|
+
`... ${left} message${left === 1 ? '' : 's'} left out ...`,
|
|
40
|
+
...lines.slice(-JUDGED_TRACE_ENDS),
|
|
41
|
+
].join('\n'),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function excerpt(text, at, length) {
|
|
47
|
+
const start = Math.max(0, at - 30);
|
|
48
|
+
const snippet = text.slice(start, at + Math.max(length, 1) + 30).replace(/\s+/g, ' ');
|
|
49
|
+
return `${start > 0 ? '...' : ''}${snippet}${at + length + 30 < text.length ? '...' : ''}`;
|
|
50
|
+
}
|
|
51
|
+
function matchesInput(call, inputMatch) {
|
|
52
|
+
return inputMatch === undefined || new RegExp(inputMatch).test(JSON.stringify(call.input));
|
|
53
|
+
}
|
|
54
|
+
function firstIndex(calls, matcher) {
|
|
55
|
+
return calls.findIndex((call) => namesCall(matcher.tool, call) && matchesInput(call, matcher.inputMatch));
|
|
56
|
+
}
|
|
57
|
+
function matcherText(matcher) {
|
|
58
|
+
return matcher.inputMatch === undefined
|
|
59
|
+
? matcher.tool
|
|
60
|
+
: `${matcher.tool} /${matcher.inputMatch}/`;
|
|
61
|
+
}
|
|
62
|
+
function plural(count, word) {
|
|
63
|
+
return `${count} ${word}${count === 1 ? '' : 's'}`;
|
|
64
|
+
}
|
|
65
|
+
/** Whether a grader calls the judge, and so costs something */
|
|
66
|
+
export function isPaidGrader(grader) {
|
|
67
|
+
return grader.type === 'llm' || grader.type === 'baseline';
|
|
68
|
+
}
|
|
69
|
+
/** Applies one grader to a run */
|
|
70
|
+
export async function grade(grader, capture, judge, signal) {
|
|
71
|
+
switch (grader.type) {
|
|
72
|
+
case 'regex': {
|
|
73
|
+
const content = contentOf(grader.target, capture, false);
|
|
74
|
+
if ('missing' in content) {
|
|
75
|
+
return grader.match === 'not_contains'
|
|
76
|
+
? {
|
|
77
|
+
passed: true,
|
|
78
|
+
explanation: `${content.missing}, so it does not contain /${grader.pattern}/`,
|
|
79
|
+
}
|
|
80
|
+
: { passed: false, explanation: content.missing };
|
|
81
|
+
}
|
|
82
|
+
const where = targetLabel(grader.target);
|
|
83
|
+
if (grader.match.startsWith('count:')) {
|
|
84
|
+
const wanted = Number(grader.match.slice('count:'.length));
|
|
85
|
+
const count = [...content.text.matchAll(new RegExp(grader.pattern, `${grader.flags}g`))]
|
|
86
|
+
.length;
|
|
87
|
+
return {
|
|
88
|
+
passed: count === wanted,
|
|
89
|
+
explanation: `/${grader.pattern}/${grader.flags} matched ${plural(count, 'time')} in ${where}, ${wanted} wanted`,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
const found = new RegExp(grader.pattern, grader.flags).exec(content.text);
|
|
93
|
+
const contains = grader.match === 'contains';
|
|
94
|
+
if (found) {
|
|
95
|
+
return {
|
|
96
|
+
passed: contains,
|
|
97
|
+
explanation: `/${grader.pattern}/${grader.flags} found in ${where}: "${excerpt(content.text, found.index, found[0].length)}"`,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
passed: !contains,
|
|
102
|
+
explanation: `/${grader.pattern}/${grader.flags} not found in ${where}`,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
case 'tool_used': {
|
|
106
|
+
const count = capture.toolCalls.filter((call) => namesCall(grader.tool, call) && matchesInput(call, grader.inputMatch)).length;
|
|
107
|
+
const passed = count >= grader.min && (grader.max === undefined || count <= grader.max);
|
|
108
|
+
const bounds = grader.max === undefined
|
|
109
|
+
? `at least ${grader.min}`
|
|
110
|
+
: grader.min === grader.max
|
|
111
|
+
? `exactly ${grader.min}`
|
|
112
|
+
: `${grader.min} to ${grader.max}`;
|
|
113
|
+
const filter = grader.inputMatch === undefined ? '' : ` with input matching /${grader.inputMatch}/`;
|
|
114
|
+
return {
|
|
115
|
+
passed,
|
|
116
|
+
explanation: `${grader.tool} called ${plural(count, 'time')}${filter}, ${bounds} wanted`,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
case 'tool_order': {
|
|
120
|
+
const before = firstIndex(capture.toolCalls, grader.before);
|
|
121
|
+
const after = firstIndex(capture.toolCalls, grader.after);
|
|
122
|
+
if (before === -1)
|
|
123
|
+
return { passed: false, explanation: `${matcherText(grader.before)} was not called` };
|
|
124
|
+
if (after === -1)
|
|
125
|
+
return { passed: false, explanation: `${matcherText(grader.after)} was not called` };
|
|
126
|
+
return {
|
|
127
|
+
passed: before < after,
|
|
128
|
+
explanation: `${matcherText(grader.before)} first at call ${before + 1}, ${matcherText(grader.after)} first at call ${after + 1}`,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
case 'file_exists': {
|
|
132
|
+
const matching = capture.filesCreated.filter((path) => globMatches(grader.path, path));
|
|
133
|
+
if (grader.exists) {
|
|
134
|
+
return matching.length > 0
|
|
135
|
+
? { passed: true, explanation: `created ${matching.slice(0, 5).join(', ')}` }
|
|
136
|
+
: { passed: false, explanation: `no file created during the run matches ${grader.path}` };
|
|
137
|
+
}
|
|
138
|
+
return matching.length === 0
|
|
139
|
+
? { passed: true, explanation: `no file created during the run matches ${grader.path}` }
|
|
140
|
+
: { passed: false, explanation: `created ${matching.slice(0, 5).join(', ')}, none wanted` };
|
|
141
|
+
}
|
|
142
|
+
case 'llm': {
|
|
143
|
+
const content = contentOf(grader.focus, capture, true);
|
|
144
|
+
if ('missing' in content)
|
|
145
|
+
return { passed: false, explanation: content.missing };
|
|
146
|
+
if (content.binary) {
|
|
147
|
+
return {
|
|
148
|
+
passed: false,
|
|
149
|
+
explanation: `${targetLabel(grader.focus)} is a binary file, which the judge cannot read: write it out as text and grade that`,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
const answer = await judge.ask({
|
|
153
|
+
kind: 'llm',
|
|
154
|
+
criteria: grader.criteria,
|
|
155
|
+
evidence: content.text,
|
|
156
|
+
prompt: capture.prompt,
|
|
157
|
+
}, signal);
|
|
158
|
+
return {
|
|
159
|
+
...tally(answer.votes),
|
|
160
|
+
votes: answer.votes,
|
|
161
|
+
evidence: content.text,
|
|
162
|
+
costUsd: answer.costUsd,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
case 'baseline': {
|
|
166
|
+
const file = join(capture.caseDir, grader.baselineFile);
|
|
167
|
+
const reference = parseTranscript(readFileSync(file, 'utf8'));
|
|
168
|
+
if ('error' in reference) {
|
|
169
|
+
return { passed: false, explanation: `${grader.baselineFile}: ${reference.error}` };
|
|
170
|
+
}
|
|
171
|
+
const run = readableTranscript(capture.entries);
|
|
172
|
+
const answer = await judge.ask({
|
|
173
|
+
kind: 'baseline',
|
|
174
|
+
criteria: grader.criteria,
|
|
175
|
+
reference: readableTranscript(reference),
|
|
176
|
+
run,
|
|
177
|
+
prompt: capture.prompt,
|
|
178
|
+
}, signal);
|
|
179
|
+
return {
|
|
180
|
+
...tally(answer.votes),
|
|
181
|
+
votes: answer.votes,
|
|
182
|
+
evidence: run,
|
|
183
|
+
costUsd: answer.costUsd,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
function tally(votes) {
|
|
189
|
+
const pass = votes.filter((vote) => vote.verdict === 'PASS').length;
|
|
190
|
+
const passed = pass * 2 > JUDGE_VOTES;
|
|
191
|
+
const deciding = votes.find((vote) => (vote.verdict === 'PASS') === passed && vote.reasoning);
|
|
192
|
+
const reason = deciding?.reasoning ?? votes.find((vote) => vote.reasoning)?.reasoning;
|
|
193
|
+
return {
|
|
194
|
+
passed,
|
|
195
|
+
explanation: `${pass} of ${votes.length} votes PASS${reason ? `: ${reason}` : ''}`,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
//# sourceMappingURL=graders.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graders.js","sourceRoot":"","sources":["../../src/plugin-evals/graders.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { experimental_runPluginEvals } from './runner.js';
|
|
2
|
+
export { PluginEvalError } from './suite.js';
|
|
3
|
+
export type { PluginEvalAblation, PluginEvalAbort, PluginEvalArm, PluginEvalBaselineGrader, PluginEvalCaseAggregates, PluginEvalCaseResult, PluginEvalExpectation, PluginEvalExpectType, PluginEvalFileExistsGrader, PluginEvalGrader, PluginEvalGraderResult, PluginEvalLlmGrader, PluginEvalMockCall, PluginEvalOptions, PluginEvalOutcome, PluginEvalPartialReason, PluginEvalProgressEvent, PluginEvalRegexGrader, PluginEvalReport, PluginEvalResult, PluginEvalRunResult, PluginEvalTarget, PluginEvalToolCall, PluginEvalToolMatcher, PluginEvalToolOrderGrader, PluginEvalToolUsedGrader, PluginEvalVote, } from './types.js';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/plugin-evals/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAC1C,YAAY,EACV,kBAAkB,EAClB,eAAe,EACf,aAAa,EACb,wBAAwB,EACxB,wBAAwB,EACxB,oBAAoB,EACpB,qBAAqB,EACrB,oBAAoB,EACpB,0BAA0B,EAC1B,gBAAgB,EAChB,sBAAsB,EACtB,mBAAmB,EACnB,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,uBAAuB,EACvB,uBAAuB,EACvB,qBAAqB,EACrB,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EACnB,gBAAgB,EAChB,kBAAkB,EAClB,qBAAqB,EACrB,yBAAyB,EACzB,wBAAwB,EACxB,cAAc,GACf,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/plugin-evals/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type JudgeCogitator } from '../schema.js';
|
|
2
|
+
import type { PluginEvalVote } from './types.js';
|
|
3
|
+
/** Votes per `llm` or `baseline` grader: the grader passes on a majority of PASS votes */
|
|
4
|
+
export declare const JUDGE_VOTES = 3;
|
|
5
|
+
/** What a judge grader asks */
|
|
6
|
+
export type JudgeQuestion = {
|
|
7
|
+
kind: 'llm';
|
|
8
|
+
criteria: string;
|
|
9
|
+
evidence: string;
|
|
10
|
+
prompt: string;
|
|
11
|
+
} | {
|
|
12
|
+
kind: 'baseline';
|
|
13
|
+
criteria: string;
|
|
14
|
+
reference: string;
|
|
15
|
+
run: string;
|
|
16
|
+
prompt: string;
|
|
17
|
+
};
|
|
18
|
+
/** The judge's answer: every vote and what the votes cost */
|
|
19
|
+
export interface JudgeAnswer {
|
|
20
|
+
votes: PluginEvalVote[];
|
|
21
|
+
costUsd: number;
|
|
22
|
+
}
|
|
23
|
+
/** Asks the judge model, three votes per question */
|
|
24
|
+
export interface PluginEvalJudge {
|
|
25
|
+
/** Asks `question`, its judge runs aborted with `signal` */
|
|
26
|
+
ask(question: JudgeQuestion, signal?: AbortSignal): Promise<JudgeAnswer>;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A judge on `model`, run by `cogitator`: each question is asked three times as a judge metric of
|
|
30
|
+
* this package, at temperature 1 so the votes are independent samples
|
|
31
|
+
*/
|
|
32
|
+
export declare function createPluginEvalJudge(cogitator: JudgeCogitator, model: string): PluginEvalJudge;
|
|
33
|
+
//# sourceMappingURL=judge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"judge.d.ts","sourceRoot":"","sources":["../../src/plugin-evals/judge.ts"],"names":[],"mappings":"AAQA,OAAO,EAAqB,KAAK,cAAc,EAAE,MAAM,WAAW,CAAC;AACnE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,0FAA0F;AAC1F,eAAO,MAAM,WAAW,IAAI,CAAC;AAE7B,+BAA+B;AAC/B,MAAM,MAAM,aAAa,GACrB;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACnE;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAE3F,6DAA6D;AAC7D,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qDAAqD;AACrD,MAAM,WAAW,eAAe;IAC9B,4DAA4D;IAC5D,GAAG,CAAC,QAAQ,EAAE,aAAa,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CAC1E;AAkDD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,GAAG,eAAe,CAqC/F"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { bindJudgeContext, createJudgeMetric, judgeContextFor, } from '../metrics/llm-judge.js';
|
|
2
|
+
import { tagged } from '../metrics/judge-prompt.js';
|
|
3
|
+
import { JudgeConfigSchema } from '../schema.js';
|
|
4
|
+
/** Votes per `llm` or `baseline` grader: the grader passes on a majority of PASS votes */
|
|
5
|
+
export const JUDGE_VOTES = 3;
|
|
6
|
+
const LLM_INSTRUCTIONS = `You grade one run of an AI agent against a rubric. Read the <rubric> and the <evidence> from the run (and the <task> the agent was given), then decide whether the evidence meets the rubric.
|
|
7
|
+
|
|
8
|
+
Respond with JSON: {"score": 1 for PASS or 0 for FAIL, "reasoning": "<one or two sentences>"}`;
|
|
9
|
+
const BASELINE_INSTRUCTIONS = `You compare one run of an AI agent with a reference run of the same <task>. Read the <criteria>, the <reference> transcript and the <run> transcript, then decide whether the run satisfies the criteria at least as well as the reference does.
|
|
10
|
+
|
|
11
|
+
Respond with JSON: {"score": 1 for PASS (at least as well) or 0 for FAIL (worse), "reasoning": "<one or two sentences>"}`;
|
|
12
|
+
function verdictScore(verdict) {
|
|
13
|
+
if (verdict.score === 1 || verdict.score === 0)
|
|
14
|
+
return { score: verdict.score };
|
|
15
|
+
return { error: `the judge gave ${verdict.score}, which is neither 1 (PASS) nor 0 (FAIL)` };
|
|
16
|
+
}
|
|
17
|
+
function messageOf(question) {
|
|
18
|
+
const task = tagged('task', question.prompt);
|
|
19
|
+
if (question.kind === 'llm') {
|
|
20
|
+
return `${task}\n${tagged('rubric', question.criteria)}\n${tagged('evidence', question.evidence)}`;
|
|
21
|
+
}
|
|
22
|
+
return `${task}\n${tagged('criteria', question.criteria)}\n${tagged('reference', question.reference)}\n${tagged('run', question.run)}`;
|
|
23
|
+
}
|
|
24
|
+
function votesOf(metadata, fallback) {
|
|
25
|
+
const samples = metadata?.samples;
|
|
26
|
+
if (!Array.isArray(samples))
|
|
27
|
+
return Array.from({ length: JUDGE_VOTES }, () => ({ verdict: 'ERROR', reasoning: fallback }));
|
|
28
|
+
return samples.map((sample) => {
|
|
29
|
+
if (typeof sample.score !== 'number') {
|
|
30
|
+
return {
|
|
31
|
+
verdict: 'ERROR',
|
|
32
|
+
reasoning: typeof sample.error === 'string' ? sample.error : fallback,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
verdict: sample.score === 1 ? 'PASS' : 'FAIL',
|
|
37
|
+
...(typeof sample.reasoning === 'string' && { reasoning: sample.reasoning }),
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* A judge on `model`, run by `cogitator`: each question is asked three times as a judge metric of
|
|
43
|
+
* this package, at temperature 1 so the votes are independent samples
|
|
44
|
+
*/
|
|
45
|
+
export function createPluginEvalJudge(cogitator, model) {
|
|
46
|
+
const context = judgeContextFor(cogitator, JudgeConfigSchema.parse({ model, temperature: 1, samples: JUDGE_VOTES }));
|
|
47
|
+
return {
|
|
48
|
+
async ask(question, signal) {
|
|
49
|
+
const message = messageOf(question);
|
|
50
|
+
const metric = createJudgeMetric(question.kind === 'llm' ? 'llm' : 'baseline', question.kind === 'llm' ? LLM_INSTRUCTIONS : BASELINE_INSTRUCTIONS, { message: () => ({ message }), score: verdictScore });
|
|
51
|
+
signal?.throwIfAborted();
|
|
52
|
+
const scoped = signal
|
|
53
|
+
? {
|
|
54
|
+
...context,
|
|
55
|
+
cogitator: {
|
|
56
|
+
run: (options) => context.cogitator.run({ ...options, signal }),
|
|
57
|
+
},
|
|
58
|
+
}
|
|
59
|
+
: context;
|
|
60
|
+
const scored = await bindJudgeContext(metric, scoped)({
|
|
61
|
+
case: { input: question.prompt },
|
|
62
|
+
output: '',
|
|
63
|
+
duration: 0,
|
|
64
|
+
});
|
|
65
|
+
signal?.throwIfAborted();
|
|
66
|
+
return {
|
|
67
|
+
votes: votesOf(scored.metadata, scored.error ?? scored.details ?? 'no verdict'),
|
|
68
|
+
costUsd: scored.usage?.cost ?? 0,
|
|
69
|
+
};
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=judge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"judge.js","sourceRoot":"","sources":["../../src/plugin-evals/judge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { PluginEvalAbort, PluginEvalMockTool } from './types.js';
|
|
2
|
+
/** Longest string value an `expect:` pattern checks: a longer one counts as a violation */
|
|
3
|
+
export declare const EXPECT_MAX_LENGTH = 4096;
|
|
4
|
+
/** The mocks of a case, and why the servers that cannot be used cannot, by server */
|
|
5
|
+
export interface CaseMocks {
|
|
6
|
+
mocks: Record<string, PluginEvalMockTool[]>;
|
|
7
|
+
problems: Record<string, string>;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* The mocked tools of a case: the suite's mocks with the case's own over them, file by file.
|
|
11
|
+
* A file of the case's own `mocks/` that cannot be used throws with the file and the reason, since
|
|
12
|
+
* the case asked for it. A suite file that cannot be used is reported in `problems` under its
|
|
13
|
+
* server, so it fails only the cases that use that server
|
|
14
|
+
*/
|
|
15
|
+
export declare function loadMocks(suiteDir: string | undefined, caseDir: string): CaseMocks;
|
|
16
|
+
/**
|
|
17
|
+
* Why `source` is outside the pattern dialect of `expect:` (literals, `.`, escapes, classes, the
|
|
18
|
+
* quantifiers `* + ? {m,n}` on one of those, an optional `^` and `$`), undefined when it is in it
|
|
19
|
+
*/
|
|
20
|
+
export declare function dialectProblem(source: string): string | undefined;
|
|
21
|
+
/** Why `input` violates the mock's `expect:` checks, undefined when it passes them */
|
|
22
|
+
export declare function expectViolation(mock: PluginEvalMockTool, input: Record<string, unknown>): string | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* The mock's answer to `input`: its body with `{{input.<field>}}` replaced by the field and
|
|
25
|
+
* `{{file:<path>}}` by the contents of a file of the server's mock directory, where `<path>` may
|
|
26
|
+
* hold `{input.<field>}`
|
|
27
|
+
*/
|
|
28
|
+
export declare function renderMock(mock: PluginEvalMockTool, input: Record<string, unknown>): string;
|
|
29
|
+
/** A mock stopping its run: the run scores 0 and reports `aborted` */
|
|
30
|
+
export declare class MockAbortError extends Error {
|
|
31
|
+
readonly abort: PluginEvalAbort;
|
|
32
|
+
constructor(abort: PluginEvalAbort);
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=mocks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mocks.d.ts","sourceRoot":"","sources":["../../src/plugin-evals/mocks.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,eAAe,EAGf,kBAAkB,EACnB,MAAM,SAAS,CAAC;AAEjB,2FAA2F;AAC3F,eAAO,MAAM,iBAAiB,OAAO,CAAC;AAiBtC,qFAAqF;AACrF,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAC5C,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,CA6BlF;AAyID;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAmCjE;AA8BD,sFAAsF;AACtF,wBAAgB,eAAe,CAC7B,IAAI,EAAE,kBAAkB,EACxB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,MAAM,GAAG,SAAS,CAQpB;AAuDD;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CA4B3F;AAED,sEAAsE;AACtE,qBAAa,cAAe,SAAQ,KAAK;IAC3B,QAAQ,CAAC,KAAK,EAAE,eAAe;gBAAtB,KAAK,EAAE,eAAe;CAI5C"}
|