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
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ describe("EfficiencyCharts", () => {
test("opens on the wall-clock metric", () => {
renderCharts();
expect(screen.getByRole("heading")).toHaveTextContent(
"Time per Passed Task",
"Agent Time per Passed Task",
);
expect(
screen.getByRole("tab", { name: "Time" }),
Expand Down
6 changes: 3 additions & 3 deletions evalboard/app/_overview/efficiency-charts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ const TABS: Array<{
{
key: "time",
label: "Time",
heading: "Time per Passed Task",
title: "Total wall clock ÷ tasks passed. Every task's seconds count, failures included; only passes count in the denominator, so a run that fails more reads slower.",
heading: "Agent Time per Passed Task",
title: "Agent wall clock ÷ tasks passed. Counts the agent's turns only: sandbox setup, pre_run, grading and cleanup are excluded. Every task's agent seconds count, failures included; only passes count in the denominator, so a run that fails more reads slower.",
blurb: (scoped) =>
"Seconds of every task that ran ÷ the number that passed · hover a point for the share within 2× expected" +
"Agent seconds of every task that ran (setup and grading excluded) ÷ the number that passed · hover a point for the share within 2× expected" +
(scoped ? " · scoped to the active filter" : ""),
render: (props) => <TimePerPassedTaskChart {...props} />,
},
Expand Down
8 changes: 4 additions & 4 deletions evalboard/app/_overview/window-summary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ function Tile({
// Front-page window rollup: total spend + shape of the runs in scope. Every
// tile is summed over the same set — `runCount` and `totals` both come out of
// getOverview's single pass, so the Runs tile can never disagree with the
// Cost/Tasks/Pass/Compute tiles or with the charts. The totals are scoped to
// Cost/Tasks/Pass/Agent time tiles or with the charts. The totals are scoped to
// matching tasks whenever a filter is active.
//
// This describes the window the charts plot, NOT however far the run table below
Expand Down Expand Up @@ -91,9 +91,9 @@ export function WindowSummary({
valueClass={passClass(pct)}
/>
<Tile
label="Compute time"
value={fmtDuration(totals.durationSeconds)}
sub={totals.durationPartial ? "some runs missing" : undefined}
label="Agent time"
value={fmtDuration(totals.agentSeconds)}
sub={totals.agentPartial ? "some runs missing" : undefined}
/>
</div>
</section>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -544,9 +544,8 @@ describe("MessageTimelineSection — Unaccounted cell", () => {
expect(cell("Unaccounted").textContent).toBe("5.0s (50%)");
});

test("the four pre-existing cells still render their values", () => {
test("the pre-existing cells still render their values", () => {
renderStrip(10);
expect(cell("Messages").textContent).toBe("1");
expect(cell("Generation").textContent).toBe("4.0s");
expect(cell("Tool exec").textContent).toBe("1.0s");
expect(cell("Slow events").textContent).toBe("0 gen · 0 tool");
Expand Down Expand Up @@ -753,6 +752,72 @@ describe("MessageTimelineSection — Unaccounted cell", () => {
});
});

describe("MessageTimelineSection — agent time vs eval overhead", () => {
function cell(label: string): HTMLElement {
const parent = screen.getByText(label).parentElement as HTMLElement;
return parent.children[1] as HTMLElement;
}

const message = () => makeMessage({ generationMs: 4000, textMs: 4000 });

function renderSplit() {
return render(
<MessageTimelineSection
messages={[message()]}
taskDurationSeconds={10}
agentSeconds={6}
harnessStartupMs={1000}
harnessTeardownMs={500}
setupMs={2500}
gradingMs={1000}
/>,
);
}

test("the task total splits into agent time and eval overhead", () => {
renderSplit();
expect(cell("Task total").textContent).toBe("10.0s");
expect(cell("Agent time").textContent).toBe("6.0s (60%)");
expect(cell("Eval overhead").textContent).toBe("4.0s (40%)");
});

test("each group's cells sum to its header", () => {
renderSplit();
// 6s agent = 1s startup + 4s generation + 0.5s teardown + 0.5s unaccounted.
expect(cell("Unaccounted").textContent).toBe("500ms (8%)");
// 4s overhead = 2.5s setup + 1s grading + 0.5s other.
expect(cell("Other").textContent).toBe("500ms");
});

test("a residual that rounds to 0% of agent time is hidden", () => {
render(
<MessageTimelineSection
messages={[message()]}
taskDurationSeconds={10}
agentSeconds={6.002}
harnessStartupMs={1000}
harnessTeardownMs={1000}
/>,
);
expect(screen.queryByText("Unaccounted")).toBeNull();
});

test("without per-turn durations the residual spans the whole task", () => {
render(
<MessageTimelineSection
messages={[message()]}
taskDurationSeconds={10}
setupMs={2500}
gradingMs={1000}
/>,
);
expect(cell("Agent time").textContent).toBe("—");
expect(cell("Eval overhead").textContent).toBe("—");
expect(cell("Other").textContent).toBe("—");
expect(cell("Unaccounted").textContent).toBe("2.5s (25%)");
});
});

describe("MessageTimelineSection — a row's EXEC cell", () => {
function span(start: number, end: number) {
return {
Expand Down
Loading
Loading