@hazeljs/eval 2.0.13 → 2.0.14
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 +9 -2
- package/dist/golden-runner.d.ts.map +1 -1
- package/dist/golden-runner.js +25 -6
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/types.d.ts +28 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -23,9 +23,10 @@ npm install @hazeljs/core
|
|
|
23
23
|
- **Retrieval metrics** — `precisionAtK`, `recallAtK`, `meanReciprocalRank`, `ndcgAtK`
|
|
24
24
|
- **RAG helpers** — `evaluateRetrieval`, `answerContextOverlap` (lightweight faithfulness proxy)
|
|
25
25
|
- **Agent trajectories** — `trajectoryScore`, `toolCallAccuracy`
|
|
26
|
-
- **LLM judge** — `parseJudgeScore`, `buildRelevanceJudgePrompt`, `buildFaithfulnessJudgePrompt`
|
|
26
|
+
- **LLM judge** — `parseJudgeScore`, `buildRelevanceJudgePrompt`, `buildFaithfulnessJudgePrompt`; pass `judge` on `EvalRunOptions` to blend into `runGoldenDataset`
|
|
27
27
|
- **Runner** — `runGoldenDataset` with configurable concurrency and thresholds
|
|
28
28
|
- **CI** — `reportEvalForCi` with optional non-zero exit via `process.exitCode`
|
|
29
|
+
- **AI call goldens** — put `metadata.expectedCalls` on cases and use `@hazeljs/ai` `runAiGolden` / `FakeModel` for provider-request regression
|
|
29
30
|
|
|
30
31
|
## Quick start
|
|
31
32
|
|
|
@@ -46,7 +47,13 @@ const result = await runGoldenDataset(
|
|
|
46
47
|
retrievedIds: ['doc-1', 'doc-2'],
|
|
47
48
|
};
|
|
48
49
|
},
|
|
49
|
-
{
|
|
50
|
+
{
|
|
51
|
+
concurrency: 2,
|
|
52
|
+
minAverageScore: 0.75,
|
|
53
|
+
// optional: blend LLM-as-judge (skip per-case with metadata.skipJudge)
|
|
54
|
+
// judge: async (prompt) => ai.chat(prompt).text(),
|
|
55
|
+
// judgePrompt: 'relevance',
|
|
56
|
+
}
|
|
50
57
|
);
|
|
51
58
|
|
|
52
59
|
reportEvalForCi(result, { exitOnFail: true });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"golden-runner.d.ts","sourceRoot":"","sources":["../src/golden-runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAc,aAAa,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"golden-runner.d.ts","sourceRoot":"","sources":["../src/golden-runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAc,aAAa,EAAE,MAAM,SAAS,CAAC;AASxF,MAAM,MAAM,UAAU,GAAG,CAAC,KAAK,EAAE;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC,KAAK,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAAC;AAEjF;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,UAAU,EAClB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAAC,aAAa,CAAC,CA6GxB"}
|
package/dist/golden-runner.js
CHANGED
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.runGoldenDataset = runGoldenDataset;
|
|
4
4
|
const agent_trajectory_1 = require("./agent-trajectory");
|
|
5
5
|
const retrieval_metrics_1 = require("./retrieval-metrics");
|
|
6
|
+
const llm_judge_1 = require("./llm-judge");
|
|
6
7
|
/**
|
|
7
8
|
* Run a golden dataset against an async runner (your app, agent, or RAG pipeline).
|
|
8
9
|
*/
|
|
@@ -22,30 +23,48 @@ async function runGoldenDataset(dataset, runner, options) {
|
|
|
22
23
|
metadata: c.metadata,
|
|
23
24
|
});
|
|
24
25
|
let score = 0;
|
|
26
|
+
let scoredParts = 0;
|
|
25
27
|
const details = {};
|
|
26
28
|
if (c.expectedOutput !== undefined) {
|
|
27
29
|
const out = result.output ?? '';
|
|
28
30
|
const exp = c.expectedOutput;
|
|
29
31
|
const passed = out.includes(exp) || out.trim().toLowerCase() === exp.trim().toLowerCase();
|
|
30
|
-
score
|
|
32
|
+
score += passed ? 1 : 0;
|
|
33
|
+
scoredParts += 1;
|
|
31
34
|
details.outputMatch = passed;
|
|
32
35
|
}
|
|
33
36
|
if (c.expectedToolCalls && c.expectedToolCalls.length > 0) {
|
|
34
37
|
const traj = (0, agent_trajectory_1.trajectoryScore)(c.expectedToolCalls, result.toolCalls ?? []);
|
|
35
|
-
score
|
|
38
|
+
score += traj;
|
|
39
|
+
scoredParts += 1;
|
|
36
40
|
details.trajectoryScore = traj;
|
|
37
41
|
}
|
|
38
42
|
if (c.expectedRetrievedIds && c.expectedRetrievedIds.length > 0) {
|
|
39
43
|
const rel = new Set(c.expectedRetrievedIds);
|
|
40
44
|
const p = (0, retrieval_metrics_1.precisionAtK)(result.retrievedIds ?? [], rel, 5);
|
|
41
|
-
score
|
|
45
|
+
score += p;
|
|
46
|
+
scoredParts += 1;
|
|
42
47
|
details.precisionAt5 = p;
|
|
43
48
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
49
|
+
const skipJudge = Boolean(c.metadata?.skipJudge);
|
|
50
|
+
if (options?.judge && !skipJudge) {
|
|
51
|
+
const promptKind = options.judgePrompt ?? 'relevance';
|
|
52
|
+
const judgePrompt = promptKind === 'faithfulness'
|
|
53
|
+
? (0, llm_judge_1.buildFaithfulnessJudgePrompt)(String(c.metadata?.judgeContext ?? ''), result.output ?? '')
|
|
54
|
+
: (0, llm_judge_1.buildRelevanceJudgePrompt)(c.input, result.output ?? '');
|
|
55
|
+
const raw = await options.judge(judgePrompt);
|
|
56
|
+
const judged = await (0, llm_judge_1.parseJudgeScore)(raw);
|
|
57
|
+
score += judged.score;
|
|
58
|
+
scoredParts += 1;
|
|
59
|
+
details.judgeScore = judged.score;
|
|
60
|
+
details.judgeReasoning = judged.reasoning;
|
|
61
|
+
}
|
|
62
|
+
if (scoredParts === 0) {
|
|
47
63
|
score = 1;
|
|
48
64
|
}
|
|
65
|
+
else {
|
|
66
|
+
score = score / scoredParts;
|
|
67
|
+
}
|
|
49
68
|
const threshold = options?.minAverageScore ?? 0.7;
|
|
50
69
|
return {
|
|
51
70
|
caseId: c.id,
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @hazeljs/eval — Evaluation toolkit for AI-native HazelJS apps
|
|
3
3
|
*/
|
|
4
|
-
export type { GoldenCase, GoldenDataset, EvalRunOptions, CaseResult, EvalRunResult } from './types';
|
|
4
|
+
export type { GoldenCase, GoldenDataset, EvalRunOptions, CaseResult, EvalRunResult, ExpectedCallSlice, } from './types';
|
|
5
5
|
export { precisionAtK, recallAtK, meanReciprocalRank, ndcgAtK } from './retrieval-metrics';
|
|
6
6
|
export { evaluateRetrieval, answerContextOverlap, type RagRetrievalEvalInput, type RagRetrievalEvalResult, } from './rag-metrics';
|
|
7
7
|
export { trajectoryScore, toolCallAccuracy, type AgentTrajectory } from './agent-trajectory';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,YAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,YAAY,EACV,UAAU,EACV,aAAa,EACb,cAAc,EACd,UAAU,EACV,aAAa,EACb,iBAAiB,GAClB,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAE3F,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,KAAK,qBAAqB,EAC1B,KAAK,sBAAsB,GAC5B,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAE7F,OAAO,EACL,eAAe,EACf,yBAAyB,EACzB,4BAA4B,EAC5B,KAAK,UAAU,EACf,KAAK,UAAU,GAChB,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,gBAAgB,EAAE,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,KAAK,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAExE,OAAO,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,6 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Core types for @hazeljs/eval
|
|
3
3
|
*/
|
|
4
|
+
import type { LLMJudgeFn } from './llm-judge';
|
|
5
|
+
/**
|
|
6
|
+
* Optional provider-call golden shape (used by `@hazeljs/ai` FakeModel matchers).
|
|
7
|
+
* Store under `GoldenCase.metadata.expectedCalls`.
|
|
8
|
+
*/
|
|
9
|
+
export interface ExpectedCallSlice {
|
|
10
|
+
/** Exact model id if asserted */
|
|
11
|
+
model?: string;
|
|
12
|
+
/** Subset of message roles in order (e.g. ['system','user']) */
|
|
13
|
+
messageRoles?: string[];
|
|
14
|
+
/** Tool / function names expected to be offered on the request */
|
|
15
|
+
toolNames?: string[];
|
|
16
|
+
/** Substring that must appear in some message content */
|
|
17
|
+
messageIncludes?: string;
|
|
18
|
+
}
|
|
4
19
|
export interface GoldenCase {
|
|
5
20
|
id: string;
|
|
6
21
|
input: string;
|
|
@@ -10,6 +25,12 @@ export interface GoldenCase {
|
|
|
10
25
|
expectedToolCalls?: string[];
|
|
11
26
|
/** Relevant document IDs or content snippets retrieval should surface */
|
|
12
27
|
expectedRetrievedIds?: string[];
|
|
28
|
+
/**
|
|
29
|
+
* Free-form case metadata. Recognized keys:
|
|
30
|
+
* - `expectedCalls`: ExpectedCallSlice[] for FakeModel request goldens
|
|
31
|
+
* - `judgeContext`: string used when `EvalRunOptions.judgePrompt === 'faithfulness'`
|
|
32
|
+
* - `skipJudge`: boolean to skip LLM judge for this case
|
|
33
|
+
*/
|
|
13
34
|
metadata?: Record<string, unknown>;
|
|
14
35
|
}
|
|
15
36
|
export interface GoldenDataset {
|
|
@@ -22,6 +43,13 @@ export interface EvalRunOptions {
|
|
|
22
43
|
concurrency?: number;
|
|
23
44
|
/** Fail CI when average score below threshold */
|
|
24
45
|
minAverageScore?: number;
|
|
46
|
+
/**
|
|
47
|
+
* Optional LLM-as-judge. When set, blends judge score with existing matchers
|
|
48
|
+
* (unless `metadata.skipJudge` is true).
|
|
49
|
+
*/
|
|
50
|
+
judge?: LLMJudgeFn;
|
|
51
|
+
/** Which rubric prompt to build (default relevance). */
|
|
52
|
+
judgePrompt?: 'relevance' | 'faithfulness';
|
|
25
53
|
}
|
|
26
54
|
export interface CaseResult {
|
|
27
55
|
caseId: string;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,4EAA4E;IAC5E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2DAA2D;IAC3D,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,yEAAyE;IACzE,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,qCAAqC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,eAAe,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C;;;GAGG;AACH,MAAM,WAAW,iBAAiB;IAChC,iCAAiC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gEAAgE;IAChE,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,yDAAyD;IACzD,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,4EAA4E;IAC5E,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,2DAA2D;IAC3D,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,yEAAyE;IACzE,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,qCAAqC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,wDAAwD;IACxD,WAAW,CAAC,EAAE,WAAW,GAAG,cAAc,CAAC;CAC5C;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;CACjB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hazeljs/eval",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.14",
|
|
4
4
|
"description": "Evaluation toolkit for HazelJS AI apps — golden datasets, RAG metrics, agent trajectories, LLM-as-judge, CI reports",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -19,10 +19,10 @@
|
|
|
19
19
|
"zod": "^3.25.76"
|
|
20
20
|
},
|
|
21
21
|
"peerDependencies": {
|
|
22
|
-
"@hazeljs/core": "^2.0.
|
|
22
|
+
"@hazeljs/core": "^2.0.14"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@hazeljs/core": "^2.0.
|
|
25
|
+
"@hazeljs/core": "^2.0.14",
|
|
26
26
|
"@types/jest": "^29.5.14",
|
|
27
27
|
"@types/node": "^20.19.39",
|
|
28
28
|
"@typescript-eslint/eslint-plugin": "^8.58.0",
|