import React from 'react'; import { Button } from '@/components/ui/button'; import { ButtonLarge } from '@/components/ui/button-large'; import { Input } from '@/components/ui/input'; import { toast } from 'sonner'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger, } from '@/components/ui/dialog'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; import { RiAddLine, RiAiAgentFill, RiAiAgentLine, RiDeleteBinLine, RiFileCopyLine, RiMore2Line, RiRobot2Line, RiRobotLine } from '@remixicon/react'; import { useAgentsStore, isAgentBuiltIn, isAgentHidden } from '@/stores/useAgentsStore'; import { useUIStore } from '@/stores/useUIStore'; import { useDeviceInfo } from '@/lib/device'; import { cn } from '@/lib/utils'; import type { Agent } from '@opencode-ai/sdk'; import { ScrollableOverlay } from '@/components/ui/ScrollableOverlay'; interface AgentsSidebarProps { onItemSelect?: () => void; } export const AgentsSidebar: React.FC = ({ onItemSelect }) => { const [newAgentName, setNewAgentName] = React.useState(''); const [isCreateDialogOpen, setIsCreateDialogOpen] = React.useState(false); const { selectedAgentName, agents, setSelectedAgent, deleteAgent, loadAgents, } = useAgentsStore(); const { setSidebarOpen } = useUIStore(); const { isMobile } = useDeviceInfo(); const [isDesktopRuntime, setIsDesktopRuntime] = React.useState(() => { if (typeof window === 'undefined') return false; return typeof window.opencodeDesktop !== 'undefined'; }); React.useEffect(() => { if (typeof window === 'undefined') return; setIsDesktopRuntime(typeof window.opencodeDesktop !== 'undefined'); }, []); React.useEffect(() => { loadAgents(); }, [loadAgents]); const handleCreateAgent = () => { if (!newAgentName.trim()) { toast.error('Agent name is required'); return; } if (agents.some((agent) => agent.name === newAgentName)) { toast.error('An agent with this name already exists'); return; } setSelectedAgent(newAgentName); setNewAgentName(''); setIsCreateDialogOpen(false); if (isMobile) { setSidebarOpen(false); } }; const handleDeleteAgent = async (agent: Agent) => { if (isAgentBuiltIn(agent)) { toast.error('Built-in agents cannot be deleted'); return; } if (window.confirm(`Are you sure you want to delete agent "${agent.name}"?`)) { const success = await deleteAgent(agent.name); if (success) { toast.success(`Agent "${agent.name}" deleted successfully`); } else { toast.error('Failed to delete agent'); } } }; const handleDuplicateAgent = (agent: Agent) => { const baseName = agent.name; let copyNumber = 1; let newName = `${baseName} Copy`; while (agents.some((a) => a.name === newName)) { copyNumber++; newName = `${baseName} Copy ${copyNumber}`; } setSelectedAgent(newName); setIsCreateDialogOpen(false); if (isMobile) { setSidebarOpen(false); } }; const getAgentModeIcon = (mode?: string) => { switch (mode) { case 'primary': return ; case 'all': return ; case 'subagent': return ; default: return null; } }; // Filter out hidden agents (internal agents like title, compaction, summary) const visibleAgents = agents.filter((agent) => !isAgentHidden(agent)); const builtInAgents = visibleAgents.filter(isAgentBuiltIn); const customAgents = visibleAgents.filter((agent) => !isAgentBuiltIn(agent)); return (
Total {visibleAgents.length}
{visibleAgents.length === 0 ? (

No agents configured

Use the + button above to create one

) : ( <> {builtInAgents.length > 0 && ( <>
Built-in Agents
{builtInAgents.map((agent) => ( { setSelectedAgent(agent.name); onItemSelect?.(); if (isMobile) { setSidebarOpen(false); } }} onDuplicate={() => handleDuplicateAgent(agent)} getAgentModeIcon={getAgentModeIcon} /> ))} )} {customAgents.length > 0 && ( <>
Custom Agents
{customAgents.map((agent) => ( { setSelectedAgent(agent.name); onItemSelect?.(); if (isMobile) { setSidebarOpen(false); } }} onDelete={() => handleDeleteAgent(agent)} onDuplicate={() => handleDuplicateAgent(agent)} getAgentModeIcon={getAgentModeIcon} /> ))} )} )}
Create New Agent Enter a unique name for your new agent setNewAgentName(e.target.value)} placeholder="Agent name..." className="text-foreground placeholder:text-muted-foreground" onKeyDown={(e) => { if (e.key === 'Enter') { handleCreateAgent(); } }} /> Create
); }; interface AgentListItemProps { agent: Agent; isSelected: boolean; onSelect: () => void; onDelete?: () => void; onDuplicate: () => void; getAgentModeIcon: (mode?: string) => React.ReactNode; } const AgentListItem: React.FC = ({ agent, isSelected, onSelect, onDelete, onDuplicate, getAgentModeIcon, }) => { return (
{ e.stopPropagation(); onDuplicate(); }} > Duplicate {!isAgentBuiltIn(agent) && onDelete && ( { e.stopPropagation(); onDelete(); }} className="text-destructive focus:text-destructive" > Delete )}
); };