@graphorin/evals 0.6.0 → 0.7.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/CHANGELOG.md +30 -0
  2. package/README.md +29 -3
  3. package/dist/index.d.ts +1 -2
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +3 -2
  6. package/dist/index.js.map +1 -1
  7. package/dist/loaders/locomo.d.ts.map +1 -1
  8. package/dist/loaders/locomo.js +24 -2
  9. package/dist/loaders/locomo.js.map +1 -1
  10. package/dist/loaders/memory-eval.d.ts +8 -0
  11. package/dist/loaders/memory-eval.d.ts.map +1 -1
  12. package/dist/package.js +6 -0
  13. package/dist/package.js.map +1 -0
  14. package/package.json +10 -9
  15. package/src/cli/index.ts +124 -0
  16. package/src/index.ts +136 -0
  17. package/src/loaders/csv.ts +147 -0
  18. package/src/loaders/dmr.ts +137 -0
  19. package/src/loaders/from-traces.ts +92 -0
  20. package/src/loaders/index.ts +46 -0
  21. package/src/loaders/iterable.ts +22 -0
  22. package/src/loaders/jsonl.ts +94 -0
  23. package/src/loaders/locomo.ts +217 -0
  24. package/src/loaders/longmemeval.ts +164 -0
  25. package/src/loaders/memory-eval.ts +80 -0
  26. package/src/regression.ts +133 -0
  27. package/src/reporters/html.ts +83 -0
  28. package/src/reporters/index.ts +14 -0
  29. package/src/reporters/json.ts +18 -0
  30. package/src/reporters/junit.ts +53 -0
  31. package/src/reporters/markdown.ts +65 -0
  32. package/src/reporters/terminal.ts +46 -0
  33. package/src/runner.ts +233 -0
  34. package/src/scorers/code/exact-match.ts +95 -0
  35. package/src/scorers/code/index.ts +10 -0
  36. package/src/scorers/code/json-path.ts +101 -0
  37. package/src/scorers/code/predicate.ts +32 -0
  38. package/src/scorers/code/regex.ts +55 -0
  39. package/src/scorers/index.ts +15 -0
  40. package/src/scorers/llm/index.ts +13 -0
  41. package/src/scorers/llm/judge.ts +170 -0
  42. package/src/scorers/prebuilt/index.ts +95 -0
  43. package/src/scorers/trajectory/argument-validity.ts +63 -0
  44. package/src/scorers/trajectory/correct-tool-selected.ts +61 -0
  45. package/src/scorers/trajectory/final-state-correct.ts +62 -0
  46. package/src/scorers/trajectory/index.ts +25 -0
  47. package/src/scorers/trajectory/recovery-after-error.ts +55 -0
  48. package/src/scorers/trajectory/redundant-call-detection.ts +58 -0
  49. package/src/scorers/trajectory/types.ts +44 -0
  50. package/src/scorers/trajectory/util.ts +81 -0
  51. package/src/stats.ts +196 -0
  52. package/src/types.ts +135 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # @graphorin/evals
2
2
 
