@fede0089/skill-eval 1.2.2 → 1.3.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/dist/reporters/html-reporter.js +99 -59
- package/package.json +1 -1
|
@@ -87,38 +87,62 @@ function renderMetricsGrid(report) {
|
|
|
87
87
|
</div>`;
|
|
88
88
|
}
|
|
89
89
|
// ---------------------------------------------------------------------------
|
|
90
|
-
//
|
|
90
|
+
// Expectations × Variants table (per-task drill-down)
|
|
91
91
|
// ---------------------------------------------------------------------------
|
|
92
|
-
function
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
92
|
+
function renderExpectationCell(trials, expIdx, variant, taskId, clickable, totalCols) {
|
|
93
|
+
const passed = trials.filter(t => t.assertionResults[expIdx]?.passed).length;
|
|
94
|
+
const total = trials.length;
|
|
95
|
+
const rate = total > 0 ? passed / total : 0;
|
|
96
|
+
const colorCls = passColorClass(rate);
|
|
97
|
+
const ratePct = formatPercent(rate);
|
|
98
|
+
const frac = `${passed} / ${total}`;
|
|
99
|
+
const detailId = `exp-detail-${taskId}-${expIdx}-${variant}`;
|
|
100
|
+
const dataAttr = clickable ? ` data-detail="${escapeHtml(detailId)}"` : '';
|
|
101
|
+
const cell = `<td class="pass-cell ${colorCls}"${dataAttr}><span class="rate">${ratePct}</span><span class="frac">${frac}</span></td>`;
|
|
102
|
+
if (!clickable)
|
|
103
|
+
return { cell, detail: '' };
|
|
104
|
+
const lines = trials.map(t => {
|
|
105
|
+
const r = t.assertionResults[expIdx];
|
|
106
|
+
const ok = !!r?.passed;
|
|
107
|
+
const reason = r?.reason ?? '';
|
|
108
|
+
const icon = ok ? '✓' : '✗';
|
|
109
|
+
const iconCls = ok ? 'pass' : 'fail';
|
|
110
|
+
return `<div class="exp-trial-line"><div class="exp-trial-icon ${iconCls}">${icon}</div><div class="exp-trial-body"><span class="trial-label">Trial ${t.id}</span><span class="trial-reason">${escapeHtml(reason)}</span></div></div>`;
|
|
105
111
|
}).join('');
|
|
112
|
+
const detail = `<tr class="exp-detail-row" id="${escapeHtml(detailId)}"><td colspan="${totalCols}"><div class="exp-detail-inner"><div class="exp-detail-header">Judge per trial · <span class="variant-pill">${escapeHtml(variant)}</span></div>${lines}</div></td></tr>`;
|
|
113
|
+
return { cell, detail };
|
|
106
114
|
}
|
|
107
|
-
function
|
|
108
|
-
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
115
|
+
function renderExpectationsTable(result, allVersions, isFunctionalEval) {
|
|
116
|
+
let canonical = [];
|
|
117
|
+
for (const v of allVersions) {
|
|
118
|
+
const trials = v === 'baseline' ? result.baselineTrials : result.skillTrials[v];
|
|
119
|
+
if (trials && trials.length > 0 && trials[0].assertionResults.length > 0) {
|
|
120
|
+
canonical = trials[0].assertionResults;
|
|
121
|
+
break;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (canonical.length === 0) {
|
|
125
|
+
return '<p class="muted">No assertions recorded.</p>';
|
|
126
|
+
}
|
|
127
|
+
const totalCols = 1 + allVersions.length;
|
|
128
|
+
const headerCells = allVersions.map(v => `<th class="variant-col">${escapeHtml(v)}</th>`).join('');
|
|
129
|
+
const rows = canonical.map((a, expIdx) => {
|
|
130
|
+
const cells = [];
|
|
131
|
+
const details = [];
|
|
132
|
+
for (const v of allVersions) {
|
|
133
|
+
const trials = v === 'baseline' ? result.baselineTrials : result.skillTrials[v];
|
|
134
|
+
const { cell, detail } = renderExpectationCell(trials, expIdx, v, result.taskId, isFunctionalEval, totalCols);
|
|
135
|
+
cells.push(cell);
|
|
136
|
+
if (detail)
|
|
137
|
+
details.push(detail);
|
|
138
|
+
}
|
|
139
|
+
return `<tr class="exp-row"><td class="exp-text">${escapeHtml(a.assertion)}</td>${cells.join('')}</tr>${details.join('')}`;
|
|
140
|
+
}).join('');
|
|
141
|
+
return `<div class="expectations-table-wrap">
|
|
142
|
+
<table class="expectations-table">
|
|
143
|
+
<thead><tr><th class="exp-col">Expectation</th>${headerCells}</tr></thead>
|
|
144
|
+
<tbody>${rows}</tbody>
|
|
145
|
+
</table>
|
|
122
146
|
</div>`;
|
|
123
147
|
}
|
|
124
148
|
function avgTrialTokens(trials) {
|
|
@@ -175,16 +199,11 @@ function renderTaskMiniGrid(result, isFunctionalEval) {
|
|
|
175
199
|
</div>`;
|
|
176
200
|
}
|
|
177
201
|
function renderTaskDetails(result, isFunctionalEval) {
|
|
202
|
+
const skillVersions = Object.keys(result.skillTrials);
|
|
203
|
+
const allVersions = isFunctionalEval ? ['baseline', ...skillVersions] : skillVersions;
|
|
178
204
|
const sections = [];
|
|
179
205
|
sections.push(renderTaskMiniGrid(result, isFunctionalEval));
|
|
180
|
-
|
|
181
|
-
sections.push('<div class="trial-group-label">Baseline</div>');
|
|
182
|
-
sections.push(...result.baselineTrials.map(t => renderTrial(t)));
|
|
183
|
-
}
|
|
184
|
-
for (const version of Object.keys(result.skillTrials)) {
|
|
185
|
-
sections.push(`<div class="trial-group-label">${version}</div>`);
|
|
186
|
-
sections.push(...result.skillTrials[version].map(t => renderTrial(t)));
|
|
187
|
-
}
|
|
206
|
+
sections.push(renderExpectationsTable(result, allVersions, isFunctionalEval));
|
|
188
207
|
return `<div class="task-details" id="details-${result.taskId}">${sections.join('')}</div>`;
|
|
189
208
|
}
|
|
190
209
|
// ---------------------------------------------------------------------------
|
|
@@ -281,31 +300,42 @@ tr:last-child td { border-bottom: none; }
|
|
|
281
300
|
.details-row > td { padding: 0; background: #f8fafc; }
|
|
282
301
|
.task-details { display: none; padding: 12px 16px; }
|
|
283
302
|
.task-details.visible { display: block; }
|
|
284
|
-
.trial-group-label { font-size: 11px; font-weight: 600; text-transform: uppercase; color: #94a3b8; letter-spacing: 0.05em; margin: 8px 0 4px; }
|
|
285
303
|
|
|
286
|
-
/*
|
|
287
|
-
.
|
|
288
|
-
.
|
|
289
|
-
.
|
|
290
|
-
.
|
|
291
|
-
.
|
|
292
|
-
.
|
|
293
|
-
.
|
|
304
|
+
/* Expectations × Variants table */
|
|
305
|
+
.expectations-table-wrap { border: 1px solid #e2e8f0; border-radius: 6px; overflow: hidden; background: #fff; }
|
|
306
|
+
.expectations-table { width: 100%; border-collapse: collapse; table-layout: fixed; }
|
|
307
|
+
.expectations-table thead th { background: #f1f5f9; font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: #475569; padding: 10px 14px; text-align: left; border-bottom: 1px solid #e2e8f0; }
|
|
308
|
+
.expectations-table thead th.exp-col { width: auto; }
|
|
309
|
+
.expectations-table thead th.variant-col { width: 110px; text-align: center; }
|
|
310
|
+
.expectations-table tbody td { padding: 10px 14px; border-bottom: 1px solid #f1f5f9; vertical-align: middle; font-size: 13px; }
|
|
311
|
+
.expectations-table tbody tr.exp-row:last-of-type > td { border-bottom: none; }
|
|
312
|
+
.exp-text { color: #1e293b; line-height: 1.4; word-break: break-word; }
|
|
294
313
|
|
|
295
|
-
|
|
296
|
-
.
|
|
297
|
-
.
|
|
298
|
-
.
|
|
299
|
-
.
|
|
314
|
+
.pass-cell { text-align: center; border-left: 1px solid #f1f5f9; }
|
|
315
|
+
.pass-cell[data-detail] { cursor: pointer; user-select: none; transition: background 0.12s; }
|
|
316
|
+
.pass-cell[data-detail]:hover { background: #f1f5f9; }
|
|
317
|
+
.pass-cell.open { background: #e0f2fe; }
|
|
318
|
+
.pass-cell .rate { display: block; font-size: 13px; font-weight: 700; line-height: 1.1; }
|
|
319
|
+
.pass-cell .frac { display: block; font-size: 10px; font-weight: 600; color: #94a3b8; margin-top: 2px; letter-spacing: 0.03em; }
|
|
320
|
+
.pass-cell.green .rate { color: #16a34a; }
|
|
321
|
+
.pass-cell.amber .rate { color: #d97706; }
|
|
322
|
+
.pass-cell.red .rate { color: #dc2626; }
|
|
323
|
+
|
|
324
|
+
.exp-detail-row { display: none; }
|
|
325
|
+
.exp-detail-row.visible { display: table-row; }
|
|
326
|
+
.exp-detail-row > td { padding: 0; background: #f8fafc; border-bottom: 1px solid #f1f5f9; }
|
|
327
|
+
.exp-detail-inner { padding: 12px 14px 14px; border-left: 3px solid #3b82f6; }
|
|
328
|
+
.exp-detail-header { font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em; color: #64748b; margin-bottom: 8px; }
|
|
329
|
+
.exp-detail-header .variant-pill { display: inline-block; background: #e0f2fe; color: #0369a1; padding: 1px 7px; border-radius: 4px; margin-left: 4px; font-weight: 700; }
|
|
330
|
+
.exp-trial-line { display: flex; gap: 8px; padding: 6px 0; border-top: 1px dashed #e2e8f0; }
|
|
331
|
+
.exp-trial-line:first-of-type { border-top: none; }
|
|
332
|
+
.exp-trial-icon { flex-shrink: 0; font-size: 13px; font-weight: 700; line-height: 1.4; width: 16px; }
|
|
333
|
+
.exp-trial-icon.pass { color: #16a34a; }
|
|
334
|
+
.exp-trial-icon.fail { color: #dc2626; }
|
|
335
|
+
.exp-trial-body { flex: 1; min-width: 0; font-size: 12px; color: #334155; line-height: 1.45; }
|
|
336
|
+
.exp-trial-body .trial-label { font-weight: 700; color: #475569; margin-right: 4px; }
|
|
337
|
+
.exp-trial-body .trial-reason { color: #64748b; }
|
|
300
338
|
|
|
301
|
-
/* Assertions */
|
|
302
|
-
.assertion { display: flex; gap: 8px; }
|
|
303
|
-
.assert-icon { flex-shrink: 0; font-size: 14px; margin-top: 1px; }
|
|
304
|
-
.assert-pass .assert-icon { color: #16a34a; }
|
|
305
|
-
.assert-fail .assert-icon { color: #dc2626; }
|
|
306
|
-
.assert-body { flex: 1; min-width: 0; }
|
|
307
|
-
.assert-text { font-size: 13px; color: #1e293b; word-break: break-word; }
|
|
308
|
-
.assert-reason { font-size: 12px; color: #64748b; margin-top: 2px; word-break: break-word; }
|
|
309
339
|
.muted { color: #94a3b8; font-size: 13px; }
|
|
310
340
|
</style>
|
|
311
341
|
</head>
|
|
@@ -345,6 +375,16 @@ tr:last-child td { border-bottom: none; }
|
|
|
345
375
|
btn.textContent = isOpen ? '▶' : '▼';
|
|
346
376
|
});
|
|
347
377
|
});
|
|
378
|
+
|
|
379
|
+
document.querySelectorAll('.pass-cell[data-detail]').forEach(function (cell) {
|
|
380
|
+
cell.addEventListener('click', function () {
|
|
381
|
+
const detailRow = document.getElementById(cell.getAttribute('data-detail'));
|
|
382
|
+
if (!detailRow) return;
|
|
383
|
+
const isOpen = detailRow.classList.contains('visible');
|
|
384
|
+
detailRow.classList.toggle('visible', !isOpen);
|
|
385
|
+
cell.classList.toggle('open', !isOpen);
|
|
386
|
+
});
|
|
387
|
+
});
|
|
348
388
|
}());
|
|
349
389
|
</script>
|
|
350
390
|
</body>
|