From fd6bdb1f11598a3c2654e1c81083b959227d079c Mon Sep 17 00:00:00 2001 From: alowpoly Date: Sun, 26 Jul 2026 16:33:24 -0300 Subject: [PATCH 01/17] feat: add Agent Monitor oven --- bin/burnlist.mjs | 4 + dashboard/src/App.tsx | 13 +- .../components/AgentMonitor/AgentMonitor.tsx | 60 +++ .../components/AgentMonitor/agent-monitor.css | 313 ++++++++++++++ .../src/components/AgentMonitor/index.ts | 1 + .../src/components/AppHeader/AppHeader.tsx | 12 +- .../ChecklistDashboard/ChecklistDashboard.tsx | 4 +- .../CustomOvenView/CustomOvenView.css | 185 +++++++++ .../CustomOvenView/CustomOvenView.tsx | 32 +- .../custom-oven-render.test.mjs | 95 ++++- .../differential-testing.css | 3 + .../StreamingDiff/streaming-diff.css | 20 +- dashboard/src/components/index.ts | 1 + dashboard/src/hooks/index.ts | 1 + dashboard/src/hooks/useAgentMonitor.ts | 85 ++++ dashboard/src/index.css | 5 + dashboard/src/lib/agent-monitor.mjs | 100 +++++ dashboard/src/lib/agent-monitor.test.mjs | 80 ++++ .../lib/canonical-oven-architecture.test.mjs | 1 + dashboard/src/lib/hrefs.ts | 9 +- dashboard/src/lib/index.ts | 5 +- dashboard/src/lib/route-model.mjs | 7 +- dashboard/src/lib/route-model.test.mjs | 4 + dashboard/src/lib/types.ts | 17 +- .../AgentMonitorActivityChart.test.ts | 74 ++++ .../AgentMonitorActivityChart.tsx | 212 ++++++++++ .../oven/AgentMonitorActivityChart/index.ts | 2 + .../AgentMonitorEventCard.test.ts | 117 ++++++ .../AgentMonitorEventCard.tsx | 189 +++++++++ .../src/oven/AgentMonitorEventCard/index.ts | 1 + dashboard/src/oven/FeedList/FeedList.test.ts | 47 ++- dashboard/src/oven/FeedList/FeedList.tsx | 60 ++- dashboard/src/oven/FeedList/feed-list.css | 50 +++ dashboard/src/oven/KpiItem/KpiItem.test.ts | 12 +- dashboard/src/oven/KpiItem/KpiItem.tsx | 6 +- dashboard/src/oven/OvenView/registries.ts | 8 + .../src/oven/PaginationBar/PaginationBar.tsx | 8 +- .../oven/SectionHeader/SectionHeader.test.ts | 4 + .../src/oven/SectionHeader/SectionHeader.tsx | 4 +- dashboard/src/oven/index.ts | 2 + dashboard/src/oven/runtime/OvenNode.test.ts | 44 +- dashboard/src/oven/runtime/OvenNode.tsx | 34 +- dashboard/src/oven/runtime/OvenRuntime.tsx | 20 +- .../agent-monitor-oven-render.test.mjs | 137 +++++++ .../oven/runtime/collection-pipeline.test.ts | 19 + .../src/oven/runtime/control-adapters.tsx | 1 + .../runtime/differential-testing-fields.tsx | 5 +- .../oven/runtime/log-table-adapter.test.ts | 10 +- .../src/oven/runtime/log-table-adapter.ts | 6 +- .../src/oven/runtime/lower-oven-ir.test.ts | 13 + dashboard/src/oven/runtime/lower-oven-ir.ts | 21 + .../oven/runtime/oven-live-data-304.test.mjs | 2 +- .../src/oven/runtime/oven-live-data.test.ts | 2 +- dashboard/src/oven/runtime/oven-live-data.ts | 2 +- .../src/oven/runtime/oven-reducer.test.ts | 24 ++ dashboard/src/oven/runtime/oven-reducer.ts | 15 +- .../oven-runtime-controlled-payload.test.ts | 11 + .../src/oven/runtime/oven-runtime-state.css | 98 ++++- dashboard/src/oven/runtime/oven-selectors.ts | 4 +- .../oven/runtime/predicate-sort-registry.ts | 8 + ovens/agent-monitor/agent-monitor.oven | 68 ++++ .../engine/agent-monitor-data-contract.mjs | 197 +++++++++ .../engine/agent-monitor-event.mjs | 301 ++++++++++++++ .../engine/agent-monitor-event.test.mjs | 283 +++++++++++++ .../engine/agent-monitor-feed.mjs | 320 +++++++++++++++ .../engine/agent-monitor-handler.mjs | 192 +++++++++ .../engine/agent-monitor-handler.test.mjs | 159 ++++++++ .../engine/agent-monitor-patch.mjs | 133 ++++++ .../engine/agent-monitor-patch.test.mjs | 91 +++++ .../engine/agent-monitor-producer.mjs | 382 ++++++++++++++++++ .../engine/agent-monitor-producer.test.mjs | 241 +++++++++++ .../engine/agent-monitor-projection.mjs | 274 +++++++++++++ .../engine/agent-monitor-replay.mjs | 41 ++ .../engine/agent-monitor-reproject.mjs | 45 +++ .../engine/agent-monitor-reproject.test.mjs | 40 ++ ovens/agent-monitor/instructions.md | 56 +++ ovens/catalog.json | 13 +- scripts/audit-oven-event-bus-architecture.mjs | 2 + scripts/verify-test-files.mjs | 6 + scripts/verify.mjs | 1 + src/cli/agent-monitor-cli.mjs | 239 +++++++++++ src/cli/agent-monitor-cli.test.mjs | 62 +++ src/cli/oven-cli.test.mjs | 2 + src/ovens/built-in-handlers.mjs | 1 + src/ovens/dsl/oven-grammar.mjs | 22 +- src/ovens/dsl/oven-validate.mjs | 6 +- src/ovens/dsl/oven-validate.test.mjs | 15 + src/ovens/official-oven-catalog.test.mjs | 3 +- src/ovens/oven-data-validate.mjs | 7 +- src/ovens/oven-data-validate.test.mjs | 5 +- src/ovens/oven-registry.test.mjs | 4 + src/server/burnlist-dashboard-server.mjs | 4 +- .../canonical-oven-architecture.test.mjs | 1 + src/server/dashboard-routes.test.mjs | 4 +- 94 files changed, 5415 insertions(+), 134 deletions(-) create mode 100644 dashboard/src/components/AgentMonitor/AgentMonitor.tsx create mode 100644 dashboard/src/components/AgentMonitor/agent-monitor.css create mode 100644 dashboard/src/components/AgentMonitor/index.ts create mode 100644 dashboard/src/components/CustomOvenView/CustomOvenView.css create mode 100644 dashboard/src/hooks/useAgentMonitor.ts create mode 100644 dashboard/src/lib/agent-monitor.mjs create mode 100644 dashboard/src/lib/agent-monitor.test.mjs create mode 100644 dashboard/src/oven/AgentMonitorActivityChart/AgentMonitorActivityChart.test.ts create mode 100644 dashboard/src/oven/AgentMonitorActivityChart/AgentMonitorActivityChart.tsx create mode 100644 dashboard/src/oven/AgentMonitorActivityChart/index.ts create mode 100644 dashboard/src/oven/AgentMonitorEventCard/AgentMonitorEventCard.test.ts create mode 100644 dashboard/src/oven/AgentMonitorEventCard/AgentMonitorEventCard.tsx create mode 100644 dashboard/src/oven/AgentMonitorEventCard/index.ts create mode 100644 dashboard/src/oven/FeedList/feed-list.css create mode 100644 dashboard/src/oven/runtime/agent-monitor-oven-render.test.mjs create mode 100644 ovens/agent-monitor/agent-monitor.oven create mode 100644 ovens/agent-monitor/engine/agent-monitor-data-contract.mjs create mode 100644 ovens/agent-monitor/engine/agent-monitor-event.mjs create mode 100644 ovens/agent-monitor/engine/agent-monitor-event.test.mjs create mode 100644 ovens/agent-monitor/engine/agent-monitor-feed.mjs create mode 100644 ovens/agent-monitor/engine/agent-monitor-handler.mjs create mode 100644 ovens/agent-monitor/engine/agent-monitor-handler.test.mjs create mode 100644 ovens/agent-monitor/engine/agent-monitor-patch.mjs create mode 100644 ovens/agent-monitor/engine/agent-monitor-patch.test.mjs create mode 100644 ovens/agent-monitor/engine/agent-monitor-producer.mjs create mode 100644 ovens/agent-monitor/engine/agent-monitor-producer.test.mjs create mode 100644 ovens/agent-monitor/engine/agent-monitor-projection.mjs create mode 100644 ovens/agent-monitor/engine/agent-monitor-replay.mjs create mode 100644 ovens/agent-monitor/engine/agent-monitor-reproject.mjs create mode 100644 ovens/agent-monitor/engine/agent-monitor-reproject.test.mjs create mode 100644 ovens/agent-monitor/instructions.md create mode 100644 src/cli/agent-monitor-cli.mjs create mode 100644 src/cli/agent-monitor-cli.test.mjs diff --git a/bin/burnlist.mjs b/bin/burnlist.mjs index dd34550b..0a13f6f1 100755 --- a/bin/burnlist.mjs +++ b/bin/burnlist.mjs @@ -10,6 +10,7 @@ const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), ".."); const knownSubcommands = new Set([ "install", "uninstall", + "agent-monitor", "differential-testing", "streaming-diff", "hooks", @@ -119,6 +120,7 @@ Usage: burnlist differential-testing validate-bundle burnlist differential-testing schema burnlist differential-testing sdk + burnlist agent-monitor ... burnlist streaming-diff ... burnlist hooks [install|uninstall|status] [--agent codex,claude] [--untracked] (bare defaults to status) burnlist oven ... @@ -179,6 +181,8 @@ if (args[0] !== "oven" && (args.includes("--version") || args.includes("-v"))) { if (args[0] === "oven") { await import("../src/cli/oven-cli.mjs"); +} else if (args[0] === "agent-monitor") { + await import("../src/cli/agent-monitor-cli.mjs"); } else if (args[0] === "streaming-diff") { await import("../src/cli/streaming-diff-cli.mjs"); } else if (args[0] === "hooks") { diff --git a/dashboard/src/App.tsx b/dashboard/src/App.tsx index 5a90ee4e..54659ca8 100644 --- a/dashboard/src/App.tsx +++ b/dashboard/src/App.tsx @@ -1,8 +1,8 @@ import { useMemo, useState } from "react"; import { ListChecks } from "lucide-react"; -import { AppHeader, BurnlistTable, ChecklistOvenView, CustomOvenView, DashboardError, DifferentialTestingOvenPage, EmptyState, FILTERS, Filters, LensSwitcher, ModelLabPage, NewOvenPage, OvenCatalog, OvenDefinition, OvenExplainer, PerformanceTracingOvenPage, ProjectGroup, RunBurnPage, StreamingDiff, VisualParityPage } from "@components"; +import { AgentMonitor, AppHeader, BurnlistTable, ChecklistOvenView, CustomOvenView, DashboardError, DifferentialTestingOvenPage, EmptyState, FILTERS, Filters, LensSwitcher, ModelLabPage, NewOvenPage, OvenCatalog, OvenDefinition, OvenExplainer, PerformanceTracingOvenPage, ProjectGroup, RunBurnPage, StreamingDiff, VisualParityPage } from "@components"; import { useDashboardData } from "@hooks"; -import { checklistOvenRepoKey, currentSection, filterFromUrl, ovenRepoKey, selectedBurnlist } from "@lib"; +import { checklistOvenRepoKey, currentSection, customOvenSelection, filterFromUrl, ovenRepoKey, selectedBurnlist } from "@lib"; import type { Filter } from "@lib"; import { Button } from "@layout"; @@ -10,8 +10,9 @@ export function App() { const section = currentSection(); const selected = useMemo(selectedBurnlist, [window.location.pathname, window.location.search]); const repoKey = ovenRepoKey(); + const customOven = section === "custom-oven" ? customOvenSelection() : null; const [filter, setFilter] = useState(() => filterFromUrl(FILTERS)); - const dashboardSection = ["landing", "burnlist", "streaming-diff"].includes(section) || (section === "custom-oven" && selected) ? "burnlists" : section; + const dashboardSection = ["landing", "burnlist", "agent-monitor", "streaming-diff"].includes(section) || (section === "custom-oven" && selected) ? "burnlists" : section; const { projects, progress, error, loading, stale } = useDashboardData({ section: dashboardSection, selected }); const checklistRepoKey = checklistOvenRepoKey(progress, selected); const visibleBurnlistCount = projects.reduce((total, project) => total + project.entries.filter((entry) => filter === "all" || entry.status === filter).length, 0); @@ -26,13 +27,13 @@ export function App() { setFilter(nextFilter); }; - const fullLayout = ["differential-testing", "model-lab", "performance-tracing", "streaming-diff", "visual-parity", "custom-oven"].includes(section) || selected; + const fullLayout = ["agent-monitor", "differential-testing", "model-lab", "performance-tracing", "streaming-diff", "visual-parity", "custom-oven"].includes(section) || selected; return (
- +
- {section === "differential-testing" ? {(ir) => } : section === "model-lab" ? {(ir) => } : section === "performance-tracing" ? {(ir) => } : section === "streaming-diff" ? {(ir) => } : section === "visual-parity" ? {(ir) => } : section === "custom-oven" ? : section === "new-oven" ? : section === "run-burn" ? : section === "ovens-catalog" ? : section === "oven-explainer" ? : selected ? ( + {section === "agent-monitor" ? {(ir) => } : section === "differential-testing" ? {(ir) => } : section === "model-lab" ? {(ir) => } : section === "performance-tracing" ? {(ir) => } : section === "streaming-diff" ? {(ir) => } : section === "visual-parity" ? {(ir) => } : section === "custom-oven" ? : section === "new-oven" ? : section === "run-burn" ? : section === "ovens-catalog" ? : section === "oven-explainer" ? : selected ? ( loading && !progress ? : progress ? ( <>{error && }{(ir) => } ) : error ? : diff --git a/dashboard/src/components/AgentMonitor/AgentMonitor.tsx b/dashboard/src/components/AgentMonitor/AgentMonitor.tsx new file mode 100644 index 00000000..85396c2c --- /dev/null +++ b/dashboard/src/components/AgentMonitor/AgentMonitor.tsx @@ -0,0 +1,60 @@ +import { useEffect, useMemo } from "react"; +import { useAgentMonitorFeeds, useAgentMonitorSnapshot, type ResolvedOvenIr } from "@hooks"; +import { FeedList } from "@oven"; +import { + agentMonitorAutoOpenHref, + agentMonitorRepositories, + agentMonitorSelection, + agentMonitorSnapshotNotice, + ovenRepoKey, +} from "@lib"; +import type { Project } from "@lib"; +import { OvenRuntime } from "@/oven/runtime/OvenRuntime"; +import "./agent-monitor.css"; + +export function AgentMonitor({ + ir, + projects, + projectsLoading, +}: { + ir: ResolvedOvenIr; + projects: Project[]; + projectsLoading: boolean; +}) { + const selection = agentMonitorSelection(); + const repoKey = ovenRepoKey(); + const repositories = useMemo( + () => repoKey ? [{ repoKey, label: repoKey }] : agentMonitorRepositories(projects), + [projects, repoKey], + ); + const feeds = useAgentMonitorFeeds(repositories, projectsLoading, Boolean(selection)); + const snapshot = useAgentMonitorSnapshot(selection); + const notice = agentMonitorSnapshotNotice(snapshot); + const autoOpenHref = agentMonitorAutoOpenHref(feeds.feeds); + + useEffect(() => { + if (autoOpenHref) window.location.replace(autoOpenHref); + }, [autoOpenHref]); + + if (!selection) { + return 1} + title="Agent Monitor" + />; + } + + const backHref = `/r/${encodeURIComponent(selection.repoKey)}/o/agent-monitor`; + return
+
+ Recent threads +

Agent Monitor

+

Thread {selection.session}

+
+ {notice &&

{notice.text}

} + {snapshot.data && } +
; +} diff --git a/dashboard/src/components/AgentMonitor/agent-monitor.css b/dashboard/src/components/AgentMonitor/agent-monitor.css new file mode 100644 index 00000000..c76ace01 --- /dev/null +++ b/dashboard/src/components/AgentMonitor/agent-monitor.css @@ -0,0 +1,313 @@ +.agent-monitor-selected { + width: min(calc(100% - 32px), 1120px); + margin: 0 auto; + padding: 24px 0 40px; +} + +.agent-monitor-heading { margin: 0 0 18px; } +.agent-monitor-heading h1 { margin: 0; font: 400 24px/1.2 var(--dashboard-title-font); } +.agent-monitor-heading p { margin: 6px 0 0; color: var(--muted-foreground); overflow-wrap: anywhere; } +.agent-monitor-back { display: inline-block; margin-bottom: 12px; color: var(--primary); font-size: 13px; } +.agent-monitor-back:hover { text-decoration: underline; text-underline-offset: 4px; } + +.agent-monitor-message { + margin: 0 0 12px; + padding: 12px 16px; + border: 1px solid var(--line); + border-radius: var(--radius); + background: var(--panel); + color: var(--muted-foreground); +} + +.agent-monitor-message.is-error { border-color: rgba(239, 68, 68, .35); color: var(--destructive-foreground); } + +.agent-monitor-view { + display: grid; + min-width: 0; + gap: 14px; +} + +.agent-monitor-view .checklist-kpi-strip { + display: grid; + width: 100%; + height: auto; + min-height: 0; + grid-template-columns: minmax(240px, 1.4fr) minmax(190px, 1.1fr) repeat(3, minmax(110px, .75fr)); + gap: 8px; + padding: 0; + overflow: visible; + border: 0; + background: transparent; +} + +.agent-monitor-view .driving-parity-kpi-item { + min-height: 78px; + padding: 14px 16px; + border: 1px solid var(--line); + border-radius: 8px; + background: var(--panel); +} + +.agent-monitor-view .driving-parity-kpi-item:first-child { border-left: 1px solid var(--line); } +.agent-monitor-view .driving-parity-kpi-heading { + color: var(--muted); + font: 400 12px/1.2 var(--dashboard-title-font); +} +.agent-monitor-view .driving-parity-kpi-ratio { + overflow: hidden; + color: var(--foreground); + font-size: 18px; + line-height: 1.3; + text-overflow: ellipsis; + white-space: nowrap; +} + +.agent-monitor-health [data-slot="alert"] { + min-height: 64px; + justify-content: center; +} + +.agent-monitor-activity { + min-width: 0; + padding: 16px; + border: 1px solid var(--line); + border-radius: 8px; + background: var(--panel); +} + +.agent-monitor-activity-heading { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 16px; +} + +.agent-monitor-activity-heading h2 { + margin: 0; + color: var(--foreground); + font: 400 18px/1.25 var(--dashboard-title-font); +} + +.agent-monitor-activity-heading p, +.agent-monitor-activity-empty { + margin: 4px 0 0; + color: var(--muted); + font-size: 12px; +} + +.agent-monitor-activity-legend { + display: flex; + flex-wrap: wrap; + justify-content: flex-end; + gap: 7px 12px; + margin: 1px 0 0; + padding: 0; + color: var(--muted-foreground); + font-size: 11px; + list-style: none; +} + +.agent-monitor-activity-legend li { + display: inline-flex; + align-items: center; + gap: 5px; + white-space: nowrap; +} + +.agent-monitor-activity-legend span { + width: 7px; + height: 7px; + border-radius: 1px; + background: currentColor; +} + +.agent-monitor-activity-legend [data-category="command"] { color: var(--primary); } +.agent-monitor-activity-legend [data-category="diff"] { color: var(--status-green); } +.agent-monitor-activity-legend [data-category="message"] { color: var(--amber); } +.agent-monitor-activity-legend [data-category="tool"] { color: var(--foreground); } +.agent-monitor-activity-legend [data-category="lifecycle"] { color: var(--muted-foreground); } +.agent-monitor-activity-legend [data-category="result"] { color: var(--destructive); } + +.agent-monitor-activity-chart { + display: block; + width: 100%; + height: 176px; + margin-top: 10px; +} + +.agent-monitor-activity-grid { + stroke: var(--line); + stroke-width: 1; + vector-effect: non-scaling-stroke; +} + +.agent-monitor-activity-axis { + fill: var(--muted); + font: 11px/1 var(--dashboard-font); +} + +.agent-monitor-activity-mark[data-category="command"] { fill: var(--primary); } +.agent-monitor-activity-mark[data-category="diff"] { fill: var(--status-green); } +.agent-monitor-activity-mark[data-category="message"] { fill: var(--amber); } +.agent-monitor-activity-mark[data-category="tool"] { fill: var(--foreground); } +.agent-monitor-activity-mark[data-category="lifecycle"] { fill: var(--muted-foreground); } +.agent-monitor-activity-mark[data-category="result"] { fill: var(--destructive); } + +.agent-monitor-activity-signal[data-signal="failure"] { fill: var(--destructive); } +.agent-monitor-activity-signal[data-signal="message"] { fill: var(--amber); } +.agent-monitor-activity-signal[data-signal="lifecycle"] { + stroke: var(--muted-foreground); + stroke-width: 2; + vector-effect: non-scaling-stroke; +} + +.agent-monitor-events { + display: grid; + min-width: 0; + gap: 8px; + margin-top: 4px; +} + +.agent-monitor-events > h2 { + margin: 4px 0 2px; + color: var(--foreground); + font: 400 20px/1.25 var(--dashboard-title-font); +} + +.agent-monitor-events .field-list-count { + color: var(--muted); + font: 400 13px/1 var(--dashboard-font); +} + +#agent-monitor-event-filter { + display: flex; + flex-wrap: wrap; + align-items: baseline; + gap: 7px 14px; + color: var(--muted); + font: 14px/1.2 var(--dashboard-title-font); +} + +#agent-monitor-event-filter button { + appearance: none; + width: auto; + height: auto; + padding: 0 0 2px; + border: 0; + border-bottom: 1px solid transparent; + border-radius: 0; + background: transparent; + box-shadow: none; + color: var(--muted); + font: inherit; + opacity: .5; +} + +#agent-monitor-event-filter button[aria-pressed="true"] { + border-bottom-color: currentColor; + color: var(--foreground); + opacity: 1; +} + +#agent-monitor-event-filter button:not(:disabled):hover { + border-color: transparent; + background: transparent; + color: var(--foreground); +} + +.agent-monitor-filter-empty { + color: var(--muted); + font-size: 13px; +} + +.agent-monitor-events:has(.agent-monitor-event) .agent-monitor-filter-empty { + display: none; +} + +.agent-monitor-event, +.agent-monitor-event [data-slot="alert-title"], +.agent-monitor-event [data-slot="alert-description"] { + min-width: 0; + overflow-wrap: anywhere; +} + +.agent-monitor-event-type { color: var(--muted-foreground); } +.agent-monitor-event[data-category="command"] .agent-monitor-event-type { color: var(--primary); } +.agent-monitor-event[data-category="diff"] .agent-monitor-event-type { color: var(--status-green); } +.agent-monitor-event[data-category="message"] .agent-monitor-event-type { color: var(--amber); } +.agent-monitor-event[data-category="result"] .agent-monitor-event-type { color: var(--destructive); } +.agent-monitor-event[data-category="tool"] .agent-monitor-event-type { color: var(--foreground); } + +.agent-monitor-patch { + margin-top: 12px; + border-top: 1px solid var(--line); + padding-top: 10px; +} + +.agent-monitor-patch summary { + width: fit-content; + color: var(--foreground); + cursor: pointer; + font: 12px/1.35 var(--dashboard-font); +} + +.agent-monitor-patch pre { + max-height: 360px; + margin: 10px 0 0; + padding: 12px; + overflow: auto; + border: 1px solid var(--line); + border-radius: 6px; + background: rgba(0, 0, 0, .28); + font: 12px/1.45 var(--dashboard-font); + tab-size: 2; + white-space: pre; +} + +.agent-monitor-patch code { font: inherit; } +.agent-monitor-patch code > span { + display: block; + min-height: 1.45em; +} + +.agent-monitor-patch [data-kind="header"] { color: var(--muted); } +.agent-monitor-patch [data-kind="hunk"] { color: var(--primary); } +.agent-monitor-patch [data-kind="add"] { color: var(--status-green); } +.agent-monitor-patch [data-kind="remove"] { color: var(--destructive); } +.agent-monitor-patch [data-kind="context"] { color: var(--muted-foreground); } +.agent-monitor-patch > p { + margin: 8px 0 0; + color: var(--muted); + font-size: 11px; +} + +.agent-monitor-events .driving-parity-pagination { + justify-content: flex-end; + margin-top: 4px; + padding: 4px 0 0; +} + +@media (max-width: 760px) { + .agent-monitor-view .checklist-kpi-strip { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + .agent-monitor-view .driving-parity-kpi-item:first-child { + grid-column: 1 / -1; + } + .agent-monitor-activity-heading { + display: grid; + } + .agent-monitor-activity-legend { + justify-content: flex-start; + } +} + +@media (max-width: 480px) { + .agent-monitor-selected { + width: calc(100% - 20px); + padding-top: 16px; + } + .agent-monitor-view .checklist-kpi-strip { grid-template-columns: minmax(0, 1fr); } + .agent-monitor-view .driving-parity-kpi-item:first-child { grid-column: auto; } + .agent-monitor-events .driving-parity-pagination { justify-content: flex-start; } +} diff --git a/dashboard/src/components/AgentMonitor/index.ts b/dashboard/src/components/AgentMonitor/index.ts new file mode 100644 index 00000000..945bdebc --- /dev/null +++ b/dashboard/src/components/AgentMonitor/index.ts @@ -0,0 +1 @@ +export { AgentMonitor } from "./AgentMonitor"; diff --git a/dashboard/src/components/AppHeader/AppHeader.tsx b/dashboard/src/components/AppHeader/AppHeader.tsx index 0ed22637..e1ccf19f 100644 --- a/dashboard/src/components/AppHeader/AppHeader.tsx +++ b/dashboard/src/components/AppHeader/AppHeader.tsx @@ -5,14 +5,16 @@ const HEADER_LINKS = [ { href: "/ovens/new", label: "New Oven", section: "new-oven" }, ] as const; -const OVEN_SECTIONS = ["differential-testing", "model-lab", "performance-tracing", "streaming-diff", "visual-parity"]; +const OVEN_SECTIONS = ["agent-monitor", "custom-oven", "differential-testing", "model-lab", "performance-tracing", "streaming-diff", "visual-parity"]; -export function AppHeader({ detail, section }: { detail: ChecklistProgressData | null; section: string }) { - const title = section === "differential-testing" ? "Differential Testing" +export function AppHeader({ detail, ovenId, section }: { detail: ChecklistProgressData | null; ovenId?: string | null; section: string }) { + const title = section === "agent-monitor" ? "Agent Monitor" + : section === "differential-testing" ? "Differential Testing" : section === "model-lab" ? "Model Lab" : section === "performance-tracing" ? "Performance Tracing" : section === "streaming-diff" ? "Streaming Diff" - : section === "visual-parity" ? "Visual Parity" : detail?.title; + : section === "visual-parity" ? "Visual Parity" + : section === "custom-oven" ? detail?.title ?? ovenId : detail?.title; return (
@@ -20,7 +22,7 @@ export function AppHeader({ detail, section }: { detail: ChecklistProgressData | Burnlist - {title &&
{title}
} + {title &&
{title}
}