Compare commits

..

No commits in common. "0179bf75f2de8b9a9fc8a83a9db2437ecc2a3e3a" and "5a2ca101f8949b6058c288da5fd3eb06c980abf6" have entirely different histories.

7 changed files with 43 additions and 339 deletions

View File

@ -10,7 +10,7 @@ const router = express.Router()
*/ */
router.post('/', async (req, res) => { router.post('/', async (req, res) => {
try { try {
const { prompt, documentFormat = 'md', agentCount = 7, aiProvider = 'mistral' } = req.body const { prompt, documentFormat = 'md', agentCount = 7 } = req.body
if (!prompt || prompt.trim().length === 0) { if (!prompt || prompt.trim().length === 0) {
return res.status(400).json({ error: 'Prompt is required' }) return res.status(400).json({ error: 'Prompt is required' })
@ -20,18 +20,13 @@ router.post('/', async (req, res) => {
return res.status(400).json({ error: 'Document format must be "md" or "txt"' }) return res.status(400).json({ error: 'Document format must be "md" or "txt"' })
} }
if (!['mistral', 'claude'].includes(aiProvider)) {
return res.status(400).json({ error: 'AI provider must be "mistral" or "claude"' })
}
// Validate agent count // Validate agent count
const validAgentCount = Math.min(Math.max(agentCount, 3), 50) const validAgentCount = Math.min(Math.max(agentCount, 3), 50)
const sessionId = collaborativeOrchestrator.createSession( const sessionId = collaborativeOrchestrator.createSession(
prompt, prompt,
documentFormat, documentFormat,
validAgentCount, validAgentCount
aiProvider
) )
const sessionInfo = collaborativeOrchestrator.getSessionInfo(sessionId) const sessionInfo = collaborativeOrchestrator.getSessionInfo(sessionId)
@ -41,7 +36,6 @@ router.post('/', async (req, res) => {
prompt, prompt,
documentFormat, documentFormat,
agentCount: validAgentCount, agentCount: validAgentCount,
aiProvider,
status: 'created', status: 'created',
agents: sessionInfo.agents, agents: sessionInfo.agents,
message: 'Collaborative session created. Start the session to begin collaboration.' message: 'Collaborative session created. Start the session to begin collaboration.'

View File

@ -1,144 +0,0 @@
import dotenv from 'dotenv'
dotenv.config()
const CLAUDE_API_KEY = process.env.CLAUDE_API_KEY
const CLAUDE_API_URL = 'https://api.anthropic.com/v1/messages'
/**
* Generic AI prompt for collaborative document editing
*/
function getAgentPrompt(agentName) {
return `You are an AI assistant named ${agentName} collaborating on a technical document design.
Your responsibilities:
1. Review the current document structure
2. Either:
a) Modify ONE existing section (identified by #, ##, ###, #### headers), OR
b) Create a NEW section if you think it's needed, OR
c) Delete a section if you think it's redundant or not useful
3. Provide your thinking process and reasoning
4. Return ONLY the section (modified or new) with its header, or command to delete, or confirm it's good as-is
CRITICAL RULES - FOLLOW THESE EXACTLY:
- Work on exactly ONE section only
- NEVER return the entire document
- NEVER return multiple sections
- Return ONLY the section you're working on, not the whole document
- You CAN create a new section if document is missing important content
- You CAN delete a section if it's redundant, duplicate, or not useful
- To delete a section, respond: "DELETE: ## Section Name" (with exact header)
- If section is good, respond: "Section is good, no changes needed"
- Think step-by-step about what could be improved or removed
- Share your reasoning process
RESPONSE FORMAT - FOLLOW THIS EXACTLY:
THINKING: [Your analysis and reasoning about the current document]
DECISION: [Exactly what you will do: modify section X, create new section Y, delete section Z, or keep as-is]
SECTION:
[ONLY ONE: Either a markdown section starting with # or ##, a DELETE command, or the text "Section is good, no changes needed"]
EXAMPLE OF CORRECT RESPONSE:
THINKING: The Overview section is too brief and doesn't explain the main purpose.
DECISION: I will modify the Overview section to be more comprehensive.
SECTION:
## Overview
This is a technical document for designing system architecture...
EXAMPLE OF INCORRECT RESPONSE (DO NOT DO THIS):
[The entire document repeated here] <- WRONG!`
}
/**
* Call Claude API
*/
async function callClaudeAPI(messages) {
const response = await fetch(CLAUDE_API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': CLAUDE_API_KEY,
'anthropic-version': '2023-06-01'
},
body: JSON.stringify({
model: 'claude-3-5-sonnet-20241022',
max_tokens: 2048,
system: messages[0].content,
messages: messages.slice(1)
})
})
if (!response.ok) {
const error = await response.text()
throw new Error(`Claude API error: ${error}`)
}
return response
}
/**
* Generate agent response using Claude
*/
export async function generateAgentResponseSync(agentName, prompt, currentDocument = '') {
const systemPrompt = getAgentPrompt(agentName)
const messages = [
{ role: 'user', content: systemPrompt },
{ role: 'user', content: `Project description: ${prompt}\n\nCurrent document:\n${currentDocument}` }
]
try {
const response = await callClaudeAPI(messages)
const data = await response.json()
if (!data.content?.[0]?.text) {
throw new Error('Invalid response from Claude API')
}
return data.content[0].text
} catch (error) {
console.error(`Error generating response from ${agentName}:`, error)
return `Error: ${error.message}`
}
}
/**
* Extract section from AI response
* Validates that we get a proper section, not the entire document
*/
export function extractSection(aiResponse) {
const sectionMatch = aiResponse.match(/SECTION:\s*([\s\S]*?)(?:$)/)
if (sectionMatch) {
const extracted = sectionMatch[1].trim()
// Validate: extracted should be either:
// 1. A markdown section starting with # (DELETE: or "Section is good...")
// 2. OR a single section with < 5000 chars (not entire document)
const isMarkdownSection = /^(#|DELETE:|Section is good)/.test(extracted)
const isShortEnough = extracted.length < 5000 // Single section should be < 5KB
if (isMarkdownSection || isShortEnough) {
return extracted
}
}
// Fallback: if no SECTION: tag found, treat entire response as section
// but only if it starts with markdown header or is a command
if (/^(#|DELETE:|Section is good)/.test(aiResponse)) {
return aiResponse.trim()
}
// If none of the above, return error indicator
return "ERROR: Response does not contain a valid section format"
}
/**
* Extract thinking from AI response
*/
export function extractThinking(aiResponse) {
const thinkingMatch = aiResponse.match(/THINKING:\s*([\s\S]*?)(?:DECISION:|SECTION:)/)
if (thinkingMatch) {
return thinkingMatch[1].trim()
}
return ''
}

View File

@ -1,6 +1,5 @@
import db from '../db/schema.js' import db from '../db/schema.js'
import * as mistralClient from './mistralClient.js' import { generateAgentResponseSync, extractSection, extractThinking } from './mistralClient.js'
import * as claudeClient from './claudeClient.js'
import { getRandomNames } from './nameGenerator.js' import { getRandomNames } from './nameGenerator.js'
class CollaborativeOrchestrator { class CollaborativeOrchestrator {
@ -45,13 +44,13 @@ class CollaborativeOrchestrator {
/** /**
* Create a new collaborative session with N random-named agents * Create a new collaborative session with N random-named agents
*/ */
createSession(initialPrompt, documentFormat = 'md', agentCount = 7, aiProvider = 'mistral') { createSession(initialPrompt, documentFormat = 'md', agentCount = 7) {
const stmt = db.prepare( const stmt = db.prepare(
'INSERT INTO collaborative_sessions (initial_prompt, document_format, status) VALUES (?, ?, ?)' 'INSERT INTO collaborative_sessions (initial_prompt, document_format, status) VALUES (?, ?, ?)'
) )
const result = stmt.run(initialPrompt, documentFormat, 'created') const result = stmt.run(initialPrompt, documentFormat, 'created')
const sessionId = result.lastInsertRowid const sessionId = result.lastInsertRowid
console.log(`[Session ${sessionId}] Created with ${agentCount} agents, format: ${documentFormat}, provider: ${aiProvider}`) console.log(`[Session ${sessionId}] Created with ${agentCount} agents, format: ${documentFormat}`)
// Generate random names for agents // Generate random names for agents
const agentNames = getRandomNames(Math.min(agentCount, 50)) const agentNames = getRandomNames(Math.min(agentCount, 50))
@ -60,7 +59,6 @@ class CollaborativeOrchestrator {
id: sessionId, id: sessionId,
initialPrompt, initialPrompt,
documentFormat, documentFormat,
aiProvider, // Claude or Mistral
agents: agentNames, // Array of agent names agents: agentNames, // Array of agent names
agentCount, agentCount,
currentAgentIndex: 0, currentAgentIndex: 0,
@ -181,15 +179,14 @@ class CollaborativeOrchestrator {
try { try {
console.log(`[Session ${sessionId}] ${agentName} analyzing and generating response...`) console.log(`[Session ${sessionId}] ${agentName} analyzing and generating response...`)
const client = session.aiProvider === 'claude' ? claudeClient : mistralClient const response = await generateAgentResponseSync(
const response = await client.generateAgentResponseSync(
agentName, agentName,
session.initialPrompt, session.initialPrompt,
session.currentDocument // <-- This is always the latest version session.currentDocument // <-- This is always the latest version
) )
const thinking = client.extractThinking(response) const thinking = extractThinking(response)
const section = client.extractSection(response) const section = extractSection(response)
console.log(`[Session ${sessionId}] ${agentName} response received (${response.length} chars)`) console.log(`[Session ${sessionId}] ${agentName} response received (${response.length} chars)`)
console.log(`[Session ${sessionId}] --- THINKING (${agentName}) ---`) console.log(`[Session ${sessionId}] --- THINKING (${agentName}) ---`)

View File

@ -9,23 +9,24 @@ const collaborationStore = useCollaborationStore()
const prompt = ref('') const prompt = ref('')
const contextFile = ref(null) const contextFile = ref(null)
const agentCount = ref(7) const agentCount = ref(7)
const aiProvider = ref('mistral')
const documentFormat = ref('md')
const isCreating = ref(false) const isCreating = ref(false)
const previousSessions = ref([])
const loadingPreviousSessions = ref(false)
const showAllSessions = ref(false) const showAllSessions = ref(false)
const showArchives = ref(false)
const sessionStatusFilter = ref('all') // 'all', 'completed', 'ongoing', 'created' const sessionStatusFilter = ref('all') // 'all', 'completed', 'ongoing', 'created'
const searchQuery = ref('') const searchQuery = ref('')
const isFetchingSessions = ref(false)
onMounted(async () => { onMounted(async () => {
if (collaborationStore.sessionsLoaded.value) return loadingPreviousSessions.value = true
isFetchingSessions.value = true
try { try {
await collaborationStore.fetchSessions() const response = await fetch('/api/collaborate')
const data = await response.json()
previousSessions.value = data.sessions || []
} catch (error) { } catch (error) {
console.error('Error loading previous sessions:', error) console.error('Error loading previous sessions:', error)
} finally { } finally {
isFetchingSessions.value = false loadingPreviousSessions.value = false
} }
}) })
@ -33,8 +34,6 @@ const handleOpenSession = (sessionId) => {
emit('session-created', { sessionId }) emit('session-created', { sessionId })
} }
const sessions = computed(() => collaborationStore.sessions.value)
const agentOptions = computed(() => { const agentOptions = computed(() => {
return Array.from({ length: 48 }, (_, i) => ({ return Array.from({ length: 48 }, (_, i) => ({
value: i + 3, value: i + 3,
@ -43,7 +42,7 @@ const agentOptions = computed(() => {
}) })
const filteredSessions = computed(() => { const filteredSessions = computed(() => {
let filtered = sessions.value let filtered = previousSessions.value
if (sessionStatusFilter.value !== 'all') { if (sessionStatusFilter.value !== 'all') {
filtered = filtered.filter(s => s.status === sessionStatusFilter.value) filtered = filtered.filter(s => s.status === sessionStatusFilter.value)
@ -65,11 +64,11 @@ const displayedSessions = computed(() => {
}) })
const completedCount = computed(() => { const completedCount = computed(() => {
return sessions.value.filter(s => s.status === 'completed').length return previousSessions.value.filter(s => s.status === 'completed').length
}) })
const ongoingCount = computed(() => { const ongoingCount = computed(() => {
return sessions.value.filter(s => s.status === 'ongoing').length return previousSessions.value.filter(s => s.status === 'ongoing').length
}) })
const handleFileSelect = (event) => { const handleFileSelect = (event) => {
@ -108,9 +107,8 @@ const handleCreateSession = async () => {
// Always use 'md' format for output // Always use 'md' format for output
const session = await collaborationStore.createSession( const session = await collaborationStore.createSession(
finalPrompt, finalPrompt,
documentFormat.value, 'md',
agentCount.value, agentCount.value
aiProvider.value
) )
emit('session-created', session) emit('session-created', session)
@ -119,8 +117,6 @@ const handleCreateSession = async () => {
prompt.value = '' prompt.value = ''
contextFile.value = null contextFile.value = null
agentCount.value = 7 agentCount.value = 7
aiProvider.value = 'mistral'
documentFormat.value = 'md'
} catch (error) { } catch (error) {
alert(`Error creating session: ${collaborationStore.error}`) alert(`Error creating session: ${collaborationStore.error}`)
} finally { } finally {
@ -151,11 +147,7 @@ const removeFile = () => {
</header> </header>
<!-- Quick Access Section --> <!-- Quick Access Section -->
<div v-if="isFetchingSessions" class="loading-sessions"> <div v-if="previousSessions.length > 0" class="quick-access-section">
Loading previous sessions...
</div>
<div v-else-if="sessions.length > 0" class="quick-access-section">
<div class="stats-bar"> <div class="stats-bar">
<div class="stat"> <div class="stat">
<span class="stat-label">Completed</span> <span class="stat-label">Completed</span>
@ -167,7 +159,7 @@ const removeFile = () => {
</div> </div>
<div class="stat"> <div class="stat">
<span class="stat-label">Total</span> <span class="stat-label">Total</span>
<span class="stat-value">{{ sessions.length }}</span> <span class="stat-value">{{ previousSessions.length }}</span>
</div> </div>
</div> </div>
@ -188,7 +180,7 @@ const removeFile = () => {
class="filter-btn" class="filter-btn"
:class="{ active: sessionStatusFilter === 'all' }" :class="{ active: sessionStatusFilter === 'all' }"
> >
All Sessions ({{ sessions.length }}) All Sessions ({{ previousSessions.length }})
</button> </button>
<button <button
@click="sessionStatusFilter = 'completed'" @click="sessionStatusFilter = 'completed'"
@ -242,7 +234,7 @@ const removeFile = () => {
</div> </div>
<!-- Divider --> <!-- Divider -->
<div v-if="sessions.length > 0" class="divider"> <div v-if="previousSessions.length > 0" class="divider">
<span>Or start a new session</span> <span>Or start a new session</span>
</div> </div>
@ -298,7 +290,7 @@ const removeFile = () => {
<p class="hint">Optional: Provide existing documentation or requirements to guide the design.</p> <p class="hint">Optional: Provide existing documentation or requirements to guide the design.</p>
</div> </div>
<!-- Agent Count and AI Provider Selection --> <!-- Agent Count Selection -->
<div class="form-grid"> <div class="form-grid">
<div class="form-group"> <div class="form-group">
<label for="agents" class="label">Number of AI Specialists</label> <label for="agents" class="label">Number of AI Specialists</label>
@ -309,22 +301,6 @@ const removeFile = () => {
</select> </select>
<p class="hint">More agents = more diverse perspectives.</p> <p class="hint">More agents = more diverse perspectives.</p>
</div> </div>
<div class="form-group">
<label for="provider" class="label">AI Provider</label>
<select v-model="aiProvider" id="provider" class="select">
<option value="mistral">Mistral (Large 2411)</option>
<option value="claude">Claude (3.5 Sonnet)</option>
</select>
<p class="hint">Choose the AI model for specialists.</p>
</div>
<div class="form-group">
<label for="format" class="label">Document Format</label>
<select v-model="documentFormat" id="format" class="select">
<option value="md">Markdown (.md)</option>
<option value="txt">Plain Text (.txt)</option>
</select>
<p class="hint">Markdown recommended for structured documents.</p>
</div>
</div> </div>
<!-- Info Box --> <!-- Info Box -->
@ -637,17 +613,6 @@ const removeFile = () => {
cursor: not-allowed; cursor: not-allowed;
} }
.loading-sessions {
margin-bottom: 2rem;
padding: 1rem;
text-align: center;
color: rgba(255, 255, 255, 0.7);
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: 12px;
backdrop-filter: blur(8px);
}
.file-input-wrapper { .file-input-wrapper {
position: relative; position: relative;
margin-bottom: 1rem; margin-bottom: 1rem;

View File

@ -80,19 +80,11 @@ const handleWebSocketMessage = (message) => {
if (message.type === 'initial_document_created') { if (message.type === 'initial_document_created') {
sessionStarted.value = true sessionStarted.value = true
collaborationStore.currentDocument = message.content collaborationStore.currentDocument = message.content
collaborationStore.currentRound = 0
if (collaborationStore.currentSession) {
collaborationStore.currentSession.status = 'ongoing'
collaborationStore.currentSession.currentDocument = message.content
}
currentWorkingAgent.value = null currentWorkingAgent.value = null
currentAgentThinking.value = '' currentAgentThinking.value = ''
scheduleNextRound(2000) scheduleNextRound(2000)
} else if (message.type === 'document_modified') { } else if (message.type === 'document_modified') {
collaborationStore.currentDocument = message.content collaborationStore.currentDocument = message.content
if (collaborationStore.currentSession) {
collaborationStore.currentSession.currentDocument = message.content
}
} else if (message.type === 'agent_working') { } else if (message.type === 'agent_working') {
currentWorkingAgent.value = message.agentName currentWorkingAgent.value = message.agentName
currentAgentThinking.value = '' currentAgentThinking.value = ''
@ -100,17 +92,11 @@ const handleWebSocketMessage = (message) => {
currentAgentThinking.value = message.thinking || '' currentAgentThinking.value = message.thinking || ''
} else if (message.type === 'round_complete') { } else if (message.type === 'round_complete') {
isRunningRound.value = false isRunningRound.value = false
const roundEntry = { collaborationStore.conversationHistory.push({
roundNumber: message.roundNumber, roundNumber: message.roundNumber,
agentsMadeChanges: message.agentsMadeChanges, agentsMadeChanges: message.agentsMadeChanges,
timestamp: Date.now() timestamp: Date.now()
} })
collaborationStore.conversationHistory.push(roundEntry)
if (collaborationStore.currentSession) {
const history = collaborationStore.currentSession.conversationHistory || []
collaborationStore.currentSession.conversationHistory = [...history, roundEntry]
}
collaborationStore.currentRound = message.roundNumber
currentWorkingAgent.value = null currentWorkingAgent.value = null
currentAgentThinking.value = '' currentAgentThinking.value = ''
@ -130,9 +116,6 @@ const handleWebSocketMessage = (message) => {
} else if (message.type === 'session_completed') { } else if (message.type === 'session_completed') {
currentWorkingAgent.value = null currentWorkingAgent.value = null
isAutoRunning.value = false isAutoRunning.value = false
if (collaborationStore.currentSession) {
collaborationStore.currentSession.status = 'completed'
}
} }
} }
@ -254,10 +237,6 @@ function formatAgentName(agent) {
<span class="hand"></span> <span class="hand"></span>
</div> </div>
<div class="agent-name-working">{{ formatAgentName(currentWorkingAgent) }}</div> <div class="agent-name-working">{{ formatAgentName(currentWorkingAgent) }}</div>
<div class="agent-thinking">
<span v-if="currentAgentThinking">{{ currentAgentThinking }}</span>
<span v-else>Analyzing the document...</span>
</div>
</div> </div>
<!-- Convergence Message --> <!-- Convergence Message -->
@ -482,16 +461,6 @@ function formatAgentName(agent) {
font-weight: 600; font-weight: 600;
} }
.agent-thinking {
flex: 1;
font-size: 0.95rem;
color: rgba(255, 255, 255, 0.75);
background: rgba(102, 126, 234, 0.08);
border-radius: 12px;
padding: 0.75rem 1rem;
line-height: 1.4;
}
.convergence-message { .convergence-message {
display: flex; display: flex;
align-items: center; align-items: center;

View File

@ -1,8 +1,7 @@
<script setup> <script setup>
import { computed, onMounted, watch, ref, nextTick } from 'vue' import { computed } from 'vue'
import { marked } from 'marked' import { marked } from 'marked'
import hljs from 'highlight.js' import hljs from 'highlight.js'
import mermaid from 'mermaid'
const props = defineProps({ const props = defineProps({
document: { document: {
@ -24,28 +23,22 @@ marked.setOptions({
const renderer = new marked.Renderer() const renderer = new marked.Renderer()
// Configure mermaid once // Override code block rendering to add syntax highlighting
mermaid.initialize({
startOnLoad: false,
theme: 'dark',
securityLevel: 'loose'
})
// Override code block rendering to handle Mermaid and syntax highlighting
renderer.code = ({ text, lang }) => { renderer.code = ({ text, lang }) => {
if ((lang || '').toLowerCase() === 'mermaid') { const language = lang || 'plain'
return `<div class="mermaid">${text}</div>` let highlighted = text
if (hljs.getLanguage(language)) {
highlighted = hljs.highlight(text, { language }).value
} else {
highlighted = hljs.highlight(text, { language: 'plain' }).value
} }
const language = lang && hljs.getLanguage(lang) ? lang : 'plaintext'
const highlighted = hljs.highlight(text, { language }).value
return `<pre><code class="hljs language-${language}">${highlighted}</code></pre>` return `<pre><code class="hljs language-${language}">${highlighted}</code></pre>`
} }
marked.setOptions({ renderer }) marked.setOptions({ renderer })
const containerRef = ref(null)
const renderedContent = computed(() => { const renderedContent = computed(() => {
if (!props.document) { if (!props.document) {
return '<p class="empty-state">No document content yet. Start the session to begin collaboration.</p>' return '<p class="empty-state">No document content yet. Start the session to begin collaboration.</p>'
@ -64,40 +57,18 @@ const renderedContent = computed(() => {
return `<pre><code>${escaped}</code></pre>` return `<pre><code>${escaped}</code></pre>`
} }
}) })
async function renderMermaid() {
await nextTick()
if (!containerRef.value) return
const nodes = containerRef.value.querySelectorAll('.mermaid')
if (!nodes.length) return
try {
await mermaid.run({ nodes })
} catch (error) {
console.error('Mermaid render error:', error)
}
}
onMounted(() => {
renderMermaid()
})
watch(() => [props.document, props.format], () => {
renderMermaid()
})
</script> </script>
<template> <template>
<div class="document-viewer"> <div class="document-viewer">
<div class="document-container" :class="`format-${format}`"> <div class="document-container" :class="`format-${format}`">
<div ref="containerRef" v-html="renderedContent" class="document-content"></div> <div v-html="renderedContent" class="document-content"></div>
</div> </div>
</div> </div>
</template> </template>
<style scoped> <style scoped>
@import 'highlight.js/styles/atom-one-dark.css'; :import 'highlight.js/styles/atom-one-dark.css';
.document-viewer { .document-viewer {
width: 100%; width: 100%;

View File

@ -9,40 +9,13 @@ export const useCollaborationStore = defineStore('collaboration', () => {
const currentDocument = ref('') const currentDocument = ref('')
const currentRound = ref(0) const currentRound = ref(0)
const conversationHistory = ref([]) const conversationHistory = ref([])
const sessionsLoaded = ref(false)
const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000' const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000'
/**
* Fetch recent collaborative sessions
*/
async function fetchSessions() {
if (loading.value) return
loading.value = true
error.value = null
try {
const response = await fetch(`${API_URL}/api/collaborate`)
if (!response.ok) {
throw new Error('Failed to fetch sessions')
}
const data = await response.json()
sessions.value = data.sessions || []
sessionsLoaded.value = true
return sessions.value
} catch (err) {
error.value = err.message
throw err
} finally {
loading.value = false
}
}
/** /**
* Create a new collaborative session * Create a new collaborative session
*/ */
async function createSession(prompt, documentFormat = 'md', agentCount = 7, aiProvider = 'mistral') { async function createSession(prompt, documentFormat = 'md', agentCount = 7) {
loading.value = true loading.value = true
error.value = null error.value = null
@ -55,8 +28,7 @@ export const useCollaborationStore = defineStore('collaboration', () => {
body: JSON.stringify({ body: JSON.stringify({
prompt, prompt,
documentFormat, documentFormat,
agentCount, agentCount
aiProvider
}) })
}) })
@ -66,8 +38,7 @@ export const useCollaborationStore = defineStore('collaboration', () => {
const data = await response.json() const data = await response.json()
currentSession.value = data currentSession.value = data
sessions.value = [data, ...sessions.value.filter(s => s.sessionId !== data.sessionId)] sessions.value.unshift(data)
sessionsLoaded.value = true
return data return data
} catch (err) { } catch (err) {
@ -181,24 +152,7 @@ export const useCollaborationStore = defineStore('collaboration', () => {
throw new Error('Failed to complete session') throw new Error('Failed to complete session')
} }
const data = await response.json() return await response.json()
if (currentSession.value && currentSession.value.sessionId === sessionId) {
currentSession.value = {
...currentSession.value,
status: 'completed',
completedAt: new Date().toISOString()
}
}
sessions.value = sessions.value.map(session => {
if (session.sessionId === sessionId) {
return { ...session, status: 'completed', completedAt: new Date().toISOString() }
}
return session
})
return data
} catch (err) { } catch (err) {
error.value = err.message error.value = err.message
throw err throw err
@ -236,13 +190,11 @@ export const useCollaborationStore = defineStore('collaboration', () => {
return { return {
currentSession, currentSession,
sessions, sessions,
sessionsLoaded,
loading, loading,
error, error,
currentDocument, currentDocument,
currentRound, currentRound,
conversationHistory, conversationHistory,
fetchSessions,
createSession, createSession,
startSession, startSession,
runRound, runRound,