@@ -211,15 +211,107 @@ def extract_session_pull_request_id(conversation_key: str) -> str | None:
211211 return None
212212
213213
214- def should_reply_to_message (event : Dict [str , Any ]) -> bool :
214+ def get_bot_user_id (client : WebClient ) -> str | None :
215+ """
216+ Get the bot's user ID using auth.test API.
217+ This is cached to avoid repeated API calls.
218+ """
219+ if not hasattr (get_bot_user_id , "_cache" ):
220+ get_bot_user_id ._cache = {}
221+
222+ cache_key = id (client )
223+
224+ if cache_key in get_bot_user_id ._cache :
225+ return get_bot_user_id ._cache [cache_key ]
226+
227+ try :
228+ auth_response = client .auth_test ()
229+ if auth_response .get ("ok" ):
230+ bot_user_id = auth_response .get ("user_id" )
231+ get_bot_user_id ._cache [cache_key ] = bot_user_id
232+ logger .info ("Cached bot user ID" , extra = {"bot_user_id" : bot_user_id })
233+ return bot_user_id
234+ except Exception :
235+ logger .error ("Error fetching bot user ID" , extra = {"error" : traceback .format_exc ()})
236+
237+ return None
238+
239+
240+ def was_bot_mentioned_in_thread_root (channel : str , thread_ts : str , client : WebClient ) -> bool :
241+ """
242+ Check if THIS specific bot was mentioned anywhere in the thread history.
243+ This handles cases where:
244+ - Multiple bots are in the same channel (checks for this bot's specific user ID)
245+ - Bot is mentioned later in a thread (not just the root message)
246+ """
247+ try :
248+ # get this bot's user ID
249+ bot_user_id = get_bot_user_id (client )
250+ if not bot_user_id :
251+ logger .warning ("Could not determine bot user ID, failing open" )
252+ return True
253+
254+ response = client .conversations_replies (channel = channel , ts = thread_ts , inclusive = True )
255+
256+ if not response .get ("ok" ) or not response .get ("messages" ):
257+ logger .warning ("Failed to fetch thread messages" , extra = {"channel" : channel , "thread_ts" : thread_ts })
258+ return True
259+
260+ # check if THIS bot is mentioned in any message in the thread
261+ bot_mention_pattern = rf"<@{ re .escape (bot_user_id )} (?:\|[^>]+)?>"
262+
263+ for message in response ["messages" ]:
264+ message_text = message .get ("text" , "" )
265+ if re .search (bot_mention_pattern , message_text ):
266+ logger .debug (
267+ "Found bot mention in thread" ,
268+ extra = {
269+ "channel" : channel ,
270+ "thread_ts" : thread_ts ,
271+ "bot_user_id" : bot_user_id ,
272+ "message_ts" : message .get ("ts" ),
273+ },
274+ )
275+ return True
276+
277+ logger .debug (
278+ "Bot not mentioned in thread" ,
279+ extra = {"channel" : channel , "thread_ts" : thread_ts , "bot_user_id" : bot_user_id },
280+ )
281+ return False
282+
283+ except Exception :
284+ logger .error ("Error checking bot mention in thread" , extra = {"error" : traceback .format_exc ()})
285+ return True
286+
287+
288+ def should_reply_to_message (event : Dict [str , Any ], client : WebClient = None ) -> bool :
215289 """
216290 Determine if the bot should reply to the message.
217291
218292 Conditions:
219293 should not reply if:
220294 - Message is in a group chat (channel_type == 'group') but not in a thread
295+ - Message is in a channel thread where the bot was not initially mentioned
221296 """
222297
298+ # we don't reply to non-threaded messages in group chats
223299 if event .get ("channel_type" ) == "group" and event .get ("type" ) == "message" and event .get ("thread_ts" ) is None :
224300 return False
301+
302+ # for channel threads, check if bot was mentioned anywhere in the thread history
303+ if event .get ("channel_type" ) == "channel" and event .get ("thread_ts" ):
304+ if not client :
305+ logger .warning ("No Slack client provided to check thread participation" )
306+ return True
307+
308+ channel = event .get ("channel" )
309+ thread_ts = event .get ("thread_ts" )
310+
311+ if not was_bot_mentioned_in_thread_root (channel , thread_ts , client ):
312+ logger .debug (
313+ "Bot not mentioned in thread, ignoring message" , extra = {"channel" : channel , "thread_ts" : thread_ts }
314+ )
315+ return False
316+
225317 return True
0 commit comments