3
+ ## 0.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#154](https://github.com/o-stepper/graphorin/pull/154) [`fe98522`](https://github.com/o-stepper/graphorin/commit/fe98522ce2477c9a7dc09029f9dcfdb1f7c9aa04) Thanks [@o-stepper](https://github.com/o-stepper)! - W-072: every export map's `import` condition becomes `default`, and the Node floor rises to `>=22.12.0`.
8
+
9
+ CJS consumers previously hit a bewildering `ERR_PACKAGE_PATH_NOT_EXPORTED` instead of a clear ESM-only signal. With the `default` condition, plain `require('@graphorin/core')` works via Node's stable `require(esm)` - which shipped in 22.12, hence the engines bump across every workspace manifest (packages, examples, benchmarks, docs; enforced by the widened mvp-readiness sweep). No dual-instance hazard: there is no CJS build, `require()` returns the same ESM module instance. ESM consumers are unaffected (`default` serves both paths; `types` stays first). The pack gate now runs attw under the full `node16` profile (was `esm-only`) and adds a runtime `require(esm)` smoke against the packed tarballs. Installs on Node 22.0-22.11 with `engine-strict` will refuse - upgrade Node (see the migration guide).
10
+
11
+ - [#153](https://github.com/o-stepper/graphorin/pull/153) [`832f22e`](https://github.com/o-stepper/graphorin/commit/832f22e570b8c3175c1adeb4c150070cbd131534) Thanks [@o-stepper](https://github.com/o-stepper)! - LOCOMO loader fidelity (W-022): `MemoryEvalTurn` gains an optional `speaker` field carrying the dataset-native speaker NAME alongside the two-role mapping - most LOCOMO questions reference speakers by name, and the LongMemEval benchmark runner now renders `<speaker>: ...` in both the full-context prompt and the ingested memory text. Numeric LOCOMO reference answers (e.g. `2022` - 6 of the 1986 QA pairs) are stringified instead of silently collapsing to `expected: ''`; QA pairs with no reference answer at all are SKIPPED rather than emitted, so the LLM judge never grades against an empty reference (documented in the module docs; this reduces the case count for such pairs). Any locally seeded LOCOMO baselines should be re-seeded - the ingested text changed; the committed stub-fixture CI baseline is unaffected.
12
+
13
+ ### Patch Changes
14
+
15
+ - [#164](https://github.com/o-stepper/graphorin/pull/164) [`764239b`](https://github.com/o-stepper/graphorin/commit/764239b97e0e0202442e91272583f13adeb12d00) Thanks [@o-stepper](https://github.com/o-stepper)! - TSDoc `{@link}` hygiene sweep (W-130): all 55 broken links found by TypeDoc's now-enabled `validation.invalidLink` are fixed - two resolved to their real targets (`GraphorinMCPError` was misnamed `MCPError`), the rest (cross-package, `import()`-form, unexported-constant, and DOM-type references that have never rendered as hrefs) converted to plain inline code. The docs build now fails on any new broken `{@link}` via a scoped gate.
16
+
17
+ - [#164](https://github.com/o-stepper/graphorin/pull/164) [`764239b`](https://github.com/o-stepper/graphorin/commit/764239b97e0e0202442e91272583f13adeb12d00) Thanks [@o-stepper](https://github.com/o-stepper)! - Tarballs now ship `src/` so the published `dist/**/*.d.ts.map` files actually work (W-136): the maps referenced `../src/*.ts` that the `files` whitelist excluded, so go-to-definition fell back into `.d.ts` and the shipped maps were dead weight. The pack gate gains a `map-integrity` leg: every source referenced by a shipped map must resolve inside the tarball (or be embedded via `sourcesContent`), with an anti-vacuous guard - a package whose tsdown config emits declaration maps must contain a non-zero number of `.d.ts.map` files, so a cache-restored dist that silently dropped maps fails the gate instead of passing vacuously. `mvp-readiness` now requires `src` in every publishable `files` array.
18
+
19
+ - Updated dependencies [[`fe98522`](https://github.com/o-stepper/graphorin/commit/fe98522ce2477c9a7dc09029f9dcfdb1f7c9aa04), [`fe98522`](https://github.com/o-stepper/graphorin/commit/fe98522ce2477c9a7dc09029f9dcfdb1f7c9aa04), [`fe98522`](https://github.com/o-stepper/graphorin/commit/fe98522ce2477c9a7dc09029f9dcfdb1f7c9aa04), [`fe98522`](https://github.com/o-stepper/graphorin/commit/fe98522ce2477c9a7dc09029f9dcfdb1f7c9aa04), [`832f22e`](https://github.com/o-stepper/graphorin/commit/832f22e570b8c3175c1adeb4c150070cbd131534), [`832f22e`](https://github.com/o-stepper/graphorin/commit/832f22e570b8c3175c1adeb4c150070cbd131534), [`fe98522`](https://github.com/o-stepper/graphorin/commit/fe98522ce2477c9a7dc09029f9dcfdb1f7c9aa04), [`fe98522`](https://github.com/o-stepper/graphorin/commit/fe98522ce2477c9a7dc09029f9dcfdb1f7c9aa04), [`832f22e`](https://github.com/o-stepper/graphorin/commit/832f22e570b8c3175c1adeb4c150070cbd131534), [`fe98522`](https://github.com/o-stepper/graphorin/commit/fe98522ce2477c9a7dc09029f9dcfdb1f7c9aa04), [`fe98522`](https://github.com/o-stepper/graphorin/commit/fe98522ce2477c9a7dc09029f9dcfdb1f7c9aa04), [`32bbd03`](https://github.com/o-stepper/graphorin/commit/32bbd03b588136a355e4b5ad6ac5e19b36b4d8ab), [`32bbd03`](https://github.com/o-stepper/graphorin/commit/32bbd03b588136a355e4b5ad6ac5e19b36b4d8ab), [`32bbd03`](https://github.com/o-stepper/graphorin/commit/32bbd03b588136a355e4b5ad6ac5e19b36b4d8ab), [`4ee256e`](https://github.com/o-stepper/graphorin/commit/4ee256e30fe9190cef6c48dc6785464757707156), [`4ee256e`](https://github.com/o-stepper/graphorin/commit/4ee256e30fe9190cef6c48dc6785464757707156), [`4ee256e`](https://github.com/o-stepper/graphorin/commit/4ee256e30fe9190cef6c48dc6785464757707156), [`32bbd03`](https://github.com/o-stepper/graphorin/commit/32bbd03b588136a355e4b5ad6ac5e19b36b4d8ab), [`4ee256e`](https://github.com/o-stepper/graphorin/commit/4ee256e30fe9190cef6c48dc6785464757707156), [`4ee256e`](https://github.com/o-stepper/graphorin/commit/4ee256e30fe9190cef6c48dc6785464757707156), [`4ee256e`](https://github.com/o-stepper/graphorin/commit/4ee256e30fe9190cef6c48dc6785464757707156), [`32bbd03`](https://github.com/o-stepper/graphorin/commit/32bbd03b588136a355e4b5ad6ac5e19b36b4d8ab), [`32bbd03`](https://github.com/o-stepper/graphorin/commit/32bbd03b588136a355e4b5ad6ac5e19b36b4d8ab), [`764239b`](https://github.com/o-stepper/graphorin/commit/764239b97e0e0202442e91272583f13adeb12d00), [`764239b`](https://github.com/o-stepper/graphorin/commit/764239b97e0e0202442e91272583f13adeb12d00), [`764239b`](https://github.com/o-stepper/graphorin/commit/764239b97e0e0202442e91272583f13adeb12d00), [`764239b`](https://github.com/o-stepper/graphorin/commit/764239b97e0e0202442e91272583f13adeb12d00), [`764239b`](https://github.com/o-stepper/graphorin/commit/764239b97e0e0202442e91272583f13adeb12d00), [`fe98522`](https://github.com/o-stepper/graphorin/commit/fe98522ce2477c9a7dc09029f9dcfdb1f7c9aa04), [`fe98522`](https://github.com/o-stepper/graphorin/commit/fe98522ce2477c9a7dc09029f9dcfdb1f7c9aa04), [`fe98522`](https://github.com/o-stepper/graphorin/commit/fe98522ce2477c9a7dc09029f9dcfdb1f7c9aa04)]:
20
+ - @graphorin/core@0.7.0
21
+ - @graphorin/observability@0.7.0
22
+
23
+ ## 0.6.1
24
+
25
+ ### Patch Changes
26
+
27
+ - [#142](https://github.com/o-stepper/graphorin/pull/142) [`436d6ca`](https://github.com/o-stepper/graphorin/commit/436d6ca5ebbd16df094e915682d3915c279a8430) Thanks [@o-stepper](https://github.com/o-stepper)! - Version constants and version-bearing strings now derive from each package's manifest at build time (`VERSION = pkg.version`; writer ids, client/server info, OTLP framework attributes, build-info metrics interpolate it). No behavioral change at the current version: the rendered strings are byte-identical. A release bump no longer edits source; the new `check-version-consistency` gate fails any reintroduced hardcoded framework version.
28
+
29
+ - Updated dependencies [[`826ee59`](https://github.com/o-stepper/graphorin/commit/826ee5933ad38693b0dd2f20a110abfecba7d23d), [`436d6ca`](https://github.com/o-stepper/graphorin/commit/436d6ca5ebbd16df094e915682d3915c279a8430)]:
30
+ - @graphorin/observability@0.6.1
31
+ - @graphorin/core@0.6.1
32
+
3
33
  ## 0.6.0
4
34
 
5
35
  ### Minor Changes
package/README.md CHANGED
@@ -7,14 +7,14 @@
7
7
  > bounded concurrency, and regression detection that compares the
8
8
  > current run against a stored baseline.
9
9
  >
10
- > Project Graphorin · v0.6.0 · MIT License · © 2026 Oleksiy Stepurenko ·
10
+ > Project Graphorin · v0.7.0 · MIT License · © 2026 Oleksiy Stepurenko ·
11
11
  > <https://github.com/o-stepper/graphorin>
12
12
 
13
13
  ---
14
14
 
15
15
  ## Status
16
16
 
17
- - **Published:** v0.6.0 (optional sub-pack; the full orchestrator is
17
+ - **Published:** v0.7.0 (optional sub-pack; the full orchestrator is
18
18
  decoupled from `@graphorin/observability` per RB-17 / DEC-152).
19
19
 
20
20
  ---
@@ -103,6 +103,25 @@ const report = await runEvals({
103
103
  });
104
104
  ```
105
105
 
106
+ Every report summary carries a Wilson 95% confidence interval for the
107
+ pass rate (`summary.passRateCi`), and, when `iterations > 1`,
108
+ `summary.passHatK` - the pass^k estimate over the per-case iteration
109
+ outcomes (the probability that all k iterations of a case pass).
110
+
111
+ ---
112
+
113
+ ## Statistics
114
+
115
+ Sample-size-aware statistics ship as plain exported functions:
116
+
117
+ ```ts
118
+ import { mean, sampleStddev, wilsonInterval, passHatK, pairedPassSignificance } from '@graphorin/evals';
119
+
120
+ wilsonInterval(18, 20); // { lo, hi } - 95% CI for 18/20 passes
121
+ passHatK(outcomesByCase); // pass^k over `-iter-N` outcome groups
122
+ pairedPassSignificance(a, b); // McNemar paired test between two runs
123
+ ```
124
+
106
125
  ---
107
126
 
108
127
  ## Regression detection
@@ -116,6 +135,9 @@ const regression = detectRegressions(report, baseline, {
116
135
  maxPassRateDropPct: 5,
117
136
  maxAvgScoreDrop: 0.05,
118
137
  maxAvgDurationIncreaseMs: 250,
138
+ // Opt-in: veto pass-rate-drop findings the McNemar paired test
139
+ // cannot distinguish from noise at the given alpha (default 0.05).
140
+ requireSignificance: true,
119
141
  });
120
142
  if (regression.hasRegressions) {
121
143
  for (const f of regression.findings) {
@@ -125,6 +147,10 @@ if (regression.hasRegressions) {
125
147
  exitOnFailures(report, regression);
126
148
  ```
127
149
 
150
+ Pass-rate findings are annotated with the paired regressed / improved
151
+ case counts and the McNemar p-value, so a 3-point drop on 20 cases
152
+ reads differently from the same drop on 2000.
153
+
128
154
  ---
129
155
 
130
156
  ## Multi-format report writing
@@ -154,4 +180,4 @@ MIT © 2026 Oleksiy Stepurenko
154
180
 
155
181
  ---
156
182
 
157
- **Project Graphorin** · v0.6.0 · MIT License · © 2026 Oleksiy Stepurenko · <https://github.com/o-stepper/graphorin>
183
+ **Project Graphorin** · v0.7.0 · MIT License · © 2026 Oleksiy Stepurenko · <https://github.com/o-stepper/graphorin>
package/dist/index.d.ts CHANGED
@@ -60,8 +60,7 @@ import { PairedSignificance, mean, pairedPassSignificance, passByBaseCase, passH
60
60
  *
61
61
  * @packageDocumentation
62
62
  */
63
- /** Canonical version constant. Mirrors the `package.json` version. */
64
- declare const VERSION = "0.6.0";
63
+ declare const VERSION: string;
65
64
  //#endregion
66
65
  export { type AgentLike, type ArgumentValidityOptions, type Case, type CorrectToolSelectedOptions, type Dataset, type EvalCaseResult, type EvalReport, type ExactMatchOptions, type FinalStateCorrectOptions, type FromTracesOptions, type JsonPathOptions, type LlmJudgeOptions, type LoadCsvOptions, type LoadDmrOptions, type LoadJsonlOptions, type LoadLocomoOptions, type LoadLongMemEvalOptions, type MemoryEvalAbility, type MemoryEvalInput, type MemoryEvalSession, type MemoryEvalTurn, type PairedSignificance, type PrebuiltScorerOptions, type PredicateOptions, type ProgressEvent, type RecoveryAfterErrorOptions, type RedundantCallDetectionOptions, type RegexMatchOptions, type RegressionFinding, type RegressionOptions, type RegressionReport, type ReporterFormat, type RunEvalOptions, type RunOptions, type ScoreResult, type Scorer, type TraceEvent, type Trajectory, type TrajectoryToolCall, VERSION, type WriteReportsOptions, type WrittenReport, argumentValidity, correctToolSelected, detectRegressions, detectRegressions as detectRegressionsFromReports, exactMatch, exitOnFailures, factualityScorer, fenceForJudge, finalStateCorrect, fromIterable, helpfulnessScorer, jsonPath, llmJudge, loadCsvDataset, loadDatasetFromTraces, loadDmrDataset, loadJsonlDataset, loadLocomoDataset, loadLongMemEvalDataset, mean, pairedPassSignificance, parseCsv, parseDmr, parseJsonl, parseLocomo, parseLongMemEval, parseScore, passByBaseCase, passHatK, predicate, recoveryAfterError, redundantCallDetection, regexMatch, renderHtmlReport, renderJsonReport, renderJunitReport, renderMarkdownReport, renderTerminalReport, runEvals, sampleStddev, scoreContract, stripIterationSuffix, toxicityScorer, wilsonInterval, writeReports };
67
66
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAgCa,OAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAkCa"}
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { version } from "./package.js";
1
2
  import { mean, pairedPassSignificance, passByBaseCase, passHatK, sampleStddev, stripIterationSuffix, wilsonInterval } from "./stats.js";
2
3
  import { detectRegressions } from "./regression.js";
3
4
  import { renderHtmlReport } from "./reporters/html.js";
@@ -57,8 +58,8 @@ import { redundantCallDetection } from "./scorers/trajectory/redundant-call-dete
57
58
  *
58
59
  * @packageDocumentation
59
60
  */
60
- /** Canonical version constant. Mirrors the `package.json` version. */
61
- const VERSION = "0.6.0";
61
+ /** Canonical version constant, derived from `package.json` at build time. */
62
+ const VERSION = version;
62
63
 
63
64
  //#endregion
64
65
  export { VERSION, argumentValidity, correctToolSelected, detectRegressions, detectRegressions as detectRegressionsFromReports, exactMatch, exitOnFailures, factualityScorer, fenceForJudge, finalStateCorrect, fromIterable, helpfulnessScorer, jsonPath, llmJudge, loadCsvDataset, loadDatasetFromTraces, loadDmrDataset, loadJsonlDataset, loadLocomoDataset, loadLongMemEvalDataset, mean, pairedPassSignificance, parseCsv, parseDmr, parseJsonl, parseLocomo, parseLongMemEval, parseScore, passByBaseCase, passHatK, predicate, recoveryAfterError, redundantCallDetection, regexMatch, renderHtmlReport, renderJsonReport, renderJunitReport, renderMarkdownReport, renderTerminalReport, runEvals, sampleStddev, scoreContract, stripIterationSuffix, toxicityScorer, wilsonInterval, writeReports };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @graphorin/evals - eval framework for the Graphorin framework.\n *\n * Builds on the eval primitives shipped from `@graphorin/observability`\n * (RB-17 / DEC-152) - full orchestrator lives here, post-MVP, decoupled\n * from the core observability bundle so consumers do not pay the\n * dataset / reporter cost when only the inline runner is needed.\n *\n * ```ts\n * import {\n * runEvals,\n * loadJsonlDataset,\n * exactMatch,\n * renderTerminalReport,\n * exitOnFailures,\n * } from '@graphorin/evals';\n *\n * const dataset = await loadJsonlDataset('./fixtures/golden.jsonl');\n * const report = await runEvals({\n * agent,\n * dataset,\n * scorers: [exactMatch()],\n * concurrency: 4,\n * });\n * console.log(renderTerminalReport(report));\n * exitOnFailures(report);\n * ```\n *\n * @packageDocumentation\n */\n\n/** Canonical version constant. Mirrors the `package.json` version. */\nexport const VERSION = '0.6.0';\n\nexport {\n detectRegressions,\n exitOnFailures,\n type ReporterFormat,\n type WriteReportsOptions,\n type WrittenReport,\n writeReports,\n} from './cli/index.js';\nexport type {\n FromTracesOptions,\n LoadDmrOptions,\n LoadLocomoOptions,\n LoadLongMemEvalOptions,\n MemoryEvalAbility,\n MemoryEvalInput,\n MemoryEvalSession,\n MemoryEvalTurn,\n TraceEvent,\n} from './loaders/index.js';\nexport {\n fromIterable,\n type LoadCsvOptions,\n type LoadJsonlOptions,\n loadCsvDataset,\n loadDatasetFromTraces,\n loadDmrDataset,\n loadJsonlDataset,\n loadLocomoDataset,\n loadLongMemEvalDataset,\n parseCsv,\n parseDmr,\n parseJsonl,\n parseLocomo,\n parseLongMemEval,\n} from './loaders/index.js';\nexport { detectRegressions as detectRegressionsFromReports } from './regression.js';\nexport {\n renderHtmlReport,\n renderJsonReport,\n renderJunitReport,\n renderMarkdownReport,\n renderTerminalReport,\n} from './reporters/index.js';\nexport { runEvals } from './runner.js';\nexport {\n type ArgumentValidityOptions,\n argumentValidity,\n type CorrectToolSelectedOptions,\n correctToolSelected,\n type ExactMatchOptions,\n exactMatch,\n type FinalStateCorrectOptions,\n factualityScorer,\n fenceForJudge,\n finalStateCorrect,\n helpfulnessScorer,\n type JsonPathOptions,\n jsonPath,\n type LlmJudgeOptions,\n llmJudge,\n type PrebuiltScorerOptions,\n type PredicateOptions,\n parseScore,\n predicate,\n type RecoveryAfterErrorOptions,\n type RedundantCallDetectionOptions,\n type RegexMatchOptions,\n recoveryAfterError,\n redundantCallDetection,\n regexMatch,\n scoreContract,\n type Trajectory,\n type TrajectoryToolCall,\n toxicityScorer,\n} from './scorers/index.js';\nexport {\n mean,\n type PairedSignificance,\n pairedPassSignificance,\n passByBaseCase,\n passHatK,\n sampleStddev,\n stripIterationSuffix,\n wilsonInterval,\n} from './stats.js';\nexport type {\n AgentLike,\n Case,\n Dataset,\n EvalCaseResult,\n EvalReport,\n ProgressEvent,\n RegressionFinding,\n RegressionOptions,\n RegressionReport,\n RunEvalOptions,\n RunOptions,\n ScoreResult,\n Scorer,\n} from './types.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCA,MAAa,UAAU"}
1
+ {"version":3,"file":"index.js","names":["VERSION: string","pkg.version"],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @graphorin/evals - eval framework for the Graphorin framework.\n *\n * Builds on the eval primitives shipped from `@graphorin/observability`\n * (RB-17 / DEC-152) - full orchestrator lives here, post-MVP, decoupled\n * from the core observability bundle so consumers do not pay the\n * dataset / reporter cost when only the inline runner is needed.\n *\n * ```ts\n * import {\n * runEvals,\n * loadJsonlDataset,\n * exactMatch,\n * renderTerminalReport,\n * exitOnFailures,\n * } from '@graphorin/evals';\n *\n * const dataset = await loadJsonlDataset('./fixtures/golden.jsonl');\n * const report = await runEvals({\n * agent,\n * dataset,\n * scorers: [exactMatch()],\n * concurrency: 4,\n * });\n * console.log(renderTerminalReport(report));\n * exitOnFailures(report);\n * ```\n *\n * @packageDocumentation\n */\n\n/** Canonical version constant, derived from `package.json` at build time. */\nimport pkg from '../package.json' with { type: 'json' };\n\nexport const VERSION: string = pkg.version;\n\nexport {\n detectRegressions,\n exitOnFailures,\n type ReporterFormat,\n type WriteReportsOptions,\n type WrittenReport,\n writeReports,\n} from './cli/index.js';\nexport type {\n FromTracesOptions,\n LoadDmrOptions,\n LoadLocomoOptions,\n LoadLongMemEvalOptions,\n MemoryEvalAbility,\n MemoryEvalInput,\n MemoryEvalSession,\n MemoryEvalTurn,\n TraceEvent,\n} from './loaders/index.js';\nexport {\n fromIterable,\n type LoadCsvOptions,\n type LoadJsonlOptions,\n loadCsvDataset,\n loadDatasetFromTraces,\n loadDmrDataset,\n loadJsonlDataset,\n loadLocomoDataset,\n loadLongMemEvalDataset,\n parseCsv,\n parseDmr,\n parseJsonl,\n parseLocomo,\n parseLongMemEval,\n} from './loaders/index.js';\nexport { detectRegressions as detectRegressionsFromReports } from './regression.js';\nexport {\n renderHtmlReport,\n renderJsonReport,\n renderJunitReport,\n renderMarkdownReport,\n renderTerminalReport,\n} from './reporters/index.js';\nexport { runEvals } from './runner.js';\nexport {\n type ArgumentValidityOptions,\n argumentValidity,\n type CorrectToolSelectedOptions,\n correctToolSelected,\n type ExactMatchOptions,\n exactMatch,\n type FinalStateCorrectOptions,\n factualityScorer,\n fenceForJudge,\n finalStateCorrect,\n helpfulnessScorer,\n type JsonPathOptions,\n jsonPath,\n type LlmJudgeOptions,\n llmJudge,\n type PrebuiltScorerOptions,\n type PredicateOptions,\n parseScore,\n predicate,\n type RecoveryAfterErrorOptions,\n type RedundantCallDetectionOptions,\n type RegexMatchOptions,\n recoveryAfterError,\n redundantCallDetection,\n regexMatch,\n scoreContract,\n type Trajectory,\n type TrajectoryToolCall,\n toxicityScorer,\n} from './scorers/index.js';\nexport {\n mean,\n type PairedSignificance,\n pairedPassSignificance,\n passByBaseCase,\n passHatK,\n sampleStddev,\n stripIterationSuffix,\n wilsonInterval,\n} from './stats.js';\nexport type {\n AgentLike,\n Case,\n Dataset,\n EvalCaseResult,\n EvalReport,\n ProgressEvent,\n RegressionFinding,\n RegressionOptions,\n RegressionReport,\n RunEvalOptions,\n RunOptions,\n ScoreResult,\n Scorer,\n} from './types.js';\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCA,MAAaA,UAAkBC"}
@@ -1 +1 @@
1
- {"version":3,"file":"locomo.d.ts","names":[],"sources":["../../src/loaders/locomo.ts"],"sourcesContent":[],"mappings":";;;;;;UA6CiB,iBAAA;;;;;;;;;;;;;;;iBAgBK,iBAAA,UACX,oBACR,QAAQ,QAAQ;;;;;;;iBAmBH,WAAA,gBAA2B,cAAc,KAAK"}
1
+ {"version":3,"file":"locomo.d.ts","names":[],"sources":["../../src/loaders/locomo.ts"],"sourcesContent":[],"mappings":";;;;;;UAuDiB,iBAAA;;;;;;;;;;;;;;;iBAgBK,iBAAA,UACX,oBACR,QAAQ,QAAQ;;;;;;;iBAmBH,WAAA,gBAA2B,cAAc,KAAK"}
@@ -31,6 +31,16 @@ import { readFile } from "node:fs/promises";
31
31
  * (adversarial), everything else (`3` open-domain, `4` single-hop)
32
32
  * →info-extraction.
33
33
  *
34
+ * Answer handling (W-022): LOCOMO answers may be numbers (e.g. `2022`)
35
+ * - they are stringified, never silently coerced to `''`. A QA pair
36
+ * with NO answer at all (neither `answer` nor `adversarial_answer`) is
37
+ * SKIPPED rather than emitted with an empty `expected`: the LLM judge
38
+ * grading against an empty reference produces meaningless verdicts, so
39
+ * a missing reference must reduce the case count, not poison scores.
40
+ * Turns carry the dataset-native `speaker` name alongside the
41
+ * two-role mapping (~99 percent of LOCOMO questions reference speakers
42
+ * by name).
43
+ *
34
44
  * @packageDocumentation
35
45
  */
36
46
  /**
@@ -79,7 +89,8 @@ function appendSampleCases(sample, index, out) {
79
89
  if (question === void 0) continue;
80
90
  const category = typeof item.category === "number" ? item.category : void 0;
81
91
  const ability = mapCategory(category);
82
- const answer = asString(item.answer) ?? asString(item.adversarial_answer) ?? "";
92
+ const answer = answerToText(item.answer) ?? answerToText(item.adversarial_answer);
93
+ if (answer === void 0) continue;
83
94
  const evidence = asArray(item.evidence).filter((e) => typeof e === "string");
84
95
  out.push({
85
96
  id: `${sampleId}-q${q}`,
@@ -121,7 +132,8 @@ function extractSessions(conversation) {
121
132
  turns.push({
122
133
  role,
123
134
  content,
124
- ...date !== void 0 ? { timestamp: date } : {}
135
+ ...date !== void 0 ? { timestamp: date } : {},
136
+ ...speaker !== void 0 ? { speaker } : {}
125
137
  });
126
138
  }
127
139
  sessions.push({
@@ -143,6 +155,16 @@ function mapCategory(category) {
143
155
  function asString(value) {
144
156
  return typeof value === "string" ? value : void 0;
145
157
  }
158
+ /**
159
+ * LOCOMO reference answers may be strings OR bare numbers (6 of the
160
+ * 1986 QA pairs ship e.g. `2022`). Stringify finite numbers instead of
161
+ * dropping them to `''` (W-022); a blank string counts as "no answer"
162
+ * so the judge never grades against an empty reference.
163
+ */
164
+ function answerToText(value) {
165
+ if (typeof value === "string") return value.trim().length > 0 ? value : void 0;
166
+ if (typeof value === "number" && Number.isFinite(value)) return String(value);
167
+ }
146
168
  function asArray(value) {
147
169
  return Array.isArray(value) ? value : [];
148
170
  }
@@ -1 +1 @@
1
- {"version":3,"file":"locomo.js","names":["parsed: unknown","out: Case<MemoryEvalInput, string>[]","indices: number[]","sessions: MemoryEvalSession[]","turns: MemoryEvalTurn[]","role: 'user' | 'assistant'"],"sources":["../../src/loaders/locomo.ts"],"sourcesContent":["/**\n * Real LOCOMO dataset loader (arXiv:2402.17753 -\n * https://snap-research.github.io/locomo/). LOCOMO ships as a JSON\n * **array** of samples; each sample bundles one multi-session\n * conversation with many QA pairs over it:\n *\n * ```jsonc\n * {\n * \"sample_id\": \"conv-26\",\n * \"conversation\": {\n * \"speaker_a\": \"Caroline\",\n * \"speaker_b\": \"Melanie\",\n * \"session_1_date_time\": \"1:56 pm on 8 May, 2023\",\n * \"session_1\": [ { \"speaker\": \"Caroline\", \"dia_id\": \"D1:1\", \"text\": \"...\" }, ... ],\n * \"session_2_date_time\": \"...\",\n * \"session_2\": [ ... ]\n * },\n * \"qa\": [\n * { \"question\": \"...\", \"answer\": \"...\", \"evidence\": [\"D1:1\"], \"category\": 1 },\n * { \"question\": \"...\", \"category\": 5, \"adversarial_answer\": \"Not mentioned ...\" }\n * ]\n * }\n * ```\n *\n * Each QA pair becomes one {@link MemoryEvalInput} case that shares the\n * sample's sessions. LOCOMO categories map to abilities as:\n * `1`→multi-session (multi-hop), `2`→temporal, `5`→abstention\n * (adversarial), everything else (`3` open-domain, `4` single-hop)\n * →info-extraction.\n *\n * @packageDocumentation\n */\n\nimport { readFile } from 'node:fs/promises';\n\nimport type { Case, Dataset } from '@graphorin/observability/eval';\n\nimport type {\n MemoryEvalAbility,\n MemoryEvalInput,\n MemoryEvalSession,\n MemoryEvalTurn,\n} from './memory-eval.js';\n\n/** @stable */\nexport interface LoadLocomoOptions {\n /** Local path to the LOCOMO JSON (under `benchmarks/.datasets/`). */\n readonly path: string;\n /** Optional dataset name surfaced in `Dataset.metadata.name`. */\n readonly name?: string;\n /** Optional description surfaced in `Dataset.metadata.description`. */\n readonly description?: string;\n}\n\n/**\n * Read a LOCOMO JSON file and return a fully-materialised\n * {@link Dataset} - one case per QA pair, scored against the reference\n * answer string (LLM-judge \"J\").\n *\n * @stable\n */\nexport async function loadLocomoDataset(\n options: LoadLocomoOptions,\n): Promise<Dataset<MemoryEvalInput, string>> {\n const text = await readFile(options.path, 'utf8');\n const cases = parseLocomo(text);\n return {\n cases,\n metadata: {\n name: options.name ?? 'locomo',\n ...(options.description !== undefined ? { description: options.description } : {}),\n createdAt: new Date(),\n },\n };\n}\n\n/**\n * Pure parser. Exported so tests can exercise the mapping without\n * touching the filesystem.\n *\n * @stable\n */\nexport function parseLocomo(text: string): ReadonlyArray<Case<MemoryEvalInput, string>> {\n const parsed: unknown = JSON.parse(text);\n if (!Array.isArray(parsed)) {\n throw new Error('[graphorin/evals] LOCOMO dataset must be a JSON array of samples.');\n }\n const samples = parsed as ReadonlyArray<unknown>;\n const out: Case<MemoryEvalInput, string>[] = [];\n for (let i = 0; i < samples.length; i++) {\n const sample = samples[i];\n if (sample === null || typeof sample !== 'object') {\n throw new Error(`[graphorin/evals] LOCOMO sample ${i} is not an object.`);\n }\n appendSampleCases(sample as Record<string, unknown>, i, out);\n }\n return out;\n}\n\nfunction appendSampleCases(\n sample: Record<string, unknown>,\n index: number,\n out: Case<MemoryEvalInput, string>[],\n): void {\n const sampleId = asString(sample.sample_id) ?? `locomo-${index}`;\n const conversation = isRecord(sample.conversation) ? sample.conversation : {};\n const sessions = extractSessions(conversation);\n const qa = asArray(sample.qa);\n for (let q = 0; q < qa.length; q++) {\n const item = qa[q];\n if (!isRecord(item)) continue;\n const question = asString(item.question);\n if (question === undefined) continue;\n const category = typeof item.category === 'number' ? item.category : undefined;\n const ability = mapCategory(category);\n const answer = asString(item.answer) ?? asString(item.adversarial_answer) ?? '';\n const evidence = asArray(item.evidence).filter((e): e is string => typeof e === 'string');\n out.push({\n id: `${sampleId}-q${q}`,\n input: { haystackSessions: sessions, question, ability },\n expected: answer,\n metadata: {\n datasetName: 'locomo',\n sampleId,\n ability,\n ...(category !== undefined ? { category } : {}),\n evidence,\n },\n });\n }\n}\n\nfunction extractSessions(conversation: Record<string, unknown>): MemoryEvalSession[] {\n const speakerA = asString(conversation.speaker_a);\n const indices: number[] = [];\n for (const key of Object.keys(conversation)) {\n const m = /^session_(\\d+)$/.exec(key);\n if (m?.[1] !== undefined) indices.push(Number.parseInt(m[1], 10));\n }\n indices.sort((a, b) => a - b);\n const sessions: MemoryEvalSession[] = [];\n for (const n of indices) {\n const raw = asArray(conversation[`session_${n}`]);\n const date = asString(conversation[`session_${n}_date_time`]);\n const turns: MemoryEvalTurn[] = [];\n for (const t of raw) {\n if (!isRecord(t)) continue;\n const content = asString(t.text) ?? asString(t.content);\n if (content === undefined) continue;\n const speaker = asString(t.speaker);\n const role: 'user' | 'assistant' =\n speakerA !== undefined && speaker !== undefined && speaker !== speakerA\n ? 'assistant'\n : 'user';\n turns.push({ role, content, ...(date !== undefined ? { timestamp: date } : {}) });\n }\n sessions.push({ id: `session_${n}`, turns });\n }\n return sessions;\n}\n\n/** Maps a LOCOMO numeric `category` onto a {@link MemoryEvalAbility}. */\nfunction mapCategory(category: number | undefined): MemoryEvalAbility {\n switch (category) {\n case 1:\n return 'multi-session';\n case 2:\n return 'temporal';\n case 5:\n return 'abstention';\n default:\n return 'info-extraction';\n }\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction asArray(value: unknown): ReadonlyArray<unknown> {\n return Array.isArray(value) ? (value as ReadonlyArray<unknown>) : [];\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"locomo.js","names":["parsed: unknown","out: Case<MemoryEvalInput, string>[]","indices: number[]","sessions: MemoryEvalSession[]","turns: MemoryEvalTurn[]","role: 'user' | 'assistant'"],"sources":["../../src/loaders/locomo.ts"],"sourcesContent":["/**\n * Real LOCOMO dataset loader (arXiv:2402.17753 -\n * https://snap-research.github.io/locomo/). LOCOMO ships as a JSON\n * **array** of samples; each sample bundles one multi-session\n * conversation with many QA pairs over it:\n *\n * ```jsonc\n * {\n * \"sample_id\": \"conv-26\",\n * \"conversation\": {\n * \"speaker_a\": \"Caroline\",\n * \"speaker_b\": \"Melanie\",\n * \"session_1_date_time\": \"1:56 pm on 8 May, 2023\",\n * \"session_1\": [ { \"speaker\": \"Caroline\", \"dia_id\": \"D1:1\", \"text\": \"...\" }, ... ],\n * \"session_2_date_time\": \"...\",\n * \"session_2\": [ ... ]\n * },\n * \"qa\": [\n * { \"question\": \"...\", \"answer\": \"...\", \"evidence\": [\"D1:1\"], \"category\": 1 },\n * { \"question\": \"...\", \"category\": 5, \"adversarial_answer\": \"Not mentioned ...\" }\n * ]\n * }\n * ```\n *\n * Each QA pair becomes one {@link MemoryEvalInput} case that shares the\n * sample's sessions. LOCOMO categories map to abilities as:\n * `1`→multi-session (multi-hop), `2`→temporal, `5`→abstention\n * (adversarial), everything else (`3` open-domain, `4` single-hop)\n * →info-extraction.\n *\n * Answer handling (W-022): LOCOMO answers may be numbers (e.g. `2022`)\n * - they are stringified, never silently coerced to `''`. A QA pair\n * with NO answer at all (neither `answer` nor `adversarial_answer`) is\n * SKIPPED rather than emitted with an empty `expected`: the LLM judge\n * grading against an empty reference produces meaningless verdicts, so\n * a missing reference must reduce the case count, not poison scores.\n * Turns carry the dataset-native `speaker` name alongside the\n * two-role mapping (~99 percent of LOCOMO questions reference speakers\n * by name).\n *\n * @packageDocumentation\n */\n\nimport { readFile } from 'node:fs/promises';\n\nimport type { Case, Dataset } from '@graphorin/observability/eval';\n\nimport type {\n MemoryEvalAbility,\n MemoryEvalInput,\n MemoryEvalSession,\n MemoryEvalTurn,\n} from './memory-eval.js';\n\n/** @stable */\nexport interface LoadLocomoOptions {\n /** Local path to the LOCOMO JSON (under `benchmarks/.datasets/`). */\n readonly path: string;\n /** Optional dataset name surfaced in `Dataset.metadata.name`. */\n readonly name?: string;\n /** Optional description surfaced in `Dataset.metadata.description`. */\n readonly description?: string;\n}\n\n/**\n * Read a LOCOMO JSON file and return a fully-materialised\n * {@link Dataset} - one case per QA pair, scored against the reference\n * answer string (LLM-judge \"J\").\n *\n * @stable\n */\nexport async function loadLocomoDataset(\n options: LoadLocomoOptions,\n): Promise<Dataset<MemoryEvalInput, string>> {\n const text = await readFile(options.path, 'utf8');\n const cases = parseLocomo(text);\n return {\n cases,\n metadata: {\n name: options.name ?? 'locomo',\n ...(options.description !== undefined ? { description: options.description } : {}),\n createdAt: new Date(),\n },\n };\n}\n\n/**\n * Pure parser. Exported so tests can exercise the mapping without\n * touching the filesystem.\n *\n * @stable\n */\nexport function parseLocomo(text: string): ReadonlyArray<Case<MemoryEvalInput, string>> {\n const parsed: unknown = JSON.parse(text);\n if (!Array.isArray(parsed)) {\n throw new Error('[graphorin/evals] LOCOMO dataset must be a JSON array of samples.');\n }\n const samples = parsed as ReadonlyArray<unknown>;\n const out: Case<MemoryEvalInput, string>[] = [];\n for (let i = 0; i < samples.length; i++) {\n const sample = samples[i];\n if (sample === null || typeof sample !== 'object') {\n throw new Error(`[graphorin/evals] LOCOMO sample ${i} is not an object.`);\n }\n appendSampleCases(sample as Record<string, unknown>, i, out);\n }\n return out;\n}\n\nfunction appendSampleCases(\n sample: Record<string, unknown>,\n index: number,\n out: Case<MemoryEvalInput, string>[],\n): void {\n const sampleId = asString(sample.sample_id) ?? `locomo-${index}`;\n const conversation = isRecord(sample.conversation) ? sample.conversation : {};\n const sessions = extractSessions(conversation);\n const qa = asArray(sample.qa);\n for (let q = 0; q < qa.length; q++) {\n const item = qa[q];\n if (!isRecord(item)) continue;\n const question = asString(item.question);\n if (question === undefined) continue;\n const category = typeof item.category === 'number' ? item.category : undefined;\n const ability = mapCategory(category);\n const answer = answerToText(item.answer) ?? answerToText(item.adversarial_answer);\n // No reference answer at all: skip the pair (see module docs, W-022).\n if (answer === undefined) continue;\n const evidence = asArray(item.evidence).filter((e): e is string => typeof e === 'string');\n out.push({\n id: `${sampleId}-q${q}`,\n input: { haystackSessions: sessions, question, ability },\n expected: answer,\n metadata: {\n datasetName: 'locomo',\n sampleId,\n ability,\n ...(category !== undefined ? { category } : {}),\n evidence,\n },\n });\n }\n}\n\nfunction extractSessions(conversation: Record<string, unknown>): MemoryEvalSession[] {\n const speakerA = asString(conversation.speaker_a);\n const indices: number[] = [];\n for (const key of Object.keys(conversation)) {\n const m = /^session_(\\d+)$/.exec(key);\n if (m?.[1] !== undefined) indices.push(Number.parseInt(m[1], 10));\n }\n indices.sort((a, b) => a - b);\n const sessions: MemoryEvalSession[] = [];\n for (const n of indices) {\n const raw = asArray(conversation[`session_${n}`]);\n const date = asString(conversation[`session_${n}_date_time`]);\n const turns: MemoryEvalTurn[] = [];\n for (const t of raw) {\n if (!isRecord(t)) continue;\n const content = asString(t.text) ?? asString(t.content);\n if (content === undefined) continue;\n const speaker = asString(t.speaker);\n const role: 'user' | 'assistant' =\n speakerA !== undefined && speaker !== undefined && speaker !== speakerA\n ? 'assistant'\n : 'user';\n turns.push({\n role,\n content,\n ...(date !== undefined ? { timestamp: date } : {}),\n // W-022: keep the dataset-native name; the role mapping stays\n // for cross-dataset machinery compatibility.\n ...(speaker !== undefined ? { speaker } : {}),\n });\n }\n sessions.push({ id: `session_${n}`, turns });\n }\n return sessions;\n}\n\n/** Maps a LOCOMO numeric `category` onto a {@link MemoryEvalAbility}. */\nfunction mapCategory(category: number | undefined): MemoryEvalAbility {\n switch (category) {\n case 1:\n return 'multi-session';\n case 2:\n return 'temporal';\n case 5:\n return 'abstention';\n default:\n return 'info-extraction';\n }\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined;\n}\n\n/**\n * LOCOMO reference answers may be strings OR bare numbers (6 of the\n * 1986 QA pairs ship e.g. `2022`). Stringify finite numbers instead of\n * dropping them to `''` (W-022); a blank string counts as \"no answer\"\n * so the judge never grades against an empty reference.\n */\nfunction answerToText(value: unknown): string | undefined {\n if (typeof value === 'string') return value.trim().length > 0 ? value : undefined;\n if (typeof value === 'number' && Number.isFinite(value)) return String(value);\n return undefined;\n}\n\nfunction asArray(value: unknown): ReadonlyArray<unknown> {\n return Array.isArray(value) ? (value as ReadonlyArray<unknown>) : [];\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuEA,eAAsB,kBACpB,SAC2C;AAG3C,QAAO;EACL,OAFY,YADD,MAAM,SAAS,QAAQ,MAAM,OAAO,CAClB;EAG7B,UAAU;GACR,MAAM,QAAQ,QAAQ;GACtB,GAAI,QAAQ,gBAAgB,SAAY,EAAE,aAAa,QAAQ,aAAa,GAAG,EAAE;GACjF,2BAAW,IAAI,MAAM;GACtB;EACF;;;;;;;;AASH,SAAgB,YAAY,MAA4D;CACtF,MAAMA,SAAkB,KAAK,MAAM,KAAK;AACxC,KAAI,CAAC,MAAM,QAAQ,OAAO,CACxB,OAAM,IAAI,MAAM,oEAAoE;CAEtF,MAAM,UAAU;CAChB,MAAMC,MAAuC,EAAE;AAC/C,MAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;EACvC,MAAM,SAAS,QAAQ;AACvB,MAAI,WAAW,QAAQ,OAAO,WAAW,SACvC,OAAM,IAAI,MAAM,mCAAmC,EAAE,oBAAoB;AAE3E,oBAAkB,QAAmC,GAAG,IAAI;;AAE9D,QAAO;;AAGT,SAAS,kBACP,QACA,OACA,KACM;CACN,MAAM,WAAW,SAAS,OAAO,UAAU,IAAI,UAAU;CAEzD,MAAM,WAAW,gBADI,SAAS,OAAO,aAAa,GAAG,OAAO,eAAe,EAAE,CAC/B;CAC9C,MAAM,KAAK,QAAQ,OAAO,GAAG;AAC7B,MAAK,IAAI,IAAI,GAAG,IAAI,GAAG,QAAQ,KAAK;EAClC,MAAM,OAAO,GAAG;AAChB,MAAI,CAAC,SAAS,KAAK,CAAE;EACrB,MAAM,WAAW,SAAS,KAAK,SAAS;AACxC,MAAI,aAAa,OAAW;EAC5B,MAAM,WAAW,OAAO,KAAK,aAAa,WAAW,KAAK,WAAW;EACrE,MAAM,UAAU,YAAY,SAAS;EACrC,MAAM,SAAS,aAAa,KAAK,OAAO,IAAI,aAAa,KAAK,mBAAmB;AAEjF,MAAI,WAAW,OAAW;EAC1B,MAAM,WAAW,QAAQ,KAAK,SAAS,CAAC,QAAQ,MAAmB,OAAO,MAAM,SAAS;AACzF,MAAI,KAAK;GACP,IAAI,GAAG,SAAS,IAAI;GACpB,OAAO;IAAE,kBAAkB;IAAU;IAAU;IAAS;GACxD,UAAU;GACV,UAAU;IACR,aAAa;IACb;IACA;IACA,GAAI,aAAa,SAAY,EAAE,UAAU,GAAG,EAAE;IAC9C;IACD;GACF,CAAC;;;AAIN,SAAS,gBAAgB,cAA4D;CACnF,MAAM,WAAW,SAAS,aAAa,UAAU;CACjD,MAAMC,UAAoB,EAAE;AAC5B,MAAK,MAAM,OAAO,OAAO,KAAK,aAAa,EAAE;EAC3C,MAAM,IAAI,kBAAkB,KAAK,IAAI;AACrC,MAAI,IAAI,OAAO,OAAW,SAAQ,KAAK,OAAO,SAAS,EAAE,IAAI,GAAG,CAAC;;AAEnE,SAAQ,MAAM,GAAG,MAAM,IAAI,EAAE;CAC7B,MAAMC,WAAgC,EAAE;AACxC,MAAK,MAAM,KAAK,SAAS;EACvB,MAAM,MAAM,QAAQ,aAAa,WAAW,KAAK;EACjD,MAAM,OAAO,SAAS,aAAa,WAAW,EAAE,aAAa;EAC7D,MAAMC,QAA0B,EAAE;AAClC,OAAK,MAAM,KAAK,KAAK;AACnB,OAAI,CAAC,SAAS,EAAE,CAAE;GAClB,MAAM,UAAU,SAAS,EAAE,KAAK,IAAI,SAAS,EAAE,QAAQ;AACvD,OAAI,YAAY,OAAW;GAC3B,MAAM,UAAU,SAAS,EAAE,QAAQ;GACnC,MAAMC,OACJ,aAAa,UAAa,YAAY,UAAa,YAAY,WAC3D,cACA;AACN,SAAM,KAAK;IACT;IACA;IACA,GAAI,SAAS,SAAY,EAAE,WAAW,MAAM,GAAG,EAAE;IAGjD,GAAI,YAAY,SAAY,EAAE,SAAS,GAAG,EAAE;IAC7C,CAAC;;AAEJ,WAAS,KAAK;GAAE,IAAI,WAAW;GAAK;GAAO,CAAC;;AAE9C,QAAO;;;AAIT,SAAS,YAAY,UAAiD;AACpE,SAAQ,UAAR;EACE,KAAK,EACH,QAAO;EACT,KAAK,EACH,QAAO;EACT,KAAK,EACH,QAAO;EACT,QACE,QAAO;;;AAIb,SAAS,SAAS,OAAoC;AACpD,QAAO,OAAO,UAAU,WAAW,QAAQ;;;;;;;;AAS7C,SAAS,aAAa,OAAoC;AACxD,KAAI,OAAO,UAAU,SAAU,QAAO,MAAM,MAAM,CAAC,SAAS,IAAI,QAAQ;AACxE,KAAI,OAAO,UAAU,YAAY,OAAO,SAAS,MAAM,CAAE,QAAO,OAAO,MAAM;;AAI/E,SAAS,QAAQ,OAAwC;AACvD,QAAO,MAAM,QAAQ,MAAM,GAAI,QAAmC,EAAE;;AAGtE,SAAS,SAAS,OAAkD;AAClE,QAAO,UAAU,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,MAAM"}
@@ -25,6 +25,14 @@ interface MemoryEvalTurn {
25
25
  readonly content: string;
26
26
  /** Dataset-native (often ISO-8601) timestamp, when the dataset provides one. */
27
27
  readonly timestamp?: string;
28
+ /**
29
+ * Dataset-native speaker NAME (e.g. LOCOMO's `"Melanie"`), when the
30
+ * dataset provides one (W-022). Distinct from `role`: two-speaker
31
+ * datasets map onto user/assistant for machinery compatibility, but
32
+ * most LOCOMO questions reference the speakers by name, so the
33
+ * system under test must see the names in the ingested text.
34
+ */
35
+ readonly speaker?: string;
28
36
  }
29
37
  /**
30
38
  * One prior session in the haystack the memory system must ingest
@@ -1 +1 @@
1
- {"version":3,"file":"memory-eval.d.ts","names":[],"sources":["../../src/loaders/memory-eval.ts"],"sourcesContent":[],"mappings":";;AAsBA;AAaA;AAYA;AAYA;;;;;;;;;;;;;;;;;UArCiB,cAAA;;;;;;;;;;;;UAaA,iBAAA;;kBAEC,cAAc;;;;;;;;;KAUpB,iBAAA;;;;;;UAYK,eAAA;;6BAEY,cAAc;;;;;;;;;qBAStB"}
1
+ {"version":3,"file":"memory-eval.d.ts","names":[],"sources":["../../src/loaders/memory-eval.ts"],"sourcesContent":[],"mappings":";;AAsBA;AAqBA;AAYA;AAYA;;;;;;;;;;;;;;;;;UA7CiB,cAAA;;;;;;;;;;;;;;;;;;;;UAqBA,iBAAA;;kBAEC,cAAc;;;;;;;;;KAUpB,iBAAA;;;;;;UAYK,eAAA;;6BAEY,cAAc;;;;;;;;;qBAStB"}
@@ -0,0 +1,6 @@
1
+ //#region package.json
2
+ var version = "0.7.0";
3
+
4
+ //#endregion
5
+ export { version };
6
+ //# sourceMappingURL=package.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"package.js","names":[],"sources":["../package.json"],"sourcesContent":["{\n \"name\": \"@graphorin/evals\",\n \"version\": \"0.7.0\",\n \"description\": \"Eval framework for the Graphorin framework. Ships scorer libraries (`code/` exact-match, regex, JSON path, predicates; `llm/` LLM-judge; `prebuilt/` toxicity / factuality / helpfulness), dataset loaders (JSONL, CSV, from-traces, generic iterable), reporters (terminal, markdown, JSON, JUnit XML), a parallel runner with `concurrency` config, and regression detection that compares the current run against a stored baseline. Builds on the eval primitives shipped from `@graphorin/observability` (RB-17 / DEC-152 - full orchestrator lives here, post-MVP, decoupled from the core observability bundle so consumers do not pay the dataset / reporter cost when only the inline runner is needed). Created and maintained by Oleksiy Stepurenko.\",\n \"license\": \"MIT\",\n \"author\": \"Oleksiy Stepurenko\",\n \"homepage\": \"https://github.com/o-stepper/graphorin/tree/main/packages/evals\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/o-stepper/graphorin.git\",\n \"directory\": \"packages/evals\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/o-stepper/graphorin/issues\"\n },\n \"keywords\": [\n \"graphorin\",\n \"ai\",\n \"agents\",\n \"framework\",\n \"evals\",\n \"evaluation\",\n \"scorers\",\n \"llm-judge\",\n \"datasets\",\n \"reporters\",\n \"regression-detection\"\n ],\n \"type\": \"module\",\n \"engines\": {\n \"node\": \">=22.12.0\"\n },\n \"main\": \"./dist/index.js\",\n \"module\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"sideEffects\": false,\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"default\": \"./dist/index.js\"\n },\n \"./scorers\": {\n \"types\": \"./dist/scorers/index.d.ts\",\n \"default\": \"./dist/scorers/index.js\"\n },\n \"./loaders\": {\n \"types\": \"./dist/loaders/index.d.ts\",\n \"default\": \"./dist/loaders/index.js\"\n },\n \"./reporters\": {\n \"types\": \"./dist/reporters/index.d.ts\",\n \"default\": \"./dist/reporters/index.js\"\n },\n \"./cli\": {\n \"types\": \"./dist/cli/index.d.ts\",\n \"default\": \"./dist/cli/index.js\"\n },\n \"./package.json\": \"./package.json\"\n },\n \"files\": [\n \"dist\",\n \"src\",\n \"README.md\",\n \"CHANGELOG.md\",\n \"LICENSE\"\n ],\n \"scripts\": {\n \"build\": \"tsdown\",\n \"typecheck\": \"tsc --noEmit && tsc -p tsconfig.tests.json\",\n \"test\": \"vitest run\",\n \"lint\": \"biome check .\",\n \"clean\": \"rimraf dist .turbo *.tsbuildinfo\"\n },\n \"dependencies\": {\n \"@graphorin/core\": \"workspace:*\",\n \"@graphorin/observability\": \"workspace:*\"\n },\n \"publishConfig\": {\n \"access\": \"public\",\n \"provenance\": true\n }\n}\n"],"mappings":";cAEa"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graphorin/evals",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "Eval framework for the Graphorin framework. Ships scorer libraries (`code/` exact-match, regex, JSON path, predicates; `llm/` LLM-judge; `prebuilt/` toxicity / factuality / helpfulness), dataset loaders (JSONL, CSV, from-traces, generic iterable), reporters (terminal, markdown, JSON, JUnit XML), a parallel runner with `concurrency` config, and regression detection that compares the current run against a stored baseline. Builds on the eval primitives shipped from `@graphorin/observability` (RB-17 / DEC-152 - full orchestrator lives here, post-MVP, decoupled from the core observability bundle so consumers do not pay the dataset / reporter cost when only the inline runner is needed). Created and maintained by Oleksiy Stepurenko.",
5
5
  "license": "MIT",
6
6
  "author": "Oleksiy Stepurenko",
@@ -28,7 +28,7 @@
28
28
  ],
29
29
  "type": "module",
30
30
  "engines": {
31
- "node": ">=22.0.0"
31
+ "node": ">=22.12.0"
32
32
  },
33
33
  "main": "./dist/index.js",
34
34
  "module": "./dist/index.js",
@@ -37,35 +37,36 @@
37
37
  "exports": {
38
38
  ".": {
39
39
  "types": "./dist/index.d.ts",
40
- "import": "./dist/index.js"
40
+ "default": "./dist/index.js"
41
41
  },
42
42
  "./scorers": {
43
43
  "types": "./dist/scorers/index.d.ts",
44
- "import": "./dist/scorers/index.js"
44
+ "default": "./dist/scorers/index.js"
45
45
  },
46
46
  "./loaders": {
47
47
  "types": "./dist/loaders/index.d.ts",
48
- "import": "./dist/loaders/index.js"
48
+ "default": "./dist/loaders/index.js"
49
49
  },
50
50
  "./reporters": {
51
51
  "types": "./dist/reporters/index.d.ts",
52
- "import": "./dist/reporters/index.js"
52
+ "default": "./dist/reporters/index.js"
53
53
  },
54
54
  "./cli": {
55
55
  "types": "./dist/cli/index.d.ts",
56
- "import": "./dist/cli/index.js"
56
+ "default": "./dist/cli/index.js"
57
57
  },
58
58
  "./package.json": "./package.json"
59
59
  },
60
60
  "files": [
61
61
  "dist",
62
+ "src",
62
63
  "README.md",
63
64
  "CHANGELOG.md",
64
65
  "LICENSE"
65
66
  ],
66
67
  "dependencies": {
67
- "@graphorin/core": "0.6.0",
68
- "@graphorin/observability": "0.6.0"
68
+ "@graphorin/core": "0.7.0",
69
+ "@graphorin/observability": "0.7.0"
69
70
  },
70
71
  "publishConfig": {
71
72
  "access": "public",
@@ -0,0 +1,124 @@
1
+ /**
2
+ * CLI integration helpers. Convenience wrappers that combine the
3
+ * runner + a reporter + an exit-code mapping so consumer scripts can
4
+ * stay short.
5
+ *
6
+ * Typical use from a `package.json` script:
7
+ *
8
+ * ```jsonc
9
+ * {
10
+ * "scripts": {
11
+ * "eval": "node ./scripts/run-evals.mjs"
12
+ * }
13
+ * }
14
+ * ```
15
+ *
16
+ * Where `run-evals.mjs` looks like:
17
+ *
18
+ * ```ts
19
+ * import { runEvals, exitOnFailures, renderTerminalReport } from '@graphorin/evals';
20
+ *
21
+ * const report = await runEvals({...});
22
+ * console.log(renderTerminalReport(report));
23
+ * exitOnFailures(report);
24
+ * ```
25
+ *
26
+ * @packageDocumentation
27
+ */
28
+
29
+ import { writeFile } from 'node:fs/promises';
30
+ import process from 'node:process';
31
+
32
+ import type { EvalReport } from '@graphorin/observability/eval';
33
+
34
+ import { detectRegressions } from '../regression.js';
35
+ import {
36
+ renderHtmlReport,
37
+ renderJsonReport,
38
+ renderJunitReport,
39
+ renderMarkdownReport,
40
+ renderTerminalReport,
41
+ } from '../reporters/index.js';
42
+ import type { RegressionOptions, RegressionReport } from '../types.js';
43
+
44
+ /**
45
+ * Set `process.exitCode` to `1` when at least one case failed, or
46
+ * when a regression report contains findings. Uses `exitCode` rather
47
+ * than `process.exit` so other async tasks finish cleanly.
48
+ *
49
+ * @stable
50
+ */
51
+ export function exitOnFailures<I, O>(
52
+ report: EvalReport<I, O>,
53
+ regression?: RegressionReport<I, O>,
54
+ ): void {
55
+ if (report.summary.failed > 0) process.exitCode = 1;
56
+ if (regression?.hasRegressions) process.exitCode = 1;
57
+ }
58
+
59
+ /**
60
+ * Reporter ids accepted by {@link writeReports}.
61
+ *
62
+ * @stable
63
+ */
64
+ export type ReporterFormat = 'terminal' | 'markdown' | 'json' | 'junit' | 'html';
65
+
66
+ /** @stable */
67
+ export interface WriteReportsOptions<I, O> {
68
+ readonly report: EvalReport<I, O>;
69
+ readonly outDir?: string;
70
+ readonly formats: ReadonlyArray<ReporterFormat>;
71
+ readonly basename?: string;
72
+ }
73
+
74
+ /** @stable */
75
+ export interface WrittenReport {
76
+ readonly format: ReporterFormat;
77
+ readonly path: string;
78
+ readonly bytes: number;
79
+ }
80
+
81
+ /**
82
+ * Render the report in every requested format and write each one to a
83
+ * file. Returns the manifest of written files.
84
+ *
85
+ * @stable
86
+ */
87
+ export async function writeReports<I, O>(
88
+ options: WriteReportsOptions<I, O>,
89
+ ): Promise<ReadonlyArray<WrittenReport>> {
90
+ const out: WrittenReport[] = [];
91
+ const dir = options.outDir ?? '.';
92
+ const basename = options.basename ?? 'eval-report';
93
+ for (const format of options.formats) {
94
+ const { extension, body } = renderForFormat(format, options.report);
95
+ const path = `${dir}/${basename}.${extension}`;
96
+ await writeFile(path, body, 'utf8');
97
+ out.push({ format, path, bytes: Buffer.byteLength(body, 'utf8') });
98
+ }
99
+ return out;
100
+ }
101
+
102
+ function renderForFormat<I, O>(
103
+ format: ReporterFormat,
104
+ report: EvalReport<I, O>,
105
+ ): { extension: string; body: string } {
106
+ switch (format) {
107
+ case 'terminal':
108
+ return { extension: 'txt', body: renderTerminalReport(report) };
109
+ case 'markdown':
110
+ return { extension: 'md', body: renderMarkdownReport(report) };
111
+ case 'json':
112
+ return { extension: 'json', body: renderJsonReport(report, { pretty: true }) };
113
+ case 'junit':
114
+ return { extension: 'xml', body: renderJunitReport(report) };
115
+ case 'html':
116
+ return { extension: 'html', body: renderHtmlReport(report) };
117
+ default: {
118
+ const exhaustive: never = format;
119
+ throw new Error(`unknown reporter format '${exhaustive as string}'`);
120
+ }
121
+ }
122
+ }
123
+
124
+ export { detectRegressions, type RegressionOptions };
package/src/index.ts ADDED
@@ -0,0 +1,136 @@
1
+ /**
2
+ * @graphorin/evals - eval framework for the Graphorin framework.
3
+ *
4
+ * Builds on the eval primitives shipped from `@graphorin/observability`
5
+ * (RB-17 / DEC-152) - full orchestrator lives here, post-MVP, decoupled
6
+ * from the core observability bundle so consumers do not pay the
7
+ * dataset / reporter cost when only the inline runner is needed.
8
+ *
9
+ * ```ts
10
+ * import {
11
+ * runEvals,
12
+ * loadJsonlDataset,
13
+ * exactMatch,
14
+ * renderTerminalReport,
15
+ * exitOnFailures,
16
+ * } from '@graphorin/evals';
17
+ *
18
+ * const dataset = await loadJsonlDataset('./fixtures/golden.jsonl');
19
+ * const report = await runEvals({
20
+ * agent,
21
+ * dataset,
22
+ * scorers: [exactMatch()],
23
+ * concurrency: 4,
24
+ * });
25
+ * console.log(renderTerminalReport(report));
26
+ * exitOnFailures(report);
27
+ * ```
28
+ *
29
+ * @packageDocumentation
30
+ */
31
+
32
+ /** Canonical version constant, derived from `package.json` at build time. */
33
+ import pkg from '../package.json' with { type: 'json' };
34
+
35
+ export const VERSION: string = pkg.version;
36
+
37
+ export {
38
+ detectRegressions,
39
+ exitOnFailures,
40
+ type ReporterFormat,
41
+ type WriteReportsOptions,
42
+ type WrittenReport,
43
+ writeReports,
44
+ } from './cli/index.js';
45
+ export type {
46
+ FromTracesOptions,
47
+ LoadDmrOptions,
48
+ LoadLocomoOptions,
49
+ LoadLongMemEvalOptions,
50
+ MemoryEvalAbility,
51
+ MemoryEvalInput,
52
+ MemoryEvalSession,
53
+ MemoryEvalTurn,
54
+ TraceEvent,
55
+ } from './loaders/index.js';
56
+ export {
57
+ fromIterable,
58
+ type LoadCsvOptions,
59
+ type LoadJsonlOptions,
60
+ loadCsvDataset,
61
+ loadDatasetFromTraces,
62
+ loadDmrDataset,
63
+ loadJsonlDataset,
64
+ loadLocomoDataset,
65
+ loadLongMemEvalDataset,
66
+ parseCsv,
67
+ parseDmr,
68
+ parseJsonl,
69
+ parseLocomo,
70
+ parseLongMemEval,
71
+ } from './loaders/index.js';
72
+ export { detectRegressions as detectRegressionsFromReports } from './regression.js';
73
+ export {
74
+ renderHtmlReport,
75
+ renderJsonReport,
76
+ renderJunitReport,
77
+ renderMarkdownReport,
78
+ renderTerminalReport,
79
+ } from './reporters/index.js';
80
+ export { runEvals } from './runner.js';
81
+ export {
82
+ type ArgumentValidityOptions,
83
+ argumentValidity,
84
+ type CorrectToolSelectedOptions,
85
+ correctToolSelected,
86
+ type ExactMatchOptions,
87
+ exactMatch,
88
+ type FinalStateCorrectOptions,
89
+ factualityScorer,
90
+ fenceForJudge,
91
+ finalStateCorrect,
92
+ helpfulnessScorer,
93
+ type JsonPathOptions,
94
+ jsonPath,
95
+ type LlmJudgeOptions,
96
+ llmJudge,
97
+ type PrebuiltScorerOptions,
98
+ type PredicateOptions,
99
+ parseScore,
100
+ predicate,
101
+ type RecoveryAfterErrorOptions,
102
+ type RedundantCallDetectionOptions,
103
+ type RegexMatchOptions,
104
+ recoveryAfterError,
105
+ redundantCallDetection,
106
+ regexMatch,
107
+ scoreContract,
108
+ type Trajectory,
109
+ type TrajectoryToolCall,
110
+ toxicityScorer,
111
+ } from './scorers/index.js';
112
+ export {
113
+ mean,
114
+ type PairedSignificance,
115
+ pairedPassSignificance,
116
+ passByBaseCase,
117
+ passHatK,
118
+ sampleStddev,
119
+ stripIterationSuffix,
120
+ wilsonInterval,
121
+ } from './stats.js';
122
+ export type {
123
+ AgentLike,
124
+ Case,
125
+ Dataset,
126
+ EvalCaseResult,
127
+ EvalReport,
128
+ ProgressEvent,
129
+ RegressionFinding,
130
+ RegressionOptions,
131
+ RegressionReport,
132
+ RunEvalOptions,
133
+ RunOptions,
134
+ ScoreResult,
135
+ Scorer,
136
+ } from './types.js';