@post-print/agent-test 2.2.0 → 2.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,7 +4,8 @@ import { useMutation, useQueries, useQuery, useQueryClient } from "@tanstack/rea
4
4
  import { createRootRoute, createRoute, createRouter, Link, Outlet, useNavigate, } from "@tanstack/react-router";
5
5
  import { createContext, useCallback, useContext, useEffect, useId, useRef, useState, } from "react";
6
6
  import Markdown from "react-markdown";
7
- import { assertionComparison, conversationPlaceholder, formatRunDate, median, preferredTestExecutionId, stripAnsi, testRunStatus, unwrapShellCommand, } from "./presentation.js";
7
+ import { ElapsedTime } from "./elapsed-time.js";
8
+ import { assertionComparison, conversationPlaceholder, describeShape, formatRunDate, median, preferredTestExecutionId, stripAnsi, testIntent, testRunStatus, unwrapShellCommand, } from "./presentation.js";
8
9
  import { RunInboxPage, RunPage } from "./run-inbox.js";
9
10
  import { ToolImages, toolImages } from "./tool-images.js";
10
11
  import { cancelExecution, fetchExecution as fetchExecutionRecord, startSuite, startTest, startTestGroup, useCatalog, useExecutionHistory, } from "./viewer-queries.js";
@@ -363,6 +364,18 @@ const styles = stylex.create({
363
364
  letterSpacing: "0.08em",
364
365
  textTransform: "uppercase",
365
366
  },
367
+ catalogNotice: {
368
+ margin: "0.6rem 1.25rem 0",
369
+ color: "var(--muted)",
370
+ fontSize: "0.72rem",
371
+ lineHeight: 1.45,
372
+ },
373
+ catalogNoticeError: {
374
+ padding: "0.45rem 0.6rem",
375
+ borderRadius: 8,
376
+ color: "var(--fail)",
377
+ backgroundColor: "var(--fail-soft)",
378
+ },
366
379
  groupCount: { color: "var(--subtle)", fontSize: "0.66rem", fontVariantNumeric: "tabular-nums" },
367
380
  navLink: {
368
381
  display: "block",
@@ -431,6 +444,16 @@ const styles = stylex.create({
431
444
  alignSelf: "start",
432
445
  },
433
446
  description: { color: "var(--muted)", fontSize: "0.82rem", lineHeight: 1.5, maxWidth: "54rem" },
447
+ suiteDescription: {
448
+ margin: 0,
449
+ color: "var(--subtle)",
450
+ fontSize: "0.74rem",
451
+ lineHeight: 1.45,
452
+ overflow: "hidden",
453
+ textOverflow: "ellipsis",
454
+ whiteSpace: "nowrap",
455
+ },
456
+ headerChecks: { paddingTop: "0.55rem" },
434
457
  path: {
435
458
  color: "var(--subtle)",
436
459
  fontSize: "0.7rem",
@@ -632,6 +655,46 @@ const styles = stylex.create({
632
655
  gap: "0.7rem",
633
656
  },
634
657
  attemptTitle: { fontSize: "0.84rem", lineHeight: 1.4 },
658
+ liveStrip: {
659
+ position: "sticky",
660
+ top: 0,
661
+ zIndex: 2,
662
+ display: "grid",
663
+ gap: "0.3rem",
664
+ padding: "0.55rem 0.75rem",
665
+ border: "1px solid var(--border-strong)",
666
+ borderRadius: 10,
667
+ backgroundColor: "var(--panel-2)",
668
+ minWidth: 0,
669
+ },
670
+ liveStripLine: {
671
+ display: "flex",
672
+ flexWrap: "wrap",
673
+ alignItems: "center",
674
+ gap: "0.4rem 0.75rem",
675
+ },
676
+ liveStripElapsed: {
677
+ color: "var(--text)",
678
+ fontSize: "0.82rem",
679
+ fontWeight: 700,
680
+ fontVariantNumeric: "tabular-nums",
681
+ },
682
+ liveStripMeta: { color: "var(--muted)", fontSize: "0.76rem", fontVariantNumeric: "tabular-nums" },
683
+ liveStripNow: {
684
+ margin: 0,
685
+ minWidth: 0,
686
+ overflow: "hidden",
687
+ textOverflow: "ellipsis",
688
+ whiteSpace: "nowrap",
689
+ color: "var(--text)",
690
+ fontSize: "0.78rem",
691
+ },
692
+ liveStripLabel: { color: "var(--subtle)", fontWeight: 650 },
693
+ liveStripDetail: {
694
+ marginLeft: "0.4rem",
695
+ color: "var(--muted)",
696
+ fontSize: "0.72rem",
697
+ },
635
698
  verdictPanel: {
636
699
  display: "grid",
637
700
  gap: "0.55rem",
@@ -1000,15 +1063,38 @@ const styles = stylex.create({
1000
1063
  judgeContextList: { display: "grid", gap: "0.3rem", margin: 0 },
1001
1064
  judgeContextItem: {
1002
1065
  display: "grid",
1003
- gridTemplateColumns: {
1004
- default: "minmax(7.5rem, 0.3fr) minmax(0, 1fr)",
1005
- "@media (max-width: 620px)": "1fr",
1006
- },
1007
- gap: "0.65rem",
1066
+ gap: "0.45rem",
1008
1067
  padding: "0.4rem 0.5rem",
1009
1068
  borderRadius: 6,
1010
1069
  backgroundColor: "var(--bg)",
1011
1070
  },
1071
+ judgeContextFieldSummary: {
1072
+ display: "flex",
1073
+ alignItems: "baseline",
1074
+ gap: "0.5rem",
1075
+ cursor: "pointer",
1076
+ minWidth: 0,
1077
+ },
1078
+ judgeContextShape: {
1079
+ color: "var(--muted)",
1080
+ fontSize: "0.68rem",
1081
+ fontVariantNumeric: "tabular-nums",
1082
+ },
1083
+ judgeContextFieldBody: {
1084
+ display: "grid",
1085
+ gap: "0.35rem",
1086
+ maxHeight: "24rem",
1087
+ overflow: "auto",
1088
+ },
1089
+ judgeContextStringList: {
1090
+ margin: 0,
1091
+ paddingLeft: "1.1rem",
1092
+ color: "var(--text)",
1093
+ fontSize: "0.72rem",
1094
+ lineHeight: 1.5,
1095
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
1096
+ wordBreak: "break-word",
1097
+ },
1012
1098
  judgeContextLabel: {
1013
1099
  color: "var(--subtle)",
1014
1100
  fontSize: "0.64rem",
@@ -1291,7 +1377,7 @@ function ViewerSidebarContent({ mode, open = true, headingId, navigationId, onTo
1291
1377
  const history = useExecutionHistory();
1292
1378
  const groups = groupTests(catalog.data?.tests ?? []);
1293
1379
  const statuses = latestTestStatuses(history.data ?? []);
1294
- return (_jsxs(_Fragment, { children: [_jsx(SidebarHeader, { mode: mode, open: open, count: catalog.data?.tests.length ?? 0, headingId: headingId, navigationId: navigationId, onToggle: mode === "mobile" ? onClose : onToggle, onNavigate: onClose }), open ? (_jsx(SidebarNavigation, { groups: groups, statuses: statuses, error: catalog.isError, navigationId: navigationId, onNavigate: onClose })) : null] }));
1380
+ return (_jsxs(_Fragment, { children: [_jsx(SidebarHeader, { mode: mode, open: open, count: catalog.data?.tests.length ?? 0, headingId: headingId, navigationId: navigationId, onToggle: mode === "mobile" ? onClose : onToggle, onNavigate: onClose }), open ? (_jsx(SidebarNavigation, { groups: groups, statuses: statuses, catalogState: catalogState(catalog), navigationId: navigationId, onNavigate: onClose })) : null] }));
1295
1381
  }
1296
1382
  function SidebarHeader({ mode, open, count, headingId, navigationId, onToggle, onNavigate, }) {
1297
1383
  const { workers } = useContext(WorkerContext);
@@ -1319,8 +1405,21 @@ function SidebarToggle({ mode, open, navigationId, onToggle, }) {
1319
1405
  const mobile = mode === "mobile";
1320
1406
  return (_jsx("button", { type: "button", "data-drawer-close": mobile ? "true" : undefined, "aria-controls": navigationId, "aria-expanded": open, "aria-label": mobile ? "Close test menu" : open ? "Collapse test sidebar" : "Expand test sidebar", ...stylex.props(styles.buttonReset, styles.toggleButton, mobile && styles.mobileCloseButton), onClick: onToggle, children: mobile ? "×" : open ? "←" : "→" }));
1321
1407
  }
1322
- function SidebarNavigation({ groups, statuses, error, navigationId, onNavigate, }) {
1323
- return (_jsxs(_Fragment, { children: [error ? _jsx("p", { role: "alert", children: "Test discovery is unavailable." }) : null, _jsx("nav", { id: navigationId, "aria-label": "Tests", ...stylex.props(styles.navigation), children: [...groups].map(([name, tests]) => (_jsxs("section", { "aria-label": `${name} tests`, ...stylex.props(styles.navSection), children: [_jsxs("div", { ...stylex.props(styles.groupHeader), children: [_jsx("strong", { ...stylex.props(styles.groupLabel), children: name }), _jsxs("div", { ...stylex.props(styles.groupHeaderActions), children: [_jsx("span", { ...stylex.props(styles.groupCount), children: tests.length }), _jsx(RunTestGroupButton, { name: name, tests: tests, onNavigate: onNavigate })] })] }), tests.map((test) => (_jsx(TestLink, { test: test, status: statuses.get(test.id), onNavigate: onNavigate }, test.id)))] }, name))) })] }));
1408
+ /** A failed refresh over a list already shown is stale, not missing. */
1409
+ function catalogState(catalog) {
1410
+ if (!catalog.isError)
1411
+ return "ready";
1412
+ return catalog.data ? "stale" : "unavailable";
1413
+ }
1414
+ function CatalogNotice({ state }) {
1415
+ if (state === "ready")
1416
+ return null;
1417
+ if (state === "stale")
1418
+ return (_jsx("p", { role: "status", ...stylex.props(styles.catalogNotice), children: "Test list may be out of date. Retrying\u2026" }));
1419
+ return (_jsx("p", { role: "alert", ...stylex.props(styles.catalogNotice, styles.catalogNoticeError), children: "Test discovery is unavailable. Retrying\u2026" }));
1420
+ }
1421
+ function SidebarNavigation({ groups, statuses, catalogState, navigationId, onNavigate, }) {
1422
+ return (_jsxs(_Fragment, { children: [_jsx(CatalogNotice, { state: catalogState }), _jsx("nav", { id: navigationId, "aria-label": "Tests", ...stylex.props(styles.navigation), children: [...groups].map(([name, tests]) => (_jsxs("section", { "aria-label": `${name} tests`, ...stylex.props(styles.navSection), children: [_jsxs("div", { ...stylex.props(styles.groupHeader), children: [_jsx("strong", { title: tests[0] ? testIntent(tests[0], tests).suite : undefined, ...stylex.props(styles.groupLabel), children: name }), _jsxs("div", { ...stylex.props(styles.groupHeaderActions), children: [_jsx("span", { ...stylex.props(styles.groupCount), children: tests.length }), _jsx(RunTestGroupButton, { name: name, tests: tests, onNavigate: onNavigate })] })] }), tests.map((test) => (_jsx(TestLink, { test: test, hint: testIntent(test, tests).own, status: statuses.get(test.id), onNavigate: onNavigate }, test.id)))] }, name))) })] }));
1324
1423
  }
1325
1424
  function RunTestGroupButton({ name, tests, onNavigate, }) {
1326
1425
  const { workers } = useContext(WorkerContext);
@@ -1336,8 +1435,8 @@ function RunTestGroupButton({ name, tests, onNavigate, }) {
1336
1435
  });
1337
1436
  return (_jsx("button", { type: "button", "aria-label": `Run ${name} suite`, title: `Run ${name} suite`, ...stylex.props(styles.buttonReset, styles.groupRunButton), onClick: () => run.mutate(), disabled: run.isPending, children: run.isPending ? "●" : "▶" }));
1338
1437
  }
1339
- function TestLink({ test, status, onNavigate, }) {
1340
- return (_jsxs(Link, { to: "/tests/$testId", params: { testId: test.id }, search: {}, ...stylex.props(styles.navLink), activeProps: stylex.props(styles.navLink, styles.active), onClick: onNavigate, children: [_jsxs("div", { ...stylex.props(styles.navItemHeader), children: [status ? _jsx(TestStatus, { status: status }) : _jsx("span", { "aria-hidden": "true" }), _jsx("span", { ...stylex.props(styles.navItemTitle), children: test.title.at(-1) })] }), test.project !== "default" ? _jsx("div", { ...stylex.props(styles.meta), children: test.project }) : null] }));
1438
+ function TestLink({ test, hint, status, onNavigate, }) {
1439
+ return (_jsxs(Link, { to: "/tests/$testId", params: { testId: test.id }, search: {}, ...stylex.props(styles.navLink), activeProps: stylex.props(styles.navLink, styles.active), onClick: onNavigate, children: [_jsxs("div", { ...stylex.props(styles.navItemHeader), children: [status ? _jsx(TestStatus, { status: status }) : _jsx("span", { "aria-hidden": "true" }), _jsx("span", { title: hint ?? test.title.at(-1), ...stylex.props(styles.navItemTitle), children: test.title.at(-1) })] }), test.project !== "default" ? _jsx("div", { ...stylex.props(styles.meta), children: test.project }) : null] }));
1341
1440
  }
1342
1441
  function TestStatus({ status }) {
1343
1442
  return (_jsx("span", { role: "img", "aria-label": `Latest execution: ${status}`, title: `Latest execution: ${status}`, ...stylex.props(styles.navStatus), children: _jsx("span", { "aria-hidden": "true", ...stylex.props(styles.navStatusDot, status === "passed" && styles.navStatusDotPass, status === "failed" && styles.navStatusDotFail, status === "running" && styles.navStatusDotRunning) }) }));
@@ -1350,9 +1449,9 @@ function TestPage() {
1350
1449
  const test = catalog.data?.tests.find((item) => item.id === testId);
1351
1450
  if (!test)
1352
1451
  return (_jsx("p", { role: "alert", children: "This test is no longer available. Choose another test in the sidebar." }));
1353
- return _jsx(TestDetail, { test: test }, test.id);
1452
+ return (_jsx(TestDetail, { test: test, intent: testIntent(test, catalog.data?.tests ?? []) }, test.id));
1354
1453
  }
1355
- function TestDetail({ test }) {
1454
+ function TestDetail({ test, intent }) {
1356
1455
  const { execution, view } = testRoute.useSearch();
1357
1456
  const history = useExecutionHistory();
1358
1457
  const navigate = useNavigate();
@@ -1369,7 +1468,7 @@ function TestDetail({ test }) {
1369
1468
  params: { testId: test.id },
1370
1469
  search: { execution, view: next === "current" ? undefined : next },
1371
1470
  });
1372
- return (_jsxs(_Fragment, { children: [_jsx(TestHeader, { test: test, onStarted: chooseExecution }), _jsx(BatchRunLink, { run: runs.find((run) => run.id === selected) }), _jsx(TestTabs, { active: activeView, onChange: chooseView }), _jsx(TestViewPanel, { view: activeView, test: test, runs: runs, selected: selected, historyLoading: history.isPending, onChooseExecution: chooseExecution })] }));
1471
+ return (_jsxs(_Fragment, { children: [_jsx(TestHeader, { test: test, intent: intent, onStarted: chooseExecution }), _jsx(BatchRunLink, { run: runs.find((run) => run.id === selected) }), _jsx(TestTabs, { active: activeView, onChange: chooseView }), _jsx(TestViewPanel, { view: activeView, test: test, runs: runs, selected: selected, historyLoading: history.isPending, onChooseExecution: chooseExecution })] }));
1373
1472
  }
1374
1473
  /** Return path to the run inbox when this test was opened from a batch run. */
1375
1474
  function BatchRunLink({ run }) {
@@ -1378,8 +1477,14 @@ function BatchRunLink({ run }) {
1378
1477
  return null;
1379
1478
  return (_jsxs(Link, { to: "/executions/$executionId", params: { executionId: run.id }, ...stylex.props(styles.batchRunLink), children: ["\u2190 Back to run \u00B7 ", formatRunDate(run.startedAt), " \u00B7 ", count, " tests"] }));
1380
1479
  }
1381
- function TestHeader({ test, onStarted }) {
1382
- return (_jsxs("header", { ...stylex.props(styles.hero), children: [_jsxs("div", { ...stylex.props(styles.heroTop), children: [_jsxs("div", { ...stylex.props(styles.heroCopy), children: [_jsx("div", { ...stylex.props(styles.brand), children: test.title.slice(0, -1).join(" / ") }), _jsx("h2", { ...stylex.props(styles.title), children: test.title.at(-1) }), _jsx("p", { ...stylex.props(styles.description), children: test.description ?? "This test has no additional description." })] }), _jsx(RunTestButton, { test: test, onStarted: onStarted })] }), _jsxs("div", { ...stylex.props(styles.path), children: [test.project, " \u00B7 ", test.file] })] }));
1480
+ function TestHeader({ test, intent, onStarted, }) {
1481
+ return (_jsxs("header", { ...stylex.props(styles.hero), children: [_jsxs("div", { ...stylex.props(styles.heroTop), children: [_jsxs("div", { ...stylex.props(styles.heroCopy), children: [_jsx("div", { ...stylex.props(styles.brand), children: test.title.slice(0, -1).join(" / ") }), intent.suite ? (_jsx("p", { title: intent.suite, ...stylex.props(styles.suiteDescription), children: intent.suite })) : null, _jsx("h2", { ...stylex.props(styles.title), children: test.title.at(-1) }), intent.own ? _jsx("p", { ...stylex.props(styles.description), children: intent.own }) : null] }), _jsx(RunTestButton, { test: test, onStarted: onStarted })] }), _jsx(TestChecks, { criteria: test.criteria ?? [] }), _jsxs("div", { ...stylex.props(styles.path), children: [test.project, " \u00B7 ", test.file] })] }));
1482
+ }
1483
+ /** What the test checks, folded: the verdict below lists the same checks once a run exists. */
1484
+ function TestChecks({ criteria }) {
1485
+ if (!criteria.length)
1486
+ return null;
1487
+ return (_jsxs("details", { "data-disclosure": true, ...stylex.props(styles.judgeContextDisclosure), children: [_jsxs("summary", { ...stylex.props(styles.judgeContextSummary), children: ["Passes when \u00B7 ", criteria.length, " ", pluralize(criteria.length, "check")] }), _jsx("ul", { ...stylex.props(styles.criteriaList, styles.headerChecks), children: criteria.map((criterion) => (_jsxs("li", { ...stylex.props(styles.criterion), children: [_jsx("span", { "aria-hidden": "true", ...stylex.props(styles.criterionIcon), children: "\u2022" }), _jsx("span", { children: criterion })] }, criterion))) })] }));
1383
1488
  }
1384
1489
  const TEST_VIEWS = [
1385
1490
  { id: "current", label: "Current run" },
@@ -1501,7 +1606,7 @@ function ExecutionDetailView({ execution, criteria = [], }) {
1501
1606
  });
1502
1607
  const stopping = execution.status === "running" && (cancel.isPending || cancel.isSuccess);
1503
1608
  const stopLabel = (execution.testIds?.length ?? 0) > 1 ? "Stop suite run" : "Stop this run";
1504
- return (_jsxs("div", { ...stylex.props(styles.statusPanel), children: [execution.status === "running" && execution.cancellable ? (_jsx("div", { ...stylex.props(styles.runControls), children: _jsx("button", { type: "button", ...stylex.props(styles.buttonReset, styles.button, styles.secondaryButton), onClick: () => cancel.mutate(), disabled: stopping, children: stopping ? "Stopping…" : stopLabel }) })) : null, cancel.isError ? _jsx("p", { role: "alert", children: "The run could not be stopped." }) : null, _jsxs("section", { ...stylex.props(styles.list), children: [execution.attempts.map((attempt) => (_jsx(AttemptCard, { attempt: attempt, criteria: criteria, showTitle: false }, attempt.id))), execution.attempts.length === 0 ? (_jsx("p", { ...stylex.props(styles.empty), children: emptyExecutionMessage(execution, stopping) })) : null] })] }));
1609
+ return (_jsxs("div", { ...stylex.props(styles.statusPanel), children: [execution.status === "running" && execution.cancellable ? (_jsx("div", { ...stylex.props(styles.runControls), children: _jsx("button", { type: "button", ...stylex.props(styles.buttonReset, styles.button, styles.secondaryButton), onClick: () => cancel.mutate(), disabled: stopping, children: stopping ? "Stopping…" : stopLabel }) })) : null, cancel.isError ? _jsx("p", { role: "alert", children: "The run could not be stopped." }) : null, _jsxs("section", { ...stylex.props(styles.list), children: [execution.attempts.map((attempt) => (_jsx(AttemptCard, { attempt: attempt, criteria: criteria, showTitle: false, progress: execution.progress?.filter((entry) => entry.attemptId === attempt.id) }, attempt.id))), execution.attempts.length === 0 ? (_jsx("p", { ...stylex.props(styles.empty), children: emptyExecutionMessage(execution, stopping) })) : null] })] }));
1505
1610
  }
1506
1611
  function emptyExecutionMessage(execution, stopping) {
1507
1612
  if (stopping)
@@ -1533,11 +1638,45 @@ function ComparisonColumn({ execution, label }) {
1533
1638
  return (_jsxs("article", { ...stylex.props(styles.card), children: [_jsxs("strong", { children: [label, ": ", execution.status] }), _jsx("p", { ...stylex.props(styles.meta), children: execution.id.slice(0, 8) }), execution.attempts.map((attempt) => (_jsx(AttemptCard, { attempt: attempt }, attempt.id)))] }));
1534
1639
  }
1535
1640
  /** `showTitle` is off on a test page, whose header already names the test. */
1536
- function AttemptCard({ attempt, criteria = [], showTitle = true, }) {
1641
+ function AttemptCard({ attempt, criteria = [], showTitle = true, progress = [], }) {
1537
1642
  const { operations, output, title } = attemptPresentation(attempt, criteria);
1538
1643
  const agents = operations.filter((operation) => operation.kind !== "evaluation");
1539
1644
  const judges = operations.filter((operation) => operation.kind === "evaluation");
1540
- return (_jsxs("article", { ...stylex.props(styles.attemptCard), children: [_jsxs("div", { ...stylex.props(styles.row), children: [_jsxs("div", { children: [showTitle ? _jsx("strong", { ...stylex.props(styles.attemptTitle), children: title }) : null, _jsxs("p", { ...stylex.props(styles.meta), children: [attempt.project || "default", " \u00B7 ", attempt.operations.length, " named", " ", pluralize(attempt.operations.length, "operation")] })] }), _jsxs("div", { ...stylex.props(styles.attemptActions), children: [attempt.status === "failed" ? (_jsx(CopyFailureButton, { attempt: attempt, criteria: criteria })) : null, _jsx("span", { ...stylex.props(styles.status, attempt.status === "passed" && styles.statusPass, attempt.status === "failed" && styles.statusFail, attempt.status === "running" && styles.statusRunning), children: attempt.status })] })] }), _jsx(TestVerdict, { attempt: attempt, criteria: criteria, operations: operations }), _jsx(OperationList, { operations: operations }), _jsx(ConversationSection, { label: "Judges", sectionOperations: judges, allOperations: operations, attempt: attempt }), _jsx(ConversationSection, { label: "Agents", sectionOperations: agents, allOperations: operations, attempt: attempt }), _jsx(TechnicalDetails, { operations: operations, output: output })] }));
1645
+ return (_jsxs("article", { ...stylex.props(styles.attemptCard), children: [_jsxs("div", { ...stylex.props(styles.row), children: [_jsxs("div", { children: [showTitle ? _jsx("strong", { ...stylex.props(styles.attemptTitle), children: title }) : null, _jsxs("p", { ...stylex.props(styles.meta), children: [attempt.project || "default", " \u00B7 ", attempt.operations.length, " named", " ", pluralize(attempt.operations.length, "operation")] })] }), _jsxs("div", { ...stylex.props(styles.attemptActions), children: [attempt.status === "failed" ? (_jsx(CopyFailureButton, { attempt: attempt, criteria: criteria })) : null, _jsx("span", { ...stylex.props(styles.status, attempt.status === "passed" && styles.statusPass, attempt.status === "failed" && styles.statusFail, attempt.status === "running" && styles.statusRunning), children: attempt.status })] })] }), attempt.status === "running" ? (_jsx(LiveRunStrip, { attempt: attempt, operations: operations, progress: progress.at(-1) })) : null, _jsx(TestVerdict, { attempt: attempt, criteria: criteria, operations: operations }), _jsx(OperationList, { operations: operations }), _jsx(ConversationSection, { label: "Judges", sectionOperations: judges, allOperations: operations, attempt: attempt }), _jsx(ConversationSection, { label: "Agents", sectionOperations: agents, allOperations: operations, attempt: attempt }), _jsx(TechnicalDetails, { operations: operations, output: output })] }));
1646
+ }
1647
+ /** Where a long run is right now: how long it has run, how far it got, and what it is doing. */
1648
+ function LiveRunStrip({ attempt, operations, progress, }) {
1649
+ const step = currentStep(operations);
1650
+ const reported = progress ? progressSummary(progress.data) : undefined;
1651
+ return (_jsxs("section", { "aria-label": "Live run status", ...stylex.props(styles.liveStrip), children: [_jsxs("div", { ...stylex.props(styles.liveStripLine), children: [_jsx(RunningIndicator, { kind: step.kind }), attempt.startedAt ? (_jsx("span", { ...stylex.props(styles.liveStripElapsed), children: _jsx(ElapsedTime, { since: attempt.startedAt }) })) : null, _jsxs("span", { ...stylex.props(styles.liveStripMeta), children: [step.count, " ", pluralize(step.count, "step")] })] }), _jsxs("p", { "aria-live": "polite", title: step.detail, ...stylex.props(styles.liveStripNow), children: [_jsx("span", { ...stylex.props(styles.liveStripLabel), children: "Now:" }), " ", step.label, step.detail ? _jsx("code", { ...stylex.props(styles.liveStripDetail), children: step.detail }) : null] }), reported ? (_jsxs("p", { title: reported, ...stylex.props(styles.liveStripNow), children: [_jsx("span", { ...stylex.props(styles.liveStripLabel), children: "Progress:" }), " ", reported] })) : null] }));
1652
+ }
1653
+ /** The newest thing the running test did, read from the same live records as the transcript. */
1654
+ function currentStep(operations) {
1655
+ const count = operations
1656
+ .filter((operation) => operation.kind !== "evaluation")
1657
+ .flatMap((operation) => liveConversationTimeline(operation.data.filter(isRecord)))
1658
+ .filter((event) => event.kind === "tool").length;
1659
+ const active = [...operations].reverse().find((operation) => operation.status === "running");
1660
+ if (!active)
1661
+ return { label: "Preparing the next step", count };
1662
+ if (active.kind === "evaluation")
1663
+ return { kind: active.kind, label: `Judge ${active.name ?? ""} is reviewing`.trim(), count };
1664
+ const latest = liveConversationTimeline(active.data.filter(isRecord)).at(-1);
1665
+ if (latest?.kind === "tool") {
1666
+ const tool = toolPresentation(latest.tool);
1667
+ return { kind: active.kind, label: tool.title, detail: tool.detail || undefined, count };
1668
+ }
1669
+ const label = latest ? "Writing a reply" : "Waiting for the first agent event";
1670
+ return { kind: active.kind, label, count };
1671
+ }
1672
+ /** One line from whatever the test passed to reportProgress. */
1673
+ function progressSummary(data) {
1674
+ if (typeof data === "string")
1675
+ return data || undefined;
1676
+ if (!isRecord(data))
1677
+ return data === undefined || data === null ? undefined : String(data);
1678
+ const facts = Object.entries(data).map(([key, value]) => `${humanizeKey(key)}: ${formatConversationValue(value)}`);
1679
+ return facts.join(" · ") || undefined;
1541
1680
  }
1542
1681
  /** Test-level outcome first: every check with its result, including judge-decided checks. */
1543
1682
  function TestVerdict({ attempt, criteria, operations, }) {
@@ -1548,7 +1687,7 @@ function TestVerdict({ attempt, criteria, operations, }) {
1548
1687
  status: attempt.status,
1549
1688
  errors: attempt.errors,
1550
1689
  });
1551
- return (_jsxs("section", { "aria-label": "Test verdict", ...stylex.props(styles.verdictPanel, attempt.status === "passed" && styles.verdictPass, attempt.status === "failed" && styles.verdictFail), children: [_jsxs("p", { ...stylex.props(styles.verdictHeadline), children: [capitalize(attempt.status), _jsx("span", { ...stylex.props(styles.verdictCount), children: checkSummary(presentations, attempt.status) })] }), attempt.status === "running" ? (_jsx("p", { ...stylex.props(styles.meta), children: "The test is still running." })) : null, _jsx(VerdictMetrics, { operations: operations, reported: attempt.metrics }), _jsx(VerdictChecks, { presentations: presentations }), _jsx(UnassignedFailures, { errors: attempt.errors, presentations: presentations }), _jsx(VerdictAttachments, { attachments: attempt.attachments })] }));
1690
+ return (_jsxs("section", { "aria-label": "Test verdict", ...stylex.props(styles.verdictPanel, attempt.status === "passed" && styles.verdictPass, attempt.status === "failed" && styles.verdictFail), children: [_jsxs("p", { ...stylex.props(styles.verdictHeadline), children: [capitalize(attempt.status), _jsx("span", { ...stylex.props(styles.verdictCount), children: checkSummary(presentations, attempt.status) })] }), _jsx(VerdictMetrics, { operations: operations, reported: attempt.metrics }), _jsx(VerdictChecks, { presentations: presentations }), _jsx(UnassignedFailures, { errors: attempt.errors, presentations: presentations }), _jsx(VerdictAttachments, { attachments: attempt.attachments })] }));
1552
1691
  }
1553
1692
  const SHORT_CHECK_LIST = 3;
1554
1693
  /** Checks needing attention always show; passing checks fold away once the list is long. */
@@ -2100,12 +2239,12 @@ function JudgeAsked({ review }) {
2100
2239
  return null;
2101
2240
  return (_jsx("section", { "aria-label": "Judge question", ...stylex.props(styles.judgeQuestion), children: _jsxs("p", { ...stylex.props(styles.judgeQuestionText), children: [_jsx("span", { ...stylex.props(styles.judgeAskedLabel), children: "Asked" }), _jsx("span", { children: review.question })] }) }));
2102
2241
  }
2103
- /** Everything the test sent the judge, folded away: it mostly repeats the agent answers. */
2242
+ /** Everything the test sent the judge, folded away unless a finding failed. */
2104
2243
  function JudgeInputs({ review, operations, }) {
2105
2244
  if (!review.context.length)
2106
2245
  return null;
2107
- // Inputs matter most before findings exist and when a finding failed.
2108
- const inputsFirst = review.outcomes.length === 0 || review.outcomes.some((outcome) => !outcome.passed);
2246
+ // Inputs explain a failed finding; while the judge runs they only push the transcript away.
2247
+ const inputsFirst = review.outcomes.some((outcome) => !outcome.passed);
2109
2248
  return (_jsx("section", { "aria-label": "Context included", children: _jsxs("details", { "data-disclosure": true, open: inputsFirst, ...stylex.props(styles.judgeContextDisclosure), children: [_jsxs("summary", { ...stylex.props(styles.judgeContextSummary), children: ["What the judge saw \u00B7 ", review.context.length, " selected", " ", pluralize(review.context.length, "field")] }), _jsx(JudgeContext, { context: review.context, operations: operations })] }) }));
2110
2249
  }
2111
2250
  function JudgeContext({ context, operations, }) {
@@ -2113,7 +2252,37 @@ function JudgeContext({ context, operations, }) {
2113
2252
  const [selectedId, setSelectedId] = useState(answers[0]?.id);
2114
2253
  const selected = answers.find((item) => item.id === selectedId) ?? answers[0];
2115
2254
  const panelId = useId();
2116
- return (_jsxs("div", { ...stylex.props(styles.judgeContext), children: [_jsx("p", { ...stylex.props(styles.judgeContextNote), children: "Only these fields, chosen by the test, were sent to the judge." }), answers.length ? (_jsxs("section", { "aria-label": "Agent answers", ...stylex.props(styles.judgeContextGroup), children: [_jsx("h5", { ...stylex.props(styles.judgeContextGroupHeading), children: "Agent answers" }), _jsx("div", { role: "tablist", "aria-label": "Agent answers included", ...stylex.props(styles.judgeContextTabs), children: answers.map((answer, index) => (_jsx("button", { type: "button", role: "tab", "aria-selected": answer.id === selected?.id, "aria-controls": panelId, ...stylex.props(styles.buttonReset, styles.judgeContextTab, answer.id === selected?.id && styles.judgeContextTabActive), onClick: () => setSelectedId(answer.id), onKeyDown: (event) => selectContextWithKeyboard({ event, answers, index, select: setSelectedId }), children: answer.tabLabel }, answer.id))) }), selected ? (_jsx("div", { id: panelId, role: "tabpanel", "aria-label": `Agent response from ${selected.tabLabel}`, ...stylex.props(styles.judgeContextAnswer), children: _jsx("div", { ...stylex.props(styles.judgeContextValue), children: _jsx("div", { className: "message-markdown", children: _jsx(Markdown, { children: normalizeTranscriptMarkdown(selected.value) }) }) }) })) : null] })) : null, supplied.length ? (_jsxs("section", { "aria-label": "Additional context", ...stylex.props(styles.judgeContextGroup), children: [_jsx("h5", { ...stylex.props(styles.judgeContextGroupHeading), children: "Additional context" }), _jsx("dl", { ...stylex.props(styles.judgeContextList), children: supplied.map((item) => (_jsxs("div", { ...stylex.props(styles.judgeContextItem), children: [_jsx("dt", { ...stylex.props(styles.judgeContextLabel), children: item.label }), _jsx("dd", { ...stylex.props(styles.judgeContextValue), children: item.value })] }, item.label))) })] })) : null] }));
2255
+ return (_jsxs("div", { ...stylex.props(styles.judgeContext), children: [_jsx("p", { ...stylex.props(styles.judgeContextNote), children: "Only these fields, chosen by the test, were sent to the judge." }), answers.length ? (_jsxs("section", { "aria-label": "Agent answers", ...stylex.props(styles.judgeContextGroup), children: [_jsx("h5", { ...stylex.props(styles.judgeContextGroupHeading), children: "Agent answers" }), _jsx("div", { role: "tablist", "aria-label": "Agent answers included", ...stylex.props(styles.judgeContextTabs), children: answers.map((answer, index) => (_jsx("button", { type: "button", role: "tab", "aria-selected": answer.id === selected?.id, "aria-controls": panelId, ...stylex.props(styles.buttonReset, styles.judgeContextTab, answer.id === selected?.id && styles.judgeContextTabActive), onClick: () => setSelectedId(answer.id), onKeyDown: (event) => selectContextWithKeyboard({ event, answers, index, select: setSelectedId }), children: answer.tabLabel }, answer.id))) }), selected ? (_jsx("div", { id: panelId, role: "tabpanel", "aria-label": `Agent response from ${selected.tabLabel}`, ...stylex.props(styles.judgeContextAnswer), children: _jsx("div", { ...stylex.props(styles.judgeContextValue), children: _jsx("div", { className: "message-markdown", children: _jsx(Markdown, { children: normalizeTranscriptMarkdown(selected.value) }) }) }) })) : null] })) : null, supplied.length ? (_jsxs("section", { "aria-label": "Additional context", ...stylex.props(styles.judgeContextGroup), children: [_jsx("h5", { ...stylex.props(styles.judgeContextGroupHeading), children: "Additional context" }), _jsx("div", { ...stylex.props(styles.judgeContextList), children: supplied.map((item) => (_jsx(JudgeContextField, { item: item }, item.label))) })] })) : null] }));
2256
+ }
2257
+ /** One supplied judge input. A short value reads inline; anything larger folds behind its size. */
2258
+ function JudgeContextField({ item }) {
2259
+ if (isInlineValue(item.rawValue))
2260
+ return (_jsxs("div", { ...stylex.props(styles.judgeContextItem, styles.judgeContextFieldSummary), children: [_jsx("span", { ...stylex.props(styles.judgeContextLabel), children: item.label }), _jsx("span", { ...stylex.props(styles.judgeContextValue), children: item.value })] }));
2261
+ return (_jsxs("details", { "data-disclosure": true, ...stylex.props(styles.judgeContextItem), children: [_jsxs("summary", { ...stylex.props(styles.judgeContextFieldSummary), children: [_jsx("span", { ...stylex.props(styles.judgeContextLabel), children: item.label }), _jsx("span", { ...stylex.props(styles.judgeContextShape), children: describeShape(item.rawValue) })] }), _jsx(JudgeContextFieldValue, { item: item })] }));
2262
+ }
2263
+ function JudgeContextFieldValue({ item }) {
2264
+ const tools = judgeInputToolCalls(item.rawValue);
2265
+ if (tools)
2266
+ return (_jsx("div", { ...stylex.props(styles.judgeContextFieldBody), children: tools.map((tool, index) => (_jsx(ToolActivity, { tool: tool }, tool.seq ?? index))) }));
2267
+ if (isStringList(item.rawValue))
2268
+ return (_jsx("ul", { ...stylex.props(styles.judgeContextFieldBody, styles.judgeContextStringList), children: item.rawValue.map((value, index) => (_jsx("li", { children: value }, `${index}:${value}`))) }));
2269
+ return (_jsx("div", { ...stylex.props(styles.judgeContextFieldBody, styles.judgeContextValue), children: item.value }));
2270
+ }
2271
+ /** A judge input that is a list of agent tool calls reads like the transcript, not as JSON. */
2272
+ function judgeInputToolCalls(value) {
2273
+ if (!Array.isArray(value) || value.length === 0)
2274
+ return undefined;
2275
+ const tools = toolCallsFromOperation({ trace: { toolCalls: value } });
2276
+ return tools.length === value.length ? tools : undefined;
2277
+ }
2278
+ const INLINE_VALUE_LENGTH = 120;
2279
+ function isInlineValue(value) {
2280
+ if (typeof value === "string")
2281
+ return value.length <= INLINE_VALUE_LENGTH && !value.includes("\n");
2282
+ return value === null || value === undefined || typeof value !== "object";
2283
+ }
2284
+ function isStringList(value) {
2285
+ return (Array.isArray(value) && value.length > 0 && value.every((item) => typeof item === "string"));
2117
2286
  }
2118
2287
  function judgeContextGroups(context, operations) {
2119
2288
  const candidates = operations