Fix peer chat queue sync

This commit is contained in:
Codex
2026-05-23 19:51:12 +08:00
committed by ekko
parent 7b05731d44
commit 238dbb507e
7 changed files with 53 additions and 12 deletions
+1
View File
@@ -57,6 +57,7 @@ export interface RunEvent {
role?: string role?: string
content?: string content?: string
timestamp?: number timestamp?: number
queued?: boolean
} }
} }
+14 -3
View File
@@ -1887,18 +1887,29 @@ export const useChatStore = defineStore('chat', () => {
resumeServerWorkingRun(sid, true) resumeServerWorkingRun(sid, true)
return return
} }
if (messageId && (queuedUserMessages.value.get(sid) || []).some(msg => msg.id === messageId)) {
serverWorking.value.add(sid)
resumeServerWorkingRun(sid, true)
return
}
const timestamp = typeof peer?.timestamp === 'number' && Number.isFinite(peer.timestamp) const timestamp = typeof peer?.timestamp === 'number' && Number.isFinite(peer.timestamp)
? Math.round(peer.timestamp * 1000) ? Math.round(peer.timestamp * 1000)
: Date.now() : Date.now()
addMessage(sid, { const message: Message = {
id: messageId || uid(), id: messageId || uid(),
role: 'user', role: 'user',
content, content,
timestamp, timestamp,
}) queued: !!peer?.queued,
updateSessionTitle(sid) }
if (peer?.queued) {
enqueueUserMessage(sid, message)
} else {
addMessage(sid, message)
updateSessionTitle(sid)
}
serverWorking.value.add(sid) serverWorking.value.add(sid)
resumeServerWorkingRun(sid, true) resumeServerWorkingRun(sid, true)
} }
@@ -68,7 +68,7 @@ export async function loadSessionStateFromDb(sid: string, _sessionMap: Map<strin
export async function handleApiRun( export async function handleApiRun(
nsp: ReturnType<Server['of']>, nsp: ReturnType<Server['of']>,
socket: Socket, socket: Socket,
data: { input: string | ContentBlock[]; session_id?: string; model?: string; provider?: string; instructions?: string; source?: string }, data: { input: string | ContentBlock[]; session_id?: string; model?: string; provider?: string; instructions?: string; source?: string; queue_id?: string; peerExcludeSocketId?: string },
profile: string, profile: string,
sessionMap: Map<string, SessionState>, sessionMap: Map<string, SessionState>,
skipUserMessage = false, skipUserMessage = false,
@@ -133,7 +133,7 @@ export async function handleApiRun(
content: inputStr, content: inputStr,
timestamp: now, timestamp: now,
}) })
peerUserMessage = { id: messageId, role: 'user', content: inputStr, timestamp: now } peerUserMessage = { id: data.queue_id ? undefined : messageId, role: 'user', content: inputStr, timestamp: now }
} else { } else {
const inputStr = contentBlocksToString(input) const inputStr = contentBlocksToString(input)
state.messages.push({ state.messages.push({
@@ -155,15 +155,21 @@ export async function handleApiRun(
content: inputStr, content: inputStr,
timestamp: now, timestamp: now,
}) })
peerUserMessage = { id: messageId, role: 'user', content: inputStr, timestamp: now } peerUserMessage = { id: data.queue_id ? undefined : messageId, role: 'user', content: inputStr, timestamp: now }
} }
socket.join(`session:${session_id}`) socket.join(`session:${session_id}`)
if (peerUserMessage) { if (peerUserMessage) {
socket.to(`session:${session_id}`).emit('run.peer_user_message', { const target = data.peerExcludeSocketId
? nsp.to(`session:${session_id}`).except(data.peerExcludeSocketId)
: socket.to(`session:${session_id}`)
target.emit('run.peer_user_message', {
event: 'run.peer_user_message', event: 'run.peer_user_message',
session_id, session_id,
message: peerUserMessage, message: {
...peerUserMessage,
id: data.queue_id || peerUserMessage.id,
},
}) })
} }
} }
@@ -94,7 +94,7 @@ function cacheBridgeContext(state: SessionState, data: Record<string, unknown> |
export async function handleBridgeRun( export async function handleBridgeRun(
nsp: ReturnType<Server['of']>, nsp: ReturnType<Server['of']>,
socket: Socket, socket: Socket,
data: { input: string | ContentBlock[]; session_id?: string; model?: string; provider?: string; model_groups?: RunModelGroup[]; instructions?: string; source?: string }, data: { input: string | ContentBlock[]; session_id?: string; model?: string; provider?: string; model_groups?: RunModelGroup[]; instructions?: string; source?: string; queue_id?: string; peerExcludeSocketId?: string },
profile: string, profile: string,
sessionMap: Map<string, SessionState>, sessionMap: Map<string, SessionState>,
bridge: AgentBridgeClient, bridge: AgentBridgeClient,
@@ -181,11 +181,14 @@ export async function handleBridgeRun(
}) })
socket.join(`session:${session_id}`) socket.join(`session:${session_id}`)
socket.to(`session:${session_id}`).emit('run.peer_user_message', { const peerTarget = data.peerExcludeSocketId
? nsp.to(`session:${session_id}`).except(data.peerExcludeSocketId)
: socket.to(`session:${session_id}`)
peerTarget.emit('run.peer_user_message', {
event: 'run.peer_user_message', event: 'run.peer_user_message',
session_id, session_id,
message: { message: {
id: messageId, id: data.queue_id || messageId,
role: 'user', role: 'user',
content: inputStr, content: inputStr,
timestamp: now, timestamp: now,
@@ -19,6 +19,7 @@ import { handleBridgeRun } from './handle-bridge-run'
import { handleAbort } from './abort' import { handleAbort } from './abort'
import { getOrCreateSession } from './compression' import { getOrCreateSession } from './compression'
import { handleSessionCommand, isSessionCommand, parseSessionCommand } from './session-command' import { handleSessionCommand, isSessionCommand, parseSessionCommand } from './session-command'
import { contentBlocksToString } from './content-blocks'
import type { ContentBlock, QueuedRun, SessionState } from './types' import type { ContentBlock, QueuedRun, SessionState } from './types'
import { authenticateUserToken, isAuthEnabled, type AuthenticatedUser } from '../../../middleware/user-auth' import { authenticateUserToken, isAuthEnabled, type AuthenticatedUser } from '../../../middleware/user-auth'
import { userCanAccessProfile } from '../../../db/hermes/users-store' import { userCanAccessProfile } from '../../../db/hermes/users-store'
@@ -146,8 +147,9 @@ export class ChatRunSocket {
return return
} }
if (state.isWorking) { if (state.isWorking) {
const queueId = data.queue_id || `queue_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`
state.queue.push({ state.queue.push({
queue_id: data.queue_id || `queue_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`, queue_id: queueId,
input: data.input, input: data.input,
model: data.model, model: data.model,
provider: data.provider, provider: data.provider,
@@ -155,6 +157,18 @@ export class ChatRunSocket {
instructions: data.instructions, instructions: data.instructions,
profile: runProfile, profile: runProfile,
source, source,
originSocketId: socket.id,
})
socket.to(`session:${data.session_id}`).emit('run.peer_user_message', {
event: 'run.peer_user_message',
session_id: data.session_id,
message: {
id: queueId,
role: 'user',
content: contentBlocksToString(data.input),
timestamp: Math.floor(Date.now() / 1000),
queued: true,
},
}) })
this.nsp.to(`session:${data.session_id}`).emit('run.queued', { this.nsp.to(`session:${data.session_id}`).emit('run.queued', {
event: 'run.queued', event: 'run.queued',
@@ -249,6 +263,8 @@ export class ChatRunSocket {
model_groups?: Array<{ provider: string; models: string[] }> model_groups?: Array<{ provider: string; models: string[] }>
instructions?: string instructions?: string
source?: string source?: string
queue_id?: string
peerExcludeSocketId?: string
}, },
profile: string, profile: string,
skipUserMessage = false, skipUserMessage = false,
@@ -336,6 +352,8 @@ export class ChatRunSocket {
model_groups: next.model_groups, model_groups: next.model_groups,
instructions: next.instructions, instructions: next.instructions,
source: next.source, source: next.source,
queue_id: next.queue_id,
peerExcludeSocketId: next.originSocketId,
}, next.profile || fallbackProfile, true) }, next.profile || fallbackProfile, true)
} }
@@ -157,6 +157,7 @@ export async function handleSessionCommand(
instructions: ctx.instructions, instructions: ctx.instructions,
profile: ctx.profile, profile: ctx.profile,
source: 'cli', source: 'cli',
originSocketId: ctx.socket.id,
}) })
emitToSession(ctx.nsp, ctx.socket, sessionId, 'run.queued', { emitToSession(ctx.nsp, ctx.socket, sessionId, 'run.queued', {
event: 'run.queued', event: 'run.queued',
@@ -34,6 +34,7 @@ export interface QueuedRun {
instructions?: string instructions?: string
profile: string profile: string
source?: ChatRunSource source?: ChatRunSource
originSocketId?: string
} }
export interface SessionState { export interface SessionState {