Skip to content

fix(webchat): preserve refresh-visible history and composer state#83992

Merged
steipete merged 6 commits into
openclaw:mainfrom
spacegeologist:fix/webchat-refresh-history-composer
May 31, 2026
Merged

fix(webchat): preserve refresh-visible history and composer state#83992
steipete merged 6 commits into
openclaw:mainfrom
spacegeologist:fix/webchat-refresh-history-composer

Conversation

@spacegeologist

@spacegeologist spacegeologist commented May 19, 2026

Copy link
Copy Markdown
Contributor

Summary

Refs #83344.

This intentionally does not auto-close #83344 because session preview/title metadata remains out of scope for this PR.

Addresses two refresh-time WebChat state gaps from #83344:

  • expands the raw transcript window used by chat.history before visible-message projection/pagination, so recent visible conversation can be backfilled even when the latest raw transcript tail is mostly silent/internal traffic
  • persists WebChat composer draft text and queued messages per gateway/session in sessionStorage, then restores them after refresh/session switching

Notes

  • Uses sessionStorage instead of localStorage as the safer privacy default: drafts/queued prompts survive refresh in the same tab, but do not persist indefinitely across browser restarts.
  • Queued attachments are restored only when their payload data is available. If a queued attachment cannot be serialized safely, the queue item is not persisted rather than being restored without the attachment.
  • Session preview/title metadata is intentionally out of scope for this PR.

Real behavior proof

  • Behavior or issue addressed: WebChat refresh keeps visible chat history available after a tool-heavy/raw-tail transcript, and preserves same-tab composer draft plus queued messages for the same gateway/session.

  • Real environment tested: Local OpenClaw Control UI from this PR served by Vite at http://127.0.0.1:5173, connected in Google Chrome to a local loopback WebSocket gateway at ws://127.0.0.1:18789.

  • Exact steps or command run after this patch:

    1. Started the patched Control UI with npm --prefix ui run dev -- --host 127.0.0.1 --port 5173 --force.
    2. Started a local loopback WebSocket gateway that returns real gateway frames for connect, sessions.list, chat.history, and chat.send, and keeps the first chat.send run active.
    3. Opened Chrome to http://127.0.0.1:5173/chat?session=main.
    4. Verified history showed visible history before tool-heavy tail and visible assistant reply restored after refresh.
    5. Sent start long run proof, then queued queued proof after refresh while that run stayed active.
    6. Typed an unsent draft draft proof after refresh.
    7. Reloaded the browser tab and waited for the Control UI to reconnect to the same gateway/session.
  • Evidence after fix: Copied live output from the browser accessibility tree after reload included:

    URL: 127.0.0.1:5173/chat?session=main
    VERSION v proof-local-gateway
    Gateway status: Online
    visible history before tool-heavy tail
    visible assistant reply restored after refresh
    start long run proof
    Queued ( 1 )
    queued proof after refresh
    text entry area Value: draft proof after refresh
    Run status: In progress
    Queue message
    
  • Observed result after fix: The refreshed WebChat kept the same visible history messages, restored the queued message under Queued (1), and restored the unsent draft in the composer for session main. The queued message stayed in the queue rather than being delivered early on reconnect.

  • What was not tested: The gateway Vitest target did not run locally because root node_modules does not contain vitest/package.json after the full pnpm workspace install stalled; session preview/title metadata remains intentionally out of scope for this PR.

Tests

  • Added gateway coverage for chat.history backfilling visible messages when the raw tail is mostly NO_REPLY.
  • Added UI coverage for composer draft/queue restore, gateway/session scoping, clearing, attachment payload handling, and lifecycle persistence.
  • Ran npm --prefix ui test -- src/ui/chat/composer-persistence.test.ts src/ui/app-lifecycle.node.test.ts:
    • 2 test files passed
    • 8 tests passed
  • Ran git diff --check.
  • Ran a lightweight Node smoke check for ui/src/ui/chat/composer-persistence.ts.
  • Attempted OPENCLAW_GATEWAY_PROJECT_SHARDS=1 node scripts/run-vitest.mjs run --config test/vitest/vitest.gateway.config.ts src/gateway/server.chat.gateway-server-chat-b.test.ts; it failed before running tests because root node_modules is missing vitest/package.json in this local environment.

