openclaw - ✅(Solved) Fix Control UI: /clear button restores stale history after reset (race condition in ap()) [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#65719Fetched 2026-04-14 05:40:38
View on GitHub
Comments
0
Participants
1
Timeline
2
Reactions
0
Author
Participants
Timeline (top)
cross-referenced ×1referenced ×1

The Clear chat history button in the control UI appears to do nothing — clicking it leaves old messages visible. Clicking Reset works correctly.

Root Cause

In dist/control-ui/assets/index-D0pCc5YA.js, the ap() function handles the /clear slash command:

async function ap(e) {
  if (!(!e.client || !e.connected)) {
    try {
      await e.client.request(`sessions.reset`, { key: e.sessionKey }),
      e.chatMessages = [],
      e.chatSideResult = null,
      e.chatSideResultTerminalRuns?.clear(),
      e.chatStream = null,
      e.chatRunId = null,
      await bf(e)   // ← THIS IS THE BUG
    } catch (t) { e.lastError = String(t) }
    Gr(e)
  }
}

After sessions.reset resolves, bf(e) immediately calls chat.history. Because the server's session file transition isn't fully flushed at that point, chat.history returns the just-archived session's messages — which get written back into chatMessages. The local e.chatMessages = [] is effectively overwritten with the old history. Net result: the UI clears for a frame, then old messages reload.

The commands.log confirms the bug: clear button clicks appear as "source": "gateway:sessions.reset", "senderId": "unknown" (three entries at 04:25, 04:26, 04:32 UTC today) — the server-side reset is succeeding, but the UI race undoes it visually.

Fix Action

Fix

Remove await bf(e) from ap(). The local state (chatMessages, chatStream, etc.) is already zeroed; the subscription mechanism handles any needed history refresh on next interaction.

async function ap(e) {
  if (!(!e.client || !e.connected)) {
    try {
      await e.client.request(`sessions.reset`, { key: e.sessionKey }),
      e.chatMessages = [],
      e.chatSideResult = null,
      e.chatSideResultTerminalRuns?.clear(),
      e.chatStream = null,
      e.chatRunId = null
      // bf(e) removed — was causing stale history to reload
    } catch (t) { e.lastError = String(t) }
    Gr(e)
  }
}

Optionally, also route clear through sessions.send('/clear') to match the Reset button's pattern and restore proper sender attribution in the command log.

PR fix notes

PR #65750: fix(control-ui): stop reloading history after clear (#65719)

Description (problem / solution / changelog)

Summary

`clearChatHistory()` in `ui/src/ui/app-chat.ts` called `loadChatHistory()` immediately after `sessions.reset` resolved, racing the server-side session-archive flush. `chat.history` returned the just-archived session's messages, which then overwrote the zeroed local state. Net effect: clicking the "Clear" button flashed the cleared state for a frame, then repopulated with the old history.

Credit to @mickey (issue #65719 reporter) for tracing the exact root cause and proposing this fix — this PR just ports the proposed change to the TS source.

Closes #65719.

Fix

Remove the follow-up `loadChatHistory` call. Local state (`chatMessages`, `chatSideResult`, `chatStream`, `chatRunId`) is already zeroed right before this, and the normal subscription path will refresh on the next interaction. Reset button behavior is unaffected (it goes through `sessions.send('/reset')`).

Changes

  • `ui/src/ui/app-chat.ts` — drop `await loadChatHistory(host as unknown as ChatState)` from `clearChatHistory()` and add a short comment explaining the race

Test plan

  • Minimal 1-line removal (+4 lines of comment explaining why)
  • No behavior change for the Reset button path (separate code path through `sessions.send('/reset')`)
  • Subscription mechanism continues to handle history refresh on next interaction

🤖 Generated with Claude Code

Changed files

  • ui/src/ui/app-chat.ts (modified, +5/-1)

Code Example

async function ap(e) {
  if (!(!e.client || !e.connected)) {
    try {
      await e.client.request(`sessions.reset`, { key: e.sessionKey }),
      e.chatMessages = [],
      e.chatSideResult = null,
      e.chatSideResultTerminalRuns?.clear(),
      e.chatStream = null,
      e.chatRunId = null,
      await bf(e)   // ← THIS IS THE BUG
    } catch (t) { e.lastError = String(t) }
    Gr(e)
  }
}

---

async function ap(e) {
  if (!(!e.client || !e.connected)) {
    try {
      await e.client.request(`sessions.reset`, { key: e.sessionKey }),
      e.chatMessages = [],
      e.chatSideResult = null,
      e.chatSideResultTerminalRuns?.clear(),
      e.chatStream = null,
      e.chatRunId = null
      // bf(e) removed — was causing stale history to reload
    } catch (t) { e.lastError = String(t) }
    Gr(e)
  }
}
RAW_BUFFERClick to expand / collapse

Summary

The Clear chat history button in the control UI appears to do nothing — clicking it leaves old messages visible. Clicking Reset works correctly.

Root Cause

In dist/control-ui/assets/index-D0pCc5YA.js, the ap() function handles the /clear slash command:

async function ap(e) {
  if (!(!e.client || !e.connected)) {
    try {
      await e.client.request(`sessions.reset`, { key: e.sessionKey }),
      e.chatMessages = [],
      e.chatSideResult = null,
      e.chatSideResultTerminalRuns?.clear(),
      e.chatStream = null,
      e.chatRunId = null,
      await bf(e)   // ← THIS IS THE BUG
    } catch (t) { e.lastError = String(t) }
    Gr(e)
  }
}

After sessions.reset resolves, bf(e) immediately calls chat.history. Because the server's session file transition isn't fully flushed at that point, chat.history returns the just-archived session's messages — which get written back into chatMessages. The local e.chatMessages = [] is effectively overwritten with the old history. Net result: the UI clears for a frame, then old messages reload.

The commands.log confirms the bug: clear button clicks appear as "source": "gateway:sessions.reset", "senderId": "unknown" (three entries at 04:25, 04:26, 04:32 UTC today) — the server-side reset is succeeding, but the UI race undoes it visually.

Secondary Issue

Unlike the Reset button (which routes through sessions.send('/reset') and gets proper sender attribution: source: "webchat", senderId: "openclaw-control-ui"), the Clear button calls sessions.reset directly without sender context. This makes log-based debugging confusing.

Fix

Remove await bf(e) from ap(). The local state (chatMessages, chatStream, etc.) is already zeroed; the subscription mechanism handles any needed history refresh on next interaction.

async function ap(e) {
  if (!(!e.client || !e.connected)) {
    try {
      await e.client.request(`sessions.reset`, { key: e.sessionKey }),
      e.chatMessages = [],
      e.chatSideResult = null,
      e.chatSideResultTerminalRuns?.clear(),
      e.chatStream = null,
      e.chatRunId = null
      // bf(e) removed — was causing stale history to reload
    } catch (t) { e.lastError = String(t) }
    Gr(e)
  }
}

Optionally, also route clear through sessions.send('/clear') to match the Reset button's pattern and restore proper sender attribution in the command log.

Version

2026.4.11

Steps to Reproduce

  1. Open control UI, have an active chat session with messages
  2. Click the Clear (trash icon) button
  3. Messages remain — UI appears unchanged
  4. Click Reset — works correctly

extent analysis

TL;DR

Remove await bf(e) from the ap() function to prevent stale history from reloading after clearing the chat.

Guidance

  • The issue is caused by the bf(e) function being called immediately after sessions.reset, which reloads the old chat history.
  • To fix this, remove the await bf(e) line from the ap() function, as the local state is already zeroed and the subscription mechanism will handle any needed history refresh.
  • Optionally, consider routing the clear button through sessions.send('/clear') to match the Reset button's pattern and restore proper sender attribution in the command log.
  • Verify the fix by clicking the Clear button and checking that the chat history is properly cleared.

Example

The corrected ap() function would look like this:

async function ap(e) {
  if (!(!e.client || !e.connected)) {
    try {
      await e.client.request(`sessions.reset`, { key: e.sessionKey }),
      e.chatMessages = [],
      e.chatSideResult = null,
      e.chatSideResultTerminalRuns?.clear(),
      e.chatStream = null,
      e.chatRunId = null
    } catch (t) { e.lastError = String(t) }
    Gr(e)
  }
}

Notes

This fix assumes that the bf(e) function is not necessary for other functionality. If it is, alternative solutions may be needed.

Recommendation

Apply the workaround by removing await bf(e) from the ap() function, as it is a straightforward fix that addresses the root cause of the issue.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING