#9195: Fix: Control UI fails to render new messages after chat.history WebSocket response
app: web-ui
stale
## Summary
Fixes #9183 - Control UI was failing to render new agent messages after successful chat.history WebSocket responses.
## Problem
When a chat run completed and the `final` event was received, `loadChatHistory()` was called to refresh the message list. However, the new messages never appeared in the UI without a manual page refresh. The browser console showed successful `[ws] ⇄ res ✓ chat.history` responses, indicating the data was received but not rendered.
## Root Cause
The `GatewayHost` type definition was missing properties required by `loadChatHistory()`:
- `chatLoading`
- `chatMessages`
- `chatThinkingLevel`
When `handleGatewayEvent()` called:
```typescript
void loadChatHistory(host as unknown as OpenClawApp);
```
The unsafe type cast (`as unknown as OpenClawApp`) passed TypeScript's checks, but at runtime:
1. `loadChatHistory()` tried to assign `state.chatMessages = newMessages`
2. This property didn't exist on the `GatewayHost` interface
3. The assignment had no effect on the OpenClawApp component's reactive `@state() chatMessages`
4. Lit Element never knew to re-render
TypeScript allowed the cast because `unknown` bypasses type checking, but the actual object structure didn't match expectations.
## Solution
Added the missing properties to the `GatewayHost` type definition:
```typescript
type GatewayHost = {
// ... existing properties
chatLoading: boolean;
chatMessages: unknown[];
chatThinkingLevel: string | null;
// ... rest
};
```
Now when `loadChatHistory()` updates these properties:
1. The assignments affect the actual OpenClawApp component state
2. The `@state()` decorator detects the change
3. Lit Element triggers a re-render
4. New messages appear automatically
## Why This Works
The `GatewayHost` type is used as a constraint for functions that manipulate the OpenClawApp state. By ensuring it includes all properties that event handlers need to update, we guarantee that:
- TypeScript type checking is accurate
- Runtime property assignments affect the correct Lit Element reactive state
- UI re-renders happen automatically when data changes
## Impact
✅ Messages now render immediately after agent replies
✅ No more manual page refreshes needed
✅ Fixes the UX issue reported in #9183
✅ Type safety improved - prevents similar bugs
✅ Single file changed, minimal risk
## Testing
**Before fix:**
1. Send message to agent
2. Agent responds
3. Message doesn't appear
4. Console shows `[ws] ⇄ res ✓ chat.history`
5. Hard refresh (Ctrl+Shift+R) shows the message
**After fix:**
1. Send message to agent
2. Agent responds
3. Message appears immediately ✅
4. No refresh needed
---
**Technical note:** This is a type system bug where an unsafe cast (`as unknown as T`) bypassed proper type checking. The fix tightens the type constraint to match runtime requirements.
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR updates the `GatewayHost` type in `ui/src/ui/app-gateway.ts` to include chat-related state (`chatLoading`, `chatMessages`, `chatThinkingLevel`, `chatStream`, `chatStreamStartedAt`) that is mutated by `loadChatHistory()` and other chat controllers.
By aligning `GatewayHost` with the `OpenClawApp` reactive `@state()` properties, the existing call site `loadChatHistory(host as unknown as OpenClawApp)` now reliably updates real reactive fields instead of assigning to missing properties on an object with an incompatible shape. It also removes two ad-hoc `unknown` casts previously used to reset `chatStream` and `chatStreamStartedAt` on connect.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk.
- The change is a type-level alignment in a single file and matches existing `OpenClawApp` reactive state fields used by chat controllers; it also reduces unsafe casts in the connect path.
- No files require special attention
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#9218: Fix Control UI chat resync on gaps and terminal events
by figitaki · 2026-02-05
80.5%
#14309: fix(ui): resolve chat event session key mismatch
by justonlyforyou · 2026-02-11
79.5%
#13902: fix: auto-recover on event gap instead of showing error
by nikogamulin · 2026-02-11
79.3%
#19343: Refactor chat state management: reset chat messages and queue on se...
by saurav470 · 2026-02-17
79.0%
#14966: fix(webchat): preserve user message visibility after chat.send
by BenediktSchackenberg · 2026-02-12
78.0%
#8678: fix(control-ui): restore useDefineForClassFields for Lit reactivity
by chainyoda · 2026-02-04
77.6%
#11889: fix(chat): filter HEARTBEAT_OK messages in chat.history when showOk...
by bendyclaw · 2026-02-08
76.9%
#16767: fix: auto-resync webchat on reconnect and prevent message flicker o...
by alewcock · 2026-02-15
76.9%
#3721: fix(ui): webchat not displaying chat responses
by maxmaxrouge-rgb · 2026-01-29
76.3%
#11647: fix(webchat): filter HEARTBEAT_OK messages from chat.history response
by liuxiaopai-ai · 2026-02-08
76.2%