@m4trix/evals 0.20.0 → 0.21.1

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/dist/cli.cjs CHANGED
@@ -13,7 +13,8 @@ var fs = require('fs');
13
13
  var jitiModule = require('jiti');
14
14
  var promises = require('fs/promises');
15
15
  var url = require('url');
16
- var jsonDiff = require('json-diff');
16
+ var diff = require('diff');
17
+ var stringify = require('fast-json-stable-stringify');
17
18
 
18
19
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
19
20
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -38,6 +39,7 @@ function _interopNamespace(e) {
38
39
 
39
40
  var React2__default = /*#__PURE__*/_interopDefault(React2);
40
41
  var jitiModule__namespace = /*#__PURE__*/_interopNamespace(jitiModule);
42
+ var stringify__default = /*#__PURE__*/_interopDefault(stringify);
41
43
 
42
44
  var SEP = " ";
43
45
  var ARROW = "\u203A";
@@ -1004,10 +1006,102 @@ async function collectTestCasesFromFiles(config) {
1004
1006
  );
1005
1007
  return found.flat();
1006
1008
  }
1009
+ function preprocessForDiff(value, options) {
1010
+ if (options?.sort && Array.isArray(value)) {
1011
+ return [...value].sort((a, b) => {
1012
+ const aStr = stringify__default.default(preprocessForDiff(a, options));
1013
+ const bStr = stringify__default.default(preprocessForDiff(b, options));
1014
+ return aStr.localeCompare(bStr);
1015
+ }).map((item) => preprocessForDiff(item, options));
1016
+ }
1017
+ if (value !== null && typeof value === "object" && !Array.isArray(value) && options?.excludeKeys) {
1018
+ const keys = Array.isArray(options.excludeKeys) ? options.excludeKeys : options.excludeKeys.split(",").map((k) => k.trim());
1019
+ const filtered = {};
1020
+ for (const [k, v] of Object.entries(value)) {
1021
+ if (!keys.includes(k)) {
1022
+ filtered[k] = preprocessForDiff(v, options);
1023
+ }
1024
+ }
1025
+ return filtered;
1026
+ }
1027
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
1028
+ const result = {};
1029
+ for (const [k, v] of Object.entries(value)) {
1030
+ result[k] = preprocessForDiff(v, options);
1031
+ }
1032
+ return result;
1033
+ }
1034
+ if (typeof value === "number" && options?.precision !== void 0) {
1035
+ return Number(value.toFixed(options.precision));
1036
+ }
1037
+ return value;
1038
+ }
1039
+ function toPrettyJson(value) {
1040
+ const str = stringify__default.default(value);
1041
+ try {
1042
+ const parsed = JSON.parse(str);
1043
+ return JSON.stringify(parsed, null, 2);
1044
+ } catch {
1045
+ return str;
1046
+ }
1047
+ }
1048
+ function formatDiffParts(parts) {
1049
+ const lines = [];
1050
+ for (const part of parts) {
1051
+ const prefix = part.added ? "+ " : part.removed ? "- " : "";
1052
+ const partLines = part.value.split("\n");
1053
+ for (let i = 0; i < partLines.length; i++) {
1054
+ const line = partLines[i];
1055
+ if (i === partLines.length - 1 && line === "")
1056
+ continue;
1057
+ lines.push(prefix + line);
1058
+ }
1059
+ }
1060
+ return lines.join("\n");
1061
+ }
1007
1062
  function createDiffString(expected, actual, diffOptions) {
1008
- const opts = { ...diffOptions, color: false };
1009
- const result = jsonDiff.diffString(expected, actual, opts);
1010
- return typeof result === "string" ? result : "";
1063
+ const expectedProcessed = preprocessForDiff(expected, diffOptions);
1064
+ const actualProcessed = preprocessForDiff(actual, diffOptions);
1065
+ if (diffOptions?.keysOnly) {
1066
+ const expectedKeys = JSON.stringify(
1067
+ extractKeys(expectedProcessed),
1068
+ null,
1069
+ 2
1070
+ );
1071
+ const actualKeys = JSON.stringify(
1072
+ extractKeys(actualProcessed),
1073
+ null,
1074
+ 2
1075
+ );
1076
+ const parts2 = diff.diffLines(expectedKeys, actualKeys);
1077
+ return formatDiffParts(parts2);
1078
+ }
1079
+ const expectedStr = toPrettyJson(expectedProcessed);
1080
+ const actualStr = toPrettyJson(actualProcessed);
1081
+ if (expectedStr === actualStr) {
1082
+ return "";
1083
+ }
1084
+ const parts = diff.diffLines(expectedStr, actualStr);
1085
+ if (diffOptions?.outputNewOnly) {
1086
+ const filtered = parts.filter(
1087
+ (p) => p.added === true
1088
+ );
1089
+ return formatDiffParts(filtered);
1090
+ }
1091
+ return formatDiffParts(parts);
1092
+ }
1093
+ function extractKeys(value) {
1094
+ if (value === null || typeof value !== "object") {
1095
+ return "\xB7";
1096
+ }
1097
+ if (Array.isArray(value)) {
1098
+ return value.map(extractKeys);
1099
+ }
1100
+ const result = {};
1101
+ for (const [k, v] of Object.entries(value)) {
1102
+ result[k] = extractKeys(v);
1103
+ }
1104
+ return result;
1011
1105
  }
