From 4c5a379ca1cba8557bc12d8fa52197efe08f5639 Mon Sep 17 00:00:00 2001 From: Rick Ye Date: Thu, 10 Sep 2026 11:43:37 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=B7=A5=E4=BD=9C=E8=BF=87=E7=A8=8B?= =?UTF-8?q?=E8=AF=AF=E6=8A=98=E5=8F=A0/=E5=8F=8D=E5=A4=8D=E6=A8=AA?= =?UTF-8?q?=E8=B7=B3=E2=80=94=E2=80=94ready-to-show=20=E4=BA=8C=E6=AC=A1?= =?UTF-8?q?=E8=A7=A6=E5=8F=91=E4=B8=8D=E5=BE=97=E9=87=8D=E7=BD=AE=E5=9B=9E?= =?UTF-8?q?=E5=90=88=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/desktop/src/main/index.ts | 8 +++++++- .../src/renderer/src/components/MessageItem.tsx | 11 ++++++----- apps/desktop/src/renderer/src/hooks/useAgent.ts | 17 +++++++++++------ 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/apps/desktop/src/main/index.ts b/apps/desktop/src/main/index.ts index 6d8dc26..f249c22 100644 --- a/apps/desktop/src/main/index.ts +++ b/apps/desktop/src/main/index.ts @@ -81,10 +81,16 @@ async function createWindow(): Promise { } }) + // ready-to-show 在 Electron 中可能不止一次触发(实测:回合中途首次挂载受管浏览器 + // WebContentsView 后会再次发出)。会话初始化只能做一次——二次触发会全量广播 + // session_switched,把渲染层进行中的回合状态清掉(过程区误折叠/反复横跳的根因)。 + let sessionInitialized = false win.on('ready-to-show', () => { win.show() + if (sessionInitialized) return + sessionInitialized = true // pi 会话初始化放在窗口就绪后,错误可以第一时间在 UI 上呈现 - agentService.ensureReady().catch((err) => { + agentService.ensureReady().catch((err: unknown) => { console.error('[main] pi session init failed:', err) }) }) diff --git a/apps/desktop/src/renderer/src/components/MessageItem.tsx b/apps/desktop/src/renderer/src/components/MessageItem.tsx index d1321c1..c9f5afb 100644 --- a/apps/desktop/src/renderer/src/components/MessageItem.tsx +++ b/apps/desktop/src/renderer/src/components/MessageItem.tsx @@ -252,7 +252,8 @@ function AssistantTurnBase({ // live 回合从一开始就可见,挂载内容;一旦挂载过就保持(再次折叠走 GSAP // 高度动画需要内容在场,且 Thinking 面板内部滚动状态不重置)。 const [contentMounted, setContentMounted] = useState(() => live) - const autoCollapsedRef = useRef(false) + // 用户手动收起过的回合不再自动展开;自动收起(结算/技术性重挂载)不受此限 + const userCollapsedRef = useRef(false) const prevLiveRef = useRef(live) useEffect(() => { const prev = prevLiveRef.current @@ -260,14 +261,14 @@ function AssistantTurnBase({ if (prev && !live) { const timer = window.setTimeout(() => { if (scrollPinnedRef?.current !== false) { - autoCollapsedRef.current = true setCollapsed(true) } }, 600) return () => window.clearTimeout(timer) } - if (!prev && live && autoCollapsedRef.current) { - autoCollapsedRef.current = false + // live 恢复时重新展开(含重挂载场景:初始收起的回合在回合续跑后自愈展开, + // 不依赖随重挂载丢失的 ref 状态);用户手动收起过的除外 + if (!prev && live && !userCollapsedRef.current) { setContentMounted(true) setCollapsed(false) } @@ -401,7 +402,7 @@ function AssistantTurnBase({ type="button" aria-expanded={!collapsed} onClick={() => { - autoCollapsedRef.current = false + userCollapsedRef.current = true setContentMounted(true) setCollapsed((v) => !v) }} diff --git a/apps/desktop/src/renderer/src/hooks/useAgent.ts b/apps/desktop/src/renderer/src/hooks/useAgent.ts index 48de44d..b4bae84 100644 --- a/apps/desktop/src/renderer/src/hooks/useAgent.ts +++ b/apps/desktop/src/renderer/src/hooks/useAgent.ts @@ -178,22 +178,27 @@ function reducer(state: AgentUiState, action: Action): AgentUiState { return { ...state, ready: true, sessionState: event.state } case 'session_error': return { ...state, sessionError: event.message } - case 'session_switched': + case 'session_switched': { + // 同一会话的技术性重发(初始化重放等)不得打断进行中的回合:保留回合 + // 状态,仅刷新会话数据与历史。真正的切换(新会话/切换/分叉)会话 id + // 不同,走完整重置。 + const sameSession = state.sessionState?.sessionId === event.state.sessionId return { ...state, ready: true, error: null, retry: null, - streaming: false, - turnActive: false, - queue: { steering: [], followUp: [] }, + streaming: sameSession ? state.streaming : false, + turnActive: sameSession ? state.turnActive : false, + queue: sameSession ? state.queue : { steering: [], followUp: [] }, stats: null, - compacting: false, - compactionNotice: null, + compacting: sameSession ? state.compacting : false, + compactionNotice: sameSession ? state.compactionNotice : null, sessionState: event.state, messages: historyToMessages(event.messages), tools: historyToTools(event.messages) } + } case 'agent_start': return { ...state, streaming: true, turnActive: true, error: null, retry: null } case 'agent_end':