openclaw - ✅(Solved) Fix [Bug] Slack: targetsMatchForSuppression() skips Slack targets, nativeStreaming leaks reasoning blocks [2 pull requests, 1 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#59687Fetched 2026-04-08 02:41:43
View on GitHub
Comments
0
Participants
1
Timeline
4
Reactions
0
Participants
Timeline (top)
cross-referenced ×2referenced ×2

Two related bugs in Slack message delivery cause (1) duplicate messages and (2) internal reasoning/thinking text leaking into visible Slack messages.

Root Cause

Two related bugs in Slack message delivery cause (1) duplicate messages and (2) internal reasoning/thinking text leaking into visible Slack messages.

Fix Action

Fix / Workaround

Current Workaround

Set nativeStreaming: false for all Slack accounts. This disables the native streaming pipeline entirely and falls back to draft-preview mode, which does not leak reasoning blocks.

PR fix notes

PR #59714: fix(dedup): extend targetsMatchForSuppression to all channels, fix Slack duplicate delivery

Description (problem / solution / changelog)

Summary

Fixes #59687 — Slack messages were being delivered twice when an agent both called the message tool and produced response text, because the dedup suppression logic (targetsMatchForSuppression) only performed semantic target normalization for Telegram.

Root cause

targetsMatchForSuppression() had a hard-coded if (provider !== "telegram") guard that short-circuited to a plain string equality check for all non-Telegram channels. For Slack, the message tool target (e.g. "C12345678") and the auto-delivery target (e.g. "channel:c12345678") are semantically equivalent but string-different after normalization, so the suppression check always returned false → duplicate delivery.

Fix

  • Replaced the Telegram-only branch with a generic channel-aware approach: parseExplicitTargetForChannel(provider, ...) is tried for all channels via the plugin registry.
  • Added built-in fallback parsers for Telegram and Slack that activate when the channel plugin is not registered, so Telegram topic-thread matching still works in environments without the full plugin registry (this also fixes 3 pre-existing failing tests on main).
  • Thread-aware comparison logic (topic thread IDs) now applies uniformly to all channels.

Tests

  • All 16 pre-existing tests pass (including 3 that were failing on main).
  • Added 3 new Slack-specific suppression tests.

Test plan

  • DM an agent bound to Slack; agent responds via message.send + produces response text → only one message appears in Slack
  • Same test in a Slack channel thread → only one message in the thread
  • Run pnpm vitest run src/auto-reply/reply/reply-payloads.test.ts → 19/19 pass

Changed files

  • src/auto-reply/reply/reply-payloads-dedupe.ts (modified, +35/-10)
  • src/auto-reply/reply/reply-payloads.test.ts (modified, +30/-0)
  • src/cron/isolated-agent/delivery-dispatch.named-agent.test.ts (modified, +2/-0)

PR #60049: fix: provider-agnostic dedup + filter reasoning blocks from Slack streaming

Description (problem / solution / changelog)

Fixes #59687

Summary

Two bugs in the Slack message delivery pipeline:

Bug 1 — targetsMatchForSuppression() skips non-Telegram channels

The function hard-coded 'telegram' as the provider when calling parseExplicitTargetForChannel, so thread-aware reply deduplication only worked for Telegram. When an agent called message.send to reply AND OpenClaw auto-delivered the response text on Slack (or any other channel), users received both messages.

Fix: Pass params.provider instead of 'telegram' so all channels get the same dedup logic.

Bug 2 — deliverWithStreaming() leaks reasoning/thinking blocks to Slack

When nativeStreaming: true was enabled for a Slack session, extended thinking blocks (isReasoning: true) from Claude were streamed to the Slack channel as visible messages.

Fix: Added an early return at the top of deliverWithStreaming() in the Slack dispatch: if (payload.isReasoning) return;

Changes

  • extensions/slack/src/monitor/message-handler/dispatch.ts — reasoning block filter
  • core/src/reply-payloads/dedupe.ts — provider-agnostic target comparison
  • 4 new Slack dedup tests + existing 14 streaming tests still pass
  • 4 files changed, 72 insertions, 6 deletions

Changed files

  • extensions/slack/src/monitor/message-handler/dispatch.streaming.test.ts (modified, +15/-0)
  • extensions/slack/src/monitor/message-handler/dispatch.ts (modified, +7/-0)
  • src/auto-reply/reply/reply-payloads-dedupe.ts (modified, +9/-6)
  • src/auto-reply/reply/reply-payloads.test.ts (modified, +41/-0)
RAW_BUFFERClick to expand / collapse

Summary

Two related bugs in Slack message delivery cause (1) duplicate messages and (2) internal reasoning/thinking text leaking into visible Slack messages.

Bug 1: targetsMatchForSuppression() does not match Slack targets

Problem

When an agent sends a reply via the message tool AND OpenClaw auto-delivers the conversational response text, the reply-dedup logic (targetsMatchForSuppression()) is supposed to suppress the duplicate. This works correctly for Telegram but not for Slack.

The function appears to only perform thread-aware target comparison for Telegram, causing Slack replies to be delivered twice — once from the message tool call and once from the auto-delivered response text.

Expected Behavior

targetsMatchForSuppression() should use generic/provider-agnostic target comparison so that dedup works identically for Slack, Telegram, iMessage, and any other channel.

Reproduction

  1. Configure an agent bound to a Slack channel
  2. Have a user DM the agent
  3. Agent responds by calling message.send to the same user AND producing response text
  4. Both the tool-sent message AND the response text appear in Slack as separate messages

Bug 2: nativeStreaming: true leaks reasoning/thinking blocks to Slack

Problem

When nativeStreaming is set to true for a Slack account, the streaming pipeline delivers raw thinking/reasoning blocks (e.g., extended thinking from Claude) directly to Slack as visible messages. These should never be visible to users.

Expected Behavior

When nativeStreaming is enabled, reasoning/thinking blocks should be filtered out before being streamed to the channel. Only final response content should be delivered.

Current Workaround

Set nativeStreaming: false for all Slack accounts. This disables the native streaming pipeline entirely and falls back to draft-preview mode, which does not leak reasoning blocks.

Environment

  • OpenClaw version: 2026.3.31
  • Channel: Slack (socket mode)
  • Models: Claude Opus 4, Claude Sonnet 4 (extended thinking enabled)
  • OS: macOS arm64

Related Issues

  • #25592 — Text between tool calls leaks to messaging channels (broader issue, same class)
  • #56675 — Slack streaming mutual exclusion (related streaming architecture)
  • #50597 — Slack socket mode reconnect duplicates (different trigger, same symptom)

extent analysis

TL;DR

Modify the targetsMatchForSuppression() function to use a generic target comparison method for all channels, including Slack, to prevent duplicate messages.

Guidance

  • Review the targetsMatchForSuppression() function to identify the channel-specific logic that is causing the issue with Slack and modify it to use a provider-agnostic approach.
  • Verify the fix by reproducing the steps outlined in the bug reproduction section and checking that only one message is delivered to the Slack channel.
  • Consider filtering out reasoning/thinking blocks when nativeStreaming is enabled by modifying the streaming pipeline to exclude these blocks before delivering the content to the channel.
  • Investigate the related issues (#25592, #56675, #50597) to ensure that the fix does not introduce any new problems or regressions.

Example

// Example of a generic target comparison method
function targetsMatchForSuppression(target1, target2) {
  // Compare the target IDs or other unique identifiers
  return target1.id === target2.id;
}

Notes

The fix may require additional modifications to the OpenClaw codebase, and thorough testing is necessary to ensure that the changes do not introduce any new issues.

Recommendation

Apply a workaround by modifying the targetsMatchForSuppression() function to use a generic target comparison method, as this is a more targeted fix than disabling nativeStreaming entirely.

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] Slack: targetsMatchForSuppression() skips Slack targets, nativeStreaming leaks reasoning blocks [2 pull requests, 1 participants]