feat(slack): follow threads where bot was previously mentioned#30754
feat(slack): follow threads where bot was previously mentioned#30754chilang wants to merge 2 commits intoopenclaw:mainfrom
Conversation
When `channels.slack.thread.followMentionedThreads` is enabled (default: false), the bot responds to all replies in threads where it has an active session — without requiring @mention in every reply. This checks both the thread-specific and base (channel) session keys, so it works whether the bot was first invoked via @mention in the thread or the parent message. Config: `channels.slack.thread.followMentionedThreads: true`
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 10afbeb78d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| readSessionUpdatedAt({ storePath, sessionKey }) != null || | ||
| readSessionUpdatedAt({ storePath, sessionKey: baseSessionKey }) != null |
There was a problem hiding this comment.
Restrict thread follow-up to the current thread session
Using baseSessionKey as a fallback here makes thread-follow behavior channel-wide instead of thread-scoped: baseSessionKey is derived from route.sessionKey and represents the whole channel, so any prior bot interaction in that channel causes threadFollowImplicit to become true for unrelated threads. With followMentionedThreads enabled (especially where mentions are required), the bot will start replying in threads where it was never invoked, which contradicts the intended “follow only threads where the bot was previously mentioned” behavior.
Useful? React with 👍 / 👎.
Greptile SummaryThis PR adds a new opt-in config option The overall approach — plumbing the flag through config, context, and the Key concern:
Confidence Score: 2/5
Last reviewed commit: 10afbeb |
| (() => { | ||
| const storePath = resolveStorePath(ctx.cfg.session?.store, { | ||
| agentId: route.agentId, | ||
| }); | ||
| return ( | ||
| readSessionUpdatedAt({ storePath, sessionKey }) != null || | ||
| readSessionUpdatedAt({ storePath, sessionKey: baseSessionKey }) != null | ||
| ); | ||
| })(), |
There was a problem hiding this comment.
baseSessionKey fallback is too broad — matches unrelated threads
Checking for an existing session under baseSessionKey is scoped to (agent, channel) and does not encode the specific thread timestamp. This means once the bot is @mentioned in any top-level channel message and a base-key session is created, the threadFollowImplicit flag will be true for every subsequent thread reply in that channel — even threads the bot was never part of.
Concrete scenario:
- Bot is mentioned in a top-level message in channel X → session created under
baseSessionKey - An entirely unrelated thread is started later in channel X
- A user replies to that unrelated thread → the
baseSessionKeysession lookup returns a non-null value →threadFollowImplicit = true→ bot responds unexpectedly
The PR description says the feature should activate "in threads where it has an active session," but the baseSessionKey fallback activates it for any thread in the channel after any top-level mention.
A tighter approach would be to confirm that the current threadTs corresponds to the channel-level message that originally created the baseSessionKey session (e.g., by storing the originating message ts as part of the session metadata and comparing it here).
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/slack/monitor/message-handler/prepare.ts
Line: 218-226
Comment:
**`baseSessionKey` fallback is too broad — matches unrelated threads**
Checking for an existing session under `baseSessionKey` is scoped to `(agent, channel)` and does **not** encode the specific thread timestamp. This means once the bot is `@mentioned` in any top-level channel message and a base-key session is created, the `threadFollowImplicit` flag will be `true` for *every* subsequent thread reply in that channel — even threads the bot was never part of.
Concrete scenario:
1. Bot is mentioned in a top-level message in channel X → session created under `baseSessionKey`
2. An entirely unrelated thread is started later in channel X
3. A user replies to that unrelated thread → the `baseSessionKey` session lookup returns a non-null value → `threadFollowImplicit = true` → bot responds unexpectedly
The PR description says the feature should activate "in threads where it has an active session," but the `baseSessionKey` fallback activates it for *any thread in the channel* after any top-level mention.
A tighter approach would be to confirm that the current `threadTs` corresponds to the channel-level message that originally created the `baseSessionKey` session (e.g., by storing the originating message `ts` as part of the session metadata and comparing it here).
How can I resolve this? If you propose a fix, please make it concise.Address review feedback: remove the baseSessionKey fallback from threadFollowImplicit. The base key is scoped to (agent, channel) and would cause the bot to respond to every thread in a channel where it was ever mentioned — not just the specific thread with an active session. Now only checks the thread-specific sessionKey, which correctly encodes the thread timestamp. Added regression test: verifies bot does NOT follow an unrelated thread when only a base channel session exists.
|
Addressed the review feedback in fae17a9:
Type-checked clean, lint clean. |
|
Closing this PR — upstream merged #29165 ( Our approach used the session store to check for active thread sessions, while upstream uses a lightweight in-memory cache that records participation when the bot replies. The upstream approach is arguably better (no disk I/O, no stale session false positives). The only thing our PR added that upstream doesn't have is the opt-in config toggle ( Thanks to the reviewers for the feedback — the |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fae17a9ba0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const storePath = resolveStorePath(ctx.cfg.session?.store, { | ||
| agentId: route.agentId, | ||
| }); | ||
| return readSessionUpdatedAt({ storePath, sessionKey }) != null; |
There was a problem hiding this comment.
Handle root-mentioned threads when follow mode is enabled
threadFollowImplicit only checks readSessionUpdatedAt for the thread-suffixed sessionKey, but top-level mentions are persisted under the base channel key because resolveThreadSessionKeys appends threadId only for isThreadReply. In a common flow (followMentionedThreads=true, requireMention=true) where a user mentions the bot in a parent channel message and then continues in that thread without another mention, the first thread reply still gets dropped, so the new follow behavior does not work for parent-started thread conversations.
Useful? React with 👍 / 👎.
Summary
When
channels.slack.thread.followMentionedThreadsis enabled, the bot responds to all replies in threads where it has an active session — without requiring@mentionin every reply.Problem
Currently, when a user
@mentionsthe bot in a Slack channel and a threaded conversation starts, the user must@mentionthe bot in every single reply to keep the conversation going. This is unnatural — in a thread that's clearly a conversation with the bot, having to re-mention it each time adds friction.Solution
A new opt-in config option:
When enabled, thread replies are treated as implicit mentions if the bot already has an active session for that thread. This checks both the thread-specific session key and the base (channel) session key, so it works whether the bot was first invoked via
@mentionin the thread or in the parent message.Changes
channels.slack.thread.followMentionedThreads(boolean, defaultfalse)readSessionUpdatedAtScope
9 files changed, +38 / -1. No breaking changes, fully opt-in, off by default.