MCPcopy Create free account
hub / github.com/adcontextprotocol/adcp / handleUserMessage

Function handleUserMessage

server/src/addie/bolt-app.ts:1355–1936  ·  view source on GitHub ↗

* Handle user message in assistant thread * Uses streaming to show response as it's generated

({
  event,
  client,
  context,
  say,
  setStatus,
  setTitle,
  getThreadContext,
}: AllAssistantMiddlewareArgs<AssistantUserMessageMiddlewareArgs>)

Source from the content-addressed store, hash-verified

1353 * Uses streaming to show response as it's generated
1354 */
1355async 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

Callers

nothing calls this directly

Calls 15

getThreadServiceFunction · 0.85
sanitizeInputFunction · 0.85
setStatusFunction · 0.85
buildChannelContextFunction · 0.85
getMemberContextFunction · 0.85
matchRuleIdFromMessageFunction · 0.85
recordPromptClickedFunction · 0.85
setSiContextFunction · 0.85
buildSlackCostScopeFunction · 0.85

Tested by

no test coverage detected