diff --git a/static/src/app/methods/conversation.ts b/static/src/app/methods/conversation.ts index 82e92f3..d90ef3b 100644 --- a/static/src/app/methods/conversation.ts +++ b/static/src/app/methods/conversation.ts @@ -4,6 +4,8 @@ import { debugLog, traceLog } from './common'; export const conversationMethods = { // 完整重置所有状态 resetAllStates(reason = 'unspecified', options: { preserveMonitorWindows?: boolean } = {}) { + console.log('[DEBUG_AWAITING] ===== resetAllStates =====', { reason }); + // 如果正在等待子智能体完成,不重置任务状态 if (this.waitingForSubAgent) { debugLog('跳过状态重置:正在等待子智能体完成', { reason }); @@ -30,18 +32,44 @@ export const conversationMethods = { // 清理工具状态 this.toolResetTracking(); - // 新增:将所有未完成的工具标记为已完成 - this.messages.forEach(msg => { - if (msg.role === 'assistant' && msg.actions) { - msg.actions.forEach(action => { - if (action.type === 'tool' && - (action.tool.status === 'preparing' || action.tool.status === 'running')) { - action.tool.status = 'completed'; - } - }); + // 新增:将所有未完成的工具标记为已完成,并清理awaitingFirstContent状态 + const assistantMsgsBefore = this.messages.filter(m => m.role === 'assistant').map(m => ({ + awaitingFirstContent: m.awaitingFirstContent, + generatingLabel: m.generatingLabel + })); + + this.messages.forEach((msg) => { + if (msg.role === 'assistant') { + // 清理等待动画状态 + if (msg.awaitingFirstContent) { + msg.awaitingFirstContent = false; + } + if (msg.generatingLabel) { + msg.generatingLabel = ''; + } + + // 清理工具状态 + if (msg.actions) { + msg.actions.forEach(action => { + if (action.type === 'tool' && + (action.tool.status === 'preparing' || action.tool.status === 'running')) { + action.tool.status = 'completed'; + } + }); + } } }); + const assistantMsgsAfter = this.messages.filter(m => m.role === 'assistant').map(m => ({ + awaitingFirstContent: m.awaitingFirstContent, + generatingLabel: m.generatingLabel + })); + + console.log('[DEBUG_AWAITING] resetAllStates 清理完成', { + before: assistantMsgsBefore, + after: assistantMsgsAfter + }); + // 清理Markdown缓存 if (this.markdownCache) { this.markdownCache.clear(); @@ -232,6 +260,9 @@ export const conversationMethods = { if (taskStore.hasActiveTask) { await taskStore.cancelTask(); taskStore.clearTask(); + if (typeof this.clearProcessedEvents === 'function') { + this.clearProcessedEvents(); + } } if (this.waitingForSubAgent && !taskStore.hasActiveTask) { @@ -317,6 +348,8 @@ export const conversationMethods = { }, async createNewConversation() { + console.log('[DEBUG_AWAITING] ===== createNewConversation ====='); + debugLog('创建新对话...'); traceLog('createNewConversation:start', { currentConversationId: this.currentConversationId, @@ -383,6 +416,9 @@ export const conversationMethods = { if (taskStore.hasActiveTask) { await taskStore.cancelTask(); taskStore.clearTask(); + if (typeof this.clearProcessedEvents === 'function') { + this.clearProcessedEvents(); + } } // 重置任务相关状态 diff --git a/static/src/app/methods/history.ts b/static/src/app/methods/history.ts index 9558d8c..2588e8b 100644 --- a/static/src/app/methods/history.ts +++ b/static/src/app/methods/history.ts @@ -179,7 +179,7 @@ export const historyMethods = { streamingText: '', currentStreamingType: null, activeThinkingId: null, - awaitingFirstContent: false, + awaitingFirstContent: false, // 历史消息不应该显示等待动画 generatingLabel: '' }; } diff --git a/static/src/app/methods/message.ts b/static/src/app/methods/message.ts index 519fb69..f070e33 100644 --- a/static/src/app/methods/message.ts +++ b/static/src/app/methods/message.ts @@ -110,6 +110,8 @@ export const messageMethods = { }, async sendMessage() { + console.log('[DEBUG_AWAITING] ===== sendMessage ====='); + if (this.streamingUi) { return; } @@ -204,6 +206,9 @@ export const messageMethods = { try { const { useTaskStore } = await import('../../stores/task'); const taskStore = useTaskStore(); + if (typeof this.clearProcessedEvents === 'function') { + this.clearProcessedEvents(); + } await taskStore.createTask(message, images, videos, this.currentConversationId); @@ -252,6 +257,8 @@ export const messageMethods = { // 新增:停止任务方法 async stopTask() { + console.log('[DEBUG_AWAITING] ===== stopTask ====='); + const canStop = this.composerBusy && !this.stopRequested; if (!canStop) { return; @@ -277,6 +284,31 @@ export const messageMethods = { this.streamingMessage = false; this.taskInProgress = false; this.forceUnlockMonitor('user_stop'); + if (typeof this.clearProcessedEvents === 'function') { + this.clearProcessedEvents(); + } + + // 清理assistant消息的等待动画状态 + const lastMessage = this.messages[this.messages.length - 1]; + const before = { + hasLastMessage: !!lastMessage, + role: lastMessage?.role, + awaitingFirstContent: lastMessage?.awaitingFirstContent, + generatingLabel: lastMessage?.generatingLabel + }; + + if (lastMessage && lastMessage.role === 'assistant') { + lastMessage.awaitingFirstContent = false; + lastMessage.generatingLabel = ''; + } + + console.log('[DEBUG_AWAITING] stopTask 清理完成', { + before, + after: { + awaitingFirstContent: lastMessage?.awaitingFirstContent, + generatingLabel: lastMessage?.generatingLabel + } + }); } catch (error) { console.error('[Message] 取消任务失败:', error); @@ -285,6 +317,16 @@ export const messageMethods = { this.streamingMessage = false; this.taskInProgress = false; this.forceUnlockMonitor('user_stop'); + if (typeof this.clearProcessedEvents === 'function') { + this.clearProcessedEvents(); + } + + // 清理assistant消息的等待动画状态 + const lastMessage = this.messages[this.messages.length - 1]; + if (lastMessage && lastMessage.role === 'assistant') { + lastMessage.awaitingFirstContent = false; + lastMessage.generatingLabel = ''; + } this.uiPushToast({ title: '停止失败', @@ -388,6 +430,9 @@ export const messageMethods = { try { const { useTaskStore } = await import('../../stores/task'); const taskStore = useTaskStore(); + if (typeof this.clearProcessedEvents === 'function') { + this.clearProcessedEvents(); + } await taskStore.createTask(message, [], [], this.currentConversationId); } catch (error) { console.error('[Message] 自动消息创建任务失败:', error); diff --git a/static/src/app/methods/taskPolling.ts b/static/src/app/methods/taskPolling.ts index bc98d68..97b95ca 100644 --- a/static/src/app/methods/taskPolling.ts +++ b/static/src/app/methods/taskPolling.ts @@ -42,6 +42,12 @@ export const taskPollingMethods = { // 如果不匹配,忽略该事件(避免切换对话后旧任务的事件显示到新对话中) if (eventData.conversation_id && this.currentConversationId) { if (eventData.conversation_id !== this.currentConversationId) { + console.log(`[DEBUG_AWAITING] 忽略不匹配的事件`, { + eventType, + eventIdx, + eventConversationId: eventData.conversation_id, + currentConversationId: this.currentConversationId + }); debugLog(`[TaskPolling] 忽略不匹配的事件 #${eventIdx}: ${eventType}, 事件对话=${eventData.conversation_id}, 当前对话=${this.currentConversationId}`); return; } @@ -49,6 +55,13 @@ export const taskPollingMethods = { debugLog(`[TaskPolling] 处理事件 #${eventIdx}: ${eventType}`, eventData); + console.log(`[DEBUG_AWAITING] 处理事件`, { + eventType, + eventIdx, + eventConversationId: eventData.conversation_id, + currentConversationId: this.currentConversationId + }); + // 根据事件类型调用对应的处理方法 switch (eventType) { case 'ai_message_start': @@ -137,25 +150,82 @@ export const taskPollingMethods = { }, handleAiMessageStart(data: any, eventIdx: number) { + const lastMessage = this.messages[this.messages.length - 1]; + console.log('[DEBUG_AWAITING] ===== handleAiMessageStart =====', { + eventIdx, + lastMessageRole: lastMessage?.role, + lastMessageAwaitingFirstContent: lastMessage?.awaitingFirstContent, + lastMessageGeneratingLabel: lastMessage?.generatingLabel + }); + debugLog('[TaskPolling] AI消息开始, idx:', eventIdx); + console.log('[AiMessageStart] 开始处理', { + eventIdx, + messagesLength: this.messages.length, + lastMessageRole: this.messages[this.messages.length - 1]?.role, + streamingMessage: this.streamingMessage, + taskInProgress: this.taskInProgress, + currentConversationId: this.currentConversationId + }); + if (this.waitingForSubAgent) { this.waitingForSubAgent = false; } - // 检查是否已经有 assistant 消息(刷新恢复的情况) - const lastMessage = this.messages[this.messages.length - 1]; + // 检查是否已经有 assistant 消息 const hasAssistantMessage = lastMessage && lastMessage.role === 'assistant'; - if (hasAssistantMessage) { - debugLog('[TaskPolling] 已有 assistant 消息,跳过创建新消息'); + console.log('[AiMessageStart] 最后一条消息状态', { + hasAssistantMessage, + lastMessageActionsLength: lastMessage?.actions?.length || 0, + lastMessageAwaitingFirstContent: lastMessage?.awaitingFirstContent, + lastMessageGeneratingLabel: lastMessage?.generatingLabel + }); + + // 判断是否是刷新恢复的情况: + // 1. 有assistant消息 + // 2. 且该消息正在streaming或者没有任何内容(说明是刚创建的) + // 3. 且不是历史加载完成的消息(历史消息的awaitingFirstContent应该是false) + const isRefreshRestore = hasAssistantMessage && + (this.streamingMessage || !lastMessage.actions || lastMessage.actions.length === 0) && + (lastMessage.awaitingFirstContent === true || this.taskInProgress); + + console.log('[AiMessageStart] 场景判断', { + isRefreshRestore, + streamingMessage: this.streamingMessage, + hasActions: !!(lastMessage?.actions && lastMessage.actions.length > 0), + awaitingFirstContent: lastMessage?.awaitingFirstContent, + taskInProgress: this.taskInProgress + }); + + if (isRefreshRestore) { + console.log('[AiMessageStart] 场景=刷新恢复,复用现有assistant消息'); + debugLog('[TaskPolling] 刷新恢复场景,复用现有 assistant 消息'); // 只更新状态,不创建新消息 this.taskInProgress = true; this.stopRequested = false; this.streamingMessage = true; + + // 确保 awaitingFirstContent 被正确设置 + const hasContent = lastMessage.actions && lastMessage.actions.length > 0; + if (!hasContent) { + lastMessage.awaitingFirstContent = true; + lastMessage.generatingLabel = lastMessage.generatingLabel || '思考中...'; + console.log('[AiMessageStart] 设置等待动画', { + awaitingFirstContent: true, + generatingLabel: lastMessage.generatingLabel + }); + } else { + // 如果已有内容,确保等待动画不显示 + lastMessage.awaitingFirstContent = false; + lastMessage.generatingLabel = ''; + console.log('[AiMessageStart] 关闭等待动画(已有内容)'); + } return; } - // 没有 assistant 消息,创建新的 + // 其他情况:创建新的 assistant 消息 + console.log('[AiMessageStart] 场景=创建新消息'); debugLog('[TaskPolling] 创建新的 assistant 消息'); this.monitorResetSpeech(); this.cleanupStaleToolActions(); @@ -164,66 +234,71 @@ export const taskPollingMethods = { this.stopRequested = false; this.streamingMessage = true; + const newMessage = this.messages[this.messages.length - 1]; + console.log('[AiMessageStart] 新消息创建完成', { + role: newMessage?.role, + awaitingFirstContent: newMessage?.awaitingFirstContent, + generatingLabel: newMessage?.generatingLabel, + actionsLength: newMessage?.actions?.length || 0, + messagesLength: this.messages.length + }); + // 如果是从头重建,标记消息为静默恢复 if (this._rebuildingFromScratch) { - const newMessage = this.messages[this.messages.length - 1]; if (newMessage && newMessage.role === 'assistant') { debugLog('[TaskPolling] 标记消息为静默恢复(从头重建)'); newMessage.awaitingFirstContent = false; newMessage.generatingLabel = ''; + console.log('[AiMessageStart] 从头重建,关闭等待动画'); } } - this.scrollToBottom(); + // 强制触发Vue响应式更新 + this.$forceUpdate(); + console.log('[AiMessageStart] 已调用$forceUpdate'); + + this.$nextTick(() => { + console.log('[AiMessageStart] nextTick回调执行'); + this.scrollToBottom(); + }); }, handleThinkingStart(data: any, eventIdx: number) { + console.log('[ThinkingStart] 开始处理', { eventIdx }); debugLog('[TaskPolling] 思考开始, idx:', eventIdx); const ignoreThinking = this.runMode === 'fast' || this.thinkingMode === false; if (ignoreThinking) { this.monitorEndModelOutput(); + console.log('[ThinkingStart] 忽略思考(fast模式或关闭思考)'); return; } + // 防御性检查:如果没有assistant消息,先创建一个 + const lastMessage = this.messages[this.messages.length - 1]; + if (!lastMessage || lastMessage.role !== 'assistant') { + console.log('[DEBUG_AWAITING] ThinkingStart 检测到缺少assistant消息,自动创建'); + this.chatStartAssistantMessage(); + } + this.monitorShowThinking(); - // 获取当前 actions 数量,用于调试(已禁用) - // const lastMessage = this.messages[this.messages.length - 1]; - // const beforeCount = lastMessage?.actions?.length || 0; - // console.log('[TaskPolling] 添加思考块前,actions 数量:', beforeCount); - // console.log('[TaskPolling] 当前 currentMessageIndex:', this.currentMessageIndex); - // console.log('[TaskPolling] messages 总数:', this.messages.length); - // console.log('[TaskPolling] 最后一条消息 role:', lastMessage?.role); - const result = this.chatStartThinkingAction(); - // console.log('[TaskPolling] chatStartThinkingAction 返回:', result); - if (result && result.blockId) { const blockId = result.blockId; - // 检查新添加的 action(已禁用) - // const afterCount = lastMessage?.actions?.length || 0; - // console.log('[TaskPolling] 添加思考块后,actions 数量:', afterCount); - - // 检查 currentMessageIndex 指向的消息(已禁用) - // const currentMsg = this.messages[this.currentMessageIndex]; - // if (currentMsg) { - // console.log('[TaskPolling] currentMessageIndex 指向的消息 actions 数量:', currentMsg.actions?.length || 0); - // } - - // if (afterCount > beforeCount) { - // const newAction = lastMessage.actions[afterCount - 1]; - // console.log('[TaskPolling] 新添加的思考块:', { - // type: newAction.type, - // blockId: newAction.blockId, - // hasId: !!newAction.id, - // timestamp: newAction.timestamp - // }); - // } - const lastMessage = this.messages[this.messages.length - 1]; + // 有内容了,关闭等待动画 + if (lastMessage && lastMessage.role === 'assistant') { + console.log('[ThinkingStart] 关闭等待动画', { + beforeAwaitingFirstContent: lastMessage.awaitingFirstContent, + beforeGeneratingLabel: lastMessage.generatingLabel + }); + lastMessage.awaitingFirstContent = false; + lastMessage.generatingLabel = ''; + } + // 只在非历史恢复时展开思考块 if (!this._rebuildingFromScratch) { this.chatExpandBlock(blockId); @@ -287,8 +362,29 @@ export const taskPollingMethods = { }, handleTextStart(data: any) { + console.log('[TextStart] 开始处理'); debugLog('[TaskPolling] 文本开始'); + + // 防御性检查:如果没有assistant消息,先创建一个 + const lastMessage = this.messages[this.messages.length - 1]; + if (!lastMessage || lastMessage.role !== 'assistant') { + console.log('[DEBUG_AWAITING] TextStart 检测到缺少assistant消息,自动创建'); + this.chatStartAssistantMessage(); + } + this.chatStartTextAction(); + + // 有内容了,关闭等待动画 + const currentMessage = this.messages[this.messages.length - 1]; + if (currentMessage && currentMessage.role === 'assistant') { + console.log('[TextStart] 关闭等待动画', { + beforeAwaitingFirstContent: currentMessage.awaitingFirstContent, + beforeGeneratingLabel: currentMessage.generatingLabel + }); + currentMessage.awaitingFirstContent = false; + currentMessage.generatingLabel = ''; + } + this.$forceUpdate(); }, @@ -313,18 +409,25 @@ export const taskPollingMethods = { }, handleToolPreparing(data: any) { + console.log('[ToolPreparing] 开始处理', { name: data.name, id: data.id }); debugLog('[TaskPolling] 工具准备中:', data.name); if (this.dropToolEvents) { + console.log('[ToolPreparing] dropToolEvents=true,跳过'); return; } const msg = this.chatEnsureAssistantMessage(); if (!msg) { + console.log('[ToolPreparing] 无法获取assistant消息'); return; } if (msg.awaitingFirstContent) { + console.log('[ToolPreparing] 关闭等待动画', { + beforeAwaitingFirstContent: msg.awaitingFirstContent, + beforeGeneratingLabel: msg.generatingLabel + }); msg.awaitingFirstContent = false; msg.generatingLabel = ''; } diff --git a/static/src/stores/chat.ts b/static/src/stores/chat.ts index 21adc6a..5db0aa1 100644 --- a/static/src/stores/chat.ts +++ b/static/src/stores/chat.ts @@ -179,6 +179,12 @@ export const useChatStore = defineStore('chat', { this.currentMessageIndex = this.messages.length - 1; this.streamingMessage = true; message.awaitingFirstContent = true; + + console.log('[DEBUG_AWAITING] ===== startAssistantMessage =====', { + awaitingFirstContent: message.awaitingFirstContent, + generatingLabel: message.generatingLabel + }); + return message; }, startThinkingAction() {