'use client' import { useState, useEffect, useCallback } from 'react' import { useTranslations } from 'next-intl' import { Button } from '@/components/ui/button' import { Loader } from '@/components/ui/loader' import { createClientLogger } from '@/lib/client-logger' const log = createClientLogger('AgentSquadPanel') interface Agent { id: number name: string role: string session_key?: string soul_content?: string status: 'offline' | 'idle' | 'busy' | 'error' last_seen?: number last_activity?: string created_at: number updated_at: number config?: any taskStats?: { total: number assigned: number in_progress: number completed: number } } const statusColors: Record = { offline: 'bg-gray-500', idle: 'bg-green-500', busy: 'bg-yellow-500', error: 'bg-red-500', } const statusIcons: Record = { offline: '⚫', idle: '🟢', busy: '🟡', error: '🔴', } export function AgentSquadPanel() { const t = useTranslations('agentSquad') const [agents, setAgents] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [selectedAgent, setSelectedAgent] = useState(null) const [showCreateModal, setShowCreateModal] = useState(false) const [autoRefresh, setAutoRefresh] = useState(true) // Fetch agents const fetchAgents = useCallback(async () => { try { setError(null) if (agents.length === 0) setLoading(true) const response = await fetch('/api/agents') if (!response.ok) throw new Error(t('failedToFetch')) const data = await response.json() setAgents(data.agents || []) } catch (err) { setError(err instanceof Error ? err.message : t('errorOccurred')) } finally { setLoading(false) } }, [agents.length]) // Initial load useEffect(() => { fetchAgents() }, [fetchAgents]) // Auto-refresh useEffect(() => { if (!autoRefresh) return const interval = setInterval(fetchAgents, 10000) // Every 10 seconds return () => clearInterval(interval) }, [autoRefresh, fetchAgents]) // Update agent status const updateAgentStatus = async (agentName: string, status: Agent['status'], activity?: string) => { try { const response = await fetch('/api/agents', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: agentName, status, last_activity: activity || `Status changed to ${status}` }) }) if (!response.ok) throw new Error(t('failedToUpdateStatus')) // Update local state setAgents(prev => prev.map(agent => agent.name === agentName ? { ...agent, status, last_activity: activity || `Status changed to ${status}`, last_seen: Math.floor(Date.now() / 1000), updated_at: Math.floor(Date.now() / 1000) } : agent )) } catch (error) { log.error('Failed to update agent status:', error) setError(t('failedToUpdateStatus')) } } // Format last seen time const formatLastSeen = (timestamp?: number) => { if (!timestamp) return t('never') const now = Date.now() const diffMs = now - (timestamp * 1000) const diffMinutes = Math.floor(diffMs / (1000 * 60)) const diffHours = Math.floor(diffMs / (1000 * 60 * 60)) const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24)) if (diffMinutes < 1) return t('justNow') if (diffMinutes < 60) return t('minutesAgo', { count: diffMinutes }) if (diffHours < 24) return t('hoursAgo', { count: diffHours }) if (diffDays < 7) return t('daysAgo', { count: diffDays }) return new Date(timestamp * 1000).toLocaleDateString() } // Get status distribution for summary const statusCounts = agents.reduce((acc, agent) => { acc[agent.status] = (acc[agent.status] || 0) + 1 return acc }, {} as Record) if (loading && agents.length === 0) { return } return (
{/* Header */}

{t('title')}

{/* Status Summary */}
{Object.entries(statusCounts).map(([status, count]) => (
{count}
))}
{/* Error Display */} {error && (
{error}
)} {/* Agent Grid */}
{agents.length === 0 ? (
🤖

{t('noAgents')}

{t('addFirstAgent')}

) : (
{agents.map(agent => (
setSelectedAgent(agent)} > {/* Agent Header */}

{agent.name}

{agent.role}

{agent.status}
{/* Session Info */} {agent.session_key && (
{t('session')}: {agent.session_key}
)} {/* Task Stats */} {agent.taskStats && (
{agent.taskStats.total}
{t('totalTasks')}
{agent.taskStats.in_progress}
{t('inProgress')}
)} {/* Last Activity */}
{t('lastSeen')}: {formatLastSeen(agent.last_seen)}
{agent.last_activity && (
{t('activity')}: {agent.last_activity}
)}
{/* Quick Actions */}
))}
)}
{/* Agent Detail Modal */} {selectedAgent && ( setSelectedAgent(null)} onUpdate={fetchAgents} onStatusUpdate={updateAgentStatus} /> )} {/* Create Agent Modal */} {showCreateModal && ( setShowCreateModal(false)} onCreated={fetchAgents} /> )}
) } // Agent Detail Modal function AgentDetailModal({ agent, onClose, onUpdate, onStatusUpdate }: { agent: Agent onClose: () => void onUpdate: () => void onStatusUpdate: (name: string, status: Agent['status'], activity?: string) => Promise }) { const t = useTranslations('agentSquad') const [editing, setEditing] = useState(false) const [formData, setFormData] = useState({ role: agent.role, session_key: agent.session_key || '', soul_content: agent.soul_content || '', }) const handleSave = async () => { try { const response = await fetch('/api/agents', { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: agent.name, ...formData }) }) if (!response.ok) throw new Error(t('failedToUpdate')) setEditing(false) onUpdate() } catch (error) { log.error('Failed to update agent:', error) } } return (

{agent.name}

{agent.role}

{agent.status}
{/* Status Controls */}

{t('statusControl')}

{(['idle', 'busy', 'offline'] as const).map(status => ( ))}
{/* Agent Details */}
{editing ? ( setFormData(prev => ({ ...prev, role: e.target.value }))} className="w-full bg-gray-700 text-white rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" /> ) : (

{agent.role}

)}
{editing ? ( setFormData(prev => ({ ...prev, session_key: e.target.value }))} className="w-full bg-gray-700 text-white rounded px-3 py-2 focus:outline-none focus:ring-2 focus:ring-blue-500" /> ) : (

{agent.session_key || t('notSet')}

)}
{editing ? (