* Handle reaction_added events * When users react to Addie's messages, interpret the reaction as input: * - Thumbs up / check = "yes, proceed" or positive feedback * - Thumbs down / X = "no, don't do that" or negative feedback
({
event,
context,
}: SlackEventMiddlewareArgs<'reaction_added'> & { context: { botUserId?: string } })
| 4760 | * - Thumbs down / X = "no, don't do that" or negative feedback |
| 4761 | */ |
| 4762 | async function handleReactionAdded({ |
| 4763 | event, |
| 4764 | context, |
| 4765 | }: SlackEventMiddlewareArgs<'reaction_added'> & { context: { botUserId?: string } }): Promise<void> { |
| 4766 | if (!claudeClient || !boltApp) { |
| 4767 | return; |
| 4768 | } |
| 4769 | |
| 4770 | // Use boltApp.client for API calls |
| 4771 | const client = boltApp.client; |
| 4772 | |
| 4773 | const reaction = event.reaction; |
| 4774 | const reactingUserId = event.user; |
| 4775 | const itemChannel = event.item.channel; |
| 4776 | const itemTs = event.item.ts; |
| 4777 | const itemUser = event.item_user; // Who authored the message that received the reaction |
| 4778 | |
| 4779 | // Only process reactions on Addie's messages |
| 4780 | if (!context.botUserId || itemUser !== context.botUserId) { |
| 4781 | return; |
| 4782 | } |
| 4783 | |
| 4784 | // Check for weekly digest approval (white_check_mark on digest review message) |
| 4785 | if (reaction === 'white_check_mark') { |
| 4786 | const handled = await handleDigestApproval(reactingUserId, itemChannel, itemTs); |
| 4787 | if (handled) return; |
| 4788 | } |
| 4789 | |
| 4790 | // Check for weekly digest regeneration (🔄 on digest review message) |
| 4791 | if (reaction === 'arrows_counterclockwise') { |
| 4792 | const handled = await handleDigestRegenerate(reactingUserId, itemChannel, itemTs); |
| 4793 | if (handled) return; |
| 4794 | } |
| 4795 | |
| 4796 | // Check if this is a meaningful reaction (positive or negative) |
| 4797 | const isPositive = POSITIVE_REACTIONS.has(reaction); |
| 4798 | const isNegative = NEGATIVE_REACTIONS.has(reaction); |
| 4799 | |
| 4800 | if (!isPositive && !isNegative) { |
| 4801 | // Not a reaction we care about |
| 4802 | return; |
| 4803 | } |
| 4804 | |
| 4805 | logger.info( |
| 4806 | { reaction, isPositive, isNegative, reactingUserId, itemChannel, itemTs }, |
| 4807 | 'Addie Bolt: Received reaction on Addie message' |
| 4808 | ); |
| 4809 | |
| 4810 | const startTime = Date.now(); |
| 4811 | const threadService = getThreadService(); |
| 4812 | |
| 4813 | // Build external ID to find the thread |
| 4814 | // For thread replies, itemTs is the reply ts; we need to find the thread |
| 4815 | // First, try to get the message to find its thread_ts |
| 4816 | let threadTs = itemTs; |
| 4817 | try { |
| 4818 | const result = await client.conversations.replies({ |
| 4819 | channel: itemChannel, |
nothing calls this directly
no test coverage detected