openclaw - ✅(Solved) Fix Slack reply pipeline should mark runs complete before dispatch idle [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#84049Fetched 2026-05-20 03:44:47
View on GitHub
Comments
1
Participants
2
Timeline
13
Reactions
2
Timeline (top)
labeled ×5mentioned ×3subscribed ×3commented ×1

The Slack inbound reply pipeline appears to mark dispatch idle without marking the run complete. This leaves Slack typing/thread status active until the typing TTL fallback clears it (observed around ~2 minutes), even after the final reply has already been delivered.

This looks like a Slack extension regression / parity gap with the Discord/message handler paths.

Error Message

  • Slack assistant replies are delivered successfully.
  • The Slack status / typing indicator can remain visible long after the reply is sent.
  • Local config has doneHoldMs=5000, so the status should clear shortly after completion.
  • In practice it appears to wait for the fallback TTL instead.

Root Cause

  • Slack users see stale assistant typing/status indicators after replies complete.
  • This makes runs look stuck even when the agent has finished.
  • It also hides real stuck cases because stale status becomes noisy.

Fix Action

Fix / Workaround

The Slack inbound reply pipeline appears to mark dispatch idle without marking the run complete. This leaves Slack typing/thread status active until the typing TTL fallback clears it (observed around ~2 minutes), even after the final reply has already been delivered.

In the current Slack source, extensions/slack/src/monitor/message-handler/dispatch.ts only destructures and calls markDispatchIdle:

const { dispatcher, replyOptions, markDispatchIdle } = createReplyDispatcherWithTyping({
  ...replyPipeline,
  // ...
});

PR fix notes

PR #84061: fix(slack): call markRunComplete before markDispatchIdle in reply pipeline

Description (problem / solution / changelog)

Summary

Fixes #84049.

Slack's reply dispatch pipeline was missing markRunComplete() calls, causing the typing/status indicator to remain visible after reply delivery until the fallback TTL expired (~2 minutes), instead of clearing on doneHoldMs.

Root Cause

Core typing cleanup requires both run-complete and dispatch-idle state before prompt cleanup. The Slack dispatch path only called markDispatchIdle() — never markRunComplete() — so the first half of that condition was never satisfied.

Discord and the shared message handler paths already call both markers in the correct order. This PR brings Slack into parity.

Changes

extensions/slack/src/monitor/message-handler/dispatch.ts

  • Destructure markRunComplete from createReplyDispatcherWithTyping result
  • Call markRunComplete() before markDispatchIdle() in the normal finally path
  • Call markRunComplete() before markDispatchIdle() in the onPreDispatchFailure callback

extensions/slack/src/monitor/message-handler/dispatch.preview-fallback.test.ts

  • Add markRunComplete: () => {} to the createReplyDispatcherWithTyping mock so existing tests continue to work

extensions/slack/src/monitor/message-handler/dispatch.lifecycle.test.ts (new)

  • Tests that markRunComplete is called before markDispatchIdle on normal dispatch completion
  • Tests that markRunComplete is called before markDispatchIdle when onPreDispatchFailure fires
  • Tests that both are called exactly once on successful dispatch

Before / After

Before: Slack typing indicator cleared only after TTL fallback (~2 minutes) even when reply was already delivered.

After: Slack typing indicator clears after doneHoldMs (e.g. 5000ms with doneHoldMs=5000) as intended, matching Discord behavior.

Parity Reference

Discord already calls both:

markRunComplete();
markDispatchIdle();

This PR makes Slack identical.

Changed files

  • extensions/slack/src/monitor/message-handler/dispatch.lifecycle.test.ts (added, +344/-0)
  • extensions/slack/src/monitor/message-handler/dispatch.preview-fallback.test.ts (modified, +1/-0)
  • extensions/slack/src/monitor/message-handler/dispatch.ts (modified, +6/-2)

Code Example

{
  "name": "@openclaw/slack",
  "version": "2026.5.12",
  "repository": {
    "type": "git",
    "url": "https://github.com/openclaw/openclaw"
  }
}

---

const { dispatcher, replyOptions, markDispatchIdle } = createReplyDispatcherWithTyping({
  ...replyPipeline,
  // ...
});

---

onSettled: () => markDispatchIdle(),

---

if (!dispatchSettledBeforeStart) {
  markDispatchIdle();
}

---

const { dispatcher, replyOptions, markDispatchIdle, markRunComplete } =
  createReplyDispatcherWithTyping({ ... });

// ...
markRunComplete();
markDispatchIdle();

---

- const { dispatcher, replyOptions, markDispatchIdle } = createReplyDispatcherWithTyping({
+ const { dispatcher, replyOptions, markDispatchIdle, markRunComplete } = createReplyDispatcherWithTyping({

---

- onSettled: () => markDispatchIdle(),
+ onSettled: () => {
+   markRunComplete();
+   markDispatchIdle();
+ },

---

if (!dispatchSettledBeforeStart) {
+   markRunComplete();
    markDispatchIdle();
  }
RAW_BUFFERClick to expand / collapse

Summary

The Slack inbound reply pipeline appears to mark dispatch idle without marking the run complete. This leaves Slack typing/thread status active until the typing TTL fallback clears it (observed around ~2 minutes), even after the final reply has already been delivered.

This looks like a Slack extension regression / parity gap with the Discord/message handler paths.

Observed behavior

  • Slack assistant replies are delivered successfully.
  • The Slack status / typing indicator can remain visible long after the reply is sent.
  • Local config has doneHoldMs=5000, so the status should clear shortly after completion.
  • In practice it appears to wait for the fallback TTL instead.

Version / local evidence

Installed Slack extension package:

{
  "name": "@openclaw/slack",
  "version": "2026.5.12",
  "repository": {
    "type": "git",
    "url": "https://github.com/openclaw/openclaw"
  }
}

In the current Slack source, extensions/slack/src/monitor/message-handler/dispatch.ts only destructures and calls markDispatchIdle:

const { dispatcher, replyOptions, markDispatchIdle } = createReplyDispatcherWithTyping({
  ...replyPipeline,
  // ...
});

and later:

onSettled: () => markDispatchIdle(),
if (!dispatchSettledBeforeStart) {
  markDispatchIdle();
}

By contrast, Discord already calls both markers, with markRunComplete() before markDispatchIdle():

const { dispatcher, replyOptions, markDispatchIdle, markRunComplete } =
  createReplyDispatcherWithTyping({ ... });

// ...
markRunComplete();
markDispatchIdle();

Core typing cleanup also appears to require both run-complete and dispatch-idle state before prompt cleanup, so Slack never signals the first half of that condition.

Expected behavior

Slack should align with Discord and the shared message handler paths:

  • Mark the reply run complete when the run has finished.
  • Then mark dispatch idle after pending reply dispatch is settled.
  • Typing/status cleanup should run after doneHoldMs instead of waiting for TTL fallback.

Suggested fix

In extensions/slack/src/monitor/message-handler/dispatch.ts:

- const { dispatcher, replyOptions, markDispatchIdle } = createReplyDispatcherWithTyping({
+ const { dispatcher, replyOptions, markDispatchIdle, markRunComplete } = createReplyDispatcherWithTyping({
- onSettled: () => markDispatchIdle(),
+ onSettled: () => {
+   markRunComplete();
+   markDispatchIdle();
+ },
  if (!dispatchSettledBeforeStart) {
+   markRunComplete();
    markDispatchIdle();
  }

I also have a local patch adding a Slack test asserting markRunComplete is called before markDispatchIdle. The local test run was blocked by dependency install/network instability before completion, so I am filing the issue first with the source parity evidence.

Impact

  • Slack users see stale assistant typing/status indicators after replies complete.
  • This makes runs look stuck even when the agent has finished.
  • It also hides real stuck cases because stale status becomes noisy.

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…

FAQ

Expected behavior

Slack should align with Discord and the shared message handler paths:

  • Mark the reply run complete when the run has finished.
  • Then mark dispatch idle after pending reply dispatch is settled.
  • Typing/status cleanup should run after doneHoldMs instead of waiting for TTL fallback.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING