@deepagents/evals 0.19.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.
Files changed (52) hide show
  1. package/README.md +218 -0
  2. package/dist/comparison/index.d.ts +41 -0
  3. package/dist/comparison/index.d.ts.map +1 -0
  4. package/dist/comparison/index.js +106 -0
  5. package/dist/comparison/index.js.map +7 -0
  6. package/dist/dataset/hf.d.ts +16 -0
  7. package/dist/dataset/hf.d.ts.map +1 -0
  8. package/dist/dataset/index.d.ts +17 -0
  9. package/dist/dataset/index.d.ts.map +1 -0
  10. package/dist/dataset/index.js +256 -0
  11. package/dist/dataset/index.js.map +7 -0
  12. package/dist/engine/index.d.ts +67 -0
  13. package/dist/engine/index.d.ts.map +1 -0
  14. package/dist/engine/index.js +332 -0
  15. package/dist/engine/index.js.map +7 -0
  16. package/dist/evaluate/index.d.ts +47 -0
  17. package/dist/evaluate/index.d.ts.map +1 -0
  18. package/dist/evaluate/index.js +977 -0
  19. package/dist/evaluate/index.js.map +7 -0
  20. package/dist/index.d.ts +15 -0
  21. package/dist/index.d.ts.map +1 -0
  22. package/dist/index.js +1763 -0
  23. package/dist/index.js.map +7 -0
  24. package/dist/reporters/console.d.ts +6 -0
  25. package/dist/reporters/console.d.ts.map +1 -0
  26. package/dist/reporters/csv.d.ts +6 -0
  27. package/dist/reporters/csv.d.ts.map +1 -0
  28. package/dist/reporters/format.d.ts +12 -0
  29. package/dist/reporters/format.d.ts.map +1 -0
  30. package/dist/reporters/html.d.ts +6 -0
  31. package/dist/reporters/html.d.ts.map +1 -0
  32. package/dist/reporters/index.d.ts +12 -0
  33. package/dist/reporters/index.d.ts.map +1 -0
  34. package/dist/reporters/index.js +447 -0
  35. package/dist/reporters/index.js.map +7 -0
  36. package/dist/reporters/json.d.ts +7 -0
  37. package/dist/reporters/json.d.ts.map +1 -0
  38. package/dist/reporters/markdown.d.ts +6 -0
  39. package/dist/reporters/markdown.d.ts.map +1 -0
  40. package/dist/reporters/shared.d.ts +11 -0
  41. package/dist/reporters/shared.d.ts.map +1 -0
  42. package/dist/reporters/types.d.ts +35 -0
  43. package/dist/reporters/types.d.ts.map +1 -0
  44. package/dist/scorers/index.d.ts +30 -0
  45. package/dist/scorers/index.d.ts.map +1 -0
  46. package/dist/scorers/index.js +175 -0
  47. package/dist/scorers/index.js.map +7 -0
  48. package/dist/store/index.d.ts +103 -0
  49. package/dist/store/index.d.ts.map +1 -0
  50. package/dist/store/index.js +361 -0
  51. package/dist/store/index.js.map +7 -0
  52. package/package.json +99 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/dataset/index.ts", "../../src/dataset/hf.ts"],
