修复: aichat 切换/新建对话缺陷(队列串会话/回切丢消息/审批误终态化/删除复活/切换链路)

This commit is contained in:
lxy
2026-08-08 14:20:10 +08:00
parent 795e05f42d
commit 9f75db5b15
8 changed files with 511 additions and 325 deletions
+20 -5
View File
@@ -25,7 +25,7 @@ import { aiApi } from '@/api'
import { useAppSettingsStore } from '@/stores/appSettings'
import { state } from '@/stores/ai'
import { t } from '@/i18n/i18n-helpers'
import { nextMsgId, findToolCall, startApprovalTimer, clearApprovalTimer, clearAllApprovalTimers, convStates, setConvState } from './aiShared'
import { nextMsgId, findToolCall, startApprovalTimer, clearApprovalTimer, clearAllApprovalTimers, convStates, setConvState, switchingConvs, getConvStreamState, setConvCurrentText, setConvStreaming } from './aiShared'
// 批4 双轨收口:getConvState 下沉到 aiShared,本模块 re-export 保持消费方
// (ChatInput.vue/MaxRoundsCard.vue 等)import 路径不变,组件零改动透明继承。
export { getConvState } from './aiShared'
@@ -877,15 +877,30 @@ export function handleEvent(event: AiChatEvent) {
// 不影响其他态(handleUserMessageEvent 去重幂等)。
if (handleUserMessageEvent(event)) return
// 事件不属于当前展示对话(生成中切走了)→ 不污染当前视图,仅完成/错误/求助时刷新侧边栏
// L1 求助协议(§2.3):AiHelpRequired 同 AiError 后端已 guard.reset 终止 loop,需收敛生成态。
const isCurrent = !convId || convId === state.activeConversationId
if (!isCurrent) {
if (event.type === 'AiCompleted' || event.type === 'AiError' || event.type === 'AiHelpRequired') {
// 批4 双轨收口:非当前会话终止事件,收敛 convStates(删 Map 项回 idle/不在生成),
// 对齐 :592/:660/:711 当前会话分支语义。非当前会话的 error 态无消费方(MaxRoundsCard/
// ChatInput 均读 activeConversationId),回退 null 与停止按钮 streaming 回退行为等价。
// 非当前会话终止事件:收敛会话状态(删 Map 项回不在生成)。非当前会话的 error 态无
// 消费方(操作卡/输入区均读 activeConversationId),回退 null 与停止按钮回退行为等价。
convStates.delete(convId || '')
void loadConversations()
// 后台会话终止也触发队列续发/清队(原 isCurrent 守卫拦截导致非当前会话排队消息永不
// drain,切回后队列卡死)。完成触发续发;错误终止对齐当前会话分支清该会话队列。
if (event.type === 'AiCompleted') {
emit('ai-drain-queue', { conversationId: event.conversation_id })
} else if (event.type === 'AiError') {
if (event.conversation_id) {
state.queue = state.queue.filter(q => q.conversationId !== event.conversation_id)
} else {
state.queue = []
}
}
} else if (event.type === 'AiTextDelta' && convId && switchingConvs.has(convId)) {
// 切换中缓冲:目标会话正被 switchConversation 拉取,该会话的 delta 累积到其 per-conv
// 流式态(而非丢弃),切换完成后由渲染层续显,避免切换窗口丢可见内容。不做气泡/工具
// 副作用(消息视图尚未切到目标会话,避免污染当前视图)。
setConvStreaming(convId, true)
setConvCurrentText(convId, (getConvStreamState(convId)?.currentText ?? '') + (event.delta ?? ''))
}
return
}