diff --git a/src/hooks/useSessionManager.test.tsx b/src/hooks/useSessionManager.test.tsx index 1331931f..1cb0d63b 100644 --- a/src/hooks/useSessionManager.test.tsx +++ b/src/hooks/useSessionManager.test.tsx @@ -80,4 +80,29 @@ describe('useSessionManager', () => { expect.objectContaining({ name: 'APIError' }), ) }) + + it('keeps loaded state during force reload with rendered messages (SSE reconnect)', async () => { + // 重连后:markAllSessionsStale 已标记 isStale,但消息仍在渲染中 + messageStoreMock.getSessionState.mockReturnValue({ + messages: [{ info: { id: 'msg-1', role: 'user' }, parts: [] }], + loadState: 'loaded', + isStale: true, + isStreaming: false, + }) + getSessionMessagesMock.mockResolvedValue([ + { info: { id: 'msg-1', role: 'user', time: { created: 1, completed: 1 } }, parts: [] }, + ]) + + const { result } = renderHook(() => useSessionManager({ sessionId: null, directory: '/workspace/demo' })) + + await result.current.loadSession('session-1', { force: true }) + + // 不回退 loading(ChatPane 在 loading 会卸载 ChatArea,滚动位置丢失) + expect(messageStoreMock.setLoadState).not.toHaveBeenCalled() + expect(messageStoreMock.setMessages).toHaveBeenCalledWith( + 'session-1', + expect.anything(), + expect.anything(), + ) + }) }) diff --git a/src/hooks/useSessionManager.ts b/src/hooks/useSessionManager.ts index d0276b70..c46ac13d 100644 --- a/src/hooks/useSessionManager.ts +++ b/src/hooks/useSessionManager.ts @@ -176,7 +176,12 @@ export function useSessionManager({ sessionId, directory, onLoadComplete, onErro return } - messageStore.setLoadState(sid, 'loading') + // force 补数据(SSE 重连)时页面已有渲染内容,不回退 loading—— + // ChatPane 在 loading 状态会卸载 ChatArea,重挂后滚动位置丢失; + // 无消息时(首次加载 / 加载失败重试)仍走正常 loading 流程 + if (!force || !hasExistingMessages) { + messageStore.setLoadState(sid, 'loading') + } try { // 并行加载 session 信息和消息(传递 directory)