fix(chat): 显式新建对话路由隔离后端残留上下文
/new 与 /multiagent/new 上不再被 terminal 状态快照、对话广播事件 拽回上一个对话;个性化默认值在显式新建路由下保持权威。
This commit is contained in:
parent
3c66c6b05f
commit
0aa8af8618
@ -132,10 +132,15 @@ export const resourceMethods = {
|
||||
// - 非空对话:以对话 meta 为准(enterConversation bootstrap 恢复),
|
||||
// status 快照不得覆盖(terminal 状态可能滞后于对话加载)
|
||||
// - 空对话/首页:terminal 状态即权威,从 status 同步
|
||||
// - 例外:显式新建路由(/new、/multiagent/new)上 terminal 状态属于上一个
|
||||
// 对话的残留上下文,不同步(个性化默认值是这里的权威,见 loadInitialData)
|
||||
const convId = this.currentConversationId;
|
||||
const hasConversation =
|
||||
typeof convId === 'string' && convId.length > 0 && !convId.startsWith('temp_');
|
||||
if (!hasConversation) {
|
||||
const onExplicitNewRoute =
|
||||
typeof this.isExplicitNewConversationRoute === 'function' &&
|
||||
this.isExplicitNewConversationRoute();
|
||||
if (!hasConversation && !onExplicitNewRoute) {
|
||||
if (status && typeof status.thinking_mode !== 'undefined') {
|
||||
this.thinkingMode = !!status.thinking_mode;
|
||||
}
|
||||
|
||||
@ -266,12 +266,22 @@ export const socketMethods = {
|
||||
|
||||
// 仅在“无当前对话”的新会话入口应用默认模型/模式;
|
||||
// 对于已存在对话(含刷新恢复/URL指定对话),必须保留对话自身设置。
|
||||
// 注意:显式新建路由(/new、/multiagent/new)上,后端的“当前对话”
|
||||
// 只是上一个对话的残留上下文,不等于本页要创建新对话的意图,
|
||||
// 因此此时也必须应用个性化默认值(与“新建空对话”按钮行为一致)。
|
||||
const statusConversationIdForDefaults = statusData?.conversation?.current_id;
|
||||
const hasActiveConversation =
|
||||
typeof statusConversationIdForDefaults === 'string' &&
|
||||
statusConversationIdForDefaults.length > 0 &&
|
||||
!statusConversationIdForDefaults.startsWith('temp_');
|
||||
if (personalizationStore.loaded && !hasActiveConversation && !this.currentConversationId) {
|
||||
const isExplicitNewRouteForDefaults =
|
||||
typeof this.isExplicitNewConversationRoute === 'function' &&
|
||||
this.isExplicitNewConversationRoute();
|
||||
if (
|
||||
personalizationStore.loaded &&
|
||||
!this.currentConversationId &&
|
||||
(!hasActiveConversation || isExplicitNewRouteForDefaults)
|
||||
) {
|
||||
const defaultRunMode = personalizationStore.form.default_run_mode;
|
||||
const defaultModel = personalizationStore.form.default_model;
|
||||
const defaultReasoningEffort = personalizationStore.form.default_reasoning_effort;
|
||||
@ -324,15 +334,16 @@ export const socketMethods = {
|
||||
const runningConversationId = await this.getRunningTaskConversationId();
|
||||
const statusConversationId = statusData.conversation && statusData.conversation.current_id;
|
||||
const resumeConversationId = statusConversationId || runningConversationId;
|
||||
const shouldResumeOnNewRoute = isExplicitNewRoute && !!runningConversationId;
|
||||
const currentPath = window.location.pathname.replace(/^\/+/, '');
|
||||
const isMultiAgentNewRoute = currentPath === 'multiagent/new' || currentPath === 'multiagent';
|
||||
|
||||
// 显式新建对话路由(/new、/multiagent/new)永不自动恢复运行中的对话:
|
||||
// 用户主动点击"新建对话"就是明确要空白页,运行中任务可从侧边栏随时切回。
|
||||
if (
|
||||
resumeConversationId &&
|
||||
!this.currentConversationId &&
|
||||
!isMultiAgentNewRoute &&
|
||||
(!isExplicitNewRoute || shouldResumeOnNewRoute)
|
||||
!isExplicitNewRoute
|
||||
) {
|
||||
this.skipConversationHistoryReload = true;
|
||||
// 首次从状态恢复对话时,避免 socket 的 conversation_loaded 再次触发历史加载
|
||||
|
||||
@ -772,8 +772,16 @@ export async function initializeLegacySocket(ctx: any) {
|
||||
|
||||
// 初始化期间不修改 currentConversationId,避免与 bootstrapRoute 冲突
|
||||
if (ctx.initialRouteResolved) {
|
||||
// 用户停留在显式新建对话页(/new、/multiagent/new)时,不被其他对话的
|
||||
// 广播事件(如运行中任务的标题生成)拽走视图,仅同步列表数据。
|
||||
const stayOnNewRoute =
|
||||
!data.cleared &&
|
||||
typeof ctx.isExplicitNewConversationRoute === 'function' &&
|
||||
ctx.isExplicitNewConversationRoute();
|
||||
if (!stayOnNewRoute) {
|
||||
ctx.currentConversationId = data.conversation_id;
|
||||
ctx.currentConversationTitle = data.title || '';
|
||||
}
|
||||
|
||||
// 更新对话列表中的标题
|
||||
if (data.title && Array.isArray(ctx.conversations)) {
|
||||
@ -897,19 +905,27 @@ export async function initializeLegacySocket(ctx: any) {
|
||||
// 监听状态更新事件
|
||||
ctx.socket.on('status_update', (status) => {
|
||||
ctx.applyStatusSnapshot(status);
|
||||
// 显式新建路由(/new、/multiagent/new):status 快照反映的是后端 terminal
|
||||
// 残留的旧对话上下文,既不能把它设成当前对话(防跳回),也不能让它
|
||||
// 覆盖刚应用的个性化默认运行模式。
|
||||
const onExplicitNewRoute =
|
||||
typeof ctx.isExplicitNewConversationRoute === 'function' &&
|
||||
ctx.isExplicitNewConversationRoute();
|
||||
// 只有在初始化完成后,才允许 status_update 修改 currentConversationId
|
||||
// 避免与 bootstrapRoute 冲突
|
||||
if (status.conversation && status.conversation.current_id) {
|
||||
if (ctx.initialRouteResolved && !ctx.currentConversationId) {
|
||||
if (ctx.initialRouteResolved && !ctx.currentConversationId && !onExplicitNewRoute) {
|
||||
// 初始化完成且当前没有对话ID,才设置
|
||||
ctx.currentConversationId = status.conversation.current_id;
|
||||
}
|
||||
}
|
||||
if (!onExplicitNewRoute) {
|
||||
if (typeof status.run_mode === 'string') {
|
||||
ctx.runMode = status.run_mode;
|
||||
} else if (typeof status.thinking_mode !== 'undefined') {
|
||||
ctx.runMode = status.thinking_mode ? 'thinking' : 'fast';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 用户消息(后台子智能体完成后自动触发)
|
||||
@ -1068,7 +1084,12 @@ export async function initializeLegacySocket(ctx: any) {
|
||||
});
|
||||
|
||||
// AI消息开始(已废弃,改用 REST API 轮询)
|
||||
ctx.socket.on('ai_message_start', () => {
|
||||
ctx.socket.on('ai_message_start', (data) => {
|
||||
// 用户级广播:只响应当前对话的 AI 消息开始事件。
|
||||
if (data?.conversation_id && data.conversation_id !== ctx.currentConversationId) {
|
||||
socketLog('跳过ai_message_start(对话不匹配)', data.conversation_id);
|
||||
return;
|
||||
}
|
||||
// 只处理子智能体模式
|
||||
if (ctx.waitingForSubAgent) {
|
||||
ctx.waitingForSubAgent = false;
|
||||
@ -1600,6 +1621,11 @@ export async function initializeLegacySocket(ctx: any) {
|
||||
|
||||
// 停止请求确认
|
||||
ctx.socket.on('stop_requested', (data) => {
|
||||
// 用户级广播:只清理当前对话的 pending 工具状态。
|
||||
if (data?.conversation_id && data.conversation_id !== ctx.currentConversationId) {
|
||||
socketLog('跳过stop_requested(对话不匹配)', data.conversation_id);
|
||||
return;
|
||||
}
|
||||
socketLog('停止请求已接收:', data.message);
|
||||
// 可以显示提示信息
|
||||
try {
|
||||
@ -1613,6 +1639,13 @@ export async function initializeLegacySocket(ctx: any) {
|
||||
|
||||
// 任务停止
|
||||
ctx.socket.on('task_stopped', (data) => {
|
||||
// 多对话并行运行:任务生命周期事件是用户级广播,只响应当前对话的,
|
||||
// 否则其他对话的停止会误清本对话的运行态(侧边栏标识由
|
||||
// refreshRunningWorkspaceTasks 独立轮询维护,不受影响)。
|
||||
if (data?.conversation_id && data.conversation_id !== ctx.currentConversationId) {
|
||||
socketLog('跳过task_stopped(对话不匹配)', data.conversation_id);
|
||||
return;
|
||||
}
|
||||
socketLog('任务已停止:', data.message);
|
||||
const hasRunningSubAgents = !!data?.has_running_sub_agents;
|
||||
const hasRunningBackgroundCommands = !!data?.has_running_background_commands;
|
||||
@ -1634,6 +1667,11 @@ export async function initializeLegacySocket(ctx: any) {
|
||||
|
||||
// 任务完成(重点:更新Token统计)
|
||||
ctx.socket.on('task_complete', (data) => {
|
||||
// 同 task_stopped:用户级广播,只响应当前对话的任务完成事件。
|
||||
if (data?.conversation_id && data.conversation_id !== ctx.currentConversationId) {
|
||||
socketLog('跳过task_complete(对话不匹配)', data.conversation_id);
|
||||
return;
|
||||
}
|
||||
socketLog('任务完成', data);
|
||||
|
||||
const hasRunningMultiAgent = !!data?.has_running_multi_agent;
|
||||
@ -1660,6 +1698,12 @@ export async function initializeLegacySocket(ctx: any) {
|
||||
|
||||
// 子智能体等待状态
|
||||
ctx.socket.on('sub_agent_waiting', (data) => {
|
||||
// 用户级广播:只响应当前对话的等待事件,避免把其他对话的
|
||||
// waitingForSubAgent 标志安到本对话上(会阻塞 resetAllStates)。
|
||||
if (data?.conversation_id && data.conversation_id !== ctx.currentConversationId) {
|
||||
socketLog('跳过sub_agent_waiting(对话不匹配)', data.conversation_id);
|
||||
return;
|
||||
}
|
||||
socketLog('等待子智能体完成:', data);
|
||||
|
||||
// 多智能体模式下,子智能体 idle/running 是常态,不阻塞主对话输入区
|
||||
@ -1711,6 +1755,11 @@ export async function initializeLegacySocket(ctx: any) {
|
||||
if (!data || !data.content) {
|
||||
return;
|
||||
}
|
||||
// 用户级广播:其他对话的系统提示不应串进当前对话视图。
|
||||
if (data.conversation_id && data.conversation_id !== ctx.currentConversationId) {
|
||||
socketLog('跳过system_message(对话不匹配)', data.conversation_id);
|
||||
return;
|
||||
}
|
||||
ctx.appendSystemAction(data.content);
|
||||
});
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user