(results: TaskRunResult[], summary: EvalSummary, meta: { model?: string; when?: string } = {})
| 142 | |
| 143 | /** Render a Markdown report. Pure — the runner writes it to disk. */ |
| 144 | export function formatReport(results: TaskRunResult[], summary: EvalSummary, meta: { model?: string; when?: string } = {}): string { |
| 145 | const lines: string[] = []; |
| 146 | lines.push('# QodeX Eval Report'); |
| 147 | if (meta.when) lines.push(`Run: ${meta.when}`); |
| 148 | if (meta.model) lines.push(`Model: ${meta.model}`); |
| 149 | lines.push(''); |
| 150 | lines.push(`**${summary.passed}/${summary.total} passed (${(summary.passRate * 100).toFixed(0)}%)**`); |
| 151 | lines.push(''); |
| 152 | lines.push(`- avg iterations: ${summary.avgIterations.toFixed(1)}`); |
| 153 | lines.push(`- avg tool calls: ${summary.avgToolCalls.toFixed(1)}`); |
| 154 | lines.push(`- avg wall time: ${(summary.avgWallMs / 1000).toFixed(1)}s`); |
| 155 | lines.push(`- total cost: $${summary.totalCostUsd.toFixed(4)}`); |
| 156 | lines.push(''); |
| 157 | lines.push('| Task | Result | Iters | Tools | Time | Notes |'); |
| 158 | lines.push('|------|--------|-------|-------|------|-------|'); |
| 159 | for (const r of results) { |
| 160 | const mark = r.passed ? '✅ pass' : '❌ fail'; |
| 161 | const notes = r.passed ? '' : r.reasons.slice(0, 2).join('; ').replace(/\|/g, '\\|'); |
| 162 | lines.push(`| ${r.id} | ${mark} | ${r.iterations} | ${r.toolCalls} | ${(r.wallMs / 1000).toFixed(1)}s | ${notes} |`); |
| 163 | } |
| 164 | lines.push(''); |
| 165 | return lines.join('\n'); |
| 166 | } |
no test coverage detected