fix(slack): respect replyToMode when incomingThreadTs is auto-created#23320
fix(slack): respect replyToMode when incomingThreadTs is auto-created#23320dorukardahan wants to merge 2 commits intoopenclaw:mainfrom
Conversation
When Slack's 'Agents & AI Apps' feature is enabled (or in certain bot interaction scenarios), Slack auto-creates a thread_ts for channel messages. The existing code in createSlackReplyReferencePlanner() unconditionally forced replyToMode to 'all' whenever incomingThreadTs was present, ignoring the user's configured replyToMode. The fix distinguishes between genuine thread replies (where incomingThreadTs differs from messageTs, indicating the user wrote in an existing thread) and auto-created thread_ts values. Only genuine thread replies force 'all' mode; otherwise the configured replyToMode is respected. Changes: - replies.ts: Accept isThreadReply param, use it instead of bare incomingThreadTs presence check - threading.ts: resolveSlackThreadTargets now checks isThreadReply before using incomingThreadTs for reply threading - dispatch.ts: Compute and pass isThreadReply to delivery plan - threading.test.ts: Add tests for auto-created thread_ts scenarios Fixes openclaw#5470
src/slack/threading.ts
Outdated
| const replyThreadTs = isThreadReply | ||
| ? incomingThreadTs | ||
| : params.replyToMode === "off" | ||
| ? undefined | ||
| : (incomingThreadTs ?? (params.replyToMode === "all" ? messageTs : undefined)); |
There was a problem hiding this comment.
logic bug: replyToMode: "first" not handled correctly for auto-created threads
when isThreadReply=false (auto-created thread) and replyToMode="first", the ternary evaluates to incomingThreadTs ?? undefined, which returns the auto-created thread_ts instead of messageTs for the first reply
| const replyThreadTs = isThreadReply | |
| ? incomingThreadTs | |
| : params.replyToMode === "off" | |
| ? undefined | |
| : (incomingThreadTs ?? (params.replyToMode === "all" ? messageTs : undefined)); | |
| const replyThreadTs = isThreadReply | |
| ? incomingThreadTs | |
| : params.replyToMode === "off" | |
| ? undefined | |
| : params.replyToMode === "all" | |
| ? (incomingThreadTs ?? messageTs) | |
| : (params.replyToMode === "first" ? messageTs : undefined); |
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/slack/threading.ts
Line: 45-49
Comment:
logic bug: `replyToMode: "first"` not handled correctly for auto-created threads
when `isThreadReply=false` (auto-created thread) and `replyToMode="first"`, the ternary evaluates to `incomingThreadTs ?? undefined`, which returns the auto-created thread_ts instead of `messageTs` for the first reply
```suggestion
const replyThreadTs = isThreadReply
? incomingThreadTs
: params.replyToMode === "off"
? undefined
: params.replyToMode === "all"
? (incomingThreadTs ?? messageTs)
: (params.replyToMode === "first" ? messageTs : undefined);
```
How can I resolve this? If you propose a fix, please make it concise.| expect(context.isThreadReply).toBe(false); | ||
| expect(context.messageThreadId).toBeUndefined(); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
add test for replyToMode: "first" with auto-created thread_ts to verify first reply uses messageTs when thread_ts equals ts
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/slack/threading.test.ts
Line: 126
Comment:
add test for `replyToMode: "first"` with auto-created `thread_ts` to verify first reply uses `messageTs` when `thread_ts` equals `ts`
<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>
How can I resolve this? If you propose a fix, please make it concise.…eads - Fix logic bug in resolveSlackThreadTargets where 'first' mode with auto-created thread_ts would use incomingThreadTs instead of messageTs - Add test for replyToMode 'first' with auto-created thread_ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
|
Consolidating this into #23839 so we ship one scoped Slack threading fix:
Closing this as superseded. |
|
Superseded by #23839. |
fix(slack): respect replyToMode when Slack auto-creates thread_ts
What
Fixes a bug where
replyToMode: "off"was ignored whenincomingThreadTsexists, causing all bot replies to become thread replies even when configured to post to the main channel.Why
When Slack's "Agents & AI Apps" feature is enabled (or in certain bot interaction scenarios), Slack auto-creates a
thread_tsfor channel messages. The existing code increateSlackReplyReferencePlanner()unconditionally forcedreplyToModeto"all"wheneverincomingThreadTswas present:This meant users who configured
replyToModeByChatType.channel: "off"expecting channel-level replies would instead get thread replies when this auto-threading occurred.The fix distinguishes between:
isThreadReply=true) → stay in thread regardless ofreplyToModereplyToModeRelated Issues
Reproduction Steps
Before this fix:
replyToModeByChatType.channel: "off"in OpenClaw configExpected behavior:
With
replyToMode: "off", the bot should reply to the main channel unless the user explicitly sent their message within an existing thread.Changes
src/slack/monitor/replies.ts: ModifiedcreateSlackReplyReferencePlanner()to acceptisThreadReplyparameter and use it to determine effective mode instead of just checkingincomingThreadTssrc/slack/monitor/message-handler/dispatch.ts: Updated to passisThreadReplycontext fromresolveSlackThreadContext()src/slack/threading.ts: ExposedisThreadReplyin return valueTest Plan
Manual Testing
Scenario 1: Channel Message with Auto-Created Thread (Bug Fix)
replyToModeByChatType.channel: "off"Scenario 2: Genuine Thread Reply (Preserved Behavior)
replyToModeByChatType.channel: "off"Scenario 3: DM with replyToMode
replyToModeByChatType.im: "off"(or any value)Scenario 4: replyToMode: "all" (Preserved Behavior)
replyToModeByChatType.channel: "all"Scenario 5: Mixed Chat Types
Automated Tests
pnpm test -- src/slack/monitor/replies.test.tspassesshould respect replyToMode="off" when incomingThreadTs exists but isThreadReply=falseshould force thread reply when isThreadReply=true regardless of replyToModeshould handle auto-created thread_ts from Slack Agents featureEdge Cases
Build & Check
pnpm check)pnpm test)pnpm lintif applicable)Comparison with PR #16113
PR #16113 (by @zerone0x) addresses a similar issue but at the
deliverReplies()level, focusing on inline directive tags (e.g.,@openclaw reply-to=channel). This approach:createSlackReplyReferencePlanner()Our approach is more comprehensive:
createSlackReplyReferencePlanner()) where reply mode decisions are madedeliverReplies()correctly handles thereplyToIdparameterChecklist
Greptile Summary
fixes
replyToMode: "off"being ignored when Slack auto-createsthread_tsfor channel messages (Agents & AI Apps feature)Key changes:
isThreadReplyflag to distinguish genuine thread replies from auto-createdthread_tsisThreadReplyis true whenthread_ts !== tsORparent_user_idis presentcreateSlackReplyReferencePlannerto respect configuredreplyToModefor auto-created threadsIssues found:
resolveSlackThreadTargets(src/slack/threading.ts:45-49) - doesn't handlereplyToMode: "first"correctly for auto-created threadsConfidence Score: 3/5
resolveSlackThreadTargetscreateSlackReplyReferencePlanner, but introduces a logic bug inresolveSlackThreadTargetsthat doesn't properly handlereplyToMode: "first"with auto-created threads - this needs to be fixed before mergeLast reviewed commit: f158d38
(5/5) You can turn off certain types of comments like style here!