From a0f69a6feee6d1dec563ea0e385ceeac89ae9908 Mon Sep 17 00:00:00 2001 From: viettranx Date: Thu, 5 Mar 2026 14:36:13 +0700 Subject: [PATCH] enhance(ui): improve realtime event cards with richer payload rendering Split agent event cards into RunEventCard and ToolEventCard with full context rows (channel, delegation, parent agent, team task, call ID). Add channel badge and delegation ID to delegation lifecycle cards, completed task count to announce cards, task ID to task/message cards. Co-Authored-By: Claude Opus 4.6 --- .../event-sections/agent-event-cards.tsx | 114 ++++++++++++++---- .../event-sections/delegation-event-cards.tsx | 28 ++++- .../event-sections/message-event-card.tsx | 5 + .../teams/event-sections/task-event-cards.tsx | 8 ++ 4 files changed, 124 insertions(+), 31 deletions(-) diff --git a/ui/web/src/pages/teams/event-sections/agent-event-cards.tsx b/ui/web/src/pages/teams/event-sections/agent-event-cards.tsx index 65acaf66..22ad603c 100644 --- a/ui/web/src/pages/teams/event-sections/agent-event-cards.tsx +++ b/ui/web/src/pages/teams/event-sections/agent-event-cards.tsx @@ -11,44 +11,35 @@ export function AgentEventCard({ entry, resolveAgent }: Props) { const p = entry.payload as EnrichedAgentEventPayload; const subtype = p.type; - const subtypeBadgeVariant = + if (subtype === "tool.call" || subtype === "tool.result") { + return ; + } + + return ; +} + +/** run.started / run.completed / run.failed / run.retrying */ +function RunEventCard({ p, resolveAgent }: { p: EnrichedAgentEventPayload; resolveAgent: Props["resolveAgent"] }) { + const subtype = p.type; + const variant = subtype === "run.completed" ? ("success" as const) : subtype === "run.failed" ? ("destructive" as const) - : subtype === "run.started" || subtype === "run.retrying" - ? ("info" as const) - : ("secondary" as const); + : subtype === "run.retrying" + ? ("warning" as const) + : ("info" as const); return (
- + {subtype} {resolveAgent(p.agentId)} - {p.delegationId && ( - - deleg: {p.delegationId.slice(0, 8)} - - )} - {p.parentAgentId && ( - - parent: {resolveAgent(p.parentAgentId)} - - )}
- {(subtype === "tool.call" || subtype === "tool.result") && p.payload && ( -
- {p.payload.name && ( - {p.payload.name} - )} - {p.payload.is_error && ( - error - )} -
- )} + {subtype === "run.failed" && p.payload?.error && (

{p.payload.error}

@@ -56,3 +47,76 @@ export function AgentEventCard({ entry, resolveAgent }: Props) {
); } + +/** tool.call / tool.result */ +function ToolEventCard({ p, resolveAgent }: { p: EnrichedAgentEventPayload; resolveAgent: Props["resolveAgent"] }) { + const isResult = p.type === "tool.result"; + const toolName = p.payload?.name; + const isError = isResult && p.payload?.is_error; + + return ( +
+
+ + {p.type} + + {toolName && ( + {toolName} + )} + {isResult && ( + + {isError ? "error" : "ok"} + + )} + → + {resolveAgent(p.agentId)} +
+ + +
+ ); +} + +/** Shared context row: channel, delegation, parent, team task, call ID */ +function ContextRow({ + p, + resolveAgent, + showCallId, +}: { + p: EnrichedAgentEventPayload; + resolveAgent: Props["resolveAgent"]; + showCallId?: boolean; +}) { + const hasContext = p.channel || p.delegationId || p.parentAgentId || p.teamTaskId || (showCallId && p.payload?.id); + if (!hasContext) return null; + + return ( +
+ {p.channel && ( + {p.channel} + )} + {p.delegationId && ( + + )} + {p.parentAgentId && ( + + parent: {resolveAgent(p.parentAgentId)} + + )} + {p.teamTaskId && ( + + )} + {showCallId && p.payload?.id && ( + + )} +
+ ); +} + +function ShortId({ label, id }: { label: string; id: string }) { + return ( + + {label}: {id.slice(0, 8)} + + ); +} diff --git a/ui/web/src/pages/teams/event-sections/delegation-event-cards.tsx b/ui/web/src/pages/teams/event-sections/delegation-event-cards.tsx index b54e143c..d5841ee6 100644 --- a/ui/web/src/pages/teams/event-sections/delegation-event-cards.tsx +++ b/ui/web/src/pages/teams/event-sections/delegation-event-cards.tsx @@ -49,11 +49,19 @@ function DelegationLifecycleCard({ entry, resolveAgent }: Props) { {p.mode} )} + {p.channel && ( + {p.channel} + )} {p.task &&

{p.task}

}
+ {p.delegation_id && ( + + deleg: {p.delegation_id.slice(0, 8)} + + )} {p.elapsed_ms != null && p.elapsed_ms > 0 && {formatDuration(p.elapsed_ms)}} - {p.error && {p.error}} + {p.error && {p.error}}
); @@ -97,11 +105,19 @@ function DelegationAccumulatedCard({ payload: p, resolveAgent }: { payload: Dele function DelegationAnnounceCard({ payload: p, resolveAgent }: { payload: DelegationAnnouncePayload } & ResolverProp) { return (
-

- {p.source_display_name || resolveAgent(p.source_agent_key)} - {" "}announcing {p.results.length} result(s) - ({formatDuration(p.total_elapsed_ms)}) -

+
+ {p.source_display_name || resolveAgent(p.source_agent_key)} + announcing {p.results.length} result(s) + ({formatDuration(p.total_elapsed_ms)}) + {p.has_media && ( + media + )} + {p.completed_task_ids && p.completed_task_ids.length > 0 && ( + + {p.completed_task_ids.length} task(s) auto-completed + + )} +
{p.results.map((r) => (
diff --git a/ui/web/src/pages/teams/event-sections/message-event-card.tsx b/ui/web/src/pages/teams/event-sections/message-event-card.tsx index f99020df..c3bdb83d 100644 --- a/ui/web/src/pages/teams/event-sections/message-event-card.tsx +++ b/ui/web/src/pages/teams/event-sections/message-event-card.tsx @@ -27,6 +27,11 @@ export function MessageEventCard({ entry, resolveAgent }: Props) { {p.preview && (

{p.preview}

)} + {p.task_id && ( + + task: {p.task_id.slice(0, 8)} + + )}
); } diff --git a/ui/web/src/pages/teams/event-sections/task-event-cards.tsx b/ui/web/src/pages/teams/event-sections/task-event-cards.tsx index 4cea4adb..d685e269 100644 --- a/ui/web/src/pages/teams/event-sections/task-event-cards.tsx +++ b/ui/web/src/pages/teams/event-sections/task-event-cards.tsx @@ -18,8 +18,16 @@ export function TaskEventCard({ entry, resolveAgent }: Props) { {p.status} + {p.channel && ( + {p.channel} + )}
+ {p.task_id && ( + + task: {p.task_id.slice(0, 8)} + + )} {p.owner_agent_key && Owner: {owner}} {p.reason && Reason: {p.reason}}