@@ -36,6 +36,12 @@ type RouterDeps = {
3636
3737type WorkspaceAuth = ReturnType < RouterDeps [ "resolveWorkspaceAuth" ] > ;
3838
39+ type BotIdentity = {
40+ botUserId : string ;
41+ teamId ?: string ;
42+ enterpriseId ?: string ;
43+ } ;
44+
3945type IncomingMessageData = {
4046 channelId : string ;
4147 userId : string ;
@@ -157,90 +163,144 @@ async function maybeHandleLauncherCommand(params: {
157163 return true ;
158164}
159165
160- export function registerSlackMessageRouter ( deps : RouterDeps ) : void {
161- const slackApp = deps . app ;
162-
163- slackApp . message ( async ( { message, say, client } : any ) => {
164- const incoming = extractIncomingMessageData ( message ) ;
165- if ( ! incoming ) return ;
166-
167- const { channelId, userId, text, threadId, messageId } = incoming ;
168-
169- const authResult = await client . auth . test ( ) ;
170- const currentBotUserId = authResult . user_id as string ;
171- const workspaceAuth = syncWorkspaceAuth (
172- deps ,
173- channelId ,
174- authResult . team_id ,
175- authResult . enterprise_id ?? undefined
176- ) ;
166+ function getCacheKey ( teamId ?: string , enterpriseId ?: string ) : string {
167+ if ( teamId ) return `team:${ teamId } ` ;
168+ if ( enterpriseId ) return `enterprise:${ enterpriseId } ` ;
169+ return "default" ;
170+ }
177171
178- if ( userId === currentBotUserId ) {
179- log . debug ( "[DROP] Message from bot user" , { channelId, userId } ) ;
180- return ;
181- }
172+ async function getBotIdentity ( params : {
173+ client : any ;
174+ cache : Map < string , BotIdentity > ;
175+ teamId ?: string ;
176+ enterpriseId ?: string ;
177+ } ) : Promise < BotIdentity > {
178+ const { client, cache, teamId, enterpriseId } = params ;
179+ const key = getCacheKey ( teamId , enterpriseId ) ;
180+ const cached = cache . get ( key ) ;
181+ if ( cached ) {
182+ return cached ;
183+ }
182184
183- const isMention = currentBotUserId ? text . includes ( `<@${ currentBotUserId } >` ) : false ;
184- await maybeRefreshWorkspaceForMention ( {
185- deps,
186- channelId,
187- isMention,
188- workspaceAuth,
189- } ) ;
185+ const authResult = await client . auth . test ( ) ;
186+ const identity : BotIdentity = {
187+ botUserId : ( authResult . user_id as string ) || "" ,
188+ teamId : ( authResult . team_id as string | undefined ) ?? teamId ,
189+ enterpriseId : ( authResult . enterprise_id as string | undefined ) ?? enterpriseId ,
190+ } ;
190191
191- if ( await maybeHandleStopCommand ( deps , text , channelId , threadId , say ) ) {
192- return ;
193- }
194- const threadActive = deps . isThreadActive ( channelId , threadId ) ;
192+ cache . set ( key , identity ) ;
193+ return identity ;
194+ }
195195
196- if ( shouldDropForThreadContext ( isMention , threadActive ) ) {
197- log . debug ( "[DROP] Not mentioned and thread inactive" , { channelId, threadId } ) ;
198- return ;
199- }
196+ export function registerSlackMessageRouter ( deps : RouterDeps ) : void {
197+ const slackApp = deps . app ;
198+ const botIdentityCache = new Map < string , BotIdentity > ( ) ;
199+
200+ slackApp . message ( async ( { message, say, client, context, body } : any ) => {
201+ let contextData : IncomingMessageData | null = null ;
202+
203+ try {
204+ const incoming = extractIncomingMessageData ( message ) ;
205+ if ( ! incoming ) return ;
206+ contextData = incoming ;
207+
208+ const { channelId, userId, text, threadId, messageId } = incoming ;
209+ const identity = await getBotIdentity ( {
210+ client,
211+ cache : botIdentityCache ,
212+ teamId : ( context ?. teamId as string | undefined ) ?? ( body ?. team_id as string | undefined ) ,
213+ enterpriseId : ( context ?. enterpriseId as string | undefined ) ?? ( body ?. enterprise_id as string | undefined ) ,
214+ } ) ;
200215
201- if ( shouldDropForOtherMentions ( text , isMention ) ) {
202- log . info ( "[DROP] Mentions other user" , { channelId, threadId } ) ;
203- return ;
204- }
216+ const currentBotUserId = identity . botUserId ;
217+ const workspaceAuth = syncWorkspaceAuth (
218+ deps ,
219+ channelId ,
220+ identity . teamId ,
221+ identity . enterpriseId
222+ ) ;
223+
224+ if ( userId === currentBotUserId ) {
225+ log . debug ( "[DROP] Message from bot user" , { channelId, userId } ) ;
226+ return ;
227+ }
228+
229+ const isMention = currentBotUserId ? text . includes ( `<@${ currentBotUserId } >` ) : false ;
230+ await maybeRefreshWorkspaceForMention ( {
231+ deps,
232+ channelId,
233+ isMention,
234+ workspaceAuth,
235+ } ) ;
205236
206- deps . markThreadActive ( channelId , threadId ) ;
237+ if ( await maybeHandleStopCommand ( deps , text , channelId , threadId , say ) ) {
238+ return ;
239+ }
240+ const threadActive = deps . isThreadActive ( channelId , threadId ) ;
207241
208- const cleanText = stripBotMention ( text , currentBotUserId ) ;
242+ if ( shouldDropForThreadContext ( isMention , threadActive ) ) {
243+ log . debug ( "[DROP] Not mentioned and thread inactive" , { channelId, threadId } ) ;
244+ return ;
245+ }
209246
210- if ( await maybeHandleLauncherCommand ( {
211- deps,
212- cleanText,
213- isMention,
214- channelId,
215- userId,
216- client,
217- } ) ) {
218- return ;
219- }
247+ if ( shouldDropForOtherMentions ( text , isMention ) ) {
248+ log . info ( "[DROP] Mentions other user" , { channelId, threadId } ) ;
249+ return ;
250+ }
220251
221- if ( await maybeNotifySettingsIssues ( deps , channelId , threadId , userId , client , say ) ) {
222- return ;
223- }
252+ deps . markThreadActive ( channelId , threadId ) ;
224253
225- const workspaceName = deps . getChannelWorkspaceName ( channelId ) || "unknown" ;
226- if ( ! cleanText ) {
227- await say ( {
228- text : "Hi! How can I help you? Just ask me anything." ,
229- thread_ts : threadId ,
230- } ) ;
231- return ;
232- }
254+ const cleanText = stripBotMention ( text , currentBotUserId ) ;
233255
234- await deps . handleIncomingMessage (
235- {
256+ if ( await maybeHandleLauncherCommand ( {
257+ deps,
258+ cleanText,
259+ isMention,
236260 channelId,
237- replyThreadId : threadId ,
238- threadId,
239261 userId,
240- messageId,
241- workspaceName,
242- } ,
243- cleanText
244- ) ;
262+ client,
263+ } ) ) {
264+ return ;
265+ }
266+
267+ if ( await maybeNotifySettingsIssues ( deps , channelId , threadId , userId , client , say ) ) {
268+ return ;
269+ }
270+
271+ const workspaceName = deps . getChannelWorkspaceName ( channelId ) || "unknown" ;
272+ if ( ! cleanText ) {
273+ await say ( {
274+ text : "Hi! How can I help you? Just ask me anything." ,
275+ thread_ts : threadId ,
276+ } ) ;
277+ return ;
278+ }
279+
280+ await deps . handleIncomingMessage (
281+ {
282+ channelId,
283+ replyThreadId : threadId ,
284+ threadId,
285+ userId,
286+ messageId,
287+ workspaceName,
288+ } ,
289+ cleanText
290+ ) ;
291+ } catch ( error ) {
292+ log . error ( "Slack message router failed" , {
293+ channelId : contextData ?. channelId ,
294+ threadId : contextData ?. threadId ,
295+ messageId : contextData ?. messageId ,
296+ error : String ( error ) ,
297+ } ) ;
298+ if ( contextData ) {
299+ await say ( {
300+ text : "I hit an internal error while handling that message. Please try again." ,
301+ thread_ts : contextData . threadId ,
302+ } ) ;
303+ }
304+ }
245305 } ) ;
246306}
0 commit comments