import express from 'express'; import collaborativeOrchestrator from '../services/collaborativeOrchestrator.js'; const router = express.Router(); /** * POST /api/collaborate * Create a new collaborative session */ router.post('/', async (req, res) => { try { const { prompt, documentFormat = 'md', agentCount = 7 } = req.body; if (!prompt || prompt.trim().length === 0) { return res.status(400).json({ error: 'Prompt is required' }); } if (!['md', 'txt'].includes(documentFormat)) { return res.status(400).json({ error: 'Document format must be "md" or "txt"' }); } const sessionId = collaborativeOrchestrator.createSession( prompt, documentFormat, Math.min(agentCount, 7) ); const session = collaborativeOrchestrator.getSessionDetails(sessionId); res.json({ sessionId, prompt, documentFormat, status: 'created', agents: session.agents.map(a => a.role), message: 'Collaborative session created. Start the session to begin collaboration.' }); } catch (error) { console.error('Error creating collaborative session:', error); res.status(500).json({ error: 'Failed to create collaborative session' }); } }); /** * POST /api/collaborate/:id/start * Start the collaborative session (Lead Architect creates initial document) */ router.post('/:id/start', async (req, res) => { try { const sessionId = parseInt(req.params.id); const session = collaborativeOrchestrator.getSession(sessionId); if (!session) { return res.status(404).json({ error: 'Session not found' }); } if (session.status !== 'ongoing') { return res.status(400).json({ error: 'Session is not in ongoing status' }); } // Start the session asynchronously res.json({ sessionId, status: 'starting', message: 'Session is starting. Initial document is being created...' }); // Start asynchronously without waiting collaborativeOrchestrator.startCollaborativeSession(sessionId).catch(error => { console.error('Error starting collaborative session:', error); }); } catch (error) { console.error('Error starting collaborative session:', error); res.status(500).json({ error: 'Failed to start collaborative session' }); } }); /** * POST /api/collaborate/:id/round * Run the next round of reviews */ router.post('/:id/round', async (req, res) => { try { const sessionId = parseInt(req.params.id); const session = collaborativeOrchestrator.getSession(sessionId); if (!session) { return res.status(404).json({ error: 'Session not found' }); } if (session.status !== 'ongoing') { return res.status(400).json({ error: 'Session is not in ongoing status' }); } const activeSession = collaborativeOrchestrator.activeSessions.get(sessionId); if (!activeSession?.started) { return res.status(400).json({ error: 'Session has not been started yet' }); } // Run round asynchronously res.json({ sessionId, roundNumber: activeSession.currentRound + 1, status: 'running', message: 'Review round in progress...' }); // Run asynchronously without waiting collaborativeOrchestrator.runRound(sessionId).catch(error => { console.error('Error running round:', error); collaborativeOrchestrator.broadcast(sessionId, { type: 'round_error', sessionId, error: error.message }); }); } catch (error) { console.error('Error running round:', error); res.status(500).json({ error: 'Failed to run round' }); } }); /** * GET /api/collaborate/:id * Get session details with full history and current document */ router.get('/:id', (req, res) => { try { const sessionId = parseInt(req.params.id); const session = collaborativeOrchestrator.getSessionDetails(sessionId); if (!session) { return res.status(404).json({ error: 'Session not found' }); } res.json({ sessionId: session.id, initialPrompt: session.initial_prompt, documentFormat: session.document_format, status: session.status, createdAt: session.created_at, completedAt: session.completed_at, currentRound: session.currentRound, agents: session.agents.map(a => a.role), currentDocument: session.currentDocument, documentVersionCount: session.versions.length, conversationHistory: session.conversationHistory, versions: session.versions.map(v => ({ versionNumber: v.version_number, modifiedBy: v.modified_by, modificationReason: v.modification_reason, roundNumber: v.round_number, createdAt: v.created_at })) }); } catch (error) { console.error('Error fetching session details:', error); res.status(500).json({ error: 'Failed to fetch session details' }); } }); /** * GET /api/collaborate/:id/document * Get the current document */ router.get('/:id/document', (req, res) => { try { const sessionId = parseInt(req.params.id); const session = collaborativeOrchestrator.getSession(sessionId); if (!session) { return res.status(404).json({ error: 'Session not found' }); } const activeSession = collaborativeOrchestrator.activeSessions.get(sessionId); const currentDocument = activeSession?.currentDocument || ''; // Determine content type based on format const contentType = session.document_format === 'md' ? 'text/markdown; charset=utf-8' : 'text/plain; charset=utf-8'; res.set('Content-Type', contentType); res.send(currentDocument); } catch (error) { console.error('Error fetching document:', error); res.status(500).json({ error: 'Failed to fetch document' }); } }); /** * GET /api/collaborate/:id/versions/:versionNumber * Get a specific document version */ router.get('/:id/versions/:versionNumber', (req, res) => { try { const sessionId = parseInt(req.params.id); const versionNumber = parseInt(req.params.versionNumber); const session = collaborativeOrchestrator.getSession(sessionId); if (!session) { return res.status(404).json({ error: 'Session not found' }); } const versions = collaborativeOrchestrator.getDocumentVersions(sessionId); const version = versions.find(v => v.version_number === versionNumber); if (!version) { return res.status(404).json({ error: 'Version not found' }); } const contentType = session.document_format === 'md' ? 'text/markdown; charset=utf-8' : 'text/plain; charset=utf-8'; res.set('Content-Type', contentType); res.json({ versionNumber: version.version_number, modifiedBy: version.modified_by, modificationReason: version.modification_reason, roundNumber: version.round_number, createdAt: version.created_at, content: version.content }); } catch (error) { console.error('Error fetching version:', error); res.status(500).json({ error: 'Failed to fetch version' }); } }); /** * POST /api/collaborate/:id/complete * Complete the collaborative session */ router.post('/:id/complete', (req, res) => { try { const sessionId = parseInt(req.params.id); const session = collaborativeOrchestrator.getSession(sessionId); if (!session) { return res.status(404).json({ error: 'Session not found' }); } collaborativeOrchestrator.completeSession(sessionId); res.json({ sessionId, status: 'completed', message: 'Session completed successfully' }); } catch (error) { console.error('Error completing session:', error); res.status(500).json({ error: 'Failed to complete session' }); } }); export default router;