Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions integrations/slack/definitions/channels/text-input-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -411,8 +411,7 @@ export const textSchema = sdk.z
.string()
.describe(
'Field text must be defined but it is ignored if blocks are provided. In this situation, the text must be provided in the blocks array'
)
.optional(),
),
blocks: sdk.z
.array(blocks)
.max(50)
Expand Down
21 changes: 10 additions & 11 deletions integrations/slack/definitions/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,21 @@ const SHARED_CONFIGURATION = {
.default(false)
.title('Typing Indicator Emoji')
.describe('Temporarily add an emoji to received messages to indicate when bot is processing message'),
createReplyThread: sdk.z
replyBehaviour: sdk.z
.object({
enabled: sdk.z
.boolean()
.default(false)
.title('Reply Threading Enabled')
.describe('When enabled, the bot will forward incoming messages to threads'),
location: sdk.z
.enum(['channel', 'thread', 'channelAndThread'])
.default('channel')
.title('Reply Location')
.describe('Where the bot sends replies: Channel only, Thread only (creates if needed), or both'),
onlyOnBotMention: sdk.z
.boolean()
.default(false)
.title('Require Bot Mention for Reply Threading')
.describe('When enabled, the bot will only forward messages to threads when mentioned'),
.title('Require Bot Mention for Replies')
.describe('This ensures that the bot only replies to messages when it is explicitly mentioned'),
})
.optional()
.title('Proactive Threads')
.describe('Create reply threads for each incoming message'),
.title('Reply Behaviour')
.describe('How the bot should reply to messages'),
} as const

