Remove agent creation success modal (#5063)

## Summary
- remove the post-creation private-key modal
- return directly to the underlying page with one “Agent created” toast
- preserve failed channel-attachment retry through an actionable toast

## Validation
- desktop checks and E2E build
- 4,392 desktop unit tests
- focused Playwright coverage for standard, customized, and
attachment-retry creation flows

Signed-off-by: kenny lopez <klopez4212@gmail.com>
This commit is contained in:
klopez4212
2026-08-07 17:03:16 +01:00
committed by GitHub
parent 346ae8cadc
commit c8743b2f20
10 changed files with 91 additions and 272 deletions
@@ -1,4 +0,0 @@
export type AgentChannelAttachmentFailure = {
channelName: string;
error: string;
};
@@ -1,7 +1,6 @@
import { useAgentManagement } from "@/features/agents/useAgentManagement";
import { AgentCardDialogs } from "./AgentCardViewerDialog";
import { AgentDialog } from "./AgentDialog";
import { SecretRevealDialog } from "./SecretRevealDialog";
/** Global review surfaces opened by owned agents through the Buzz harness. */
export function AgentManagementDialogs() {
@@ -25,19 +24,6 @@ export function AgentManagementDialogs() {
runtimeCatalogStatus={management.runtimeCatalogStatus}
/>
) : null}
{management.createdAgent ? (
<SecretRevealDialog
attachmentFailure={management.attachmentFailure}
created={management.createdAgent}
isRetryingAttachment={management.isRetryingAttachment}
onOpenChange={(open) => {
if (!open) management.dismissCreatedAgent();
}}
onRetryAttachment={() => {
void management.retryAttachment();
}}
/>
) : null}
{management.request?.action === "update" ? (
<AgentDialog
description=""
@@ -16,7 +16,6 @@ import { AgentSnapshotImportDialog } from "./AgentSnapshotImportDialog";
import { TeamSnapshotExportDialog } from "./TeamSnapshotExportDialog";
import { TeamSnapshotImportDialog } from "./TeamSnapshotImportDialog";
import { TeamShareDialog } from "./TeamShareDialog";
import { SecretRevealDialog } from "./SecretRevealDialog";
import { TeamDeleteDialog } from "./TeamDeleteDialog";
import { TeamDialog } from "./TeamDialog";
import { TeamsSection } from "./TeamsSection";
@@ -344,24 +343,6 @@ export function AgentsView() {
open={agents.agentToAddToChannel !== null}
/>
) : null}
{agents.createdAgent ? (
<SecretRevealDialog
created={agents.createdAgent}
onOpenChange={(open) => {
if (!open) {
agents.setCreatedAgent(null);
}
}}
/>
) : null}
{personas.createdAgent ? (
<SecretRevealDialog
created={personas.createdAgent}
onOpenChange={(open) => {
if (!open) personas.dismissCreatedAgent();
}}
/>
) : null}
{personas.personaDialogState ? (
<AgentDialog
description={personas.personaDialogState.description}
@@ -6,7 +6,6 @@ import {
type OpenCreateAgentOptions,
} from "@/features/agents/openCreateAgentEvent";
import { AgentDialog } from "./AgentDialog";
import { SecretRevealDialog } from "./SecretRevealDialog";
import { usePersonaActions } from "./usePersonaActions";
/** App-level create flow so contextual entry points do not navigate away. */
@@ -64,19 +63,6 @@ export function RequestedAgentCreateDialogs() {
}
/>
) : null}
{personas.createdAgent ? (
<SecretRevealDialog
attachmentFailure={personas.attachmentFailure}
created={personas.createdAgent}
isRetryingAttachment={personas.isRetryingAttachment}
onOpenChange={(open) => {
if (!open) personas.dismissCreatedAgent();
}}
onRetryAttachment={() => {
void personas.retryAttachment();
}}
/>
) : null}
</>
);
}
@@ -1,121 +0,0 @@
import type { AgentChannelAttachmentFailure } from "@/features/agents/channelAttachmentFailure";
import type { CreateManagedAgentResponse } from "@/shared/api/types";
import { Button } from "@/shared/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
} from "@/shared/ui/dialog";
import { CopyButton } from "./CopyButton";
export function SecretRevealDialog({
attachmentFailure,
created,
isRetryingAttachment = false,
onOpenChange,
onRetryAttachment,
}: {
attachmentFailure?: AgentChannelAttachmentFailure | null;
created: CreateManagedAgentResponse | null;
isRetryingAttachment?: boolean;
onOpenChange: (open: boolean) => void;
onRetryAttachment?: () => void;
}) {
return (
<Dialog onOpenChange={onOpenChange} open={created !== null}>
<DialogContent className="max-w-2xl overflow-hidden p-0">
<div className="flex max-h-[85vh] flex-col">
<DialogHeader className="border-b border-border/60 px-6 py-5 pr-14">
<DialogTitle>Agent created</DialogTitle>
<DialogDescription>
Save the private key now. The app can keep running the harness
locally, but this secret is only revealed here.
</DialogDescription>
</DialogHeader>
<div className="flex-1 space-y-4 overflow-y-auto px-6 py-5">
{created ? (
<>
<div className="rounded-2xl border border-border/70 bg-muted/20 p-4">
<div className="flex items-center justify-between gap-3">
<div>
<p className="text-sm font-semibold tracking-tight">
Private key (nsec)
</p>
<p className="text-sm text-muted-foreground">
This is the agent identity used by `buzz-acp`.
</p>
</div>
<CopyButton
label="Copy key"
value={created.privateKeyNsec}
/>
</div>
<code className="mt-3 block break-all rounded-xl border border-border/70 bg-background/80 px-3 py-2 text-xs">
{created.privateKeyNsec}
</code>
</div>
{created.profileSyncError ? (
<p className="rounded-2xl border border-amber-500/30 bg-amber-500/10 px-4 py-3 text-sm text-warning">
{created.profileSyncError}
</p>
) : null}
{created.spawnError ? (
<p className="rounded-2xl border border-destructive/30 bg-destructive/10 px-4 py-3 text-sm text-destructive">
{created.spawnError}
</p>
) : attachmentFailure ? (
<div
className="space-y-1 rounded-2xl border border-destructive/30 bg-destructive/10 px-4 py-3 text-sm text-destructive"
role="alert"
>
<p>
{created.agent.name} was created, but couldnt be added to
#{attachmentFailure.channelName}.
</p>
<p>{attachmentFailure.error}</p>
</div>
) : (
<p className="rounded-2xl border border-primary/20 bg-primary/10 px-4 py-3 text-sm text-primary">
{created.agent.name} is ready
{created.agent.status === "running"
? " and running."
: created.agent.status === "deployed"
? " and deployed."
: "."}
</p>
)}
</>
) : null}
</div>
<div className="flex justify-end gap-2 border-t border-border/60 px-6 py-4">
{attachmentFailure && onRetryAttachment ? (
<Button
disabled={isRetryingAttachment}
onClick={onRetryAttachment}
size="sm"
type="button"
>
{isRetryingAttachment ? "Trying again…" : "Try again"}
</Button>
) : null}
<Button
disabled={isRetryingAttachment}
onClick={() => onOpenChange(false)}
size="sm"
type="button"
variant="outline"
>
Done
</Button>
</div>
</div>
</DialogContent>
</Dialog>
);
}
@@ -1,4 +1,5 @@
import * as React from "react";
import { toast } from "sonner";
import {
type AttachManagedAgentToChannelResult,
@@ -15,12 +16,7 @@ import {
import { useGlobalAgentConfig } from "@/features/agents/useGlobalAgentConfig";
import { useChannelsQuery } from "@/features/channels/hooks";
import { usePresenceQuery } from "@/features/presence/hooks";
import type {
AgentPersona,
Channel,
CreateManagedAgentResponse,
ManagedAgent,
} from "@/shared/api/types";
import type { AgentPersona, Channel, ManagedAgent } from "@/shared/api/types";
import { removeChannelMember } from "@/shared/api/tauri";
import { normalizePubkey } from "@/shared/lib/pubkey";
import {
@@ -52,8 +48,6 @@ export function useManagedAgentActions() {
const [isCreateOpen, setIsCreateOpen] = React.useState(false);
const [agentToAddToChannel, setAgentToAddToChannel] =
React.useState<ManagedAgent | null>(null);
const [createdAgent, setCreatedAgent] =
React.useState<CreateManagedAgentResponse | null>(null);
const [startingPersonaIds, setStartingPersonaIds] = React.useState<
ReadonlySet<string>
>(() => new Set());
@@ -229,13 +223,11 @@ export function useManagedAgentActions() {
const input = await buildInstanceInputForDefinition(persona, runtime);
const created = await createAgentMutation.mutateAsync(input);
setCreatedAgent(created);
toast.success("Agent created");
const notices = [...warnings];
if (created.spawnError) {
setActionErrorMessage(created.spawnError);
} else {
notices.push(`Started ${created.agent.name}.`);
}
if (created.profileSyncError) {
@@ -440,8 +432,6 @@ export function useManagedAgentActions() {
setIsCreateOpen,
agentToAddToChannel,
setAgentToAddToChannel,
createdAgent,
setCreatedAgent,
logAgentPubkey,
setLogAgentPubkey,
actionNoticeMessage,
@@ -254,10 +254,6 @@ export function usePersonaActions() {
setPersonaErrorMessage(
`${persona.displayName} was created, but it did not start: ${created.spawnError}`,
);
} else {
setPersonaNoticeMessage(
`Created and started ${created.agent.name}.`,
);
}
if (created.profileSyncError) {
setPersonaErrorMessage(
@@ -1,82 +1,74 @@
import * as React from "react";
import { toast } from "sonner";
import { attachManagedAgentToChannel } from "./channelAgents";
import type { AgentChannelAttachmentFailure } from "./channelAttachmentFailure";
import type { Channel, CreateManagedAgentResponse } from "@/shared/api/types";
type TargetChannel = Pick<Channel, "id" | "name">;
/**
* Keeps agent creation successful even when the follow-up channel attachment
* fails, and retries only that attachment rather than recreating the agent.
*/
async function attach(
created: CreateManagedAgentResponse,
targetChannel: TargetChannel,
) {
const attached = await attachManagedAgentToChannel(targetChannel.id, {
agent: created.agent,
role: "bot",
ensureRunning: true,
});
created.agent = attached.agent;
}
function showAttachmentFailure(
created: CreateManagedAgentResponse,
targetChannel: TargetChannel,
cause: unknown,
toastId?: string | number,
) {
const error = cause instanceof Error ? cause.message : "Failed to add agent.";
const id = toast.warning("Agent created", {
description: `${created.agent.name} couldnt be added to #${targetChannel.name}. ${error}`,
id: toastId,
action: {
label: "Try again",
onClick: (event) => {
event.preventDefault();
toast.loading("Agent created", {
description: `Adding ${created.agent.name} to #${targetChannel.name}`,
id,
});
void attach(created, targetChannel).then(
() => {
toast.success("Agent created", {
description: `Added ${created.agent.name} to #${targetChannel.name}`,
id,
});
},
(retryCause: unknown) => {
showAttachmentFailure(created, targetChannel, retryCause, id);
},
);
},
},
});
}
/** Keeps creation successful when its optional channel attachment fails. */
export function useCreatedAgentChannelAttachment() {
const [createdAgent, setCreatedAgent] =
React.useState<CreateManagedAgentResponse | null>(null);
const [attachmentFailure, setAttachmentFailure] =
React.useState<AgentChannelAttachmentFailure | null>(null);
const targetChannelRef = React.useRef<TargetChannel | null>(null);
const [isRetryingAttachment, setIsRetryingAttachment] = React.useState(false);
async function attach(
created: CreateManagedAgentResponse,
targetChannel: TargetChannel,
) {
targetChannelRef.current = targetChannel;
try {
const attached = await attachManagedAgentToChannel(targetChannel.id, {
agent: created.agent,
role: "bot",
ensureRunning: true,
});
created.agent = attached.agent;
targetChannelRef.current = null;
setAttachmentFailure(null);
} catch (cause) {
setAttachmentFailure({
channelName: targetChannel.name,
error: cause instanceof Error ? cause.message : "Failed to add agent.",
});
}
}
async function presentCreatedAgent(
created: CreateManagedAgentResponse,
targetChannel?: TargetChannel | null,
) {
setAttachmentFailure(null);
targetChannelRef.current = null;
if (!created.spawnError && targetChannel) {
await attach(created, targetChannel);
if (created.spawnError || !targetChannel) {
toast.success("Agent created");
return;
}
setCreatedAgent({ ...created });
}
async function retryAttachment() {
const targetChannel = targetChannelRef.current;
if (!createdAgent || !targetChannel || isRetryingAttachment) return;
setIsRetryingAttachment(true);
try {
await attach(createdAgent, targetChannel);
setCreatedAgent({ ...createdAgent });
} finally {
setIsRetryingAttachment(false);
await attach(created, targetChannel);
toast.success("Agent created");
} catch (cause) {
showAttachmentFailure(created, targetChannel, cause);
}
}
function dismissCreatedAgent() {
setCreatedAgent(null);
setAttachmentFailure(null);
targetChannelRef.current = null;
}
return {
attachmentFailure,
createdAgent,
dismissCreatedAgent,
isRetryingAttachment,
presentCreatedAgent,
retryAttachment,
};
return { presentCreatedAgent };
}
+12 -7
View File
@@ -175,9 +175,12 @@ test("create agent persists Buzz shared compute with auto model", async ({
const model = page.locator("#persona-model");
await expect(model).toContainText("Automatic");
await page.getByTestId("persona-dialog-submit").click();
await expect(
page.getByRole("heading", { name: "Agent created" }),
).toBeVisible({ timeout: 10_000 });
const createdToast = page
.locator("[data-sonner-toast][data-removed='false']")
.filter({ hasText: "Agent created" });
await expect(createdToast).toBeVisible({ timeout: 10_000 });
await expect(createdToast).toHaveCount(1);
await expect(page.getByRole("dialog")).toHaveCount(0);
const createPayload = await page.evaluate((name) => {
const log = (
@@ -252,10 +255,12 @@ test("create agent supports parallelism and system prompt overrides", async ({
// the definition (agents always start after creation).
await page.getByTestId("persona-dialog-submit").click();
await expect(
page.getByRole("heading", { name: "Agent created" }),
).toBeVisible({ timeout: 10_000 });
await page.getByRole("button", { name: "Done" }).click();
const createdToast = page
.locator("[data-sonner-toast][data-removed='false']")
.filter({ hasText: "Agent created" });
await expect(createdToast).toBeVisible({ timeout: 10_000 });
await expect(createdToast).toHaveCount(1);
await expect(page.getByRole("dialog")).toHaveCount(0);
await expect(page.getByTestId("agents-library-personas")).toContainText(
agentName,
@@ -159,16 +159,16 @@ test.describe("welcome and channel agent entry points", () => {
await expect(page.getByTestId("persona-dialog-submit")).toBeEnabled();
await page.getByTestId("persona-dialog-submit").click();
const createdDialog = page.getByRole("dialog");
await expect(
createdDialog.getByRole("heading", { name: "Agent created" }),
).toBeVisible({ timeout: 10_000 });
await expect(createdDialog).toContainText(
"Scout was created, but couldnt be added to #random.",
const createdToast = page
.locator("[data-sonner-toast][data-removed='false']")
.filter({ hasText: "Agent created" });
await expect(createdToast).toBeVisible({ timeout: 10_000 });
await expect(createdToast).toContainText(
"Scout couldnt be added to #random. Relay unavailable.",
);
await expect(createdDialog).toContainText("Relay unavailable.");
await expect(page.getByRole("dialog")).toHaveCount(0);
await waitForAnimations(page);
await createdDialog.screenshot({
await createdToast.screenshot({
path: `${SHOTS}/05-agent-channel-attachment-failed.png`,
});
@@ -179,10 +179,19 @@ test.describe("welcome and channel agent entry points", () => {
);
const addCount = commandCount(commandsBeforeRetry, "add_channel_members");
await createdDialog.getByRole("button", { name: "Try again" }).click();
await expect(createdDialog).toContainText("Scout is ready and running.");
await createdToast.getByRole("button", { name: "Try again" }).click();
await expect
.poll(async () => {
const commands = await readCommandLog(page);
return commandCount(commands, "add_channel_members");
})
.toEqual(addCount + 1);
const attachedToast = page
.locator("[data-sonner-toast][data-removed='false']")
.filter({ hasText: "Added Scout to #random" });
await expect(attachedToast).toBeVisible();
await expect(
createdDialog.getByRole("button", { name: "Try again" }),
attachedToast.getByRole("button", { name: "Try again" }),
).toHaveCount(0);
const commandsAfterRetry = await readCommandLog(page);
@@ -192,7 +201,6 @@ test.describe("welcome and channel agent entry points", () => {
expect(commandCount(commandsAfterRetry, "add_channel_members")).toEqual(
addCount + 1,
);
await createdDialog.getByRole("button", { name: "Done" }).click();
await expect(page.getByTestId("chat-title")).toHaveText("random");
});