// @ts-nocheck import { debugLog, traceLog } from '../common'; import { usePersonalizationStore } from '../../../stores/personalization'; import { } from './shared'; export const loadMethods = { async loadConversationsList() { const queryOffset = this.conversationsOffset; const queryLimit = this.conversationsLimit; const refreshToken = queryOffset === 0 ? ++this.conversationListRefreshToken : this.conversationListRefreshToken; const requestSeq = ++this.conversationListRequestSeq; this.conversationsLoading = true; try { // 多智能体模式下只加载多智能体对话记录;常规模式排除多智能体对话 const maParam = this.multiAgentMode ? '&multi_agent_mode=1' : '&multi_agent_mode=0'; const response = await fetch(`/api/conversations?limit=${queryLimit}&offset=${queryOffset}${maParam}`); const data = await response.json(); if (data.success) { if (refreshToken < this.conversationListRefreshToken) { debugLog('忽略已过期的对话列表响应', { requestSeq, responseOffset: queryOffset, refreshToken, currentRefreshToken: this.conversationListRefreshToken }); return; } if (queryOffset === 0) { this.conversations = data.data.conversations; } else { this.conversations.push(...data.data.conversations); } if (this.currentConversationId) { this.promoteConversationToTop(this.currentConversationId); } this.hasMoreConversations = data.data.has_more; debugLog(`已加载 ${this.conversations.length} 个对话`); if ( this.conversationsOffset === 0 && !this.currentConversationId && this.conversations.length > 0 && !this.isExplicitNewConversationRoute() ) { // 只有在初始化完成后,才自动加载第一个对话 // 避免与 bootstrapRoute 冲突 if (this.initialRouteResolved) { const latestConversation = this.conversations[0]; if (latestConversation && latestConversation.id) { await this.loadConversation(latestConversation.id); } } } } else { console.error('加载对话列表失败:', data.error); } } catch (error) { console.error('加载对话列表异常:', error); } finally { if (refreshToken === this.conversationListRefreshToken) { this.conversationsLoading = false; } } }, async loadMoreConversations() { if (this.loadingMoreConversations || !this.hasMoreConversations) return; this.loadingMoreConversations = true; this.conversationsOffset += this.conversationsLimit; await this.loadConversationsList(); this.loadingMoreConversations = false; }, async loadConversation(conversationId, options = {}) { const force = Boolean(options.force); const preserveListPosition = Boolean(options.preserveListPosition); const workspaceId = options.workspaceId ? String(options.workspaceId) : ''; const isHostLikeMode = Boolean(this.versioningHostMode || this.dockerProjectMode); debugLog('加载对话:', conversationId); traceLog('loadConversation:start', { conversationId, currentConversationId: this.currentConversationId, force }); this.logMessageState('loadConversation:start', { conversationId, force }); this.suppressTitleTyping = true; this.titleReady = false; this.currentConversationTitle = ''; this.titleTypingText = ''; if (!force && conversationId === this.currentConversationId) { debugLog('已是当前对话,跳过加载'); traceLog('loadConversation:skip-same', { conversationId }); this.suppressTitleTyping = false; this.titleReady = true; return; } if ((this.compressionInProgress || this.compressing) && !force) { const confirmed = await this.confirmAction({ title: '压缩进行中', message: '对话正在压缩中,切换对话会导致压缩失败,确认要继续吗?', confirmText: '确认', cancelText: '取消' }); if (!confirmed) { this.suppressTitleTyping = false; this.titleReady = true; return; } try { if (this.currentConversationId) { await fetch(`/api/conversations/${this.currentConversationId}/compression_cancel`, { method: 'POST' }); } } catch (e) { console.warn('取消压缩失败:', e); } this.compressionInProgress = false; this.compressing = false; this.compressionMode = ''; this.compressionStage = ''; if (this.compressionToastId) { this.uiDismissToast(this.compressionToastId); this.compressionToastId = null; } } // 注意:加载已有对话时必须保留该对话自身的模型/模式,不能套用用户默认值。 // 多工作区并行后,切换对话只切换视图,不再取消后台任务;停止当前轮询避免事件写入新对话界面。 try { const { useTaskStore } = await import('../../../stores/task'); const taskStore = useTaskStore(); if (taskStore.hasActiveTask || this.taskInProgress) { taskStore.clearTask(); if (typeof this.clearProcessedEvents === 'function') { this.clearProcessedEvents(); } } this.clearLocalTaskUiState?.(`switch-conversation:${conversationId}`); } catch (error) { console.error('[切换对话] 停止本地轮询失败:', error); } await this.persistComposerDraftNow({ reason: `switch-conversation:${conversationId}`, force: true, keepalive: true }).catch(() => {}); try { // 1. 调用加载API(多工作区模式下携带目标 workspace_id,避免并发/session 漂移导致加载错误工作区) const loadUrl = workspaceId && isHostLikeMode ? `/api/conversations/${conversationId}/load?workspace_id=${encodeURIComponent(workspaceId)}` : `/api/conversations/${conversationId}/load`; const response = await fetch(loadUrl, { method: 'PUT' }); const result = await response.json(); if (result.success) { debugLog('对话加载API成功:', result); traceLog('loadConversation:api-success', { conversationId, title: result.title }); if (typeof result.run_mode === 'string') { this.runMode = result.run_mode; this.thinkingMode = typeof result.thinking_mode === 'boolean' ? result.thinking_mode : result.run_mode !== 'fast'; } else if (typeof result.thinking_mode === 'boolean') { this.thinkingMode = result.thinking_mode; this.runMode = result.thinking_mode ? 'thinking' : 'fast'; } if (typeof result.model_key === 'string' && result.model_key) { this.modelSet(result.model_key); } if (typeof result.multi_agent_mode === 'boolean') { this.multiAgentMode = result.multi_agent_mode; } // 2. 更新当前对话信息 this.skipConversationHistoryReload = true; this.currentConversationId = conversationId; this.refreshProjectGitSummary?.(); this.fetchTerminalCount(); this.currentConversationTitle = result.title; this.titleReady = true; this.suppressTitleTyping = false; this.startTitleTyping(this.currentConversationTitle, { animate: false }); if (!preserveListPosition) { this.promoteConversationToTop(conversationId); } const urlPrefix = this.multiAgentMode ? '/multiagent/' : '/'; history.pushState( { conversationId }, '', `${urlPrefix}${this.stripConversationPrefix(conversationId)}` ); this.skipConversationLoadedEvent = true; // 3. 重置UI状态 this.resetAllStates(`loadConversation:${conversationId}`); this.subAgentFetch(); this.fetchTodoList(); // 4. 立即加载历史和统计,确保列表切换后界面同步更新 await this.fetchAndDisplayHistory(); await this.refreshRunningWorkspaceTasks?.(); const visibleTask = typeof this.getVisibleWorkspaceTaskForConversation === 'function' ? this.getVisibleWorkspaceTaskForConversation(conversationId) : null; const visibleTaskStatus = String(visibleTask?.status || ''); const activeStatuses = new Set(['pending', 'running', 'cancel_requested']); const terminalStatuses = new Set(['succeeded', 'failed', 'canceled']); if (visibleTask && activeStatuses.has(visibleTaskStatus)) { // 切回正在运行的对话时,必须恢复该任务的 REST 轮询和输入区忙碌态; // 否则只切换了历史视图,后续输出不会续接到当前对话,发送按钮也不会变成停止按钮。 await this.restoreTaskState?.(); } else if (visibleTask && terminalStatuses.has(visibleTaskStatus)) { // 用户已点进完成后的“待查看”对话,清除列表里的完成标记。 this.acknowledgeCompletedWorkspaceTask?.(visibleTask.task_id); } this.fetchPermissionMode(); this.fetchExecutionMode(); this.fetchNetworkPermission(); await this.fetchVersioningStatus(conversationId, { silent: true }); this.fetchPendingToolApprovals(); this.fetchPendingUserQuestions(); this.refreshProjectGitSummary(); this.fetchConversationTokenStatistics(); this.updateCurrentContextTokens(); traceLog('loadConversation:after-history', { conversationId, messagesLen: Array.isArray(this.messages) ? this.messages.length : 'n/a' }); } else { console.error('对话加载失败:', result.message); this.suppressTitleTyping = false; this.titleReady = true; this.uiPushToast({ title: '加载对话失败', message: result.message || '服务器未返回成功状态', type: 'error' }); } } catch (error) { console.error('加载对话异常:', error); traceLog('loadConversation:error', { conversationId, error: error?.message || String(error) }); this.suppressTitleTyping = false; this.titleReady = true; this.uiPushToast({ title: '加载对话异常', message: error.message || String(error), type: 'error' }); } }, async loadWorkspaceConversations(workspaceId: string, { reset = false } = {}) { if (!workspaceId) return; const { useConversationStore } = await import('../../../stores/conversation'); const conversationStore = useConversationStore(); let group = conversationStore.workspaceGroups.find((g: any) => g.workspaceId === workspaceId); if (!group) { group = { workspaceId, conversations: [], loading: true, hasMore: false, loadingMore: false, offset: 0, limit: 20, expanded: true }; conversationStore.workspaceGroups.push(group); } if (reset) { group.conversations = []; group.offset = 0; group.hasMore = false; } if (group.loading || group.loadingMore) return; group.loading = true; try { const maParam = this.multiAgentMode ? '&multi_agent_mode=1' : '&multi_agent_mode=0'; const response = await fetch(`/api/conversations?workspace_id=${encodeURIComponent(workspaceId)}&limit=${group.limit}&offset=${group.offset}${maParam}`); const data = await response.json(); if (data.success) { const items = (data.data?.conversations || []).map((conv: any) => ({ id: conv.id, title: conv.title, updated_at: conv.updated_at, total_messages: conv.total_messages, total_tools: conv.total_tools })); if (group.offset === 0) { group.conversations = items; } else { group.conversations.push(...items); } group.hasMore = !!data.data?.has_more; } else { console.error('加载工作区对话失败:', data.error); } } catch (error) { console.error('加载工作区对话异常:', error); } finally { group.loading = false; } }, async loadMoreWorkspaceConversations(workspaceId: string) { const { useConversationStore } = await import('../../../stores/conversation'); const conversationStore = useConversationStore(); const group = conversationStore.workspaceGroups.find((g: any) => g.workspaceId === workspaceId); if (!group || group.loadingMore || !group.hasMore) return; group.loadingMore = true; group.offset += group.limit; await this.loadWorkspaceConversations(workspaceId); group.loadingMore = false; } };