Bug Description
The Slack adapter applies outgoing @name mention resolution when a streamed response uses the post-and-edit fallback, but not when it uses Slack native streaming.
As a result, identical streamed content behaves differently depending on the nativeStreaming option. With native streaming disabled, a uniquely cached @alice is rewritten to Slack's <@U123> form and renders as a real mention. With native streaming enabled (the default), @alice remains plain text and does not mention or notify the user.
Steps to Reproduce
- Configure a Slack
Chat instance and receive a message from a user whose unique display name is alice, allowing the adapter to populate its user-name and thread-participant caches.
- In the message handler, stream a response containing
@alice.
- Run with
nativeStreaming: true and observe that @alice remains plain text.
- Run the same response with
nativeStreaming: false and observe that it renders as a native Slack mention.
Expected Behavior
Outgoing mention resolution should be consistent across Slack streaming modes. A uniquely resolvable cached @alice should become a native Slack mention whether the response uses native streaming or the post-and-edit fallback.
The existing ambiguity behavior should remain unchanged: participant disambiguation should be used when possible, and unresolved or ambiguous names should remain plain text.
Mention resolution should also work when a mention spans source chunks, for example "@ali" followed by "ce".
Actual Behavior
The post-and-edit path rewrites @alice to <@U123>, while the native streaming path appends @alice directly as markdown_text. The native-streamed message therefore displays the name without creating a Slack mention.
Code Sample
import { createSlackAdapter } from "@chat-adapter/slack";
import { createMemoryState } from "@chat-adapter/state-memory";
import { Chat } from "chat";
const bot = new Chat({
userName: "mybot",
adapters: {
slack: createSlackAdapter({
botToken: process.env.SLACK_BOT_TOKEN!,
signingSecret: process.env.SLACK_SIGNING_SECRET!,
nativeStreaming: process.env.NATIVE_STREAMING !== "false",
}),
},
state: createMemoryState(),
});
bot.onNewMention(async (thread, message) => {
await thread.subscribe();
await thread.post(
(async function* () {
yield `Thanks, @${message.author.userName}`;
})()
);
});
Chat SDK Version
4.35.0
Node.js Version
v24.18.0
Platform Adapter
Slack
Operating System
macOS
Additional Context
This appears to come from a path difference in SlackAdapter:
postMessage and editMessage call resolveMessageMentions, which delegates to resolveOutgoingMentions.
stream sends committed renderer deltas directly through streamer.append({ markdown_text: delta }) without applying the outgoing mention resolver.
Because native streaming is enabled by default, the default mode silently loses behavior that is present in the fallback mode. Resolving the renderer's committed text before calculating/appending each delta may provide a chunk-safe place to apply the existing resolution semantics, but the issue does not depend on a particular implementation.
Bug Description
The Slack adapter applies outgoing
@namemention resolution when a streamed response uses the post-and-edit fallback, but not when it uses Slack native streaming.As a result, identical streamed content behaves differently depending on the
nativeStreamingoption. With native streaming disabled, a uniquely cached@aliceis rewritten to Slack's<@U123>form and renders as a real mention. With native streaming enabled (the default),@aliceremains plain text and does not mention or notify the user.Steps to Reproduce
Chatinstance and receive a message from a user whose unique display name isalice, allowing the adapter to populate its user-name and thread-participant caches.@alice.nativeStreaming: trueand observe that@aliceremains plain text.nativeStreaming: falseand observe that it renders as a native Slack mention.Expected Behavior
Outgoing mention resolution should be consistent across Slack streaming modes. A uniquely resolvable cached
@aliceshould become a native Slack mention whether the response uses native streaming or the post-and-edit fallback.The existing ambiguity behavior should remain unchanged: participant disambiguation should be used when possible, and unresolved or ambiguous names should remain plain text.
Mention resolution should also work when a mention spans source chunks, for example
"@ali"followed by"ce".Actual Behavior
The post-and-edit path rewrites
@aliceto<@U123>, while the native streaming path appends@alicedirectly asmarkdown_text. The native-streamed message therefore displays the name without creating a Slack mention.Code Sample
Chat SDK Version
4.35.0
Node.js Version
v24.18.0
Platform Adapter
Slack
Operating System
macOS
Additional Context
This appears to come from a path difference in
SlackAdapter:postMessageandeditMessagecallresolveMessageMentions, which delegates toresolveOutgoingMentions.streamsends committed renderer deltas directly throughstreamer.append({ markdown_text: delta })without applying the outgoing mention resolver.Because native streaming is enabled by default, the default mode silently loses behavior that is present in the fallback mode. Resolving the renderer's committed text before calculating/appending each delta may provide a chunk-safe place to apply the existing resolution semantics, but the issue does not depend on a particular implementation.