From fcb4e00f5b16bd4d33bbd9c89f40ded05c82a172 Mon Sep 17 00:00:00 2001 From: dmarticus Date: Thu, 18 Jun 2026 22:36:24 -0700 Subject: [PATCH 1/2] =?UTF-8?q?feat(agents):=20agent=20builder=20polish=20?= =?UTF-8?q?=E2=80=94=20alignment,=20naming,=20landing=20copy?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Drop the redundant sidebar-toggle from the page header when the dock is open; the dock owns its own close button. When the dock is closed, the split button is the entry point. - Pin AgentBuilderHeaderControls absolutely at the top-right of each agents-page header so "New agent" / "Edit configuration" / "Explain this session" sit on the same row as the dock's "Agent Builder" header. - Centralise the meta-agent display name in displayAgentName(app): wherever the agent-concierge slug surfaces in user-visible copy it now reads "Agent Builder" (Live now row, Applications list, detail title, header, Observability subtitle, Approvals row, promote-to-live confirm). Backend slug unchanged. - Tighten the Applications tab description to lean into the pitch: "Talk it through. Ship it. Watch it work. The Agent Builder turns ideas into production agents." - Update the dock's no-ingress empty-state copy to match. - Add format.test.ts covering displayAgentName. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../agent-builder/AgentBuilderDock.tsx | 11 +-- .../AgentBuilderHeaderControls.tsx | 72 ++++++++++--------- .../components/AgentApplicationsListView.tsx | 4 +- .../components/AgentDetailLayout.tsx | 11 ++- .../components/AgentFleetApprovalsPane.tsx | 10 ++- .../AgentFleetLiveSessionsPanel.tsx | 6 +- .../components/AgentObservabilityPane.tsx | 3 +- .../components/AgentRevisionBar.tsx | 4 +- .../components/AgentSessionTranscriptView.tsx | 12 ++-- .../agent-applications/utils/format.test.ts | 39 ++++++++++ .../agent-applications/utils/format.ts | 18 +++++ .../agents/components/AgentsTabLayout.tsx | 26 ++++--- 12 files changed, 143 insertions(+), 73 deletions(-) create mode 100644 packages/ui/src/features/agent-applications/utils/format.test.ts diff --git a/packages/ui/src/features/agent-applications/agent-builder/AgentBuilderDock.tsx b/packages/ui/src/features/agent-applications/agent-builder/AgentBuilderDock.tsx index ed0469ac03..2d9b2542b1 100644 --- a/packages/ui/src/features/agent-applications/agent-builder/AgentBuilderDock.tsx +++ b/packages/ui/src/features/agent-applications/agent-builder/AgentBuilderDock.tsx @@ -66,10 +66,11 @@ function buildAgentBuilderContext( } /** - * The agent builder chat — an always-on dock talking to the deployed - * `agent-concierge`. Streams through the shared `useAgentChat`/`AgentChatSurface` - * stack, prepends the current `/code/agents` page context to the first message, - * answers `get_context`, and lets the agent drive the UI via `focus_*`. + * The Agent Builder chat — an always-on dock talking to the deployed meta-agent + * (backend slug `agent-concierge`). Streams through the shared + * `useAgentChat`/`AgentChatSurface` stack, prepends the current `/code/agents` + * page context to the first message, answers `get_context`, and lets the agent + * drive the UI via `focus_*`. */ export function AgentBuilderDock() { const { data: application } = useAgentApplication(AGENT_BUILDER_SLUG); @@ -254,7 +255,7 @@ export function AgentBuilderDock() {
) : ( diff --git a/packages/ui/src/features/agent-applications/agent-builder/AgentBuilderHeaderControls.tsx b/packages/ui/src/features/agent-applications/agent-builder/AgentBuilderHeaderControls.tsx index bbe49b9e1f..edf3c9d244 100644 --- a/packages/ui/src/features/agent-applications/agent-builder/AgentBuilderHeaderControls.tsx +++ b/packages/ui/src/features/agent-applications/agent-builder/AgentBuilderHeaderControls.tsx @@ -15,15 +15,18 @@ import { useAgentBuilderStore } from "./agentBuilderStore"; /** * The agents-header control cluster — identical across every agents view. * + * Pinned absolutely to the top-right of the nearest `relative` ancestor so it + * sits on the same row as the Agent Builder dock header (matching `py-2`), + * keeping the two halves of the agents UI visually aligned across views. + * * One split button is the single entry point into the Agent Builder dock: * - the primary segment is the contextual "edit with AI" action for the view * you're on (New agent / Edit configuration / Explain this session / …) — it * opens the dock and seeds the matching prompt, - * - the trailing segment just opens/closes the dock without seeding, so you - * can peek at or dismiss the existing conversation. - * The two were previously near-identical gold buttons; fusing them keeps both - * affordances but with one sparkle (the AI identity) and one neutral toggle. - * Views with no obvious action (Scouts) collapse to the lone open/close toggle. + * - the trailing segment just opens the dock without seeding, so you can peek + * at the existing conversation; once the dock is open it disappears so we + * don't double up with the dock's own close button. + * Views with no obvious action (Scouts) collapse to the lone open toggle. * Renders nothing unless the `agent-platform` flag is on. */ export function AgentBuilderHeaderControls() { @@ -36,13 +39,15 @@ export function AgentBuilderHeaderControls() { if (!enabled) return null; const action = headerActionForPage(page); - const toggleTip = visible - ? "Hide the agent builder (⌘⇧I)" - : "Open the agent builder (⌘⇧I)"; + const openTip = "Open the agent builder (⌘⇧I)"; return ( - + {action ? (
@@ -51,7 +56,11 @@ export function AgentBuilderHeaderControls() { - } - /> - {toggleTip} - + {visible ? null : ( + + + + + } + /> + {openTip} + + )}
- ) : ( + ) : visible ? null : ( } /> - {toggleTip} + {openTip} )}
diff --git a/packages/ui/src/features/agent-applications/components/AgentApplicationsListView.tsx b/packages/ui/src/features/agent-applications/components/AgentApplicationsListView.tsx index 003353816b..6c75343182 100644 --- a/packages/ui/src/features/agent-applications/components/AgentApplicationsListView.tsx +++ b/packages/ui/src/features/agent-applications/components/AgentApplicationsListView.tsx @@ -18,7 +18,7 @@ import { useAuthStateValue } from "../../auth/store"; import { useAgentAnalytics } from "../hooks/useAgentAnalytics"; import { useAgentApplications } from "../hooks/useAgentApplications"; import { useAgentFleetApprovals } from "../hooks/useAgentFleetApprovals"; -import { formatSpendUsd } from "../utils/format"; +import { displayAgentName, formatSpendUsd } from "../utils/format"; import { aiObservabilityTracesUrl } from "../utils/observabilityLinks"; import { AgentAnalyticsKpiStrip } from "./AgentAnalyticsView"; import { AgentDetailEmptyState } from "./AgentDetailLayout"; @@ -197,7 +197,7 @@ function ApplicationRow({ - {application.name} + {displayAgentName(application) ?? application.name} {isLive ? "Live" : "Draft"} diff --git a/packages/ui/src/features/agent-applications/components/AgentDetailLayout.tsx b/packages/ui/src/features/agent-applications/components/AgentDetailLayout.tsx index 89d1db64bb..4f5e8bb5d8 100644 --- a/packages/ui/src/features/agent-applications/components/AgentDetailLayout.tsx +++ b/packages/ui/src/features/agent-applications/components/AgentDetailLayout.tsx @@ -8,6 +8,7 @@ import { AgentBuilderHeaderControls } from "../agent-builder/AgentBuilderHeaderC import type { AgentBuilderPageContext } from "../agent-builder/agentBuilderStore"; import { useSetAgentBuilderPage } from "../agent-builder/useSetAgentBuilderPage"; import { useAgentApplication } from "../hooks/useAgentApplication"; +import { displayAgentName } from "../utils/format"; /** Map a detail sub-tab to the agent builder page context for this agent. */ function tabToAgentBuilderPage( @@ -110,7 +111,7 @@ export function AgentDetailLayout({ isError, } = useAgentApplication(idOrSlug); - const title = application?.name ?? idOrSlug; + const title = displayAgentName(application) ?? idOrSlug; const headerContent = useMemo( () => ( @@ -134,8 +135,9 @@ export function AgentDetailLayout({ + Applications - + {title} @@ -152,9 +154,6 @@ export function AgentDetailLayout({ {application.live_revision ? "Live" : "Draft"} ) : null} - - - {application?.description?.trim() ? ( diff --git a/packages/ui/src/features/agent-applications/components/AgentFleetApprovalsPane.tsx b/packages/ui/src/features/agent-applications/components/AgentFleetApprovalsPane.tsx index 30434d8711..863a678167 100644 --- a/packages/ui/src/features/agent-applications/components/AgentFleetApprovalsPane.tsx +++ b/packages/ui/src/features/agent-applications/components/AgentFleetApprovalsPane.tsx @@ -12,7 +12,11 @@ import { useMemo } from "react"; import { useSetAgentBuilderPage } from "../agent-builder/useSetAgentBuilderPage"; import { useAgentApplications } from "../hooks/useAgentApplications"; import { useAgentFleetApprovals } from "../hooks/useAgentFleetApprovals"; -import { approvalStateColor, approvalStateLabel } from "../utils/format"; +import { + approvalStateColor, + approvalStateLabel, + displayAgentName, +} from "../utils/format"; import { AgentApprovalDetail } from "./AgentApprovalDetail"; import { AgentDetailEmptyState } from "./AgentDetailLayout"; import { APPROVAL_FILTERS, type ApprovalFilter } from "./agentApprovalsFilters"; @@ -198,7 +202,9 @@ function FleetApprovalRow({ }) { const isQueued = approval.state === "queued"; const agentLabel = - application?.name ?? application?.slug ?? approval.application_id; + displayAgentName(application) ?? + application?.slug ?? + approval.application_id; return (