Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,32 @@ agentv eval --dry-run evals/my-eval.yaml

See `agentv eval --help` for all options: workers, timeouts, output formats, trace dumping, and more.

#### Output Formats

Write results to different formats using the `-o` flag (format auto-detected from extension):

```bash
# JSONL (default streaming format)
agentv eval evals/my-eval.yaml -o results.jsonl

# Self-contained HTML dashboard (opens in any browser, no server needed)
agentv eval evals/my-eval.yaml -o report.html

# Multiple formats simultaneously
agentv eval evals/my-eval.yaml -o results.jsonl -o report.html

# JUnit XML for CI/CD integration
agentv eval evals/my-eval.yaml -o results.xml
```

The HTML report auto-refreshes every 2 seconds during a live run, then locks once the run completes.

You can also convert an existing JSONL results file to HTML after the fact:

```bash
agentv convert results.jsonl -o report.html
```

#### Timeouts

AgentV does not apply a default top-level evaluation timeout. If you want one, set it explicitly
Expand Down
33 changes: 31 additions & 2 deletions apps/cli/src/commands/convert/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,23 @@ import { isAgentSkillsFormat, normalizeLineEndings, parseAgentSkillsEvals } from
import { command, option, optional, positional, string } from 'cmd-ts';
import { stringify as stringifyYaml } from 'yaml';

import { HtmlWriter } from '../eval/html-writer.js';

async function convertJsonlToHtml(inputPath: string, outputPath: string): Promise<number> {
const content = readFileSync(inputPath, 'utf8');
const lines = content
.trim()
.split('\n')
.filter((line) => line.trim());

const writer = await HtmlWriter.open(outputPath);
for (const line of lines) {
await writer.append(JSON.parse(line));
}
await writer.close();
return lines.length;
}

function convertJsonlToYaml(inputPath: string, outputPath: string): number {
const content = readFileSync(inputPath, 'utf8');
const lines = content
Expand Down Expand Up @@ -147,7 +164,7 @@ export function convertEvalsJsonToYaml(inputPath: string): string {

export const convertCommand = command({
name: 'convert',
description: 'Convert between evaluation formats (JSONL→YAML, evals.json→EVAL.yaml)',
description: 'Convert between evaluation formats (JSONL→YAML, JSONL→HTML, evals.json→EVAL.yaml)',
args: {
input: positional({
type: string,
Expand All @@ -158,7 +175,7 @@ export const convertCommand = command({
type: optional(string),
long: 'out',
short: 'o',
description: 'Output file path (defaults to stdout for evals.json, or .yaml for JSONL)',
description: 'Output file path (defaults to stdout for evals.json, .yaml or .html for JSONL)',
}),
},
handler: async ({ input, out }) => {
Expand All @@ -181,6 +198,18 @@ export const convertCommand = command({
}

if (ext === '.jsonl') {
const outExt = out ? path.extname(out).toLowerCase() : '.yaml';
if (outExt === '.html' || outExt === '.htm') {
const outputPath = out ?? input.replace(/\.jsonl$/, '.html');
try {
const count = await convertJsonlToHtml(input, outputPath);
console.log(`Converted ${count} records to ${path.resolve(outputPath)}`);
} catch (error) {
console.error(`Error: ${(error as Error).message}`);
process.exit(1);
}
return;
}
const outputPath = out ?? input.replace(/\.jsonl$/, '.yaml');
try {
const count = convertJsonlToYaml(input, outputPath);
Expand Down
4 changes: 2 additions & 2 deletions apps/cli/src/commands/eval/commands/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@ export const evalRunCommand = command({
long: 'output',
short: 'o',
description:
'Output file path(s). Format inferred from extension: .jsonl, .json, .xml, .yaml',
'Output file path(s). Format inferred from extension: .jsonl, .json, .xml, .yaml, .html',
}),
outputFormat: option({
type: optional(string),
long: 'output-format',
description: "Output format: 'jsonl' or 'yaml' (default: jsonl)",
description: "Output format: 'jsonl', 'yaml', or 'html' (default: jsonl)",
}),
dryRun: flag({
long: 'dry-run',
Expand Down
Loading