Full targeted Vitest was not run locally because dependency installation for the full 128-workspace pnpm repo stalled in this environment.

@openclaw-barnacle openclaw-barnacle Bot added app: web-ui App: web-ui gateway Gateway runtime size: L triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels May 19, 2026
@clawsweeper

clawsweeper Bot commented May 19, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed May 31, 2026, 4:20 AM ET / 08:20 UTC.

Summary
The PR widens WebChat refresh history backfill and adds per-gateway/session persistence for composer drafts and queued messages in browser sessionStorage.

PR surface: Source +459, Tests +380. Total +839 across 11 files.

Reproducibility: yes. at source level: current main stores chatMessage and chatQueue in component memory and reads a narrow raw transcript tail before visible projection, matching the reported refresh loss mode. I did not run a live browser before/after repro in this read-only review.

Review metrics: 2 noteworthy metrics.

  • Browser Storage Surface: 1 sessionStorage key family added. The new store retains user-authored WebChat draft and queue data in the browser, so maintainers should review the privacy boundary before merge.
  • Gateway History Read Window: 1 chat.history path widened from limit+1 to limit*20+21 raw lines/messages. The broader bounded read is the core history fix and changes per-refresh Gateway transcript I/O on a hot path.

Merge readiness
Overall: 🦐 gold shrimp
Proof: 🦞 diamond lobster
Patch quality: 🦐 gold shrimp
Result: needs maintainer review before merge.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Get explicit maintainer acceptance or a narrowing patch for sessionStorage retention of drafts, queued prompts, local command args, and attachment data URLs.
  • [P2] Let the latest head's required checks finish green before merge.

Mantis proof suggestion
A short browser recording would give maintainers direct visual proof of reload-restored history, draft text, and queue behavior. A maintainer can ask Mantis to capture proof by posting a new PR comment that starts with the OpenClaw Mantis account mention, followed by:

visual task: verify WebChat reload restores recent visible history, unsent draft text, and a queued prompt without sending it early.

Risk before merge

  • [P1] Browser sessionStorage will retain user-authored draft text, queued prompt text, local slash-command arguments, and serializable attachment data URLs until the browser clears the tab session; maintainers need to accept that privacy boundary.
  • [P1] Restored queues can now drain after refresh once a fresh sessions.list result says the selected session is idle, so queued prompts or local slash commands may be delivered later than the user last saw them.
  • [P1] The PR intentionally does not finish the session preview/title metadata part of [Bug]: WebChat refresh can lose visible conversation history when transcript tail is mostly internal tool traffic #83344, so it should not be treated as the complete fix for that issue cluster.
  • [P1] Latest head checks were still queued or in progress when inspected through the GitHub check-runs API, so required CI should settle before merge.

Maintainer options:

  1. Approve Current Retention Boundary
    Merge after required checks are green if maintainers explicitly accept same-tab sessionStorage retention for drafts, queued text, local command args, and serializable attachment payloads.
  2. Narrow Persisted Payloads First
    Before merge, remove attachment data URL persistence or add an explicit clearing/UX policy if maintainers do not want queued files retained in browser storage.
  3. Pause Queue Replay Semantics
    Pause the PR if restored queued prompts or local slash commands should require an explicit user action after refresh instead of auto-draining on fresh idle proof.

Next step before merge

  • [P2] The next action is maintainer judgment on privacy and replay semantics, not an autonomous repair against a clear code defect.

Security
Needs attention: The diff changes the browser-side sensitive-data retention boundary by storing drafts, queued prompts, local command args, and serializable attachment payloads in sessionStorage.

Review details

Best possible solution:

Land the focused history/composer fix only after maintainers explicitly accept or narrow the browser-storage and restored-queue replay boundaries, then keep the linked issues open or updated for remaining preview/title metadata work.

