diff --git a/static/src/app/methods/message.ts b/static/src/app/methods/message.ts index ba2412f..9bfa621 100644 --- a/static/src/app/methods/message.ts +++ b/static/src/app/methods/message.ts @@ -255,6 +255,16 @@ export const messageMethods = { // 标记任务进行中,直到任务完成或用户手动停止 this.taskInProgress = true; this.chatAddUserMessage(message, images, videos); + // 关键体验修复:用户发送后立刻显示 assistant 头部 + 工作中计时 + 等待提示, + // 不等待 createTask / 轮询首事件返回。 + this.chatStartAssistantMessage(); + this.stopRequested = false; + if (typeof this.monitorShowPendingReply === 'function') { + this.monitorShowPendingReply(); + } + if (this.autoScrollEnabled) { + this.scrollToBottom(); + } // 使用 REST API 创建任务(轮询模式) try { @@ -278,13 +288,17 @@ export const messageMethods = { message: error.message || '创建任务失败,请重试', type: 'error' }); + this.streamingMessage = false; this.taskInProgress = false; + if (typeof this.cleanupTrailingEmptyAssistantPlaceholder === 'function') { + this.cleanupTrailingEmptyAssistantPlaceholder('create_task_failed'); + } + if (typeof this.forceUnlockMonitor === 'function') { + this.forceUnlockMonitor('create_task_failed'); + } return; } - if (typeof this.monitorShowPendingReply === 'function') { - this.monitorShowPendingReply(); - } this.inputClearMessage(); this.inputClearSelectedImages(); this.inputClearSelectedVideos(); @@ -555,6 +569,11 @@ export const messageMethods = { } this.taskInProgress = true; this.chatAddUserMessage(message, []); + this.chatStartAssistantMessage(); + this.stopRequested = false; + if (typeof this.monitorShowPendingReply === 'function') { + this.monitorShowPendingReply(); + } try { const { useTaskStore } = await import('../../stores/task'); const taskStore = useTaskStore(); @@ -569,12 +588,16 @@ export const messageMethods = { message: error?.message || '创建任务失败,请重试', type: 'error' }); + this.streamingMessage = false; this.taskInProgress = false; + if (typeof this.cleanupTrailingEmptyAssistantPlaceholder === 'function') { + this.cleanupTrailingEmptyAssistantPlaceholder('auto_create_task_failed'); + } + if (typeof this.forceUnlockMonitor === 'function') { + this.forceUnlockMonitor('auto_create_task_failed'); + } return false; } - if (typeof this.monitorShowPendingReply === 'function') { - this.monitorShowPendingReply(); - } if (this.autoScrollEnabled) { this.scrollToBottom(); } diff --git a/static/src/app/methods/taskPolling.ts b/static/src/app/methods/taskPolling.ts index 700026a..3fa3f45 100644 --- a/static/src/app/methods/taskPolling.ts +++ b/static/src/app/methods/taskPolling.ts @@ -83,6 +83,24 @@ function isEmptyAssistantPlaceholderMessage(message: any): boolean { return actions.length === 0 && !!message.awaitingFirstContent; } +function getOptimisticUserEchoTarget(messages: any[]): any | null { + if (!Array.isArray(messages) || messages.length === 0) { + return null; + } + const lastIndex = messages.length - 1; + const last = messages[lastIndex]; + if (last?.role === 'user') { + return last; + } + if (isEmptyAssistantPlaceholderMessage(last) && lastIndex > 0) { + const prev = messages[lastIndex - 1]; + if (prev?.role === 'user') { + return prev; + } + } + return null; +} + /** * 任务轮询事件处理器 * 将从 REST API 轮询获取的事件转换为前端状态更新 @@ -1284,10 +1302,7 @@ export const taskPollingMethods = { : Array.isArray(data?.mediaRefs) ? data.mediaRefs : []; - const last = - Array.isArray(this.messages) && this.messages.length > 0 - ? this.messages[this.messages.length - 1] - : null; + const last = getOptimisticUserEchoTarget(this.messages || []); const isLikelyOptimisticEcho = !!( last && last.role === 'user' &&