/** * Agent Panel Component * * Displays a list of active agents on the project with their status and current task. */ 'use client'; import { Bot, MoreVertical } from 'lucide-react'; import { formatDistanceToNow } from 'date-fns'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from '@/components/ui/card'; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu'; import { Skeleton } from '@/components/ui/skeleton'; import { AgentStatusIndicator } from './AgentStatusIndicator'; import type { AgentInstance } from './types'; // ============================================================================ // Types // ============================================================================ interface AgentPanelProps { /** List of agent instances */ agents: AgentInstance[]; /** Whether data is loading */ isLoading?: boolean; /** Callback when "Manage Agents" is clicked */ onManageAgents?: () => void; /** Callback when an agent action is triggered */ onAgentAction?: (agentId: string, action: 'view' | 'pause' | 'restart' | 'terminate') => void; /** Additional CSS classes */ className?: string; } // ============================================================================ // Helper Functions // ============================================================================ function getAgentAvatarText(agent: AgentInstance): string { if (agent.avatar) return agent.avatar; // Generate initials from role const words = agent.role.split(/[\s_-]+/); if (words.length >= 2) { return (words[0][0] + words[1][0]).toUpperCase(); } return agent.role.substring(0, 2).toUpperCase(); } function formatLastActivity(lastActivity?: string): string { if (!lastActivity) return 'No activity'; try { return formatDistanceToNow(new Date(lastActivity), { addSuffix: true }); } catch { return 'Unknown'; } } // ============================================================================ // Subcomponents // ============================================================================ function AgentListItem({ agent, onAction, }: { agent: AgentInstance; onAction?: (agentId: string, action: 'view' | 'pause' | 'restart' | 'terminate') => void; }) { const avatarText = getAgentAvatarText(agent); const lastActivity = formatLastActivity(agent.last_activity_at); return (
{/* Avatar */} {/* Info */}
{agent.name}

{agent.current_task || 'No active task'}

{lastActivity} {onAction && ( onAction(agent.id, 'view')}> View Details {agent.status === 'working' || agent.status === 'waiting' ? ( onAction(agent.id, 'pause')}> Pause Agent ) : ( onAction(agent.id, 'restart')}> Restart Agent )} onAction(agent.id, 'terminate')} className="text-destructive focus:text-destructive" > Terminate Agent )}
); } function AgentPanelSkeleton() { return (
{[1, 2, 3].map((i) => (
))}
); } // ============================================================================ // Main Component // ============================================================================ export function AgentPanel({ agents, isLoading = false, onManageAgents, onAgentAction, className, }: AgentPanelProps) { if (isLoading) { return ; } const activeAgentCount = agents.filter( (a) => a.status === 'working' || a.status === 'waiting' ).length; return (
{activeAgentCount} of {agents.length} agents working
{onManageAgents && ( )}
{agents.length === 0 ? (
) : (
{agents.map((agent) => ( ))}
)}
); }