1012
1106
  function formatLogMessage(msg) {
1013
1107
  if (typeof msg === "string")
@@ -1358,13 +1452,27 @@ function createArtifactPath(artifactDirectory, datasetId, runId) {
1358
1452
  `${datasetId}_${runId}_${nowIsoForFile()}.jsonl`
1359
1453
  );
1360
1454
  }
1361
- function processOneTestCase(task, testCaseItem, totalEvaluations, publishEvent, persistenceQueue, updateSnapshot, completedRef, passedRef, failedRef) {
1455
+ function processOneTestCase(task, testCaseItem, totalEvaluations, publishEvent, persistenceQueue, updateSnapshot, startedRef, completedRef, passedRef, failedRef) {
1362
1456
  return effect.Effect.gen(function* () {
1363
1457
  const reruns = typeof testCaseItem.testCase.getReruns === "function" ? testCaseItem.testCase.getReruns() : 1;
1364
1458
  const rerunPassed = [];
1365
1459
  for (let r = 0; r < reruns; r++) {
1366
1460
  const evaluatorRunId = `run-${crypto.randomUUID()}`;
1367
1461
  const started = Date.now();
1462
+ const startedEvaluations = yield* effect.Ref.modify(startedRef, (n) => [
1463
+ n + 1,
1464
+ n + 1
1465
+ ]);
1466
+ yield* publishEvent({
1467
+ type: "TestCaseStarted",
1468
+ runId: task.runId,
1469
+ testCaseId: testCaseItem.id,
1470
+ testCaseName: testCaseItem.testCase.getName(),
1471
+ startedTestCases: startedEvaluations,
1472
+ totalTestCases: totalEvaluations,
1473
+ rerunIndex: r + 1,
1474
+ rerunTotal: reruns
1475
+ });
1368
1476
  const evaluatorScores = [];
1369
1477
  let testCaseError;
1370
1478
  const output = readOutput(testCaseItem.testCase);
@@ -1510,6 +1618,7 @@ var executeRunTask = (task, publishEvent, persistenceQueue, updateSnapshot) => e
1510
1618
  );
1511
1619
  const maxConcurrency = Math.max(1, task.maxConcurrency ?? 1);
1512
1620
  const completedRef = yield* effect.Ref.make(0);
1621
+ const startedRef = yield* effect.Ref.make(0);
1513
1622
  const passedRef = yield* effect.Ref.make(0);
1514
1623
  const failedRef = yield* effect.Ref.make(0);
1515
1624
  const processTestCase = (testCaseItem) => processOneTestCase(
@@ -1519,6 +1628,7 @@ var executeRunTask = (task, publishEvent, persistenceQueue, updateSnapshot) => e
1519
1628
  publishEvent,
1520
1629
  persistenceQueue,
1521
1630
  updateSnapshot,
1631
+ startedRef,
1522
1632
  completedRef,
1523
1633
  passedRef,
1524
1634
  failedRef