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
28 changes: 26 additions & 2 deletions apps/docs/content/docs/en/tools/slack.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Slack
description: Send, update, delete messages, send ephemeral messages, add reactions in Slack or trigger workflows from Slack events
description: Send, update, delete messages, send ephemeral messages, add or remove reactions in Slack or trigger workflows from Slack events
---

import { BlockInfoCard } from "@/components/ui/block-info-card"
Expand Down Expand Up @@ -39,7 +39,7 @@ If you encounter issues with the Slack integration, contact us at [help@sim.ai](

## Usage Instructions

Integrate Slack into the workflow. Can send, update, and delete messages, send ephemeral messages visible only to a specific user, create canvases, read messages, and add reactions. Requires Bot Token instead of OAuth in advanced mode. Can be used in trigger mode to trigger a workflow when a message is sent to a channel.
Integrate Slack into the workflow. Can send, update, and delete messages, send ephemeral messages visible only to a specific user, create canvases, read messages, and add or remove reactions. Requires Bot Token instead of OAuth in advanced mode. Can be used in trigger mode to trigger a workflow when a message is sent to a channel.



Expand Down Expand Up @@ -799,4 +799,28 @@ Add an emoji reaction to a Slack message
| ↳ `timestamp` | string | Message timestamp |
| ↳ `reaction` | string | Emoji reaction name |

### `slack_remove_reaction`

Remove an emoji reaction from a Slack message

#### Input

| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `authMethod` | string | No | Authentication method: oauth or bot_token |
| `botToken` | string | No | Bot token for Custom Bot |
| `channel` | string | Yes | Channel ID where the message was posted \(e.g., C1234567890\) |
| `timestamp` | string | Yes | Timestamp of the message to remove reaction from \(e.g., 1405894322.002768\) |
| `name` | string | Yes | Name of the emoji reaction to remove \(without colons, e.g., thumbsup, heart, eyes\) |

#### Output

| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `content` | string | Success message |
| `metadata` | object | Reaction metadata |
| ↳ `channel` | string | Channel ID |
| ↳ `timestamp` | string | Message timestamp |
| ↳ `reaction` | string | Emoji reaction name |


87 changes: 87 additions & 0 deletions apps/sim/app/api/tools/slack/remove-reaction/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { type NextRequest, NextResponse } from 'next/server'
import { z } from 'zod'
import { checkInternalAuth } from '@/lib/auth/hybrid'

export const dynamic = 'force-dynamic'

const SlackRemoveReactionSchema = z.object({
accessToken: z.string().min(1, 'Access token is required'),
channel: z.string().min(1, 'Channel is required'),
timestamp: z.string().min(1, 'Message timestamp is required'),
name: z.string().min(1, 'Emoji name is required'),
})

export async function POST(request: NextRequest) {
try {
const authResult = await checkInternalAuth(request, { requireWorkflowId: false })

if (!authResult.success) {
return NextResponse.json(
{
success: false,
error: authResult.error || 'Authentication required',
},
{ status: 401 }
)
}

const body = await request.json()
const validatedData = SlackRemoveReactionSchema.parse(body)

const slackResponse = await fetch('https://slack.com/api/reactions.remove', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${validatedData.accessToken}`,
},
body: JSON.stringify({
channel: validatedData.channel,
timestamp: validatedData.timestamp,
name: validatedData.name,
}),
})

const data = await slackResponse.json()

if (!data.ok) {
return NextResponse.json(
{
success: false,
error: data.error || 'Failed to remove reaction',
},
{ status: slackResponse.status }
)
}

return NextResponse.json({
success: true,
output: {
content: `Successfully removed :${validatedData.name}: reaction`,
metadata: {
channel: validatedData.channel,
timestamp: validatedData.timestamp,
reaction: validatedData.name,
},
},
})
} catch (error) {
if (error instanceof z.ZodError) {
return NextResponse.json(
{
success: false,
error: 'Invalid request data',
details: error.errors,
},
{ status: 400 }
)
}

return NextResponse.json(
{
success: false,
error: error instanceof Error ? error.message : 'Unknown error occurred',
},
{ status: 500 }
)
}
}
13 changes: 9 additions & 4 deletions apps/sim/blocks/blocks/slack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ export const SlackBlock: BlockConfig<SlackResponse> = {
type: 'slack',
name: 'Slack',
description:
'Send, update, delete messages, send ephemeral messages, add reactions in Slack or trigger workflows from Slack events',
'Send, update, delete messages, send ephemeral messages, add or remove reactions in Slack or trigger workflows from Slack events',
authMode: AuthMode.OAuth,
longDescription:
'Integrate Slack into the workflow. Can send, update, and delete messages, send ephemeral messages visible only to a specific user, create canvases, read messages, and add reactions. Requires Bot Token instead of OAuth in advanced mode. Can be used in trigger mode to trigger a workflow when a message is sent to a channel.',
'Integrate Slack into the workflow. Can send, update, and delete messages, send ephemeral messages visible only to a specific user, create canvases, read messages, and add or remove reactions. Requires Bot Token instead of OAuth in advanced mode. Can be used in trigger mode to trigger a workflow when a message is sent to a channel.',
docsLink: 'https://docs.sim.ai/tools/slack',
category: 'tools',
bgColor: '#611f69',
Expand All @@ -38,6 +38,7 @@ export const SlackBlock: BlockConfig<SlackResponse> = {
{ label: 'Update Message', id: 'update' },
{ label: 'Delete Message', id: 'delete' },
{ label: 'Add Reaction', id: 'react' },
{ label: 'Remove Reaction', id: 'unreact' },
],
value: () => 'send',
},
Expand Down Expand Up @@ -608,7 +609,7 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
placeholder: 'Message timestamp (e.g., 1405894322.002768)',
condition: {
field: 'operation',
value: 'react',
value: ['react', 'unreact'],
},
required: true,
},
Expand All @@ -619,7 +620,7 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
placeholder: 'Emoji name without colons (e.g., thumbsup, heart, eyes)',
condition: {
field: 'operation',
value: 'react',
value: ['react', 'unreact'],
},
required: true,
},
Expand All @@ -641,6 +642,7 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
'slack_update_message',
'slack_delete_message',
'slack_add_reaction',
'slack_remove_reaction',
],
config: {
tool: (params) => {
Expand Down Expand Up @@ -673,6 +675,8 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
return 'slack_delete_message'
case 'react':
return 'slack_add_reaction'
case 'unreact':
return 'slack_remove_reaction'
default:
throw new Error(`Invalid Slack operation: ${params.operation}`)
}
Expand Down Expand Up @@ -841,6 +845,7 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
break

case 'react':
case 'unreact':
baseParams.timestamp = reactionTimestamp
baseParams.name = emojiName
break
Expand Down
2 changes: 2 additions & 0 deletions apps/sim/tools/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1808,6 +1808,7 @@ import {
slackListUsersTool,
slackMessageReaderTool,
slackMessageTool,
slackRemoveReactionTool,
slackUpdateMessageTool,
} from '@/tools/slack'
import { smsSendTool } from '@/tools/sms'
Expand Down Expand Up @@ -2611,6 +2612,7 @@ export const tools: Record<string, ToolConfig> = {
slack_update_message: slackUpdateMessageTool,
slack_delete_message: slackDeleteMessageTool,
slack_add_reaction: slackAddReactionTool,
slack_remove_reaction: slackRemoveReactionTool,
github_repo_info: githubRepoInfoTool,
github_repo_info_v2: githubRepoInfoV2Tool,
github_latest_commit: githubLatestCommitTool,
Expand Down
2 changes: 2 additions & 0 deletions apps/sim/tools/slack/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { slackListMembersTool } from '@/tools/slack/list_members'
import { slackListUsersTool } from '@/tools/slack/list_users'
import { slackMessageTool } from '@/tools/slack/message'
import { slackMessageReaderTool } from '@/tools/slack/message_reader'
import { slackRemoveReactionTool } from '@/tools/slack/remove_reaction'
import { slackUpdateMessageTool } from '@/tools/slack/update_message'

export {
Expand All @@ -22,6 +23,7 @@ export {
slackUpdateMessageTool,
slackDeleteMessageTool,
slackAddReactionTool,
slackRemoveReactionTool,
slackListChannelsTool,
slackListMembersTool,
slackListUsersTool,
Expand Down
108 changes: 108 additions & 0 deletions apps/sim/tools/slack/remove_reaction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import type { SlackRemoveReactionParams, SlackRemoveReactionResponse } from '@/tools/slack/types'
import { REACTION_METADATA_OUTPUT_PROPERTIES } from '@/tools/slack/types'
import type { ToolConfig } from '@/tools/types'

export const slackRemoveReactionTool: ToolConfig<
SlackRemoveReactionParams,
SlackRemoveReactionResponse
> = {
id: 'slack_remove_reaction',
name: 'Slack Remove Reaction',
description: 'Remove an emoji reaction from a Slack message',
version: '1.0.0',

oauth: {
required: true,
provider: 'slack',
},

params: {
authMethod: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Authentication method: oauth or bot_token',
},
botToken: {
type: 'string',
required: false,
visibility: 'user-only',
description: 'Bot token for Custom Bot',
},
accessToken: {
type: 'string',
required: false,
visibility: 'hidden',
description: 'OAuth access token or bot token for Slack API',
},
channel: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Channel ID where the message was posted (e.g., C1234567890)',
},
timestamp: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Timestamp of the message to remove reaction from (e.g., 1405894322.002768)',
},
name: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'Name of the emoji reaction to remove (without colons, e.g., thumbsup, heart, eyes)',
},
},

request: {
url: '/api/tools/slack/remove-reaction',
method: 'POST',
headers: () => ({
'Content-Type': 'application/json',
}),
body: (params: SlackRemoveReactionParams) => ({
accessToken: params.accessToken || params.botToken,
channel: params.channel,
timestamp: params.timestamp,
name: params.name,
}),
},

transformResponse: async (response: Response) => {
const data = await response.json()

if (!data.success) {
return {
success: false,
output: {
content: data.error || 'Failed to remove reaction',
metadata: {
channel: '',
timestamp: '',
reaction: '',
},
},
error: data.error,
}
}

return {
success: true,
output: {
content: data.output.content,
metadata: data.output.metadata,
},
}
},

outputs: {
content: { type: 'string', description: 'Success message' },
metadata: {
type: 'object',
description: 'Reaction metadata',
properties: REACTION_METADATA_OUTPUT_PROPERTIES,
},
},
}
18 changes: 18 additions & 0 deletions apps/sim/tools/slack/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,12 @@ export interface SlackAddReactionParams extends SlackBaseParams {
name: string
}

export interface SlackRemoveReactionParams extends SlackBaseParams {
channel: string
timestamp: string
name: string
}

export interface SlackListChannelsParams extends SlackBaseParams {
includePrivate?: boolean
excludeArchived?: boolean
Expand Down Expand Up @@ -759,6 +765,17 @@ export interface SlackAddReactionResponse extends ToolResponse {
}
}

export interface SlackRemoveReactionResponse extends ToolResponse {
output: {
content: string
metadata: {
channel: string
timestamp: string
reaction: string
}
}
}

export interface SlackChannel {
id: string
name: string
Expand Down Expand Up @@ -866,6 +883,7 @@ export type SlackResponse =
| SlackUpdateMessageResponse
| SlackDeleteMessageResponse
| SlackAddReactionResponse
| SlackRemoveReactionResponse
| SlackListChannelsResponse
| SlackListMembersResponse
| SlackListUsersResponse
Expand Down