Do we have a high-confidence way to reproduce the issue?

Yes at source level: current main stores chatMessage and chatQueue in component memory and reads a narrow raw transcript tail before visible projection, matching the reported refresh loss mode. I did not run a live browser before/after repro in this read-only review.

Is this the best way to solve the issue?

Unclear as a product decision: the code path is a plausible focused fix, but the durable answer depends on whether maintainers accept sessionStorage retention and auto-drain semantics for restored queues. If not, the safer direction is to narrow persisted payloads or require explicit replay after refresh.

AGENTS.md: found and applied where relevant.

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

Label changes

Label changes:

  • add proof: sufficient: Contributor real behavior proof is sufficient. The PR body contains after-fix live browser output from a local Control UI connected to a loopback gateway showing restored visible history, a queued message, and an unsent draft after reload.

Label justifications:

  • P2: The PR addresses a normal-priority WebChat state-loss bug with limited blast radius but real user impact.
  • merge-risk: 🚨 session-state: The patch persists and restores WebChat draft and queue state across refresh and session switching.
  • merge-risk: 🚨 message-delivery: The patch can replay restored queued prompts and local slash commands after refresh once fresh session state reports idle.
  • merge-risk: 🚨 security-boundary: The patch stores prompt text, command args, and serializable attachment data URLs in browser sessionStorage.
  • rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🦞 diamond lobster and patch quality is 🦐 gold shrimp.
  • status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Sufficient (live_output): The PR body contains after-fix live browser output from a local Control UI connected to a loopback gateway showing restored visible history, a queued message, and an unsent draft after reload.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body contains after-fix live browser output from a local Control UI connected to a loopback gateway showing restored visible history, a queued message, and an unsent draft after reload.
Evidence reviewed

PR surface:

Source +459, Tests +380. Total +839 across 11 files.

View PR surface stats
Area Files Added Removed Net
Source 7 468 9 +459
Tests 4 381 1 +380
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 11 849 10 +839

Security concerns:

  • [medium] Accept browser storage retention — ui/src/ui/chat/composer-persistence.ts:326
    persistChatComposerState writes drafts and serialized queue items to sessionStorage, and serializeChatAttachment includes data URLs when available. That may be acceptable for same-tab refresh recovery, but it should be explicitly accepted or narrowed because prompts and attachments can contain sensitive data.
    Confidence: 0.88

Acceptance criteria:

  • [P1] npm --prefix ui test -- src/ui/chat/composer-persistence.test.ts src/ui/app-lifecycle.node.test.ts.
  • [P1] node scripts/run-vitest.mjs run --config test/vitest/vitest.gateway.config.ts src/gateway/server.chat.gateway-server-chat-b.test.ts.
  • [P1] git diff --check.

What I checked:

  • Repository policy read: Root AGENTS.md plus UI and Gateway scoped AGENTS.md files were read; their guidance makes persisted state, message delivery, security boundaries, and Gateway hot paths merge-sensitive review surfaces. (AGENTS.md:1, b81adc6202b2)
  • Current main composer state is memory-only: Current main initializes chatMessage and chatQueue as component state, so a full browser refresh rebuilds those values empty without a storage-backed restore path. (ui/src/ui/app.ts:245, b81adc6202b2)
  • Current main session switch only preserves in-memory queues: Current main saves and restores chatQueue by session during in-app switching, then clears chatMessage; that does not survive tab refresh. (ui/src/ui/app-render.helpers.ts:136, b81adc6202b2)
  • Current main history read is too narrow for tool-heavy tails: Current chat.history reads only max+1 raw local messages before visible-message projection, which matches the linked report's source-level failure mode when the raw tail is mostly silent/internal records. (src/gateway/server-methods/chat.ts:2441, b81adc6202b2)
  • PR widens bounded raw history reads: The PR changes chat.history to use resolveSessionHistoryTailReadOptions(max), reading a bounded raw window before visible projection while preserving maxBytes. (src/gateway/server-methods/chat.ts:2443, 5fc2e6c63972)
  • PR stores composer snapshots in sessionStorage: The new persistence path stores draft text and serialized queue items per gateway/session, including attachment data URLs when available. (ui/src/ui/chat/composer-persistence.ts:326, 5fc2e6c63972)

