Skip to content

fix(heartbeat): propagate sessionKey in exec/hooks to fix async context loss#1094

Open
BingqingLyu wants to merge 2 commits into
mainfrom
fork-pr-50818-fix-heartbeat-async-session-routing
Open

fix(heartbeat): propagate sessionKey in exec/hooks to fix async context loss#1094
BingqingLyu wants to merge 2 commits into
mainfrom
fork-pr-50818-fix-heartbeat-async-session-routing

Conversation

@BingqingLyu

@BingqingLyu BingqingLyu commented Apr 27, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes openclaw#52305. Related: openclaw#18237, openclaw#14191 (closed as stale).

Update 2026-04-26: openclaw#39978 (originally also in this PR's scope) was closed 2026-04-24, fixed upstream by openclaw#70258 (merged 2026-04-23). openclaw#70258 takes a narrower approach — adding deliveryContext / lastChannel / lastTo fallback in auto-reply/reply/dispatch-from-config.ts (3 files). openclaw#66648 (related "exec leakage to wrong sessions") was also closed 2026-04-25.

This PR's remaining unique value is the sessionKey-targeting fix for openclaw#52305 — wake events not being session-targeted, causing async task completions to route to whatever session is active rather than the originating one. The 14-file scope below covers that broader sessionKey-propagation path (heartbeat-runner, exec runtimes, cron event session keys, ACP spawn stream). Pending verification on v2026.4.24 to confirm openclaw#70258 doesn't incidentally cover openclaw#52305.

Async exec completion events silently vanish instead of being relayed to the originating channel. The root cause is a session key mismatch: events are enqueued under cron or channel-specific session keys, but the heartbeat runner always checks the agent's main session key.

Changes

  1. Propagate sessionKey in wake requests — exec/hook/ACP paths now pass sessionKey through scopedHeartbeatWakeOptions(), which scopes agent sessions correctly while preserving unscoped behavior for non-agent keys.

  2. Cron session key remapping — new resolveEventSessionKey() centralizes cron→agent-main remapping for event enqueueing. All affected enqueue sites updated: bash exec runtime, node exec events, ACP spawn stream.

  3. Custom mainKey threadingscopedHeartbeatWakeOptions() now accepts optional mainKey so cron wake targets align with enqueue targets in custom session.mainKey configurations.

  4. Exec completion delivery override — when a pending exec completion event is detected, resolveHeartbeatDeliveryTarget overrides target: "none" to fall back to the session's last delivery target, so exec results reach the user. Respects upstream fix(heartbeat): keep exec-event runs on the non-owner tool surface openclaw/openclaw#57652 auth blocking (ForceSenderIsOwnerFalse). Note: this overlaps with fix(auto-reply): restore route replies for exec-event completions openclaw/openclaw#70258's lastChannel/lastTo fallback, but operates at the heartbeat-delivery-target layer rather than the auto-reply route-resolution layer — they may be complementary or one may make the other redundant. Verification pending.

  5. Exec completion detection — start-anchored regex matching for both exec finished (gateway/node approval path) and Exec completed/failed/killed (backgrounded allowlisted commands). Supports word-based session slugs from createSessionSlug().

Test plan

🤖 Generated with Claude Code

Kaspre and others added 2 commits April 26, 2026 18:36
…xt loss

Exec completion events enqueued under cron or channel-specific session
keys were invisible to the heartbeat runner, which always checked the
agent's main session key. This caused exec results to silently vanish
instead of being relayed back to the originating channel.

1. Propagate sessionKey through scopedHeartbeatWakeOptions in bash
   exec, ACP spawn, gateway/node exec, and CLI watchdog paths
2. Add resolveEventSessionKey to remap cron session keys to the
   originating agent's main session key for event enqueueing

Scope was previously broader. Dropped per maintainer review feedback
on openclaw#50818 (issuecomment-4322767117):

- The forceLastTargetWhenNone override for resolveHeartbeatDeliveryTarget,
  which routed exec completions to the session's last target even when
  heartbeat.target was explicitly "none". Current main and its regression
  tests intentionally keep target="none" internal-only, so this routing
  change is left for a separate focused PR if it is ever revisited.
- The openclaw#39978 hook-cancel handling has already shipped via upstream PR
  openclaw#70258, so it is no longer part of this PR's scope.

The PR now closes openclaw#52305 only.

Closes openclaw#52305. Related: openclaw#18237.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: async task completion reports can be lost because system event/wake is not reliably session-targeted

3 participants