@axlsdk/eval 0.1.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 +169 -0
- package/dist/chunk-F5UZX6FP.js +198 -0
- package/dist/chunk-F5UZX6FP.js.map +1 -0
- package/dist/cli.cjs +375 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +161 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +334 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +126 -0
- package/dist/index.d.ts +126 -0
- package/dist/index.js +104 -0
- package/dist/index.js.map +1 -0
- package/package.json +66 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
dataset: () => dataset,
|
|
34
|
+
defineEval: () => defineEval,
|
|
35
|
+
evalCompare: () => evalCompare,
|
|
36
|
+
llmScorer: () => llmScorer,
|
|
37
|
+
runEval: () => runEval,
|
|
38
|
+
scorer: () => scorer
|
|
39
|
+
});
|
|
40
|
+
module.exports = __toCommonJS(index_exports);
|
|
41
|
+
|
|
42
|
+
// src/dataset.ts
|
|
43
|
+
var import_promises = require("fs/promises");
|
|
44
|
+
var path = __toESM(require("path"), 1);
|
|
45
|
+
function dataset(config) {
|
|
46
|
+
return {
|
|
47
|
+
name: config.name,
|
|
48
|
+
schema: config.schema,
|
|
49
|
+
annotationsSchema: config.annotations,
|
|
50
|
+
async getItems() {
|
|
51
|
+
if (config.items && config.file) {
|
|
52
|
+
throw new Error('Dataset config error: "items" and "file" are mutually exclusive');
|
|
53
|
+
}
|
|
54
|
+
if (!config.items && !config.file) {
|
|
55
|
+
throw new Error('Dataset config error: either "items" or "file" must be provided');
|
|
56
|
+
}
|
|
57
|
+
if (config.items) {
|
|
58
|
+
return config.items.map((item) => ({
|
|
59
|
+
input: config.schema.parse(item.input),
|
|
60
|
+
annotations: item.annotations && config.annotations ? config.annotations.parse(item.annotations) : item.annotations
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
63
|
+
const resolvedPath = path.resolve(config.basePath ?? process.cwd(), config.file);
|
|
64
|
+
const content = await (0, import_promises.readFile)(resolvedPath, "utf-8");
|
|
65
|
+
const items = JSON.parse(content);
|
|
66
|
+
return items.map((item) => ({
|
|
67
|
+
input: config.schema.parse(item.input),
|
|
68
|
+
annotations: item.annotations && config.annotations ? config.annotations.parse(item.annotations) : item.annotations
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// src/scorer.ts
|
|
75
|
+
function scorer(config) {
|
|
76
|
+
return {
|
|
77
|
+
name: config.name,
|
|
78
|
+
description: config.description,
|
|
79
|
+
isLlm: false,
|
|
80
|
+
score: config.score
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// src/llm-scorer.ts
|
|
85
|
+
function llmScorer(config) {
|
|
86
|
+
const scorerInstance = {
|
|
87
|
+
name: config.name,
|
|
88
|
+
description: config.description,
|
|
89
|
+
isLlm: true,
|
|
90
|
+
async score(output, input, annotations) {
|
|
91
|
+
const injectedProvider = scorerInstance._provider;
|
|
92
|
+
if (!injectedProvider) {
|
|
93
|
+
throw new Error(
|
|
94
|
+
`LLM scorer "${config.name}" requires a provider. Run via axl.eval() or the CLI.`
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
const prompt = [
|
|
98
|
+
`Evaluate the following output.`,
|
|
99
|
+
``,
|
|
100
|
+
`## Input`,
|
|
101
|
+
`${JSON.stringify(input, null, 2)}`,
|
|
102
|
+
annotations ? `
|
|
103
|
+
## Annotations (Ground Truth)
|
|
104
|
+
${JSON.stringify(annotations, null, 2)}` : "",
|
|
105
|
+
``,
|
|
106
|
+
`## Output to Evaluate`,
|
|
107
|
+
`${JSON.stringify(output, null, 2)}`,
|
|
108
|
+
``,
|
|
109
|
+
`Respond with valid JSON matching the required schema with a score field (0-1) and reasoning.`
|
|
110
|
+
].join("\n");
|
|
111
|
+
const colonIdx = config.model.indexOf(":");
|
|
112
|
+
const model = colonIdx > -1 ? config.model.slice(colonIdx + 1) : config.model;
|
|
113
|
+
const response = await injectedProvider.chat(
|
|
114
|
+
[
|
|
115
|
+
{ role: "system", content: config.system },
|
|
116
|
+
{ role: "user", content: prompt }
|
|
117
|
+
],
|
|
118
|
+
{ model, temperature: config.temperature ?? 0.2 }
|
|
119
|
+
);
|
|
120
|
+
const parsed = JSON.parse(response.content);
|
|
121
|
+
const validated = config.schema.parse(parsed);
|
|
122
|
+
return validated.score;
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
return scorerInstance;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// src/define-eval.ts
|
|
129
|
+
function defineEval(config) {
|
|
130
|
+
return config;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// src/runner.ts
|
|
134
|
+
var import_node_crypto = require("crypto");
|
|
135
|
+
function computeStats(scores) {
|
|
136
|
+
if (scores.length === 0) return { mean: 0, min: 0, max: 0, p50: 0, p95: 0 };
|
|
137
|
+
const sorted = [...scores].sort((a, b) => a - b);
|
|
138
|
+
const mean = sorted.reduce((a, b) => a + b, 0) / sorted.length;
|
|
139
|
+
const min = sorted[0];
|
|
140
|
+
const max = sorted[sorted.length - 1];
|
|
141
|
+
const p50 = sorted[Math.floor(sorted.length * 0.5)];
|
|
142
|
+
const p95 = sorted[Math.floor(sorted.length * 0.95)];
|
|
143
|
+
return { mean: round(mean), min: round(min), max: round(max), p50: round(p50), p95: round(p95) };
|
|
144
|
+
}
|
|
145
|
+
function round(n) {
|
|
146
|
+
return Math.round(n * 1e3) / 1e3;
|
|
147
|
+
}
|
|
148
|
+
function parseCost(cost) {
|
|
149
|
+
const match = cost.match(/^\$?([\d.]+)$/);
|
|
150
|
+
if (!match) throw new Error(`Invalid cost format: "${cost}"`);
|
|
151
|
+
return parseFloat(match[1]);
|
|
152
|
+
}
|
|
153
|
+
async function runEval(config, executeWorkflow, provider) {
|
|
154
|
+
const startTime = Date.now();
|
|
155
|
+
const id = (0, import_node_crypto.randomUUID)();
|
|
156
|
+
const items = await config.dataset.getItems();
|
|
157
|
+
const concurrency = config.concurrency ?? 5;
|
|
158
|
+
const budgetLimit = config.budget ? parseCost(config.budget) : void 0;
|
|
159
|
+
if (provider) {
|
|
160
|
+
for (const scorer2 of config.scorers) {
|
|
161
|
+
if (scorer2.isLlm) {
|
|
162
|
+
scorer2._provider = provider;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
const evalItems = [];
|
|
167
|
+
let totalCost = 0;
|
|
168
|
+
let budgetExceeded = false;
|
|
169
|
+
async function processItem(item) {
|
|
170
|
+
if (budgetExceeded) {
|
|
171
|
+
evalItems.push({
|
|
172
|
+
input: item.input,
|
|
173
|
+
annotations: item.annotations,
|
|
174
|
+
output: null,
|
|
175
|
+
error: "Budget exceeded",
|
|
176
|
+
scores: {}
|
|
177
|
+
});
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
const evalItem = {
|
|
181
|
+
input: item.input,
|
|
182
|
+
annotations: item.annotations,
|
|
183
|
+
output: null,
|
|
184
|
+
scores: {}
|
|
185
|
+
};
|
|
186
|
+
try {
|
|
187
|
+
const result = await executeWorkflow(item.input);
|
|
188
|
+
evalItem.output = result.output;
|
|
189
|
+
if (result.cost != null) {
|
|
190
|
+
totalCost += result.cost;
|
|
191
|
+
}
|
|
192
|
+
} catch (err) {
|
|
193
|
+
evalItem.error = err instanceof Error ? err.message : String(err);
|
|
194
|
+
evalItems.push(evalItem);
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
if (budgetLimit != null && totalCost > budgetLimit) {
|
|
198
|
+
budgetExceeded = true;
|
|
199
|
+
}
|
|
200
|
+
for (const scorer2 of config.scorers) {
|
|
201
|
+
try {
|
|
202
|
+
const score = await scorer2.score(evalItem.output, item.input, item.annotations);
|
|
203
|
+
if (score < 0 || score > 1) {
|
|
204
|
+
if (!evalItem.errors) evalItem.errors = [];
|
|
205
|
+
evalItem.errors.push(
|
|
206
|
+
`Scorer "${scorer2.name}" returned out-of-range score ${score} for input ${JSON.stringify(item.input)}`
|
|
207
|
+
);
|
|
208
|
+
evalItem.scores[scorer2.name] = -1;
|
|
209
|
+
} else {
|
|
210
|
+
evalItem.scores[scorer2.name] = round(score);
|
|
211
|
+
}
|
|
212
|
+
} catch (err) {
|
|
213
|
+
if (!evalItem.errors) evalItem.errors = [];
|
|
214
|
+
evalItem.errors.push(
|
|
215
|
+
`Scorer "${scorer2.name}" threw: ${err instanceof Error ? err.message : String(err)}`
|
|
216
|
+
);
|
|
217
|
+
evalItem.scores[scorer2.name] = -1;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
evalItems.push(evalItem);
|
|
221
|
+
}
|
|
222
|
+
let index = 0;
|
|
223
|
+
async function runNext() {
|
|
224
|
+
while (index < items.length) {
|
|
225
|
+
const currentIndex = index++;
|
|
226
|
+
await processItem(items[currentIndex]);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
const workers = Array.from({ length: Math.min(concurrency, items.length) }, () => runNext());
|
|
230
|
+
await Promise.all(workers);
|
|
231
|
+
const failures = evalItems.filter((i) => i.error).length;
|
|
232
|
+
const scorerNames = config.scorers.map((s) => s.name);
|
|
233
|
+
const scorerStats = {};
|
|
234
|
+
for (const name of scorerNames) {
|
|
235
|
+
const scores = evalItems.filter((i) => !i.error && i.scores[name] !== void 0 && i.scores[name] >= 0).map((i) => i.scores[name]);
|
|
236
|
+
scorerStats[name] = computeStats(scores);
|
|
237
|
+
}
|
|
238
|
+
return {
|
|
239
|
+
id,
|
|
240
|
+
workflow: config.workflow,
|
|
241
|
+
dataset: config.dataset.name,
|
|
242
|
+
metadata: config.metadata ?? {},
|
|
243
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
244
|
+
totalCost,
|
|
245
|
+
duration: Date.now() - startTime,
|
|
246
|
+
items: evalItems,
|
|
247
|
+
summary: { count: items.length, failures, scorers: scorerStats }
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// src/compare.ts
|
|
252
|
+
function round2(n) {
|
|
253
|
+
return Math.round(n * 100) / 100;
|
|
254
|
+
}
|
|
255
|
+
function evalCompare(baseline, candidate) {
|
|
256
|
+
if (baseline.dataset !== candidate.dataset) {
|
|
257
|
+
throw new Error(
|
|
258
|
+
`Cannot compare evals from different datasets: "${baseline.dataset}" vs "${candidate.dataset}"`
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
const baselineScorerNames = Object.keys(baseline.summary.scorers).sort();
|
|
262
|
+
const candidateScorerNames = Object.keys(candidate.summary.scorers).sort();
|
|
263
|
+
if (JSON.stringify(baselineScorerNames) !== JSON.stringify(candidateScorerNames)) {
|
|
264
|
+
throw new Error(`Cannot compare evals with different scorers`);
|
|
265
|
+
}
|
|
266
|
+
const scorers = {};
|
|
267
|
+
for (const name of baselineScorerNames) {
|
|
268
|
+
const bMean = baseline.summary.scorers[name].mean;
|
|
269
|
+
const cMean = candidate.summary.scorers[name].mean;
|
|
270
|
+
const delta = round2(cMean - bMean);
|
|
271
|
+
const deltaPercent = bMean > 0 ? round2(delta / bMean * 100) : 0;
|
|
272
|
+
scorers[name] = { baselineMean: bMean, candidateMean: cMean, delta, deltaPercent };
|
|
273
|
+
}
|
|
274
|
+
const regressions = [];
|
|
275
|
+
const improvements = [];
|
|
276
|
+
const minLength = Math.min(baseline.items.length, candidate.items.length);
|
|
277
|
+
for (let i = 0; i < minLength; i++) {
|
|
278
|
+
const bItem = baseline.items[i];
|
|
279
|
+
const cItem = candidate.items[i];
|
|
280
|
+
if (bItem.error || cItem.error) continue;
|
|
281
|
+
for (const name of baselineScorerNames) {
|
|
282
|
+
const bScore = bItem.scores[name];
|
|
283
|
+
const cScore = cItem.scores[name];
|
|
284
|
+
if (bScore === void 0 || cScore === void 0 || bScore < 0 || cScore < 0) continue;
|
|
285
|
+
const delta = round2(cScore - bScore);
|
|
286
|
+
if (delta < -0.1)
|
|
287
|
+
regressions.push({
|
|
288
|
+
input: bItem.input,
|
|
289
|
+
scorer: name,
|
|
290
|
+
baselineScore: bScore,
|
|
291
|
+
candidateScore: cScore,
|
|
292
|
+
delta
|
|
293
|
+
});
|
|
294
|
+
else if (delta > 0.1)
|
|
295
|
+
improvements.push({
|
|
296
|
+
input: bItem.input,
|
|
297
|
+
scorer: name,
|
|
298
|
+
baselineScore: bScore,
|
|
299
|
+
candidateScore: cScore,
|
|
300
|
+
delta
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
const parts = [];
|
|
305
|
+
for (const name of baselineScorerNames) {
|
|
306
|
+
const s = scorers[name];
|
|
307
|
+
if (Math.abs(s.delta) > 1e-3) {
|
|
308
|
+
const direction = s.delta > 0 ? "improves" : "regresses";
|
|
309
|
+
const sign = s.delta > 0 ? "+" : "";
|
|
310
|
+
parts.push(
|
|
311
|
+
`'${name}' ${direction} by ${sign}${s.deltaPercent.toFixed(1)}% (${s.baselineMean.toFixed(2)} -> ${s.candidateMean.toFixed(2)})`
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
const summaryStr = `candidate ${parts.length > 0 ? parts.join(", ") : "no significant changes"} with ${regressions.length} regressions and ${improvements.length} improvements`;
|
|
316
|
+
return {
|
|
317
|
+
baseline: { id: baseline.id, metadata: baseline.metadata },
|
|
318
|
+
candidate: { id: candidate.id, metadata: candidate.metadata },
|
|
319
|
+
scorers,
|
|
320
|
+
regressions,
|
|
321
|
+
improvements,
|
|
322
|
+
summary: summaryStr
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
326
|
+
0 && (module.exports = {
|
|
327
|
+
dataset,
|
|
328
|
+
defineEval,
|
|
329
|
+
evalCompare,
|
|
330
|
+
llmScorer,
|
|
331
|
+
runEval,
|
|
332
|
+
scorer
|
|
333
|
+
});
|
|
334
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/dataset.ts","../src/scorer.ts","../src/llm-scorer.ts","../src/define-eval.ts","../src/runner.ts","../src/compare.ts"],"sourcesContent":["export { dataset } from './dataset.js';\nexport type { Dataset, DatasetConfig, DatasetItem } from './dataset.js';\n\nexport { scorer } from './scorer.js';\nexport type { Scorer, ScorerConfig, ScorerFn } from './scorer.js';\n\nexport { llmScorer } from './llm-scorer.js';\nexport type { LlmScorerConfig } from './llm-scorer.js';\n\nexport { defineEval } from './define-eval.js';\nexport { runEval } from './runner.js';\nexport { evalCompare } from './compare.js';\n\nexport type {\n EvalConfig,\n EvalResult,\n EvalItem,\n EvalSummary,\n EvalComparison,\n EvalRegression,\n EvalImprovement,\n} from './types.js';\n","import type { z } from 'zod';\nimport { readFile } from 'node:fs/promises';\nimport * as path from 'node:path';\n\nexport type DatasetItem<TInput, TAnnotations = undefined> = {\n input: TInput;\n annotations?: TAnnotations;\n};\n\nexport type DatasetConfig<\n TInput extends z.ZodTypeAny,\n TAnnotations extends z.ZodTypeAny = z.ZodTypeAny,\n> = {\n name: string;\n schema: TInput;\n annotations?: TAnnotations;\n items?: DatasetItem<z.infer<TInput>, z.infer<TAnnotations>>[];\n file?: string;\n /** Base directory for resolving relative file paths. Defaults to cwd. */\n basePath?: string;\n};\n\nexport type Dataset<TInput = unknown, TAnnotations = unknown> = {\n readonly name: string;\n readonly schema: z.ZodTypeAny;\n readonly annotationsSchema?: z.ZodTypeAny;\n getItems(): Promise<DatasetItem<TInput, TAnnotations>[]>;\n};\n\nexport function dataset<TInput extends z.ZodTypeAny, TAnnotations extends z.ZodTypeAny>(\n config: DatasetConfig<TInput, TAnnotations>,\n): Dataset<z.infer<TInput>, z.infer<TAnnotations>> {\n return {\n name: config.name,\n schema: config.schema,\n annotationsSchema: config.annotations,\n async getItems() {\n if (config.items && config.file) {\n throw new Error('Dataset config error: \"items\" and \"file\" are mutually exclusive');\n }\n if (!config.items && !config.file) {\n throw new Error('Dataset config error: either \"items\" or \"file\" must be provided');\n }\n if (config.items) {\n return config.items.map((item) => ({\n input: config.schema.parse(item.input),\n annotations:\n item.annotations && config.annotations\n ? config.annotations.parse(item.annotations)\n : item.annotations,\n }));\n }\n const resolvedPath = path.resolve(config.basePath ?? process.cwd(), config.file!);\n const content = await readFile(resolvedPath, 'utf-8');\n const items = JSON.parse(content) as DatasetItem<z.infer<TInput>, z.infer<TAnnotations>>[];\n return items.map((item) => ({\n input: config.schema.parse(item.input),\n annotations:\n item.annotations && config.annotations\n ? config.annotations.parse(item.annotations)\n : item.annotations,\n }));\n },\n };\n}\n","export type ScorerFn<TOutput, TInput, TAnnotations> = (\n output: TOutput,\n input: TInput,\n annotations?: TAnnotations,\n) => number;\n\nexport type ScorerConfig<TOutput = any, TInput = any, TAnnotations = any> = {\n name: string;\n description: string;\n score: ScorerFn<TOutput, TInput, TAnnotations>;\n};\n\nexport type Scorer<TOutput = any, TInput = any, TAnnotations = any> = {\n readonly name: string;\n readonly description: string;\n readonly isLlm: boolean;\n score(output: TOutput, input: TInput, annotations?: TAnnotations): number | Promise<number>;\n};\n\nexport function scorer<TOutput = any, TInput = any, TAnnotations = any>(\n config: ScorerConfig<TOutput, TInput, TAnnotations>,\n): Scorer<TOutput, TInput, TAnnotations> {\n return {\n name: config.name,\n description: config.description,\n isLlm: false,\n score: config.score,\n };\n}\n","import type { z } from 'zod';\nimport type { Scorer } from './scorer.js';\n\nexport type LlmScorerConfig = {\n name: string;\n description: string;\n model: string;\n system: string;\n schema: z.ZodType<{ score: number; [key: string]: any }>;\n temperature?: number;\n};\n\nexport function llmScorer(config: LlmScorerConfig): Scorer {\n const scorerInstance: Scorer & { _provider?: any } = {\n name: config.name,\n description: config.description,\n isLlm: true,\n async score(output: any, input: any, annotations?: any): Promise<number> {\n const injectedProvider = (scorerInstance as any)._provider;\n if (!injectedProvider) {\n throw new Error(\n `LLM scorer \"${config.name}\" requires a provider. Run via axl.eval() or the CLI.`,\n );\n }\n\n const prompt = [\n `Evaluate the following output.`,\n ``,\n `## Input`,\n `${JSON.stringify(input, null, 2)}`,\n annotations\n ? `\\n## Annotations (Ground Truth)\\n${JSON.stringify(annotations, null, 2)}`\n : '',\n ``,\n `## Output to Evaluate`,\n `${JSON.stringify(output, null, 2)}`,\n ``,\n `Respond with valid JSON matching the required schema with a score field (0-1) and reasoning.`,\n ].join('\\n');\n\n const colonIdx = config.model.indexOf(':');\n const model = colonIdx > -1 ? config.model.slice(colonIdx + 1) : config.model;\n\n const response = await injectedProvider.chat(\n [\n { role: 'system', content: config.system },\n { role: 'user', content: prompt },\n ],\n { model, temperature: config.temperature ?? 0.2 },\n );\n\n const parsed = JSON.parse(response.content);\n const validated = config.schema.parse(parsed);\n return validated.score;\n },\n };\n\n return scorerInstance;\n}\n","import type { EvalConfig } from './types.js';\n\nexport function defineEval(config: EvalConfig): EvalConfig {\n return config;\n}\n","import type { EvalConfig, EvalResult, EvalItem, EvalSummary } from './types.js';\nimport { randomUUID } from 'node:crypto';\n\nfunction computeStats(scores: number[]): {\n mean: number;\n min: number;\n max: number;\n p50: number;\n p95: number;\n} {\n if (scores.length === 0) return { mean: 0, min: 0, max: 0, p50: 0, p95: 0 };\n const sorted = [...scores].sort((a, b) => a - b);\n const mean = sorted.reduce((a, b) => a + b, 0) / sorted.length;\n const min = sorted[0];\n const max = sorted[sorted.length - 1];\n const p50 = sorted[Math.floor(sorted.length * 0.5)];\n const p95 = sorted[Math.floor(sorted.length * 0.95)];\n return { mean: round(mean), min: round(min), max: round(max), p50: round(p50), p95: round(p95) };\n}\n\nfunction round(n: number): number {\n return Math.round(n * 1000) / 1000;\n}\n\nfunction parseCost(cost: string): number {\n const match = cost.match(/^\\$?([\\d.]+)$/);\n if (!match) throw new Error(`Invalid cost format: \"${cost}\"`);\n return parseFloat(match[1]);\n}\n\nexport async function runEval(\n config: EvalConfig,\n executeWorkflow: (input: unknown) => Promise<{ output: unknown; cost?: number }>,\n provider?: any,\n): Promise<EvalResult> {\n const startTime = Date.now();\n const id = randomUUID();\n const items = await config.dataset.getItems();\n const concurrency = config.concurrency ?? 5;\n const budgetLimit = config.budget ? parseCost(config.budget) : undefined;\n\n if (provider) {\n for (const scorer of config.scorers) {\n if (scorer.isLlm) {\n (scorer as any)._provider = provider;\n }\n }\n }\n\n const evalItems: EvalItem[] = [];\n let totalCost = 0;\n let budgetExceeded = false;\n\n async function processItem(item: (typeof items)[0]): Promise<void> {\n if (budgetExceeded) {\n evalItems.push({\n input: item.input,\n annotations: item.annotations,\n output: null,\n error: 'Budget exceeded',\n scores: {},\n });\n return;\n }\n\n const evalItem: EvalItem = {\n input: item.input,\n annotations: item.annotations,\n output: null,\n scores: {},\n };\n try {\n const result = await executeWorkflow(item.input);\n evalItem.output = result.output;\n if (result.cost != null) {\n totalCost += result.cost;\n }\n } catch (err) {\n evalItem.error = err instanceof Error ? err.message : String(err);\n evalItems.push(evalItem);\n return;\n }\n\n if (budgetLimit != null && totalCost > budgetLimit) {\n budgetExceeded = true;\n }\n\n for (const scorer of config.scorers) {\n try {\n const score = await scorer.score(evalItem.output, item.input, item.annotations);\n if (score < 0 || score > 1) {\n if (!evalItem.errors) evalItem.errors = [];\n evalItem.errors.push(\n `Scorer \"${scorer.name}\" returned out-of-range score ${score} for input ${JSON.stringify(item.input)}`,\n );\n evalItem.scores[scorer.name] = -1;\n } else {\n evalItem.scores[scorer.name] = round(score);\n }\n } catch (err) {\n if (!evalItem.errors) evalItem.errors = [];\n evalItem.errors.push(\n `Scorer \"${scorer.name}\" threw: ${err instanceof Error ? err.message : String(err)}`,\n );\n evalItem.scores[scorer.name] = -1;\n }\n }\n evalItems.push(evalItem);\n }\n\n let index = 0;\n async function runNext(): Promise<void> {\n while (index < items.length) {\n const currentIndex = index++;\n await processItem(items[currentIndex]);\n }\n }\n\n const workers = Array.from({ length: Math.min(concurrency, items.length) }, () => runNext());\n await Promise.all(workers);\n\n const failures = evalItems.filter((i) => i.error).length;\n const scorerNames = config.scorers.map((s) => s.name);\n const scorerStats: EvalSummary['scorers'] = {};\n for (const name of scorerNames) {\n const scores = evalItems\n .filter((i) => !i.error && i.scores[name] !== undefined && i.scores[name] >= 0)\n .map((i) => i.scores[name]);\n scorerStats[name] = computeStats(scores);\n }\n\n return {\n id,\n workflow: config.workflow,\n dataset: config.dataset.name,\n metadata: config.metadata ?? {},\n timestamp: new Date().toISOString(),\n totalCost,\n duration: Date.now() - startTime,\n items: evalItems,\n summary: { count: items.length, failures, scorers: scorerStats },\n };\n}\n","import type { EvalResult, EvalComparison, EvalRegression, EvalImprovement } from './types.js';\n\nfunction round(n: number): number {\n return Math.round(n * 100) / 100;\n}\n\nexport function evalCompare(baseline: EvalResult, candidate: EvalResult): EvalComparison {\n if (baseline.dataset !== candidate.dataset) {\n throw new Error(\n `Cannot compare evals from different datasets: \"${baseline.dataset}\" vs \"${candidate.dataset}\"`,\n );\n }\n\n const baselineScorerNames = Object.keys(baseline.summary.scorers).sort();\n const candidateScorerNames = Object.keys(candidate.summary.scorers).sort();\n if (JSON.stringify(baselineScorerNames) !== JSON.stringify(candidateScorerNames)) {\n throw new Error(`Cannot compare evals with different scorers`);\n }\n\n const scorers: EvalComparison['scorers'] = {};\n for (const name of baselineScorerNames) {\n const bMean = baseline.summary.scorers[name].mean;\n const cMean = candidate.summary.scorers[name].mean;\n const delta = round(cMean - bMean);\n const deltaPercent = bMean > 0 ? round((delta / bMean) * 100) : 0;\n scorers[name] = { baselineMean: bMean, candidateMean: cMean, delta, deltaPercent };\n }\n\n const regressions: EvalRegression[] = [];\n const improvements: EvalImprovement[] = [];\n\n const minLength = Math.min(baseline.items.length, candidate.items.length);\n for (let i = 0; i < minLength; i++) {\n const bItem = baseline.items[i];\n const cItem = candidate.items[i];\n if (bItem.error || cItem.error) continue;\n for (const name of baselineScorerNames) {\n const bScore = bItem.scores[name];\n const cScore = cItem.scores[name];\n if (bScore === undefined || cScore === undefined || bScore < 0 || cScore < 0) continue;\n const delta = round(cScore - bScore);\n if (delta < -0.1)\n regressions.push({\n input: bItem.input,\n scorer: name,\n baselineScore: bScore,\n candidateScore: cScore,\n delta,\n });\n else if (delta > 0.1)\n improvements.push({\n input: bItem.input,\n scorer: name,\n baselineScore: bScore,\n candidateScore: cScore,\n delta,\n });\n }\n }\n\n const parts: string[] = [];\n for (const name of baselineScorerNames) {\n const s = scorers[name];\n if (Math.abs(s.delta) > 0.001) {\n const direction = s.delta > 0 ? 'improves' : 'regresses';\n const sign = s.delta > 0 ? '+' : '';\n parts.push(\n `'${name}' ${direction} by ${sign}${s.deltaPercent.toFixed(1)}% (${s.baselineMean.toFixed(2)} -> ${s.candidateMean.toFixed(2)})`,\n );\n }\n }\n const summaryStr = `candidate ${parts.length > 0 ? parts.join(', ') : 'no significant changes'} with ${regressions.length} regressions and ${improvements.length} improvements`;\n\n return {\n baseline: { id: baseline.id, metadata: baseline.metadata },\n candidate: { id: candidate.id, metadata: candidate.metadata },\n scorers,\n regressions,\n improvements,\n summary: summaryStr,\n };\n}\n"],"mappings":"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","names":["scorer","round"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
type DatasetItem<TInput, TAnnotations = undefined> = {
|
|
4
|
+
input: TInput;
|
|
5
|
+
annotations?: TAnnotations;
|
|
6
|
+
};
|
|
7
|
+
type DatasetConfig<TInput extends z.ZodTypeAny, TAnnotations extends z.ZodTypeAny = z.ZodTypeAny> = {
|
|
8
|
+
name: string;
|
|
9
|
+
schema: TInput;
|
|
10
|
+
annotations?: TAnnotations;
|
|
11
|
+
items?: DatasetItem<z.infer<TInput>, z.infer<TAnnotations>>[];
|
|
12
|
+
file?: string;
|
|
13
|
+
/** Base directory for resolving relative file paths. Defaults to cwd. */
|
|
14
|
+
basePath?: string;
|
|
15
|
+
};
|
|
16
|
+
type Dataset<TInput = unknown, TAnnotations = unknown> = {
|
|
17
|
+
readonly name: string;
|
|
18
|
+
readonly schema: z.ZodTypeAny;
|
|
19
|
+
readonly annotationsSchema?: z.ZodTypeAny;
|
|
20
|
+
getItems(): Promise<DatasetItem<TInput, TAnnotations>[]>;
|
|
21
|
+
};
|
|
22
|
+
declare function dataset<TInput extends z.ZodTypeAny, TAnnotations extends z.ZodTypeAny>(config: DatasetConfig<TInput, TAnnotations>): Dataset<z.infer<TInput>, z.infer<TAnnotations>>;
|
|
23
|
+
|
|
24
|
+
type ScorerFn<TOutput, TInput, TAnnotations> = (output: TOutput, input: TInput, annotations?: TAnnotations) => number;
|
|
25
|
+
type ScorerConfig<TOutput = any, TInput = any, TAnnotations = any> = {
|
|
26
|
+
name: string;
|
|
27
|
+
description: string;
|
|
28
|
+
score: ScorerFn<TOutput, TInput, TAnnotations>;
|
|
29
|
+
};
|
|
30
|
+
type Scorer<TOutput = any, TInput = any, TAnnotations = any> = {
|
|
31
|
+
readonly name: string;
|
|
32
|
+
readonly description: string;
|
|
33
|
+
readonly isLlm: boolean;
|
|
34
|
+
score(output: TOutput, input: TInput, annotations?: TAnnotations): number | Promise<number>;
|
|
35
|
+
};
|
|
36
|
+
declare function scorer<TOutput = any, TInput = any, TAnnotations = any>(config: ScorerConfig<TOutput, TInput, TAnnotations>): Scorer<TOutput, TInput, TAnnotations>;
|
|
37
|
+
|
|
38
|
+
type LlmScorerConfig = {
|
|
39
|
+
name: string;
|
|
40
|
+
description: string;
|
|
41
|
+
model: string;
|
|
42
|
+
system: string;
|
|
43
|
+
schema: z.ZodType<{
|
|
44
|
+
score: number;
|
|
45
|
+
[key: string]: any;
|
|
46
|
+
}>;
|
|
47
|
+
temperature?: number;
|
|
48
|
+
};
|
|
49
|
+
declare function llmScorer(config: LlmScorerConfig): Scorer;
|
|
50
|
+
|
|
51
|
+
type EvalConfig = {
|
|
52
|
+
workflow: string;
|
|
53
|
+
dataset: Dataset<any, any>;
|
|
54
|
+
scorers: Scorer<any, any, any>[];
|
|
55
|
+
concurrency?: number;
|
|
56
|
+
budget?: string;
|
|
57
|
+
metadata?: Record<string, any>;
|
|
58
|
+
};
|
|
59
|
+
type EvalResult = {
|
|
60
|
+
id: string;
|
|
61
|
+
workflow: string;
|
|
62
|
+
dataset: string;
|
|
63
|
+
metadata: Record<string, any>;
|
|
64
|
+
timestamp: string;
|
|
65
|
+
totalCost: number;
|
|
66
|
+
duration: number;
|
|
67
|
+
items: EvalItem[];
|
|
68
|
+
summary: EvalSummary;
|
|
69
|
+
};
|
|
70
|
+
type EvalItem = {
|
|
71
|
+
input: any;
|
|
72
|
+
annotations?: any;
|
|
73
|
+
output: any;
|
|
74
|
+
error?: string;
|
|
75
|
+
errors?: string[];
|
|
76
|
+
scores: Record<string, number>;
|
|
77
|
+
};
|
|
78
|
+
type EvalSummary = {
|
|
79
|
+
count: number;
|
|
80
|
+
failures: number;
|
|
81
|
+
scorers: Record<string, {
|
|
82
|
+
mean: number;
|
|
83
|
+
min: number;
|
|
84
|
+
max: number;
|
|
85
|
+
p50: number;
|
|
86
|
+
p95: number;
|
|
87
|
+
}>;
|
|
88
|
+
};
|
|
89
|
+
type EvalComparison = {
|
|
90
|
+
baseline: {
|
|
91
|
+
id: string;
|
|
92
|
+
metadata: Record<string, any>;
|
|
93
|
+
};
|
|
94
|
+
candidate: {
|
|
95
|
+
id: string;
|
|
96
|
+
metadata: Record<string, any>;
|
|
97
|
+
};
|
|
98
|
+
scorers: Record<string, {
|
|
99
|
+
baselineMean: number;
|
|
100
|
+
candidateMean: number;
|
|
101
|
+
delta: number;
|
|
102
|
+
deltaPercent: number;
|
|
103
|
+
}>;
|
|
104
|
+
regressions: EvalRegression[];
|
|
105
|
+
improvements: EvalImprovement[];
|
|
106
|
+
summary: string;
|
|
107
|
+
};
|
|
108
|
+
type EvalRegression = {
|
|
109
|
+
input: any;
|
|
110
|
+
scorer: string;
|
|
111
|
+
baselineScore: number;
|
|
112
|
+
candidateScore: number;
|
|
113
|
+
delta: number;
|
|
114
|
+
};
|
|
115
|
+
type EvalImprovement = EvalRegression;
|
|
116
|
+
|
|
117
|
+
declare function defineEval(config: EvalConfig): EvalConfig;
|
|
118
|
+
|
|
119
|
+
declare function runEval(config: EvalConfig, executeWorkflow: (input: unknown) => Promise<{
|
|
120
|
+
output: unknown;
|
|
121
|
+
cost?: number;
|
|
122
|
+
}>, provider?: any): Promise<EvalResult>;
|
|
123
|
+
|
|
124
|
+
declare function evalCompare(baseline: EvalResult, candidate: EvalResult): EvalComparison;
|
|
125
|
+
|
|
126
|
+
export { type Dataset, type DatasetConfig, type DatasetItem, type EvalComparison, type EvalConfig, type EvalImprovement, type EvalItem, type EvalRegression, type EvalResult, type EvalSummary, type LlmScorerConfig, type Scorer, type ScorerConfig, type ScorerFn, dataset, defineEval, evalCompare, llmScorer, runEval, scorer };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
type DatasetItem<TInput, TAnnotations = undefined> = {
|
|
4
|
+
input: TInput;
|
|
5
|
+
annotations?: TAnnotations;
|
|
6
|
+
};
|
|
7
|
+
type DatasetConfig<TInput extends z.ZodTypeAny, TAnnotations extends z.ZodTypeAny = z.ZodTypeAny> = {
|
|
8
|
+
name: string;
|
|
9
|
+
schema: TInput;
|
|
10
|
+
annotations?: TAnnotations;
|
|
11
|
+
items?: DatasetItem<z.infer<TInput>, z.infer<TAnnotations>>[];
|
|
12
|
+
file?: string;
|
|
13
|
+
/** Base directory for resolving relative file paths. Defaults to cwd. */
|
|
14
|
+
basePath?: string;
|
|
15
|
+
};
|
|
16
|
+
type Dataset<TInput = unknown, TAnnotations = unknown> = {
|
|
17
|
+
readonly name: string;
|
|
18
|
+
readonly schema: z.ZodTypeAny;
|
|
19
|
+
readonly annotationsSchema?: z.ZodTypeAny;
|
|
20
|
+
getItems(): Promise<DatasetItem<TInput, TAnnotations>[]>;
|
|
21
|
+
};
|
|
22
|
+
declare function dataset<TInput extends z.ZodTypeAny, TAnnotations extends z.ZodTypeAny>(config: DatasetConfig<TInput, TAnnotations>): Dataset<z.infer<TInput>, z.infer<TAnnotations>>;
|
|
23
|
+
|
|
24
|
+
type ScorerFn<TOutput, TInput, TAnnotations> = (output: TOutput, input: TInput, annotations?: TAnnotations) => number;
|
|
25
|
+
type ScorerConfig<TOutput = any, TInput = any, TAnnotations = any> = {
|
|
26
|
+
name: string;
|
|
27
|
+
description: string;
|
|
28
|
+
score: ScorerFn<TOutput, TInput, TAnnotations>;
|
|
29
|
+
};
|
|
30
|
+
type Scorer<TOutput = any, TInput = any, TAnnotations = any> = {
|
|
31
|
+
readonly name: string;
|
|
32
|
+
readonly description: string;
|
|
33
|
+
readonly isLlm: boolean;
|
|
34
|
+
score(output: TOutput, input: TInput, annotations?: TAnnotations): number | Promise<number>;
|
|
35
|
+
};
|
|
36
|
+
declare function scorer<TOutput = any, TInput = any, TAnnotations = any>(config: ScorerConfig<TOutput, TInput, TAnnotations>): Scorer<TOutput, TInput, TAnnotations>;
|
|
37
|
+
|
|
38
|
+
type LlmScorerConfig = {
|
|
39
|
+
name: string;
|
|
40
|
+
description: string;
|
|
41
|
+
model: string;
|
|
42
|
+
system: string;
|
|
43
|
+
schema: z.ZodType<{
|
|
44
|
+
score: number;
|
|
45
|
+
[key: string]: any;
|
|
46
|
+
}>;
|
|
47
|
+
temperature?: number;
|
|
48
|
+
};
|
|
49
|
+
declare function llmScorer(config: LlmScorerConfig): Scorer;
|
|
50
|
+
|
|
51
|
+
type EvalConfig = {
|
|
52
|
+
workflow: string;
|
|
53
|
+
dataset: Dataset<any, any>;
|
|
54
|
+
scorers: Scorer<any, any, any>[];
|
|
55
|
+
concurrency?: number;
|
|
56
|
+
budget?: string;
|
|
57
|
+
metadata?: Record<string, any>;
|
|
58
|
+
};
|
|
59
|
+
type EvalResult = {
|
|
60
|
+
id: string;
|
|
61
|
+
workflow: string;
|
|
62
|
+
dataset: string;
|
|
63
|
+
metadata: Record<string, any>;
|
|
64
|
+
timestamp: string;
|
|
65
|
+
totalCost: number;
|
|
66
|
+
duration: number;
|
|
67
|
+
items: EvalItem[];
|
|
68
|
+
summary: EvalSummary;
|
|
69
|
+
};
|
|
70
|
+
type EvalItem = {
|
|
71
|
+
input: any;
|
|
72
|
+
annotations?: any;
|
|
73
|
+
output: any;
|
|
74
|
+
error?: string;
|
|
75
|
+
errors?: string[];
|
|
76
|
+
scores: Record<string, number>;
|
|
77
|
+
};
|
|
78
|
+
type EvalSummary = {
|
|
79
|
+
count: number;
|
|
80
|
+
failures: number;
|
|
81
|
+
scorers: Record<string, {
|
|
82
|
+
mean: number;
|
|
83
|
+
min: number;
|
|
84
|
+
max: number;
|
|
85
|
+
p50: number;
|
|
86
|
+
p95: number;
|
|
87
|
+
}>;
|
|
88
|
+
};
|
|
89
|
+
type EvalComparison = {
|
|
90
|
+
baseline: {
|
|
91
|
+
id: string;
|
|
92
|
+
metadata: Record<string, any>;
|
|
93
|
+
};
|
|
94
|
+
candidate: {
|
|
95
|
+
id: string;
|
|
96
|
+
metadata: Record<string, any>;
|
|
97
|
+
};
|
|
98
|
+
scorers: Record<string, {
|
|
99
|
+
baselineMean: number;
|
|
100
|
+
candidateMean: number;
|
|
101
|
+
delta: number;
|
|
102
|
+
deltaPercent: number;
|
|
103
|
+
}>;
|
|
104
|
+
regressions: EvalRegression[];
|
|
105
|
+
improvements: EvalImprovement[];
|
|
106
|
+
summary: string;
|
|
107
|
+
};
|
|
108
|
+
type EvalRegression = {
|
|
109
|
+
input: any;
|
|
110
|
+
scorer: string;
|
|
111
|
+
baselineScore: number;
|
|
112
|
+
candidateScore: number;
|
|
113
|
+
delta: number;
|
|
114
|
+
};
|
|
115
|
+
type EvalImprovement = EvalRegression;
|
|
116
|
+
|
|
117
|
+
declare function defineEval(config: EvalConfig): EvalConfig;
|
|
118
|
+
|
|
119
|
+
declare function runEval(config: EvalConfig, executeWorkflow: (input: unknown) => Promise<{
|
|
120
|
+
output: unknown;
|
|
121
|
+
cost?: number;
|
|
122
|
+
}>, provider?: any): Promise<EvalResult>;
|
|
123
|
+
|
|
124
|
+
declare function evalCompare(baseline: EvalResult, candidate: EvalResult): EvalComparison;
|
|
125
|
+
|
|
126
|
+
export { type Dataset, type DatasetConfig, type DatasetItem, type EvalComparison, type EvalConfig, type EvalImprovement, type EvalItem, type EvalRegression, type EvalResult, type EvalSummary, type LlmScorerConfig, type Scorer, type ScorerConfig, type ScorerFn, dataset, defineEval, evalCompare, llmScorer, runEval, scorer };
|