feat(desktop): improve agent activity header ui (#3321)

**Category:** improvement
**User Impact:** Activity feeds now clearly identify the agent and keep
update recency visible even when channel names are long.

**Problem:** The activity header led with a generic label, making it
hard to tell which agent was in view, while channel scope and recency
competed for limited horizontal space. Long channel names could hide the
update timestamp entirely.

**Solution:** Lead with the resolved agent avatar and name, then place
mode and scope in a truncating metadata region with recency pinned at
the right edge. This preserves the compact two-line header while keeping
the most important identity and freshness signals legible.

<details>
<summary>File changes</summary>

**desktop/src/features/channels/ui/AgentSessionThreadPanel.tsx**
Reorganizes the activity header around the agent identity, reuses the
existing resolved profile avatar and label helpers, and separates scope
truncation from the always-visible recency label.

**desktop/tests/e2e/activity-scope-label-screenshots.spec.ts**
Expands activity-header coverage across channel-scoped, all-channel,
raw, long-name, and narrow layouts, including measured truncation and
recency visibility.

</details>

## Reproduction steps

1. Open an agent's activity feed from a channel.
2. Confirm the agent avatar and name lead the header.
3. Open a feed scoped to a channel with a long name and resize the panel
narrowly.
4. Confirm the mode and channel scope truncate while the recency label
remains visible at the right edge.
5. Toggle Raw mode and open an all-channel feed to confirm the same
hierarchy and truncation behavior.

## Screenshots

| Long channel | Narrow layout |
|---|---|
| <img width="380" height="671" alt="image"
src="https://github.com/user-attachments/assets/19682aac-9938-41ed-8c27-fe59bf8b7535"
/> | <img width="371" height="771" alt="image"
src="https://github.com/user-attachments/assets/92a6fc05-c9ba-4c11-a18c-22b5225d8b9a"
/> |

| Raw mode | All channels |
|---|---|
| <img width="380" height="671" alt="image"
src="https://github.com/user-attachments/assets/c8135600-e3c9-4644-8350-fa5f6b2d3aaa"
/> | <img width="380" height="671" alt="image"
src="https://github.com/user-attachments/assets/bac73a6a-4ed5-42d6-98cc-039a75c48ef3"
/> |

---------

Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
Co-authored-by: npub1223z34hd7vtwc6qj4s7flsxkj644nlre2nthu7lrrmkumhu3xddsrx9r6w <52a228d6edf316ec6812ac3c9fc0d696ab59fc7954d77e7be31eedcddf91335b@buzz.block.builderlab.xyz>
This commit is contained in:
Taylor Ho
2026-07-30 12:34:35 -07:00
committed by GitHub
co-authored by npub1223z34hd7vtwc6qj4s7flsxkj644nlre2nthu7lrrmkumhu3xddsrx9r6w
parent bf139e8d0b
commit 4d47aa8345
2 changed files with 112 additions and 18 deletions
@@ -35,10 +35,12 @@ import {
AuxiliaryPanelHeader,
AuxiliaryPanelHeaderActions,
AuxiliaryPanelHeaderGroup,
AuxiliaryPanelHeaderTitleBlock,
} from "@/shared/layout/AuxiliaryPanel";
import { Button } from "@/shared/ui/button";
import type { UserProfileLookup } from "@/features/profile/lib/identity";
import { resolveUserLabel } from "@/features/profile/lib/identity";
import { ProfileAvatar } from "@/features/profile/ui/ProfileAvatar";
import { normalizePubkey } from "@/shared/lib/pubkey";
import {
DropdownMenu,
DropdownMenuContent,
@@ -237,6 +239,15 @@ export function AgentSessionThreadPanel({
? `#${scopeChannelName}`
: "1 channel"
: "All channels";
const agentProfile = profiles?.[normalizePubkey(agent.pubkey)] ?? null;
const agentLabel = resolveUserLabel({
pubkey: agent.pubkey,
fallbackName: agent.name,
profiles,
preferResolvedSelfLabel: true,
});
const viewLabel = showRawFeed ? "Raw ACP activity" : "Activity";
const headerScopeLabel = `${viewLabel} · ${scopeLabel}`;
const animateActivity = useTranscriptAnimationEnabled();
const showTimestamps = useTranscriptTimestampsEnabled();
async function handleInterruptTurn() {
@@ -417,19 +428,39 @@ export function AgentSessionThreadPanel({
backButtonTestId="agent-session-back"
onBack={onBack}
>
<AuxiliaryPanelHeaderTitleBlock
subtitle={lastUpdatedLabel}
subtitleTitle={lastUpdatedTitle}
title={showRawFeed ? "Raw ACP Activity" : "Activity"}
<ProfileAvatar
avatarUrl={agentProfile?.avatarUrl ?? null}
className="size-9"
label={agentLabel}
testId="agent-session-agent-avatar"
/>
{/* Scope label: makes channel-targeted vs all-channels state obvious
(an all-channels pane can look "wrong" without it). */}
<span
className="min-w-0 shrink truncate text-xs text-muted-foreground"
data-testid="agent-session-scope-label"
>
{scopeLabel}
</span>
<div className="min-w-0 flex-1">
<h2
className="truncate text-sm font-semibold leading-5"
data-testid="agent-session-agent-name"
title={agentLabel}
>
{agentLabel}
</h2>
<div className="flex min-w-0 items-center gap-1 text-xs text-muted-foreground">
<p
className="min-w-0 flex-1 truncate"
data-testid="agent-session-scope-label"
>
{headerScopeLabel}
</p>
<span aria-hidden="true" className="shrink-0">
·
</span>
<span
className="shrink-0"
data-testid="agent-session-recency-label"
title={lastUpdatedTitle}
>
{lastUpdatedLabel}
</span>
</div>
</div>
</AuxiliaryPanelHeaderGroup>
{agentHeaderActions}
</>