diff --git a/desktop/src/features/channels/ui/AgentSessionThreadPanel.tsx b/desktop/src/features/channels/ui/AgentSessionThreadPanel.tsx
index a907f87245..641b81490b 100644
--- a/desktop/src/features/channels/ui/AgentSessionThreadPanel.tsx
+++ b/desktop/src/features/channels/ui/AgentSessionThreadPanel.tsx
@@ -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}
>
-
- {/* Scope label: makes channel-targeted vs all-channels state obvious
- (an all-channels pane can look "wrong" without it). */}
-
- {scopeLabel}
-
+
+
+ {agentLabel}
+
+
+
+ {headerScopeLabel}
+
+
+ ·
+
+
+ {lastUpdatedLabel}
+
+
+
{agentHeaderActions}
>
diff --git a/desktop/tests/e2e/activity-scope-label-screenshots.spec.ts b/desktop/tests/e2e/activity-scope-label-screenshots.spec.ts
index 0fee5ebf9d..4ed0a211e5 100644
--- a/desktop/tests/e2e/activity-scope-label-screenshots.spec.ts
+++ b/desktop/tests/e2e/activity-scope-label-screenshots.spec.ts
@@ -6,6 +6,8 @@ import { installMockBridge, TEST_IDENTITIES } from "../helpers/bridge";
const SHOTS = "test-results/activity-scope-label";
const AGENT_PUBKEY = TEST_IDENTITIES.tyler.pubkey;
+const LONG_AGENT_NAME =
+ "Observer Agent With An Exceptionally Long Display Name";
const AGENTS_CHANNEL_ID = "94a444a4-c0a3-5966-ab05-530c6ddc2301"; // #agents
// Open the activity pane via profile → "View activity" (same ingress the
@@ -57,9 +59,36 @@ test.describe("activity panel scope label", () => {
"channel-agents",
"agents",
);
- await expect(page.getByTestId("agent-session-scope-label")).toHaveText(
- "#agents",
+ await expect(page.getByTestId("agent-session-agent-name")).toHaveText(
+ "Observer Agent",
);
+ await expect(page.getByTestId("agent-session-agent-avatar")).toBeVisible();
+ const scope = page.getByTestId("agent-session-scope-label");
+ await expect(scope).toHaveText("Activity · #agents");
+ const recency = page.getByTestId("agent-session-recency-label");
+ await expect(recency).toHaveText("No updates yet");
+ await expect(recency).toBeVisible();
+
+ // Simulate long-scope pressure deterministically: scope owns truncation
+ // while the independently shrinking recency stays visible.
+ await scope.evaluate((element) => {
+ element.style.width = "5rem";
+ element.style.flex = "none";
+ });
+ expect(
+ await scope.evaluate((element) => element.scrollWidth),
+ ).toBeGreaterThan(await scope.evaluate((element) => element.clientWidth));
+ await expect(recency).toBeVisible();
+
+ await page.getByTestId("agent-session-settings-menu-trigger").click();
+ await page.getByTestId("agent-session-toggle-raw-feed").click();
+ await expect(scope).toHaveText("Raw ACP activity · #agents");
+ expect(
+ await scope.evaluate((element) => element.scrollWidth),
+ ).toBeGreaterThan(await scope.evaluate((element) => element.clientWidth));
+ await expect(recency).toHaveText("No updates yet");
+ await expect(recency).toBeVisible();
+ await page.keyboard.press("Escape");
await waitForAnimations(page);
await panel.screenshot({ path: `${SHOTS}/01-channel-scoped.png` });
@@ -75,11 +104,18 @@ test.describe("activity panel scope label", () => {
managedAgents: [
{
pubkey: AGENT_PUBKEY,
- name: "Observer Agent",
+ name: LONG_AGENT_NAME,
status: "running" as const,
channelNames: ["random"],
},
],
+ searchProfiles: [
+ {
+ pubkey: AGENT_PUBKEY,
+ displayName: LONG_AGENT_NAME,
+ isAgent: true,
+ },
+ ],
});
await page.goto(
@@ -90,9 +126,36 @@ test.describe("activity panel scope label", () => {
const panel = page.getByTestId("agent-session-thread-panel");
await expect(panel).toBeVisible({ timeout: 10_000 });
- await expect(page.getByTestId("agent-session-scope-label")).toHaveText(
- "All channels",
+ await expect(page.getByTestId("agent-session-agent-name")).toHaveText(
+ LONG_AGENT_NAME,
+ );
+ const agentName = page.getByTestId("agent-session-agent-name");
+ expect(
+ await agentName.evaluate((element) => element.scrollWidth),
+ ).toBeGreaterThan(
+ await agentName.evaluate((element) => element.clientWidth),
+ );
+ const scope = page.getByTestId("agent-session-scope-label");
+ await expect(scope).toHaveText("Activity · All channels");
+ const recency = page.getByTestId("agent-session-recency-label");
+ await expect(recency).toHaveText("No updates yet");
+ await expect(recency).toBeVisible();
+
+ await page.setViewportSize({ width: 720, height: 700 });
+ await expect(scope).toBeVisible();
+ await expect(recency).toBeVisible();
+ const recencyWidth = await recency.evaluate(
+ (element) => element.clientWidth,
+ );
+
+ await page.getByTestId("agent-session-settings-menu-trigger").click();
+ await page.getByTestId("agent-session-toggle-raw-feed").click();
+ await expect(scope).toHaveText("Raw ACP activity · All channels");
+ await expect(recency).toBeVisible();
+ expect(await recency.evaluate((element) => element.clientWidth)).toBe(
+ recencyWidth,
);
+ await page.keyboard.press("Escape");
await waitForAnimations(page);
await panel.screenshot({ path: `${SHOTS}/02-all-channels.png` });