openclaw - ✅(Solved) Fix Bug: Subagent completion announcements silently drop on Telegram when parent session is idle between turns [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#75663Fetched 2026-05-02 05:32:07
View on GitHub
Comments
1
Participants
2
Timeline
4
Reactions
2
Timeline (top)
commented ×1cross-referenced ×1referenced ×1subscribed ×1

When a subagent spawned via sessions_spawn completes its work in the background, the completion announcement (result) is silently dropped and never delivered to the Telegram user. The user only sees the result after sending another message that re-triggers the session.

Error Message

// Line ~756-778 in subagent-announce-delivery.ts if (requesterActivity.isActive) { try { const didFallback = await sendCompletionFallback({...}); if (didFallback) { return { delivered: true, path: "..." }; // ✓ correct } } catch (err) { return { delivered: false, ... }; // ✗ DEAD END — should fall through } return { delivered: false, error: "could not be woken" }; // ✗ DEAD END — should fall through }

// Line ~795+ — the working gateway call that never gets reached directAnnounceResponse = await runAnnounceDeliveryWithRetry({ ...callGateway("agent", { message, deliver: true, expectFinal: true })... });

Root Cause

In src/agents/subagent-announce-delivery.ts, function sendSubagentAnnounceDirectly:

When the parent session has an active embedded Pi run that is not actively consuming messages (between turns, waiting for LLM response, or post-response idle), the following sequence occurs:

  1. queueEmbeddedPiMessage returns false (correctly — the run isn't streaming)
  2. The code enters the requesterActivity.isActive block and tries sendCompletionFallback
  3. sendCompletionFallback often fails (empty completionFallbackText, no direct channel target available)
  4. The function returns { delivered: false } as a dead-end — even though a perfectly good callGateway("agent", ...) path exists ~40 lines below that would start a new run and deliver the message

The early return at the end of the if (requesterActivity.isActive) block prevents the code from falling through to the gateway call that would actually deliver the result.

Fix Action

Workaround

Increasing agents.defaults.subagents.announceTimeoutMs from the default 120s to 180s provides marginal improvement by extending the retry window, but does not fix the architectural dead-end.

PR fix notes

PR #75669: fix(subagents): fall through to gateway call when steer+fallback fail

Description (problem / solution / changelog)

Summary

When a subagent completes and the parent session has an active but non-consuming Pi run (e.g., between turns, waiting for LLM response), the completion announcement is silently dropped instead of being delivered.

Fixes #75663

Root Cause

In sendSubagentAnnounceDirectly, when steer returns false (run not consuming) and the completion fallback also fails (often empty completionFallbackText), the function returns { delivered: false } as a dead-end — even though a working callGateway("agent", ...) path exists 30 lines below.

Changes

src/agents/subagent-announce-delivery.ts (~10 lines changed)

  • Removed early return { delivered: false } in the catch block of sendCompletionFallback
  • Removed early return { delivered: false } after the fallback try block
  • Both paths now fall through to the existing callGateway("agent", { expectFinal: true }) call

src/agents/subagent-announce-delivery.test.ts (+2 tests)

  • Test: steer fails + fallback throws → falls through to gateway call ✓
  • Test: steer succeeds → returns steered, gateway not called (regression) ✓

Impact

  • Telegram: Subagent results will now be delivered even when parent session is idle between turns
  • WebChat: Unaffected (already worked via polling)
  • Cron announcements: Will also benefit from this fix

Testing

  • Existing tests pass (no regressions)
  • 2 new tests covering the fixed failure paths
  • Manual reproduction confirmed the bug and the fix resolves it

Risk

Low. The gateway call path already exists and works — we are just removing a dead-end that prevented it from being reached. No new dependencies, no architectural changes.

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • src/agents/subagent-announce-delivery.test.ts (modified, +63/-0)
  • src/agents/subagent-announce-delivery.ts (modified, +1/-10)

Code Example

// Line ~756-778 in subagent-announce-delivery.ts
if (requesterActivity.isActive) {
  try {
    const didFallback = await sendCompletionFallback({...});
    if (didFallback) {
      return { delivered: true, path: "..." };  // ✓ correct
    }
  } catch (err) {
    return { delivered: false, ... };  // ✗ DEAD END — should fall through
  }
  return { delivered: false, error: "could not be woken" };  // ✗ DEAD END — should fall through
}

// Line ~795+ — the working gateway call that never gets reached
directAnnounceResponse = await runAnnounceDeliveryWithRetry({
  ...callGateway("agent", { message, deliver: true, expectFinal: true })...
});
RAW_BUFFERClick to expand / collapse

Summary

When a subagent spawned via sessions_spawn completes its work in the background, the completion announcement (result) is silently dropped and never delivered to the Telegram user. The user only sees the result after sending another message that re-triggers the session.

Environment

  • OpenClaw version: 2026.4.29 (installed via npm)
  • Channel: Telegram (push-based delivery)
  • Node: v22.22.2
  • OS: Linux 6.8.0-107-generic (x64)
  • Less affected: WebChat (polling picks up queued messages eventually)

Steps to Reproduce

  1. Send a message on Telegram that triggers a sessions_spawn call
  2. Wait for the subagent to complete (can verify via subagents list or watching logs)
  3. Observe: no response is delivered to Telegram
  4. Send another arbitrary message → the subagent result appears immediately (it was queued as a steer message)

Root Cause

In src/agents/subagent-announce-delivery.ts, function sendSubagentAnnounceDirectly:

When the parent session has an active embedded Pi run that is not actively consuming messages (between turns, waiting for LLM response, or post-response idle), the following sequence occurs:

  1. queueEmbeddedPiMessage returns false (correctly — the run isn't streaming)
  2. The code enters the requesterActivity.isActive block and tries sendCompletionFallback
  3. sendCompletionFallback often fails (empty completionFallbackText, no direct channel target available)
  4. The function returns { delivered: false } as a dead-end — even though a perfectly good callGateway("agent", ...) path exists ~40 lines below that would start a new run and deliver the message

The early return at the end of the if (requesterActivity.isActive) block prevents the code from falling through to the gateway call that would actually deliver the result.

Key Code Path

// Line ~756-778 in subagent-announce-delivery.ts
if (requesterActivity.isActive) {
  try {
    const didFallback = await sendCompletionFallback({...});
    if (didFallback) {
      return { delivered: true, path: "..." };  // ✓ correct
    }
  } catch (err) {
    return { delivered: false, ... };  // ✗ DEAD END — should fall through
  }
  return { delivered: false, error: "could not be woken" };  // ✗ DEAD END — should fall through
}

// Line ~795+ — the working gateway call that never gets reached
directAnnounceResponse = await runAnnounceDeliveryWithRetry({
  ...callGateway("agent", { message, deliver: true, expectFinal: true })...
});

Proposed Fix

Remove the early return { delivered: false } statements in the steer-fallback failure paths (the catch block and the post-try fallback). Let execution fall through to the existing callGateway("agent", ...) path that already handles creating a new run and delivering the message.

One file, ~10 lines changed. No new dependencies, no architectural changes. The delivery infrastructure already exists — it just isn't reachable from this code path.

Impact

  • User-facing: Subagent results silently disappear on Telegram until next user message
  • Cron announcements: Same pattern — background cron job completions may not reach the user
  • WebChat: Less affected because the UI polls and picks up queued messages
  • Frequency: Intermittent — depends on timing between subagent completion and parent session state

Workaround

Increasing agents.defaults.subagents.announceTimeoutMs from the default 120s to 180s provides marginal improvement by extending the retry window, but does not fix the architectural dead-end.

Labels

bug, channel:telegram, area:subagents, priority:medium

extent analysis

TL;DR

Remove the early return { delivered: false } statements in the steer-fallback failure paths to allow execution to fall through to the existing callGateway("agent", ...) path.

Guidance

  • Identify the subagent-announce-delivery.ts file and locate the sendSubagentAnnounceDirectly function.
  • Remove the early return { delivered: false } statements in the requesterActivity.isActive block, specifically in the catch block and after the try block.
  • Verify that the callGateway("agent", ...) path is reachable and functional after making these changes.
  • Test the fix by reproducing the issue and checking if the subagent results are delivered correctly to the Telegram user.

Example

// Modified code path
if (requesterActivity.isActive) {
  try {
    const didFallback = await sendCompletionFallback({...});
    if (didFallback) {
      return { delivered: true, path: "..." };  
    }
  } catch (err) {
    // Remove the early return statement
    // return { delivered: false, ... };  
  }
  // Allow execution to fall through to the gateway call
}

// Existing gateway call that should now be reachable
directAnnounceResponse = await runAnnounceDeliveryWithRetry({
  ...callGateway("agent", { message, deliver: true, expectFinal: true })...
});

Notes

The proposed fix assumes that the callGateway("agent", ...) path is correctly implemented and functional. If issues persist, further debugging may be required to ensure this path is working as expected.

Recommendation

Apply the proposed fix by removing the early return { delivered: false } statements, as it directly addresses the identified issue and allows the existing delivery infrastructure to handle the subagent results.

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: Subagent completion announcements silently drop on Telegram when parent session is idle between turns [1 pull requests, 1 comments, 2 participants]