data pipeline refactor and fix
This commit is contained in:
@@ -59,6 +59,18 @@ const addToolCallBubble = (label: string) => {
|
||||
}]
|
||||
}
|
||||
|
||||
const appendToolCallStatus = (status: string) => {
|
||||
if (!toolCallMessageId) return
|
||||
const idx = messages.value.findIndex(m => m._id === toolCallMessageId)
|
||||
if (idx !== -1) {
|
||||
messages.value[idx] = {
|
||||
...messages.value[idx],
|
||||
content: messages.value[idx].content + `\n↳ ${status}`
|
||||
}
|
||||
messages.value = [...messages.value]
|
||||
}
|
||||
}
|
||||
|
||||
const removeToolCallBubble = () => {
|
||||
if (toolCallMessageId) {
|
||||
messages.value = messages.value.filter(m => m._id !== toolCallMessageId)
|
||||
@@ -76,11 +88,47 @@ const streamingImages = ref<any[]>([])
|
||||
const handleMessage = (data: WebSocketMessage) => {
|
||||
console.log('[ChatPanel] Received message:', data)
|
||||
|
||||
if (data.type === 'conversation_history') {
|
||||
messages.value = (data.messages as any[]).map((m: any) => {
|
||||
const ts = new Date(m.timestamp / 1000) // microseconds → ms
|
||||
const files = (m.files ?? []).map((b: any) => ({
|
||||
name: `image_${b.id}.png`,
|
||||
size: 0,
|
||||
type: b.mimeType.split('/')[1] ?? 'png',
|
||||
url: `data:${b.mimeType};base64,${b.data}`,
|
||||
preview: `data:${b.mimeType};base64,${b.data}`,
|
||||
}))
|
||||
return {
|
||||
_id: m.id,
|
||||
content: m.content,
|
||||
senderId: m.role === 'user' ? CURRENT_USER_ID : AGENT_ID,
|
||||
timestamp: ts.toTimeString().split(' ')[0].slice(0, 5),
|
||||
date: ts.toLocaleDateString(),
|
||||
saved: true,
|
||||
distributed: true,
|
||||
seen: true,
|
||||
files,
|
||||
}
|
||||
})
|
||||
messagesLoaded.value = true
|
||||
return
|
||||
}
|
||||
|
||||
if (data.type === 'agent_tool_call') {
|
||||
addToolCallBubble(data.label ?? data.toolName ?? 'Tool call...')
|
||||
return
|
||||
}
|
||||
|
||||
if (data.type === 'subagent_tool_call') {
|
||||
appendToolCallStatus(data.toolName ?? data.label ?? 'tool')
|
||||
return
|
||||
}
|
||||
|
||||
if (data.type === 'subagent_chunk') {
|
||||
// Subagent final text — not shown separately; the main agent will incorporate it in its response
|
||||
return
|
||||
}
|
||||
|
||||
if (data.type === 'image') {
|
||||
// Handle image message - attach to current streaming message or create standalone
|
||||
console.log('[ChatPanel] Processing image message')
|
||||
|
||||
@@ -3,6 +3,24 @@ import * as jsonpatch from 'fast-json-patch';
|
||||
import type { BackendMessage, FrontendMessage, HelloMessage, PatchMessage } from '../types/sync';
|
||||
import { wsManager } from './useWebSocket';
|
||||
|
||||
function deepReplace(target: Record<string, any>, source: Record<string, any>) {
|
||||
for (const key of Object.keys(target)) {
|
||||
if (!(key in source)) {
|
||||
delete target[key]
|
||||
}
|
||||
}
|
||||
for (const [key, value] of Object.entries(source)) {
|
||||
if (
|
||||
value !== null && typeof value === 'object' && !Array.isArray(value) &&
|
||||
target[key] !== null && typeof target[key] === 'object' && !Array.isArray(target[key])
|
||||
) {
|
||||
deepReplace(target[key], value)
|
||||
} else {
|
||||
target[key] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function useStateSync(stores: Record<string, Store>) {
|
||||
console.log('[StateSync] Initializing with stores:', Object.keys(stores));
|
||||
|
||||
@@ -35,7 +53,7 @@ export function useStateSync(stores: Record<string, Store>) {
|
||||
if (store) {
|
||||
console.log('[StateSync] Applying snapshot state:', msg.state);
|
||||
isApplyingBackendPatch[msg.store] = true;
|
||||
store.$patch(msg.state);
|
||||
store.$patch((state) => deepReplace(state as Record<string, any>, msg.state as Record<string, any>));
|
||||
// Update previousState to stay in sync
|
||||
previousStates[msg.store] = JSON.parse(JSON.stringify(store.$state));
|
||||
isApplyingBackendPatch[msg.store] = false;
|
||||
@@ -64,7 +82,7 @@ export function useStateSync(stores: Record<string, Store>) {
|
||||
const newState = jsonpatch.applyPatch(currentState, msg.patch, false, false).newDocument;
|
||||
console.log('[StateSync] New state after patch:', newState);
|
||||
isApplyingBackendPatch[msg.store] = true;
|
||||
store.$patch(newState);
|
||||
store.$patch((state) => deepReplace(state as Record<string, any>, newState as Record<string, any>));
|
||||
// Update previousState to stay in sync
|
||||
previousStates[msg.store] = JSON.parse(JSON.stringify(store.$state));
|
||||
isApplyingBackendPatch[msg.store] = false;
|
||||
|
||||
@@ -123,8 +123,9 @@ class WebSocketManager {
|
||||
this.statusMessage.value = ''
|
||||
console.log('WebSocket disconnected:', event.code, event.reason)
|
||||
|
||||
// Attempt to reconnect if we have a token
|
||||
if (this.token && !event.wasClean) {
|
||||
// Attempt to reconnect if we have a token and it wasn't an intentional close.
|
||||
// Check code instead of wasClean: code 1005 has wasClean=true but still needs retry.
|
||||
if (this.token && event.code !== 1000 && event.code !== 1001) {
|
||||
this.scheduleReconnect()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user