From 02f640bc4559c48ac0c2ec595ef34dd2c294b0db Mon Sep 17 00:00:00 2001 From: Taylor Ho Date: Fri, 7 Aug 2026 16:25:49 -0700 Subject: [PATCH] feat(desktop): unify add agent flows (#5015) **Category:** improvement **User Impact:** Users can create, discover, and import agents from one consistent Add agent dialog. **Problem:** Agent creation, discovery, and import were split across a dropdown and separate dialogs, making the Add agent flow fragmented. The existing E2E suite also continued targeting the deleted dropdown after the flows were unified. **Solution:** Route the new-agent card directly into a unified dialog with dedicated Create, catalog, and Import navigation, then update the affected E2E coverage to exercise that interface and its current empty state.
File changes **desktop/src/features/agents/ui/AgentDefinitionDialog.tsx** Supports rendering the agent definition form inside the unified Add agent experience while retaining the standalone dialog behavior. **desktop/src/features/agents/ui/AgentDefinitionDialogShell.tsx** Adds the shared shell used to present agent-definition content consistently in embedded and standalone contexts. **desktop/src/features/agents/ui/AgentDialog.tsx** Passes the revised dialog state and close behavior through the existing agent dialog entry point. **desktop/src/features/agents/ui/AgentsView.tsx** Connects the Agents page to the unified Add agent dialog and opens newly added catalog agents in their profile panel. **desktop/src/features/agents/ui/PersonaCatalogDialog.tsx** Combines catalog browsing, agent creation, and snapshot import behind persistent navigation, including dirty-navigation confirmation. **desktop/src/features/agents/ui/UnifiedAgentsSection.tsx** Replaces the new-agent dropdown with a direct Add agent entry point and adjusts the responsive card grid. **desktop/src/features/agents/ui/personaLibraryCopy.ts** Updates catalog-facing copy for the unified experience. **desktop/src/features/agents/ui/usePersonaActions.ts** Returns the resolved local persona after catalog activation so the caller can open the added agent. **desktop/tests/e2e/agent-readiness-screenshots.spec.ts** Opens the embedded create pane directly for readiness screenshots. **desktop/tests/e2e/agents.spec.ts** Covers unified Create, catalog, and Import navigation and asserts the current shared-agent empty state. **desktop/tests/e2e/global-agent-config-screenshots.spec.ts** Updates global configuration screenshot setup for direct create-pane entry. **desktop/tests/e2e/inline-custom-harness.spec.ts** Updates custom harness setup for the embedded create form. **desktop/tests/e2e/persona-env-vars.spec.ts** Updates environment-variable and model-provider scenarios for direct create-pane entry. **desktop/tests/e2e/persona-model-combobox-screenshots.spec.ts** Updates model combobox screenshot setup for direct create-pane entry. **desktop/tests/e2e/smoke.spec.ts** Updates agent-creation smoke coverage for the unified Add agent dialog. **desktop/tests/e2e/where-to-run-config.spec.ts** Updates provider-selection coverage for the embedded create form.
## Reproduction steps 1. Open the Agents page and select the new-agent card. 2. Confirm the Add agent dialog opens directly on Create without an intermediate dropdown. 3. Use the left navigation to browse shared agents and open Import. 4. Select a catalog agent and confirm the dialog closes and the added agent's profile panel opens. 5. Run the affected desktop Playwright smoke and integration specs and confirm all scenarios pass. --------- Signed-off-by: Taylor Ho Co-authored-by: Carl --- .../agents/ui/AgentDefinitionDialog.tsx | 616 +++++++++--------- .../agents/ui/AgentDefinitionDialogShell.tsx | 57 ++ .../src/features/agents/ui/AgentDialog.tsx | 16 +- desktop/src/features/agents/ui/AgentsView.tsx | 77 ++- .../agents/ui/PersonaCatalogDialog.tsx | 483 ++++++++++---- .../src/features/agents/ui/TeamsSection.tsx | 10 +- .../agents/ui/UnifiedAgentsSection.tsx | 94 +-- .../features/agents/ui/personaLibraryCopy.ts | 2 +- .../features/agents/ui/usePersonaActions.ts | 16 +- .../e2e/agent-readiness-screenshots.spec.ts | 1 - desktop/tests/e2e/agents.spec.ts | 103 +-- desktop/tests/e2e/edit-agent.spec.ts | 1 - .../global-agent-config-screenshots.spec.ts | 2 - .../tests/e2e/inline-custom-harness.spec.ts | 1 - desktop/tests/e2e/persona-env-vars.spec.ts | 4 +- ...persona-model-combobox-screenshots.spec.ts | 1 - desktop/tests/e2e/smoke.spec.ts | 3 - desktop/tests/e2e/where-to-run-config.spec.ts | 3 +- 18 files changed, 871 insertions(+), 619 deletions(-) create mode 100644 desktop/src/features/agents/ui/AgentDefinitionDialogShell.tsx diff --git a/desktop/src/features/agents/ui/AgentDefinitionDialog.tsx b/desktop/src/features/agents/ui/AgentDefinitionDialog.tsx index 409ae6a821..b4606a0f68 100644 --- a/desktop/src/features/agents/ui/AgentDefinitionDialog.tsx +++ b/desktop/src/features/agents/ui/AgentDefinitionDialog.tsx @@ -8,8 +8,6 @@ import type { UpdatePersonaInput, } from "@/shared/api/types"; import { cn } from "@/shared/lib/cn"; -import { ChooserDialogContent } from "@/shared/ui/chooser-dialog-content"; -import { Dialog } from "@/shared/ui/dialog"; import { Input } from "@/shared/ui/input"; import { Textarea } from "@/shared/ui/textarea"; import { AgentCreationPreview } from "./AgentCreationPreview"; @@ -85,6 +83,7 @@ import { import { useProviderApiKeyFieldState } from "./providerApiKeyFieldState"; import { buildRuntimeModelProviderPayload } from "./agentDefinitionSubmitPayload"; import { AgentDefinitionDialogFooter } from "./AgentDefinitionDialogFooter"; +import { AgentDefinitionDialogShell } from "./AgentDefinitionDialogShell"; import { AddCustomHarnessDialog } from "./AddCustomHarnessDialog"; import { ADD_CUSTOM_HARNESS_OPTION, @@ -94,6 +93,7 @@ import { type AgentDefinitionDialogProps = { open: boolean; + embedded?: boolean; title: string; description: string; submitLabel: string; @@ -102,6 +102,7 @@ type AgentDefinitionDialogProps = { isPending: boolean; runtimes: AcpRuntimeCatalogEntry[]; runtimeCatalogStatus?: "loading" | "ready" | "error"; + onDirtyChange?: (dirty: boolean) => void; onOpenChange: (open: boolean) => void; onSubmit: ( input: CreatePersonaInput | UpdatePersonaInput, @@ -120,6 +121,7 @@ export type AgentDefinitionSubmitOptions = { export function AgentDefinitionDialog({ open, + embedded = false, title, description, submitLabel, @@ -128,6 +130,7 @@ export function AgentDefinitionDialog({ isPending, runtimes, runtimeCatalogStatus = "ready" as const, + onDirtyChange, onOpenChange, onSubmit, publishCatalogUpdatesOnSave = false, @@ -192,6 +195,10 @@ export function AgentDefinitionDialog({ (hasText(initialValues.model) || hasText(initialValues.provider)), ); + React.useEffect(() => { + onDirtyChange?.(hasUserChanges); + }, [hasUserChanges, onDirtyChange]); + React.useEffect(() => { if (!open || !initialValues) { return; @@ -295,7 +302,8 @@ export function AgentDefinitionDialog({ }, [defaultRuntime, isCreateMode, open, runtime, runtimesLoading]); function handleOpenChange(next: boolean) { - if (!next) { + // The catalog may veto embedded close requests; preserve the draft until unmount. + if (!next && !embedded) { setDisplayName(""); setAvatarUrl(""); setSystemPrompt(""); @@ -724,317 +732,309 @@ export function AgentDefinitionDialog({ ); } + const footer = ( + handleOpenChange(false)} + publishesCatalogUpdates={publishCatalogUpdatesOnSave && hasUserChanges} + submitBlockReason={null} + submitLabel={submitLabel} + /> + ); + const form = ( +
setHasUserChanges(true)} + onSubmit={handleSubmitForm} + > + { + setHasUserChanges(true); + setAvatarUrl(""); + }} + onUploadPendingChange={setIsAvatarUploadPending} + onSelectAvatar={(nextAvatarUrl) => { + setHasUserChanges(true); + setAvatarUrl(nextAvatarUrl); + }} + /> + +
+
+ +
+ setDisplayName(event.target.value)} + placeholder="Fizz" + value={displayName} + /> +
+
+ +
+ +
+