@axlsdk/eval 0.17.8 → 0.18.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.
@@ -64,10 +64,52 @@ function xorshift32(seed) {
64
64
  };
65
65
  }
66
66
 
67
- // src/compare.ts
67
+ // src/utils.ts
68
+ function computeStats(scores) {
69
+ if (scores.length === 0) return { mean: 0, min: 0, max: 0, p50: 0, p95: 0 };
70
+ const sorted = [...scores].sort((a, b) => a - b);
71
+ const mean = sorted.reduce((a, b) => a + b, 0) / sorted.length;
72
+ const min = sorted[0];
73
+ const max = sorted[sorted.length - 1];
74
+ const p50 = sorted[Math.floor(sorted.length * 0.5)];
75
+ const p95 = sorted[Math.floor(sorted.length * 0.95)];
76
+ return { mean: round2(mean), min: round2(min), max: round2(max), p50: round2(p50), p95: round2(p95) };
77
+ }
68
78
  function round2(n) {
69
79
  return Math.round(n * 1e3) / 1e3;
70
80
  }
81
+ function scorerCounts(items, name) {
82
+ let scored = 0;
83
+ let failed = 0;
84
+ for (const i of items) {
85
+ if (i.error) continue;
86
+ if (i.scores[name] != null) scored++;
87
+ else if (i.scoreDetails?.[name]?.duration != null) failed++;
88
+ }
89
+ return { scored, failed };
90
+ }
91
+ function evaluateScorerTolerance(scored, failed, type, limit) {
92
+ const attempted = scored + failed;
93
+ const rate = attempted === 0 ? 0 : failed / attempted;
94
+ const exceeds = attempted > 0 && (type === "deterministic" ? failed > 0 : rate > limit);
95
+ return { attempted, rate, exceeds, zeroSample: attempted === 0 };
96
+ }
97
+ async function mapWithConcurrency(items, concurrency, task) {
98
+ const results = new Array(items.length);
99
+ const requested = Number.isFinite(concurrency) ? Math.floor(concurrency) : 1;
100
+ const workerCount = items.length === 0 ? 0 : Math.min(Math.max(1, requested), items.length);
101
+ let next = 0;
102
+ async function runNext() {
103
+ while (next < items.length) {
104
+ const i = next++;
105
+ results[i] = await task(items[i], i);
106
+ }
107
+ }
108
+ await Promise.all(Array.from({ length: workerCount }, () => runNext()));
109
+ return results;
110
+ }
111
+
112
+ // src/compare.ts
71
113
  var DEFAULT_LLM_THRESHOLD = 0.05;
72
114
  var DEFAULT_DETERMINISTIC_THRESHOLD = 0;
73
115
  var LEGACY_THRESHOLD = 0.1;
