AI-Enabled Features: Loading States, Text Streaming, and Feedback Buttons
🍿 Preview
https://github.com/user-attachments/assets/bc16597b-1632-46bb-b7aa-fe22330daf84
📚 Changelog
⚡ Getting Started
Try the AI Agent Sample app to explore the AI-enabled features and existing Assistant helper:
# Create a new AI Agent app
$ slack create slack-ai-agent-app --template slack-samples/bolt-js-assistant-template
$ cd slack-ai-agent-app/
# Add your OPENAI_API_KEY
$ export OPENAI_API_KEY=sk-proj-ahM...
# Run the local dev server
$ slack run
After the app starts, send a message to the "slack-ai-agent-app" bot for a unique response.
⌛ Loading States
Loading states allows you to not only set the status (e.g. "My app is typing...") but also sprinkle some personality by cycling through a collection of loading messages:
app.event('message', async ({ client, context, event, logger }) => {
// ...
await client.assistant.threads.setStatus({
channel_id: channelId,
thread_ts: threadTs,
status: 'thinking...',
loading_messages: [
'Teaching the hamsters to type faster…',
'Untangling the internet cables…',
'Consulting the office goldfish…',
'Polishing up the response just for you…',
'Convincing the AI to stop overthinking…',
],
});
// Start a new message stream
});
🔮 Text Streaming Helper
The client.chatStream()
helper utility can be used to streamline calling the 3 text streaming methods:
app.event('message', async ({ client, context, event, logger }) => {
// ...
// Start a new message stream
const streamer = client.chatStream({
channel: channelId,
recipient_team_id: teamId,
recipient_user_id: userId,
thread_ts: threadTs,
});
// Loop over OpenAI response stream
// https://platform.openai.com/docs/api-reference/responses/create
for await (const chunk of llmResponse) {
if (chunk.type === 'response.output_text.delta') {
await streamer.append({
markdown_text: chunk.delta,
});
}
}
// Stop the stream and attach feedback buttons
await streamer.stop({ blocks: [feedbackBlock] });
});
🔠 Text Streaming Methods
Alternative to the Text Streaming Helper is to call the individual methods.
1) client.chat.startStream
First, start a chat text stream to stream a response to any message:
app.event('message', async ({ client, context, event, logger }) => {
// ...
const streamResponse = await client.chat.startStream({
channel: channelId,
recipient_team_id: teamId,
recipient_user_id: userId,
thread_ts: threadTs,
});
const streamTs = streamResponse.ts
2) client.chat.appendStream
After starting a chat text stream, you can then append text to it in chunks (often from your favourite LLM SDK) to convey a streaming effect:
for await (const chunk of llmResponse) {
if (chunk.type === 'response.output_text.delta') {
await client.chat.appendSteam({
channel: channelId,
markdown_text: chunk.delta,
ts: streamTs,
});
}
}
3) client.chat.stopStream
Lastly, you can stop the chat text stream to finalize your message:
await client.chat.stopStream({
blocks: [feedbackBlock],
channel: channelId,
ts: streamTs,
});
👍🏻 Feedback Buttons
Add feedback buttons to the bottom of a message, after stopping a text stream, to gather user feedback:
const feedbackBlock = {
type: 'context_actions',
elements: [{
type: 'feedback_buttons',
action_id: 'feedback',
positive_button: {
text: { type: 'plain_text', text: 'Good Response' },
accessibility_label: 'Submit positive feedback on this response',
value: 'good-feedback',
},
negative_button: {
text: { type: 'plain_text', text: 'Bad Response' },
accessibility_label: 'Submit negative feedback on this response',
value: 'bad-feedback',
},
}],
};
// Using the Text Streaming Helper
await streamer.stop({ blocks: [feedbackBlock] });
// Or, using the Text Streaming Method
await client.chat.stopStream({
blocks: [feedbackBlock],
channel: channelId,
ts: streamTs,
});
What's Changed
👾 Enhancements
- feat: add ai-enabled features text streaming methods, feedback blocks, and loading state in #2399 - Thanks @zimeg!
📚 Documentation
- docs: update package homepage to docs.slack.dev tools reference in #2369 - Thanks @zimeg!
- docs: autogenerate package reference to language specific paths in #2337 - Thanks @zimeg!
🤖 Dependencies
- build(web-api): bump to minimum @slack/[email protected] in #2401 - Thanks @zimeg!
- chore(deps-dev): bump typescript from 5.9.2 to 5.9.3 in /packages/web-api in #2398 - Thanks @dependabot!
🧰 Maintenance
- build: use latest biome schema version in #2363 - Thanks @zimeg!
- chore(web-api): release @slack/[email protected] in #2402 - Thanks @zimeg!
Milestone: https://github.com/slackapi/node-slack-sdk/milestone/147?closed=1
Full Changelog: https://github.com/slackapi/node-slack-sdk/compare/@slack/[email protected]...@slack/[email protected]
Package: https://www.npmjs.com/package/@slack/web-api/v/7.11.0