* Handle user message in assistant thread * Uses streaming to show response as it's generated
({
event,
client,
context,
say,
setStatus,
setTitle,
getThreadContext,
}: AllAssistantMiddlewareArgs<AssistantUserMessageMiddlewareArgs>)
| 1353 | * Uses streaming to show response as it's generated |
| 1354 | */ |
| 1355 | async function handleUserMessage({ |
| 1356 | event, |
| 1357 | client, |
| 1358 | context, |
| 1359 | say, |
| 1360 | setStatus, |
| 1361 | setTitle, |
| 1362 | getThreadContext, |
| 1363 | }: AllAssistantMiddlewareArgs<AssistantUserMessageMiddlewareArgs>): Promise<void> { |
| 1364 | // Log entry into Assistant's userMessage handler for debugging |
| 1365 | logger.debug({ |
| 1366 | channelId: 'channel' in event ? event.channel : undefined, |
| 1367 | userId: 'user' in event ? event.user : undefined, |
| 1368 | threadTs: 'thread_ts' in event ? event.thread_ts : undefined, |
| 1369 | ts: 'ts' in event ? event.ts : undefined, |
| 1370 | hasText: 'text' in event && !!event.text, |
| 1371 | channelType: 'channel_type' in event ? event.channel_type : undefined, |
| 1372 | }, 'Addie Bolt: handleUserMessage called (Assistant handler)'); |
| 1373 | |
| 1374 | if (!claudeClient) { |
| 1375 | logger.warn('Addie Bolt: Claude client not initialized'); |
| 1376 | return; |
| 1377 | } |
| 1378 | |
| 1379 | // Skip bot messages to prevent loops (Addie talking to herself) |
| 1380 | if ('bot_id' in event && event.bot_id) { |
| 1381 | logger.debug({ botId: event.bot_id }, 'Addie Bolt: Ignoring assistant message from bot'); |
| 1382 | return; |
| 1383 | } |
| 1384 | |
| 1385 | // Extract fields safely - not all message events have these fields |
| 1386 | const userId = 'user' in event ? event.user : undefined; |
| 1387 | const messageText = 'text' in event ? event.text : undefined; |
| 1388 | const threadTs = 'thread_ts' in event ? event.thread_ts : ('ts' in event ? event.ts : undefined); |
| 1389 | |
| 1390 | // Skip if not a user message |
| 1391 | if (!userId || !messageText) { |
| 1392 | logger.debug({ userId, hasText: !!messageText }, 'Addie Bolt: Ignoring message event without user or text'); |
| 1393 | return; |
| 1394 | } |
| 1395 | |
| 1396 | // Skip Slackbot system messages (e.g., "added you to #channel") |
| 1397 | if (userId === SLACKBOT_USER_ID) { |
| 1398 | logger.debug({ messageText: messageText?.substring(0, 50) }, 'Addie Bolt: Ignoring Slackbot system message'); |
| 1399 | return; |
| 1400 | } |
| 1401 | |
| 1402 | // Skip DMs without thread_ts - these are handled by handleDirectMessage via middleware. |
| 1403 | // The Assistant framework receives message.im events through a separate pipeline from |
| 1404 | // the global middleware chain, so both handlers can fire for the same event. |
| 1405 | // First DMs (without thread_ts) are handled by handleDirectMessage; skip them here. |
| 1406 | const channelType = 'channel_type' in event ? event.channel_type : undefined; |
| 1407 | const hasRealThreadTs = 'thread_ts' in event && event.thread_ts !== undefined; |
| 1408 | if (channelType === 'im' && !hasRealThreadTs) { |
| 1409 | logger.debug({ channelType, hasThreadTs: hasRealThreadTs }, 'Addie Bolt: Skipping DM without thread_ts in Assistant handler (handled by middleware)'); |
| 1410 | return; |
| 1411 | } |
| 1412 |
nothing calls this directly
no test coverage detected