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

Function handleActiveThreadReply

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

* Handle replies in threads where Addie has already participated. * * When a user replies to a thread where Addie has already responded, * we treat it as an implicit @mention and respond directly. This creates * natural conversational flow - users don't need to explicitly @mention * Addie to co

({
  event,
  context,
  channelId,
  userId,
  messageText,
  threadTs,
  startTime,
  threadService,
  slackThreadMessages,
}: {
  event: SlackEventMiddlewareArgs<'message'>['event'];
  context: { botUserId?: string };
  channelId: string;
  userId: string;
  messageText: string;
  threadTs: string;
  startTime: number;
  threadService: ReturnType<typeof getThreadService>;
  slackThreadMessages: Awaited<ReturnType<typeof getThreadReplies>>;
})

Source from the content-addressed store, hash-verified

3336 * This is similar to DM handling but with thread context included.
3337 */
3338async function handleActiveThreadReply({
3339 event,
3340 context,
3341 channelId,
3342 userId,
3343 messageText,
3344 threadTs,
3345 startTime,
3346 threadService,
3347 slackThreadMessages,
3348}: {
3349 event: SlackEventMiddlewareArgs<'message'>['event'];
3350 context: { botUserId?: string };
3351 channelId: string;
3352 userId: string;
3353 messageText: string;
3354 threadTs: string;
3355 startTime: number;
3356 threadService: ReturnType<typeof getThreadService>;
3357 slackThreadMessages: Awaited<ReturnType<typeof getThreadReplies>>;
3358}): Promise<void> {
3359 if (!claudeClient || !boltApp) {
3360 logger.warn('Addie Bolt: Not initialized for active thread reply');
3361 return;
3362 }
3363
3364 // Build external ID for thread: channel_id:thread_ts
3365 const externalId = `${channelId}:${threadTs}`;
3366
3367 // Sanitize input
3368 const inputValidation = sanitizeInput(messageText);
3369
3370 // Fetch channel context (includes working group if channel is linked to one)
3371 let channelContext: ThreadContext | undefined;
3372 try {
3373 channelContext = await buildChannelContext(channelId);
3374 } catch (error) {
3375 logger.debug({ error, channelId }, 'Addie Bolt: Could not get channel context for active thread reply');
3376 }
3377
3378 // Build thread context from the messages already fetched (avoid duplicate API call)
3379 const MAX_THREAD_CONTEXT_MESSAGES = 25;
3380 let threadContext = '';
3381
3382 if (slackThreadMessages.length > 0) {
3383 // Include all messages (including Addie's) for full context
3384 // but exclude the current message
3385 const filteredMessages = slackThreadMessages
3386 .filter(msg => msg.ts !== event.ts) // Exclude current message
3387 .filter(msg => (msg.text || '').trim().length > 0)
3388 .slice(-MAX_THREAD_CONTEXT_MESSAGES);
3389
3390 // Collect user IDs for display name lookup
3391 const mentionedUserIds = new Set<string>();
3392 for (const msg of filteredMessages) {
3393 if (msg.user && msg.user !== context.botUserId) {
3394 mentionedUserIds.add(msg.user);
3395 }

Callers 1

handleChannelMessageFunction · 0.85

Calls 15

sanitizeInputFunction · 0.85
buildChannelContextFunction · 0.85
getSlackUserFunction · 0.85
buildThreadStyleHintFunction · 0.85
getMemberContextFunction · 0.85
isDepthChannelFunction · 0.85
buildSlackCostScopeFunction · 0.85
guardBareJsonEnvelopeFunction · 0.85
validateOutputFunction · 0.85

Tested by

no test coverage detected