diff --git a/static/src/app/methods/conversation.ts b/static/src/app/methods/conversation.ts index d90ef3b..2ada225 100644 --- a/static/src/app/methods/conversation.ts +++ b/static/src/app/methods/conversation.ts @@ -158,7 +158,12 @@ export const conversationMethods = { this.hasMoreConversations = data.data.has_more; debugLog(`已加载 ${this.conversations.length} 个对话`); - if (this.conversationsOffset === 0 && !this.currentConversationId && this.conversations.length > 0) { + if ( + this.conversationsOffset === 0 && + !this.currentConversationId && + this.conversations.length > 0 && + !this.isExplicitNewConversationRoute() + ) { // 只有在初始化完成后,才自动加载第一个对话 // 避免与 bootstrapRoute 冲突 if (this.initialRouteResolved) { diff --git a/static/src/app/methods/message.ts b/static/src/app/methods/message.ts index acb8043..1c16acc 100644 --- a/static/src/app/methods/message.ts +++ b/static/src/app/methods/message.ts @@ -198,6 +198,49 @@ export const messageMethods = { }, 320); } + let targetConversationId = this.currentConversationId; + if (!targetConversationId) { + try { + const createResp = await fetch('/api/conversations', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + thinking_mode: this.thinkingMode, + mode: this.runMode + }) + }); + const createResult = await createResp.json().catch(() => ({})); + if (!createResp.ok || !createResult?.success || !createResult?.conversation_id) { + throw new Error(createResult?.message || createResult?.error || '创建对话失败'); + } + targetConversationId = createResult.conversation_id; + this.skipConversationHistoryReload = true; + this.currentConversationId = targetConversationId; + this.currentConversationTitle = '新对话'; + this.conversations = [ + { + id: targetConversationId, + title: '新对话', + updated_at: new Date().toISOString(), + total_messages: 0, + total_tools: 0 + }, + ...this.conversations.filter((conv) => conv && conv.id !== targetConversationId) + ]; + const pathFragment = this.stripConversationPrefix(targetConversationId); + history.replaceState({ conversationId: targetConversationId }, '', `/${pathFragment}`); + } catch (error) { + this.uiPushToast({ + title: '发送失败', + message: error?.message || '创建新对话失败,请重试', + type: 'error' + }); + return; + } + } + // 标记任务进行中,直到任务完成或用户手动停止 this.taskInProgress = true; this.chatAddUserMessage(message, images, videos); @@ -210,7 +253,7 @@ export const messageMethods = { this.clearProcessedEvents(); } - await taskStore.createTask(message, images, videos, this.currentConversationId); + await taskStore.createTask(message, images, videos, targetConversationId); debugLog('[Message] 任务已创建,开始轮询'); } catch (error) { diff --git a/static/src/app/methods/ui.ts b/static/src/app/methods/ui.ts index 7495341..ed8e3a8 100644 --- a/static/src/app/methods/ui.ts +++ b/static/src/app/methods/ui.ts @@ -964,6 +964,27 @@ export const uiMethods = { return renderMarkdownHelper(content, isStreaming); }, + isExplicitNewConversationRoute() { + const normalizedPath = window.location.pathname.replace(/^\/+|\/+$/g, ''); + return normalizedPath === 'new'; + }, + + async getRunningTaskConversationId() { + try { + const resp = await fetch('/api/tasks'); + if (!resp.ok) { + return null; + } + const payload = await resp.json(); + const tasks = Array.isArray(payload?.data) ? payload.data : []; + const runningTask = tasks.find((task: any) => task?.status === 'running' && task?.conversation_id); + return runningTask?.conversation_id || null; + } catch (error) { + console.warn('获取运行中任务失败:', error); + return null; + } + }, + async bootstrapRoute() { // 在路由解析期间抑制标题动画,避免预置"新对话"闪烁 this.suppressTitleTyping = true; @@ -971,13 +992,16 @@ export const uiMethods = { this.currentConversationTitle = ''; this.titleTypingText = ''; const path = window.location.pathname.replace(/^\/+/, ''); - if (!path || path === 'new') { + if (!path || this.isExplicitNewConversationRoute()) { this.currentConversationId = null; this.currentConversationTitle = '新对话'; + this.logMessageState('bootstrapRoute:clear-messages-for-new'); + this.messages = []; this.titleReady = true; this.suppressTitleTyping = false; this.startTitleTyping('新对话', { animate: false }); this.initialRouteResolved = true; + this.refreshBlankHeroState(); return; } @@ -1157,8 +1181,17 @@ export const uiMethods = { } // 获取当前对话信息 + const isExplicitNewRoute = this.isExplicitNewConversationRoute(); + const runningConversationId = await this.getRunningTaskConversationId(); const statusConversationId = statusData.conversation && statusData.conversation.current_id; - if (statusConversationId && !this.currentConversationId) { + const resumeConversationId = statusConversationId || runningConversationId; + const shouldResumeOnNewRoute = isExplicitNewRoute && !!runningConversationId; + + if ( + resumeConversationId && + !this.currentConversationId && + (!isExplicitNewRoute || shouldResumeOnNewRoute) + ) { this.skipConversationHistoryReload = true; // 首次从状态恢复对话时,避免 socket 的 conversation_loaded 再次触发历史加载 this.skipConversationLoadedEvent = true; @@ -1166,7 +1199,12 @@ export const uiMethods = { this.titleReady = false; this.currentConversationTitle = ''; this.titleTypingText = ''; - this.currentConversationId = statusConversationId; + this.currentConversationId = resumeConversationId; + const pathFragment = this.stripConversationPrefix(resumeConversationId); + const currentPath = window.location.pathname.replace(/^\/+/, ''); + if (currentPath !== pathFragment) { + history.replaceState({ conversationId: resumeConversationId }, '', `/${pathFragment}`); + } // 如果有当前对话,尝试获取标题和历史 try {