openclaw - ✅(Solved) Fix ACP parent session stuck until refresh when yielded waiting for child completion [1 pull requests, 5 comments, 5 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#52249Fetched 2026-04-08 01:13:44
View on GitHub
Comments
5
Participants
5
Timeline
9
Reactions
0
Timeline (top)
commented ×5cross-referenced ×2mentioned ×1subscribed ×1

Root Cause

In src/acp/parent-stream-relay.ts (compiled to dist/auth-profiles-CCgh0vEZ.js):

The emitOrResume(...) helper was doing:

if (isYieldedParentAwaitingResume(transcript)) {
  resumeYieldedParent(...)  // ← direct gateway re-entry
} else {
  enqueueSystemEvent() + requestHeartbeatNow()
}

This transcript-sniffing + direct-re-entry approach bypasses the normal session wake scheduler, causing state inconsistency.

Fix Action

Fix / Workaround

We deployed a Phase A stabilization patch that changed the relay to:

always: enqueueSystemEvent() + requestHeartbeatNow()
never: direct resumeYieldedParent() call
  • src/acp/parent-stream-relay.ts (source)
  • dist/auth-profiles-CCgh0vEZ.js (compiled, where patch was applied)

Workaround Status

PR fix notes

PR #60402: fix: wake targeted ACP parent sessions when heartbeat is disabled

Description (problem / solution / changelog)

Summary

  • allow targeted session wake requests (including acp:spawn:*) to execute even when periodic heartbeat scheduling is disabled
  • move targeted wake handling ahead of global heartbeat-disabled / empty-schedule guards in startHeartbeatRunner
  • add a scheduler regression test for ACP targeted wake behavior when heartbeat is disabled

Why

Issue #52249 reports that ACP child completion can enqueue system events but never wake the parent when heartbeat is disabled. This change keeps periodic heartbeat disabled while still letting session-scoped event wakes run.

Testing

  • pnpm exec vitest run --config vitest.unit.config.ts src/infra/heartbeat-runner.scheduler.test.ts
  • pnpm exec vitest run --config vitest.unit.config.ts src/infra/heartbeat-wake.test.ts

Changed files

  • src/infra/heartbeat-runner.returns-default-unset.test.ts (modified, +22/-0)
  • src/infra/heartbeat-runner.scheduler.test.ts (modified, +44/-1)
  • src/infra/heartbeat-runner.ts (modified, +44/-27)

Code Example

if (isYieldedParentAwaitingResume(transcript)) {
  resumeYieldedParent(...)  // ← direct gateway re-entry
} else {
  enqueueSystemEvent() + requestHeartbeatNow()
}

---

always: enqueueSystemEvent() + requestHeartbeatNow()
never: direct resumeYieldedParent() call
RAW_BUFFERClick to expand / collapse

When an ACP child session completes while a parent session is yielded waiting for the result, the parent session remains stuck/non-responsive until the user manually refreshes the UI.

Root cause: The ACP parent-stream relay was using transcript inspection (isYieldedParentAwaitingResume()) and direct gateway re-entry (resumeYieldedParent()) instead of the normal system-event + heartbeat wake path. This ad-hoc resumption path can leave parent session state wedged.

Steps to Reproduce

  1. Open control-ui or web chat
  2. Spawn ACP child: sessions_spawn({ runtime: "acp", agentId: "codex", task: "..." })
  3. Yield parent: sessions_yield()
  4. Wait for child to complete
  5. Observe: Parent session appears stuck, not responsive
  6. Verify: Manual refresh required to unblock chat

Expected Behavior

Parent session automatically resumes when child completes, without manual intervention.

Root Cause

In src/acp/parent-stream-relay.ts (compiled to dist/auth-profiles-CCgh0vEZ.js):

The emitOrResume(...) helper was doing:

if (isYieldedParentAwaitingResume(transcript)) {
  resumeYieldedParent(...)  // ← direct gateway re-entry
} else {
  enqueueSystemEvent() + requestHeartbeatNow()
}

This transcript-sniffing + direct-re-entry approach bypasses the normal session wake scheduler, causing state inconsistency.

The Fix Applied

We deployed a Phase A stabilization patch that changed the relay to:

always: enqueueSystemEvent() + requestHeartbeatNow()
never: direct resumeYieldedParent() call

This forces all ACP completion follow-ups back onto the existing system-event + heartbeat wake path.

Files Affected

  • src/acp/parent-stream-relay.ts (source)
  • dist/auth-profiles-CCgh0vEZ.js (compiled, where patch was applied)

Workaround Status

Phase A patch deployed locally. Tests show parent now auto-resumes on child completion (without manual refresh), but relies on heartbeat wake machinery rather than dedicated yield-resume path.

This is a stabilization patch. The proper long-term fix is:

Proper Fix (Phase B)

Implement explicit yieldWait state tracking in the runtime:

  1. Persist parent yield-wait state when sessions_yield is called
  2. Emit formal ParentYieldWaitLifecycleEvent on child completion
  3. Use dedicated resumeAcpYieldWaitingParent() path (code already exists but unused)
  4. Clear wait state on completion
  5. Do not rely on transcript inspection or ad-hoc gateway calls

System Information

  • OpenClaw: 2026.3.13 (61d171a)
  • Node: 25.8.1
  • Affected: All ACP spawn + yield workflows in browser UIs

Impact

Severity: High

  • Makes ACP tasks in threads/web chat appear frozen
  • User must manually refresh to proceed
  • Degrades UX for code review, long-running tasks in browser
  • Affects: control-ui, web chat, any browser-based ACP spawn

Current Status

Phase A patch has been applied and partially tested. Parent auto-resume now works, but the architecture still couples to heartbeat wake machinery rather than having proper yield-resume semantics.

Full proper fix requires implementing the Phase B architecture with explicit yield-wait state and lifecycle events.

extent analysis

Fix Plan

To implement the proper fix (Phase B), follow these steps:

  • Step 1: Persist parent yield-wait state
    • Modify sessions_yield to store the parent's yield-wait state in the runtime.
    • Example code:

// src/acp/runtime.ts export function sessions_yield() { // ... yieldWaitState[parentSessionId] = true; // ... }

* **Step 2: Emit formal `ParentYieldWaitLifecycleEvent`**
  * Create a new event type `ParentYieldWaitLifecycleEvent` to signal child completion.
  * Modify the child completion handler to emit this event.
  * Example code:
    ```typescript
// src/acp/child-completion-handler.ts
import { ParentYieldWaitLifecycleEvent } from './events';

export function handleChildCompletion() {
  // ...
  emitEvent(new ParentYieldWaitLifecycleEvent(parentSessionId));
  // ...
}
  • Step 3: Use dedicated resumeAcpYieldWaitingParent path
    • Modify the ParentYieldWaitLifecycleEvent handler to call resumeAcpYieldWaitingParent.
    • Example code:

// src/acp/event-handlers.ts import { ParentYieldWaitLifecycleEvent } from './events'; import { resumeAcpYieldWaitingParent } from './parent-stream-relay';

export function handleParentYieldWaitLifecycleEvent(event: ParentYieldWaitLifecycleEvent) { resumeAcpYieldWaitingParent(event.parentSessionId); }

* **Step 4: Clear wait state on completion**
  * Modify `resumeAcpYieldWaitingParent` to clear the yield-wait state.
  * Example code:
    ```typescript
// src/acp/parent-stream-relay.ts
export function resumeAcpYieldWaitingParent(parentSessionId: string) {
  // ...
  yieldWaitState[parentSessionId] = false;
  // ...
}

Verification

To verify the fix, follow these steps:

  • Test ACP spawn and yield workflows in the browser UI.
  • Verify that the parent session auto-resumes on child completion without manual refresh.
  • Check the system logs for any errors or warnings related to the yield-wait state or lifecycle events.

Extra Tips

  • Ensure that the yieldWaitState is properly persisted and cleared to avoid inconsistent state.
  • Consider adding additional logging or monitoring to track the yield-wait state and lifecycle events.
  • Review the existing codebase to ensure that the new fix does not introduce any regressions or conflicts with other features.

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 ACP parent session stuck until refresh when yielded waiting for child completion [1 pull requests, 5 comments, 5 participants]