Likely related people:

  • steipete: Current-main blame for the relevant WebChat refresh/session-switch/Gateway history surfaces points to Peter Steinberger, the live PR is assigned to steipete, and the PR head commits in the provided context are authored by steipete. (role: recent area contributor and likely follow-up owner; confidence: high; commits: 5c38c0c76d27, 25a06c8e94e8, 5fc2e6c63972; files: ui/src/ui/app-chat.ts, ui/src/ui/app-render.helpers.ts, ui/src/ui/chat/composer-persistence.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. labels May 19, 2026
@openclaw-barnacle openclaw-barnacle Bot added proof: supplied External PR includes structured after-fix real behavior proof. and removed triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels May 19, 2026
@spacegeologist spacegeologist marked this pull request as ready for review May 19, 2026 10:39
@spacegeologist

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented May 19, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@spacegeologist spacegeologist force-pushed the fix/webchat-refresh-history-composer branch from 6bb9097 to 77025f3 Compare May 19, 2026 10:47
@spacegeologist

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented May 19, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels May 19, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 19, 2026
@spacegeologist

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. labels May 19, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 31, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels May 31, 2026
@steipete steipete force-pushed the fix/webchat-refresh-history-composer branch from 7e1f0c1 to b4c9804 Compare May 31, 2026 07:27
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 31, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 31, 2026
@steipete steipete force-pushed the fix/webchat-refresh-history-composer branch from b4c9804 to 4e475b9 Compare May 31, 2026 07:50
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 31, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 31, 2026
@steipete steipete force-pushed the fix/webchat-refresh-history-composer branch from 4e475b9 to 93b8d7a Compare May 31, 2026 08:03
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 31, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 31, 2026
@steipete steipete force-pushed the fix/webchat-refresh-history-composer branch from 93b8d7a to bc0bcb6 Compare May 31, 2026 08:10
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 31, 2026
@steipete steipete force-pushed the fix/webchat-refresh-history-composer branch from bc0bcb6 to 5fc2e6c Compare May 31, 2026 08:12
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 31, 2026
@steipete steipete merged commit 15ae2de into openclaw:main May 31, 2026
145 of 149 checks passed
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jun 1, 2026
…enclaw#83992)

WebChat now stores/restores composer draft and queued sends across refresh, scoped by gateway/session/agent. It skips in-flight/steered sends, restores after agent scope hydration, waits for fresh idle session proof before draining restored sends, and backfills visible chat history when the raw tail contains silent/context entries.

Refs openclaw#83344

Co-authored-by: Zee Zheng <zheng.zuo0@gmail.com>
SYU8384 pushed a commit to SYU8384/openclaw that referenced this pull request Jun 3, 2026
…enclaw#83992)

WebChat now stores/restores composer draft and queued sends across refresh, scoped by gateway/session/agent. It skips in-flight/steered sends, restores after agent scope hydration, waits for fresh idle session proof before draining restored sends, and backfills visible chat history when the raw tail contains silent/context entries.

Refs openclaw#83344

Co-authored-by: Zee Zheng <zheng.zuo0@gmail.com>
sablehead pushed a commit to sablehead/openclaw that referenced this pull request Jun 10, 2026
…enclaw#83992)

WebChat now stores/restores composer draft and queued sends across refresh, scoped by gateway/session/agent. It skips in-flight/steered sends, restores after agent scope hydration, waits for fresh idle session proof before draining restored sends, and backfills visible chat history when the raw tail contains silent/context entries.

Refs openclaw#83344

Co-authored-by: Zee Zheng <zheng.zuo0@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: web-ui App: web-ui gateway Gateway runtime merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. size: L status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: WebChat refresh can lose visible conversation history when transcript tail is mostly internal tool traffic

3 participants