@cogitator-ai/evals 0.10.0 → 0.12.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 (97) hide show
  1. package/README.md +91 -15
  2. package/dist/calibrate-judge.d.ts +53 -0
  3. package/dist/calibrate-judge.d.ts.map +1 -0
  4. package/dist/calibrate-judge.js +114 -0
  5. package/dist/calibrate-judge.js.map +1 -0
  6. package/dist/datasets/dataset.d.ts.map +1 -1
  7. package/dist/datasets/dataset.js +3 -27
  8. package/dist/datasets/dataset.js.map +1 -1
  9. package/dist/eval-comparison.d.ts +71 -2
  10. package/dist/eval-comparison.d.ts.map +1 -1
  11. package/dist/eval-comparison.js +149 -42
  12. package/dist/eval-comparison.js.map +1 -1
  13. package/dist/index.d.ts +17 -5
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +9 -2
  16. package/dist/index.js.map +1 -1
  17. package/dist/metrics/deterministic.d.ts +1 -0
  18. package/dist/metrics/deterministic.d.ts.map +1 -1
  19. package/dist/metrics/deterministic.js +49 -4
  20. package/dist/metrics/deterministic.js.map +1 -1
  21. package/dist/metrics/g-eval.d.ts +29 -0
  22. package/dist/metrics/g-eval.d.ts.map +1 -0
  23. package/dist/metrics/g-eval.js +89 -0
  24. package/dist/metrics/g-eval.js.map +1 -0
  25. package/dist/metrics/index.d.ts +4 -2
  26. package/dist/metrics/index.d.ts.map +1 -1
  27. package/dist/metrics/index.js +2 -1
  28. package/dist/metrics/index.js.map +1 -1
  29. package/dist/metrics/judge-prompt.d.ts +31 -0
  30. package/dist/metrics/judge-prompt.d.ts.map +1 -0
  31. package/dist/metrics/judge-prompt.js +90 -0
  32. package/dist/metrics/judge-prompt.js.map +1 -0
  33. package/dist/metrics/llm-judge.d.ts +96 -9
  34. package/dist/metrics/llm-judge.d.ts.map +1 -1
  35. package/dist/metrics/llm-judge.js +265 -120
  36. package/dist/metrics/llm-judge.js.map +1 -1
  37. package/dist/options.d.ts +4 -0
  38. package/dist/options.d.ts.map +1 -0
  39. package/dist/options.js +9 -0
  40. package/dist/options.js.map +1 -0
  41. package/dist/pairwise.d.ts +53 -0
  42. package/dist/pairwise.d.ts.map +1 -0
  43. package/dist/pairwise.js +118 -0
  44. package/dist/pairwise.js.map +1 -0
  45. package/dist/schema.d.ts +16 -0
  46. package/dist/schema.d.ts.map +1 -1
  47. package/dist/schema.js +17 -0
  48. package/dist/schema.js.map +1 -1
  49. package/dist/stats/bootstrap.d.ts +22 -0
  50. package/dist/stats/bootstrap.d.ts.map +1 -0
  51. package/dist/stats/bootstrap.js +34 -0
  52. package/dist/stats/bootstrap.js.map +1 -0
  53. package/dist/stats/correlation.d.ts +11 -0
  54. package/dist/stats/correlation.d.ts.map +1 -0
  55. package/dist/stats/correlation.js +42 -0
  56. package/dist/stats/correlation.js.map +1 -0
  57. package/dist/stats/effect-size.d.ts +7 -0
  58. package/dist/stats/effect-size.d.ts.map +1 -0
  59. package/dist/stats/effect-size.js +17 -0
  60. package/dist/stats/effect-size.js.map +1 -0
  61. package/dist/stats/holm.d.ts +7 -0
  62. package/dist/stats/holm.d.ts.map +1 -0
  63. package/dist/stats/holm.js +21 -0
  64. package/dist/stats/holm.js.map +1 -0
  65. package/dist/stats/index.d.ts +10 -2
  66. package/dist/stats/index.d.ts.map +1 -1
  67. package/dist/stats/index.js +7 -1
  68. package/dist/stats/index.js.map +1 -1
  69. package/dist/stats/mcnemar.d.ts +9 -0
  70. package/dist/stats/mcnemar.d.ts.map +1 -1
  71. package/dist/stats/mcnemar.js +27 -13
  72. package/dist/stats/mcnemar.js.map +1 -1
  73. package/dist/stats/normal.d.ts +5 -0
  74. package/dist/stats/normal.d.ts.map +1 -0
  75. package/dist/stats/normal.js +19 -0
  76. package/dist/stats/normal.js.map +1 -0
  77. package/dist/stats/precision.d.ts +12 -0
  78. package/dist/stats/precision.d.ts.map +1 -0
  79. package/dist/stats/precision.js +29 -0
  80. package/dist/stats/precision.js.map +1 -0
  81. package/dist/stats/random.d.ts +6 -0
  82. package/dist/stats/random.d.ts.map +1 -0
  83. package/dist/stats/random.js +25 -0
  84. package/dist/stats/random.js.map +1 -0
  85. package/dist/stats/ranks.d.ts +5 -0
  86. package/dist/stats/ranks.d.ts.map +1 -0
  87. package/dist/stats/ranks.js +24 -0
  88. package/dist/stats/ranks.js.map +1 -0
  89. package/dist/stats/t-test.d.ts +4 -0
  90. package/dist/stats/t-test.d.ts.map +1 -1
  91. package/dist/stats/t-test.js +9 -3
  92. package/dist/stats/t-test.js.map +1 -1
  93. package/dist/stats/wilcoxon.d.ts +19 -0
  94. package/dist/stats/wilcoxon.d.ts.map +1 -0
  95. package/dist/stats/wilcoxon.js +70 -0
  96. package/dist/stats/wilcoxon.js.map +1 -0
  97. package/package.json +1 -1
