Skip to content
Open
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
42 changes: 30 additions & 12 deletions website/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@

## Routes

| URL | Description |
| :---------------------------- | :---------------------------------------------- |
| `/` | View the latest design system benchmark results |
| `/benchmarks` | List benchmarks |
| `/benchmarks/:id` | View benchmark results and dated runs |
| `/benchmarks/:id/runs/:date` | View benchmark run details and walkthroughs |
| `/experiments` | List experiments |
| `/experiments/:id` | View experiment details |
| `/experiments/:id/runs/:date` | View experiment run details and walkthroughs |
| `/scenarios` | List scenarios |
| `/scenarios/:id` | View scenario details |
| URL | Description |
| :---------------------------- | :--------------------------------------------------- |
| `/` | View the latest benchmark and experiment results |
| `/benchmarks` | List benchmarks |
| `/benchmarks/:id` | View benchmark results and dated runs |
| `/benchmarks/:id/runs/:date` | View benchmark run details and walkthroughs |
| `/experiments` | List experiments |
| `/experiments/:id` | Compare latest treatments, scenarios, and dated runs |
| `/experiments/:id/runs/:date` | View experiment run details and walkthroughs |
| `/scenarios` | List scenarios |
| `/scenarios/:id` | View scenario details |

## Results

Expand All @@ -31,8 +31,26 @@ results/
Artifact and walkthrough paths are relative to each `output.json`, so result
directories should be moved or uploaded as complete bundles.

The overview includes each configured experiment and its latest dated run.
It reads only the newest available result bundle for each experiment; dated
run history is loaded on the experiment page.
Experiment pages compare treatments separately for each model and reasoning
effort, both across the run and within each scenario. Test pass rates use the
sum of passed tests divided by the sum of total tests. Output tokens, premium
requests, session time, and API time are averages per recorded trial. Trial and
scenario counts are shown so differences in coverage are visible; these are
descriptive results, not paired comparisons or significance estimates.

Select **View output** for a scenario to open its walkthrough, test results,
and transcript. The run viewer supports switching model, treatment, and trial
when multiple trials were recorded. Runs without trials and experiments without
runs show empty states rather than falling back to older results.
Changing the model or treatment selects the first trial for that combination.
Scenario output links also support IDs containing spaces, slashes, and percent
escapes.

Benchmark and experiment run details include a **Judges** tab for the selected
model and treatment. Each judge shows its score, scoring criteria, rationale,
model, treatment, and trial. Each judge shows its score, scoring criteria, rationale,
and file-backed findings with code snippets. Scores use the judge's configured
scale, not a shared pass/fail threshold. Judge errors and missing results are
shown separately from scored results.
198 changes: 198 additions & 0 deletions website/src/app/components/ExperimentResults.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
'use client'

import {Blankslate, DataTable, Table} from '@primer/react/experimental'
import type {Route} from 'next'
import {useId} from 'react'
import type {ExperimentResults, TreatmentResult} from '../../experiment-results'
import {Link} from '../../components/Link'
import {getScenarioAnchor} from '../../scenario-anchor'

type ExperimentSummary = {
id: string
name: string
description: string
date: string | null
treatments: Array<TreatmentResult>
}

function formatNumber(value: number): string {
return value.toLocaleString('en-US', {maximumFractionDigits: 1})
}