4
+ "sourcesContent": ["import { createReadStream } from 'node:fs';\nimport { readFile } from 'node:fs/promises';\nimport { extname } from 'node:path';\nimport { createInterface } from 'node:readline';\n\nexport { hf } from './hf.ts';\nexport type { HfOptions } from './hf.ts';\n\nexport type TransformFn<T, U> = (item: T) => U;\nexport type PredicateFn<T> = (item: T) => boolean;\n\nexport class Dataset<T> implements AsyncIterable<T> {\n #source: () => AsyncIterable<T>;\n\n constructor(source: () => AsyncIterable<T>) {\n this.#source = source;\n }\n\n map<U>(fn: TransformFn<T, U>): Dataset<U> {\n const source = this.#source;\n return new Dataset(async function* () {\n for await (const item of source()) {\n yield fn(item);\n }\n });\n }\n\n filter(fn: PredicateFn<T>): Dataset<T> {\n const source = this.#source;\n return new Dataset(async function* () {\n for await (const item of source()) {\n if (fn(item)) yield item;\n }\n });\n }\n\n limit(n: number): Dataset<T> {\n const source = this.#source;\n return new Dataset(async function* () {\n let count = 0;\n for await (const item of source()) {\n if (count >= n) return;\n yield item;\n count++;\n }\n });\n }\n\n shuffle(): Dataset<T> {\n const source = this.#source;\n return new Dataset(async function* () {\n const items: T[] = [];\n for await (const item of source()) {\n items.push(item);\n }\n for (let i = items.length - 1; i > 0; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n const temp = items[i] as T;\n items[i] = items[j] as T;\n items[j] = temp;\n }\n yield* items;\n });\n }\n\n sample(n: number): Dataset<T> {\n const source = this.#source;\n return new Dataset(async function* () {\n const items: T[] = [];\n for await (const item of source()) {\n items.push(item);\n }\n const count = Math.min(Math.max(0, n), items.length);\n for (let i = items.length - 1; i > items.length - count - 1; i--) {\n const j = Math.floor(Math.random() * (i + 1));\n const temp = items[i] as T;\n items[i] = items[j] as T;\n items[j] = temp;\n }\n for (let i = items.length - count; i < items.length; i++) {\n yield items[i]!;\n }\n });\n }\n\n async toArray(): Promise<T[]> {\n const result: T[] = [];\n for await (const item of this.#source()) {\n result.push(item);\n }\n return result;\n }\n\n [Symbol.asyncIterator](): AsyncIterator<T> {\n return this.#source()[Symbol.asyncIterator]();\n }\n}\n\nfunction parseCSVLine(line: string): string[] {\n const fields: string[] = [];\n let current = '';\n let inQuotes = false;\n\n for (let i = 0; i < line.length; i++) {\n const char = line[i]!;\n if (inQuotes) {\n if (char === '\"') {\n if (i + 1 < line.length && line[i + 1] === '\"') {\n current += '\"';\n i++;\n } else {\n inQuotes = false;\n }\n } else {\n current += char;\n }\n } else {\n if (char === '\"' && current === '') {\n inQuotes = true;\n } else if (char === ',') {\n fields.push(current);\n current = '';\n } else {\n current += char;\n }\n }\n }\n fields.push(current);\n return fields;\n}\n\nfunction loadJSON<T>(filePath: string): () => AsyncIterable<T> {\n return async function* () {\n const content = await readFile(filePath, 'utf-8');\n const data = JSON.parse(content);\n if (!Array.isArray(data)) {\n throw new Error(`JSON file \"${filePath}\" does not contain an array`);\n }\n yield* data;\n };\n}\n\nfunction loadJSONL<T>(filePath: string): () => AsyncIterable<T> {\n return async function* () {\n const rl = createInterface({\n input: createReadStream(filePath, 'utf-8'),\n crlfDelay: Infinity,\n });\n try {\n for await (const line of rl) {\n const trimmed = line.trim();\n if (trimmed) {\n yield JSON.parse(trimmed);\n }\n }\n } finally {\n rl.close();\n }\n };\n}\n\nfunction loadCSV(\n filePath: string,\n): () => AsyncIterable<Record<string, string>> {\n return async function* () {\n const rl = createInterface({\n input: createReadStream(filePath, 'utf-8'),\n crlfDelay: Infinity,\n });\n try {\n let headers: string[] | undefined;\n for await (const line of rl) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n const fields = parseCSVLine(trimmed);\n if (!headers) {\n headers = fields;\n continue;\n }\n const row: Record<string, string> = {};\n for (let i = 0; i < headers.length; i++) {\n row[headers[i]!] = fields[i] ?? '';\n }\n yield row;\n }\n } finally {\n rl.close();\n }\n };\n}\n\nexport function dataset<T>(\n source: T[] | string | AsyncIterable<T>,\n): Dataset<T> {\n if (Array.isArray(source)) {\n return new Dataset(async function* () {\n yield* source;\n });\n }\n\n if (typeof source === 'object' && Symbol.asyncIterator in source) {\n return new Dataset(() => source);\n }\n\n const ext = extname(source).toLowerCase();\n switch (ext) {\n case '.json':\n return new Dataset(loadJSON<T>(source));\n case '.jsonl':\n return new Dataset(loadJSONL<T>(source));\n case '.csv':\n return new Dataset(loadCSV(source) as () => AsyncIterable<T>);\n default:\n throw new Error(\n `Unsupported file extension \"${ext}\" for dataset file \"${source}\". Supported: .json, .jsonl, .csv`,\n );\n }\n}\n", "export interface HfOptions {\n dataset: string;\n config: string;\n split: string;\n rows?: number;\n}\n\ninterface HfApiResponse {\n rows: Array<{ row_idx: number; row: Record<string, unknown> }>;\n num_rows_total: number;\n}\n\nconst HF_BASE_URL = 'https://datasets-server.huggingface.co/rows';\nconst PAGE_SIZE = 100;\n\nexport function hf<T = Record<string, unknown>>(\n options: HfOptions,\n): AsyncIterable<T> {\n return {\n [Symbol.asyncIterator]() {\n return paginate<T>(options);\n },\n };\n}\n\nasync function* paginate<T>(options: HfOptions): AsyncGenerator<T> {\n const { dataset, config, split, rows } = options;\n const limit = rows ?? Infinity;\n let offset = 0;\n let yielded = 0;\n\n while (yielded < limit) {\n const pageSize =\n limit === Infinity ? PAGE_SIZE : Math.min(PAGE_SIZE, limit - yielded);\n const url = buildUrl(dataset, config, split, offset, pageSize);\n const page = await fetchPage(url);\n\n if (page.rows.length === 0) return;\n\n for (const entry of page.rows) {\n yield entry.row as T;\n yielded++;\n if (yielded >= limit) return;\n }\n\n offset += page.rows.length;\n if (page.rows.length < pageSize || offset >= page.num_rows_total) return;\n }\n}\n\nfunction buildUrl(\n dataset: string,\n config: string,\n split: string,\n offset: number,\n length: number,\n): string {\n const url = new URL(HF_BASE_URL);\n url.searchParams.set('dataset', dataset);\n url.searchParams.set('config', config);\n url.searchParams.set('split', split);\n url.searchParams.set('offset', String(offset));\n url.searchParams.set('length', String(length));\n return url.toString();\n}\n\nexport async function fetchHfRows(\n options: { dataset: string; config: string; split: string },\n offset: number,\n length: number,\n): Promise<{ rows: Record<string, unknown>[]; total: number }> {\n const url = buildUrl(\n options.dataset,\n options.config,\n options.split,\n offset,\n length,\n );\n const page = await fetchPage(url);\n return {\n rows: page.rows.map((entry) => entry.row),\n total: page.num_rows_total,\n };\n}\n\nasync function fetchPage(url: string): Promise<HfApiResponse> {\n const response = await fetch(url);\n if (!response.ok) {\n const body = await response.text().catch(() => '');\n throw new Error(\n `HuggingFace API error ${response.status}: ${body || response.statusText}`,\n );\n }\n const text = await response.text();\n try {\n return JSON.parse(text) as HfApiResponse;\n } catch {\n throw new Error(\n `HuggingFace API returned non-JSON response from ${url}: ${text.slice(0, 200)}`,\n );\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["dataset"]
7
+ }
@@ -0,0 +1,67 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import type { Scorer, ScorerResult } from '../scorers/index.ts';
3
+ import type { RunStore, RunSummary } from '../store/index.ts';
4
+ export interface TaskResult {
5
+ output: string;
6
+ usage?: {
7
+ inputTokens: number;
8
+ outputTokens: number;
9
+ };
10
+ }
11
+ export type TaskFn<T> = (input: T) => Promise<TaskResult>;
12
+ export interface EngineEvents {
13
+ 'run:start': {
14
+ runId: string;
15
+ totalCases: number;
16
+ name: string;
17
+ model: string;
18
+ };
19
+ 'case:start': {
20
+ runId: string;
21
+ index: number;
22
+ input: unknown;
23
+ };
24
+ 'case:scored': {
25
+ runId: string;
26
+ index: number;
27
+ input: unknown;
28
+ output: string;
29
+ expected: unknown;
30
+ scores: Record<string, ScorerResult>;
31
+ error?: unknown;
32
+ latencyMs: number;
33
+ tokensIn: number;
34
+ tokensOut: number;
35
+ };
36
+ 'case:error': {
37
+ runId: string;
38
+ index: number;
39
+ error: string;
40
+ };
41
+ 'run:end': {
42
+ runId: string;
43
+ summary: RunSummary;
44
+ };
45
+ }
46
+ export declare class EvalEmitter extends EventEmitter {
47
+ on<K extends keyof EngineEvents>(event: K, listener: (data: EngineEvents[K]) => void): this;
48
+ emit<K extends keyof EngineEvents>(event: K, data: EngineEvents[K]): boolean;
49
+ }
50
+ export interface EvalConfig<T> {
51
+ name: string;
52
+ model: string;
53
+ dataset: AsyncIterable<T>;
54
+ task: TaskFn<T>;
55
+ scorers: Record<string, Scorer>;
56
+ store: RunStore;
57
+ emitter?: EvalEmitter;
58
+ suiteId?: string;
59
+ config?: Record<string, unknown>;
60
+ maxConcurrency?: number;
61
+ batchSize?: number;
62
+ timeout?: number;
63
+ trials?: number;
64
+ threshold?: number;
65
+ }
66
+ export declare function runEval<T>(config: EvalConfig<T>): Promise<RunSummary>;
67
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/engine/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,KAAK,EAEV,QAAQ,EACR,UAAU,EAEX,MAAM,mBAAmB,CAAC;AAE3B,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE;QAAE,WAAW,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,CAAC;CACvD;AAED,MAAM,MAAM,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;AAE1D,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE;QACX,KAAK,EAAE,MAAM,CAAC;QACd,UAAU,EAAE,MAAM,CAAC;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;IACF,YAAY,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC;IAC/D,aAAa,EAAE;QACb,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,OAAO,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,OAAO,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QACrC,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,YAAY,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9D,SAAS,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,UAAU,CAAA;KAAE,CAAC;CACnD;AAED,qBAAa,WAAY,SAAQ,YAAY;IAClC,EAAE,CAAC,CAAC,SAAS,MAAM,YAAY,EACtC,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,IAAI,GACxC,IAAI;IAIE,IAAI,CAAC,CAAC,SAAS,MAAM,YAAY,EACxC,KAAK,EAAE,CAAC,EACR,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,GACpB,OAAO;CAGX;AAED,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,KAAK,EAAE,QAAQ,CAAC;IAChB,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAkID,wBAAsB,OAAO,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CA0N3E"}
@@ -0,0 +1,332 @@
1
+ // packages/evals/src/engine/index.ts
2
+ import { EventEmitter } from "node:events";
3
+ var EvalEmitter = class extends EventEmitter {
4
+ on(event, listener) {
5
+ return super.on(event, listener);
6
+ }
7
+ emit(event, data) {
8
+ return super.emit(event, data);
9
+ }
10
+ };
11
+ function errorMessage(err) {
12
+ if (err instanceof Error) {
13
+ return `${err.name}: ${err.message}`;
14
+ }
15
+ if (typeof err === "string") return err;
16
+ if (err == null) return "Unknown error";
17
+ try {
18
+ return JSON.stringify(err);
19
+ } catch {
20
+ return String(err);
21
+ }
22
+ }
23
+ function serializeError(err) {
24
+ if (err instanceof Error) {
25
+ return JSON.stringify({
26
+ name: err.name,
27
+ message: err.message,
28
+ stack: err.stack,
29
+ cause: err.cause instanceof Error ? {
30
+ name: err.cause.name,
31
+ message: err.cause.message
32
+ } : err.cause
33
+ });
34
+ }
35
+ if (typeof err === "string") return JSON.stringify({ message: err });
36
+ if (err == null) return JSON.stringify({ message: "Unknown error" });
37
+ try {
38
+ return JSON.stringify(err);
39
+ } catch {
40
+ return JSON.stringify({ message: String(err) });
41
+ }
42
+ }
43
+ function failureScores(scorerNames, error) {
44
+ const reason = `Task failed: ${errorMessage(error)}`;
45
+ const scores = {};
46
+ for (const scorerName of scorerNames) {
47
+ scores[scorerName] = { score: 0, reason };
48
+ }
49
+ return scores;
50
+ }
51
+ function createSemaphore(maxConcurrency) {
52
+ let active = 0;
53
+ const queue = [];
54
+ return {
55
+ async acquire() {
56
+ if (active < maxConcurrency) {
57
+ active++;
58
+ return;
59
+ }
60
+ return new Promise((resolve) => queue.push(resolve));
61
+ },
62
+ release() {
63
+ active--;
64
+ const next = queue.shift();
65
+ if (next) {
66
+ active++;
67
+ next();
68
+ }
69
+ }
70
+ };
71
+ }
72
+ async function wrapTask(task, input, timeoutMs) {
73
+ const start = performance.now();
74
+ let timerId;
75
+ try {
76
+ const result = await Promise.race([
77
+ task(input),
78
+ new Promise((_, reject) => {
79
+ timerId = setTimeout(
80
+ () => reject(new Error("timeout exceeded")),
81
+ timeoutMs
82
+ );
83
+ })
84
+ ]);
85
+ clearTimeout(timerId);
86
+ const latencyMs = Math.round(performance.now() - start);
87
+ return {
88
+ output: result.output,
89
+ latencyMs,
90
+ tokensIn: result.usage?.inputTokens ?? 0,
91
+ tokensOut: result.usage?.outputTokens ?? 0
92
+ };
93
+ } catch (err) {
94
+ clearTimeout(timerId);
95
+ const latencyMs = Math.round(performance.now() - start);
96
+ return {
97
+ output: "",
98
+ latencyMs,
99
+ tokensIn: 0,
100
+ tokensOut: 0,
101
+ error: err
102
+ };
103
+ }
104
+ }
105
+ function clampScore(score, scorerName) {
106
+ if (score < 0 || score > 1) {
107
+ console.warn(
108
+ `Scorer "${scorerName}" returned out-of-range score ${score}, clamping to 0..1`
109
+ );
110
+ return Math.max(0, Math.min(1, score));
111
+ }
112
+ return score;
113
+ }
114
+ async function runEval(config) {
115
+ const {
116
+ name,
117
+ model,
118
+ dataset: ds,
119
+ task,
120
+ scorers,
121
+ store,
122
+ suiteId,
123
+ maxConcurrency = 10,
124
+ batchSize,
125
+ timeout = 3e4,
126
+ trials = 1,
127
+ threshold = 0.5
128
+ } = config;
129
+ const emitter = config.emitter ?? new EvalEmitter();
130
+ const resolvedSuiteId = suiteId ?? store.createSuite(name).id;
131
+ const runId = store.createRun({
132
+ suite_id: resolvedSuiteId,
133
+ name,
134
+ model,
135
+ config: config.config
136
+ });
137
+ const items = [];
138
+ let idx = 0;
139
+ for await (const item of ds) {
140
+ items.push({ index: idx++, input: item });
141
+ }
142
+ emitter.emit("run:start", { runId, totalCases: items.length, name, model });
143
+ const semaphore = createSemaphore(maxConcurrency);
144
+ const scorerNames = Object.keys(scorers);
145
+ const allCaseScores = [];
146
+ const processItem = async ({ index, input }) => {
147
+ await semaphore.acquire();
148
+ try {
149
+ emitter.emit("case:start", { runId, index, input });
150
+ let finalResult;
151
+ let finalScores;
152
+ if (trials > 1) {
153
+ const trialResults = [];
154
+ for (let t = 0; t < trials; t++) {
155
+ const result = await wrapTask(task, input, timeout);
156
+ if (result.error) {
157
+ trialResults.push({
158
+ result,
159
+ scores: failureScores(scorerNames, result.error)
160
+ });
161
+ } else {
162
+ const scores = {};
163
+ for (const [sName, scorer] of Object.entries(scorers)) {
164
+ const sr = await scorer({
165
+ input,
166
+ output: result.output,
167
+ expected: input.expected
168
+ });
169
+ scores[sName] = {
170
+ score: clampScore(sr.score, sName),
171
+ reason: sr.reason
172
+ };
173
+ }
174
+ trialResults.push({ result, scores });
175
+ }
176
+ }
177
+ const lastSuccessful = [...trialResults].reverse().find((t) => !t.result.error);
178
+ const baseResult = lastSuccessful?.result ?? trialResults[trialResults.length - 1].result;
179
+ finalResult = {
180
+ output: baseResult.output,
181
+ latencyMs: Math.round(
182
+ trialResults.reduce((sum, t) => sum + t.result.latencyMs, 0) / trials
183
+ ),
184
+ tokensIn: Math.round(
185
+ trialResults.reduce((sum, t) => sum + t.result.tokensIn, 0) / trials
186
+ ),
187
+ tokensOut: Math.round(
188
+ trialResults.reduce((sum, t) => sum + t.result.tokensOut, 0) / trials
189
+ ),
190
+ error: lastSuccessful ? void 0 : baseResult.error
191
+ };
192
+ finalScores = {};
193
+ for (const sName of scorerNames) {
194
+ const meanScore = trialResults.reduce((sum, t) => sum + t.scores[sName].score, 0) / trials;
195
+ finalScores[sName] = {
196
+ score: meanScore,
197
+ reason: trialResults[trialResults.length - 1].scores[sName]?.reason
198
+ };
199
+ }
200
+ } else {
201
+ finalResult = await wrapTask(task, input, timeout);
202
+ if (finalResult.error) {
203
+ finalScores = failureScores(scorerNames, finalResult.error);
204
+ } else {
205
+ finalScores = {};
206
+ for (const [sName, scorer] of Object.entries(scorers)) {
207
+ const sr = await scorer({
208
+ input,
209
+ output: finalResult.output,
210
+ expected: input.expected
211
+ });
212
+ finalScores[sName] = {
213
+ score: clampScore(sr.score, sName),
214
+ reason: sr.reason
215
+ };
216
+ }
217
+ }
218
+ }
219
+ const caseId = crypto.randomUUID();
220
+ const caseData = {
221
+ id: caseId,
222
+ run_id: runId,
223
+ idx: index,
224
+ input,
225
+ output: finalResult.output || null,
226
+ expected: input.expected,
227
+ latency_ms: finalResult.latencyMs,
228
+ tokens_in: finalResult.tokensIn,
229
+ tokens_out: finalResult.tokensOut,
230
+ error: finalResult.error ? serializeError(finalResult.error) : void 0
231
+ };
232
+ store.saveCases([caseData]);
233
+ const scoreDataList = scorerNames.map((sName) => ({
234
+ id: crypto.randomUUID(),
235
+ case_id: caseId,
236
+ scorer_name: sName,
237
+ score: finalScores[sName].score,
238
+ reason: finalScores[sName].reason
239
+ }));
240
+ store.saveScores(scoreDataList);
241
+ allCaseScores.push({
242
+ index,
243
+ scores: Object.fromEntries(
244
+ scorerNames.map((sName) => [sName, finalScores[sName].score])
245
+ ),
246
+ latencyMs: finalResult.latencyMs,
247
+ tokensIn: finalResult.tokensIn,
248
+ tokensOut: finalResult.tokensOut
249
+ });
250
+ if (finalResult.error) {
251
+ emitter.emit("case:error", {
252
+ runId,
253
+ index,
254
+ error: errorMessage(finalResult.error)
255
+ });
256
+ }
257
+ emitter.emit("case:scored", {
258
+ runId,
259
+ index,
260
+ input,
261
+ output: finalResult.output,
262
+ expected: input.expected,
263
+ scores: finalScores,
264
+ error: finalResult.error,
265
+ latencyMs: finalResult.latencyMs,
266
+ tokensIn: finalResult.tokensIn,
267
+ tokensOut: finalResult.tokensOut
268
+ });
269
+ } finally {
270
+ semaphore.release();
271
+ }
272
+ };
273
+ const batches = batchSize ? Array.from(
274
+ { length: Math.ceil(items.length / batchSize) },
275
+ (_, i) => items.slice(i * batchSize, (i + 1) * batchSize)
276
+ ) : [items];
277
+ try {
278
+ for (const batch of batches) {
279
+ await Promise.all(batch.map(processItem));
280
+ }
281
+ } catch (err) {
282
+ store.finishRun(runId, "failed");
283
+ throw err;
284
+ }
285
+ const summary = computeSummary(allCaseScores, scorerNames, threshold);
286
+ store.finishRun(runId, "completed", summary);
287
+ emitter.emit("run:end", { runId, summary });
288
+ return summary;
289
+ }
290
+ function computeSummary(cases, scorerNames, threshold) {
291
+ const totalCases = cases.length;
292
+ let passCount = 0;
293
+ let failCount = 0;
294
+ let totalLatencyMs = 0;
295
+ let totalTokensIn = 0;
296
+ let totalTokensOut = 0;
297
+ const scoreSums = {};
298
+ for (const name of scorerNames) {
299
+ scoreSums[name] = 0;
300
+ }
301
+ for (const c of cases) {
302
+ totalLatencyMs += c.latencyMs;
303
+ totalTokensIn += c.tokensIn;
304
+ totalTokensOut += c.tokensOut;
305
+ let allPass = true;
306
+ for (const name of scorerNames) {
307
+ const score = c.scores[name] ?? 0;
308
+ scoreSums[name] += score;
309
+ if (score < threshold) allPass = false;
310
+ }
311
+ if (allPass) passCount++;
312
+ else failCount++;
313
+ }
314
+ const meanScores = {};
315
+ for (const name of scorerNames) {
316
+ meanScores[name] = totalCases > 0 ? scoreSums[name] / totalCases : 0;
317
+ }
318
+ return {
319
+ totalCases,
320
+ passCount,
321
+ failCount,
322
+ meanScores,
323
+ totalLatencyMs,
324
+ totalTokensIn,
325
+ totalTokensOut
326
+ };
327
+ }
328
+ export {
329
+ EvalEmitter,
330
+ runEval
331
+ };
332
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/engine/index.ts"],
4
+ "sourcesContent": ["import { EventEmitter } from 'node:events';\n\nimport type { Scorer, ScorerResult } from '../scorers/index.ts';\nimport type {\n CaseData,\n RunStore,\n RunSummary,\n ScoreData,\n} from '../store/index.ts';\n\nexport interface TaskResult {\n output: string;\n usage?: { inputTokens: number; outputTokens: number };\n}\n\nexport type TaskFn<T> = (input: T) => Promise<TaskResult>;\n\nexport interface EngineEvents {\n 'run:start': {\n runId: string;\n totalCases: number;\n name: string;\n model: string;\n };\n 'case:start': { runId: string; index: number; input: unknown };\n 'case:scored': {\n runId: string;\n index: number;\n input: unknown;\n output: string;\n expected: unknown;\n scores: Record<string, ScorerResult>;\n error?: unknown;\n latencyMs: number;\n tokensIn: number;\n tokensOut: number;\n };\n 'case:error': { runId: string; index: number; error: string };\n 'run:end': { runId: string; summary: RunSummary };\n}\n\nexport class EvalEmitter extends EventEmitter {\n override on<K extends keyof EngineEvents>(\n event: K,\n listener: (data: EngineEvents[K]) => void,\n ): this {\n return super.on(event, listener);\n }\n\n override emit<K extends keyof EngineEvents>(\n event: K,\n data: EngineEvents[K],\n ): boolean {\n return super.emit(event, data);\n }\n}\n\nexport interface EvalConfig<T> {\n name: string;\n model: string;\n dataset: AsyncIterable<T>;\n task: TaskFn<T>;\n scorers: Record<string, Scorer>;\n store: RunStore;\n emitter?: EvalEmitter;\n suiteId?: string;\n config?: Record<string, unknown>;\n maxConcurrency?: number;\n batchSize?: number;\n timeout?: number;\n trials?: number;\n threshold?: number;\n}\n\ninterface WrappedResult {\n output: string;\n latencyMs: number;\n tokensIn: number;\n tokensOut: number;\n error?: unknown;\n}\n\nfunction errorMessage(err: unknown): string {\n if (err instanceof Error) {\n return `${err.name}: ${err.message}`;\n }\n if (typeof err === 'string') return err;\n if (err == null) return 'Unknown error';\n try {\n return JSON.stringify(err);\n } catch {\n return String(err);\n }\n}\n\nfunction serializeError(err: unknown): string {\n if (err instanceof Error) {\n return JSON.stringify({\n name: err.name,\n message: err.message,\n stack: err.stack,\n cause:\n err.cause instanceof Error\n ? {\n name: err.cause.name,\n message: err.cause.message,\n }\n : err.cause,\n });\n }\n if (typeof err === 'string') return JSON.stringify({ message: err });\n if (err == null) return JSON.stringify({ message: 'Unknown error' });\n try {\n return JSON.stringify(err);\n } catch {\n return JSON.stringify({ message: String(err) });\n }\n}\n\nfunction failureScores(\n scorerNames: string[],\n error: unknown,\n): Record<string, ScorerResult> {\n const reason = `Task failed: ${errorMessage(error)}`;\n const scores: Record<string, ScorerResult> = {};\n for (const scorerName of scorerNames) {\n scores[scorerName] = { score: 0, reason };\n }\n return scores;\n}\n\nfunction createSemaphore(maxConcurrency: number) {\n let active = 0;\n const queue: Array<() => void> = [];\n\n return {\n async acquire(): Promise<void> {\n if (active < maxConcurrency) {\n active++;\n return;\n }\n return new Promise<void>((resolve) => queue.push(resolve));\n },\n release(): void {\n active--;\n const next = queue.shift();\n if (next) {\n active++;\n next();\n }\n },\n };\n}\n\nasync function wrapTask<T>(\n task: TaskFn<T>,\n input: T,\n timeoutMs: number,\n): Promise<WrappedResult> {\n const start = performance.now();\n let timerId: ReturnType<typeof setTimeout> | undefined;\n try {\n const result = await Promise.race([\n task(input),\n new Promise<never>((_, reject) => {\n timerId = setTimeout(\n () => reject(new Error('timeout exceeded')),\n timeoutMs,\n );\n }),\n ]);\n clearTimeout(timerId);\n const latencyMs = Math.round(performance.now() - start);\n return {\n output: result.output,\n latencyMs,\n tokensIn: result.usage?.inputTokens ?? 0,\n tokensOut: result.usage?.outputTokens ?? 0,\n };\n } catch (err) {\n clearTimeout(timerId);\n const latencyMs = Math.round(performance.now() - start);\n return {\n output: '',\n latencyMs,\n tokensIn: 0,\n tokensOut: 0,\n error: err,\n };\n }\n}\n\nfunction clampScore(score: number, scorerName: string): number {\n if (score < 0 || score > 1) {\n console.warn(\n `Scorer \"${scorerName}\" returned out-of-range score ${score}, clamping to 0..1`,\n );\n return Math.max(0, Math.min(1, score));\n }\n return score;\n}\n\nexport async function runEval<T>(config: EvalConfig<T>): Promise<RunSummary> {\n const {\n name,\n model,\n dataset: ds,\n task,\n scorers,\n store,\n suiteId,\n maxConcurrency = 10,\n batchSize,\n timeout = 30_000,\n trials = 1,\n threshold = 0.5,\n } = config;\n\n const emitter = config.emitter ?? new EvalEmitter();\n const resolvedSuiteId = suiteId ?? store.createSuite(name).id;\n const runId = store.createRun({\n suite_id: resolvedSuiteId,\n name,\n model,\n config: config.config,\n });\n\n const items: Array<{ index: number; input: T }> = [];\n let idx = 0;\n for await (const item of ds) {\n items.push({ index: idx++, input: item });\n }\n\n emitter.emit('run:start', { runId, totalCases: items.length, name, model });\n\n const semaphore = createSemaphore(maxConcurrency);\n const scorerNames = Object.keys(scorers);\n\n const allCaseScores: Array<{\n index: number;\n scores: Record<string, number>;\n latencyMs: number;\n tokensIn: number;\n tokensOut: number;\n }> = [];\n\n const processItem = async ({ index, input }: { index: number; input: T }) => {\n await semaphore.acquire();\n try {\n emitter.emit('case:start', { runId, index, input });\n\n let finalResult: WrappedResult;\n let finalScores: Record<string, ScorerResult>;\n\n if (trials > 1) {\n const trialResults: Array<{\n result: WrappedResult;\n scores: Record<string, ScorerResult>;\n }> = [];\n\n for (let t = 0; t < trials; t++) {\n const result = await wrapTask(task, input, timeout);\n if (result.error) {\n trialResults.push({\n result,\n scores: failureScores(scorerNames, result.error),\n });\n } else {\n const scores: Record<string, ScorerResult> = {};\n for (const [sName, scorer] of Object.entries(scorers)) {\n const sr = await scorer({\n input,\n output: result.output,\n expected: (input as Record<string, unknown>).expected,\n });\n scores[sName] = {\n score: clampScore(sr.score, sName),\n reason: sr.reason,\n };\n }\n trialResults.push({ result, scores });\n }\n }\n\n const lastSuccessful = [...trialResults]\n .reverse()\n .find((t) => !t.result.error);\n const baseResult =\n lastSuccessful?.result ??\n trialResults[trialResults.length - 1]!.result;\n finalResult = {\n output: baseResult.output,\n latencyMs: Math.round(\n trialResults.reduce((sum, t) => sum + t.result.latencyMs, 0) /\n trials,\n ),\n tokensIn: Math.round(\n trialResults.reduce((sum, t) => sum + t.result.tokensIn, 0) /\n trials,\n ),\n tokensOut: Math.round(\n trialResults.reduce((sum, t) => sum + t.result.tokensOut, 0) /\n trials,\n ),\n error: lastSuccessful ? undefined : baseResult.error,\n };\n\n finalScores = {};\n for (const sName of scorerNames) {\n const meanScore =\n trialResults.reduce((sum, t) => sum + t.scores[sName]!.score, 0) /\n trials;\n finalScores[sName] = {\n score: meanScore,\n reason:\n trialResults[trialResults.length - 1]!.scores[sName]?.reason,\n };\n }\n } else {\n finalResult = await wrapTask(task, input, timeout);\n if (finalResult.error) {\n finalScores = failureScores(scorerNames, finalResult.error);\n } else {\n finalScores = {};\n for (const [sName, scorer] of Object.entries(scorers)) {\n const sr = await scorer({\n input,\n output: finalResult.output,\n expected: (input as Record<string, unknown>).expected,\n });\n finalScores[sName] = {\n score: clampScore(sr.score, sName),\n reason: sr.reason,\n };\n }\n }\n }\n\n const caseId = crypto.randomUUID();\n\n const caseData: CaseData = {\n id: caseId,\n run_id: runId,\n idx: index,\n input,\n output: finalResult.output || null,\n expected: (input as Record<string, unknown>).expected,\n latency_ms: finalResult.latencyMs,\n tokens_in: finalResult.tokensIn,\n tokens_out: finalResult.tokensOut,\n error: finalResult.error\n ? serializeError(finalResult.error)\n : undefined,\n };\n store.saveCases([caseData]);\n\n const scoreDataList: ScoreData[] = scorerNames.map((sName) => ({\n id: crypto.randomUUID(),\n case_id: caseId,\n scorer_name: sName,\n score: finalScores[sName]!.score,\n reason: finalScores[sName]!.reason,\n }));\n store.saveScores(scoreDataList);\n\n allCaseScores.push({\n index,\n scores: Object.fromEntries(\n scorerNames.map((sName) => [sName, finalScores[sName]!.score]),\n ),\n latencyMs: finalResult.latencyMs,\n tokensIn: finalResult.tokensIn,\n tokensOut: finalResult.tokensOut,\n });\n\n if (finalResult.error) {\n emitter.emit('case:error', {\n runId,\n index,\n error: errorMessage(finalResult.error),\n });\n }\n\n emitter.emit('case:scored', {\n runId,\n index,\n input,\n output: finalResult.output,\n expected: (input as Record<string, unknown>).expected,\n scores: finalScores,\n error: finalResult.error,\n latencyMs: finalResult.latencyMs,\n tokensIn: finalResult.tokensIn,\n tokensOut: finalResult.tokensOut,\n });\n } finally {\n semaphore.release();\n }\n };\n\n const batches = batchSize\n ? Array.from({ length: Math.ceil(items.length / batchSize) }, (_, i) =>\n items.slice(i * batchSize, (i + 1) * batchSize),\n )\n : [items];\n\n try {\n for (const batch of batches) {\n await Promise.all(batch.map(processItem));\n }\n } catch (err) {\n store.finishRun(runId, 'failed');\n throw err;\n }\n\n const summary = computeSummary(allCaseScores, scorerNames, threshold);\n store.finishRun(runId, 'completed', summary);\n emitter.emit('run:end', { runId, summary });\n\n return summary;\n}\n\nfunction computeSummary(\n cases: Array<{\n index: number;\n scores: Record<string, number>;\n latencyMs: number;\n tokensIn: number;\n tokensOut: number;\n }>,\n scorerNames: string[],\n threshold: number,\n): RunSummary {\n const totalCases = cases.length;\n let passCount = 0;\n let failCount = 0;\n let totalLatencyMs = 0;\n let totalTokensIn = 0;\n let totalTokensOut = 0;\n\n const scoreSums: Record<string, number> = {};\n for (const name of scorerNames) {\n scoreSums[name] = 0;\n }\n\n for (const c of cases) {\n totalLatencyMs += c.latencyMs;\n totalTokensIn += c.tokensIn;\n totalTokensOut += c.tokensOut;\n\n let allPass = true;\n for (const name of scorerNames) {\n const score = c.scores[name] ?? 0;\n scoreSums[name]! += score;\n if (score < threshold) allPass = false;\n }\n if (allPass) passCount++;\n else failCount++;\n }\n\n const meanScores: Record<string, number> = {};\n for (const name of scorerNames) {\n meanScores[name] = totalCases > 0 ? scoreSums[name]! / totalCases : 0;\n }\n\n return {\n totalCases,\n passCount,\n failCount,\n meanScores,\n totalLatencyMs,\n totalTokensIn,\n totalTokensOut,\n };\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,47 @@
1
+ import type { TaskFn, TaskResult } from '../engine/index.ts';
2
+ import type { Reporter } from '../reporters/index.ts';
3
+ import type { Scorer } from '../scorers/index.ts';
4
+ import type { RunSummary } from '../store/index.ts';
5
+ import { RunStore } from '../store/index.ts';
6
+ interface BaseEvalOptions<T> {
7
+ /** Human-readable name for this evaluation run, used in reports and filenames. */
8
+ name: string;
9
+ /** The dataset of input/expected pairs to evaluate against. */
10
+ dataset: AsyncIterable<T>;
11
+ /** Named scoring functions that assess model output quality. Each key becomes a column in reports. */
12
+ scorers: Record<string, Scorer>;
13
+ /** Reporters that receive lifecycle events and produce output (console, JSON, CSV, etc.). */
14
+ reporters: Reporter[];
15
+ /** Persistent store for run history. Accepts a `RunStore` instance or a file path for SQLite storage. */
16
+ store?: RunStore | string;
17
+ /** Maximum number of dataset cases to run concurrently. Defaults to unbounded. */
18
+ maxConcurrency?: number;
19
+ /** Per-case timeout in milliseconds before the case is marked as failed. */
20
+ timeout?: number;
21
+ /** Number of times to run each case and average the scores. Useful for reducing LLM variance. */
22
+ trials?: number;
23
+ /** Minimum average score (0–1) required to consider the run passing. Defaults to `0.5`. */
24
+ threshold?: number;
25
+ }
26
+ export interface EvaluateOptions<T> extends BaseEvalOptions<T> {
27
+ /** The model identifier passed to the task function. */
28
+ model: string;
29
+ /** Function that calls the model under evaluation and returns its output for a single dataset item. */
30
+ task: TaskFn<T>;
31
+ /** Associates this run with an existing suite ID for grouped comparisons. */
32
+ suiteId?: string;
33
+ }
34
+ export interface EvaluateEachOptions<T, V extends {
35
+ name: string;
36
+ }> extends BaseEvalOptions<T> {
37
+ /** List of model variants to evaluate. Each variant runs the full dataset independently. */
38
+ models: V[];
39
+ /** Function that calls the model under evaluation for a given dataset item and model variant. */
40
+ task: (input: T, variant: V) => Promise<TaskResult>;
41
+ }
42
+ export declare function evaluate<T>(options: EvaluateOptions<T>): Promise<RunSummary>;
43
+ export declare function evaluate<T, V extends {
44
+ name: string;
45
+ }>(options: EvaluateEachOptions<T, V>): Promise<RunSummary[]>;
46
+ export {};
47
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/evaluate/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAE7D,OAAO,KAAK,EAAc,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE7C,UAAU,eAAe,CAAC,CAAC;IACzB,kFAAkF;IAClF,IAAI,EAAE,MAAM,CAAC;IACb,+DAA+D;IAC/D,OAAO,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;IAC1B,sGAAsG;IACtG,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,6FAA6F;IAC7F,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,yGAAyG;IACzG,KAAK,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IAC1B,kFAAkF;IAClF,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iGAAiG;IACjG,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2FAA2F;IAC3F,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe,CAAC,CAAC,CAAE,SAAQ,eAAe,CAAC,CAAC,CAAC;IAC5D,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAC;IACd,uGAAuG;IACvG,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IAChB,6EAA6E;IAC7E,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB,CAClC,CAAC,EACD,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAC1B,SAAQ,eAAe,CAAC,CAAC,CAAC;IAC1B,4FAA4F;IAC5F,MAAM,EAAE,CAAC,EAAE,CAAC;IACZ,iGAAiG;IACjG,IAAI,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;CACrD;AAED,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AAC9E,wBAAgB,QAAQ,CAAC,CAAC,EAAE,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EACpD,OAAO,EAAE,mBAAmB,CAAC,CAAC,EAAE,CAAC,CAAC,GACjC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC"}