export const configuration = {
Expand Down
17 changes: 10 additions & 7 deletions integrations/slack/hub.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
The Slack integration enables seamless communication between your AI-powered chatbot and Slack, the popular collaboration platform. Connect your chatbot to Slack and streamline team communication, automate tasks, and enhance productivity. With this integration, your chatbot can send and receive messages, share updates, handle inquiries, and perform actions directly within Slack channels. Leverage Slack's extensive features such as chat, file sharing, notifications, and app integrations to create a powerful conversational AI experience. Enhance team collaboration and streamline workflows with the Slack Integration for Botpress.

## Migrating from version `3.x` to `4.x`

Version 4.0 of the Slack integration refines the bot's reply behaviour by introducing the possibility to reply in either `channel`, `thread` or `channel and thread`. This replaces the previous `createReplyThread` configuration option by adding the ability to **only** reply in threads.

Features that have been added are:

- Improved reply behaviour
- Added rich text! Users are now able to input markdown text and it display in rich text in slack

## Migrating from version `2.x` to `3.x`

Version 3.0 of the Slack integration changes the way the mention system works with Botpress.
Expand Down Expand Up @@ -133,13 +142,7 @@ Regardless of the configuration mode you choose, you can optionally set a custom

## Replying in threads instead of the main channel

To minimize disruption in busy Slack channels, you can activate reply threading in the integration settings. This feature creates a thread for each incoming message, where the bot will respond. For a more targeted approach, enable the "Require Bot Mention for Reply Threading Option" to only create threads when the bot is mentioned by name.

Note that enabling reply threading alone doesn't stop your bot from posting in the main channel. To restrict responses exclusively to threads, modify your workflow in the Botpress Studio to terminate when receiving messages from the main channel:

1. Insert an empty Standard Node at the very beginning of your Main workflow and connect it to your existing flow.
2. Add an Expression card with the condition `event.channel === 'channel'`.
3. Create an End card and connect the Expression card to it.
To minimize disruption in busy Slack channels, you can activate reply threading in the integration settings. This feature creates a thread for each incoming message, where the bot will respond. For a more targeted approach, enable the "Require Bot Mention for Replies" to only create threads when the bot is mentioned by name.

## Limitations

Expand Down
2 changes: 1 addition & 1 deletion integrations/slack/integration.definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export default new IntegrationDefinition({
name: 'slack',
title: 'Slack',
description: 'Automate interactions with your team.',
version: '3.2.0',
version: '4.0.0',
icon: 'icon.svg',
readme: 'hub.md',
configuration,
Expand Down
6 changes: 1 addition & 5 deletions integrations/slack/src/misc/markdown-to-slack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,6 @@ const slackHandlers: MarkdownHandlers = {
paragraph: (node, visit) => `${visit(node)}\n`,
}

export function transformMarkdownForSlack(text: string | undefined): string | undefined {
if (!text) {
return text
}

export function transformMarkdownForSlack(text: string): string {
return transformMarkdown(text, slackHandlers)
}
4 changes: 0 additions & 4 deletions integrations/slack/src/misc/replace-mentions.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import { test, expect, vi } from 'vitest'
import { replaceMentions, Mention } from './replace-mentions'

test('returns undefined if text is undefined', () => {
expect(replaceMentions(undefined, [])).toBeUndefined()
})

test('returns text unchanged if mentions is undefined', () => {
expect(replaceMentions('hey <@John Doe>', undefined)).toBe('hey <@John Doe>')
})
Expand Down
4 changes: 2 additions & 2 deletions integrations/slack/src/misc/replace-mentions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ export type Mention = {
user: { id: string; name: string }
}

export const replaceMentions = (text: string | undefined, mentions: Mention[] | undefined): string | undefined => {
if (!mentions || !text) {
export const replaceMentions = (text: string, mentions: Mention[] | undefined): string => {
if (!mentions) {
return text
}

Expand Down
103 changes: 57 additions & 46 deletions integrations/slack/src/webhook-events/handlers/message-received.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,62 +47,73 @@ export const handleEvent = async (props: HandleEventProps) => {
return
}

const { botpressConversation } = await getBotpressConversationFromSlackThread(
{ slackChannelId: slackEvent.channel, slackThreadId: slackEvent.thread_ts },
client
)
const { botpressUser } = await getBotpressUserFromSlackUser({ slackUserId: slackEvent.user }, client)
await updateBotpressUserFromSlackUser(slackEvent.user, botpressUser, client, ctx, logger)

const mentionsBot = await _isBotMentionedInMessage({ slackEvent, client, ctx })
const isSentInChannel = !slackEvent.thread_ts
const isThreadingEnabled = ctx.configuration.createReplyThread?.enabled ?? false
const threadingRequiresMention = ctx.configuration.createReplyThread?.onlyOnBotMention ?? false
const shouldForkToReplyThread = isSentInChannel && isThreadingEnabled && (!threadingRequiresMention || mentionsBot)

await _sendMessage({
botpressConversation,
botpressUser,
tags: {
ts: slackEvent.ts,
userId: slackEvent.user,
channelId: slackEvent.channel,
mentionsBot: mentionsBot ? 'true' : undefined,
forkedToThread: 'false',
},
discriminateByTags: ['ts', 'channelId'],
slackEvent,
client,
ctx,
logger,
})
const replyLocation = ctx.configuration.replyBehaviour?.location ?? 'channel'
const replyOnlyOnBotMention = ctx.configuration.replyBehaviour?.onlyOnBotMention ?? false

if (!shouldForkToReplyThread) {
if (replyOnlyOnBotMention && !mentionsBot) {
logger.forBot().warn('Message was not sent because the bot was not mentioned')
return
}

const { conversation: threadConversation } = await client.getOrCreateConversation({
channel: 'thread',
tags: { id: slackEvent.channel, thread: slackEvent.ts, isBotReplyThread: 'true' },
discriminateByTags: ['id', 'thread'],
})
const shouldRespondInChannel =
isSentInChannel && (replyLocation === 'channel' || replyLocation === 'channelAndThread')
const shouldRespondInThread = !isSentInChannel || replyLocation === 'thread' || replyLocation === 'channelAndThread'

await _sendMessage({
botpressConversation: threadConversation,
botpressUser,
tags: {
ts: slackEvent.ts,
userId: slackEvent.user,
channelId: slackEvent.channel,
mentionsBot: mentionsBot ? 'true' : undefined,
forkedToThread: 'true',
},
discriminateByTags: ['ts', 'channelId', 'forkedToThread'],
slackEvent,
client,
ctx,
logger,
})
if (shouldRespondInChannel) {
const { botpressConversation } = await getBotpressConversationFromSlackThread(
{ slackChannelId: slackEvent.channel, slackThreadId: undefined },
client
)

await _sendMessage({
botpressConversation,
botpressUser,
tags: {
ts: slackEvent.ts,
userId: slackEvent.user,
channelId: slackEvent.channel,
mentionsBot: mentionsBot ? 'true' : undefined,
forkedToThread: 'false',
},
discriminateByTags: ['ts', 'channelId'],
slackEvent,
client,
ctx,
logger,
})
}

if (shouldRespondInThread) {
const threadTs = slackEvent.thread_ts ?? slackEvent.ts

const { conversation: threadConversation } = await client.getOrCreateConversation({
channel: 'thread',
tags: { id: slackEvent.channel, thread: threadTs, isBotReplyThread: 'true' },
discriminateByTags: ['id', 'thread'],
})

await _sendMessage({
botpressConversation: threadConversation,
botpressUser,
tags: {
ts: slackEvent.ts,
userId: slackEvent.user,
channelId: slackEvent.channel,
mentionsBot: mentionsBot ? 'true' : undefined,
forkedToThread: isSentInChannel ? 'true' : 'false',
},
discriminateByTags: ['ts', 'channelId', 'forkedToThread'],
slackEvent,
client,
ctx,
logger,
})
}
}

type _SendMessageProps = HandleEventProps & {
Expand Down
5 changes: 0 additions & 5 deletions integrations/trello/.sentryclirc

This file was deleted.

Loading
Loading