@cogitator-ai/evals 0.12.0 → 0.13.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 (72) hide show
  1. package/README.md +75 -26
  2. package/dist/comparison-stats.d.ts +104 -0
  3. package/dist/comparison-stats.d.ts.map +1 -0
  4. package/dist/comparison-stats.js +179 -0
  5. package/dist/comparison-stats.js.map +1 -0
  6. package/dist/eval-comparison.d.ts +2 -51
  7. package/dist/eval-comparison.d.ts.map +1 -1
  8. package/dist/eval-comparison.js +12 -149
  9. package/dist/eval-comparison.js.map +1 -1
  10. package/dist/eval-suite.d.ts +33 -0
  11. package/dist/eval-suite.d.ts.map +1 -1
  12. package/dist/eval-suite.js +81 -2
  13. package/dist/eval-suite.js.map +1 -1
  14. package/dist/index.d.ts +5 -1
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +2 -0
  17. package/dist/index.js.map +1 -1
  18. package/dist/metrics/types.d.ts +25 -0
  19. package/dist/metrics/types.d.ts.map +1 -1
  20. package/dist/metrics/types.js.map +1 -1
  21. package/dist/reporters/comparison.d.ts +24 -0
  22. package/dist/reporters/comparison.d.ts.map +1 -0
  23. package/dist/reporters/comparison.js +290 -0
  24. package/dist/reporters/comparison.js.map +1 -0
  25. package/dist/reporters/format.d.ts +21 -0
  26. package/dist/reporters/format.d.ts.map +1 -1
  27. package/dist/reporters/format.js +31 -0
  28. package/dist/reporters/format.js.map +1 -1
  29. package/dist/reporters/github.d.ts.map +1 -1
  30. package/dist/reporters/github.js +1 -16
  31. package/dist/reporters/github.js.map +1 -1
  32. package/dist/reporters/html-format.d.ts +11 -0
  33. package/dist/reporters/html-format.d.ts.map +1 -0
  34. package/dist/reporters/html-format.js +111 -0
  35. package/dist/reporters/html-format.js.map +1 -0
  36. package/dist/reporters/html.d.ts +12 -0
  37. package/dist/reporters/html.d.ts.map +1 -0
  38. package/dist/reporters/html.js +119 -0
  39. package/dist/reporters/html.js.map +1 -0
  40. package/dist/reporters/index.d.ts +20 -6
  41. package/dist/reporters/index.d.ts.map +1 -1
  42. package/dist/reporters/index.js +15 -4
  43. package/dist/reporters/index.js.map +1 -1
  44. package/dist/reporters/markdown.d.ts +15 -0
  45. package/dist/reporters/markdown.d.ts.map +1 -0
  46. package/dist/reporters/markdown.js +67 -0
  47. package/dist/reporters/markdown.js.map +1 -0
  48. package/dist/runs/compare.d.ts +103 -0
  49. package/dist/runs/compare.d.ts.map +1 -0
  50. package/dist/runs/compare.js +208 -0
  51. package/dist/runs/compare.js.map +1 -0
  52. package/dist/runs/index.d.ts +9 -0
  53. package/dist/runs/index.d.ts.map +1 -0
  54. package/dist/runs/index.js +5 -0
  55. package/dist/runs/index.js.map +1 -0
  56. package/dist/runs/json.d.ts +11 -0
  57. package/dist/runs/json.d.ts.map +1 -0
  58. package/dist/runs/json.js +58 -0
  59. package/dist/runs/json.js.map +1 -0
  60. package/dist/runs/run.d.ts +44 -0
  61. package/dist/runs/run.d.ts.map +1 -0
  62. package/dist/runs/run.js +136 -0
  63. package/dist/runs/run.js.map +1 -0
  64. package/dist/runs/schema.d.ts +504 -0
  65. package/dist/runs/schema.d.ts.map +1 -0
  66. package/dist/runs/schema.js +171 -0
  67. package/dist/runs/schema.js.map +1 -0
  68. package/dist/runs/store.d.ts +57 -0
  69. package/dist/runs/store.d.ts.map +1 -0
  70. package/dist/runs/store.js +146 -0
  71. package/dist/runs/store.js.map +1 -0
  72. package/package.json +1 -1
