fix: 工作过程误折叠/反复横跳——ready-to-show 二次触发不得重置回合状态

This commit is contained in:
Rick Ye
2026-09-10 11:43:37 +08:00
parent ddecaef4ef
commit 4c5a379ca1
3 changed files with 24 additions and 12 deletions
+7 -1
View File
@@ -81,10 +81,16 @@ async function createWindow(): Promise<void> {
}
})
// 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)
})
})
@@ -252,7 +252,8 @@ function AssistantTurnBase({
// live 回合从一开始就可见,挂载内容;一旦挂载过就保持(再次折叠走 GSAP
// 高度动画需要内容在场,且 Thinking 面板内部滚动状态不重置)。
const [contentMounted, setContentMounted] = useState<boolean>(() => 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)
}}
@@ -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':