function TreatmentResultsTable({results, label}: {results: Array<TreatmentResult>; label: string}) {
const labelId = useId()
return (
<Table.Container>
<span className="sr-only" id={labelId}>
{label}
</span>
<DataTable
aria-labelledby={labelId}
cellPadding="condensed"
columns={[
{id: 'treatment', header: 'Treatment', field: 'treatment', rowHeader: true},
{id: 'model', header: 'Model', field: 'model'},
{id: 'effort', header: 'Effort', field: 'reasoningEffort'},
{id: 'trials', header: 'Trials', field: 'trials', align: 'end'},
{id: 'scenarios', header: 'Scenarios', field: 'scenarios', align: 'end'},
{
id: 'tests',
header: 'Tests passed',
field: 'passedTests',
align: 'end',
renderCell: row => {
return row.passRate === null
? 'N/A (no tests)'
: `${row.passedTests}/${row.totalTests} (${formatNumber(row.passRate * 100)}%)`
},
},
{
id: 'tokens',
header: 'Output tokens',
field: 'outputTokens',
align: 'end',
renderCell: row => {
return formatNumber(row.outputTokens)
},
},
{
id: 'requests',
header: 'Premium requests',
field: 'premiumRequests',
align: 'end',
renderCell: row => {
return formatNumber(row.premiumRequests)
},
},
{
id: 'session',
header: 'Session time',
field: 'sessionDurationMs',
align: 'end',
renderCell: row => {
return `${formatNumber(row.sessionDurationMs / 1000)} s`
},
},
{
id: 'api',
header: 'API time',
field: 'totalApiDurationMs',
align: 'end',
renderCell: row => {
return `${formatNumber(row.totalApiDurationMs / 1000)} s`
},
},
]}
data={results}
/>
</Table.Container>
)
}

function MetricsDescription() {
return (
<p className="text-muted">
Tests passed is the sum of passed tests divided by total tests across recorded trials. Resource usage is the
average per trial. Treatments are grouped by model and reasoning effort; compare scenario and trial counts before
comparing performance.
</p>
)
}

export function ExperimentsOverview({experiments}: {experiments: Array<ExperimentSummary>}) {
return (
<section className="p-4 flex flex-col gap-4" aria-labelledby="experiments-overview-heading">
<div className="flex items-center justify-between gap-3">
<h2 className="text-title-medium" id="experiments-overview-heading">
Experiments
</h2>
<Link href="/experiments">View all experiments</Link>
</div>
{experiments.length === 0 ? <p>No experiments have been configured yet.</p> : <MetricsDescription />}
{experiments.map(experiment => {
return (
<section className="flex flex-col gap-3" key={experiment.id}>
<h3 className="text-title-small">
<Link href={`/experiments/${experiment.id}`}>{experiment.name}</Link>
</h3>
<p>{experiment.description}</p>
{experiment.date ? (
<p>
Latest run:{' '}
<Link href={`/experiments/${experiment.id}/runs/${experiment.date}` as Route}>
<time dateTime={experiment.date}>{experiment.date}</time>
</Link>
. <Link href={`/experiments/${experiment.id}`}>View scenario results and run history</Link>
</p>
) : null}
{experiment.treatments.length > 0 ? (
<TreatmentResultsTable
label={`Latest treatment results for ${experiment.name}`}
results={experiment.treatments}
/>
) : (
<p>
{experiment.date
? 'No trial results were recorded in the latest run.'
: 'No results have been recorded for this experiment yet.'}
</p>
)}
</section>
)
})}
</section>
)
}

export function LatestExperimentResults({id, results}: {id: string; results: ExperimentResults | null}) {
if (!results) {
return null
}

return (
<section className="flex flex-col gap-4" aria-labelledby="latest-results-heading">
<h2 className="text-title-medium" id="latest-results-heading">
Latest results
</h2>
<p>
Run:{' '}
<Link href={`/experiments/${id}/runs/${results.date}` as Route}>
<time dateTime={results.date}>{results.date}</time>
</Link>
</p>
{results.treatments.length > 0 ? (
<>
<MetricsDescription />
<TreatmentResultsTable label="Latest treatment results" results={results.treatments} />
</>
) : (
<Blankslate border>
<Blankslate.Heading as="h3">No trial results</Blankslate.Heading>
<Blankslate.Description>No trial results were recorded in the latest run.</Blankslate.Description>
</Blankslate>
)}
<h3 className="text-title-small">Scenario results</h3>
{results.scenarios.map(scenario => {
return (
<section className="flex flex-col gap-3" key={scenario.id}>
<h4 className="text-title-small">{scenario.id}</h4>
{scenario.treatments.length > 0 ? (
<>
<TreatmentResultsTable label={`Treatment results for ${scenario.id}`} results={scenario.treatments} />
<p>
<Link
href={`/experiments/${id}/runs/${results.date}${getScenarioAnchor(scenario.id).fragment}` as Route}
>
View output for {scenario.id}
</Link>
</p>
</>
) : (
<p>No trial results were recorded for this scenario.</p>
)}
</section>
)
})}
</section>
)
}
53 changes: 47 additions & 6 deletions website/src/app/components/RunDetailsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type {Route} from 'next'
import Link from 'next/link'
import Image from 'next/image'
import {useState} from 'react'
import {getScenarioAnchor} from '../../scenario-anchor'
import {JudgeResults} from './JudgeResults'

