@deepagents/evals 0.19.0 → 0.20.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.
@@ -1 +1 @@
1
- {"version":3,"file":"console.d.ts","sourceRoot":"","sources":["../../src/reporters/console.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAc,QAAQ,EAAc,SAAS,EAAE,MAAM,YAAY,CAAC;AAE9E,MAAM,WAAW,sBAAsB;IACrC,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAED,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,QAAQ,CAwD1E"}
1
+ {"version":3,"file":"console.d.ts","sourceRoot":"","sources":["../../src/reporters/console.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAc,QAAQ,EAAc,SAAS,EAAE,MAAM,YAAY,CAAC;AAE9E,MAAM,WAAW,sBAAsB;IACrC,SAAS,CAAC,EAAE,SAAS,CAAC;CACvB;AAsBD,wBAAgB,eAAe,CAAC,OAAO,CAAC,EAAE,sBAAsB,GAAG,QAAQ,CAyD1E"}
@@ -1 +1 @@
1
- {"version":3,"file":"csv.d.ts","sourceRoot":"","sources":["../../src/reporters/csv.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,WAAW,kBAAkB;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,WAAW,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,QAAQ,CA4ClE"}
1
+ {"version":3,"file":"csv.d.ts","sourceRoot":"","sources":["../../src/reporters/csv.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,WAAW,kBAAkB;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,WAAW,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,QAAQ,CA+ClE"}
@@ -1 +1 @@
1
- {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/reporters/html.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAc,MAAM,YAAY,CAAC;AAEvD,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,YAAY,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,QAAQ,CAMpE"}
1
+ {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/reporters/html.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,QAAQ,EAAc,MAAM,YAAY,CAAC;AAEvD,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,YAAY,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,QAAQ,CAMpE"}
@@ -80,26 +80,51 @@ function createRunEndFileReporter(options) {
80
80
  }
81
81
 
82
82
  // packages/evals/src/reporters/console.ts
83
+ var BAR_WIDTH = 20;
84
+ function renderProgressBar(completed, total, elapsedMs) {
85
+ const pct = total > 0 ? completed / total : 0;
86
+ const filled = Math.round(pct * BAR_WIDTH);
87
+ const bar = "\u2593".repeat(filled) + "\u2591".repeat(BAR_WIDTH - filled);
88
+ const pctStr = `${(pct * 100).toFixed(0)}%`;
89
+ return ` ${bar} ${pctStr} (${completed}/${total}) ${formatDuration(elapsedMs)}`;
90
+ }
91
+ function statusLabel(status) {
92
+ if (status === "pass") return chalk.green("PASS");
93
+ if (status === "error") return chalk.yellow("ERROR");
94
+ return chalk.red("FAIL");
95
+ }
83
96
  function consoleReporter(options) {
84
97
  const verbosity = options?.verbosity ?? "normal";
85
98
  let totalCases = 0;
86
99
  let completed = 0;
100
+ let startTime = 0;
87
101
  return {
88
102
  onRunStart(data) {
89
103
  totalCases = data.totalCases;
90
104
  completed = 0;
105
+ startTime = Date.now();
106
+ if (verbosity !== "quiet") {
107
+ const label = data.name;
108
+ console.log("");
109
+ console.log(
110
+ ` ${chalk.dim("\u2500\u2500")} ${chalk.bold(label)} ${chalk.dim("\u2500".repeat(Math.max(0, 56 - label.length)))}`
111
+ );
112
+ console.log(` ${chalk.dim(`Running ${data.totalCases} cases...`)}`);
113
+ console.log("");
114
+ }
91
115
  },
92
116
  onCaseEnd() {
93
117
  completed++;
94
118
  if (verbosity !== "quiet") {
119
+ const elapsed = Date.now() - startTime;
95
120
  process.stdout.write(
96
- `\r ${chalk.dim(`[${completed}/${totalCases}]`)}`
121
+ `\r${renderProgressBar(completed, totalCases, elapsed)}`
97
122
  );
98
123
  }
99
124
  },
100
125
  onRunEnd(data) {
101
126
  if (verbosity !== "quiet") {
102
- process.stdout.write("\r" + " ".repeat(30) + "\r");
127
+ process.stdout.write("\r" + " ".repeat(70) + "\r");
103
128
  }
104
129
  renderSummaryTable(data);
105
130
  if (verbosity === "quiet") return;
@@ -112,19 +137,7 @@ function consoleReporter(options) {
112
137
  });
113
138
  }
114
139
  } else {
115
- const failing = sorted.filter(
116
- (c) => getCaseStatus(c, data.threshold) !== "pass"
117
- );
118
- if (failing.length > 0) {
119
- console.log(chalk.dim(` Failing cases (${failing.length}):`));
120
- console.log("");
121
- for (const c of failing) {
122
- renderCaseDetail(c, data.threshold, {
123
- includeIO: true,
124
- maxStringLength: 4e3
125
- });
126
- }
127
- }
140
+ renderFailuresByScorer(sorted, data.threshold);
128
141
  }
129
142
  }
130
143
  };
@@ -139,38 +152,51 @@ function truncateString(text, maxLength) {
139
152
  }
140
153
  function renderSummaryTable(data) {
141
154
  const { summary } = data;
142
- const scoreStr = Object.entries(summary.meanScores).map(([name, score]) => `${name}: ${score.toFixed(3)}`).join(", ");
155
+ const passRate = summary.totalCases > 0 ? (summary.passCount / summary.totalCases * 100).toFixed(1) : "0.0";
143
156
  console.log("");
144
157
  console.log(chalk.bold(" Summary"));
145
158
  console.log(chalk.dim(" " + "\u2500".repeat(60)));
146
- console.log(` ${chalk.dim("Eval:")} ${data.name}`);
147
- console.log(` ${chalk.dim("Model:")} ${data.model}`);
148
- console.log(` ${chalk.dim("Cases:")} ${summary.totalCases}`);
159
+ console.log(` ${chalk.dim("Eval:")} ${data.name}`);
160
+ console.log(` ${chalk.dim("Model:")} ${data.model}`);
161
+ console.log(` ${chalk.dim("Threshold:")} ${data.threshold}`);
162
+ console.log(` ${chalk.dim("Cases:")} ${summary.totalCases}`);
149
163
  console.log(
150
- ` ${chalk.dim("Pass/Fail:")} ${chalk.green(String(summary.passCount))} / ${chalk.red(String(summary.failCount))}`
164
+ ` ${chalk.dim("Pass/Fail:")} ${chalk.green(String(summary.passCount))} / ${chalk.red(String(summary.failCount))} ${chalk.dim(`(${passRate}%)`)}`
151
165
  );
152
- console.log(` ${chalk.dim("Scores:")} ${scoreStr}`);
153
166
  console.log(
154
- ` ${chalk.dim("Duration:")} ${formatDuration(summary.totalLatencyMs)}`
167
+ ` ${chalk.dim("Duration:")} ${formatDuration(summary.totalLatencyMs)}`
155
168
  );
156
169
  console.log(
157
- ` ${chalk.dim("Tokens:")} ${formatTokens(summary.totalTokensIn + summary.totalTokensOut)}`
170
+ ` ${chalk.dim("Tokens:")} ${chalk.dim("In:")} ${formatTokens(summary.totalTokensIn)} ${chalk.dim("Out:")} ${formatTokens(summary.totalTokensOut)} ${chalk.dim("Total:")} ${formatTokens(summary.totalTokensIn + summary.totalTokensOut)}`
158
171
  );
172
+ const scoreEntries = Object.entries(summary.meanScores);
173
+ if (scoreEntries.length > 0) {
174
+ console.log("");
175
+ console.log(chalk.bold(" Scores"));
176
+ for (const [name, score] of scoreEntries) {
177
+ const scoreColor = score >= data.threshold ? chalk.green : chalk.red;
178
+ console.log(
179
+ ` ${chalk.dim(name + ":")}${" ".repeat(Math.max(1, 12 - name.length))}${scoreColor(score.toFixed(3))}`
180
+ );
181
+ }
182
+ }
159
183
  console.log(chalk.dim(" " + "\u2500".repeat(60)));
160
184
  console.log("");
161
185
  }
162
186
  function renderCaseDetail(c, threshold, options) {
163
187
  const entries = Object.entries(c.scores);
164
- const failed = entries.some(([, s]) => s.score < threshold);
165
- const prefix = failed ? chalk.red("FAIL") : chalk.green("PASS");
188
+ const status = getCaseStatus(c, threshold);
189
+ const prefix = statusLabel(status);
166
190
  const includeIO = options?.includeIO ?? false;
167
191
  const maxStringLength = options?.maxStringLength ?? 4e3;
168
- console.log(` ${prefix} ${chalk.dim(`Case #${c.index}`)}`);
192
+ const meta = `${chalk.dim(formatDuration(c.latencyMs))} ${chalk.dim(`${c.tokensIn}/${c.tokensOut} tokens`)}`;
193
+ console.log(` ${prefix} ${chalk.dim(`Case #${c.index}`)} ${meta}`);
169
194
  const inputStr = stringifyUnknown(c.input, {
170
195
  space: 2,
171
196
  fallback: String(c.input)
172
197
  });
173
- console.log(` ${chalk.dim("Input:")} ${inputStr}`);
198
+ console.log(` ${chalk.dim("Input:")}`);
199
+ console.log(indentBlock(truncateString(inputStr, maxStringLength), 6));
174
200
  if (includeIO) {
175
201
  console.log(` ${chalk.dim("Output:")}`);
176
202
  console.log(indentBlock(truncateString(c.output, maxStringLength), 6));
@@ -197,6 +223,37 @@ function renderCaseDetail(c, threshold, options) {
197
223
  }
198
224
  console.log("");
199
225
  }
226
+ function renderFailuresByScorer(cases, threshold) {
227
+ const scorerNames = /* @__PURE__ */ new Set();
228
+ for (const c of cases) {
229
+ for (const name of Object.keys(c.scores)) {
230
+ scorerNames.add(name);
231
+ }
232
+ }
233
+ let hasFailures = false;
234
+ for (const scorer of scorerNames) {
235
+ const failing = cases.filter((c) => {
236
+ const s = c.scores[scorer];
237
+ return s && s.score < threshold || getCaseStatus(c, threshold) === "error";
238
+ });
239
+ if (failing.length === 0) continue;
240
+ if (!hasFailures) {
241
+ console.log(chalk.dim(" Failing by scorer:"));
242
+ console.log("");
243
+ hasFailures = true;
244
+ }
245
+ console.log(
246
+ ` ${chalk.bold(scorer)} ${chalk.dim(`(${failing.length} failures)`)}`
247
+ );
248
+ console.log(chalk.dim(" " + "\u2500".repeat(40)));
249
+ for (const c of failing) {
250
+ renderCaseDetail(c, threshold, {
251
+ includeIO: true,
252
+ maxStringLength: 4e3
253
+ });
254
+ }
255
+ }
256
+ }
200
257
 
201
258
  // packages/evals/src/reporters/json.ts
202
259
  import { appendFile, mkdir as mkdir2 } from "node:fs/promises";
@@ -238,6 +295,7 @@ function csvReporter(options) {
238
295
  const scorerNames = Object.keys(data.summary.meanScores);
239
296
  const headerParts = [
240
297
  "index",
298
+ "status",
241
299
  "input",
242
300
  "output",
243
301
  "expected",
@@ -251,8 +309,10 @@ function csvReporter(options) {
251
309
  }
252
310
  const rows = [headerParts.join(",")];
253
311
  for (const c of data.cases) {
312
+ const status = getCaseStatus(c, data.threshold);
254
313
  const parts = [
255
314
  String(c.index),
315
+ status,
256
316
  escapeCsv(c.input),
257
317
  escapeCsv(c.output),
258
318
  escapeCsv(c.expected),
@@ -281,15 +341,17 @@ function markdownReporter(options) {
281
341
  const { summary } = data;
282
342
  const scorerNames = Object.keys(summary.meanScores);
283
343
  const lines = [];
344
+ const passRate = summary.totalCases > 0 ? (summary.passCount / summary.totalCases * 100).toFixed(1) : "0.0";
284
345
  lines.push(`# ${data.name}`);
285
346
  lines.push("");
286
347
  lines.push(`**Model:** ${data.model}`);
348
+ lines.push(`**Threshold:** ${data.threshold}`);
287
349
  lines.push(
288
- `**Cases:** ${summary.totalCases} (${summary.passCount} pass, ${summary.failCount} fail)`
350
+ `**Cases:** ${summary.totalCases} (${summary.passCount} pass, ${summary.failCount} fail, ${passRate}%)`
289
351
  );
290
352
  lines.push(`**Duration:** ${formatDuration(summary.totalLatencyMs)}`);
291
353
  lines.push(
292
- `**Tokens:** ${formatTokens(summary.totalTokensIn + summary.totalTokensOut)}`
354
+ `**Tokens:** In: ${formatTokens(summary.totalTokensIn)} | Out: ${formatTokens(summary.totalTokensOut)} | Total: ${formatTokens(summary.totalTokensIn + summary.totalTokensOut)}`
293
355
  );
294
356
  lines.push("");
295
357
  lines.push("## Scores");
@@ -308,6 +370,7 @@ function markdownReporter(options) {
308
370
  "Input",
309
371
  ...scorerNames,
310
372
  "Latency",
373
+ "Tokens",
311
374
  "Error"
312
375
  ];
313
376
  lines.push(`| ${caseHeader.join(" | ")} |`);
@@ -325,7 +388,8 @@ function markdownReporter(options) {
325
388
  status,
326
389
  input,
327
390
  ...scores,
328
- `${c.latencyMs}ms`,
391
+ formatDuration(c.latencyMs),
392
+ `${c.tokensIn}/${c.tokensOut}`,
329
393
  error
330
394
  ];
331
395
  lines.push(`| ${row.join(" | ")} |`);
@@ -350,9 +414,10 @@ function esc(str) {
350
414
  function renderHtml(data) {
351
415
  const { summary } = data;
352
416
  const scorerNames = Object.keys(summary.meanScores);
417
+ const passRate = summary.totalCases > 0 ? (summary.passCount / summary.totalCases * 100).toFixed(1) : "0.0";
353
418
  const caseRows = data.cases.map((c) => {
354
419
  const status = getCaseStatus(c, data.threshold);
355
- const statusLabel = status === "error" ? "ERROR" : status === "pass" ? "PASS" : "FAIL";
420
+ const statusLabel2 = status === "error" ? "ERROR" : status === "pass" ? "PASS" : "FAIL";
356
421
  const scoresCells = scorerNames.map((name) => {
357
422
  const s = c.scores[name];
358
423
  const score = s?.score ?? 0;
@@ -360,13 +425,19 @@ function renderHtml(data) {
360
425
  const reason = s?.reason ? ` title="${esc(s.reason)}"` : "";
361
426
  return `<td class="${cls}"${reason}>${score.toFixed(3)}</td>`;
362
427
  }).join("");
428
+ const expectedStr = stringifyUnknown(c.expected, {
429
+ space: 0,
430
+ fallback: ""
431
+ });
363
432
  return `<tr class="${status}">
364
433
  <td>${c.index}</td>
365
- <td class="${status}">${statusLabel}</td>
434
+ <td class="${status}">${statusLabel2}</td>
366
435
  <td class="text">${esc(formatInputValue(c.input).slice(0, 120))}</td>
367
436
  <td class="text">${esc(c.output.slice(0, 120))}</td>
437
+ <td class="text">${esc(expectedStr.slice(0, 120))}</td>
368
438
  ${scoresCells}
369
- <td>${c.latencyMs}ms</td>
439
+ <td>${formatDuration(c.latencyMs)}</td>
440
+ <td>${c.tokensIn}/${c.tokensOut}</td>
370
441
  <td class="error-text">${c.error ? esc(formatErrorValue(c.error)) : ""}</td>
371
442
  </tr>`;
372
443
  }).join("\n");
@@ -404,11 +475,14 @@ function renderHtml(data) {
404
475
  <h1>${esc(data.name)}</h1>
405
476
  <div class="meta">
406
477
  <span><strong>Model:</strong> ${esc(data.model)}</span>
478
+ <span><strong>Threshold:</strong> ${data.threshold}</span>
407
479
  <span><strong>Cases:</strong> ${summary.totalCases}</span>
408
480
  <span><strong>Pass:</strong> ${summary.passCount}</span>
409
- <span><strong>Fail:</strong> ${summary.failCount}</span>
481
+ <span><strong>Fail:</strong> ${summary.failCount} (${passRate}%)</span>
410
482
  <span><strong>Duration:</strong> ${formatDuration(summary.totalLatencyMs)}</span>
411
- <span><strong>Tokens:</strong> ${formatTokens(summary.totalTokensIn + summary.totalTokensOut)}</span>
483
+ <span><strong>Tokens In:</strong> ${formatTokens(summary.totalTokensIn)}</span>
484
+ <span><strong>Tokens Out:</strong> ${formatTokens(summary.totalTokensOut)}</span>
485
+ <span><strong>Total Tokens:</strong> ${formatTokens(summary.totalTokensIn + summary.totalTokensOut)}</span>
412
486
  </div>
413
487
 
414
488
  <h2>Mean Scores</h2>
@@ -425,8 +499,10 @@ function renderHtml(data) {
425
499
  <th>Status</th>
426
500
  <th>Input</th>
427
501
  <th>Output</th>
502
+ <th>Expected</th>
428
503
  ${scorerHeaders}
429
504
  <th>Latency</th>
505
+ <th>Tokens</th>
430
506
  <th>Error</th>
431
507
  </tr>
432
508
  </thead>
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/reporters/console.ts", "../../src/reporters/format.ts", "../../src/reporters/shared.ts", "../../src/reporters/json.ts", "../../src/reporters/csv.ts", "../../src/reporters/markdown.ts", "../../src/reporters/html.ts"],
4
- "sourcesContent": ["import chalk from 'chalk';\n\nimport {\n formatDuration,\n formatErrorValue,\n formatTokens,\n stringifyUnknown,\n} from './format.ts';\nimport { getCaseStatus } from './shared.ts';\nimport type { CaseResult, Reporter, RunEndData, Verbosity } from './types.ts';\n\nexport interface ConsoleReporterOptions {\n verbosity?: Verbosity;\n}\n\nexport function consoleReporter(options?: ConsoleReporterOptions): Reporter {\n const verbosity = options?.verbosity ?? 'normal';\n\n let totalCases = 0;\n let completed = 0;\n\n return {\n onRunStart(data) {\n totalCases = data.totalCases;\n completed = 0;\n },\n\n onCaseEnd() {\n completed++;\n if (verbosity !== 'quiet') {\n process.stdout.write(\n `\\r ${chalk.dim(`[${completed}/${totalCases}]`)}`,\n );\n }\n },\n\n onRunEnd(data) {\n if (verbosity !== 'quiet') {\n process.stdout.write('\\r' + ' '.repeat(30) + '\\r');\n }\n\n renderSummaryTable(data);\n\n if (verbosity === 'quiet') return;\n\n const sorted = [...data.cases].sort((a, b) => a.index - b.index);\n\n if (verbosity === 'verbose') {\n for (const c of sorted) {\n renderCaseDetail(c, data.threshold, {\n includeIO: true,\n maxStringLength: 20_000,\n });\n }\n } else {\n const failing = sorted.filter(\n (c) => getCaseStatus(c, data.threshold) !== 'pass',\n );\n if (failing.length > 0) {\n console.log(chalk.dim(` Failing cases (${failing.length}):`));\n console.log('');\n for (const c of failing) {\n renderCaseDetail(c, data.threshold, {\n includeIO: true,\n maxStringLength: 4_000,\n });\n }\n }\n }\n },\n };\n}\n\nfunction indentBlock(text: string, spaces: number): string {\n const pad = ' '.repeat(spaces);\n return text\n .replace(/\\r\\n/g, '\\n')\n .split('\\n')\n .map((line) => pad + line)\n .join('\\n');\n}\n\nfunction truncateString(text: string, maxLength: number): string {\n if (text.length <= maxLength) return text;\n return text.slice(0, maxLength) + '\u2026';\n}\n\nfunction renderSummaryTable(data: RunEndData): void {\n const { summary } = data;\n const scoreStr = Object.entries(summary.meanScores)\n .map(([name, score]) => `${name}: ${score.toFixed(3)}`)\n .join(', ');\n\n console.log('');\n console.log(chalk.bold(' Summary'));\n console.log(chalk.dim(' ' + '\u2500'.repeat(60)));\n console.log(` ${chalk.dim('Eval:')} ${data.name}`);\n console.log(` ${chalk.dim('Model:')} ${data.model}`);\n console.log(` ${chalk.dim('Cases:')} ${summary.totalCases}`);\n console.log(\n ` ${chalk.dim('Pass/Fail:')} ${chalk.green(String(summary.passCount))} / ${chalk.red(String(summary.failCount))}`,\n );\n console.log(` ${chalk.dim('Scores:')} ${scoreStr}`);\n console.log(\n ` ${chalk.dim('Duration:')} ${formatDuration(summary.totalLatencyMs)}`,\n );\n console.log(\n ` ${chalk.dim('Tokens:')} ${formatTokens(summary.totalTokensIn + summary.totalTokensOut)}`,\n );\n console.log(chalk.dim(' ' + '\u2500'.repeat(60)));\n console.log('');\n}\n\nfunction renderCaseDetail(\n c: CaseResult,\n threshold: number,\n options?: {\n includeIO?: boolean;\n maxStringLength?: number;\n },\n): void {\n const entries = Object.entries(c.scores);\n const failed = entries.some(([, s]) => s.score < threshold);\n const prefix = failed ? chalk.red('FAIL') : chalk.green('PASS');\n const includeIO = options?.includeIO ?? false;\n const maxStringLength = options?.maxStringLength ?? 4_000;\n\n console.log(` ${prefix} ${chalk.dim(`Case #${c.index}`)}`);\n const inputStr = stringifyUnknown(c.input, {\n space: 2,\n fallback: String(c.input),\n });\n console.log(` ${chalk.dim('Input:')} ${inputStr}`);\n\n if (includeIO) {\n console.log(` ${chalk.dim('Output:')}`);\n console.log(indentBlock(truncateString(c.output, maxStringLength), 6));\n console.log(` ${chalk.dim('Expected:')}`);\n const expectedStrRaw = stringifyUnknown(c.expected, {\n space: 2,\n fallback: String(c.expected),\n });\n console.log(\n indentBlock(truncateString(expectedStrRaw, maxStringLength), 6),\n );\n }\n\n for (const [name, s] of entries) {\n const scoreColor = s.score >= threshold ? chalk.green : chalk.red;\n const reasonStr = s.reason ? ` \u2014 ${s.reason}` : '';\n console.log(\n ` ${chalk.dim(name + ':')} ${scoreColor(s.score.toFixed(3))}${reasonStr}`,\n );\n }\n\n if (c.error) {\n console.log(` ${chalk.dim('Error:')}`);\n const errorStr = formatErrorValue(c.error);\n console.log(` ${chalk.red(errorStr)}`);\n }\n\n console.log('');\n}\n", "export function truncate(str: string, maxLen = 80): string {\n if (str.length <= maxLen) return str;\n return str.slice(0, maxLen) + '...';\n}\n\nexport function formatDuration(ms: number): string {\n if (ms < 1000) return `${ms}ms`;\n return `${(ms / 1000).toFixed(1)}s`;\n}\n\nexport function formatTokens(n: number): string {\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n if (n >= 1_000) return `${(n / 1_000).toFixed(0)}k`;\n return String(n);\n}\n\nexport function generateFilename(\n name: string,\n runId: string,\n ext: string,\n): string {\n const slug = name.replace(/[^a-zA-Z0-9-_]/g, '-').toLowerCase();\n const prefix = runId.slice(0, 8);\n return `${slug}-${prefix}.${ext}`;\n}\n\nexport function stringifyUnknown(\n value: unknown,\n options?: {\n space?: number;\n fallback?: string;\n },\n): string {\n if (typeof value === 'string') return value;\n\n const space = options?.space ?? 0;\n const fallback = options?.fallback ?? 'null';\n try {\n return JSON.stringify(value, null, space) ?? fallback;\n } catch {\n return String(value);\n }\n}\n\nexport function formatInputValue(value: unknown): string {\n return stringifyUnknown(value, { space: 0, fallback: '' });\n}\n\nexport function formatErrorValue(value: unknown): string {\n if (value == null) return '';\n if (typeof value === 'string') return value;\n return stringifyUnknown(value, { space: 2, fallback: '' });\n}\n\nexport function escapeCsv(value: unknown): string {\n const str = stringifyUnknown(value, { space: 0, fallback: 'null' });\n if (str.includes(',') || str.includes('\"') || str.includes('\\n')) {\n return `\"${str.replace(/\"/g, '\"\"')}\"`;\n }\n return str;\n}\n", "import { mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { generateFilename } from './format.ts';\nimport type { CaseResult, Reporter, RunEndData } from './types.ts';\n\nconst DEFAULT_OUTPUT_DIR = '.evals/reports';\n\nexport function resolveOutputDir(outputDir?: string): string {\n return outputDir ?? DEFAULT_OUTPUT_DIR;\n}\n\nexport function getReportPath(\n outputDir: string,\n name: string,\n runId: string,\n ext: string,\n): string {\n return join(outputDir, generateFilename(name, runId, ext));\n}\n\nexport async function writeRunReportFile(\n outputDir: string,\n name: string,\n runId: string,\n ext: string,\n content: string,\n): Promise<void> {\n await mkdir(outputDir, { recursive: true });\n await writeFile(getReportPath(outputDir, name, runId, ext), content, 'utf-8');\n}\n\nexport function getCaseStatus(\n result: CaseResult,\n threshold: number,\n): 'error' | 'pass' | 'fail' {\n if (result.error) return 'error';\n const passed = Object.values(result.scores).every(\n (s) => s.score >= threshold,\n );\n return passed ? 'pass' : 'fail';\n}\n\nexport function createRunEndFileReporter(options: {\n outputDir?: string;\n ext: string;\n render: (data: RunEndData) => string | Promise<string>;\n}): Reporter {\n const outputDir = resolveOutputDir(options.outputDir);\n\n return {\n async onRunEnd(data) {\n const content = await options.render(data);\n await writeRunReportFile(\n outputDir,\n data.name,\n data.runId,\n options.ext,\n content,\n );\n },\n };\n}\n", "import { appendFile, mkdir } from 'node:fs/promises';\n\nimport { stringifyUnknown } from './format.ts';\nimport {\n getReportPath,\n resolveOutputDir,\n writeRunReportFile,\n} from './shared.ts';\nimport type { Reporter } from './types.ts';\n\nexport interface JsonReporterOptions {\n outputDir?: string;\n pretty?: boolean;\n}\n\nexport function jsonReporter(options?: JsonReporterOptions): Reporter {\n const outputDir = resolveOutputDir(options?.outputDir);\n const pretty = options?.pretty ?? true;\n let streamFilename = '';\n\n return {\n async onRunStart(data) {\n await mkdir(outputDir, { recursive: true });\n streamFilename = getReportPath(outputDir, data.name, data.runId, 'jsonl');\n },\n async onCaseEnd(data) {\n const line = stringifyUnknown(data, { space: 0, fallback: 'null' });\n await appendFile(streamFilename, line + '\\n', 'utf-8');\n },\n async onRunEnd(data) {\n const content = stringifyUnknown(data, {\n space: pretty ? 2 : 0,\n fallback: 'null',\n });\n await writeRunReportFile(\n outputDir,\n data.name,\n data.runId,\n 'json',\n content,\n );\n },\n };\n}\n", "import { escapeCsv } from './format.ts';\nimport { createRunEndFileReporter } from './shared.ts';\nimport type { Reporter } from './types.ts';\n\nexport interface CsvReporterOptions {\n outputDir?: string;\n}\n\nexport function csvReporter(options?: CsvReporterOptions): Reporter {\n return createRunEndFileReporter({\n outputDir: options?.outputDir,\n ext: 'csv',\n render(data) {\n const scorerNames = Object.keys(data.summary.meanScores);\n\n const headerParts = [\n 'index',\n 'input',\n 'output',\n 'expected',\n 'error',\n 'latency_ms',\n 'tokens_in',\n 'tokens_out',\n ];\n for (const name of scorerNames) {\n headerParts.push(`${name}_score`, `${name}_reason`);\n }\n\n const rows = [headerParts.join(',')];\n\n for (const c of data.cases) {\n const parts = [\n String(c.index),\n escapeCsv(c.input),\n escapeCsv(c.output),\n escapeCsv(c.expected),\n escapeCsv(c.error ?? ''),\n String(c.latencyMs),\n String(c.tokensIn),\n String(c.tokensOut),\n ];\n for (const name of scorerNames) {\n const s = c.scores[name];\n parts.push(String(s?.score ?? ''), escapeCsv(s?.reason ?? ''));\n }\n rows.push(parts.join(','));\n }\n\n return rows.join('\\n') + '\\n';\n },\n });\n}\n", "import {\n formatDuration,\n formatErrorValue,\n formatInputValue,\n formatTokens,\n} from './format.ts';\nimport { createRunEndFileReporter, getCaseStatus } from './shared.ts';\nimport type { Reporter } from './types.ts';\n\nexport interface MarkdownReporterOptions {\n outputDir?: string;\n}\n\nexport function markdownReporter(options?: MarkdownReporterOptions): Reporter {\n return createRunEndFileReporter({\n outputDir: options?.outputDir,\n ext: 'md',\n render(data) {\n const { summary } = data;\n const scorerNames = Object.keys(summary.meanScores);\n const lines: string[] = [];\n\n lines.push(`# ${data.name}`);\n lines.push('');\n lines.push(`**Model:** ${data.model}`);\n lines.push(\n `**Cases:** ${summary.totalCases} (${summary.passCount} pass, ${summary.failCount} fail)`,\n );\n lines.push(`**Duration:** ${formatDuration(summary.totalLatencyMs)}`);\n lines.push(\n `**Tokens:** ${formatTokens(summary.totalTokensIn + summary.totalTokensOut)}`,\n );\n lines.push('');\n\n lines.push('## Scores');\n lines.push('');\n lines.push('| Scorer | Mean |');\n lines.push('|--------|------|');\n for (const [name, score] of Object.entries(summary.meanScores)) {\n lines.push(`| ${name} | ${score.toFixed(3)} |`);\n }\n lines.push('');\n\n lines.push('## Cases');\n lines.push('');\n\n const caseHeader = [\n '#',\n 'Status',\n 'Input',\n ...scorerNames,\n 'Latency',\n 'Error',\n ];\n lines.push(`| ${caseHeader.join(' | ')} |`);\n lines.push(`| ${caseHeader.map(() => '---').join(' | ')} |`);\n\n for (const c of data.cases) {\n const statusValue = getCaseStatus(c, data.threshold);\n const status =\n statusValue === 'error'\n ? '\uD83D\uDD34 Error'\n : statusValue === 'pass'\n ? '\u2705 Pass'\n : '\u274C Fail';\n const input = formatInputValue(c.input).slice(0, 60);\n const scores = scorerNames.map(\n (name) => c.scores[name]?.score.toFixed(3) ?? '-',\n );\n const error = c.error\n ? formatErrorValue(c.error)\n .replace(/\\r?\\n/g, '<br>')\n .replace(/\\|/g, '\\\\|')\n : '-';\n const row = [\n String(c.index),\n status,\n input,\n ...scores,\n `${c.latencyMs}ms`,\n error,\n ];\n lines.push(`| ${row.join(' | ')} |`);\n }\n lines.push('');\n\n return lines.join('\\n');\n },\n });\n}\n", "import {\n formatDuration,\n formatErrorValue,\n formatInputValue,\n formatTokens,\n} from './format.ts';\nimport { createRunEndFileReporter, getCaseStatus } from './shared.ts';\nimport type { Reporter, RunEndData } from './types.ts';\n\nexport interface HtmlReporterOptions {\n outputDir?: string;\n}\n\nexport function htmlReporter(options?: HtmlReporterOptions): Reporter {\n return createRunEndFileReporter({\n outputDir: options?.outputDir,\n ext: 'html',\n render: renderHtml,\n });\n}\n\nfunction esc(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;');\n}\n\nfunction renderHtml(data: RunEndData): string {\n const { summary } = data;\n const scorerNames = Object.keys(summary.meanScores);\n\n const caseRows = data.cases\n .map((c) => {\n const status = getCaseStatus(c, data.threshold);\n const statusLabel =\n status === 'error' ? 'ERROR' : status === 'pass' ? 'PASS' : 'FAIL';\n const scoresCells = scorerNames\n .map((name) => {\n const s = c.scores[name];\n const score = s?.score ?? 0;\n const cls = score >= data.threshold ? 'pass' : 'fail';\n const reason = s?.reason ? ` title=\"${esc(s.reason)}\"` : '';\n return `<td class=\"${cls}\"${reason}>${score.toFixed(3)}</td>`;\n })\n .join('');\n\n return `<tr class=\"${status}\">\n <td>${c.index}</td>\n <td class=\"${status}\">${statusLabel}</td>\n <td class=\"text\">${esc(formatInputValue(c.input).slice(0, 120))}</td>\n <td class=\"text\">${esc(c.output.slice(0, 120))}</td>\n ${scoresCells}\n <td>${c.latencyMs}ms</td>\n <td class=\"error-text\">${c.error ? esc(formatErrorValue(c.error)) : ''}</td>\n </tr>`;\n })\n .join('\\n');\n\n const scorerHeaders = scorerNames.map((n) => `<th>${esc(n)}</th>`).join('');\n const meanScoreRows = Object.entries(summary.meanScores)\n .map(\n ([name, score]) =>\n `<tr><td>${esc(name)}</td><td>${score.toFixed(3)}</td></tr>`,\n )\n .join('');\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<title>${esc(data.name)} \u2014 Eval Report</title>\n<style>\n * { box-sizing: border-box; margin: 0; padding: 0; }\n body { font-family: system-ui, -apple-system, sans-serif; background: #f8f9fa; color: #1a1a1a; padding: 2rem; }\n h1 { font-size: 1.5rem; margin-bottom: 0.5rem; }\n .meta { color: #666; margin-bottom: 1.5rem; font-size: 0.9rem; }\n .meta span { margin-right: 1.5rem; }\n .summary-table, .cases-table { width: 100%; border-collapse: collapse; margin-bottom: 2rem; }\n .summary-table th, .summary-table td,\n .cases-table th, .cases-table td { padding: 0.5rem 0.75rem; border: 1px solid #ddd; text-align: left; font-size: 0.85rem; }\n .summary-table th, .cases-table th { background: #f1f3f5; font-weight: 600; }\n .cases-table .text { max-width: 300px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .cases-table .error-text { max-width: 480px; white-space: pre-wrap; word-break: break-word; }\n .pass { color: #2b8a3e; }\n .fail { color: #c92a2a; }\n .error { color: #e67700; }\n tr.pass:hover, tr.fail:hover, tr.error:hover { background: #f1f3f5; }\n td.pass { background: #ebfbee; }\n td.fail { background: #fff5f5; }\n h2 { font-size: 1.2rem; margin: 1.5rem 0 0.75rem; }\n</style>\n</head>\n<body>\n <h1>${esc(data.name)}</h1>\n <div class=\"meta\">\n <span><strong>Model:</strong> ${esc(data.model)}</span>\n <span><strong>Cases:</strong> ${summary.totalCases}</span>\n <span><strong>Pass:</strong> ${summary.passCount}</span>\n <span><strong>Fail:</strong> ${summary.failCount}</span>\n <span><strong>Duration:</strong> ${formatDuration(summary.totalLatencyMs)}</span>\n <span><strong>Tokens:</strong> ${formatTokens(summary.totalTokensIn + summary.totalTokensOut)}</span>\n </div>\n\n <h2>Mean Scores</h2>\n <table class=\"summary-table\">\n <thead><tr><th>Scorer</th><th>Mean</th></tr></thead>\n <tbody>${meanScoreRows}</tbody>\n </table>\n\n <h2>Cases</h2>\n <table class=\"cases-table\">\n <thead>\n <tr>\n <th>#</th>\n <th>Status</th>\n <th>Input</th>\n <th>Output</th>\n ${scorerHeaders}\n <th>Latency</th>\n <th>Error</th>\n </tr>\n </thead>\n <tbody>\n ${caseRows}\n </tbody>\n </table>\n</body>\n</html>`;\n}\n"],
5
- "mappings": "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",
6
- "names": ["mkdir", "mkdir"]
4
+ "sourcesContent": ["import chalk from 'chalk';\n\nimport {\n formatDuration,\n formatErrorValue,\n formatTokens,\n stringifyUnknown,\n} from './format.ts';\nimport { getCaseStatus } from './shared.ts';\nimport type { CaseResult, Reporter, RunEndData, Verbosity } from './types.ts';\n\nexport interface ConsoleReporterOptions {\n verbosity?: Verbosity;\n}\n\nconst BAR_WIDTH = 20;\n\nfunction renderProgressBar(\n completed: number,\n total: number,\n elapsedMs: number,\n): string {\n const pct = total > 0 ? completed / total : 0;\n const filled = Math.round(pct * BAR_WIDTH);\n const bar = '\\u2593'.repeat(filled) + '\\u2591'.repeat(BAR_WIDTH - filled);\n const pctStr = `${(pct * 100).toFixed(0)}%`;\n return ` ${bar} ${pctStr} (${completed}/${total}) ${formatDuration(elapsedMs)}`;\n}\n\nfunction statusLabel(status: 'pass' | 'fail' | 'error'): string {\n if (status === 'pass') return chalk.green('PASS');\n if (status === 'error') return chalk.yellow('ERROR');\n return chalk.red('FAIL');\n}\n\nexport function consoleReporter(options?: ConsoleReporterOptions): Reporter {\n const verbosity = options?.verbosity ?? 'normal';\n\n let totalCases = 0;\n let completed = 0;\n let startTime = 0;\n\n return {\n onRunStart(data) {\n totalCases = data.totalCases;\n completed = 0;\n startTime = Date.now();\n\n if (verbosity !== 'quiet') {\n const label = data.name;\n console.log('');\n console.log(\n ` ${chalk.dim('\\u2500\\u2500')} ${chalk.bold(label)} ${chalk.dim('\\u2500'.repeat(Math.max(0, 56 - label.length)))}`,\n );\n console.log(` ${chalk.dim(`Running ${data.totalCases} cases...`)}`);\n console.log('');\n }\n },\n\n onCaseEnd() {\n completed++;\n if (verbosity !== 'quiet') {\n const elapsed = Date.now() - startTime;\n process.stdout.write(\n `\\r${renderProgressBar(completed, totalCases, elapsed)}`,\n );\n }\n },\n\n onRunEnd(data) {\n if (verbosity !== 'quiet') {\n process.stdout.write('\\r' + ' '.repeat(70) + '\\r');\n }\n\n renderSummaryTable(data);\n\n if (verbosity === 'quiet') return;\n\n const sorted = [...data.cases].sort((a, b) => a.index - b.index);\n\n if (verbosity === 'verbose') {\n for (const c of sorted) {\n renderCaseDetail(c, data.threshold, {\n includeIO: true,\n maxStringLength: 20_000,\n });\n }\n } else {\n renderFailuresByScorer(sorted, data.threshold);\n }\n },\n };\n}\n\nfunction indentBlock(text: string, spaces: number): string {\n const pad = ' '.repeat(spaces);\n return text\n .replace(/\\r\\n/g, '\\n')\n .split('\\n')\n .map((line) => pad + line)\n .join('\\n');\n}\n\nfunction truncateString(text: string, maxLength: number): string {\n if (text.length <= maxLength) return text;\n return text.slice(0, maxLength) + '\\u2026';\n}\n\nfunction renderSummaryTable(data: RunEndData): void {\n const { summary } = data;\n const passRate =\n summary.totalCases > 0\n ? ((summary.passCount / summary.totalCases) * 100).toFixed(1)\n : '0.0';\n\n console.log('');\n console.log(chalk.bold(' Summary'));\n console.log(chalk.dim(' ' + '\\u2500'.repeat(60)));\n console.log(` ${chalk.dim('Eval:')} ${data.name}`);\n console.log(` ${chalk.dim('Model:')} ${data.model}`);\n console.log(` ${chalk.dim('Threshold:')} ${data.threshold}`);\n console.log(` ${chalk.dim('Cases:')} ${summary.totalCases}`);\n console.log(\n ` ${chalk.dim('Pass/Fail:')} ${chalk.green(String(summary.passCount))} / ${chalk.red(String(summary.failCount))} ${chalk.dim(`(${passRate}%)`)}`,\n );\n console.log(\n ` ${chalk.dim('Duration:')} ${formatDuration(summary.totalLatencyMs)}`,\n );\n console.log(\n ` ${chalk.dim('Tokens:')} ${chalk.dim('In:')} ${formatTokens(summary.totalTokensIn)} ${chalk.dim('Out:')} ${formatTokens(summary.totalTokensOut)} ${chalk.dim('Total:')} ${formatTokens(summary.totalTokensIn + summary.totalTokensOut)}`,\n );\n\n const scoreEntries = Object.entries(summary.meanScores);\n if (scoreEntries.length > 0) {\n console.log('');\n console.log(chalk.bold(' Scores'));\n for (const [name, score] of scoreEntries) {\n const scoreColor = score >= data.threshold ? chalk.green : chalk.red;\n console.log(\n ` ${chalk.dim(name + ':')}${' '.repeat(Math.max(1, 12 - name.length))}${scoreColor(score.toFixed(3))}`,\n );\n }\n }\n\n console.log(chalk.dim(' ' + '\\u2500'.repeat(60)));\n console.log('');\n}\n\nfunction renderCaseDetail(\n c: CaseResult,\n threshold: number,\n options?: {\n includeIO?: boolean;\n maxStringLength?: number;\n },\n): void {\n const entries = Object.entries(c.scores);\n const status = getCaseStatus(c, threshold);\n const prefix = statusLabel(status);\n const includeIO = options?.includeIO ?? false;\n const maxStringLength = options?.maxStringLength ?? 4_000;\n\n const meta = `${chalk.dim(formatDuration(c.latencyMs))} ${chalk.dim(`${c.tokensIn}/${c.tokensOut} tokens`)}`;\n console.log(` ${prefix} ${chalk.dim(`Case #${c.index}`)} ${meta}`);\n\n const inputStr = stringifyUnknown(c.input, {\n space: 2,\n fallback: String(c.input),\n });\n console.log(` ${chalk.dim('Input:')}`);\n console.log(indentBlock(truncateString(inputStr, maxStringLength), 6));\n\n if (includeIO) {\n console.log(` ${chalk.dim('Output:')}`);\n console.log(indentBlock(truncateString(c.output, maxStringLength), 6));\n console.log(` ${chalk.dim('Expected:')}`);\n const expectedStrRaw = stringifyUnknown(c.expected, {\n space: 2,\n fallback: String(c.expected),\n });\n console.log(\n indentBlock(truncateString(expectedStrRaw, maxStringLength), 6),\n );\n }\n\n for (const [name, s] of entries) {\n const scoreColor = s.score >= threshold ? chalk.green : chalk.red;\n const reasonStr = s.reason ? ` \\u2014 ${s.reason}` : '';\n console.log(\n ` ${chalk.dim(name + ':')} ${scoreColor(s.score.toFixed(3))}${reasonStr}`,\n );\n }\n\n if (c.error) {\n console.log(` ${chalk.dim('Error:')}`);\n const errorStr = formatErrorValue(c.error);\n console.log(` ${chalk.red(errorStr)}`);\n }\n\n console.log('');\n}\n\nfunction renderFailuresByScorer(cases: CaseResult[], threshold: number): void {\n const scorerNames = new Set<string>();\n for (const c of cases) {\n for (const name of Object.keys(c.scores)) {\n scorerNames.add(name);\n }\n }\n\n let hasFailures = false;\n\n for (const scorer of scorerNames) {\n const failing = cases.filter((c) => {\n const s = c.scores[scorer];\n return (\n (s && s.score < threshold) || getCaseStatus(c, threshold) === 'error'\n );\n });\n\n if (failing.length === 0) continue;\n\n if (!hasFailures) {\n console.log(chalk.dim(' Failing by scorer:'));\n console.log('');\n hasFailures = true;\n }\n\n console.log(\n ` ${chalk.bold(scorer)} ${chalk.dim(`(${failing.length} failures)`)}`,\n );\n console.log(chalk.dim(' ' + '\\u2500'.repeat(40)));\n\n for (const c of failing) {\n renderCaseDetail(c, threshold, {\n includeIO: true,\n maxStringLength: 4_000,\n });\n }\n }\n}\n", "export function truncate(str: string, maxLen = 80): string {\n if (str.length <= maxLen) return str;\n return str.slice(0, maxLen) + '...';\n}\n\nexport function formatDuration(ms: number): string {\n if (ms < 1000) return `${ms}ms`;\n return `${(ms / 1000).toFixed(1)}s`;\n}\n\nexport function formatTokens(n: number): string {\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n if (n >= 1_000) return `${(n / 1_000).toFixed(0)}k`;\n return String(n);\n}\n\nexport function generateFilename(\n name: string,\n runId: string,\n ext: string,\n): string {\n const slug = name.replace(/[^a-zA-Z0-9-_]/g, '-').toLowerCase();\n const prefix = runId.slice(0, 8);\n return `${slug}-${prefix}.${ext}`;\n}\n\nexport function stringifyUnknown(\n value: unknown,\n options?: {\n space?: number;\n fallback?: string;\n },\n): string {\n if (typeof value === 'string') return value;\n\n const space = options?.space ?? 0;\n const fallback = options?.fallback ?? 'null';\n try {\n return JSON.stringify(value, null, space) ?? fallback;\n } catch {\n return String(value);\n }\n}\n\nexport function formatInputValue(value: unknown): string {\n return stringifyUnknown(value, { space: 0, fallback: '' });\n}\n\nexport function formatErrorValue(value: unknown): string {\n if (value == null) return '';\n if (typeof value === 'string') return value;\n return stringifyUnknown(value, { space: 2, fallback: '' });\n}\n\nexport function escapeCsv(value: unknown): string {\n const str = stringifyUnknown(value, { space: 0, fallback: 'null' });\n if (str.includes(',') || str.includes('\"') || str.includes('\\n')) {\n return `\"${str.replace(/\"/g, '\"\"')}\"`;\n }\n return str;\n}\n", "import { mkdir, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\n\nimport { generateFilename } from './format.ts';\nimport type { CaseResult, Reporter, RunEndData } from './types.ts';\n\nconst DEFAULT_OUTPUT_DIR = '.evals/reports';\n\nexport function resolveOutputDir(outputDir?: string): string {\n return outputDir ?? DEFAULT_OUTPUT_DIR;\n}\n\nexport function getReportPath(\n outputDir: string,\n name: string,\n runId: string,\n ext: string,\n): string {\n return join(outputDir, generateFilename(name, runId, ext));\n}\n\nexport async function writeRunReportFile(\n outputDir: string,\n name: string,\n runId: string,\n ext: string,\n content: string,\n): Promise<void> {\n await mkdir(outputDir, { recursive: true });\n await writeFile(getReportPath(outputDir, name, runId, ext), content, 'utf-8');\n}\n\nexport function getCaseStatus(\n result: CaseResult,\n threshold: number,\n): 'error' | 'pass' | 'fail' {\n if (result.error) return 'error';\n const passed = Object.values(result.scores).every(\n (s) => s.score >= threshold,\n );\n return passed ? 'pass' : 'fail';\n}\n\nexport function createRunEndFileReporter(options: {\n outputDir?: string;\n ext: string;\n render: (data: RunEndData) => string | Promise<string>;\n}): Reporter {\n const outputDir = resolveOutputDir(options.outputDir);\n\n return {\n async onRunEnd(data) {\n const content = await options.render(data);\n await writeRunReportFile(\n outputDir,\n data.name,\n data.runId,\n options.ext,\n content,\n );\n },\n };\n}\n", "import { appendFile, mkdir } from 'node:fs/promises';\n\nimport { stringifyUnknown } from './format.ts';\nimport {\n getReportPath,\n resolveOutputDir,\n writeRunReportFile,\n} from './shared.ts';\nimport type { Reporter } from './types.ts';\n\nexport interface JsonReporterOptions {\n outputDir?: string;\n pretty?: boolean;\n}\n\nexport function jsonReporter(options?: JsonReporterOptions): Reporter {\n const outputDir = resolveOutputDir(options?.outputDir);\n const pretty = options?.pretty ?? true;\n let streamFilename = '';\n\n return {\n async onRunStart(data) {\n await mkdir(outputDir, { recursive: true });\n streamFilename = getReportPath(outputDir, data.name, data.runId, 'jsonl');\n },\n async onCaseEnd(data) {\n const line = stringifyUnknown(data, { space: 0, fallback: 'null' });\n await appendFile(streamFilename, line + '\\n', 'utf-8');\n },\n async onRunEnd(data) {\n const content = stringifyUnknown(data, {\n space: pretty ? 2 : 0,\n fallback: 'null',\n });\n await writeRunReportFile(\n outputDir,\n data.name,\n data.runId,\n 'json',\n content,\n );\n },\n };\n}\n", "import { escapeCsv } from './format.ts';\nimport { createRunEndFileReporter, getCaseStatus } from './shared.ts';\nimport type { Reporter } from './types.ts';\n\nexport interface CsvReporterOptions {\n outputDir?: string;\n}\n\nexport function csvReporter(options?: CsvReporterOptions): Reporter {\n return createRunEndFileReporter({\n outputDir: options?.outputDir,\n ext: 'csv',\n render(data) {\n const scorerNames = Object.keys(data.summary.meanScores);\n\n const headerParts = [\n 'index',\n 'status',\n 'input',\n 'output',\n 'expected',\n 'error',\n 'latency_ms',\n 'tokens_in',\n 'tokens_out',\n ];\n for (const name of scorerNames) {\n headerParts.push(`${name}_score`, `${name}_reason`);\n }\n\n const rows = [headerParts.join(',')];\n\n for (const c of data.cases) {\n const status = getCaseStatus(c, data.threshold);\n const parts = [\n String(c.index),\n status,\n escapeCsv(c.input),\n escapeCsv(c.output),\n escapeCsv(c.expected),\n escapeCsv(c.error ?? ''),\n String(c.latencyMs),\n String(c.tokensIn),\n String(c.tokensOut),\n ];\n for (const name of scorerNames) {\n const s = c.scores[name];\n parts.push(String(s?.score ?? ''), escapeCsv(s?.reason ?? ''));\n }\n rows.push(parts.join(','));\n }\n\n return rows.join('\\n') + '\\n';\n },\n });\n}\n", "import {\n formatDuration,\n formatErrorValue,\n formatInputValue,\n formatTokens,\n} from './format.ts';\nimport { createRunEndFileReporter, getCaseStatus } from './shared.ts';\nimport type { Reporter } from './types.ts';\n\nexport interface MarkdownReporterOptions {\n outputDir?: string;\n}\n\nexport function markdownReporter(options?: MarkdownReporterOptions): Reporter {\n return createRunEndFileReporter({\n outputDir: options?.outputDir,\n ext: 'md',\n render(data) {\n const { summary } = data;\n const scorerNames = Object.keys(summary.meanScores);\n const lines: string[] = [];\n const passRate =\n summary.totalCases > 0\n ? ((summary.passCount / summary.totalCases) * 100).toFixed(1)\n : '0.0';\n\n lines.push(`# ${data.name}`);\n lines.push('');\n lines.push(`**Model:** ${data.model}`);\n lines.push(`**Threshold:** ${data.threshold}`);\n lines.push(\n `**Cases:** ${summary.totalCases} (${summary.passCount} pass, ${summary.failCount} fail, ${passRate}%)`,\n );\n lines.push(`**Duration:** ${formatDuration(summary.totalLatencyMs)}`);\n lines.push(\n `**Tokens:** In: ${formatTokens(summary.totalTokensIn)} | Out: ${formatTokens(summary.totalTokensOut)} | Total: ${formatTokens(summary.totalTokensIn + summary.totalTokensOut)}`,\n );\n lines.push('');\n\n lines.push('## Scores');\n lines.push('');\n lines.push('| Scorer | Mean |');\n lines.push('|--------|------|');\n for (const [name, score] of Object.entries(summary.meanScores)) {\n lines.push(`| ${name} | ${score.toFixed(3)} |`);\n }\n lines.push('');\n\n lines.push('## Cases');\n lines.push('');\n\n const caseHeader = [\n '#',\n 'Status',\n 'Input',\n ...scorerNames,\n 'Latency',\n 'Tokens',\n 'Error',\n ];\n lines.push(`| ${caseHeader.join(' | ')} |`);\n lines.push(`| ${caseHeader.map(() => '---').join(' | ')} |`);\n\n for (const c of data.cases) {\n const statusValue = getCaseStatus(c, data.threshold);\n const status =\n statusValue === 'error'\n ? '\uD83D\uDD34 Error'\n : statusValue === 'pass'\n ? '\u2705 Pass'\n : '\u274C Fail';\n const input = formatInputValue(c.input).slice(0, 60);\n const scores = scorerNames.map(\n (name) => c.scores[name]?.score.toFixed(3) ?? '-',\n );\n const error = c.error\n ? formatErrorValue(c.error)\n .replace(/\\r?\\n/g, '<br>')\n .replace(/\\|/g, '\\\\|')\n : '-';\n const row = [\n String(c.index),\n status,\n input,\n ...scores,\n formatDuration(c.latencyMs),\n `${c.tokensIn}/${c.tokensOut}`,\n error,\n ];\n lines.push(`| ${row.join(' | ')} |`);\n }\n lines.push('');\n\n return lines.join('\\n');\n },\n });\n}\n", "import {\n formatDuration,\n formatErrorValue,\n formatInputValue,\n formatTokens,\n stringifyUnknown,\n} from './format.ts';\nimport { createRunEndFileReporter, getCaseStatus } from './shared.ts';\nimport type { Reporter, RunEndData } from './types.ts';\n\nexport interface HtmlReporterOptions {\n outputDir?: string;\n}\n\nexport function htmlReporter(options?: HtmlReporterOptions): Reporter {\n return createRunEndFileReporter({\n outputDir: options?.outputDir,\n ext: 'html',\n render: renderHtml,\n });\n}\n\nfunction esc(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;');\n}\n\nfunction renderHtml(data: RunEndData): string {\n const { summary } = data;\n const scorerNames = Object.keys(summary.meanScores);\n const passRate =\n summary.totalCases > 0\n ? ((summary.passCount / summary.totalCases) * 100).toFixed(1)\n : '0.0';\n\n const caseRows = data.cases\n .map((c) => {\n const status = getCaseStatus(c, data.threshold);\n const statusLabel =\n status === 'error' ? 'ERROR' : status === 'pass' ? 'PASS' : 'FAIL';\n const scoresCells = scorerNames\n .map((name) => {\n const s = c.scores[name];\n const score = s?.score ?? 0;\n const cls = score >= data.threshold ? 'pass' : 'fail';\n const reason = s?.reason ? ` title=\"${esc(s.reason)}\"` : '';\n return `<td class=\"${cls}\"${reason}>${score.toFixed(3)}</td>`;\n })\n .join('');\n\n const expectedStr = stringifyUnknown(c.expected, {\n space: 0,\n fallback: '',\n });\n\n return `<tr class=\"${status}\">\n <td>${c.index}</td>\n <td class=\"${status}\">${statusLabel}</td>\n <td class=\"text\">${esc(formatInputValue(c.input).slice(0, 120))}</td>\n <td class=\"text\">${esc(c.output.slice(0, 120))}</td>\n <td class=\"text\">${esc(expectedStr.slice(0, 120))}</td>\n ${scoresCells}\n <td>${formatDuration(c.latencyMs)}</td>\n <td>${c.tokensIn}/${c.tokensOut}</td>\n <td class=\"error-text\">${c.error ? esc(formatErrorValue(c.error)) : ''}</td>\n </tr>`;\n })\n .join('\\n');\n\n const scorerHeaders = scorerNames.map((n) => `<th>${esc(n)}</th>`).join('');\n const meanScoreRows = Object.entries(summary.meanScores)\n .map(\n ([name, score]) =>\n `<tr><td>${esc(name)}</td><td>${score.toFixed(3)}</td></tr>`,\n )\n .join('');\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<title>${esc(data.name)} \u2014 Eval Report</title>\n<style>\n * { box-sizing: border-box; margin: 0; padding: 0; }\n body { font-family: system-ui, -apple-system, sans-serif; background: #f8f9fa; color: #1a1a1a; padding: 2rem; }\n h1 { font-size: 1.5rem; margin-bottom: 0.5rem; }\n .meta { color: #666; margin-bottom: 1.5rem; font-size: 0.9rem; }\n .meta span { margin-right: 1.5rem; }\n .summary-table, .cases-table { width: 100%; border-collapse: collapse; margin-bottom: 2rem; }\n .summary-table th, .summary-table td,\n .cases-table th, .cases-table td { padding: 0.5rem 0.75rem; border: 1px solid #ddd; text-align: left; font-size: 0.85rem; }\n .summary-table th, .cases-table th { background: #f1f3f5; font-weight: 600; }\n .cases-table .text { max-width: 300px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .cases-table .error-text { max-width: 480px; white-space: pre-wrap; word-break: break-word; }\n .pass { color: #2b8a3e; }\n .fail { color: #c92a2a; }\n .error { color: #e67700; }\n tr.pass:hover, tr.fail:hover, tr.error:hover { background: #f1f3f5; }\n td.pass { background: #ebfbee; }\n td.fail { background: #fff5f5; }\n h2 { font-size: 1.2rem; margin: 1.5rem 0 0.75rem; }\n</style>\n</head>\n<body>\n <h1>${esc(data.name)}</h1>\n <div class=\"meta\">\n <span><strong>Model:</strong> ${esc(data.model)}</span>\n <span><strong>Threshold:</strong> ${data.threshold}</span>\n <span><strong>Cases:</strong> ${summary.totalCases}</span>\n <span><strong>Pass:</strong> ${summary.passCount}</span>\n <span><strong>Fail:</strong> ${summary.failCount} (${passRate}%)</span>\n <span><strong>Duration:</strong> ${formatDuration(summary.totalLatencyMs)}</span>\n <span><strong>Tokens In:</strong> ${formatTokens(summary.totalTokensIn)}</span>\n <span><strong>Tokens Out:</strong> ${formatTokens(summary.totalTokensOut)}</span>\n <span><strong>Total Tokens:</strong> ${formatTokens(summary.totalTokensIn + summary.totalTokensOut)}</span>\n </div>\n\n <h2>Mean Scores</h2>\n <table class=\"summary-table\">\n <thead><tr><th>Scorer</th><th>Mean</th></tr></thead>\n <tbody>${meanScoreRows}</tbody>\n </table>\n\n <h2>Cases</h2>\n <table class=\"cases-table\">\n <thead>\n <tr>\n <th>#</th>\n <th>Status</th>\n <th>Input</th>\n <th>Output</th>\n <th>Expected</th>\n ${scorerHeaders}\n <th>Latency</th>\n <th>Tokens</th>\n <th>Error</th>\n </tr>\n </thead>\n <tbody>\n ${caseRows}\n </tbody>\n </table>\n</body>\n</html>`;\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["mkdir", "mkdir", "statusLabel"]
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/reporters/markdown.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,WAAW,uBAAuB;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,gBAAgB,CAAC,OAAO,CAAC,EAAE,uBAAuB,GAAG,QAAQ,CA4E5E"}
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/reporters/markdown.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,WAAW,uBAAuB;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,gBAAgB,CAAC,OAAO,CAAC,EAAE,uBAAuB,GAAG,QAAQ,CAmF5E"}
@@ -94,6 +94,8 @@ export declare class RunStore {
94
94
  getCases(runId: string): CaseRow[];
95
95
  getFailingCases(runId: string, threshold?: number): CaseWithScores[];
96
96
  getRunSummary(runId: string, threshold?: number): RunSummary;
97
+ findSuiteByName(name: string): SuiteRow | undefined;
98
+ getLatestCompletedRun(suiteId: string, model?: string): RunRow | undefined;
97
99
  listSuites(): SuiteRow[];
98
100
  createPrompt(name: string, content: string): PromptRow;
99
101
  listPrompts(): PromptRow[];
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/store/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/store/index.ts"],"names":[],"mappings":"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"}
@@ -306,6 +306,28 @@ var RunStore = class {
306
306
  totalTokensOut: totals.totalTokensOut
307
307
  };
308
308
  }
309
+ findSuiteByName(name) {
310
+ const row = this.#stmt(
311
+ "SELECT * FROM suites WHERE name = ? ORDER BY created_at DESC LIMIT 1"
312
+ ).get(name);
313
+ return row ?? void 0;
314
+ }
315
+ getLatestCompletedRun(suiteId, model) {
316
+ const sql = model ? "SELECT * FROM runs WHERE suite_id = ? AND status = ? AND model = ? ORDER BY started_at DESC LIMIT 1" : "SELECT * FROM runs WHERE suite_id = ? AND status = ? ORDER BY started_at DESC LIMIT 1";
317
+ const row = model ? this.#stmt(sql).get(suiteId, "completed", model) : this.#stmt(sql).get(suiteId, "completed");
318
+ if (!row) return void 0;
319
+ return {
320
+ id: row.id,
321
+ suite_id: row.suite_id,
322
+ name: row.name,
323
+ model: row.model,
324
+ config: row.config ? JSON.parse(row.config) : null,
325
+ started_at: row.started_at,
326
+ finished_at: row.finished_at,
327
+ status: row.status,
328
+ summary: row.summary ? JSON.parse(row.summary) : null
329
+ };
330
+ }
309
331
  listSuites() {
310
332
  const rows = this.#stmt(
311
333
  "SELECT * FROM suites ORDER BY created_at DESC"