@@ -0,0 +1,208 @@
1
+ import { z } from 'zod';
2
+ import { parseOptions } from '../options.js';
3
+ import { caseChanges, compareMetrics, determineOverallWinner, pairedScores, scoredMetricNames, } from '../comparison-stats.js';
4
+ import { truncateInput } from '../reporters/format.js';
5
+ import { canonicalJson } from './json.js';
6
+ import { runOf } from './run.js';
7
+ export const CompareRunsOptionsSchema = z.object({
8
+ alpha: z.number().gt(0).lt(1).default(0.05),
9
+ test: z.enum(['t', 'wilcoxon']).default('t'),
10
+ seed: z.union([z.number(), z.string()]).optional(),
11
+ metrics: z.array(z.string().min(1)).min(1).optional(),
12
+ });
13
+ const WINNERS = {
14
+ baseline: 'base',
15
+ challenger: 'head',
16
+ tie: 'tie',
17
+ };
18
+ function refOf(run) {
19
+ return {
20
+ runId: run.runId,
21
+ ...(run.name !== undefined && { name: run.name }),
22
+ startedAt: run.startedAt,
23
+ };
24
+ }
25
+ function caseRef(result) {
26
+ return { caseKey: result.caseKey, input: truncateInput(result.case.input) };
27
+ }
28
+ /**
29
+ * Pairs the cases of the runs by `caseKey`, in the order of the base run. A key that repeats pairs
30
+ * its first case of one run with its first case of the other, its second with the second, and so on
31
+ */
32
+ function matchCases(base, head) {
33
+ const headByKey = new Map();
34
+ for (const result of head.results) {
35
+ const list = headByKey.get(result.caseKey);
36
+ if (list)
37
+ list.push(result);
38
+ else
39
+ headByKey.set(result.caseKey, [result]);
40
+ }
41
+ const pairs = [];
42
+ const removed = [];
43
+ for (const result of base.results) {
44
+ const match = headByKey.get(result.caseKey)?.shift();
45
+ if (match)
46
+ pairs.push([result, match]);
47
+ else
48
+ removed.push(caseRef(result));
49
+ }
50
+ const added = [...headByKey.values()].flat();
51
+ const addedSet = new Set(added);
52
+ return {
53
+ pairs,
54
+ removed,
55
+ added: head.results.filter((result) => addedSet.has(result)).map(caseRef),
56
+ };
57
+ }
58
+ /** The per-case metrics of a run: those it was set up with and those its cases were scored on */
59
+ function caseMetricNames(run) {
60
+ return new Set([...run.config.metrics, ...scoredMetricNames(run.results)]);
61
+ }
62
+ function metricsToCompare(base, head, requested) {
63
+ const baseNames = caseMetricNames(base);
64
+ const headNames = caseMetricNames(head);
65
+ const shared = [...baseNames].filter((name) => headNames.has(name));
66
+ if (requested === undefined)
67
+ return shared;
68
+ const missing = requested.filter((name) => !shared.includes(name));
69
+ if (missing.length > 0) {
70
+ throw new Error(`compareRuns: ${missing.map((name) => `'${name}'`).join(', ')} not in both runs, the base run has ${[...baseNames].join(', ') || 'no metrics'} and the head run ${[...headNames].join(', ') || 'no metrics'}`);
71
+ }
72
+ return [...new Set(requested)];
73
+ }
74
+ function promptLabel(prompt) {
75
+ if (prompt.abTest)
76
+ return `A/B test ${prompt.abTest.id} (${prompt.abTest.variant})`;
77
+ if (prompt.version !== undefined) {
78
+ return prompt.versionId !== undefined
79
+ ? `v${prompt.version} (${prompt.versionId})`
80
+ : `v${prompt.version}`;
81
+ }
82
+ return prompt.versionId ?? 'unversioned instructions';
83
+ }
84
+ function promptsByKey(run) {
85
+ const byKey = new Map();
86
+ for (const prompt of run.prompts) {
87
+ const labels = byKey.get(prompt.key) ?? new Map();
88
+ labels.set(canonicalJson(prompt), promptLabel(prompt));
89
+ byKey.set(prompt.key, labels);
90
+ }
91
+ return byKey;
92
+ }
93
+ function promptWarnings(base, head) {
94
+ const baseKeys = promptsByKey(base);
95
+ const headKeys = promptsByKey(head);
96
+ const warnings = [];
97
+ for (const key of new Set([...baseKeys.keys(), ...headKeys.keys()])) {
98
+ const before = baseKeys.get(key);
99
+ const after = headKeys.get(key);
100
+ const list = (labels) => [...labels.values()].join(', ');
101
+ if (!before) {
102
+ warnings.push(`Prompt '${key}' is used by the head run only (${list(after)})`);
103
+ }
104
+ else if (!after) {
105
+ warnings.push(`Prompt '${key}' is used by the base run only (${list(before)})`);
106
+ }
107
+ else if (before.size !== after.size ||
108
+ [...before.keys()].some((identity) => !after.has(identity))) {
109
+ warnings.push(`Prompt '${key}' differs: the base run used ${list(before)}, the head run ${list(after)}`);
110
+ }
111
+ }
112
+ return warnings;
113
+ }
114
+ function difference(label, base, head) {
115
+ const onlyBase = base.filter((name) => !head.includes(name));
116
+ const onlyHead = head.filter((name) => !base.includes(name));
117
+ if (onlyBase.length === 0 && onlyHead.length === 0)
118
+ return undefined;
119
+ const parts = [
120
+ ...(onlyBase.length > 0 ? [`only the base run has ${onlyBase.join(', ')}`] : []),
121
+ ...(onlyHead.length > 0 ? [`only the head run has ${onlyHead.join(', ')}`] : []),
122
+ ];
123
+ return `${label} differ: ${parts.join(', ')}`;
124
+ }
125
+ function judgeLabel(judge) {
126
+ if (!judge)
127
+ return 'no judge';
128
+ const samples = judge.samples !== undefined ? `, ${judge.samples} samples` : '';
129
+ return `${judge.model} at temperature ${judge.temperature}${samples}`;
130
+ }
131
+ function configWarnings(base, head) {
132
+ const warnings = [];
133
+ const metrics = difference('Metrics', [...base.config.metrics, ...base.config.statisticalMetrics], [...head.config.metrics, ...head.config.statisticalMetrics]);
134
+ if (metrics)
135
+ warnings.push(metrics);
136
+ if (canonicalJson(base.config.judge ?? null) !== canonicalJson(head.config.judge ?? null)) {
137
+ warnings.push(`Judge differs: the base run used ${judgeLabel(base.config.judge)}, the head run ${judgeLabel(head.config.judge)}`);
138
+ }
139
+ return warnings;
140
+ }
141
+ function datasetWarning(base, head, added, removed) {
142
+ if (base.dataset.fingerprint === head.dataset.fingerprint)
143
+ return undefined;
144
+ if (added === 0 && removed === 0) {
145
+ return 'The datasets differ (fingerprints differ) while every case matches by input, turns and expected answer: their order, context or metadata changed';
146
+ }
147
+ return `The datasets differ (fingerprints differ): ${added} cases only in the head run, ${removed} only in the base run`;
148
+ }
149
+ /**
150
+ * Compares two saved runs, or suite results, case by case: cases are matched by their `caseKey`,
151
+ * and each metric both runs have is compared as `EvalComparison` compares its sides, the base run
152
+ * in the baseline's place and the head run in the challenger's
153
+ */
154
+ export function compareRuns(baseSource, headSource, options = {}) {
155
+ const config = parseOptions(CompareRunsOptionsSchema, options, 'compareRuns');
156
+ const base = runOf(baseSource);
157
+ const head = runOf(headSource);
158
+ const { pairs, added, removed } = matchCases(base, head);
159
+ const paired = new Map();
160
+ const unscored = [];
161
+ for (const name of metricsToCompare(base, head, config.metrics)) {
162
+ const scores = pairedScores(pairs, name);
163
+ if (scores[0].length === 0 && config.metrics === undefined)
164
+ unscored.push(name);
165
+ else
166
+ paired.set(name, scores);
167
+ }
168
+ const names = [...paired.keys()];
169
+ const compared = compareMetrics(paired, config);
170
+ const metrics = {};
171
+ for (const name of names) {
172
+ const { baseline, challenger, winner, ...stats } = compared[name];
173
+ const changes = caseChanges(pairs, name, (index) => pairs[index][0].case.input);
174
+ const toRunChange = (change) => ({
175
+ caseKey: pairs[change.index][0].caseKey,
176
+ input: change.input,
177
+ base: change.before,
178
+ head: change.after,
179
+ delta: change.delta,
180
+ });
181
+ metrics[name] = {
182
+ base: baseline,
183
+ head: challenger,
184
+ ...stats,
185
+ winner: WINNERS[winner],
186
+ improved: changes.improved.map(toRunChange),
187
+ regressed: changes.regressed.map(toRunChange),
188
+ };
189
+ }
190
+ const dataset = datasetWarning(base, head, added.length, removed.length);
191
+ const warnings = [
192
+ ...(dataset ? [dataset] : []),
193
+ ...promptWarnings(base, head),
194
+ ...configWarnings(base, head),
195
+ ...unscored.map((name) => `Metric '${name}' was scored on no case the runs share (every case errored or went unscored), so it is not compared`),
196
+ ];
197
+ return {
198
+ base: refOf(base),
199
+ head: refOf(head),
200
+ winner: WINNERS[determineOverallWinner(compared)],
201
+ metrics,
202
+ matched: pairs.length,
203
+ added,
204
+ removed,
205
+ warnings,
206
+ };
207
+ }
208
+ //# sourceMappingURL=compare.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compare.js","sourceRoot":"","sources":["../../src/runs/compare.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export { loadRun, caseKey } from './run.js';
2
+ export type { EvalRunSource } from './run.js';
3
+ export { RunStore } from './store.js';
4
+ export type { RunSummary, RunFilter, RunStoreOptions, SkippedRunFile } from './store.js';
5
+ export { compareRuns } from './compare.js';
6
+ export type { CompareRunsOptions, RunComparison, RunMetricComparison, RunCaseChange, RunCaseRef, RunRef, RunWinner, } from './compare.js';
7
+ export { EvalRunSchema, EVAL_RUN_FORMAT, EVAL_RUN_VERSION } from './schema.js';
8
+ export type { EvalRun, EvalRunCase, EvalRunConfig, JsonMetadata } from './schema.js';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/runs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AACzC,YAAY,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACtF,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,YAAY,EACV,kBAAkB,EAClB,aAAa,EACb,mBAAmB,EACnB,aAAa,EACb,UAAU,EACV,MAAM,EACN,SAAS,GACV,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5E,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,5 @@
1
+ export { loadRun, caseKey } from './run.js';
2
+ export { RunStore } from './store.js';
3
+ export { compareRuns } from './compare.js';
4
+ export { EvalRunSchema, EVAL_RUN_FORMAT, EVAL_RUN_VERSION } from './schema.js';
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/runs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAEzC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEnC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAUxC,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * A value as JSON keeps it, as `JSON.stringify` would write it (`toJSON` called once per value),
3
+ * except that a bigint becomes its
4
+ * decimal string and a circular reference the string `[Circular]` instead of throwing
5
+ */
6
+ export declare function toJson(value: unknown): unknown;
7
+ /** JSON of a value with the keys of every object sorted, the same text for the same data */
8
+ export declare function canonicalJson(value: unknown): string;
9
+ /** Hex SHA-256 of the canonical JSON of a value */
10
+ export declare function fingerprint(value: unknown): string;
11
+ //# sourceMappingURL=json.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../src/runs/json.ts"],"names":[],"mappings":"AA8CA;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAE9C;AAED,4FAA4F;AAC5F,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEpD;AAED,mDAAmD;AACnD,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAElD"}
@@ -0,0 +1,58 @@
1
+ import { createHash } from 'node:crypto';
2
+ function hasToJson(value) {
3
+ return typeof value.toJSON === 'function';
4
+ }
5
+ function convert(value, key, ancestors, sortKeys, calledToJson = false) {
6
+ if (value === null)
7
+ return null;
8
+ switch (typeof value) {
9
+ case 'string':
10
+ case 'boolean':
11
+ return value;
12
+ case 'number':
13
+ return Number.isFinite(value) ? value : null;
14
+ case 'bigint':
15
+ return value.toString();
16
+ case 'undefined':
17
+ case 'function':
18
+ case 'symbol':
19
+ return undefined;
20
+ }
21
+ const object = value;
22
+ if (!calledToJson && hasToJson(object)) {
23
+ return convert(object.toJSON(key), key, ancestors, sortKeys, true);
24
+ }
25
+ if (ancestors.includes(object))
26
+ return '[Circular]';
27
+ const nested = [...ancestors, object];
28
+ if (Array.isArray(object)) {
29
+ return object.map((item, at) => convert(item, String(at), nested, sortKeys) ?? null);
30
+ }
31
+ const keys = Object.keys(object);
32
+ if (sortKeys)
33
+ keys.sort();
34
+ const out = {};
35
+ for (const name of keys) {
36
+ const converted = convert(object[name], name, nested, sortKeys);
37
+ if (converted !== undefined)
38
+ out[name] = converted;
39
+ }
40
+ return out;
41
+ }
42
+ /**
43
+ * A value as JSON keeps it, as `JSON.stringify` would write it (`toJSON` called once per value),
44
+ * except that a bigint becomes its
45
+ * decimal string and a circular reference the string `[Circular]` instead of throwing
46
+ */
47
+ export function toJson(value) {
48
+ return convert(value, '', [], false);
49
+ }
50
+ /** JSON of a value with the keys of every object sorted, the same text for the same data */
51
+ export function canonicalJson(value) {
52
+ return JSON.stringify(convert(value, '', [], true) ?? null);
53
+ }
54
+ /** Hex SHA-256 of the canonical JSON of a value */
55
+ export function fingerprint(value) {
56
+ return createHash('sha256').update(canonicalJson(value)).digest('hex');
57
+ }
58
+ //# sourceMappingURL=json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json.js","sourceRoot":"","sources":["../../src/runs/json.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,SAAS,SAAS,CAAC,KAAa;IAC9B,OAAO,OAAQ,KAA8B,CAAC,MAAM,KAAK,UAAU,CAAC;AACtE,CAAC;AAED,SAAS,OAAO,CACd,KAAc,EACd,GAAW,EACX,SAAmB,EACnB,QAAiB,EACjB,YAAY,GAAG,KAAK;IAEpB,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAChC,QAAQ,OAAO,KAAK,EAAE,CAAC;QACrB,KAAK,QAAQ,CAAC;QACd,KAAK,SAAS;YACZ,OAAO,KAAK,CAAC;QACf,KAAK,QAAQ;YACX,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;QAC/C,KAAK,QAAQ;YACX,OAAO,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC1B,KAAK,WAAW,CAAC;QACjB,KAAK,UAAU,CAAC;QAChB,KAAK,QAAQ;YACX,OAAO,SAAS,CAAC;IACrB,CAAC;IACD,MAAM,MAAM,GAAG,KAAe,CAAC;IAC/B,IAAI,CAAC,YAAY,IAAI,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;QACvC,OAAO,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;IACrE,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,YAAY,CAAC;IACpD,MAAM,MAAM,GAAG,CAAC,GAAG,SAAS,EAAE,MAAM,CAAC,CAAC;IACtC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,IAAI,IAAI,CAAC,CAAC;IACvF,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACjC,IAAI,QAAQ;QAAE,IAAI,CAAC,IAAI,EAAE,CAAC;IAC1B,MAAM,GAAG,GAA4B,EAAE,CAAC;IACxC,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;QACxB,MAAM,SAAS,GAAG,OAAO,CAAE,MAAkC,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;QAC7F,IAAI,SAAS,KAAK,SAAS;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC;IACrD,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,MAAM,CAAC,KAAc;IACnC,OAAO,OAAO,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;AACvC,CAAC;AAED,4FAA4F;AAC5F,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC;AAC9D,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACzE,CAAC"}
@@ -0,0 +1,44 @@
1
+ import type { EvalCase } from '../schema.js';
2
+ import type { ScoredCaseResult } from '../metrics/types.js';
3
+ import type { AggregatedMetric, AssertionResult } from '../assertions/index.js';
4
+ import type { EvalRun, EvalRunConfig, JsonMetadata } from './schema.js';
5
+ /** A saved run, or a suite result that turns into one */
6
+ export type EvalRunSource = EvalRun | {
7
+ toRun(): EvalRun;
8
+ };
9
+ /** Everything a run file records of a finished suite run */
10
+ export interface RunRecord {
11
+ runId: string;
12
+ startedAt: Date;
13
+ finishedAt: Date;
14
+ name?: string;
15
+ metadata?: JsonMetadata;
16
+ cases: readonly EvalCase[];
17
+ config: EvalRunConfig;
18
+ results: readonly ScoredCaseResult[];
19
+ aggregated: Record<string, AggregatedMetric>;
20
+ assertions: readonly AssertionResult[];
21
+ stats: EvalRun['stats'];
22
+ }
23
+ /** A run id that sorts by start time: `20261022T101530123Z-1a2b3c4d` */
24
+ export declare function newRunId(startedAt: Date): string;
25
+ /** The stable key a case is matched by across runs: its input, turns and expected answer */
26
+ export declare function caseKey(evalCase: Pick<EvalCase, 'input' | 'turns' | 'expected'>): string;
27
+ /** The run file of a finished suite run, every value as JSON keeps it */
28
+ export declare function buildRun(record: RunRecord): EvalRun;
29
+ /** The run of a source: the run itself, or a suite result's `toRun()` */
30
+ export declare function runOf(source: EvalRunSource): EvalRun;
31
+ /**
32
+ * Validates a parsed run file. Throws naming `origin` when it is not a run file, when it is of
33
+ * another format version, or when a field does not fit the format
34
+ */
35
+ export declare function parseRun(value: unknown, origin: string): EvalRun;
36
+ /** Reads and validates a run file written by `result.saveRun()` or a `RunStore` */
37
+ export declare function loadRun(path: string): EvalRun;
38
+ /**
39
+ * Validates a run, so its id can never lead outside the directory, then writes its run file
40
+ * and returns its path: `<target>/<runId>.json` when `target` is a directory
41
+ * or ends with a path separator, `target` itself otherwise. Missing directories are created
42
+ */
43
+ export declare function writeRun(run: EvalRun, target: string): string;
44
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/runs/run.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,KAAK,EAAc,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAGvE,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAGrE,yDAAyD;AACzD,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG;IAAE,KAAK,IAAI,OAAO,CAAA;CAAE,CAAC;AAE3D,4DAA4D;AAC5D,MAAM,WAAW,SAAS;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,IAAI,CAAC;IAChB,UAAU,EAAE,IAAI,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,KAAK,EAAE,SAAS,QAAQ,EAAE,CAAC;IAC3B,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACrC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAC7C,UAAU,EAAE,SAAS,eAAe,EAAE,CAAC;IACvC,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;CACzB;AAED,wEAAwE;AACxE,wBAAgB,QAAQ,CAAC,SAAS,EAAE,IAAI,GAAG,MAAM,CAGhD;AAED,4FAA4F;AAC5F,wBAAgB,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,GAAG,UAAU,CAAC,GAAG,MAAM,CAExF;AA0BD,yEAAyE;AACzE,wBAAgB,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAuBnD;AAED,yEAAyE;AACzE,wBAAgB,KAAK,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAIpD;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAgBhE;AAED,mFAAmF;AACnF,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAc7C;AAUD;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAiB7D"}
@@ -0,0 +1,136 @@
1
+ import { randomBytes } from 'node:crypto';
2
+ import { mkdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from 'node:fs';
3
+ import { dirname, join, sep } from 'node:path';
4
+ import { canonicalJson, fingerprint, toJson } from './json.js';
5
+ import { EVAL_RUN_FORMAT, EVAL_RUN_VERSION, EvalRunSchema } from './schema.js';
6
+ /** A run id that sorts by start time: `20261022T101530123Z-1a2b3c4d` */
7
+ export function newRunId(startedAt) {
8
+ const stamp = startedAt.toISOString().replace(/[-:.]/g, '');
9
+ return `${stamp}-${randomBytes(4).toString('hex')}`;
10
+ }
11
+ /** The stable key a case is matched by across runs: its input, turns and expected answer */
12
+ export function caseKey(evalCase) {
13
+ return fingerprint({ input: evalCase.input, turns: evalCase.turns, expected: evalCase.expected });
14
+ }
15
+ /** The distinct versioned instructions the runs of the cases used, in the order first seen */
16
+ function promptsUsed(results) {
17
+ const seen = new Map();
18
+ const add = (prompt) => {
19
+ if (prompt)
20
+ seen.set(canonicalJson(prompt), prompt);
21
+ };
22
+ for (const result of results) {
23
+ for (const trial of result.trials ?? [result]) {
24
+ add(trial.prompt);
25
+ for (const turn of trial.turns ?? [])
26
+ add(turn.prompt);
27
+ }
28
+ }
29
+ return [...seen.values()];
30
+ }
31
+ function issuesOf(error) {
32
+ return error.issues
33
+ .slice(0, 5)
34
+ .map((issue) => issue.path.length > 0 ? `${issue.path.join('.')}: ${issue.message}` : issue.message)
35
+ .join(', ');
36
+ }
37
+ /** The run file of a finished suite run, every value as JSON keeps it */
38
+ export function buildRun(record) {
39
+ const { results } = record;
40
+ const draft = {
41
+ format: EVAL_RUN_FORMAT,
42
+ version: EVAL_RUN_VERSION,
43
+ runId: record.runId,
44
+ startedAt: record.startedAt.toISOString(),
45
+ finishedAt: record.finishedAt.toISOString(),
46
+ name: record.name,
47
+ metadata: record.metadata,
48
+ dataset: { fingerprint: fingerprint(record.cases), cases: record.cases.length },
49
+ config: record.config,
50
+ prompts: promptsUsed(results),
51
+ results: results.map((result) => ({ ...result, caseKey: caseKey(result.case) })),
52
+ aggregated: record.aggregated,
53
+ assertions: record.assertions,
54
+ stats: record.stats,
55
+ };
56
+ const parsed = EvalRunSchema.safeParse(toJson(draft));
57
+ if (!parsed.success) {
58
+ throw new Error(`Cannot record the run: ${issuesOf(parsed.error)}`);
59
+ }
60
+ return parsed.data;
61
+ }
62
+ /** The run of a source: the run itself, or a suite result's `toRun()` */
63
+ export function runOf(source) {
64
+ return 'toRun' in source && typeof source.toRun === 'function'
65
+ ? source.toRun()
66
+ : source;
67
+ }
68
+ /**
69
+ * Validates a parsed run file. Throws naming `origin` when it is not a run file, when it is of
70
+ * another format version, or when a field does not fit the format
71
+ */
72
+ export function parseRun(value, origin) {
73
+ const head = typeof value === 'object' && value !== null ? value : {};
74
+ if (head.format !== EVAL_RUN_FORMAT) {
75
+ throw new Error(`${origin} is not an eval run file: its format is not '${EVAL_RUN_FORMAT}'`);
76
+ }
77
+ if (head.version !== EVAL_RUN_VERSION) {
78
+ throw new Error(`${origin} is an eval run file of version ${String(head.version)}, this version of @cogitator-ai/evals reads version ${EVAL_RUN_VERSION}`);
79
+ }
80
+ const parsed = EvalRunSchema.safeParse(value);
81
+ if (!parsed.success) {
82
+ throw new Error(`${origin} is not a valid eval run file: ${issuesOf(parsed.error)}`);
83
+ }
84
+ return parsed.data;
85
+ }
86
+ /** Reads and validates a run file written by `result.saveRun()` or a `RunStore` */
87
+ export function loadRun(path) {
88
+ let text;
89
+ try {
90
+ text = readFileSync(path, 'utf-8');
91
+ }
92
+ catch (error) {
93
+ throw new Error(`Cannot read the run file ${path}`, { cause: error });
94
+ }
95
+ let value;
96
+ try {
97
+ value = JSON.parse(text);
98
+ }
99
+ catch (error) {
100
+ throw new Error(`${path} is not JSON`, { cause: error });
101
+ }
102
+ return parseRun(value, path);
103
+ }
104
+ function isDirectory(path) {
105
+ try {
106
+ return statSync(path).isDirectory();
107
+ }
108
+ catch {
109
+ return false;
110
+ }
111
+ }
112
+ /**
113
+ * Validates a run, so its id can never lead outside the directory, then writes its run file
114
+ * and returns its path: `<target>/<runId>.json` when `target` is a directory
115
+ * or ends with a path separator, `target` itself otherwise. Missing directories are created
116
+ */
117
+ export function writeRun(run, target) {
118
+ const checked = EvalRunSchema.safeParse(toJson(run));
119
+ if (!checked.success) {
120
+ throw new Error(`Cannot write the run: ${issuesOf(checked.error)}`);
121
+ }
122
+ const intoDirectory = target.endsWith('/') || target.endsWith(sep) || isDirectory(target);
123
+ const path = intoDirectory ? join(target, `${checked.data.runId}.json`) : target;
124
+ mkdirSync(dirname(path), { recursive: true });
125
+ const partial = `${path}.${randomBytes(6).toString('hex')}.tmp`;
126
+ try {
127
+ writeFileSync(partial, `${JSON.stringify(checked.data, null, 2)}\n`, 'utf-8');
128
+ renameSync(partial, path);
129
+ }
130
+ catch (error) {
131
+ rmSync(partial, { force: true });
132
+ throw error;
133
+ }
134
+ return path;
135
+ }
136
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/runs/run.ts"],"names":[],"mappings":"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"}