diff --git a/ui/src/components/transcript/RunTranscriptView.tsx b/ui/src/components/transcript/RunTranscriptView.tsx
index 110fa7ac..05defa14 100644
--- a/ui/src/components/transcript/RunTranscriptView.tsx
+++ b/ui/src/components/transcript/RunTranscriptView.tsx
@@ -1,14 +1,11 @@
import { useEffect, useMemo, useState, type ReactNode } from "react";
import type { TranscriptEntry } from "../../adapters";
import { MarkdownBody } from "../MarkdownBody";
-import { cn, formatTokens, relativeTime } from "../../lib/utils";
+import { cn, formatTokens } from "../../lib/utils";
import {
- Bot,
- BrainCircuit,
ChevronDown,
ChevronRight,
CircleAlert,
- Info,
TerminalSquare,
User,
Wrench,
@@ -84,12 +81,6 @@ function stripMarkdown(value: string): string {
);
}
-function formatTimestamp(ts: string): string {
- const date = new Date(ts);
- if (Number.isNaN(date.getTime())) return ts;
- return date.toLocaleTimeString("en-US", { hour12: false });
-}
-
function formatUnknown(value: unknown): string {
if (typeof value === "string") return value;
if (value === null || value === undefined) return "";
@@ -326,22 +317,10 @@ function normalizeTranscript(entries: TranscriptEntry[], streaming: boolean): Tr
}
function TranscriptDisclosure({
- icon,
- label,
- tone,
- summary,
- timestamp,
defaultOpen,
- compact,
children,
}: {
- icon: typeof BrainCircuit;
- label: string;
- tone: "thinking" | "tool";
- summary: string;
- timestamp: string;
defaultOpen: boolean;
- compact: boolean;
children: ReactNode;
}) {
const [open, setOpen] = useState(defaultOpen);
@@ -353,43 +332,20 @@ function TranscriptDisclosure({
}
}, [defaultOpen, touched]);
- const Icon = icon;
- const borderTone =
- tone === "thinking"
- ? "border-amber-500/25 bg-amber-500/[0.07]"
- : "border-cyan-500/25 bg-cyan-500/[0.07]";
- const iconTone =
- tone === "thinking"
- ? "text-amber-700 dark:text-amber-300"
- : "text-cyan-700 dark:text-cyan-300";
-
return (
-
+
- {open &&
{children}
}
+ {open &&
{children}
}
);
}
@@ -402,35 +358,16 @@ function TranscriptMessageBlock({
density: TranscriptDensity;
}) {
const isAssistant = block.role === "assistant";
- const Icon = isAssistant ? Bot : User;
- const panelTone = isAssistant
- ? "border-emerald-500/25 bg-emerald-500/[0.08]"
- : "border-violet-500/20 bg-violet-500/[0.07]";
- const iconTone = isAssistant
- ? "text-emerald-700 dark:text-emerald-300"
- : "text-violet-700 dark:text-violet-300";
const compact = density === "compact";
return (
-
-
-
-
-
-
- {isAssistant ? "Assistant" : "User"}
-
- {formatTimestamp(block.ts)}
- {block.streaming && (
-
-
-
-
-
- Streaming
-
- )}
-
+
+ {!isAssistant && (
+
+
+ User
+
+ )}
{compact ? (
{truncate(stripMarkdown(block.text), 360)}
@@ -440,6 +377,15 @@ function TranscriptMessageBlock({
{block.text}
)}
+ {block.streaming && (
+
+
+
+
+
+ Streaming
+
+ )}
);
}
@@ -451,21 +397,15 @@ function TranscriptThinkingBlock({
block: Extract
;
density: TranscriptDensity;
}) {
- const compact = density === "compact";
return (
-
-
- {block.text}
-
-
+ {block.text}
+
);
}
@@ -485,57 +425,68 @@ function TranscriptToolCard({
: "Completed";
const statusTone =
block.status === "running"
- ? "border-cyan-500/25 bg-cyan-500/10 text-cyan-700 dark:text-cyan-300"
+ ? "text-cyan-700 dark:text-cyan-300"
: block.status === "error"
- ? "border-red-500/25 bg-red-500/10 text-red-700 dark:text-red-300"
- : "border-emerald-500/25 bg-emerald-500/10 text-emerald-700 dark:text-emerald-300";
+ ? "text-red-700 dark:text-red-300"
+ : "text-emerald-700 dark:text-emerald-300";
+ const detailsClass = cn(
+ "space-y-3",
+ block.status === "error" && "rounded-xl border border-red-500/20 bg-red-500/[0.06] p-3",
+ );
return (
-
-
-
-
- {statusLabel}
-
- {block.toolUseId && (
-
- {truncate(block.toolUseId, compact ? 24 : 40)}
+
+
+
+
+
+
+ {block.name}
- )}
-
-
-
-
- Input
-
-
- {formatToolPayload(block.input) || ""}
-
+
+ {statusLabel}
+
+ {block.toolUseId && (
+
+ {truncate(block.toolUseId, compact ? 24 : 40)}
+
+ )}
-
-
- Result
-
-
- {block.result ? formatToolPayload(block.result) : "Waiting for result..."}
-
+
+ {block.status === "running"
+ ? summarizeToolInput(block.name, block.input, density)
+ : summarizeToolResult(block.result, block.isError, density)}
-
+
+
+
+
+
+ Input
+
+
+ {formatToolPayload(block.input) || ""}
+
+
+
+
+ Result
+
+
+ {block.result ? formatToolPayload(block.result) : "Waiting for result..."}
+
+
+
+
+
+
);
}
@@ -549,37 +500,34 @@ function TranscriptEventRow({
const compact = density === "compact";
const toneClasses =
block.tone === "error"
- ? "border-red-500/20 bg-red-500/[0.06] text-red-700 dark:text-red-300"
+ ? "rounded-xl border border-red-500/20 bg-red-500/[0.06] p-3 text-red-700 dark:text-red-300"
: block.tone === "warn"
- ? "border-amber-500/20 bg-amber-500/[0.06] text-amber-700 dark:text-amber-300"
+ ? "text-amber-700 dark:text-amber-300"
: block.tone === "info"
- ? "border-sky-500/20 bg-sky-500/[0.06] text-sky-700 dark:text-sky-300"
- : "border-border/70 bg-background/70 text-foreground/75";
+ ? "text-sky-700 dark:text-sky-300"
+ : "text-foreground/75";
return (
-
+
{block.tone === "error" ? (
) : block.tone === "warn" ? (
) : (
-
+
)}
{block.label}
-
- {compact ? relativeTime(block.ts) : formatTimestamp(block.ts)}
-
{block.text}
{block.detail && (
-
+
{block.detail}
)}
@@ -598,23 +546,16 @@ function RawTranscriptView({
}) {
const compact = density === "compact";
return (
-
+
{entries.map((entry, idx) => (
-
{formatTimestamp(entry.ts)}
-
+
{entry.kind}