package/README.md CHANGED
@@ -18,14 +18,14 @@ Website docs: [Evals](https://cogitator.app/docs/evals), [Datasets](https://cogi
18
18
  ## Features
19
19
 
20
20
  - **EvalSuite** — Run datasets against agents or plain functions with configurable concurrency, timeouts, and retries
21
- - **7 Deterministic Metrics** - exactMatch, contains, containsAll, containsAny, similarity, regex, jsonSchema (Zod)
22
- - **6 LLM-as-Judge Metrics** - faithfulness, relevance, coherence, helpfulness, contextRelevance, custom llmMetric
21
+ - **8 Deterministic Metrics** - exactMatch, contains, containsAll, containsAny, similarity, tokenF1, regex, jsonSchema (Zod)
22
+ - **7 LLM-as-Judge Metrics** - faithfulness, relevance, coherence, helpfulness, contextRelevance, gEval, custom llmMetric with a free prompt or a discrete rubric. Prompts keep every untrusted value in escaped tags, `judge.samples` averages several verdicts, and `calibrateJudge()` checks a judge against labels
23
23
  - **4 Statistical Metrics** - latency, cost, tokenUsage with full percentile breakdowns, and passAtK over trials
24
24
  - **Custom Metrics** — `metric()` factory for anything domain-specific
25
25
  - **Agent Evaluation** - `toolCalls()` and `trajectory()` against expected tool calls, `retrievalRecall()`, `retrievalPrecision()`, `retrievalMRR()` and the `contextRelevance()` judge against expected passages, multi-turn cases on one conversation
26
26
  - **Trials and pass@k** - run each case several times and score how often it passes with `passAtK()`
27
27
  - **Assertions** — threshold, noRegression, custom assertion with auto-detection of lower-is-better metrics
28
- - **A/B Testing** — EvalComparison with paired t-test and McNemar's test for statistical significance
28
+ - **A/B Testing** - EvalComparison with McNemar's test (exact for few discordant pairs), the paired t-test or Wilcoxon signed-rank, Holm's correction across metrics, bootstrap confidence intervals, effect sizes, latency and cost comparisons and pairwise judging
29
29
  - **6 Reporters** - console (colored table), JSON, CSV, JUnit XML, GitHub Actions annotations and job summary, CI (exit code on failure)
30
30
  - **Vitest** - `describeEval` from `@cogitator-ai/evals/vitest` runs a suite as a test file, one test per case plus one for the assertions, and `evalMatchers` from `@cogitator-ai/evals/matchers` (Vitest 5) adds `toHaveCalledTool`, `toFollowTrajectory`, `toHaveRetrieved` and `toScoreAtLeast`
31
31
  - **Builder API** — Fluent `EvalBuilder` for composable eval pipelines
@@ -176,6 +176,7 @@ Metrics that compare output against expected values using string operations or s
176
176
  | `containsAll` | Fraction of configured keywords found | No |
177
177
  | `containsAny` | Whether any configured keyword is found | No |
178
178
  | `similarity` | Levenshtein distance similarity score (0 to 1) | Yes |
179
+ | `tokenF1` | Token-level F1 score (precision and recall) | Yes |
179
180
  | `regex` | Output matches a regex pattern | No |
180
181
  | `jsonSchema` | Output is valid JSON matching a Zod schema | No |
181
182
 
@@ -186,6 +187,7 @@ import {
186
187
  containsAll,
187
188
  containsAny,
188
189
  similarity,
190
+ tokenF1,
189
191
  regex,
190
192
  jsonSchema,
191
193
  threshold,
@@ -198,6 +200,7 @@ const metrics = [
198
200
  containsAll(['security', 'privacy', 'compliance']),
199
201
  containsAny(['approved', 'accepted']),
200
202
  similarity(),
203
+ tokenF1(),
201
204
  regex(/\d{4}-\d{2}-\d{2}/),
202
205
  jsonSchema(z.object({ answer: z.string(), confidence: z.number() })),
203
206
  ];
@@ -217,6 +220,8 @@ const metrics = [
217
220
 
218
221
  `containsAll()` scores the fraction of its keywords found and reports any missing keywords in `details`. `containsAny()` scores 1 when at least one keyword is found and 0 otherwise. Keywords use substring matching, so `cat` matches `concatenate`. Both metrics are case-insensitive by default, accept `caseSensitive` and `name` options, ignore duplicate keywords, and reject empty lists or empty and whitespace-only keywords when the metric is created.
219
222
 
223
+ `tokenF1()` computes token overlap using multiset counts so duplicate tokens are handled correctly, returning the harmonic mean of precision and recall. It lowercases unless `caseSensitive: true`, strips punctuation, removes standalone articles (`a`, `an`, `the`), splits on whitespace, scores 1 for both empty strings, and reports precision and recall in `details` whenever the score is below 1.
224
+
220
225
  `regex()` ignores the `g` and `y` flags, which would make identical outputs alternate between pass and fail.
221
226
 
222
227
  ### LLM-as-Judge
@@ -230,7 +235,8 @@ Metrics scored by an LLM judge (0.0 to 1.0). They require a `judge` config on th
230
235
  | `coherence` | Logical structure and readability |
231
236
  | `helpfulness` | Practical usefulness to the user |
232
237
  | `contextRelevance` | Whether the retrieved passages fit the input |
233
- | `llmMetric` | Custom prompt, you define the criteria |
238
+ | `gEval` | G-Eval: evaluation steps, then a scale |
239
+ | `llmMetric` | Custom prompt or rubric, your criteria |
234
240
 
235
241
  ```typescript
236
242
  import { faithfulness, relevance, llmMetric } from '@cogitator-ai/evals';
@@ -258,7 +264,43 @@ Dataset.from([{ input: 'Write the lede', context: { dossier: dossierText } }]);
258
264
 
259
265
  When the run retrieved passages (see [Retrieval](#retrieval)), `faithfulness()` checks the response against them instead of `context`. `contextRelevance()` judges the input against the retrieved passages alone, or against `context` when nothing was retrieved, and scores 0 without a judge call when the case has neither.
260
266
 
261
- The `judge` option is a `JudgeConfigInput`: `{ model, temperature?, maxTokens?, cogitator?, cache?, concurrency? }`, with `temperature` defaulting to `0`. `cache: true` reuses a verdict for the same model, settings and prompt in memory (a `JudgeCache` with `get` and `set` keeps them across runs), and `concurrency` caps the judge calls running at once.
267
+ The `judge` option is a `JudgeConfigInput`: `{ model, temperature?, maxTokens?, cogitator?, cache?, concurrency?, samples? }`, with `temperature` defaulting to `0`. `cache: true` reuses a verdict for the same model, settings and prompt in memory (a `JudgeCache` with `get` and `set` keeps them across runs), and `concurrency` caps the judge calls running at once.
268
+
269
+ `llmMetric` also takes a discrete `rubric` instead of a free prompt: the judge picks one level, and the score is normalized to 0 - 1 by the lowest and highest level. A rubric needs at least two levels with distinct scores, and a verdict that is not a level counts as a judge error.
270
+
271
+ ```typescript
272
+ llmMetric({
273
+ name: 'correctness',
274
+ prompt: 'Grade whether the response answers the question correctly.', // optional with a rubric
275
+ rubric: [
276
+ { score: 1, description: 'wrong, or does not answer' },
277
+ { score: 3, description: 'partly correct' },
278
+ { score: 5, description: 'fully correct' },
279
+ ],
280
+ });
281
+ ```
282
+
283
+ `gEval({ name, criteria, steps?, scale? })` follows G-Eval: the judge scores each case on `scale` (`[1, 5]` by default, normalized to 0 - 1) following evaluation steps. Without `steps`, the judge writes them from `criteria` once per metric instance, before the first case, and every later case reuses them. A failed generation scores the cases waiting on it as judge errors, and the next case tries again. The original G-Eval weights each score by the probability of its token, which not every provider exposes, so set `judge.samples` (with a `temperature` above 0) to average several verdicts instead.
284
+
285
+ ```typescript
286
+ gEval({
287
+ name: 'clarity',
288
+ criteria: 'A beginner can follow the explanation, and it names the key idea first.',
289
+ });
290
+ ```
291
+
292
+ Every judge prompt keeps the untrusted values of a case (input, response, expected answer, context, retrieved passages, the turns of a conversation) inside XML-like tags such as `<input>` and `<response>`, with `<`, `>` and `&` escaped, so an answer cannot close its tag or open another, and the judge is told that tag contents are data to evaluate, never instructions. An answer that tells the judge to give it full marks is judged as content.
293
+
294
+ `judge.samples` asks the judge that many times per case and metric (1 by default) and scores the mean of the verdicts it could read. The score's `details` give the spread (`mean of 3 verdicts, spread 0.6..0.9`), `metadata.samples` each verdict, and `usage` the summed cost. With `cache`, each sample is cached under its own key.
295
+
296
+ `calibrateJudge(metric, examples, options?)` checks a judge against labels people gave: it scores each `{ input, output, expected?, context?, label }` (labels from 0 to 1) and returns `{ n, errors, pearson, spearman, mae, kappa, perCase }`, `kappa` being Cohen's kappa of pass and fail at `threshold` (0.5 by default). Pass a metric bound with `bindJudgeContext`, or `judge` with a `cogitator` to bind it. Examples the metric fails on are reported in `perCase` and left out of the figures.
297
+
298
+ ```typescript
299
+ const calibration = await calibrateJudge(correctness, labelled, {
300
+ judge: { model: 'openai/gpt-6.1-sol', cogitator: cog },
301
+ });
302
+ console.log(calibration.spearman, calibration.kappa);
303
+ ```
262
304
 
263
305
  The judge answers with `{ "score", "reasoning" }` JSON. A verdict in a code fence or with the score as a numeric string is read as well, and an answer without JSON falls back to its last labelled score (`Score: 0.4`, `score is 4/5`), never to a stray number in the prose. When no verdict can be read, or the judge call fails, the metric scores 0 with the reason in `score.error`. The judge's usage is reported on each score and counted in `stats.judgeCost`.
264
306
 
@@ -500,6 +542,30 @@ for (const [name, mc] of Object.entries(result.summary.metrics)) {
500
542
  }
501
543
  ```
502
544
 
545
+ Binary metrics (every score 0 or 1) take McNemar's test, exact below 25 discordant pairs and chi-square with continuity correction from 25. Other metrics take the paired t-test, or Wilcoxon's signed-rank test with `test: 'wilcoxon'` (zero differences dropped, exact up to 20 pairs, normal approximation above). Paired differences are rounded to 12 significant digits, so float noise neither splits ties nor hides a zero. The winner follows the test's direction: the higher mean for McNemar's and the t-test, the larger rank sum for Wilcoxon's, which can disagree with `difference`, the mean difference. The p-values are corrected with Holm's method across the compared metrics: `pValue` is the test's own, `adjustedPValue` the corrected one, and `significant` means `adjustedPValue < alpha` (`alpha` 0.05 by default). Each metric also reports `difference` (the mean of challenger minus baseline), `ci` (a percentile bootstrap interval of the paired differences at `1 - alpha`, the same on every run with `seed`), `effectSize` (Cohen's d of the paired differences) and the `test` it ran.
546
+
547
+ `result.summary.latency` and `result.summary.cost` compare milliseconds and USD per case, paired over the cases both sides answered, where lower is better: means, `difference`, `pValue` and `winner`. `cost` is there only when both sides reported usage. Neither takes part in the metrics' vote on the overall winner.
548
+
549
+ With `pairwise`, the judge also reads both answers of each case and says which is better, twice, the second time with the answers swapped. Agreeing verdicts give the case to that side, disagreeing ones or a tie make it a tie, a side that errored loses the case without a judge call, and a case both sides errored on is left out. A judge failure counts as a tie and is reported.
550
+
551
+ ```typescript
552
+ const comparison = new EvalComparison({
553
+ dataset,
554
+ targets: { baseline, challenger },
555
+ metrics: [exactMatch()],
556
+ judge: { model: 'openai/gpt-6.1-sol', cogitator: cog },
557
+ pairwise: { criteria: 'Which answer is more accurate.' },
558
+ test: 'wilcoxon',
559
+ alpha: 0.05,
560
+ seed: 42,
561
+ });
562
+
563
+ const { pairwise } = await comparison.run();
564
+ // { name, wins: { baseline, challenger }, ties, cases, winRate, judgeErrors, cost, perCase }
565
+ ```
566
+
567
+ `winRate` is the challenger's wins over the decided cases, NaN when none was decided.
568
+
503
569
  Access full suite results via `result.baseline` and `result.challenger`. `comparison.run({ signal })` cancels both runs.
504
570
 
505
571
  ---
@@ -652,6 +718,7 @@ result.report('ci');
652
718
  | ---------------- | ------------------------------------------------------------------- |
653
719
  | `EvalSuite` | Main evaluation runner |
654
720
  | `EvalComparison` | A/B testing runner with statistical significance |
721
+ | `calibrateJudge` | Agreement of a judge metric with labelled examples |
655
722
  | `EvalBuilder` | Fluent builder for EvalSuite |
656
723
  | `Dataset` | Immutable dataset with from/fromJsonl/fromCsv/filter/sample/shuffle |
657
724
  | `loadJsonl` | Low-level JSONL file loader |
@@ -667,6 +734,7 @@ result.report('ci');
667
734
  | `containsAll` | Deterministic | Fraction of keywords found |
668
735
  | `containsAny` | Deterministic | Any configured keyword found |
669
736
  | `similarity` | Deterministic | Levenshtein distance similarity score |
737
+ | `tokenF1` | Deterministic | Token-level F1 score |
670
738
  | `regex` | Deterministic | Regex pattern match |
671
739
  | `jsonSchema` | Deterministic | Zod schema validation |
672
740
  | `faithfulness` | LLM Judge | Factual accuracy |
@@ -674,7 +742,8 @@ result.report('ci');
674
742
  | `coherence` | LLM Judge | Logical structure |
675
743
  | `helpfulness` | LLM Judge | Practical usefulness |
676
744
  | `contextRelevance` | LLM Judge | Relevance of the retrieved passages to the input |
677
- | `llmMetric` | LLM Judge | Custom judge prompt |
745
+ | `gEval` | LLM Judge | Evaluation steps from criteria, then a score on a scale |
746
+ | `llmMetric` | LLM Judge | Custom judge prompt or discrete rubric |
678
747
  | `toolCalls` | Agent | Tool calls against `expectedToolCalls`, F1, recall or precision |
679
748
  | `trajectory` | Agent | Sequence of tool names, exact, in-order or any-order |
680
749
  | `retrievalRecall` | Agent | Share of `expectedPassages` retrieved |
@@ -720,15 +789,22 @@ result.report('ci');
720
789
 
721
790
  ### Statistics
722
791
 
723
- | Export | Description |
724
- | -------------- | --------------------------------------------------------- |
725
- | `pairedTTest` | Paired t-test for continuous metric comparison |
726
- | `mcnemarsTest` | McNemar's test for binary metric comparison |
727
- | `mean` | Arithmetic mean |
728
- | `median` | Median value |
729
- | `stdDev` | Sample standard deviation |
730
- | `percentile` | Arbitrary percentile |
731
- | `aggregate` | Full stats: mean, median, min, max, stdDev, p50, p95, p99 |
792
+ | Export | Description |
793
+ | -------------------- | --------------------------------------------------------------- |
794
+ | `pairedTTest` | Paired t-test for continuous metric comparison |
795
+ | `wilcoxonSignedRank` | Wilcoxon signed-rank test, zeros dropped, exact up to 20 pairs |
796
+ | `mcnemarsTest` | McNemar's test (chi-square, continuity corrected) for binary |
797
+ | `mcnemarExact` | Exact McNemar's test, the binomial test of the discordant pairs |
798
+ | `holm` | Holm-Bonferroni adjusted p-values |
799
+ | `bootstrapCI` | Seeded percentile bootstrap confidence interval of the mean |
800
+ | `cohensD` | Cohen's d of paired differences (dz) |
801
+ | `pearson` | Pearson's correlation |
802
+ | `spearman` | Spearman's rank correlation |
803
+ | `mean` | Arithmetic mean |
804
+ | `median` | Median value |
805
+ | `stdDev` | Sample standard deviation |
806
+ | `percentile` | Arbitrary percentile |
807
+ | `aggregate` | Full stats: mean, median, min, max, stdDev, p50, p95, p99 |
732
808
 
733
809
  ### Agent Tools
734
810
 
@@ -0,0 +1,53 @@
1
+ import type { MetricFn } from './metrics/types.js';
2
+ import type { JudgeConfigInput } from './schema.js';
3
+ /** An answer labelled by a person, with the score the metric should give it, from 0 to 1 */
4
+ export interface CalibrationExample {
5
+ input: string;
6
+ output: string;
7
+ expected?: string;
8
+ context?: Record<string, unknown>;
9
+ label: number;
10
+ }
11
+ export interface CalibrateJudgeOptions {
12
+ /** Where a score or label counts as a pass for `kappa`, 0.5 by default */
13
+ threshold?: number;
14
+ /** Binds an unbound judge metric, run by `judge.cogitator` */
15
+ judge?: JudgeConfigInput;
16
+ /** Examples scored at once, 5 by default */
17
+ concurrency?: number;
18
+ }
19
+ export interface CalibrationCase {
20
+ /** Position of the example */
21
+ index: number;
22
+ label: number;
23
+ /** The metric's score, absent when it failed */
24
+ score?: number;
25
+ details?: string;
26
+ error?: string;
27
+ }
28
+ export interface JudgeCalibration {
29
+ /** Examples the metric scored, those it failed on left out of the figures */
30
+ n: number;
31
+ /** Examples the metric failed on */
32
+ errors: number;
33
+ /** Pearson's correlation of scores and labels, NaN when either does not vary */
34
+ pearson: number;
35
+ /** Spearman's rank correlation of scores and labels */
36
+ spearman: number;
37
+ /** Mean absolute error of the scores against the labels */
38
+ mae: number;
39
+ /**
40
+ * Cohen's kappa of pass and fail, a score or label passing at `threshold` or more. NaN when
41
+ * agreement by chance is certain, every score and label being on one side
42
+ */
43
+ kappa: number;
44
+ perCase: CalibrationCase[];
45
+ }
46
+ /**
47
+ * How well a metric, usually an LLM judge, agrees with labels people gave: it scores each
48
+ * labelled example and compares the scores with the labels. Bind a judge metric first with
49
+ * `bindJudgeContext`, or pass `judge` with a `cogitator`. Examples the metric fails on are
50
+ * reported and left out of the figures
51
+ */
52
+ export declare function calibrateJudge(metric: MetricFn, examples: readonly CalibrationExample[], options?: CalibrateJudgeOptions): Promise<JudgeCalibration>;
53
+ //# sourceMappingURL=calibrate-judge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calibrate-judge.d.ts","sourceRoot":"","sources":["../src/calibrate-judge.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAkB,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAIhE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAKjD,4FAA4F;AAC5F,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,qBAAqB;IACpC,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8DAA8D;IAC9D,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,8BAA8B;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,6EAA6E;IAC7E,CAAC,EAAE,MAAM,CAAC;IACV,oCAAoC;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,gFAAgF;IAChF,OAAO,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,2DAA2D;IAC3D,GAAG,EAAE,MAAM,CAAC;IACZ;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,eAAe,EAAE,CAAC;CAC5B;AA6ED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,QAAQ,EAChB,QAAQ,EAAE,SAAS,kBAAkB,EAAE,EACvC,OAAO,GAAE,qBAA0B,GAClC,OAAO,CAAC,gBAAgB,CAAC,CAyC3B"}
@@ -0,0 +1,114 @@
1
+ import { z } from 'zod';
2
+ import { isLLMMetric } from './eval-suite.js';
3
+ import { nonFiniteScoreError } from './metrics/types.js';
4
+ import { bindJudgeContext, judgeContextFor } from './metrics/llm-judge.js';
5
+ import { JudgeConfigSchema } from './schema.js';
6
+ import { parseOptions } from './options.js';
7
+ import { pearson, spearman } from './stats/correlation.js';
8
+ import { mean } from './stats/percentiles.js';
9
+ const CalibrationExampleSchema = z.object({
10
+ input: z.string(),
11
+ output: z.string(),
12
+ expected: z.string().optional(),
13
+ context: z.record(z.string(), z.unknown()).optional(),
14
+ label: z.number().min(0).max(1),
15
+ });
16
+ const CalibrateJudgeOptionsSchema = z.object({
17
+ threshold: z.number().min(0).max(1).default(0.5),
18
+ concurrency: z.number().int().positive().default(5),
19
+ });
20
+ /** Cohen's kappa of two binary raters */
21
+ function binaryKappa(a, b) {
22
+ const n = a.length;
23
+ if (n === 0)
24
+ return Number.NaN;
25
+ let agree = 0;
26
+ let aPass = 0;
27
+ let bPass = 0;
28
+ for (let i = 0; i < n; i++) {
29
+ if (a[i] === b[i])
30
+ agree++;
31
+ if (a[i])
32
+ aPass++;
33
+ if (b[i])
34
+ bPass++;
35
+ }
36
+ const observed = agree / n;
37
+ const chance = (aPass / n) * (bPass / n) + (1 - aPass / n) * (1 - bPass / n);
38
+ return chance === 1 ? Number.NaN : (observed - chance) / (1 - chance);
39
+ }
40
+ function bindMetric(metric, judge) {
41
+ if (!isLLMMetric(metric))
42
+ return metric;
43
+ if (!judge) {
44
+ throw new Error('calibrateJudge needs options.judge to run an unbound judge metric');
45
+ }
46
+ const config = JudgeConfigSchema.parse(judge);
47
+ if (!config.cogitator) {
48
+ throw new Error('calibrateJudge needs judge.cogitator to run the judge');
49
+ }
50
+ return bindJudgeContext(metric, judgeContextFor(config.cogitator, config));
51
+ }
52
+ async function scoreExample(metric, example, index) {
53
+ const result = {
54
+ case: {
55
+ input: example.input,
56
+ ...(example.expected !== undefined && { expected: example.expected }),
57
+ ...(example.context !== undefined && { context: example.context }),
58
+ },
59
+ output: example.output,
60
+ duration: 0,
61
+ };
62
+ try {
63
+ const scored = await metric(result);
64
+ const invalid = scored.error ?? nonFiniteScoreError(scored.score);
65
+ if (invalid !== undefined)
66
+ return { index, label: example.label, error: invalid };
67
+ return {
68
+ index,
69
+ label: example.label,
70
+ score: scored.score,
71
+ ...(scored.details !== undefined && { details: scored.details }),
72
+ };
73
+ }
74
+ catch (error) {
75
+ return {
76
+ index,
77
+ label: example.label,
78
+ error: error instanceof Error ? error.message : String(error),
79
+ };
80
+ }
81
+ }
82
+ /**
83
+ * How well a metric, usually an LLM judge, agrees with labels people gave: it scores each
84
+ * labelled example and compares the scores with the labels. Bind a judge metric first with
85
+ * `bindJudgeContext`, or pass `judge` with a `cogitator`. Examples the metric fails on are
86
+ * reported and left out of the figures
87
+ */
88
+ export async function calibrateJudge(metric, examples, options = {}) {
89
+ const { threshold, concurrency } = parseOptions(CalibrateJudgeOptionsSchema, { threshold: options.threshold, concurrency: options.concurrency }, 'calibrateJudge');
90
+ const parsed = parseOptions(z.array(CalibrationExampleSchema), examples, 'calibrateJudge examples');
91
+ const bound = bindMetric(metric, options.judge);
92
+ const perCase = new Array(parsed.length);
93
+ let next = 0;
94
+ const worker = async () => {
95
+ while (next < parsed.length) {
96
+ const at = next++;
97
+ perCase[at] = await scoreExample(bound, parsed[at], at);
98
+ }
99
+ };
100
+ await Promise.all(Array.from({ length: Math.min(concurrency, parsed.length) }, worker));
101
+ const scored = perCase.filter((one) => one.score !== undefined);
102
+ const scores = scored.map((one) => one.score);
103
+ const labels = scored.map((one) => one.label);
104
+ return {
105
+ n: scored.length,
106
+ errors: perCase.length - scored.length,
107
+ pearson: pearson(scores, labels),
108
+ spearman: spearman(scores, labels),
109
+ mae: scored.length === 0 ? Number.NaN : mean(scored.map((one) => Math.abs(one.score - one.label))),
110
+ kappa: binaryKappa(scores.map((score) => score >= threshold), labels.map((label) => label >= threshold)),
111
+ perCase,
112
+ };
113
+ }
114
+ //# sourceMappingURL=calibrate-judge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"calibrate-judge.js","sourceRoot":"","sources":["../src/calibrate-judge.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAE7C,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAiD3C,MAAM,wBAAwB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC/B,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,EAAE;IACrD,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;CAChC,CAAC,CAAC;AAEH,MAAM,2BAA2B,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;IAChD,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;CACpD,CAAC,CAAC;AAEH,yCAAyC;AACzC,SAAS,WAAW,CAAC,CAAqB,EAAE,CAAqB;IAC/D,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC;IACnB,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC,GAAG,CAAC;IAC/B,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;YAAE,KAAK,EAAE,CAAC;QAC3B,IAAI,CAAC,CAAC,CAAC,CAAC;YAAE,KAAK,EAAE,CAAC;QAClB,IAAI,CAAC,CAAC,CAAC,CAAC;YAAE,KAAK,EAAE,CAAC;IACpB,CAAC;IACD,MAAM,QAAQ,GAAG,KAAK,GAAG,CAAC,CAAC;IAC3B,MAAM,MAAM,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC;IAC7E,OAAO,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC;AACxE,CAAC;AAED,SAAS,UAAU,CAAC,MAAgB,EAAE,KAAmC;IACvE,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC;IACxC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAC;IACvF,CAAC;IACD,MAAM,MAAM,GAAG,iBAAiB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC9C,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,gBAAgB,CAAC,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;AAC7E,CAAC;AAED,KAAK,UAAU,YAAY,CACzB,MAAgB,EAChB,OAAkD,EAClD,KAAa;IAEb,MAAM,MAAM,GAAmB;QAC7B,IAAI,EAAE;YACJ,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,GAAG,CAAC,OAAO,CAAC,QAAQ,KAAK,SAAS,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC;YACrE,GAAG,CAAC,OAAO,CAAC,OAAO,KAAK,SAAS,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,CAAC;SACnE;QACD,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,QAAQ,EAAE,CAAC;KACZ,CAAC;IACF,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,CAAC;QACpC,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,IAAI,mBAAmB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAClE,IAAI,OAAO,KAAK,SAAS;YAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;QAClF,OAAO;YACL,KAAK;YACL,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,GAAG,CAAC,MAAM,CAAC,OAAO,KAAK,SAAS,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;SACjE,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO;YACL,KAAK;YACL,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;SAC9D,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAgB,EAChB,QAAuC,EACvC,UAAiC,EAAE;IAEnC,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,GAAG,YAAY,CAC7C,2BAA2B,EAC3B,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,EAClE,gBAAgB,CACjB,CAAC;IACF,MAAM,MAAM,GAAG,YAAY,CACzB,CAAC,CAAC,KAAK,CAAC,wBAAwB,CAAC,EACjC,QAAQ,EACR,yBAAyB,CAC1B,CAAC;IACF,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAEhD,MAAM,OAAO,GAAG,IAAI,KAAK,CAAkB,MAAM,CAAC,MAAM,CAAC,CAAC;IAC1D,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE;QACxB,OAAO,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;YAC5B,MAAM,EAAE,GAAG,IAAI,EAAE,CAAC;YAClB,OAAO,CAAC,EAAE,CAAC,GAAG,MAAM,YAAY,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC,CAAC;IACF,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC;IAExF,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAC3B,CAAC,GAAG,EAA8C,EAAE,CAAC,GAAG,CAAC,KAAK,KAAK,SAAS,CAC7E,CAAC;IACF,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAC9C,OAAO;QACL,CAAC,EAAE,MAAM,CAAC,MAAM;QAChB,MAAM,EAAE,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM;QACtC,OAAO,EAAE,OAAO,CAAC,MAAM,EAAE,MAAM,CAAC;QAChC,QAAQ,EAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QAClC,GAAG,EACD,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC;QAC/F,KAAK,EAAE,WAAW,CAChB,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,IAAI,SAAS,CAAC,EACzC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,IAAI,SAAS,CAAC,CAC1C;QACD,OAAO;KACR,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"dataset.d.ts","sourceRoot":"","sources":["../../src/datasets/dataset.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAI1C,qBAAa,OAAO;IAClB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;IAE7C,OAAO;IAIP,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,OAAO;WAI1B,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;WAKzC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKpD,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,IAAI,KAAK,IAAI,SAAS,QAAQ,EAAE,CAE/B;IAED,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC;IAavC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,KAAK,OAAO,GAAG,OAAO;IAI7C;;;OAGG;IACH,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;KAAO,GAAG,OAAO;IAYpE,yEAAyE;IACzE,OAAO,CAAC,OAAO,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;KAAO,GAAG,OAAO;CAG3D"}
1
+ {"version":3,"file":"dataset.d.ts","sourceRoot":"","sources":["../../src/datasets/dataset.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAK1C,qBAAa,OAAO;IAClB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAsB;IAE7C,OAAO;IAIP,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,OAAO;WAI1B,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;WAKzC,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKpD,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,IAAI,KAAK,IAAI,SAAS,QAAQ,EAAE,CAE/B;IAED,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,QAAQ,CAAC;IAavC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,KAAK,OAAO,GAAG,OAAO;IAI7C;;;OAGG;IACH,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;KAAO,GAAG,OAAO;IAYpE,yEAAyE;IACzE,OAAO,CAAC,OAAO,GAAE;QAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;KAAO,GAAG,OAAO;CAG3D"}
@@ -1,6 +1,7 @@
1
1
  import { EvalCaseSchema } from '../schema.js';
2
2
  import { loadJsonl } from './jsonl-loader.js';
3
3
  import { loadCsv } from './csv-loader.js';
4
+ import { seededRandom } from '../stats/random.js';
4
5
  export class Dataset {
5
6
  _cases;
6
7
  constructor(cases) {
@@ -47,12 +48,12 @@ export class Dataset {
47
48
  return new Dataset([]);
48
49
  }
49
50
  const count = Math.min(n, this._cases.length);
50
- const indices = shuffled(Array.from({ length: this._cases.length }, (_, i) => i), randomOf(options.seed));
51
+ const indices = shuffled(Array.from({ length: this._cases.length }, (_, i) => i), seededRandom(options.seed));
51
52
  return new Dataset(indices.slice(0, count).map((i) => this._cases[i]));
52
53
  }
53
54
  /** The cases in random order, the same order on every run with `seed` */
54
55
  shuffle(options = {}) {
55
- return new Dataset(shuffled([...this._cases], randomOf(options.seed)));
56
+ return new Dataset(shuffled([...this._cases], seededRandom(options.seed)));
56
57
  }
57
58
  }
58
59
  /** Shuffles `items` in place (Fisher-Yates) with the random numbers `random` gives */
@@ -63,29 +64,4 @@ function shuffled(items, random) {
63
64
  }
64
65
  return items;
65
66
  }
66
- /**
67
- * `Math.random`, or a mulberry32 generator seeded by the hash of `seed`, so every number and
68
- * string seeds its own sequence (`1.2` and `1.7`, `-1` and `2 ** 32 - 1` alike)
69
- */
70
- function randomOf(seed) {
71
- if (seed === undefined)
72
- return Math.random;
73
- let state = hashSeed(String(seed));
74
- return () => {
75
- state = (state + 0x6d2b79f5) >>> 0;
76
- let t = state;
77
- t = Math.imul(t ^ (t >>> 15), t | 1);
78
- t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
79
- return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
80
- };
81
- }
82
- /** FNV-1a of a string, to seed the generator */
83
- function hashSeed(seed) {
84
- let hash = 0x811c9dc5;
85
- for (let i = 0; i < seed.length; i++) {
86
- hash ^= seed.charCodeAt(i);
87
- hash = Math.imul(hash, 0x01000193) >>> 0;
88
- }
89
- return hash;
90
- }
91
67
  //# sourceMappingURL=dataset.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"dataset.js","sourceRoot":"","sources":["../../src/datasets/dataset.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dataset.js","sourceRoot":"","sources":["../../src/datasets/dataset.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,7 @@ import type { EvalTarget, EvalSuiteResult } from './eval-suite.js';
2
2
  import type { MetricFn, StatisticalMetricFn } from './metrics/types.js';
3
3
  import type { JudgeConfigInput } from './schema.js';
4
4
  import { Dataset } from './datasets/index.js';
5
+ import type { PairwiseOptions, PairwiseResult } from './pairwise.js';
5
6
  export interface EvalComparisonOptions {
6
7
  dataset: Dataset;
7
8
  targets: {
@@ -10,6 +11,7 @@ export interface EvalComparisonOptions {
10
11
  };
11
12
  metrics?: MetricFn[];
12
13
  statisticalMetrics?: StatisticalMetricFn[];
14
+ /** The judge of LLM metrics and of `pairwise`, on both sides */
13
15
  judge?: JudgeConfigInput;
14
16
  concurrency?: number;
15
17
  timeout?: number;
@@ -19,6 +21,23 @@ export interface EvalComparisonOptions {
19
21
  * mean over its scored trials, and `passAtK()` statistical metrics see every trial
20
22
  */
21
23
  trials?: number;
24
+ /**
25
+ * Significance level, 0.05 by default. A metric is significant when its p-value, adjusted with
26
+ * Holm's correction across the compared metrics, is below it, and its `ci` covers `1 - alpha`
27
+ */
28
+ alpha?: number;
29
+ /**
30
+ * Test of metrics that are not binary, and of latency and cost: `t` (paired t-test, the
31
+ * default) or `wilcoxon` (Wilcoxon signed-rank). Binary metrics always take McNemar's test
32
+ */
33
+ test?: 't' | 'wilcoxon';
34
+ /** Seeds the bootstrap of each metric's `ci`, so the intervals are the same on every run */
35
+ seed?: number | string;
36
+ /**
37
+ * Asks the judge which side answered each case better, both ways round, into
38
+ * `result.pairwise`. Needs `judge`, run by `judge.cogitator` or an agent target's `cogitator`
39
+ */
40
+ pairwise?: PairwiseOptions;
22
41
  onProgress?: (progress: {
23
42
  target: string;
24
43
  completed: number;
@@ -29,25 +48,75 @@ export interface EvalComparisonRunOptions {
29
48
  /** Cancels both runs; `run()` rejects with the signal's reason */
30
49
  signal?: AbortSignal;
31
50
  }
51
+ /**
52
+ * The test a comparison ran: McNemar's (exact below 25 discordant pairs, chi-square with
53
+ * continuity correction from 25), the paired t-test, Wilcoxon signed-rank, or none with fewer
54
+ * than 2 cases
55
+ */
56
+ export type ComparisonTest = 'mcnemar' | 'mcnemar-exact' | 't' | 'wilcoxon' | 'none';
57
+ export type ComparisonWinner = 'baseline' | 'challenger' | 'tie';
32
58
  export interface MetricComparison {
33
59
  baseline: number;
34
60
  challenger: number;
35
61
  /** Cases compared: those at least one side scored, an errored side counting as a 0 */
36
62
  n: number;
63
+ /** Mean of the paired differences, challenger minus baseline */
64
+ difference: number;
65
+ /** Percentile bootstrap confidence interval of `difference` at `1 - alpha` */
66
+ ci: {
67
+ low: number;
68
+ high: number;
69
+ };
70
+ /** Cohen's d of the paired differences (dz), NaN with fewer than 2 cases */
71
+ effectSize: number;
72
+ test: ComparisonTest;
73
+ /** The test's own p-value */
74
+ pValue: number;
75
+ /** `pValue` after Holm's correction across the compared metrics */
76
+ adjustedPValue: number;
77
+ /** `adjustedPValue` is below `alpha` */
78
+ significant: boolean;
79
+ /**
80
+ * The higher side when significant, by the test's direction: the sign of `difference`, except
81
+ * for Wilcoxon's test, where it is the side with the larger rank sum and may differ from it
82
+ */
83
+ winner: ComparisonWinner;
84
+ }
85
+ /**
86
+ * Latency or cost of the two sides, paired over the cases both answered, where lower is better.
87
+ * Not corrected for multiple comparisons and not part of the metrics' vote on the winner
88
+ */
89
+ export interface ResourceComparison {
90
+ /** Mean per case, NaN when no case pairs up */
91
+ baseline: number;
92
+ challenger: number;
93
+ n: number;
94
+ /** Challenger minus baseline: below 0 when the challenger is cheaper or faster */
95
+ difference: number;
96
+ test: ComparisonTest;
37
97
  pValue: number;
38
98
  significant: boolean;
39
- winner: 'baseline' | 'challenger' | 'tie';
99
+ /** The lower side when significant, by the test's direction as for `MetricComparison.winner` */
100
+ winner: ComparisonWinner;
40
101
  }
41
102
  export interface ComparisonResult {
42
103
  summary: {
43
- winner: 'baseline' | 'challenger' | 'tie';
104
+ winner: ComparisonWinner;
44
105
  metrics: Record<string, MetricComparison>;
106
+ /** Milliseconds per case, the mean over the answered trials of a case */
107
+ latency: ResourceComparison;
108
+ /** USD per case, over the cases both sides reported usage on. Absent when none did */
109
+ cost?: ResourceComparison;
45
110
  };
46
111
  baseline: EvalSuiteResult;
47
112
  challenger: EvalSuiteResult;
113
+ /** The judge's pairwise verdicts, with the `pairwise` option */
114
+ pairwise?: PairwiseResult;
48
115
  }
49
116
  export declare class EvalComparison {
50
117
  private readonly opts;
118
+ private readonly config;
119
+ private readonly pairwiseJudge?;
51
120
  constructor(opts: EvalComparisonOptions);
52
121
  run(options?: EvalComparisonRunOptions): Promise<ComparisonResult>;
53
122
  }
@@ -1 +1 @@
1
- {"version":3,"file":"eval-comparison.d.ts","sourceRoot":"","sources":["../src/eval-comparison.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,KAAK,EAAE,QAAQ,EAAiC,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACpG,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAEjD,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAKrC,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE;QACP,QAAQ,EAAE,UAAU,CAAC;QACrB,UAAU,EAAE,UAAU,CAAC;KACxB,CAAC;IACF,OAAO,CAAC,EAAE,QAAQ,EAAE,CAAC;IACrB,kBAAkB,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAC3C,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;CACvF;AAED,MAAM,WAAW,wBAAwB;IACvC,kEAAkE;IAClE,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,sFAAsF;IACtF,CAAC,EAAE,MAAM,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,UAAU,GAAG,YAAY,GAAG,KAAK,CAAC;CAC3C;AAED,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE;QACP,MAAM,EAAE,UAAU,GAAG,YAAY,GAAG,KAAK,CAAC;QAC1C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;KAC3C,CAAC;IACF,QAAQ,EAAE,eAAe,CAAC;IAC1B,UAAU,EAAE,eAAe,CAAC;CAC7B;AAmED,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAwB;gBAEjC,IAAI,EAAE,qBAAqB;IAUjC,GAAG,CAAC,OAAO,GAAE,wBAA6B,GAAG,OAAO,CAAC,gBAAgB,CAAC;CA2E7E"}
1
+ {"version":3,"file":"eval-comparison.d.ts","sourceRoot":"","sources":["../src/eval-comparison.ts"],"names":[],"mappings":"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"}