@@ -141,11 +183,29 @@ function evalCompare(baseline, candidate, options) {
141
183
  const delta = round2(deltaRaw);
142
184
  const deltaPercent = bMeanRaw > 0 ? round2(deltaRaw / bMeanRaw * 100) : 0;
143
185
  const threshold = resolveThreshold(name, options, baselineRef.metadata);
186
+ let baselineScored = 0;
187
+ let baselineFailed = 0;
188
+ for (const run of baselineRuns) {
189
+ const c = scorerCounts(run.items, name);
190
+ baselineScored += c.scored;
191
+ baselineFailed += c.failed;
192
+ }
193
+ let candidateScored = 0;
194
+ let candidateFailed = 0;
195
+ for (const run of candidateRuns) {
196
+ const c = scorerCounts(run.items, name);
197
+ candidateScored += c.scored;
198
+ candidateFailed += c.failed;
199
+ }
144
200
  const entry = {
145
201
  baselineMean: bMean,
146
202
  candidateMean: cMean,
147
203
  delta,
148
- deltaPercent
204
+ deltaPercent,
205
+ baselineScored,
206
+ baselineFailed,
207
+ candidateScored,
208
+ candidateFailed
149
209
  };
150
210
  const diffs = pairedDiffs[name];
151
211
  if (diffs.length >= 2) {
@@ -281,11 +341,41 @@ function detectPartial(runs) {
281
341
  if (runs.length >= attempted) return void 0;
282
342
  return { completed: runs.length, attempted };
283
343
  }
344
+ function evaluateScorerErrorRateGate(comparison, maxScorerErrorRate) {
345
+ const scorerTypes = comparison.baseline.metadata?.scorerTypes ?? {};
346
+ for (const name of Object.keys(comparison.scorers)) {
347
+ const s = comparison.scorers[name];
348
+ const type = scorerTypes[name] === "deterministic" ? "deterministic" : "llm";
349
+ const limit = type === "deterministic" ? 0 : maxScorerErrorRate;
350
+ for (const side of ["baseline", "candidate"]) {
351
+ const scored = (side === "baseline" ? s.baselineScored : s.candidateScored) ?? 0;
352
+ const failed = (side === "baseline" ? s.baselineFailed : s.candidateFailed) ?? 0;
353
+ const verdict = evaluateScorerTolerance(scored, failed, type, limit);
354
+ if (verdict.zeroSample) {
355
+ return `scorer "${name}" has no scored items on ${side} (its items errored or were skipped) \u2014 cannot certify a mean over an empty sample.`;
356
+ }
357
+ if (verdict.exceeds) {
358
+ const limitStr = type === "deterministic" ? "deterministic zero-tolerance" : `${(limit * 100).toFixed(1)}%`;
359
+ return `scorer "${name}" failed ${(verdict.rate * 100).toFixed(1)}% on ${side} (${failed}/${verdict.attempted}), over the ${limitStr} limit.`;
360
+ }
361
+ }
362
+ }
363
+ return null;
364
+ }
284
365
 
285
366
  // src/scorer.ts
286
367
  function normalizeScorerResult(result) {
287
368
  return typeof result === "number" ? { score: result } : result;
288
369
  }
370
+ function attachScorerErrorCost(err, cost) {
371
+ if (err && typeof err === "object" && typeof cost === "number" && Number.isFinite(cost) && cost >= 0) {
372
+ err.cost = cost;
373
+ }
374
+ }
375
+ function extractScorerErrorCost(err) {
376
+ const v = err && typeof err === "object" ? err.cost : void 0;
377
+ return typeof v === "number" && Number.isFinite(v) && v >= 0 ? v : void 0;
378
+ }
289
379
  function scorer(config) {
290
380
  return {
291
381
  name: config.name,
@@ -295,19 +385,60 @@ function scorer(config) {
295
385
  };
296
386
  }
297
387
 
298
- // src/utils.ts
299
- function computeStats(scores) {
300
- if (scores.length === 0) return { mean: 0, min: 0, max: 0, p50: 0, p95: 0 };
301
- const sorted = [...scores].sort((a, b) => a - b);
302
- const mean = sorted.reduce((a, b) => a + b, 0) / sorted.length;
303
- const min = sorted[0];
304
- const max = sorted[sorted.length - 1];
305
- const p50 = sorted[Math.floor(sorted.length * 0.5)];
306
- const p95 = sorted[Math.floor(sorted.length * 0.95)];
307
- return { mean: round3(mean), min: round3(min), max: round3(max), p50: round3(p50), p95: round3(p95) };
308
- }
309
- function round3(n) {
310
- return Math.round(n * 1e3) / 1e3;
388
+ // src/score-item.ts
389
+ async function scoreItem(item, scorers, scorerConcurrency, scorerContext, signal) {
390
+ const scoreDetails = item.scoreDetails ??= {};
391
+ for (const s of scorers) {
392
+ item.scores[s.name] = null;
393
+ scoreDetails[s.name] = { score: null };
394
+ }
395
+ let itemScorerCost = 0;
396
+ const scorerErrorsByName = {};
397
+ await mapWithConcurrency(scorers, scorerConcurrency, async (scorer2) => {
398
+ if (signal?.aborted) return;
399
+ const scorerStart = Date.now();
400
+ try {
401
+ const raw = await scorer2.score(item.output, item.input, item.annotations, scorerContext);
402
+ const scorerResult = normalizeScorerResult(raw);
403
+ if (scorerResult.cost != null) {
404
+ itemScorerCost += scorerResult.cost;
405
+ }
406
+ const scorerDuration = Date.now() - scorerStart;
407
+ if (!Number.isFinite(scorerResult.score) || scorerResult.score < 0 || scorerResult.score > 1) {
408
+ scorerErrorsByName[scorer2.name] = `Scorer "${scorer2.name}" returned out-of-range score ${scorerResult.score} for input ${JSON.stringify(item.input)}`;
409
+ item.scores[scorer2.name] = null;
410
+ scoreDetails[scorer2.name] = {
411
+ score: null,
412
+ metadata: scorerResult.metadata,
413
+ duration: scorerDuration,
414
+ cost: scorerResult.cost
415
+ };
416
+ } else {
417
+ item.scores[scorer2.name] = round2(scorerResult.score);
418
+ scoreDetails[scorer2.name] = {
419
+ score: round2(scorerResult.score),
420
+ metadata: scorerResult.metadata,
421
+ duration: scorerDuration,
422
+ cost: scorerResult.cost
423
+ };
424
+ }
425
+ } catch (err) {
426
+ if (err?.name === "AbortError") return;
427
+ const errCost = extractScorerErrorCost(err);
428
+ if (errCost != null) itemScorerCost += errCost;
429
+ scorerErrorsByName[scorer2.name] = `Scorer "${scorer2.name}" threw: ${err instanceof Error ? err.message : String(err)}`;
430
+ item.scores[scorer2.name] = null;
431
+ scoreDetails[scorer2.name] = {
432
+ score: null,
433
+ duration: Date.now() - scorerStart,
434
+ cost: errCost
435
+ };
436
+ }
437
+ });
438
+ const orderedErrors = scorers.map((s) => scorerErrorsByName[s.name]).filter((e) => e != null);
439
+ if (orderedErrors.length > 0) item.scorerErrors = orderedErrors;
440
+ item.scorerCost = itemScorerCost > 0 ? itemScorerCost : void 0;
441
+ return itemScorerCost;
311
442
  }
312
443
 
313
444
  // src/runner.ts
@@ -350,7 +481,9 @@ async function runEval(config, executeWorkflow, runtime, options) {
350
481
  const startTime = Date.now();
351
482
  const id = randomUUID();
352
483
  const items = await config.dataset.getItems();
484
+ const droppedAnnotationKeys = [...config.dataset.droppedAnnotationKeys ?? []];
353
485
  const concurrency = config.concurrency ?? 5;
486
+ const scorerConcurrency = config.scorerConcurrency ?? 5;
354
487
  const budgetLimit = config.budget ? parseCost(config.budget) : void 0;
355
488
  const scorerContext = {
356
489
  resolveProvider: (uri) => {
@@ -360,7 +493,8 @@ async function runEval(config, executeWorkflow, runtime, options) {
360
493
  );
361
494
  }
362
495
  return runtime.resolveProvider(uri);
363
- }
496
+ },
497
+ signal: options?.signal
364
498
  };
365
499
  const evalItems = new Array(items.length);
366
500
  let totalCost = 0;
@@ -438,89 +572,53 @@ async function runEval(config, executeWorkflow, runtime, options) {
438
572
  if (budgetLimit != null && totalCost > budgetLimit) {
439
573
  budgetExceeded = true;
440
574
  }
441
- evalItem.scoreDetails = {};
442
- let itemScorerCost = 0;
443
- for (const scorer2 of config.scorers) {
444
- if (options?.signal?.aborted) break;
445
- const scorerStart = Date.now();
446
- try {
447
- const raw = await scorer2.score(
448
- evalItem.output,
449
- item.input,
450
- item.annotations,
451
- scorerContext
452
- );
453
- const scorerResult = normalizeScorerResult(raw);
454
- if (scorerResult.cost != null) {
455
- itemScorerCost += scorerResult.cost;
456
- totalCost += scorerResult.cost;
457
- }
458
- const scorerDuration = Date.now() - scorerStart;
459
- if (!Number.isFinite(scorerResult.score) || scorerResult.score < 0 || scorerResult.score > 1) {
460
- if (!evalItem.scorerErrors) evalItem.scorerErrors = [];
461
- evalItem.scorerErrors.push(
462
- `Scorer "${scorer2.name}" returned out-of-range score ${scorerResult.score} for input ${JSON.stringify(item.input)}`
463
- );
464
- evalItem.scores[scorer2.name] = null;
465
- evalItem.scoreDetails[scorer2.name] = {
466
- score: null,
467
- metadata: scorerResult.metadata,
468
- duration: scorerDuration,
469
- cost: scorerResult.cost
470
- };
471
- } else {
472
- evalItem.scores[scorer2.name] = round3(scorerResult.score);
473
- evalItem.scoreDetails[scorer2.name] = {
474
- score: round3(scorerResult.score),
475
- metadata: scorerResult.metadata,
476
- duration: scorerDuration,
477
- cost: scorerResult.cost
478
- };
479
- }
480
- } catch (err) {
481
- const errCost = typeof err?.cost === "number" ? err.cost : void 0;
482
- if (errCost != null) {
483
- itemScorerCost += errCost;
484
- totalCost += errCost;
485
- }
486
- if (!evalItem.scorerErrors) evalItem.scorerErrors = [];
487
- evalItem.scorerErrors.push(
488
- `Scorer "${scorer2.name}" threw: ${err instanceof Error ? err.message : String(err)}`
489
- );
490
- evalItem.scores[scorer2.name] = null;
491
- evalItem.scoreDetails[scorer2.name] = {
492
- score: null,
493
- duration: Date.now() - scorerStart,
494
- cost: errCost
495
- };
496
- }
497
- }
498
- evalItem.scorerCost = itemScorerCost > 0 ? itemScorerCost : void 0;
575
+ const itemScorerCost = await scoreItem(
576
+ evalItem,
577
+ config.scorers,
578
+ scorerConcurrency,
579
+ scorerContext,
580
+ options?.signal
581
+ );
582
+ totalCost += itemScorerCost;
499
583
  evalItems[itemIndex] = evalItem;
500
584
  options?.onProgress?.({ type: "item_done", itemIndex, totalItems: items.length });
501
585
  }
502
- let index = 0;
503
- async function runNext() {
504
- while (index < items.length) {
505
- const currentIndex = index++;
506
- await processItem(items[currentIndex], currentIndex);
507
- }
508
- }
509
- const workers = Array.from({ length: Math.min(concurrency, items.length) }, () => runNext());
510
- await Promise.all(workers);
586
+ await mapWithConcurrency(items, concurrency, (item, i) => processItem(item, i));
511
587
  const failures = evalItems.filter((i) => i.error).length;
512
588
  const scorerNames = config.scorers.map((s) => s.name);
513
589
  const scorerStats = {};
514
590
  for (const name of scorerNames) {
515
591
  const scores = evalItems.filter((i) => !i.error && i.scores[name] != null).map((i) => i.scores[name]);
516
- scorerStats[name] = computeStats(scores);
592
+ const { scored, failed } = scorerCounts(evalItems, name);
593
+ scorerStats[name] = { ...computeStats(scores), scored, failed };
517
594
  }
518
- const durations = evalItems.filter((i) => !i.error && i.duration != null).map((i) => i.duration);
519
- const timing = durations.length > 0 ? computeStats(durations) : void 0;
520
595
  const scorerTypes = {};
521
596
  for (const s of config.scorers) {
522
597
  scorerTypes[s.name] = s.isLlm ? "llm" : "deterministic";
523
598
  }
599
+ let degraded;
600
+ const rawLimit = config.failOnScorerErrorRate;
601
+ if (rawLimit != null) {
602
+ if (!Number.isFinite(rawLimit) || rawLimit < 0 || rawLimit > 1) {
603
+ console.warn(
604
+ `[axl-eval] Ignoring invalid failOnScorerErrorRate (${rawLimit}); expected a number in [0, 1].`
605
+ );
606
+ } else {
607
+ for (const name of scorerNames) {
608
+ const stats = scorerStats[name];
609
+ const scored = stats.scored ?? 0;
610
+ const failed = stats.failed ?? 0;
611
+ const type = scorerTypes[name] === "llm" ? "llm" : "deterministic";
612
+ const limit = type === "deterministic" ? 0 : rawLimit;
613
+ const verdict = evaluateScorerTolerance(scored, failed, type, limit);
614
+ if (verdict.exceeds) {
615
+ (degraded ??= []).push({ scorer: name, rate: verdict.rate, limit, type, scored, failed });
616
+ }
617
+ }
618
+ }
619
+ }
620
+ const durations = evalItems.filter((i) => !i.error && i.duration != null).map((i) => i.duration);
621
+ const timing = durations.length > 0 ? computeStats(durations) : void 0;
524
622
  const totalModelCalls = /* @__PURE__ */ new Map();
525
623
  for (const item of evalItems) {
526
624
  const itemCounts = item.metadata?.modelCallCounts;
@@ -579,13 +677,20 @@ async function runEval(config, executeWorkflow, runtime, options) {
579
677
  ...config.metadata,
580
678
  scorerTypes,
581
679
  ...modelsMeta,
582
- ...workflowsMeta
680
+ ...workflowsMeta,
681
+ ...droppedAnnotationKeys.length > 0 ? { droppedAnnotationKeys } : {}
583
682
  },
584
683
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
585
684
  totalCost,
586
685
  duration: Date.now() - startTime,
587
686
  items: evalItems,
588
- summary: { count: items.length, failures, scorers: scorerStats, timing }
687
+ summary: {
688
+ count: items.length,
689
+ failures,
690
+ scorers: scorerStats,
691
+ timing,
692
+ ...degraded ? { degraded } : {}
693
+ }
589
694
  };
590
695
  }
591
696
 
@@ -594,6 +699,7 @@ import { randomUUID as randomUUID2 } from "crypto";
594
699
  async function rescore(result, scorers, runtime, options) {
595
700
  const startTime = Date.now();
596
701
  const concurrency = options?.concurrency ?? 5;
702
+ const scorerConcurrency = options?.scorerConcurrency ?? 5;
597
703
  const scorerContext = {
598
704
  resolveProvider: (uri) => {
599
705
  if (typeof runtime.resolveProvider !== "function") {
@@ -602,11 +708,22 @@ async function rescore(result, scorers, runtime, options) {
602
708
  );
603
709
  }
604
710
  return runtime.resolveProvider(uri);
605
- }
711
+ },
712
+ signal: options?.signal
606
713
  };
607
714
  const rescored = new Array(result.items.length);
608
715
  let totalCost = 0;
609
716
  async function rescoreItem(original, itemIndex) {
717
+ if (options?.signal?.aborted) {
718
+ rescored[itemIndex] = {
719
+ input: original.input,
720
+ annotations: original.annotations,
721
+ output: original.output,
722
+ error: "cancelled",
723
+ scores: {}
724
+ };
725
+ return;
726
+ }
610
727
  if (original.error) {
611
728
  rescored[itemIndex] = {
612
729
  input: original.input,
@@ -626,77 +743,24 @@ async function rescore(result, scorers, runtime, options) {
626
743
  scores: {},
627
744
  scoreDetails: {}
628
745
  };
629
- let itemScorerCost = 0;
630
- for (const scorer2 of scorers) {
631
- const scorerStart = Date.now();
632
- try {
633
- const raw = await scorer2.score(item.output, item.input, item.annotations, scorerContext);
634
- const scorerResult = normalizeScorerResult(raw);
635
- if (scorerResult.cost != null) {
636
- itemScorerCost += scorerResult.cost;
637
- totalCost += scorerResult.cost;
638
- }
639
- const scorerDuration = Date.now() - scorerStart;
640
- if (!Number.isFinite(scorerResult.score) || scorerResult.score < 0 || scorerResult.score > 1) {
641
- if (!item.scorerErrors) item.scorerErrors = [];
642
- item.scorerErrors.push(
643
- `Scorer "${scorer2.name}" returned out-of-range score ${scorerResult.score} for input ${JSON.stringify(item.input)}`
644
- );
645
- item.scores[scorer2.name] = null;
646
- item.scoreDetails[scorer2.name] = {
647
- score: null,
648
- metadata: scorerResult.metadata,
649
- duration: scorerDuration,
650
- cost: scorerResult.cost
651
- };
652
- } else {
653
- item.scores[scorer2.name] = round3(scorerResult.score);
654
- item.scoreDetails[scorer2.name] = {
655
- score: round3(scorerResult.score),
656
- metadata: scorerResult.metadata,
657
- duration: scorerDuration,
658
- cost: scorerResult.cost
659
- };
660
- }
661
- } catch (err) {
662
- const errCost = typeof err?.cost === "number" ? err.cost : void 0;
663
- if (errCost != null) {
664
- itemScorerCost += errCost;
665
- totalCost += errCost;
666
- }
667
- if (!item.scorerErrors) item.scorerErrors = [];
668
- item.scorerErrors.push(
669
- `Scorer "${scorer2.name}" threw: ${err instanceof Error ? err.message : String(err)}`
670
- );
671
- item.scores[scorer2.name] = null;
672
- item.scoreDetails[scorer2.name] = {
673
- score: null,
674
- duration: Date.now() - scorerStart,
675
- cost: errCost
676
- };
677
- }
678
- }
679
- item.scorerCost = itemScorerCost > 0 ? itemScorerCost : void 0;
746
+ const itemScorerCost = await scoreItem(
747
+ item,
748
+ scorers,
749
+ scorerConcurrency,
750
+ scorerContext,
751
+ options?.signal
752
+ );
753
+ totalCost += itemScorerCost;
680
754
  rescored[itemIndex] = item;
681
755
  }
682
- let index = 0;
683
- async function runNext() {
684
- while (index < result.items.length) {
685
- const currentIndex = index++;
686
- await rescoreItem(result.items[currentIndex], currentIndex);
687
- }
688
- }
689
- const workers = Array.from(
690
- { length: Math.min(concurrency, result.items.length) },
691
- () => runNext()
692
- );
693
- await Promise.all(workers);
756
+ await mapWithConcurrency(result.items, concurrency, (item, i) => rescoreItem(item, i));
694
757
  const failures = rescored.filter((i) => i.error).length;
695
758
  const scorerNames = scorers.map((s) => s.name);
696
759
  const scorerStats = {};
697
760
  for (const name of scorerNames) {
698
761
  const scores = rescored.filter((i) => !i.error && i.scores[name] != null).map((i) => i.scores[name]);
699
- scorerStats[name] = computeStats(scores);
762
+ const { scored, failed } = scorerCounts(rescored, name);
763
+ scorerStats[name] = { ...computeStats(scores), scored, failed };
700
764
  }
701
765
  const scorerTypes = {};
702
766
  for (const s of scorers) {
@@ -706,7 +770,11 @@ async function rescore(result, scorers, runtime, options) {
706
770
  id: randomUUID2(),
707
771
  dataset: result.dataset,
708
772
  metadata: (() => {
709
- const { runGroupId: _, runIndex: __, ...rest } = result.metadata;
773
+ const rest = { ...result.metadata };
774
+ delete rest.runGroupId;
775
+ delete rest.runIndex;
776
+ delete rest.scorerFiltered;
777
+ delete rest.scorersRun;
710
778
  const merged = {
711
779
  ...rest,
712
780
  rescored: true,
@@ -759,15 +827,24 @@ function aggregateRuns(runs) {
759
827
  const scorerNames = Object.keys(runs[0].summary.scorers);
760
828
  const scorers = {};
761
829
  for (const name of scorerNames) {
762
- const means = runs.map((r) => r.summary.scorers[name]?.mean ?? 0);
830
+ const contributing = runs.filter((r) => {
831
+ const sc = r.summary.scorers[name]?.scored;
832
+ return sc == null || sc > 0;
833
+ });
834
+ const meanSource = contributing.length > 0 ? contributing : runs;
835
+ const means = meanSource.map((r) => r.summary.scorers[name]?.mean ?? 0);
763
836
  const meanOfMeans = means.reduce((a, b) => a + b, 0) / means.length;
764
837
  const minMean = Math.min(...means);
765
838
  const maxMean = Math.max(...means);
839
+ const scored = runs.reduce((sum, r) => sum + (r.summary.scorers[name]?.scored ?? 0), 0);
840
+ const failed = runs.reduce((sum, r) => sum + (r.summary.scorers[name]?.failed ?? 0), 0);
766
841
  scorers[name] = {
767
- mean: round3(meanOfMeans),
768
- std: round3(std(means, meanOfMeans)),
769
- min: round3(minMean),
770
- max: round3(maxMean)
842
+ mean: round2(meanOfMeans),
843
+ std: round2(std(means, meanOfMeans)),
844
+ min: round2(minMean),
845
+ max: round2(maxMean),
846
+ scored,
847
+ failed
771
848
  };
772
849
  }
773
850
  let timing;
@@ -775,8 +852,8 @@ function aggregateRuns(runs) {
775
852
  if (timingMeans.length === runs.length && timingMeans.length > 0) {
776
853
  const meanTiming = timingMeans.reduce((a, b) => a + b, 0) / timingMeans.length;
777
854
  timing = {
778
- mean: round3(meanTiming),
779
- std: round3(std(timingMeans, meanTiming))
855
+ mean: round2(meanTiming),
856
+ std: round2(std(timingMeans, meanTiming))
780
857
  };
781
858
  }
782
859
  return {
@@ -784,8 +861,8 @@ function aggregateRuns(runs) {
784
861
  runCount: runs.length,
785
862
  workflows,
786
863
  dataset,
787
- totalCost: round3(totalCost),
788
- totalDuration: round3(totalDuration),
864
+ totalCost: round2(totalCost),
865
+ totalDuration: round2(totalDuration),
789
866
  scorers,
790
867
  timing
791
868
  };
@@ -793,11 +870,15 @@ function aggregateRuns(runs) {
793
870
 
794
871
  export {
795
872
  pairedBootstrapCI,
873
+ scorerCounts,
874
+ evaluateScorerTolerance,
796
875
  evalCompare,
876
+ evaluateScorerErrorRateGate,
797
877
  normalizeScorerResult,
878
+ attachScorerErrorCost,
798
879
  scorer,
799
880
  runEval,
800
881
  rescore,
801
882
  aggregateRuns
802
883
  };
803
- //# sourceMappingURL=chunk-NPKIP4SB.js.map
884
+ //# sourceMappingURL=chunk-BWBX5YVQ.js.map