import * as React from "react"; import { type AttachManagedAgentToChannelResult, useAttachManagedAgentToChannelMutation, } from "@/features/agents/hooks"; import { useChannelMembersQuery, useChannelsQuery, } from "@/features/channels/hooks"; import type { Channel, ChannelRole, ManagedAgent } from "@/shared/api/types"; import { normalizePubkey } from "@/shared/lib/pubkey"; import { Button } from "@/shared/ui/button"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from "@/shared/ui/dialog"; import { CopyButton } from "./CopyButton"; export function AddAgentToChannelDialog({ agent, open, onAdded, onOpenChange, }: { agent: ManagedAgent | null; open: boolean; onAdded: ( channel: Channel, result: AttachManagedAgentToChannelResult, ) => void; onOpenChange: (open: boolean) => void; }) { const channelsQuery = useChannelsQuery(); const [channelId, setChannelId] = React.useState(""); const [role, setRole] = React.useState>("bot"); const attachAgentMutation = useAttachManagedAgentToChannelMutation( channelId || null, ); const channels = React.useMemo( () => (channelsQuery.data ?? []).filter( (channel) => channel.channelType !== "dm" && !channel.archivedAt, ), [channelsQuery.data], ); function reset() { setChannelId(""); setRole("bot"); attachAgentMutation.reset(); } function handleOpenChange(next: boolean) { if (!next) { reset(); } onOpenChange(next); } React.useEffect(() => { if (!open) { return; } if (!channelId && channels.length > 0) { setChannelId(channels[0].id); } }, [channelId, channels, open]); const membersQuery = useChannelMembersQuery( channelId || null, open && !!channelId, ); const isAlreadyMember = React.useMemo(() => { if (!agent?.pubkey || !membersQuery.data) { return false; } const normalized = normalizePubkey(agent.pubkey); return membersQuery.data.some( (member) => normalizePubkey(member.pubkey) === normalized, ); }, [agent?.pubkey, membersQuery.data]); const selectedChannel = channels.find((channel) => channel.id === channelId) ?? null; async function handleSubmit() { if (!agent || !selectedChannel) { return; } try { const result = await attachAgentMutation.mutateAsync({ agent, role, }); onAdded(selectedChannel, result); handleOpenChange(false); } catch { // React Query stores the error; keep the dialog open and render it inline. } } return (
Add agent to channel Add {agent?.name ?? "this agent"} to a channel so desktop chat can `@mention` it. Running agents pick up new channels automatically via membership notifications.

Only channels accessible to the current desktop user are shown here.

{isAlreadyMember ? (
✓ Already a member of this channel
) : null}

Agent pubkey

{agent?.pubkey ?? "No agent selected"} {agent ? ( ) : null}
{channelsQuery.error instanceof Error ? (

{channelsQuery.error.message}

) : null} {attachAgentMutation.error instanceof Error ? (

{attachAgentMutation.error.message}

) : null}
); }