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

Function handleAssistantMessage

server/src/addie/handler.ts:523–706  ·  view source on GitHub ↗
(
  event: AssistantMessageEvent,
  channelId: string
)

Source from the content-addressed store, hash-verified

521 * Handle message in Assistant thread
522 */
523export async function handleAssistantMessage(
524 event: AssistantMessageEvent,
525 channelId: string
526): Promise<void> {
527 if (!initialized || !claudeClient) {
528 logger.warn('Addie: Not initialized, ignoring message');
529 return;
530 }
531
532 // Skip Slackbot system messages (e.g., "added you to #channel")
533 if (event.user === SLACKBOT_USER_ID) {
534 logger.debug({ messageText: event.text?.substring(0, 50) }, 'Addie: Ignoring Slackbot system message');
535 return;
536 }
537
538 const startTime = Date.now();
539 const interactionId = generateInteractionId();
540
541 // Check if user is an AAO admin (for admin-only tools access)
542 const isAAOAdmin = await isSlackUserAAOAdmin(event.user);
543 logger.debug({ userId: event.user, isAAOAdmin }, 'Addie: Checked admin status');
544
545 // Resolve user mentions to include names (e.g., <@U123> -> <@U123|John>)
546 const textWithResolvedMentions = await resolveSlackMentions(event.text, lookupSlackUserName);
547
548 // Sanitize input
549 const inputValidation = sanitizeInput(textWithResolvedMentions);
550
551 // Set status to thinking
552 try {
553 await setAssistantStatus(channelId, STATUS_MESSAGES.thinking);
554 } catch {
555 // Status update failed, continue anyway
556 }
557
558 // Build per-request context for system prompt
559 const { requestContext, memberContext, personId } = await buildRequestContext(event.user);
560
561 // Heuristic click telemetry: if the incoming message text matches a
562 // known suggested-prompt verbatim, record a click against that rule.
563 const matchedRuleId = matchRuleIdFromMessage(event.text);
564 const messageWorkosUserId = memberContext?.workos_user?.workos_user_id;
565 if (matchedRuleId && messageWorkosUserId) {
566 void recordPromptClicked(messageWorkosUserId, matchedRuleId);
567 }
568
569 // Record the user's message in the relationship and event log
570 if (personId) {
571 relationshipDb.recordPersonMessage(personId, 'slack')
572 .then(() => relationshipDb.deriveSentiment(personId))
573 .catch(error => {
574 logger.warn({ error, personId }, 'Addie: Failed to record person message');
575 });
576 personEvents.recordEvent(personId, 'message_received', {
577 channel: 'slack',
578 data: { source: 'dm', text_length: textWithResolvedMentions.length },
579 }).catch(err => logger.warn({ err, personId }, 'Addie: Failed to record message_received event'));
580 }

Callers 1

handleMessageFunction · 0.85

Calls 15

generateInteractionIdFunction · 0.85
isSlackUserAAOAdminFunction · 0.85
resolveSlackMentionsFunction · 0.85
sanitizeInputFunction · 0.85
setAssistantStatusFunction · 0.85
matchRuleIdFromMessageFunction · 0.85
recordPromptClickedFunction · 0.85
checkForSensitiveTopicsFunction · 0.85
buildSlackCostScopeFunction · 0.85
validateOutputFunction · 0.85
sendChannelMessageFunction · 0.85
logInteractionFunction · 0.85

Tested by

no test coverage detected