type RunResult = RunDetails['results'][number]
Expand Down Expand Up @@ -263,6 +264,7 @@ function ScenarioResults({group, index}: {group: ScenarioResultGroup; index: num

const [selectedModel, setSelectedModel] = useState(getModelValue(group.results[0]))
const [selectedTreatment, setSelectedTreatment] = useState(group.results[0].treatment)
const [selectedTrial, setSelectedTrial] = useState(group.results[0].id)
const resultsForSelectedModel = group.results.filter(result => {
return getModelValue(result) === selectedModel
})
Expand All @@ -271,18 +273,26 @@ function ScenarioResults({group, index}: {group: ScenarioResultGroup; index: num
return firstTreatment.localeCompare(secondTreatment)
},
)
const activeTreatment = treatmentOptions.includes(selectedTreatment) ? selectedTreatment : treatmentOptions[0]
const trials = resultsForSelectedModel.filter(result => {
return result.treatment === activeTreatment
})
const selectedResult =
resultsForSelectedModel.find(result => {
return result.treatment === selectedTreatment
trials.find(result => {
return result.id === selectedTrial
}) ??
resultsForSelectedModel[0] ??
trials[0] ??
group.results[0]

const resultHeadingId = `result-${index}-heading`
const summaryHeadingId = `result-${index}-summary-heading`

return (
<article aria-labelledby={resultHeadingId} className="flex flex-col gap-4">
<article
aria-labelledby={resultHeadingId}
className="flex flex-col gap-4"
id={getScenarioAnchor(group.scenarioId).id}
>
<header className="border-b border-default pb-3 flex flex-col sm:flex-row sm:items-end sm:justify-between gap-4">
<h2 className="text-title-medium m-0" id={resultHeadingId}>
{group.scenarioId}
Comment thread
joshblack marked this conversation as resolved.
Expand All @@ -302,9 +312,14 @@ function ScenarioResults({group, index}: {group: ScenarioResultGroup; index: num
})
? selectedTreatment
: (resultsForNextModel[0] ?? group.results[0]).treatment
const nextTrial =
resultsForNextModel.find(result => {
return result.treatment === nextTreatment
}) ?? group.results[0]

setSelectedModel(nextModel)
setSelectedTreatment(nextTreatment)
setSelectedTrial(nextTrial.id)
}}
>
{sortedModelOptions.map(([value, label]) => {
Expand All @@ -319,9 +334,16 @@ function ScenarioResults({group, index}: {group: ScenarioResultGroup; index: num
<FormControl>
<FormControl.Label>Treatment</FormControl.Label>
<Select
value={selectedResult.treatment}
value={selectedTreatment}
onChange={event => {
setSelectedTreatment(event.currentTarget.value)
const nextTreatment = event.currentTarget.value
const nextTrial =
resultsForSelectedModel.find(result => {
return result.treatment === nextTreatment
}) ?? group.results[0]

setSelectedTreatment(nextTreatment)
setSelectedTrial(nextTrial.id)
}}
>
{treatmentOptions.map(treatment => {
Expand All @@ -333,6 +355,25 @@ function ScenarioResults({group, index}: {group: ScenarioResultGroup; index: num
})}
</Select>
</FormControl>
{trials.length > 1 ? (
<FormControl>
<FormControl.Label>Trial</FormControl.Label>
<Select
value={selectedResult.id}
Comment thread
joshblack marked this conversation as resolved.
onChange={event => {
setSelectedTrial(event.currentTarget.value)
}}
>
{trials.map((trial, trialIndex) => {
return (
<Select.Option key={trial.id} value={trial.id}>
Trial {trialIndex + 1}
</Select.Option>
)
})}
</Select>
</FormControl>
) : null}
</div>
</header>
<div className="flex flex-col gap-4">
Expand Down
Loading