(event: SlackMessageEvent)
| 457 | * Indexes public channel messages for Addie's local search |
| 458 | */ |
| 459 | export async function handleMessage(event: SlackMessageEvent): Promise<void> { |
| 460 | // Skip bot messages (including Addie's own messages), message edits/deletes, etc. |
| 461 | // The bot_id field is present when a bot sends a message |
| 462 | if (event.subtype || !event.user || event.bot_id) { |
| 463 | if (event.bot_id) { |
| 464 | logger.debug({ bot_id: event.bot_id, channel: event.channel }, 'Ignoring bot message'); |
| 465 | } |
| 466 | return; |
| 467 | } |
| 468 | |
| 469 | // Route DM messages to Addie if ready (Assistant thread messages) |
| 470 | if (event.channel_type === 'im' && isAddieReady() && event.text) { |
| 471 | logger.debug( |
| 472 | { userId: event.user, channel: event.channel }, |
| 473 | 'Routing DM to Addie' |
| 474 | ); |
| 475 | await handleAssistantMessage( |
| 476 | { |
| 477 | type: 'message', |
| 478 | user: event.user, |
| 479 | text: event.text, |
| 480 | ts: event.ts, |
| 481 | thread_ts: event.thread_ts || event.ts, |
| 482 | channel_type: 'im', |
| 483 | } as AssistantMessageEvent, |
| 484 | event.channel |
| 485 | ); |
| 486 | // Don't return - still record the activity below |
| 487 | } |
| 488 | |
| 489 | logger.debug( |
| 490 | { userId: event.user, channel: event.channel, hasThread: !!event.thread_ts }, |
| 491 | 'User sent message' |
| 492 | ); |
| 493 | |
| 494 | try { |
| 495 | // Get user's org mapping if they're linked |
| 496 | const mapping = await slackDb.getBySlackUserId(event.user); |
| 497 | let organizationId: string | undefined; |
| 498 | |
| 499 | if (mapping?.workos_user_id) { |
| 500 | // Note: Would need to lookup org from WorkOS - for now just record without org |
| 501 | } |
| 502 | |
| 503 | // Determine if this is a thread reply or a new message |
| 504 | const isThreadReply = event.thread_ts && event.thread_ts !== event.ts; |
| 505 | const activityType = isThreadReply ? 'thread_reply' : 'message'; |
| 506 | |
| 507 | await slackDb.recordActivity({ |
| 508 | slack_user_id: event.user, |
| 509 | activity_type: activityType, |
| 510 | channel_id: event.channel, |
| 511 | activity_timestamp: new Date(parseFloat(event.ts) * 1000), |
| 512 | organization_id: organizationId, |
| 513 | metadata: { |
| 514 | channel_type: event.channel_type, |
| 515 | is_thread_reply: isThreadReply, |
| 516 | message_length: event.text?.length || 0, |
no test coverage detected