fix(chat): recover assistant placeholder after stop and switch
This commit is contained in:
parent
0296418cff
commit
8d5a034c70
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
// 重置任务相关状态
|
||||
|
||||
@ -179,7 +179,7 @@ export const historyMethods = {
|
||||
streamingText: '',
|
||||
currentStreamingType: null,
|
||||
activeThinkingId: null,
|
||||
awaitingFirstContent: false,
|
||||
awaitingFirstContent: false, // 历史消息不应该显示等待动画
|
||||
generatingLabel: ''
|
||||
};
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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 = '';
|
||||
}
|
||||
|
||||
@ -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() {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user