openclaw - ✅(Solved) Fix [Bug]: Control UI webchat routes user input into :heartbeat-suffixed session when main session is pruned [1 pull requests, 1 comments, 2 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#75203Fetched 2026-05-01 05:36:56
View on GitHub
Comments
1
Participants
2
Timeline
2
Reactions
2
Author
Timeline (top)
commented ×1cross-referenced ×1

When aggressive session pruning removes agent:main:main from sessions, the Control UI session picker no longer shows the primary session. Heartbeat ticks keep agent:main:main:heartbeat alive, so that becomes the only visible session in the picker. The webchat input then routes user messages directly into the heartbeat-suffixed session — resulting in human↔AI conversation accumulating in a background session rather than the intended main session.

When the next heartbeat tick fires, the Control UI swaps to a newer heartbeat sessionId, effectively clobbering the conversation view mid-chat.

Root Cause

When aggressive session pruning removes agent:main:main from sessions, the Control UI session picker no longer shows the primary session. Heartbeat ticks keep agent:main:main:heartbeat alive, so that becomes the only visible session in the picker. The webchat input then routes user messages directly into the heartbeat-suffixed session — resulting in human↔AI conversation accumulating in a background session rather than the intended main session.

When the next heartbeat tick fires, the Control UI swaps to a newer heartbeat sessionId, effectively clobbering the conversation view mid-chat.

Fix Action

Workaround

Relax session pruning so agent:main:main is never pruned (e.g., increase pruneAfter / maxEntries, or exempt the primary session from pruning rules).

PR fix notes

PR #75356: fix(ui): prevent webchat sends into isolated heartbeat sessions

Description (problem / solution / changelog)

Summary

  • Problem: Control UI webchat could keep agent:main:main:heartbeat selected after the base agent:main:main session was pruned.
  • Why it matters: User messages could be sent into the isolated heartbeat session instead of the real main chat session.
  • What changed: Isolated heartbeat rows now expose their base session key, the UI session picker hides heartbeat-only rows, and both UI and gateway chat.send route stale heartbeat selections back to the base session.
  • What did NOT change (scope boundary): Heartbeat creation, heartbeat execution, session pruning policy, and normal non-heartbeat session routing are unchanged.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #75203
  • Related #
  • This PR fixes a bug or regression

Root Cause (if applicable)

  • Root cause: Isolated heartbeat sessions are persisted as normal session rows with keys like <base>:heartbeat, and the Control UI could select that row when the base session was absent from sessions.list.
  • Missing detection / guardrail: Neither the UI picker nor chat.send treated heartbeatIsolatedBaseSessionKey as a non-user-chat target.
  • Contributing context (if known): Session maintenance can prune the base session while leaving the newer heartbeat session row.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file:
    • ui/src/ui/app-render.helpers.node.test.ts
    • ui/src/ui/controllers/chat.test.ts
  • Scenario the test should lock in: A heartbeat-only session row is not offered as the chat target, and sends from a stale heartbeat selection use the base session key.
  • Why this is the smallest reliable guardrail: The regression is in UI session selection and chat-send request construction; these tests cover both without requiring a full gateway/browser E2E.
  • Existing test that already covers this (if any): None.
  • If no new test is added, why not: N/A.

User-visible / Behavior Changes

Control UI no longer shows isolated heartbeat sessions as selectable chat sessions. If a stale UI state points at an isolated heartbeat session, sending a message resumes the base session instead.

Diagram (if applicable)

Before:
[webchat active key = agent:main:main:heartbeat] -> chat.send -> [heartbeat session]

After:
[webchat active key = agent:main:main:heartbeat] -> resolve base key -> chat.send -> [agent:main:main]

Security Impact (required)

  • New permissions/capabilities? (No)
  • Secrets/tokens handling changed? (No)
  • New/changed network calls? (No)
  • Command/tool execution surface changed? (No)
  • Data access scope changed? (No)
  • If any Yes, explain risk + mitigation: N/A.

Repro + Verification

Environment

  • OS: Linux
  • Runtime/container: Node v22.22.0 via nvm
  • Model/provider: N/A
  • Integration/channel (if any): Control UI webchat
  • Relevant config (redacted): agents.defaults.heartbeat.isolatedSession: true, session.maintenance.mode: enforce

Steps

  1. Seed sessions.json with only agent:main:main:heartbeat, including heartbeatIsolatedBaseSessionKey: "agent:main:main".
  2. Load session options for active key agent:main:main:heartbeat.
  3. Send a Control UI chat message from that stale active key.

Expected

  • The picker offers agent:main:main, not agent:main:main:heartbeat.
  • chat.send uses sessionKey: "agent:main:main".

Actual

  • Before this fix, chat.send used sessionKey: "agent:main:main:heartbeat".
  • After this fix, chat.send uses sessionKey: "agent:main:main".

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification

What personally verified (not just CI), and how:

  • Verified scenarios:
    • Focused UI session picker regression test passes.
    • Focused chat send regression test passes.
    • Headless reproduction now routes to agent:main:main.
  • Edge cases checked:
    • Stale active heartbeat key.
    • Heartbeat-only sessions.list state.
    • Server-side chat.send fallback guard.
  • What you did not verify:
    • Full browser E2E with a live gateway.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? (Yes)
  • Config/env changes? (No)
  • Migration needed? (No)
  • If yes, exact upgrade steps: N/A.

Risks and Mitigations

  • Risk: A real user-created session key could intentionally end with :heartbeat.
  • Mitigation: The behavior only applies when the row carries heartbeatIsolatedBaseSessionKey, not by suffix alone.

Changed files

  • src/gateway/server-methods/chat.ts (modified, +10/-2)
  • src/gateway/session-utils.test.ts (modified, +28/-0)
  • src/gateway/session-utils.ts (modified, +1/-0)
  • src/gateway/session-utils.types.ts (modified, +1/-0)
  • ui/src/ui/app-render.helpers.node.test.ts (modified, +32/-1)
  • ui/src/ui/app-render.helpers.ts (modified, +16/-4)
  • ui/src/ui/chat/session-controls.ts (modified, +35/-6)
  • ui/src/ui/controllers/chat.test.ts (modified, +74/-0)
  • ui/src/ui/controllers/chat.ts (modified, +36/-7)
  • ui/src/ui/controllers/sessions.ts (modified, +1/-0)
  • ui/src/ui/types.ts (modified, +1/-0)

Code Example

maintenance: { mode: "enforce", pruneAfter: "3d", maxEntries: 50 }
RAW_BUFFERClick to expand / collapse

Summary

When aggressive session pruning removes agent:main:main from sessions, the Control UI session picker no longer shows the primary session. Heartbeat ticks keep agent:main:main:heartbeat alive, so that becomes the only visible session in the picker. The webchat input then routes user messages directly into the heartbeat-suffixed session — resulting in human↔AI conversation accumulating in a background session rather than the intended main session.

When the next heartbeat tick fires, the Control UI swaps to a newer heartbeat sessionId, effectively clobbering the conversation view mid-chat.

Steps to Reproduce

  1. Configure session maintenance with aggressive pruning:
    maintenance: { mode: "enforce", pruneAfter: "3d", maxEntries: 50 }
  2. Configure heartbeat with isolatedSession: true, model: "anthropic/claude-haiku-4-5", lightContext: true, target unset (defaults to "none").
  3. Wait for daily session reset (or trigger prune) — agent:main:main gets pruned from sessions.json.
  4. Heartbeat ticks continue to run, keeping agent:main:main:heartbeat alive.
  5. Open Control UI webchat. Observe session picker.
  6. Type a user message in the chat input.

Expected Behavior

  • The session picker should always surface agent:main:main (or auto-create it if missing/pruned).
  • Webchat input should be bound to the primary (main:main) session by default.
  • Heartbeat-suffixed sessions (:heartbeat) should be hidden from the picker, or clearly labeled as "background" / read-only, so users cannot accidentally route input into them.

Actual Behavior

  • Session picker only showed main:heartbeat (no main:main).
  • User typed messages; webchat routed input into agent:main:main:heartbeat.
  • Hours of human↔AI conversation accumulated in the heartbeat session.
  • On the next heartbeat tick, Control UI swapped to a newer heartbeat sessionId, appearing to clobber the conversation view.

Environment

  • OpenClaw version: 2026.4.27 (cbc2ba0)
  • Channel: webchat (Control UI)
  • Heartbeat config: every: "1h", model: "anthropic/claude-haiku-4-5", lightContext: true, isolatedSession: true, target not set
  • Session maintenance config (at time of issue): mode: "enforce", pruneAfter: "3d", maxEntries: 50

Workaround

Relax session pruning so agent:main:main is never pruned (e.g., increase pruneAfter / maxEntries, or exempt the primary session from pruning rules).

Related Issues

  • #66813 — heartbeat target: "last" skipping with no-target (related but distinct)

extent analysis

TL;DR

Relaxing session pruning rules to exempt the primary session (agent:main:main) from pruning or adjusting the pruning configuration can potentially resolve the issue.

Guidance

  • Review the session maintenance configuration to ensure it does not aggressively prune the primary session (agent:main:main).
  • Consider increasing pruneAfter or maxEntries to reduce the frequency of session pruning.
  • Evaluate the necessity of isolatedSession: true in the heartbeat configuration and its impact on session management.
  • Verify that the Control UI session picker is correctly configured to prioritize or auto-create the primary session (agent:main:main) if it's missing.

Example

No specific code snippet is provided due to the nature of the issue, which seems to be more related to configuration and session management rather than code-level fixes.

Notes

The provided workaround suggests relaxing session pruning rules, which might have implications on session management and storage. It's essential to weigh the benefits of this workaround against potential drawbacks, such as increased storage usage.

Recommendation

Apply the workaround by relaxing session pruning rules to ensure the primary session (agent:main:main) is not pruned, as this directly addresses the root cause of the issue described.

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

openclaw - ✅(Solved) Fix [Bug]: Control UI webchat routes user input into :heartbeat-suffixed session when main session is pruned [1 pull requests, 1 comments, 2 participants]