修复: CR-25 分离窗口状态机(destroyed 恢复 panelOpen/核 ai_is_generating/不自动 switch)

R3 win.once destroyed 回调补 state.panelOpen=true(X 关分离窗口后主面板自动恢复,无需手动 Ctrl+I);R4 resumeInDetached 先 await invoke('ai_is_generating') 核后端真值,generating=true 才重建生成态(置 streaming+占位气泡),false/Err 清 df-ai-gen 残留不重建(防假气泡+watchdog 130s 假超时);R5 移除 resumeInDetached 自动 switchConversation(避免覆盖 AiSession 单例 activeConversationId 致主窗口期间发消息落错会话,B-22 延伸),分离窗口可看历史列表但切换改显式触发。批9 agent,vue-tsc 0
This commit is contained in:
2026-06-15 08:23:33 +08:00
parent 5e6aa7920a
commit ac8dab3855

View File

@@ -4,13 +4,12 @@
//! - _unlistenMove / _unlistenResize: 主窗口 move/resize 跟随的 unlistener
//!
//! 耦合:
//! - detachPanel/resumeInDetached 调 useAiConversations.switchConversation
//! - resumeInDetached 调 aiShared.nextMsgId 占位 ai 气泡
//! - resumeInDetached 调 aiShared.nextMsgId 占位 ai 气泡 + invoke('ai_is_generating') 核对后端真值
//! - reattachPanel/detachPanel 调 useAiPanel.persistUiState
import { invoke } from '@tauri-apps/api/core'
import { state } from '../../stores/ai'
import { nextMsgId } from './aiShared'
import { switchConversation } from './useAiConversations'
import { persistUiState } from './useAiPanel'
// ── 主窗口事件跟随 unlistener ──
@@ -54,6 +53,8 @@ async function detachPanel() {
win.once('tauri://destroyed', () => {
state.detached = false
state.docked = false
// R3: X 关分离窗口后主面板自动恢复,无需手动 Ctrl+I
state.panelOpen = true
stopFollowMain()
})
state.detached = true
@@ -77,10 +78,26 @@ async function reattachPanel() {
/** 分离窗口挂载时接管主窗口当前对话(含生成中态) */
async function resumeInDetached(convId: string | null) {
const id = convId || state.activeConversationId
if (id) await switchConversation(id)
// R5: 不自动 switchConversation —— 分离窗口可看历史列表,但不主动覆盖主窗口 activeConversationId
// (避免主窗口期间发消息落错会话)。若需切换会话,由用户在分离窗口显式操作触发。
void convId
const gen = localStorage.getItem('df-ai-gen')
if (gen) {
// R4: 先核对后端 ai_is_generating 真值,generating=true 才重建生成态,
// 避免 df-ai-gen 残留导致假气泡 + 130s 后 watchdog 假超时
let backendGenerating = false
try {
backendGenerating = await invoke<boolean>('ai_is_generating')
} catch (e) {
console.error('[AI] resumeInDetached: 核对 ai_is_generating 失败,跳过重建生成态', e)
return
}
if (!backendGenerating) {
// 后端已不再生成,清残留快照,不重建
localStorage.removeItem('df-ai-gen')
localStorage.removeItem('df-ai-text')
return
}
// 接管正在生成的对话:恢复已生成文本并补占位,后续 delta 继续追加
state.currentText = localStorage.getItem('df-ai-text') || ''
state.messages.push({