feat: quick-add agent popover with two entry points#626
Draft
tellaho wants to merge 62 commits into
Draft
Conversation
Replace the direct + → full dialog flow with a lightweight Radix popover that shows available agents sorted by state (running > configured > catalog). One click to add. The full AddChannelBotDialog is still accessible via 'More options…' at the bottom of the popover. Two trigger points: - The existing + button in ChannelMembersBar now opens the popover - A new 'Add agent' button at the bottom of the sidebar Bots section The sidebar already had People/Bots section headers — the inline add affordance lives at the bottom of the Bots section. Actions: - Running agent not in channel → useAttachManagedAgentToChannelMutation - Persona without running agent → useCreateChannelManagedAgentMutation (leverages existing reuse logic from agentReuse.ts) The popover uses useBotRecents for smart ordering and pickBotName for instance naming. Force-new-instance stays buried in the full dialog.
Critical fixes: 1. Null channelId guard — popover renders children-only (no popover content) when channelId is null. Action handlers also early-return. 2. pickBotName fallback — safeBotName() wraps pickBotName with a defensive fallback to persona.displayName or 'Agent'. 3. E2E test updates — tests now click through the quick-add popover's 'More options…' button before asserting on the full dialog. 4. Duplicate AddChannelBotDialog — removed the sidebar's own dialog instance. Dialog state is now lifted to ChannelScreen and passed down via props. Only one dialog instance exists (in ChannelMembersBar). Medium fixes: 5. Discriminated union types — QuickAddAgentItem is now a proper tagged union (RunningAvailableItem | RunningInChannelItem | PersonaItem). No more optional agent?/persona? fields. 6. Extracted sortProviders utility — shared between ChannelMembersBar and any future consumer. Single source of truth for provider ordering. 7. Emerald colors kept — matches existing presence pattern (bg-emerald-500) used throughout the codebase. No design token exists for 'running' status. 8. Keyboard navigation — added arrow-key roving focus via onKeyDown handler on the popover container, targeting [data-quick-add-item] buttons. 9. Eager queries — channel members query already gated by popover open state. Other queries (agents, personas, providers) are globally cached by ChannelMembersBar which is always mounted — no extra network cost.
The 'More options…' button is not a listbox option, so the listbox role belongs on the inner div that contains only the agent option items.
Reorder header action buttons so the Quick Add Agent popover trigger (+ icon) is positioned directly before the manage channel button, making it more discoverable next to the channel settings. Also fix pre-existing lint: add role=menu to popover container and format QuickAddAgentPopover.tsx per biome rules.
This reverts commit bde1fc2.
Add a compact '+' icon button immediately left of the ellipsis (⋯) bulk-actions menu in the Bots section header of the Members side pane. Remove the old full-width 'Add agent' button from below the bots list. The trigger opens the same QuickAddAgentPopover as before — just in a more discoverable, compact location matching the ⋯ button style.
Change DropdownMenuContent from overflow-y-auto to overflow-hidden so hover/focus backgrounds on menu items are clipped by the container's rounded corners. Instances that need scrolling (e.g. PulseView) already pass overflow-y-auto via className which overrides the y-axis. Matches the existing SubContent pattern which already uses overflow-hidden.
Add overflow-hidden to PopoverContent so hover backgrounds on the bottom item stay clipped within the rounded corners. Also restore role=menu on the keyboard-navigable container (lost during revert).
Transform the Quick Add Agent popover into a hybrid interaction model: - Single-click on an individual agent still adds immediately (fast path) - Clicking a team row selects all its personas and enters multi-select mode - In multi-select mode, clicking agents toggles checkbox selection - Sticky 'Add (N)' confirm button appears at the bottom in multi-select - Teams section at the top shows usable teams with member count - Scroll container clips mid-item (max-h-[13.75rem]) to hint at more content - Nothing pre-selected; running agents still sort to top via recency - Batch add uses useCreateChannelManagedAgentsMutation for new personas and individual attach for already-running agents
Relocate the batch confirm button from the bottom sticky area into the 'Add agent' header row, anchored right. Uses Button size=sm (smallest variant). Only renders when multi-select mode is active with 1+ items selected.
…kboxes - Agents now appear indented under their team header as a visual unit - Ungrouped agents (not in any team) show in a separate section below - Checkboxes hidden by default, fade in on hover (group-hover) - Clicking checkbox enters multi-select mode; clicking row still does single-add (fast path preserved for ungrouped agents) - Team header click selects all members and enters multi-select mode - Once in multi-select mode, all checkboxes stay visible - Running agents still sort to top within their section
Remove team headers, nesting, multi-select mode, checkboxes, batch mutations, and team-related imports. The popover returns to its core purpose: a flat, smartly-ordered list where single-click immediately adds an agent. Teams and batch selection will live in the 'More options' dialog instead. Keeps: overflow-hidden fix, role=menu, smart ordering (running first, recents, then available), scroll container with mid-item clip.
Restructure the dialog from a flat wall of fields into three layers: 1. Primary (always visible): Persona/team selection + runtime picker. These are the two decisions that matter most. 2. Customize (collapsed): Bot name, system prompt, respond-to allowlist. Power user controls that don't block the happy path. 3. Advanced (collapsed): Backend provider selection, provider config. Expert territory hidden by default. Uses a simple DisclosureSection component with chevron toggle. All existing functionality preserved — just layered behind progressive disclosure. Description updated to match the new vibe.
- 'Select' button in the header reveals team filter chips on click - Title fades out, team chips animate in from right using motion/react - Clicking a team chip auto-selects all its member agents - Multi-select mode shows checkboxes + 'Add (N)' confirm button - Single-click fast path preserved when not in select mode - Team chips scroll horizontally when overflowing - Exiting: deselect all returns to default title state
- Team chips now use shadcn Toggle component (outline variant) with visual pressed state via data-[state=on] - Toggles are selectable/deselectable — clicking again removes the team - 'Select' button becomes 'Cancel' when active — clears all selections and exits select mode - 'Add (N)' button moved to the bottom of the popover, below More Options - Full-width button, only visible when items are selected
…ation - Remove auto-exit from select mode when selectedKeys empties — only Cancel button exits select mode now. - Stagger team Toggle animations: first chip fades in immediately, subsequent chips delay by index * 50ms for a fan-out effect.
…ion fix - Select button uses Button variant='secondary', switches to 'default' (primary) when active for clear visual state change - Checkboxes animate in with fade + scale (motion.div) when entering select mode - Agent name uses min-w-0 + truncate for proper text overflow when checkbox pushes content over
…sibility - Label stays 'Select' in both states (no more 'Cancel' label) - Inactive: variant='outline' (visible against bg-popover) - Active: variant='default' (primary) for clear state change - Popover uses bg-popover token (hsl 220 23% 95% light / 232 23% 18% dark)
…clash The outline variant includes bg-background which creates a visible contrast block against bg-popover. Use ghost variant with explicit border-input border for a truly transparent-bg outlined button.
Checkboxes were too busy in the agent list. Selection is now indicated only by the bg-accent/50 highlight on selected rows. Button already uses size=sm.
- First team chip: opacity-only animation (no x translate) - Second+ chips: translate from x:12 + fade, staggered by index - Header container: px-3 py-1.5 with gap-2 for consistent spacing around the Select button on all sides
…t shift in select mode
Three primary buttons competing looked unfocused. New hierarchy: - Add (N) button: primary (the CTA) - Toggle chips selected: bg-accent (visible but not competing) - Select button active: secondary (subtle elevation, not primary)
…efault toggle colors - Button stays ghost+border (outline look) in both states - Label changes: 'Select' → 'Cancel' when active - Toggle chips use default data-[state=on]:bg-primary (removed accent override)
- 'Add agent' title stays visible always; 's' fades in when select mode
activates ('Add agents')
- Team toggles appear to the right of the title, scroll horizontally
- Right-edge gradient (from-popover to-transparent) hints at more
content when overflowing
The width:0→auto animation caused the 's' to render broken. Just fade it in with opacity — it's one character, doesn't need a width transition.
…ation - Toggles sit in a separate row that slides in/out (height animation) - Agent list uses motion layout to smoothly translate down when row appears - Header stays clean: just title + Select/Cancel button - Gradient scroll affordance on the toggle row's right edge
…with gradient, remove 's' animation and border-2
…no more jank on exit
… mount/unmount jank
…ontent in gapped div — no extra left padding when checkbox hidden
…essive disclosure changes)
…ns while popover is open
…hannel agents sort to top
- Add optimistic onMutate to useAttachManagedAgentToChannelMutation (instant member insertion, rollback on error) - Add onSuccess cache-set to create/batch mutations (member appears as soon as server confirms, before invalidation round-trip) - Decompose QuickAddAgentPopover (816→271 lines) into: - useQuickAddAgentItems.ts (data fetching + item list building) - useQuickAddAgentActions.ts (handlers + multi-select state) - QuickAddAgentItemRow.tsx (memoized item row component) - Fix ARIA: remove conflicting role="menu" on container, add role="group" with aria-label for keyboard navigation wrapper - Fix dead team toggles: filter out teams whose members are all already in the channel
Mirror of the attach optimistic update. onMutate filters the member out of the cache immediately, rolls back on error, invalidates on settle to reconcile with server.
Adds a sortedBots memo in MembersSidebar that prioritizes online agents at the top. Within each presence group (online vs not-online), agents sort alphabetically by display name. No more recency-based reordering — the list stays stable.
The single-agent create path was calling createChannelManagedAgent without context, so the reuse guard (findReusablePersonaAgent) never fired — always spawning a new keypair + process. Now fetches managedAgents + channelMemberPubkeys before calling create, matching the batch path's behavior.
2f91f86 to
8cf10d3
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replace the "click + → full dialog" flow with a lightweight quick-add popover that makes adding an agent to a channel a one-click action. The full dialog stays as an advanced escape hatch via "More options…".
What changed
New:
QuickAddAgentPopovercomponentAddChannelBotDialogrole="listbox"scoped to item list onlyTwo trigger points, same popover
+button inChannelMembersBarnow opens the popover (not the dialog directly)Dialog ownership lifted
AddChannelBotDialoginstance owned byChannelScreenExtracted utilities
sortProviders— shared "goose first" provider sortsafeBotName— defensivepickBotNamewrapper with fallback chainE2E tests updated
Key decisions
useBotRecentsfor smart ordering (recents float to top)useAttachManagedAgentToChannelMutationuseCreateChannelManagedAgentMutation(leverages existing reuse logic from PR fix: prevent agent proliferation when adding bots to channels #621)channelIdguard: popover renders children-only, handlers early-return