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
19 changes: 18 additions & 1 deletion apps/web/app/api/pairs/route.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,33 @@
import { loadBenchmarkArtifacts } from "../../../lib/data";
import type { ArtifactFilterParams } from "../../../lib/data";
import { pairsExplorerToCsv } from "../../../lib/listExport";
import {
buildBenchmarkPairDetails,
buildBenchmarkPairSummaries,
filterPairSummaries,
} from "../../../lib/pairsExplorer";

function readPairFilters(url: URL): ArtifactFilterParams {
return {
q: url.searchParams.get("q") ?? undefined,
model: url.searchParams.get("model") ?? undefined,
preset: url.searchParams.get("preset") ?? undefined,
fast: url.searchParams.get("fast") ?? undefined,
from: url.searchParams.get("from") ?? undefined,
to: url.searchParams.get("to") ?? undefined,
};
}

export async function GET(request: Request) {
const url = new URL(request.url);
const format = url.searchParams.get("format") ?? "json";
const benchmark = url.searchParams.get("benchmark") ?? undefined;
const filters = readPairFilters(url);
const benchmarks = await loadBenchmarkArtifacts();
const summaries = await buildBenchmarkPairSummaries(benchmarks);
const summaries = filterPairSummaries(
await buildBenchmarkPairSummaries(benchmarks),
filters,
);

if (benchmark) {
const details = await buildBenchmarkPairDetails(benchmark, benchmarks);
Expand Down
12 changes: 12 additions & 0 deletions apps/web/app/errors/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ import {
buildPipelineErrorRows,
collectPipelineErrorAgents,
} from "../../lib/pipelineErrors";
import {
buildPipelineErrorByAgent,
buildPipelineErrorTrendSeries,
} from "../../lib/pipelineErrorTrends";
import { PipelineErrorTrendCharts } from "../../components/charts/PipelineErrorTrendCharts";

export const metadata: Metadata = {
title: "Pipeline errors",
Expand All @@ -43,6 +48,8 @@ export default async function PipelineErrorsPage({
agent: params.agent,
});
const errorAgents = collectPipelineErrorAgents(filteredRuns);
const errorTrendSeries = buildPipelineErrorTrendSeries(rows);
const errorAgentSeries = buildPipelineErrorByAgent(rows);
const uniqueRuns = new Set(rows.map((row) => row.runId)).size;

if (allRuns.length === 0) {
Expand Down Expand Up @@ -192,6 +199,11 @@ export default async function PipelineErrorsPage({
/>
</div>

<PipelineErrorTrendCharts
trendSeries={errorTrendSeries}
agentSeries={errorAgentSeries}
/>

<div className="card">
<h2 style={{ marginTop: 0 }}>Failed steps</h2>
{rows.length === 0 ? (
Expand Down
29 changes: 24 additions & 5 deletions apps/web/app/pairs/page.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,28 @@
import type { Metadata } from "next";
import Link from "next/link";
import { InsightFilterCard } from "../../components/InsightFilterCard";
import { MetricCard } from "../../components/MetricCard";
import {
ResponsiveTable,
TruncateText,
} from "../../components/ResponsiveTable";
import { loadBenchmarkArtifacts } from "../../lib/data";
import { collectArtifactFacets } from "../../lib/artifactFacets";
import {
loadBenchmarkArtifacts,
type ArtifactFilterParams,
} from "../../lib/data";
import { buildQueryString } from "../../lib/listPagination";
import {
buildBenchmarkPairDetails,
buildBenchmarkPairSummaries,
filterPairSummaries,
} from "../../lib/pairsExplorer";

export const metadata: Metadata = {
title: "Benchmark pairs",
};

type PairsSearchParams = {
type PairsSearchParams = ArtifactFilterParams & {
benchmark?: string;
};

Expand All @@ -26,11 +32,13 @@ export default async function PairsExplorerPage({
searchParams: Promise<PairsSearchParams>;
}) {
const params = await searchParams;
const benchmarks = await loadBenchmarkArtifacts();
const summaries = await buildBenchmarkPairSummaries(benchmarks);
const allBenchmarks = await loadBenchmarkArtifacts();
const { models, presets } = collectArtifactFacets([], allBenchmarks);
const allSummaries = await buildBenchmarkPairSummaries(allBenchmarks);
const summaries = filterPairSummaries(allSummaries, params);
const selectedBenchmark = (params.benchmark ?? "").trim();
const details = selectedBenchmark
? await buildBenchmarkPairDetails(selectedBenchmark, benchmarks)
? await buildBenchmarkPairDetails(selectedBenchmark, allBenchmarks)
: { summary: null, pairs: [] };

return (
Expand All @@ -57,6 +65,17 @@ export default async function PairsExplorerPage({
</div>
</div>

<InsightFilterCard
action="/pairs"
models={models}
presets={presets}
params={params}
totalRuns={allSummaries.length}
filteredRuns={summaries.length}
preserveKeys={["benchmark"]}
entityLabel="benchmarks with pairs"
/>

{summaries.length > 0 ? (
<div
className="page-actions"
Expand Down
5 changes: 5 additions & 0 deletions apps/web/app/quality/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import {
buildQualityRunRows,
summarizeQuality,
} from "../../lib/qualityInsights";
import { buildQualityTrendSeries } from "../../lib/qualityTrends";
import { QualityTrendCharts } from "../../components/charts/QualityTrendCharts";
import {
aggregateJudgeNarratives,
listJudgeSummaries,
Expand Down Expand Up @@ -75,6 +77,7 @@ export default async function QualityInsightsPage({
const index = applyIndexFilters(rawIndex, params);
const summary = summarizeQuality(index);
const rows = buildQualityRunRows(index);
const qualityTrendSeries = buildQualityTrendSeries(rows);
const qualityRunIds = new Set(
rows
.filter(
Expand Down Expand Up @@ -192,6 +195,8 @@ export default async function QualityInsightsPage({
/>
</div>

<QualityTrendCharts series={qualityTrendSeries} />

{summary.withQualityScores === 0 ? (
<div className="card">
<p className="muted">
Expand Down
117 changes: 111 additions & 6 deletions apps/web/app/questions/view/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,18 @@ import {
filterBenchmarkArtifacts,
filterRunArtifacts,
loadAnalysisIndex,
loadBenchmarkArtifacts,
loadBenchmarksByQuestion,
loadRunArtifacts,
loadRunsByQuestion,
} from "../../../lib/data";
import { buildQueryString } from "../../../lib/listPagination";
import {
groupArtifactsByQuestion,
questionHubHref,
listQuestionInsightLinks,
} from "../../../lib/questionGroups";
import { buildTopQuestions } from "../../../lib/topQuestions";
import {
buildQuestionExperimentMatrix,
buildMatrixCellRunCompareHref,
Expand Down Expand Up @@ -56,14 +60,115 @@ export default async function QuestionHubPage({
const params = await searchParams;
const question = (params.question ?? "").trim();
if (!question) {
const [runs, benchmarks] = await Promise.all([
loadRunArtifacts(),
loadBenchmarkArtifacts(),
]);
const topQuestions = buildTopQuestions(
groupArtifactsByQuestion(runs, benchmarks),
12,
);

return (
<section className="stack">
<h1 className="title">Question hub</h1>
<p className="subtitle">
Pick a question from the{" "}
<Link href="/questions">questions explorer</Link> to see all
runs and benchmarks for that topic.
</p>
<div>
<h1 className="title">Question hub</h1>
<p className="subtitle">
Open a research question to compare every run and
benchmark on that topic — or browse the full{" "}
<Link href="/questions">questions explorer</Link>.
</p>
<div
className="page-actions"
style={{ display: "flex", gap: 10, flexWrap: "wrap" }}
>
<Link href="/questions" className="button secondary">
All questions
</Link>
<Link href="/search" className="button secondary">
Search artifacts
</Link>
</div>
</div>

{topQuestions.length === 0 ? (
<div className="card">
<p className="muted" style={{ margin: 0 }}>
No questions yet. Run debate experiments locally,
then open the questions explorer once artifacts are
available.
</p>
</div>
) : (
<div className="card">
<h2 style={{ marginTop: 0 }}>
Popular research topics
</h2>
<p className="small muted" style={{ marginBottom: 12 }}>
Questions with the most runs and benchmarks in the
artifact store.
</p>
<ResponsiveTable
columns={[
{
key: "question",
label: "Question",
cellClass: "cell-question",
render: (row) => (
<Link
href={
(row as { hubHref: string })
.hubHref
}
>
<TruncateText
text={
(
row as {
question: string;
}
).question
}
maxLength={96}
/>
</Link>
),
},
{ key: "runCount", label: "Runs" },
{ key: "benchmarkCount", label: "Benchmarks" },
{
key: "totalExperiments",
label: "Total",
},
{
key: "latestCreatedAt",
label: "Latest",
hideOnMobile: true,
render: (row) =>
new Date(
(
row as {
latestCreatedAt: string;
}
).latestCreatedAt,
).toLocaleString(),
},
]}
data={topQuestions}
getRowId={(row) =>
(row as { question: string }).question
}
renderCardActions={(row) => (
<Link
href={(row as { hubHref: string }).hubHref}
className="button"
>
Open hub
</Link>
)}
/>
</div>
)}
</section>
);
}
Expand Down
4 changes: 3 additions & 1 deletion apps/web/components/InsightFilterCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ type InsightFilterCardProps = {
totalRuns: number;
filteredRuns: number;
preserveKeys?: string[];
entityLabel?: string;
};

export function InsightFilterCard({
Expand All @@ -21,6 +22,7 @@ export function InsightFilterCard({
totalRuns,
filteredRuns,
preserveKeys = [],
entityLabel = "runs",
}: InsightFilterCardProps) {
const clearHref = (() => {
const query = new URLSearchParams();
Expand All @@ -38,7 +40,7 @@ export function InsightFilterCard({
<CollapsibleFilterCard
resultsSummary={
<>
{filteredRuns} of {totalRuns} runs
{filteredRuns} of {totalRuns} {entityLabel}
</>
}
>
Expand Down
Loading
Loading