Update et upgrade by codex
This commit is contained in:
parent
130e21c867
commit
0179bf75f2
@ -10,24 +10,22 @@ const prompt = ref('')
|
||||
const contextFile = ref(null)
|
||||
const agentCount = ref(7)
|
||||
const aiProvider = ref('mistral')
|
||||
const documentFormat = ref('md')
|
||||
const isCreating = ref(false)
|
||||
const previousSessions = ref([])
|
||||
const loadingPreviousSessions = ref(false)
|
||||
const showAllSessions = ref(false)
|
||||
const showArchives = ref(false)
|
||||
const sessionStatusFilter = ref('all') // 'all', 'completed', 'ongoing', 'created'
|
||||
const searchQuery = ref('')
|
||||
const isFetchingSessions = ref(false)
|
||||
|
||||
onMounted(async () => {
|
||||
loadingPreviousSessions.value = true
|
||||
if (collaborationStore.sessionsLoaded.value) return
|
||||
isFetchingSessions.value = true
|
||||
try {
|
||||
const response = await fetch('/api/collaborate')
|
||||
const data = await response.json()
|
||||
previousSessions.value = data.sessions || []
|
||||
await collaborationStore.fetchSessions()
|
||||
} catch (error) {
|
||||
console.error('Error loading previous sessions:', error)
|
||||
} finally {
|
||||
loadingPreviousSessions.value = false
|
||||
isFetchingSessions.value = false
|
||||
}
|
||||
})
|
||||
|
||||
@ -35,6 +33,8 @@ const handleOpenSession = (sessionId) => {
|
||||
emit('session-created', { sessionId })
|
||||
}
|
||||
|
||||
const sessions = computed(() => collaborationStore.sessions.value)
|
||||
|
||||
const agentOptions = computed(() => {
|
||||
return Array.from({ length: 48 }, (_, i) => ({
|
||||
value: i + 3,
|
||||
@ -43,7 +43,7 @@ const agentOptions = computed(() => {
|
||||
})
|
||||
|
||||
const filteredSessions = computed(() => {
|
||||
let filtered = previousSessions.value
|
||||
let filtered = sessions.value
|
||||
|
||||
if (sessionStatusFilter.value !== 'all') {
|
||||
filtered = filtered.filter(s => s.status === sessionStatusFilter.value)
|
||||
@ -65,11 +65,11 @@ const displayedSessions = computed(() => {
|
||||
})
|
||||
|
||||
const completedCount = computed(() => {
|
||||
return previousSessions.value.filter(s => s.status === 'completed').length
|
||||
return sessions.value.filter(s => s.status === 'completed').length
|
||||
})
|
||||
|
||||
const ongoingCount = computed(() => {
|
||||
return previousSessions.value.filter(s => s.status === 'ongoing').length
|
||||
return sessions.value.filter(s => s.status === 'ongoing').length
|
||||
})
|
||||
|
||||
const handleFileSelect = (event) => {
|
||||
@ -108,7 +108,7 @@ const handleCreateSession = async () => {
|
||||
// Always use 'md' format for output
|
||||
const session = await collaborationStore.createSession(
|
||||
finalPrompt,
|
||||
'md',
|
||||
documentFormat.value,
|
||||
agentCount.value,
|
||||
aiProvider.value
|
||||
)
|
||||
@ -120,6 +120,7 @@ const handleCreateSession = async () => {
|
||||
contextFile.value = null
|
||||
agentCount.value = 7
|
||||
aiProvider.value = 'mistral'
|
||||
documentFormat.value = 'md'
|
||||
} catch (error) {
|
||||
alert(`Error creating session: ${collaborationStore.error}`)
|
||||
} finally {
|
||||
@ -150,7 +151,11 @@ const removeFile = () => {
|
||||
</header>
|
||||
|
||||
<!-- Quick Access Section -->
|
||||
<div v-if="previousSessions.length > 0" class="quick-access-section">
|
||||
<div v-if="isFetchingSessions" class="loading-sessions">
|
||||
Loading previous sessions...
|
||||
</div>
|
||||
|
||||
<div v-else-if="sessions.length > 0" class="quick-access-section">
|
||||
<div class="stats-bar">
|
||||
<div class="stat">
|
||||
<span class="stat-label">Completed</span>
|
||||
@ -162,7 +167,7 @@ const removeFile = () => {
|
||||
</div>
|
||||
<div class="stat">
|
||||
<span class="stat-label">Total</span>
|
||||
<span class="stat-value">{{ previousSessions.length }}</span>
|
||||
<span class="stat-value">{{ sessions.length }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -183,7 +188,7 @@ const removeFile = () => {
|
||||
class="filter-btn"
|
||||
:class="{ active: sessionStatusFilter === 'all' }"
|
||||
>
|
||||
All Sessions ({{ previousSessions.length }})
|
||||
All Sessions ({{ sessions.length }})
|
||||
</button>
|
||||
<button
|
||||
@click="sessionStatusFilter = 'completed'"
|
||||
@ -237,7 +242,7 @@ const removeFile = () => {
|
||||
</div>
|
||||
|
||||
<!-- Divider -->
|
||||
<div v-if="previousSessions.length > 0" class="divider">
|
||||
<div v-if="sessions.length > 0" class="divider">
|
||||
<span>Or start a new session</span>
|
||||
</div>
|
||||
|
||||
@ -312,6 +317,14 @@ const removeFile = () => {
|
||||
</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>
|
||||
|
||||
<!-- Info Box -->
|
||||
@ -624,6 +637,17 @@ const removeFile = () => {
|
||||
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 {
|
||||
position: relative;
|
||||
margin-bottom: 1rem;
|
||||
|
||||
@ -80,11 +80,19 @@ const handleWebSocketMessage = (message) => {
|
||||
if (message.type === 'initial_document_created') {
|
||||
sessionStarted.value = true
|
||||
collaborationStore.currentDocument = message.content
|
||||
collaborationStore.currentRound = 0
|
||||
if (collaborationStore.currentSession) {
|
||||
collaborationStore.currentSession.status = 'ongoing'
|
||||
collaborationStore.currentSession.currentDocument = message.content
|
||||
}
|
||||
currentWorkingAgent.value = null
|
||||
currentAgentThinking.value = ''
|
||||
scheduleNextRound(2000)
|
||||
} else if (message.type === 'document_modified') {
|
||||
collaborationStore.currentDocument = message.content
|
||||
if (collaborationStore.currentSession) {
|
||||
collaborationStore.currentSession.currentDocument = message.content
|
||||
}
|
||||
} else if (message.type === 'agent_working') {
|
||||
currentWorkingAgent.value = message.agentName
|
||||
currentAgentThinking.value = ''
|
||||
@ -92,11 +100,17 @@ const handleWebSocketMessage = (message) => {
|
||||
currentAgentThinking.value = message.thinking || ''
|
||||
} else if (message.type === 'round_complete') {
|
||||
isRunningRound.value = false
|
||||
collaborationStore.conversationHistory.push({
|
||||
const roundEntry = {
|
||||
roundNumber: message.roundNumber,
|
||||
agentsMadeChanges: message.agentsMadeChanges,
|
||||
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
|
||||
currentAgentThinking.value = ''
|
||||
|
||||
@ -116,6 +130,9 @@ const handleWebSocketMessage = (message) => {
|
||||
} else if (message.type === 'session_completed') {
|
||||
currentWorkingAgent.value = null
|
||||
isAutoRunning.value = false
|
||||
if (collaborationStore.currentSession) {
|
||||
collaborationStore.currentSession.status = 'completed'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -237,6 +254,10 @@ function formatAgentName(agent) {
|
||||
<span class="hand">✋</span>
|
||||
</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>
|
||||
|
||||
<!-- Convergence Message -->
|
||||
@ -461,6 +482,16 @@ function formatAgentName(agent) {
|
||||
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 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { computed, onMounted, watch, ref, nextTick } from 'vue'
|
||||
import { marked } from 'marked'
|
||||
import hljs from 'highlight.js'
|
||||
import mermaid from 'mermaid'
|
||||
|
||||
const props = defineProps({
|
||||
document: {
|
||||
@ -23,22 +24,28 @@ marked.setOptions({
|
||||
|
||||
const renderer = new marked.Renderer()
|
||||
|
||||
// Override code block rendering to add syntax highlighting
|
||||
renderer.code = ({ text, lang }) => {
|
||||
const language = lang || 'plain'
|
||||
let highlighted = text
|
||||
// Configure mermaid once
|
||||
mermaid.initialize({
|
||||
startOnLoad: false,
|
||||
theme: 'dark',
|
||||
securityLevel: 'loose'
|
||||
})
|
||||
|
||||
if (hljs.getLanguage(language)) {
|
||||
highlighted = hljs.highlight(text, { language }).value
|
||||
} else {
|
||||
highlighted = hljs.highlight(text, { language: 'plain' }).value
|
||||
// Override code block rendering to handle Mermaid and syntax highlighting
|
||||
renderer.code = ({ text, lang }) => {
|
||||
if ((lang || '').toLowerCase() === 'mermaid') {
|
||||
return `<div class="mermaid">${text}</div>`
|
||||
}
|
||||
|
||||
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>`
|
||||
}
|
||||
|
||||
marked.setOptions({ renderer })
|
||||
|
||||
const containerRef = ref(null)
|
||||
|
||||
const renderedContent = computed(() => {
|
||||
if (!props.document) {
|
||||
return '<p class="empty-state">No document content yet. Start the session to begin collaboration.</p>'
|
||||
@ -57,18 +64,40 @@ const renderedContent = computed(() => {
|
||||
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>
|
||||
|
||||
<template>
|
||||
<div class="document-viewer">
|
||||
<div class="document-container" :class="`format-${format}`">
|
||||
<div v-html="renderedContent" class="document-content"></div>
|
||||
<div ref="containerRef" v-html="renderedContent" class="document-content"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
:import 'highlight.js/styles/atom-one-dark.css';
|
||||
@import 'highlight.js/styles/atom-one-dark.css';
|
||||
|
||||
.document-viewer {
|
||||
width: 100%;
|
||||
|
||||
@ -9,9 +9,36 @@ export const useCollaborationStore = defineStore('collaboration', () => {
|
||||
const currentDocument = ref('')
|
||||
const currentRound = ref(0)
|
||||
const conversationHistory = ref([])
|
||||
const sessionsLoaded = ref(false)
|
||||
|
||||
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
|
||||
*/
|
||||
@ -39,7 +66,8 @@ export const useCollaborationStore = defineStore('collaboration', () => {
|
||||
|
||||
const data = await response.json()
|
||||
currentSession.value = data
|
||||
sessions.value.unshift(data)
|
||||
sessions.value = [data, ...sessions.value.filter(s => s.sessionId !== data.sessionId)]
|
||||
sessionsLoaded.value = true
|
||||
|
||||
return data
|
||||
} catch (err) {
|
||||
@ -153,7 +181,24 @@ export const useCollaborationStore = defineStore('collaboration', () => {
|
||||
throw new Error('Failed to complete session')
|
||||
}
|
||||
|
||||
return await response.json()
|
||||
const data = 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) {
|
||||
error.value = err.message
|
||||
throw err
|
||||
@ -191,11 +236,13 @@ export const useCollaborationStore = defineStore('collaboration', () => {
|
||||
return {
|
||||
currentSession,
|
||||
sessions,
|
||||
sessionsLoaded,
|
||||
loading,
|
||||
error,
|
||||
currentDocument,
|
||||
currentRound,
|
||||
conversationHistory,
|
||||
fetchSessions,
|
||||
createSession,
|
||||
startSession,
|
||||
runRound,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user