fix(chat): /new 页面隔离运行中对话的任务接管与事件推送
对话运行期间进入 /new 会把最近一次用户输入与后续 AI 输出/工具 调用渲染到空白页,刷新/重复进入均复现,任务结束后才正常。 根因是显式新建路由(currentConversationId 为空)下三层隔离缺失: - restoreTaskState 经 loadRunningTask(null) 接管任意运行中任务并 全量重放事件、恢复轮询(刷新后复现的根因) - handleTaskEvent 的对话不匹配守卫要求当前对话 id 为真才生效, 空 id 被绕过 - socket 的 thinking/text 六个流式处理器不做 conversation_id 检查 修复:显式新建路由下 restoreTaskState 直接返回;事件守卫把 "空 id + 显式新建路由"判为不匹配;流式处理器补对话守卫。 从 /new 发送消息不受影响(先建对话改路由,后才启动轮询)。
This commit is contained in:
parent
4596c67967
commit
04bd93646b
@ -112,6 +112,23 @@ export const compressionMethods = {
|
||||
messagesLen: Array.isArray(this.messages) ? this.messages.length : -1
|
||||
});
|
||||
|
||||
// 显式新建对话路由(/new、/multiagent/new):运行中的任务属于上一个对话,
|
||||
// 用户主动选择了空白页。这里不能接管任务/重放事件/恢复轮询——
|
||||
// loadRunningTask(null) 会匹配任意运行中任务,一旦接管,该对话的
|
||||
// 用户输入/AI输出/工具调用会被全量重放到空白页(刷新也复现)。
|
||||
// 侧边栏运行标识由 refreshRunningWorkspaceTasks 独立维护,不受影响。
|
||||
if (
|
||||
!this.currentConversationId &&
|
||||
typeof this.isExplicitNewConversationRoute === 'function' &&
|
||||
this.isExplicitNewConversationRoute()
|
||||
) {
|
||||
restoreDebugLog('restore:skip-explicit-new-route', {
|
||||
path: typeof window !== 'undefined' ? window.location.pathname : ''
|
||||
});
|
||||
this._restoreTaskStateWaitCount = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const { useTaskStore } = await import('../../../stores/task');
|
||||
const taskStore = useTaskStore();
|
||||
|
||||
@ -70,12 +70,20 @@ export const lifecycleMethods = {
|
||||
'shallow_compression',
|
||||
'compression_finished'
|
||||
]);
|
||||
if (
|
||||
!crossConversationAllowed.has(eventType) &&
|
||||
// 显式新建路由(/new、/multiagent/new)上 currentConversationId 为空是常态:
|
||||
// 空 id 不等于“无归属”,此时任何携带 conversation_id 的事件都属于其他对话,
|
||||
// 必须丢弃,否则运行中对话的用户输入/AI输出/工具调用会渲染到空白页。
|
||||
const onExplicitNewRoute =
|
||||
typeof this.isExplicitNewConversationRoute === 'function' &&
|
||||
this.isExplicitNewConversationRoute();
|
||||
const eventConversationMismatch = !!(
|
||||
eventData.conversation_id &&
|
||||
this.currentConversationId
|
||||
) {
|
||||
if (eventData.conversation_id !== this.currentConversationId) {
|
||||
(this.currentConversationId
|
||||
? eventData.conversation_id !== this.currentConversationId
|
||||
: onExplicitNewRoute)
|
||||
);
|
||||
if (!crossConversationAllowed.has(eventType) && eventConversationMismatch) {
|
||||
{
|
||||
if (
|
||||
[
|
||||
'ai_message_start',
|
||||
|
||||
@ -1098,7 +1098,12 @@ export async function initializeLegacySocket(ctx: any) {
|
||||
});
|
||||
|
||||
// 思考流开始
|
||||
ctx.socket.on('thinking_start', () => {
|
||||
ctx.socket.on('thinking_start', (data) => {
|
||||
// 对话定向事件:只响应当前对话,避免运行中对话的流式输出渲染到 /new 等空白页。
|
||||
if (data?.conversation_id && data.conversation_id !== ctx.currentConversationId) {
|
||||
socketLog('跳过thinking_start(对话不匹配)', data.conversation_id);
|
||||
return;
|
||||
}
|
||||
// 轮询模式下跳过 WebSocket 事件
|
||||
if (ctx.usePollingMode && !ctx.waitingForSubAgent) {
|
||||
socketLog('思考开始 (轮询模式,跳过)');
|
||||
@ -1125,6 +1130,10 @@ export async function initializeLegacySocket(ctx: any) {
|
||||
|
||||
// 思考内容块
|
||||
ctx.socket.on('thinking_chunk', (data) => {
|
||||
// 对话定向事件:只响应当前对话。
|
||||
if (data?.conversation_id && data.conversation_id !== ctx.currentConversationId) {
|
||||
return;
|
||||
}
|
||||
// 轮询模式下跳过 WebSocket 事件
|
||||
if (ctx.usePollingMode && !ctx.waitingForSubAgent) {
|
||||
return;
|
||||
@ -1147,6 +1156,11 @@ export async function initializeLegacySocket(ctx: any) {
|
||||
|
||||
// 思考结束
|
||||
ctx.socket.on('thinking_end', (data) => {
|
||||
// 对话定向事件:只响应当前对话。
|
||||
if (data?.conversation_id && data.conversation_id !== ctx.currentConversationId) {
|
||||
socketLog('跳过thinking_end(对话不匹配)', data.conversation_id);
|
||||
return;
|
||||
}
|
||||
// 轮询模式下跳过 WebSocket 事件
|
||||
if (ctx.usePollingMode && !ctx.waitingForSubAgent) {
|
||||
socketLog('思考结束 (轮询模式,跳过)');
|
||||
@ -1171,7 +1185,12 @@ export async function initializeLegacySocket(ctx: any) {
|
||||
});
|
||||
|
||||
// 文本流开始
|
||||
ctx.socket.on('text_start', () => {
|
||||
ctx.socket.on('text_start', (data) => {
|
||||
// 对话定向事件:只响应当前对话。
|
||||
if (data?.conversation_id && data.conversation_id !== ctx.currentConversationId) {
|
||||
socketLog('跳过text_start(对话不匹配)', data.conversation_id);
|
||||
return;
|
||||
}
|
||||
// 轮询模式下跳过 WebSocket 事件
|
||||
if (ctx.usePollingMode && !ctx.waitingForSubAgent) {
|
||||
socketLog('文本开始 (轮询模式,跳过)');
|
||||
@ -1191,6 +1210,10 @@ export async function initializeLegacySocket(ctx: any) {
|
||||
|
||||
// 文本内容块
|
||||
ctx.socket.on('text_chunk', (data) => {
|
||||
// 对话定向事件:只响应当前对话。
|
||||
if (data?.conversation_id && data.conversation_id !== ctx.currentConversationId) {
|
||||
return;
|
||||
}
|
||||
// 轮询模式下跳过 WebSocket 事件
|
||||
if (ctx.usePollingMode && !ctx.waitingForSubAgent) {
|
||||
return;
|
||||
@ -1228,6 +1251,11 @@ export async function initializeLegacySocket(ctx: any) {
|
||||
|
||||
// 文本结束
|
||||
ctx.socket.on('text_end', (data) => {
|
||||
// 对话定向事件:只响应当前对话。
|
||||
if (data?.conversation_id && data.conversation_id !== ctx.currentConversationId) {
|
||||
socketLog('跳过text_end(对话不匹配)', data.conversation_id);
|
||||
return;
|
||||
}
|
||||
// 轮询模式下跳过 WebSocket 事件
|
||||
if (ctx.usePollingMode && !ctx.waitingForSubAgent) {
|
||||
socketLog('文本结束 (轮询模式,跳过)');
|
||||
|
||||
Loading…
Reference in New Issue
Block a user