-
-
Notifications
You must be signed in to change notification settings - Fork 54.6k
Description
Bug Description
When replyToMode is set to "off" for Slack direct messages (via replyToModeByChatType.direct: "off"), the bot still replies in threads. This is a regression introduced in 2026.2.14.
Configuration
{
"channels": {
"slack": {
"replyToMode": "off",
"replyToModeByChatType": {
"direct": "off",
"group": "all",
"channel": "all"
}
}
}
}Expected Behavior
Bot replies appear in the main DM flow, not in threads.
Actual Behavior
Every bot reply appears as a thread reply to the user's message.
Root Cause Analysis
Traced through the source and identified two issues working together:
1. statusThreadTs always falls back to messageTs (reply-CYMZTXlH.js)
In resolveSlackThreadTargets:
const replyThreadTs = incomingThreadTs ?? (params.replyToMode === "all" ? messageTs : void 0);
return {
replyThreadTs,
statusThreadTs: replyThreadTs ?? messageTs // <-- always has a value
};When replyToMode is "off" and there's no incoming thread:
replyThreadTs=undefinedstatusThreadTs=undefined ?? messageTs=messageTs
This means the "is typing..." status indicator is posted as a thread reply to the user's message, creating a Slack thread even when threading is disabled:
await ctx.setSlackThreadStatus({
channelId: message.channel,
threadTs: statusThreadTs, // <-- messageTs, creates thread
status: "is typing..."
});2. createSlackReplyReferencePlanner overrides replyToMode to "all" (reply-CYMZTXlH.js)
function createSlackReplyReferencePlanner(params) {
return createReplyReferencePlanner({
replyToMode: params.incomingThreadTs ? "all" : params.replyToMode,
// ...
});
}Once the typing indicator creates a thread (from issue 1), subsequent messages from the user may arrive with incomingThreadTs set. This function then hardcodes replyToMode: "all", completely ignoring the user's config.
The cycle:
- User sends message in main DM
statusThreadTs=messageTs→ typing indicator creates a thread- Reply delivery respects
replyToMode: "off"for the reply text, BUT the thread already exists from the typing indicator - On subsequent messages,
incomingThreadTsis set →replyToModeforced to"all"→ all replies thread
Suggested Fix
Fix 1: Don't fall back to messageTs for statusThreadTs when not threading:
statusThreadTs: replyThreadTs // remove ?? messageTs fallbackFix 2: Respect configured replyToMode even when an incoming thread exists:
replyToMode: params.replyToMode // don't override to "all"Additional note
allowExplicitReplyTagsWhenOff (renamed from allowTagsWhenOff in #16189) is hardcoded to true in the Slack plugin dock (plugin-sdk/index.js). This means explicit [[reply_to_*]] tags from the model also create threads when replyToMode is "off". This should ideally be user-configurable via openclaw.json, but the config validator rejects threading as an unrecognized key on both channels.slack and plugins.entries.slack.
Environment
- OpenClaw version: 2026.2.14 (c1feda1)
- Channel: Slack (socket mode, plugin)
- OS: Ubuntu on EC2 (t3a.medium)
- Node: 22.22.0
Workaround
None found that persists. The threading behavior is in the gateway code, not user-configurable. Patching the dist files directly doesn't reliably take effect (multiple module copies).