import { NextRequest, NextResponse } from 'next/server' import * as fs from 'fs/promises' import * as path from 'path' /** * Agent Management API * * GET - List all agents with their status and configuration * POST - Create a new agent (with SOUL file) */ const AGENT_CORE_PATH = process.env.AGENT_CORE_PATH || '/app/agent-core' const SOUL_PATH = path.join(AGENT_CORE_PATH, 'soul') interface AgentConfig { id: string name: string description: string soulFile: string color: string icon: string status: 'running' | 'paused' | 'stopped' | 'error' activeSessions: number totalProcessed: number avgResponseTime: number lastActivity: string version: string } interface AgentStats { totalSessions: number activeSessions: number totalMessages: number avgLatency: number errorRate: number memoryUsage: number } // Default agent configurations const defaultAgents: AgentConfig[] = [ { id: 'tutor-agent', name: 'TutorAgent', description: 'Lernbegleitung und Fragen beantworten', soulFile: 'tutor-agent.soul.md', color: '#3b82f6', icon: 'brain', status: 'running', activeSessions: 0, totalProcessed: 0, avgResponseTime: 0, lastActivity: new Date().toISOString(), version: '1.0.0' }, { id: 'grader-agent', name: 'GraderAgent', description: 'Klausur-Korrektur und Bewertung', soulFile: 'grader-agent.soul.md', color: '#10b981', icon: 'bot', status: 'running', activeSessions: 0, totalProcessed: 0, avgResponseTime: 0, lastActivity: new Date().toISOString(), version: '1.0.0' }, { id: 'quality-judge', name: 'QualityJudge', description: 'BQAS Qualitaetspruefung', soulFile: 'quality-judge.soul.md', color: '#f59e0b', icon: 'settings', status: 'running', activeSessions: 0, totalProcessed: 0, avgResponseTime: 0, lastActivity: new Date().toISOString(), version: '1.0.0' }, { id: 'alert-agent', name: 'AlertAgent', description: 'Monitoring und Benachrichtigungen', soulFile: 'alert-agent.soul.md', color: '#ef4444', icon: 'alert', status: 'running', activeSessions: 0, totalProcessed: 0, avgResponseTime: 0, lastActivity: new Date().toISOString(), version: '1.0.0' }, { id: 'orchestrator', name: 'Orchestrator', description: 'Task-Koordination und Routing', soulFile: 'orchestrator.soul.md', color: '#8b5cf6', icon: 'message', status: 'running', activeSessions: 0, totalProcessed: 0, avgResponseTime: 0, lastActivity: new Date().toISOString(), version: '1.0.0' } ] // Check if SOUL file exists async function checkSoulFile(filename: string): Promise { try { await fs.access(path.join(SOUL_PATH, filename)) return true } catch { return false } } // Get agent status from Redis/API (mock for now) async function getAgentStatus(agentId: string): Promise<{ status: 'running' | 'paused' | 'stopped' | 'error' activeSessions: number totalProcessed: number avgResponseTime: number lastActivity: string }> { // In production, query Redis/PostgreSQL for real stats // For now, return mock data with some variation const mockStats = { 'tutor-agent': { activeSessions: 12, totalProcessed: 1847, avgResponseTime: 234, lastActivity: '2 min ago' }, 'grader-agent': { activeSessions: 3, totalProcessed: 456, avgResponseTime: 1205, lastActivity: '5 min ago' }, 'quality-judge': { activeSessions: 8, totalProcessed: 3291, avgResponseTime: 89, lastActivity: '1 min ago' }, 'alert-agent': { activeSessions: 1, totalProcessed: 892, avgResponseTime: 45, lastActivity: '30 sec ago' }, 'orchestrator': { activeSessions: 24, totalProcessed: 8934, avgResponseTime: 12, lastActivity: 'just now' } } const stats = mockStats[agentId as keyof typeof mockStats] || { activeSessions: 0, totalProcessed: 0, avgResponseTime: 0, lastActivity: 'never' } return { status: 'running', ...stats } } // GET - List all agents export async function GET() { try { const agents: AgentConfig[] = [] for (const defaultAgent of defaultAgents) { const soulExists = await checkSoulFile(defaultAgent.soulFile) const status = await getAgentStatus(defaultAgent.id) agents.push({ ...defaultAgent, ...status, status: soulExists ? status.status : 'error' }) } // Also check for any additional SOUL files try { const soulFiles = await fs.readdir(SOUL_PATH) for (const file of soulFiles) { if (file.endsWith('.soul.md')) { const agentId = file.replace('.soul.md', '') if (!agents.find(a => a.id === agentId)) { const status = await getAgentStatus(agentId) agents.push({ id: agentId, name: agentId.split('-').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(''), description: 'Custom agent', soulFile: file, color: '#6b7280', icon: 'bot', version: '1.0.0', ...status }) } } } } catch { // SOUL directory doesn't exist or isn't accessible } // Calculate aggregate stats const stats: AgentStats = { totalSessions: agents.reduce((sum, a) => sum + a.totalProcessed, 0), activeSessions: agents.reduce((sum, a) => sum + a.activeSessions, 0), totalMessages: agents.reduce((sum, a) => sum + a.totalProcessed, 0) * 3, // estimate avgLatency: Math.round(agents.reduce((sum, a) => sum + a.avgResponseTime, 0) / agents.length), errorRate: 0.8, // mock memoryUsage: 67 // mock } return NextResponse.json({ agents, stats, timestamp: new Date().toISOString() }) } catch (error) { console.error('Error fetching agents:', error) return NextResponse.json( { error: error instanceof Error ? error.message : 'Failed to fetch agents' }, { status: 500 } ) } } // POST - Create new agent export async function POST(request: NextRequest) { try { const body = await request.json() const { id, name, description, soulContent, color, icon } = body if (!id || !name || !soulContent) { return NextResponse.json( { error: 'id, name, and soulContent are required' }, { status: 400 } ) } // Validate agent ID format if (!/^[a-z0-9-]+$/.test(id)) { return NextResponse.json( { error: 'Agent ID must contain only lowercase letters, numbers, and hyphens' }, { status: 400 } ) } const soulFile = `${id}.soul.md` const soulFilePath = path.join(SOUL_PATH, soulFile) // Check if agent already exists const exists = await checkSoulFile(soulFile) if (exists) { return NextResponse.json( { error: 'Agent with this ID already exists' }, { status: 409 } ) } // Create SOUL file await fs.writeFile(soulFilePath, soulContent, 'utf-8') const newAgent: AgentConfig = { id, name, description: description || '', soulFile, color: color || '#6b7280', icon: icon || 'bot', status: 'stopped', activeSessions: 0, totalProcessed: 0, avgResponseTime: 0, lastActivity: new Date().toISOString(), version: '1.0.0' } return NextResponse.json({ success: true, agent: newAgent, message: `Agent ${name} created successfully` }, { status: 201 }) } catch (error) { console.error('Error creating agent:', error) return NextResponse.json( { error: error instanceof Error ? error.message : 'Failed to create agent' }, { status: 500 } ) } }