openclaw - ✅(Solved) Fix Silent-reply fires before plugin async response when inbound_claim returns {handled: true} [1 pull requests, 1 comments, 1 participants]

Official PRs (…)
ON THIS PAGE

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#70286Fetched 2026-04-23 07:26:41
View on GitHub
Comments
1
Participants
1
Timeline
3
Reactions
0
Author
Participants
Timeline (top)
commented ×1cross-referenced ×1referenced ×1

Root Cause

In src/auto-reply/reply/dispatch-from-config.ts, the plugin-bound-handled case hardcodes queuedFinal: false:

case "handled": {
  markIdle("plugin_binding_dispatch");
  recordProcessed("completed", { reason: "plugin-bound-handled" });
  return { queuedFinal: false, counts: dispatcher.getQueuedCounts() };
}

The Telegram bot handler uses queuedFinal to decide whether to fire the silent-reply fallback:

if (!queuedFinal && !sentFallback && !dispatchError && !deliverySummary.delivered) {
  // fires "No further word from me." ← spurious
}

Because the plugin responds asynchronously (after the dispatch cycle), deliverySummary.delivered is also false at this point. Both conditions are met, so the silent-reply fires even though the plugin has already claimed the message and will send a response shortly.

Fix Action

Fix / Workaround

In src/auto-reply/reply/dispatch-from-config.ts, the plugin-bound-handled case hardcodes queuedFinal: false:

case "handled": {
  markIdle("plugin_binding_dispatch");
  recordProcessed("completed", { reason: "plugin-bound-handled" });
  return { queuedFinal: false, counts: dispatcher.getQueuedCounts() };
}
if (!queuedFinal && !sentFallback && !dispatchError && !deliverySummary.delivered) {
  // fires "No further word from me." ← spurious
}

PR fix notes

PR #70288: fix(dispatch): return queuedFinal: true when plugin-bound handler claims message

Description (problem / solution / changelog)

Fixes #70286

What

When a plugin's inbound_claim handler returns { handled: true }, the dispatch was returning queuedFinal: false. This caused channel handlers (Telegram specifically) to fire a silent-reply fallback phrase before the plugin's async response arrived.

Why

The plugin-bound-handled path hardcoded queuedFinal: false. After the silent-reply fallback feature was added in 2026.4.15, queuedFinal: false gained the side effect of triggering that fallback — but the logic predates the feature and was never updated to account for it.

Fix

Return queuedFinal: true for the plugin-bound-handled case. The plugin has committed to responding; the channel handler should not send a fallback.

Tested

Verified against openclaw-codex-app-server: spurious silent-reply phrase no longer fires before the async Codex response. Confirmed regression existed in 2026.4.20 and is absent in 2026.4.14 (pre-silent-reply feature).

Changed files

  • src/auto-reply/reply/dispatch-from-config.test.ts (modified, +2/-2)
  • src/auto-reply/reply/dispatch-from-config.ts (modified, +4/-1)

Code Example

case "handled": {
  markIdle("plugin_binding_dispatch");
  recordProcessed("completed", { reason: "plugin-bound-handled" });
  return { queuedFinal: false, counts: dispatcher.getQueuedCounts() };
}

---

if (!queuedFinal && !sentFallback && !dispatchError && !deliverySummary.delivered) {
  // fires "No further word from me." ← spurious
}

---

case "handled": {
  markIdle("plugin_binding_dispatch");
  recordProcessed("completed", { reason: "plugin-bound-handled" });
  // Plugin claimed this message and will respond asynchronously.
  // Return queuedFinal: true so channel handlers do not fire a silent-reply
  // fallback before the plugin's async response arrives.
  return { queuedFinal: true, counts: dispatcher.getQueuedCounts() };
}
RAW_BUFFERClick to expand / collapse

Bug

When a plugin claims an inbound message via inbound_claim (returning { handled: true }), channel handlers — specifically the Telegram handler — fire a silent-reply fallback (e.g. "No further word from me.") before the plugin's actual async response arrives.

Root cause

In src/auto-reply/reply/dispatch-from-config.ts, the plugin-bound-handled case hardcodes queuedFinal: false:

case "handled": {
  markIdle("plugin_binding_dispatch");
  recordProcessed("completed", { reason: "plugin-bound-handled" });
  return { queuedFinal: false, counts: dispatcher.getQueuedCounts() };
}

The Telegram bot handler uses queuedFinal to decide whether to fire the silent-reply fallback:

if (!queuedFinal && !sentFallback && !dispatchError && !deliverySummary.delivered) {
  // fires "No further word from me." ← spurious
}

Because the plugin responds asynchronously (after the dispatch cycle), deliverySummary.delivered is also false at this point. Both conditions are met, so the silent-reply fires even though the plugin has already claimed the message and will send a response shortly.

Regression

This was introduced in 2026.4.15 when the silent-reply fallback feature was added. In 2026.4.14, the equivalent code path just returned without sending any fallback message, so async plugin handlers worked correctly.

Affected versions

2026.4.15 through 2026.4.21 (latest).

Steps to reproduce

  1. Install a plugin that claims inbound messages via inbound_claim and responds asynchronously (e.g. openclaw-codex-app-server)
  2. Bind a Telegram conversation to the plugin
  3. Send a message — a silent-reply phrase fires immediately, then the plugin's real response arrives seconds later

Expected behaviour

No silent-reply phrase. The plugin claimed the message and will respond; the channel handler should not send a fallback.

Proposed fix

Return queuedFinal: true in the plugin-bound-handled case to signal that a response is committed:

case "handled": {
  markIdle("plugin_binding_dispatch");
  recordProcessed("completed", { reason: "plugin-bound-handled" });
  // Plugin claimed this message and will respond asynchronously.
  // Return queuedFinal: true so channel handlers do not fire a silent-reply
  // fallback before the plugin's async response arrives.
  return { queuedFinal: true, counts: dispatcher.getQueuedCounts() };
}

A PR with this fix is linked below.

extent analysis

TL;DR

Return queuedFinal: true in the plugin-bound-handled case to prevent the silent-reply fallback from firing before the plugin's async response arrives.

Guidance

  • Review the dispatch-from-config.ts file and update the plugin-bound-handled case to return queuedFinal: true as proposed in the fix.
  • Verify that the silent-reply fallback is no longer sent prematurely by testing the updated code with a plugin that claims inbound messages via inbound_claim and responds asynchronously.
  • Check the Telegram bot handler's logic to ensure it correctly handles the updated queuedFinal value and only sends the silent-reply fallback when necessary.
  • Test the fix with different plugins and scenarios to ensure it resolves the issue without introducing new problems.

Example

case "handled": {
  markIdle("plugin_binding_dispatch");
  recordProcessed("completed", { reason: "plugin-bound-handled" });
  return { queuedFinal: true, counts: dispatcher.getQueuedCounts() };
}

Notes

The proposed fix assumes that returning queuedFinal: true will correctly signal to the channel handlers that a response is committed and prevent the silent-reply fallback from firing prematurely. However, additional testing and verification may be necessary to ensure this fix resolves the issue for all affected versions and plugins.

Recommendation

Apply the proposed workaround by returning queuedFinal: true in the plugin-bound-handled case, as this fix directly addresses the root cause of the issue and prevents the silent-reply fallback from firing prematurely.

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 Silent-reply fires before plugin async response when inbound_claim returns {handled: true} [1 pull requests, 1 comments, 1 participants]