Skip to content

fix(web-chat): prevent blank chat pane after assistant response (#67035)#77418

Open
carlytwozero wants to merge 1 commit intoopenclaw:mainfrom
carlytwozero:fix/chat-blank-after-response
Open

fix(web-chat): prevent blank chat pane after assistant response (#67035)#77418
carlytwozero wants to merge 1 commit intoopenclaw:mainfrom
carlytwozero:fix/chat-blank-after-response

Conversation

@carlytwozero
Copy link
Copy Markdown

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 chatLoading flag lifecycle when history reloads are triggered by terminal chat events:

Gap 1 — pre-set missing before void calls
In handleTerminalChatEvent and handleChatGatewayEvent, loadChatHistory is called with void (fire-and-forget). chatLoading = true is set inside the async function synchronously before the first await, but there's no guarantee a reactive render won't fire in the gap between the call site and function entry. Explicitly pre-setting chatLoading = true at each call site eliminates this window.

Gap 2 — early-exit path never cleared chatLoading
If loadChatHistory returned early due to !state.client || !state.connected, any chatLoading = true that had been pre-set externally was never reset. This left the UI stuck showing a loading state instead of cached messages. Adding state.chatLoading = false to the early-exit branch fixes this.

Together these close the render window where:
chatStream = nullchatMessages not yet updated → chatLoading still false → isEmpty = true → blank pane.

Changes

ui/src/ui/app-gateway.ts — pre-set chatLoading = true at all three void loadChatHistory() call sites (tool-turn path in handleTerminalChatEvent, final-event-needs-reload path, and deferred session-message reload path).

ui/src/ui/controllers/chat.ts — reset chatLoading = false in the early-return path so pre-set loading flag doesn't get stuck.

Test plan

  • Send a message and confirm response appears without refresh
  • Tool-call turn: response and tool results appear without refresh
  • Send a message while briefly offline, reconnect — no stuck loading spinner
  • Silent-reply / heartbeat turns: no blank flash in visible sessions

Fixes #67035

🤖 Generated with Claude Code

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>
@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented May 4, 2026

Codex review: needs changes before merge.

Summary
The PR pre-sets chatLoading before terminal-event chat history reloads in ui/src/ui/app-gateway.ts and clears chatLoading when loadChatHistory exits early while disconnected.

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
A repair worker can safely add the missing changelog entry; any PR-body closing-reference change should be left for maintainer handling if needed.

Security
Cleared: The diff only changes Control UI chat state flags and does not touch CI, dependencies, secrets, release, install, or code-execution surfaces.

Review findings

  • [P3] Add the required changelog entry — CHANGELOG.md:11
Review details

Best 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 loadChatHistory, and the PR should not broadly close #67035 without maintainer agreement.

Full review comments:

  • [P3] Add the required changelog entry — CHANGELOG.md:11
    This is a user-facing Control UI/WebChat fix, and repo policy requires user-facing fix, feat, and perf changes to include a single-line CHANGELOG.md entry. Please add an Unreleased bullet for the blank chat pane/history reload fix before merge.
    Confidence: 0.91

Overall correctness: patch is correct
Overall confidence: 0.74

Acceptance criteria:

  • git diff --check
  • pnpm exec oxfmt --check --threads=1 CHANGELOG.md

What I checked:

  • PR scope: The PR changes only ui/src/ui/app-gateway.ts and ui/src/ui/controllers/chat.ts, with 10 additions and 3 deletions, matching the narrow loading-state lifecycle described in the PR body. (6efe3f1008fd)
  • Terminal reload paths: Current main has the three terminal-event history reload paths the PR targets: tool-final reload, non-renderable final reload, and deferred session-message replay reload. (ui/src/ui/app-gateway.ts:596, 37c0520a0b9c)
  • Loading lifecycle: loadChatHistory currently returns immediately when disconnected, otherwise sets chatLoading = true before the first awaited chat.history request and clears it in the latest-request finally block. (ui/src/ui/controllers/chat.ts:387, 37c0520a0b9c)
  • Render condition: The chat view shows an empty/welcome state when there are no chat items and loading is false, and shows a loading skeleton when loading is true with no items. (ui/src/ui/views/chat.ts:850, 37c0520a0b9c)
  • WebChat contract: The WebChat docs confirm chat.history is the durable history source and note that if live assistant text disappears after reload, the Control UI optimistic-tail merge and chat.history projection are the relevant surfaces to inspect. Public docs: docs/web/webchat.md. (docs/web/webchat.md:45, 37c0520a0b9c)
  • Related issue context: The linked issue has multiple field reports across Windows, macOS, and Ubuntu, plus a prior ClawSweeper comment keeping it open because existing history-reload fixes did not cover all reported UI symptoms.

Likely related people:

  • BunsDev: Recent Control UI chat/session work touched ui/src/ui/app-gateway.ts and related chat state paths, including chat load churn and local session continuity fixes. (role: recent maintainer; confidence: high; commits: 098b72910dea, 05c9492bff0f, cb9d7884cca3; files: ui/src/ui/app-gateway.ts, ui/src/ui/controllers/chat.ts)
  • vincentkoc: Likely related by prior merged work stabilizing WebChat final reload reconciliation and clearing pending WebChat state for completed active runs. (role: feature-history owner; confidence: high; commits: cff991c88d04, 02908db62b30; files: ui/src/ui/app-gateway.ts, ui/src/ui/controllers/chat.ts)
  • steipete: Recent adjacent fixes changed optimistic chat history behavior, canonical session events, and Control UI/WebChat browser-safety around the same chat controller surface. (role: adjacent maintainer; confidence: medium; commits: f739edcf4c7e, 07877d71cd17, 8cddb6ce7d06; files: ui/src/ui/controllers/chat.ts, ui/src/ui/app-gateway.ts)

Remaining risk / open question:

Codex review notes: model gpt-5.5, reasoning high; reviewed against 37c0520a0b9c.

Re-review progress:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: 2026.4.14 Windows chat UI regression: input text swallowed, streamed replies often invisible until refresh, typing indicator flashes then blanks

1 participant