import { useEffect, useState } from 'react'; import { Check, ChevronDown } from 'lucide-react'; import { toast } from 'sonner'; import { api } from '@/api/client'; import type { Agent } from '@/api/types'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; interface Props { projectId: string; value: string | null; onChange: (agentId: string | null) => void | Promise; } export function AgentPicker({ projectId, value, onChange }: Props) { const [agents, setAgents] = useState(null); const [error, setError] = useState(null); const [open, setOpen] = useState(false); // Load on mount (and on projectId change) so the trigger shows the agent // name immediately, not the raw id. AGENTS.md parse errors surface as a // toast once per load. useEffect(() => { let cancelled = false; setAgents(null); setError(null); api.agents .list(projectId) .then((res) => { if (cancelled) return; setAgents(res.agents); if (res.parse_error) { toast.error(`AGENTS.md parse error: ${res.parse_error}`); } }) .catch((err) => { if (cancelled) return; setError(err instanceof Error ? err.message : 'failed to load agents'); }); return () => { cancelled = true; }; }, [projectId]); const selectedAgent = agents?.find((a) => a.id === value) ?? null; const triggerLabel = value === null ? 'No agent' : selectedAgent?.name ?? value; return ( {error && (
{error}
)} {agents === null && !error && (
Loading…
)} {agents !== null && ( <> void onChange(null)} className="text-xs" > No agent {agents.length > 0 && } {agents.map((a) => ( void onChange(a.id)} className="text-xs flex-col items-start gap-0.5" >
{a.name}
{a.description && ( {a.description} )}
))} )}
); }