diff --git a/README.md b/README.md index 5003d86..fe2987e 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ## Description -Project Agora est une plateforme web open-source permettant à plusieurs intelligences artificielles de **collaborer entre elles** pour concevoir la structure complète d'un projet logiciel à partir d'un **prompt utilisateur** ou d'un **document explicatif**. +Project Agora est une plateforme web permettant à plusieurs intelligences artificielles de **collaborer** pour concevoir une architecture logicielle complète à partir d'une **description de projet** et optionnellement d'une **documentation contexte**. L'objectif est de produire : @@ -77,24 +77,17 @@ graph TD ## Fonctionnalités -### Deux modes de collaboration +### Conception Collaborative par IA -#### 1. **Mode Débat Classique** (Original) -- **4 agents spécialisés** qui débattent en parallèle : Architecte logiciel, Ingénieur backend, Ingénieur frontend, Designer UI/UX -- **Sélection automatique** des agents pertinents selon le contexte du projet -- **Débat collaboratif** : Les agents échangent et négocient pour converger vers la meilleure solution -- **Système de consensus** avec vote pondéré (l'architecte a une voix prépondérante) -- Résultats reçus simultanément - -#### 2. **Mode Conception Collaborative** (Nouveau 🚀) -- **7 agents spécialisés** : Architecte Lead, Ingénieur backend, Ingénieur frontend, Designer UI/UX, Ingénieur DevOps, Chef de produit, Spécialiste Sécurité -- **Création itérative** : L'Architecte Lead crée d'abord un document initial complet -- **Tours de table** : Chaque agent revoit séquentiellement le document et propose des améliorations -- **Document évolutif** : Le document s'améliore à chaque passage d'agent -- **Convergence naturelle** : Le processus continue jusqu'à ce qu'aucun agent ne propose de modifications -- **Traçabilité complète** : Historique complet de toutes les modifications avec justifications -- **Format flexible** : Support Markdown (.md) et texte brut (.txt) -- **Export facile** : Téléchargez le document final en format désiré +- **7 agents spécialisés** : Architecte, Backend Engineer, Frontend Engineer, UI Designer, DevOps Engineer, Product Manager, Security Specialist +- **Création itérative** : Lead Architect crée le document initial +- **Tours de table** : Chaque agent revoit et propose des améliorations +- **Document évolutif** : Amélioration progressive à chaque passage +- **Convergence naturelle** : Arrêt automatique quand tous les agents sont satisfaits +- **Traçabilité complète** : Historique de toutes les modifications +- **Format Markdown** : Output toujours en Markdown (.md) +- **Context files** : Support d'upload de fichiers MD/TXT en entrée (optionnel) +- **Network monitoring** : Indicateur temps réel de latence et qualité réseau ### Système multi-agents IA - **Intégration Mistral AI** pour génération de réponses intelligentes et contextuelles @@ -148,83 +141,57 @@ npm run dev --- -## Flux utilisateur +## Flux Utilisateur -### Mode Débat Classique ```mermaid sequenceDiagram participant User - participant Orchestrator - participant AI_Architect - participant AI_Designer - participant AI_Engineer - User->>Orchestrator: Prompt project - Orchestrator->>AI_Architect: Generate approach - Orchestrator->>AI_Designer: Discuss UI/UX - Orchestrator->>AI_Engineer: Suggest modules - AI_Architect-->>Orchestrator: Architecture proposal - AI_Designer-->>Orchestrator: Interface ideas - AI_Engineer-->>Orchestrator: Technical design - Orchestrator-->>User: Final structured response + diagram -``` - -### Mode Conception Collaborative -```mermaid -sequenceDiagram - participant User - participant Orchestrator - participant Lead_Architect + participant Backend participant Agents - User->>Orchestrator: Prompt project + format choice - Orchestrator->>Lead_Architect: Create initial document - Lead_Architect-->>Orchestrator: v1 Document - Orchestrator->>Agents: Review document Round 1 - Agents-->>Orchestrator: Modifications proposed - Orchestrator->>Agents: Review document Round 2 - Agents-->>Orchestrator: No changes OR more modifications - Orchestrator-->>User: Final document + full history + User->>Backend: Project description + optional context file + Backend->>Agents: Lead Architect creates initial document + Agents-->>Backend: Document v1 + Backend->>Agents: Round 1: Review and improve + Agents-->>Backend: Updates proposed + Backend->>Agents: Round 2-N: Review updated document + Agents-->>Backend: More updates OR no changes + Backend-->>User: Final Markdown document + history ``` --- -## Utilisation du Mode Conception Collaborative +## Utilisation ### Étapes -1. **Sélectionner le mode** : Cliquez sur "Collaborative Design" depuis l'écran d'accueil -2. **Décrire le projet** : Entrez une description détaillée de votre projet logiciel -3. **Configurer** : - - **Format du document** : Choisissez entre Markdown (.md) ou Texte brut (.txt) - - **Nombre d'agents** : 3 (Quick), 5 (Balanced), ou 7 (Comprehensive) -4. **Lancer la session** : Cliquez sur "Start Collaborative Design Session" -5. **Suivre la progression** : - - Visualisez le document en évolution en temps réel - - Consultez la timeline pour voir qui a fait quoi - - Lancez les tours de table avec le bouton "Next Review Round" -6. **Convergence automatique** : Le système arrête automatiquement quand tous les agents sont satisfaits -7. **Télécharger** : Exportez le document final en format choisi +1. **Décrire le projet** : Entrez une description détaillée +2. **Ajouter un contexte** (optionnel) : Upload un fichier MD ou TXT +3. **Sélectionner** : Nombre d'agents (3, 5, ou 7) +4. **Lancer** : Start Design Session +5. **Suivre** : + - Visualisez le document en temps réel + - Consultez la timeline + - Lancez les tours avec "Next Review Round" +6. **Résultat** : Document Markdown téléchargeable -### Exemple d'utilisation +### Exemple -**Prompt utilisateur** : +Entrée: ``` -Je veux créer une plateforme de gestion de projets collaboratifs en temps réel, -avec support pour les équipes distribuées. Fonctionnalités clés: gestion des tâches, -communication temps réel, partage de fichiers, intégrations externes. -Besoin de scalabilité pour 10,000+ utilisateurs simultanés. +Plateforme gestion projets temps réel, équipes distribuées, +gestion tâches, communication, partage fichiers, 10K+ users ``` -**Résultat** : -- **Round 1** : Lead Architect crée le document initial avec architecture générale -- **Round 2** : Backend Engineer revoit et ajoute détails API et base de données -- **Round 3** : Frontend Engineer améliore avec structure UI et composants -- **Round 4** : UI Designer ajoute guidelines UX et patterns -- **Round 5** : DevOps Engineer propose infrastructure et déploiement -- **Round 6** : Product Manager aligne avec besoins métier -- **Round 7** : Security Specialist ajoute mesures de sécurité -- **Convergence** : Plus aucune modification proposée ✓ +Processus: +- Round 1: Lead Architect - Architecture générale +- Round 2: Backend - APIs et base de données +- Round 3: Frontend - Structure UI +- Round 4: UI Designer - Guidelines UX +- Round 5: DevOps - Infrastructure +- Round 6: Product Manager - Besoins métier +- Round 7: Security - Mesures sécurité -Document final : Spécification architecturale complète et cohérente ! +Sortie: Spécification architecturale Markdown complète --- diff --git a/backend/src/db/schema.js b/backend/src/db/schema.js index 63a2e55..5f02f09 100644 --- a/backend/src/db/schema.js +++ b/backend/src/db/schema.js @@ -17,28 +17,6 @@ const db = new Database(dbPath); // Enable foreign keys db.pragma('foreign_keys = ON'); -// Create debates table (legacy, kept for backward compatibility) -db.exec(` - CREATE TABLE IF NOT EXISTS debates ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - prompt TEXT NOT NULL, - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - status TEXT CHECK(status IN ('ongoing', 'completed', 'failed')) DEFAULT 'ongoing' - ) -`); - -// Create responses table (legacy, kept for backward compatibility) -db.exec(` - CREATE TABLE IF NOT EXISTS responses ( - id INTEGER PRIMARY KEY AUTOINCREMENT, - debate_id INTEGER NOT NULL, - agent_role TEXT NOT NULL, - content TEXT NOT NULL, - timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - FOREIGN KEY (debate_id) REFERENCES debates(id) ON DELETE CASCADE - ) -`); - // Create collaborative sessions table db.exec(` CREATE TABLE IF NOT EXISTS collaborative_sessions ( diff --git a/backend/src/index.js b/backend/src/index.js index e548b67..75c3a29 100644 --- a/backend/src/index.js +++ b/backend/src/index.js @@ -7,9 +7,7 @@ import { WebSocketServer } from 'ws'; import rateLimit from 'express-rate-limit'; import { parse } from 'url'; import db from './db/schema.js'; -import debateRoutes from './routes/debate.js'; import collaborateRoutes from './routes/collaborate.js'; -import orchestrator from './services/orchestrator.js'; import collaborativeOrchestrator from './services/collaborativeOrchestrator.js'; dotenv.config(); @@ -38,21 +36,9 @@ app.use('/api', limiter); // WebSocket connection handling wss.on('connection', (ws, req) => { const { query } = parse(req.url, true); - const debateId = query.debateId ? parseInt(query.debateId) : null; const sessionId = query.sessionId ? parseInt(query.sessionId) : null; - console.log('New WebSocket connection established', - debateId ? `for debate ${debateId}` : sessionId ? `for session ${sessionId}` : ''); - - if (debateId) { - orchestrator.registerWSClient(debateId, ws); - - ws.send(JSON.stringify({ - type: 'connected', - debateId, - message: 'Connected to debate updates' - })); - } + console.log('WebSocket connection', sessionId ? `session ${sessionId}` : 'established'); if (sessionId) { collaborativeOrchestrator.registerWSClient(sessionId, ws); @@ -60,7 +46,7 @@ wss.on('connection', (ws, req) => { ws.send(JSON.stringify({ type: 'connected', sessionId, - message: 'Connected to collaborative session updates' + message: 'Connected to session' })); } @@ -69,16 +55,6 @@ wss.on('connection', (ws, req) => { const data = JSON.parse(message.toString()); console.log('Received:', data); - // Handle subscribe to debate - if (data.type === 'subscribe' && data.debateId) { - orchestrator.registerWSClient(parseInt(data.debateId), ws); - ws.send(JSON.stringify({ - type: 'subscribed', - debateId: data.debateId - })); - } - - // Handle subscribe to collaborative session if (data.type === 'subscribe' && data.sessionId) { collaborativeOrchestrator.registerWSClient(parseInt(data.sessionId), ws); ws.send(JSON.stringify({ @@ -92,22 +68,18 @@ wss.on('connection', (ws, req) => { }); ws.on('close', () => { - if (debateId) { - orchestrator.unregisterWSClient(debateId, ws); - } if (sessionId) { collaborativeOrchestrator.unregisterWSClient(sessionId, ws); } - console.log('WebSocket connection closed'); + console.log('WebSocket closed'); }); }); // Routes app.get('/api/health', (req, res) => { - res.json({ status: 'ok', message: 'Agora AI Backend is running' }); + res.json({ status: 'ok' }); }); -app.use('/api/debate', debateRoutes); app.use('/api/collaborate', collaborateRoutes); // Start server diff --git a/backend/src/routes/debate.js b/backend/src/routes/debate.js deleted file mode 100644 index 7555db3..0000000 --- a/backend/src/routes/debate.js +++ /dev/null @@ -1,95 +0,0 @@ -import express from 'express'; -import orchestrator from '../services/orchestrator.js'; - -const router = express.Router(); - -/** - * POST /api/debate - * Create a new debate and start AI discussion - */ -router.post('/', async (req, res) => { - try { - const { prompt } = req.body; - - if (!prompt || prompt.trim().length === 0) { - return res.status(400).json({ error: 'Prompt is required' }); - } - - const debateId = orchestrator.createDebate(prompt); - const agents = orchestrator.selectAgents(prompt); - - // Send immediate response - res.json({ - debateId, - prompt, - agents, - status: 'ongoing' - }); - - // Start debate asynchronously (don't wait for response) - orchestrator.startDebate(debateId, agents).catch(error => { - console.error('Debate failed:', error); - }); - - } catch (error) { - console.error('Error creating debate:', error); - res.status(500).json({ error: 'Failed to create debate' }); - } -}); - -/** - * GET /api/debate/:id - * Get debate details and responses - */ -router.get('/:id', (req, res) => { - try { - const debateId = parseInt(req.params.id); - const debate = orchestrator.getDebate(debateId); - - if (!debate) { - return res.status(404).json({ error: 'Debate not found' }); - } - - const responses = orchestrator.getDebateResponses(debateId); - - res.json({ - ...debate, - responses: responses.map(r => ({ - ...r, - content: JSON.parse(r.content) - })) - }); - } catch (error) { - console.error('Error fetching debate:', error); - res.status(500).json({ error: 'Failed to fetch debate' }); - } -}); - -/** - * POST /api/debate/:id/response - * Add a response to a debate - */ -router.post('/:id/response', (req, res) => { - try { - const debateId = parseInt(req.params.id); - const { agentRole, content } = req.body; - - if (!agentRole || !content) { - return res.status(400).json({ error: 'Agent role and content are required' }); - } - - const responseId = orchestrator.addResponse(debateId, agentRole, content); - - res.json({ - responseId, - debateId, - agentRole, - content - }); - } catch (error) { - console.error('Error adding response:', error); - res.status(500).json({ error: 'Failed to add response' }); - } -}); - -export default router; diff --git a/backend/src/services/orchestrator.js b/backend/src/services/orchestrator.js deleted file mode 100644 index 8a35aaa..0000000 --- a/backend/src/services/orchestrator.js +++ /dev/null @@ -1,236 +0,0 @@ -import db from '../db/schema.js'; -import { generateMultiAgentResponses } from './mistralClient.js'; - -class Orchestrator { - constructor() { - this.activeDebates = new Map(); - this.wsClients = new Map(); // debateId -> Set of WebSocket clients - } - - /** - * Register WebSocket client for a debate - */ - registerWSClient(debateId, ws) { - if (!this.wsClients.has(debateId)) { - this.wsClients.set(debateId, new Set()); - } - this.wsClients.get(debateId).add(ws); - } - - /** - * Unregister WebSocket client - */ - unregisterWSClient(debateId, ws) { - if (this.wsClients.has(debateId)) { - this.wsClients.get(debateId).delete(ws); - } - } - - /** - * Broadcast message to all clients watching a debate - */ - broadcast(debateId, message) { - if (this.wsClients.has(debateId)) { - const data = JSON.stringify(message); - this.wsClients.get(debateId).forEach(ws => { - if (ws.readyState === 1) { // OPEN - ws.send(data); - } - }); - } - } - - /** - * Create a new debate - */ - createDebate(prompt) { - const stmt = db.prepare('INSERT INTO debates (prompt, status) VALUES (?, ?)'); - const result = stmt.run(prompt, 'ongoing'); - - const debateId = result.lastInsertRowid; - this.activeDebates.set(debateId, { - id: debateId, - prompt, - responses: [], - startTime: Date.now() - }); - - return debateId; - } - - /** - * Get debate by ID - */ - getDebate(debateId) { - const stmt = db.prepare('SELECT * FROM debates WHERE id = ?'); - return stmt.get(debateId); - } - - /** - * Get all responses for a debate - */ - getDebateResponses(debateId) { - const stmt = db.prepare('SELECT * FROM responses WHERE debate_id = ? ORDER BY timestamp ASC'); - return stmt.all(debateId); - } - - /** - * Add a response to a debate - */ - addResponse(debateId, agentRole, content) { - const stmt = db.prepare( - 'INSERT INTO responses (debate_id, agent_role, content) VALUES (?, ?, ?)' - ); - const result = stmt.run(debateId, agentRole, JSON.stringify(content)); - - if (this.activeDebates.has(debateId)) { - this.activeDebates.get(debateId).responses.push({ - agentRole, - content, - timestamp: new Date() - }); - } - - return result.lastInsertRowid; - } - - /** - * Complete a debate - */ - completeDebate(debateId) { - const stmt = db.prepare('UPDATE debates SET status = ? WHERE id = ?'); - stmt.run('completed', debateId); - this.activeDebates.delete(debateId); - } - - /** - * Fail a debate - */ - failDebate(debateId) { - const stmt = db.prepare('UPDATE debates SET status = ? WHERE id = ?'); - stmt.run('failed', debateId); - this.activeDebates.delete(debateId); - } - - /** - * Select relevant agents based on prompt analysis - */ - selectAgents(prompt) { - const agents = ['architect']; - const lowerPrompt = prompt.toLowerCase(); - - // Analyze prompt for relevant expertise - if (lowerPrompt.includes('api') || lowerPrompt.includes('backend') || lowerPrompt.includes('database')) { - agents.push('backend_engineer'); - } - if (lowerPrompt.includes('ui') || lowerPrompt.includes('frontend') || lowerPrompt.includes('interface')) { - agents.push('frontend_engineer'); - } - if (lowerPrompt.includes('design') || lowerPrompt.includes('ux') || lowerPrompt.includes('user')) { - agents.push('designer'); - } - - // Always include at least architect and one engineer - if (agents.length === 1) { - agents.push('backend_engineer', 'frontend_engineer'); - } - - return agents; - } - - /** - * Start AI debate - trigger agents and collect responses - */ - async startDebate(debateId, agents) { - try { - const debate = this.getDebate(debateId); - if (!debate) { - throw new Error('Debate not found'); - } - - const prompt = debate.prompt; - const context = this.getDebateResponses(debateId); - - // Broadcast debate start - this.broadcast(debateId, { - type: 'debate_start', - debateId, - agents, - message: 'AI agents are analyzing your project...' - }); - - // Generate responses from all agents in parallel - const agentResponses = await generateMultiAgentResponses(agents, prompt, context); - - // Store responses and broadcast each one - for (const { agent, response } of agentResponses) { - const responseId = this.addResponse(debateId, agent, response); - - this.broadcast(debateId, { - type: 'agent_response', - debateId, - responseId, - agent, - response - }); - } - - // Calculate consensus - const consensus = this.calculateConsensus(agentResponses); - - // Complete debate - this.completeDebate(debateId); - - this.broadcast(debateId, { - type: 'debate_complete', - debateId, - consensus, - message: 'Debate completed successfully' - }); - - return { - responses: agentResponses, - consensus - }; - - } catch (error) { - console.error('Error in debate:', error); - this.failDebate(debateId); - - this.broadcast(debateId, { - type: 'debate_error', - debateId, - error: error.message - }); - - throw error; - } - } - - /** - * Calculate consensus from agent responses - */ - calculateConsensus(agentResponses) { - const proposals = agentResponses.map(({ agent, response }) => ({ - agent, - proposal: response.proposal, - confidence: response.confidence || 0.5 - })); - - // Weight by confidence and architect gets 1.5x weight - const totalWeight = proposals.reduce((sum, p) => { - const weight = p.agent === 'architect' ? 1.5 : 1.0; - return sum + (p.confidence * weight); - }, 0); - - const avgConfidence = totalWeight / proposals.length; - - return { - proposals, - averageConfidence: avgConfidence, - status: avgConfidence >= 0.6 ? 'consensus_reached' : 'needs_discussion' - }; - } -} - -export default new Orchestrator(); diff --git a/frontend/src/App.vue b/frontend/src/App.vue index d6f6d78..9056840 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -33,7 +33,7 @@ function startNewCollaboration() {
- Describe your software project. Multiple AI specialists will collaboratively - design the perfect architecture through iterative refinement. + Describe your software project. AI specialists collaboratively design + the architecture through iterative refinement.
💡 The more detailed your description, the better the AI collaboration.
+The more detailed your description, the better the AI collaboration.
How it works:
+Process:
{{ debate.prompt }}
-Proposal: {{ response.response.proposal }}
-Justification: {{ response.response.justification }}
-Confidence: {{ Math.round(response.response.confidence * 100) }}%
-{{ response.response.mermaid.code || response.response.mermaid }}
- AI agents are analyzing your project...
-Status: {{ consensus.status }}
-Average Confidence: {{ Math.round(consensus.averageConfidence * 100) }}%
-AI-Powered Software Architecture Design
- -{{ error }}
-