Skip to content

feat(slack): resolve @displayname mentions to <@USER_ID> in outgoing messages#230

Merged
cramforce merged 4 commits intomainfrom
slack-at-mentions-from-markdown
Mar 13, 2026
Merged

feat(slack): resolve @displayname mentions to <@USER_ID> in outgoing messages#230
cramforce merged 4 commits intomainfrom
slack-at-mentions-from-markdown

Conversation

@cramforce
Copy link
Contributor

Build a reverse index from display name → user IDs during lookupUser(), track thread participants on incoming messages, and resolve @name mentions to Slack's <@USER_ID> format before sending. Disambiguates using thread participants when multiple users share a display name. Also increases user/channel cache TTLs to 8 days.

…messages

Build a reverse index from display name → user IDs during lookupUser(),
track thread participants on incoming messages, and resolve @name mentions
to Slack's <@USER_ID> format before sending. Disambiguates using thread
participants when multiple users share a display name. Also increases
user/channel cache TTLs to 8 days.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@vercel
Copy link
Contributor

vercel bot commented Mar 12, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
chat Ready Ready Preview, Comment, Open in v0 Mar 13, 2026 0:48am
chat-sdk-nextjs-chat Ready Ready Preview, Comment, Open in v0 Mar 13, 2026 0:48am

Copy link
Member

@matchai matchai left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-blocking but might be worth holding off until we address cache busting.

Comment on lines +2024 to +2028
return text.replace(mentionPattern, (match, name: string) => {
const idx = text.indexOf(match);
if (idx > 0 && text[idx - 1] === "<") {
return match;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the event of two mentions in the same message, this indexOf will resolve to the first instance for every match. Patched up by using the offset:

Suggested change
return text.replace(mentionPattern, (match, name: string) => {
const idx = text.indexOf(match);
if (idx > 0 && text[idx - 1] === "<") {
return match;
}
return text.replace(mentionPattern, (match, name: string, offset: number) => {
if (offset > 0 && text[offset - 1] === "<") {
return match;
}

private readonly formatConverter = new SlackFormatConverter();
private static USER_CACHE_TTL_MS = 60 * 60 * 1000; // 1 hour
private static CHANNEL_CACHE_TTL_MS = 60 * 60 * 1000; // 1 hour
private static USER_CACHE_TTL_MS = 8 * 24 * 60 * 60 * 1000; // 8 days
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The userId → displayName mapping will be stale here for 8 days. This'll cause cosmetic issues with the agent using an old user name after a name change for to up to 8 days.

We have users:read in the manifest so we should subscribe to user_change events for cache invalidation.

…date cache on user_change"

This reverts commit 8cb0d90.
@matchai
Copy link
Member

matchai commented Mar 13, 2026

@cramforce I've gone ahead and stacked #236 on your PR to implement cache invalidation 👍

…he on user_change (#236)

* fix(slack): use replace offset for duplicate mentions, invalidate cache on user_change

* style: align handleUserChange to async/await, expand changeset
@cramforce cramforce merged commit f612b44 into main Mar 13, 2026
10 checks passed
@cramforce cramforce deleted the slack-at-mentions-from-markdown branch March 13, 2026 12:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants