fix(web-chat): prevent blank chat pane after assistant response (#67035)#77418
fix(web-chat): prevent blank chat pane after assistant response (#67035)#77418carlytwozero wants to merge 1 commit intoopenclaw:mainfrom
Conversation
After a turn completes, the UI could briefly or permanently show blank content. Two related issues: 1. When loadChatHistory is triggered by a final event (tool turns or non-renderable final messages), chatLoading was only set inside the async function body — synchronously, but still after the void call site returned. In practice loadChatHistory sets it before the first await, but explicitly pre-setting chatLoading = true at every call site in handleTerminalChatEvent and handleChatGatewayEvent makes the loading state visible to any synchronous re-render that fires between the call and the function body running. 2. When loadChatHistory returned early because the client was disconnected (!state.client || !state.connected), any chatLoading = true that had been pre-set externally was never cleared, leaving the UI stuck in a loading state rather than showing cached messages. Together these close the window where: streaming ends → chatStream = null → chatMessages not yet updated → chatLoading still false → UI renders empty (isEmpty = true) before the history reload finishes. Fixes openclaw#67035 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Codex review: needs changes before merge. Summary Reproducibility: no. I did not establish a high-confidence live reproduction against current main; source inspection shows the terminal reload and empty-render paths, but the claimed connected-state async window remains partly inferred. Next step before merge Security Review findings
Review detailsBest possible solution: Land the narrow state-lifecycle fix after adding the required changelog entry and preserving the broader linked issue as open or explicitly scoped if residual chat-input and streaming symptoms remain. Do we have a high-confidence way to reproduce the issue? No. I did not establish a high-confidence live reproduction against current main; source inspection shows the terminal reload and empty-render paths, but the claimed connected-state async window remains partly inferred. Is this the best way to solve the issue? Unclear. The early-return cleanup is a narrow maintainable change, but the call-site pre-set duplicates connected-state behavior already performed synchronously inside Full review comments:
Overall correctness: patch is correct Acceptance criteria:
What I checked:
Likely related people:
Remaining risk / open question:
Codex review notes: model gpt-5.5, reasoning high; reviewed against 37c0520a0b9c. Re-review progress:
|
Problem
After a turn completes, the chat UI could render blank — showing nothing where the assistant's response should be — until the user manually refreshed the page. The content was there in gateway history, just not displayed.
Root cause
Two gaps in the
chatLoadingflag lifecycle when history reloads are triggered by terminal chat events:Gap 1 — pre-set missing before
voidcallsIn
handleTerminalChatEventandhandleChatGatewayEvent,loadChatHistoryis called withvoid(fire-and-forget).chatLoading = trueis set inside the async function synchronously before the firstawait, but there's no guarantee a reactive render won't fire in the gap between the call site and function entry. Explicitly pre-settingchatLoading = trueat each call site eliminates this window.Gap 2 — early-exit path never cleared
chatLoadingIf
loadChatHistoryreturned early due to!state.client || !state.connected, anychatLoading = truethat had been pre-set externally was never reset. This left the UI stuck showing a loading state instead of cached messages. Addingstate.chatLoading = falseto the early-exit branch fixes this.Together these close the render window where:
chatStream = null→chatMessagesnot yet updated →chatLoadingstill false →isEmpty = true→ blank pane.Changes
ui/src/ui/app-gateway.ts— pre-setchatLoading = trueat all threevoid loadChatHistory()call sites (tool-turn path inhandleTerminalChatEvent, final-event-needs-reload path, and deferred session-message reload path).ui/src/ui/controllers/chat.ts— resetchatLoading = falsein the early-return path so pre-set loading flag doesn't get stuck.Test plan
Fixes #67035
🤖 Generated with Claude Code