@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.
- package/README.md +74 -7
- package/dist/{chunk-NPKIP4SB.js → chunk-BWBX5YVQ.js} +245 -164
- package/dist/chunk-BWBX5YVQ.js.map +1 -0
- package/dist/cli.cjs +537 -214
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +305 -52
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +327 -177
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +199 -18
- package/dist/index.d.ts +199 -18
- package/dist/index.js +91 -17
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/dist/chunk-NPKIP4SB.js.map +0 -1
|
@@ -64,10 +64,52 @@ function xorshift32(seed) {
|
|
|
64
64
|
};
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
// src/
|
|
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/
|
|
299
|
-
function
|
|
300
|
-
|
|
301
|
-
const
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
const
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
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
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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: {
|
|
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
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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:
|
|
768
|
-
std:
|
|
769
|
-
min:
|
|
770
|
-
max:
|
|
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:
|
|
779
|
-
std:
|
|
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:
|
|
788
|
-
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-
|
|
884
|
+
//# sourceMappingURL=chunk-BWBX5YVQ.js.map
|