- Delete this agent?
+ Delete {agent.name}?
- Deleting this agent stops and removes the agent from this community.
+ This permanently removes the agent, its saved key, and its channel
+ access.
-
- Removes the local management record and saved agent key
- Removes the agent from every channel it belongs to
-
- Archives the agent's identity on the relay so it no longer
- appears in member lists or mention suggestions
-
-
- {isProviderAgent
- ? "Requests remote deletion; if it is online, Buzz first sends a shutdown command when possible. If the deployment cannot be reached through a channel, the remote process may keep running without local management."
- : "Stops any local agent process before deleting the record"}
-
-
-
- Archive this agent if you want to hide it instead of removing it.
-
+
+
+
Memories
+
+ {memoriesLoading ? "…" : (memoryCount ?? "—")}
+
+
+
+
Channels
+
+ {channelCount}
+
+
+
+ {showExportRecommendation ? (
+
+ Want a backup?{" "}
+ {
+ onOpenChange(false);
+ onExport();
+ }}
+ type="button"
+ variant="link"
+ >
+ Export this agent
+
+ .
+
+ ) : null}
+ {isProviderAgent ? (
+
+ The remote process may keep running if Buzz can't reach it.
+
+ ) : null}
diff --git a/desktop/src/features/profile/ui/UserProfilePanelSections.tsx b/desktop/src/features/profile/ui/UserProfilePanelSections.tsx
index 0582e53965..26983845b4 100644
--- a/desktop/src/features/profile/ui/UserProfilePanelSections.tsx
+++ b/desktop/src/features/profile/ui/UserProfilePanelSections.tsx
@@ -511,6 +511,7 @@ export function ProfileSummaryView({
archiveActions={archiveActions}
canArchiveAgent={isBot && archiveActions.canArchive}
canDeleteAgent={canDeleteAgent}
+ channelCount={channelCount}
channelIdToName={channelIdToName}
isArchived={isArchived}
isDeleteAgentPending={isAgentActionPending}
diff --git a/desktop/src/features/profile/ui/UserProfilePanelTabs.tsx b/desktop/src/features/profile/ui/UserProfilePanelTabs.tsx
index 842ffd58ff..8011646022 100644
--- a/desktop/src/features/profile/ui/UserProfilePanelTabs.tsx
+++ b/desktop/src/features/profile/ui/UserProfilePanelTabs.tsx
@@ -203,6 +203,7 @@ export function ProfileInfoTabContent({
archiveActions,
canArchiveAgent,
canDeleteAgent,
+ channelCount,
channelIdToName,
isArchived,
isDeleteAgentPending,
@@ -223,6 +224,7 @@ export function ProfileInfoTabContent({
archiveActions: IdentityArchiveActions;
canArchiveAgent: boolean;
canDeleteAgent: boolean;
+ channelCount: number;
channelIdToName: Record;
isArchived: boolean;
isDeleteAgentPending: boolean;
@@ -311,6 +313,7 @@ export function ProfileInfoTabContent({
canDeleteAgent={canDeleteAgent}
isDeletePending={isDeleteAgentPending}
managedAgent={managedAgent}
+ channelCount={channelCount}
onCreateCard={onCreateCard}
onDeleteAgent={onDeleteAgent}
onDuplicateAgent={onDuplicateAgent}
diff --git a/desktop/tests/e2e/agents.spec.ts b/desktop/tests/e2e/agents.spec.ts
index 0292ded689..023795fe35 100644
--- a/desktop/tests/e2e/agents.spec.ts
+++ b/desktop/tests/e2e/agents.spec.ts
@@ -7,7 +7,11 @@ import type { RelayEvent } from "@/shared/api/types";
import { emojiAvatarDataUrl } from "@/features/profile/ui/ProfileAvatarEditor.utils";
import { waitForAnimations } from "../helpers/animations";
-import { installMockBridge, TEST_IDENTITIES } from "../helpers/bridge";
+import {
+ createMockAgentMemoryListing,
+ installMockBridge,
+ TEST_IDENTITIES,
+} from "../helpers/bridge";
import { seedActiveIdentity } from "../helpers/onboarding";
function createCatalogEvent(input: {
@@ -2695,8 +2699,9 @@ test("duplicate instances stay visible in the gallery and agent profile", async
}) => {
const personaId = "custom:duplicate-auditor";
const primaryPubkey = TEST_IDENTITIES.alice.pubkey;
- const additionalPubkey = TEST_IDENTITIES.charlie.pubkey;
+ const additionalPubkey = TEST_IDENTITIES.outsider.pubkey;
await installMockBridge(page, {
+ agentMemory: createMockAgentMemoryListing(),
personas: [
{
id: personaId,
@@ -2716,6 +2721,14 @@ test("duplicate instances stay visible in the gallery and agent profile", async
name: "Duplicate Auditor",
personaId,
status: "stopped",
+ channelNames: ["general", "random"],
+ },
+ ],
+ relayAgents: [
+ {
+ pubkey: additionalPubkey,
+ name: "Duplicate Auditor",
+ channelNames: ["general", "random"],
},
],
});
@@ -2728,8 +2741,10 @@ test("duplicate instances stay visible in the gallery and agent profile", async
).toBeVisible();
await page.getByTestId(`managed-agent-${primaryPubkey}`).click();
+ await page.getByTestId("user-profile-tab-runtime").click();
await page.getByTestId("user-profile-instances").click();
await page.getByTestId(`user-profile-instance-${additionalPubkey}`).click();
+ await page.getByTestId("user-profile-tab-info").click();
await expect(page.getByTestId("user-profile-panel")).toBeVisible();
await expect(page.getByTestId("user-profile-agent-status")).toContainText(
@@ -2739,6 +2754,20 @@ test("duplicate instances stay visible in the gallery and agent profile", async
page.getByTestId("user-profile-settings-menu-trigger"),
).toHaveCount(0);
await expect(
- page.getByTestId(`user-profile-agent-delete-${additionalPubkey}`),
- ).toHaveCount(0);
+ page.getByTestId("user-profile-duplicate-agent-row"),
+ ).toBeVisible();
+ await expect(page.getByTestId("user-profile-export-agent-row")).toBeVisible();
+ await page.getByTestId("user-profile-delete-agent-row").click();
+
+ const deleteDialog = page.getByTestId("agent-delete-confirm-dialog");
+ await expect(deleteDialog).toBeVisible();
+ await expect(deleteDialog.getByRole("heading")).toHaveText(
+ "Delete Duplicate Auditor?",
+ );
+ await expect(page.getByTestId("agent-delete-memory-count")).toHaveText("9");
+ await expect(page.getByTestId("agent-delete-channel-count")).toHaveText("2");
+
+ await page.getByTestId("agent-delete-export-action").click();
+ await expect(deleteDialog).toHaveCount(0);
+ await expect(page.getByTestId("agent-snapshot-export-dialog")).toBeVisible();
});