From 2bc1dcba1784033e027d6b500760ae429e8158d6 Mon Sep 17 00:00:00 2001 From: mathuraditya724 Date: Fri, 7 Aug 2026 20:05:48 +0530 Subject: [PATCH] fix(dashboard): drop dead cost UI, make Agent runs page mobile-friendly MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cost was never real: the Flue runtime doesn't expose token usage or cost in the history the dashboard reads (confirmed against live raw `view=history` — no usage on messages, parts, or settlements), so every run showed "$-" / an empty figure. Removed the always-empty cost column and the detail-page cost chips; the tool-call and message counts already convey how much work happened. Agent runs page is now responsive: the header and search/per-page rows stack instead of colliding on a phone, and the wide 7-column table is replaced by tap-through cards below md while the full table stays on desktop. Co-authored-by: Cursor --- .../src/client/pages/container-detail.tsx | 32 +-- apps/server/src/client/pages/sessions.tsx | 223 +++++++++++------- 2 files changed, 138 insertions(+), 117 deletions(-) diff --git a/apps/server/src/client/pages/container-detail.tsx b/apps/server/src/client/pages/container-detail.tsx index dfefb78..cc78270 100644 --- a/apps/server/src/client/pages/container-detail.tsx +++ b/apps/server/src/client/pages/container-detail.tsx @@ -8,7 +8,6 @@ import { Clock, Code, Copy, - CurrencyDollar, ListBullets, PaperPlaneTilt, Robot, @@ -682,7 +681,6 @@ function SessionSidebarItem({ status, messageCount, agent, - cost, isActive, onClick, }: { @@ -690,7 +688,6 @@ function SessionSidebarItem({ status: string messageCount: number agent: string | null - cost: number isActive: boolean onClick: () => void }) { @@ -717,7 +714,6 @@ function SessionSidebarItem({ {messageCount} msg{messageCount !== 1 ? "s" : ""} - {cost > 0 && ${cost.toFixed(4)}} @@ -964,18 +960,10 @@ export default function ContainerDetailPage() { const repoName = parsed ? `${parsed.owner}/${parsed.repo}` : chatRepo const activeSummary = summarizeSession(activeSession, serverMessages) - // Summary. Cost is derived per-session with a message fallback so pending - // placeholder sessions (no cost on the session object) still report a total. - // When the messages live under a different key than the session id (pending - // placeholders), the per-session sum is 0, so fall back to every message. - const perSessionCost = sessions.reduce((sum, s) => { - const msgs = Array.isArray(messages[s.id]) ? messages[s.id] : [] - return sum + summarizeSession(s, msgs).cost - }, 0) - const totalCost = perSessionCost > 0 ? perSessionCost : summarizeSession(sessions[0], allMessages).cost const totalMessages = allMessages.length - // Tool calls are a far more meaningful "how much work happened" signal than - // cost, which the Flue runtime does not report per message (so it reads 0). + // Tool calls are the "how much work happened" signal. The Flue runtime never + // reports token usage/cost in the history we read, so we don't surface a + // cost figure at all rather than show a perpetually-empty one. const totalTools = allMessages.reduce((sum, m) => sum + (m.parts?.filter(isToolPart).length ?? 0), 0) const overallStatus = detail.status ?? @@ -1065,14 +1053,6 @@ export default function ContainerDetailPage() { {totalTools} - {/* The Flue runtime doesn't report token usage/cost, so most runs - have nothing to total — show a figure only when one is present - rather than a confusing "usage not tracked" placeholder. */} - {totalCost > 0 && ( - - ${totalCost.toFixed(4)} - - )} {observedAtIso && ( @@ -1168,7 +1148,6 @@ export default function ContainerDetailPage() { status={sessionStatus[s.id]?.type ?? "unknown"} messageCount={sessionMessages.length} agent={itemSummary.agent} - cost={itemSummary.cost} isActive={s.id === effectiveSessionId} onClick={() => { setActiveSessionId(s.id) @@ -1248,11 +1227,6 @@ export default function ContainerDetailPage() { {activeSummary.model} )} - {activeSummary.cost > 0 && ( - - ${activeSummary.cost.toFixed(4)} - - )} diff --git a/apps/server/src/client/pages/sessions.tsx b/apps/server/src/client/pages/sessions.tsx index afa20ac..553ae25 100644 --- a/apps/server/src/client/pages/sessions.tsx +++ b/apps/server/src/client/pages/sessions.tsx @@ -3,7 +3,6 @@ import { CaretLeft, CaretRight, ChatsCircle, - CurrencyDollar, MagnifyingGlass, Robot, Stack, @@ -142,7 +141,7 @@ export default function SessionsPage() { return (
-
+

Agent runs

@@ -151,7 +150,7 @@ export default function SessionsPage() { : "Recent agent conversations"}

-
+
-
-
+
+
setSearchInput(e.target.value)} - className="h-7 w-72 border border-input bg-background pl-7 pr-7 text-xs outline-none placeholder:text-muted-foreground focus:border-ring" + className="h-7 w-full border border-input bg-background pl-7 pr-7 text-xs outline-none placeholder:text-muted-foreground focus:border-ring" /> {searchInput && (
-
+
Per page: {PAGE_SIZES.map((s) => (
) : ( -
- - - - Entity - Agent - Status - - - Sessions - - - - - Msgs - - - - - Cost - - - Updated - - - - {filtered.map((session: SessionListItem) => { - const ghUrl = entityGitHubUrl(session.entityKey, "issues") - const parsed = parseEntityKey(session.entityKey) - const chatRepo = chatEntityRepo(session.entityKey) - const repoName = parsed ? `${parsed.owner}/${parsed.repo}` : chatRepo + <> + {/* Mobile: stacked cards (the wide table doesn't fit a phone). */} +
    + {filtered.map((session: SessionListItem) => { + const chatRepo = chatEntityRepo(session.entityKey) - return ( - +
-
+ )} +
+ + + {session.sessionCount} session{session.sessionCount !== 1 ? "s" : ""} + + + + {session.messageCount} msg{session.messageCount !== 1 ? "s" : ""} + + {formatTimeAgo(session.updatedAt)} +
+ + + ) + })} + + + {/* Desktop: full table. */} +
+ + + + Entity + Agent + Status + + + Sessions + + + + + Msgs + + + Updated + + + + {filtered.map((session: SessionListItem) => { + const ghUrl = entityGitHubUrl(session.entityKey, "issues") + const parsed = parseEntityKey(session.entityKey) + const chatRepo = chatEntityRepo(session.entityKey) + const repoName = parsed ? `${parsed.owner}/${parsed.repo}` : chatRepo + + return ( + navigate(`/containers/detail?key=${encodeURIComponent(session.entityKey)}`)} + > + +
+
+ {ghUrl ? {session.entityKey} : session.entityKey} + {chatRepo && ( + + Chat + + )} +
+ {(session.title || repoName) && ( +
+ {session.title && {session.title}} + {repoName && ( + + {repoName} + + )} +
+ )} +
+
+ +
+
{session.agent ?? "-"}
+ {session.model && ( +
{session.model}
+ )} +
+
+ + + + + {session.sessionCount} + + + {session.messageCount} + + + {formatTimeAgo(session.updatedAt)} + +
+ ) + })} +
+
+
+ )}