mirror of
https://github.com/simstudioai/sim.git
synced 2026-03-15 03:00:33 -04:00
Compare commits
7 Commits
main
...
waleedlati
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8cbd95404a | ||
|
|
5e51fa7bf8 | ||
|
|
2ace4b36a1 | ||
|
|
778defc750 | ||
|
|
33a9078948 | ||
|
|
78235e6739 | ||
|
|
be18ff4288 |
@@ -1,6 +1,6 @@
|
||||
---
|
||||
title: Slack
|
||||
description: Send, update, delete messages, send ephemeral messages, add or remove reactions in Slack or trigger workflows from Slack events
|
||||
description: Send, update, delete messages, add or remove reactions, manage canvases, get channel info and user presence in Slack
|
||||
---
|
||||
|
||||
import { BlockInfoCard } from "@/components/ui/block-info-card"
|
||||
@@ -823,4 +823,104 @@ Remove an emoji reaction from a Slack message
|
||||
| ↳ `timestamp` | string | Message timestamp |
|
||||
| ↳ `reaction` | string | Emoji reaction name |
|
||||
|
||||
### `slack_get_channel_info`
|
||||
|
||||
Get detailed information about a Slack channel by its ID
|
||||
|
||||
#### 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 to get information about \(e.g., C1234567890\) |
|
||||
| `includeNumMembers` | boolean | No | Whether to include the member count in the response |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `channelInfo` | object | Detailed channel information |
|
||||
| ↳ `id` | string | Channel ID \(e.g., C1234567890\) |
|
||||
| ↳ `name` | string | Channel name without # prefix |
|
||||
| ↳ `is_channel` | boolean | Whether this is a channel |
|
||||
| ↳ `is_private` | boolean | Whether channel is private |
|
||||
| ↳ `is_archived` | boolean | Whether channel is archived |
|
||||
| ↳ `is_general` | boolean | Whether this is the general channel |
|
||||
| ↳ `is_member` | boolean | Whether the bot/user is a member |
|
||||
| ↳ `is_shared` | boolean | Whether channel is shared across workspaces |
|
||||
| ↳ `is_ext_shared` | boolean | Whether channel is externally shared |
|
||||
| ↳ `is_org_shared` | boolean | Whether channel is org-wide shared |
|
||||
| ↳ `num_members` | number | Number of members in the channel |
|
||||
| ↳ `topic` | string | Channel topic |
|
||||
| ↳ `purpose` | string | Channel purpose/description |
|
||||
| ↳ `created` | number | Unix timestamp when channel was created |
|
||||
| ↳ `creator` | string | User ID of channel creator |
|
||||
| ↳ `updated` | number | Unix timestamp of last update |
|
||||
|
||||
### `slack_get_user_presence`
|
||||
|
||||
Check whether a Slack user is currently active or away
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `authMethod` | string | No | Authentication method: oauth or bot_token |
|
||||
| `botToken` | string | No | Bot token for Custom Bot |
|
||||
| `userId` | string | Yes | User ID to check presence for \(e.g., U1234567890\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `presence` | string | User presence status: "active" or "away" |
|
||||
| `online` | boolean | Whether user has an active client connection \(only available when checking own presence\) |
|
||||
| `autoAway` | boolean | Whether user was automatically set to away due to inactivity \(only available when checking own presence\) |
|
||||
| `manualAway` | boolean | Whether user manually set themselves as away \(only available when checking own presence\) |
|
||||
| `connectionCount` | number | Total number of active connections for the user \(only available when checking own presence\) |
|
||||
| `lastActivity` | number | Unix timestamp of last detected activity \(only available when checking own presence\) |
|
||||
|
||||
### `slack_edit_canvas`
|
||||
|
||||
Edit an existing Slack canvas by inserting, replacing, or deleting content
|
||||
|
||||
#### Input
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
| --------- | ---- | -------- | ----------- |
|
||||
| `authMethod` | string | No | Authentication method: oauth or bot_token |
|
||||
| `botToken` | string | No | Bot token for Custom Bot |
|
||||
| `canvasId` | string | Yes | Canvas ID to edit \(e.g., F1234ABCD\) |
|
||||
| `operation` | string | Yes | Edit operation: insert_at_start, insert_at_end, insert_after, insert_before, replace, delete, or rename |
|
||||
| `content` | string | No | Markdown content for the operation \(required for insert/replace operations\) |
|
||||
| `sectionId` | string | No | Section ID to target \(required for insert_after, insert_before, replace, and delete\) |
|
||||
| `title` | string | No | New title for the canvas \(only used with rename operation\) |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `content` | string | Success message |
|
||||
|
||||
### `slack_create_channel_canvas`
|
||||
|
||||
Create a canvas pinned to a Slack channel as its resource hub
|
||||
|
||||
#### 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 to create the canvas in \(e.g., C1234567890\) |
|
||||
| `title` | string | No | Title for the channel canvas |
|
||||
| `content` | string | No | Canvas content in markdown format |
|
||||
|
||||
#### Output
|
||||
|
||||
| Parameter | Type | Description |
|
||||
| --------- | ---- | ----------- |
|
||||
| `canvas_id` | string | ID of the created channel canvas |
|
||||
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ export const SlackBlock: BlockConfig<SlackResponse> = {
|
||||
type: 'slack',
|
||||
name: 'Slack',
|
||||
description:
|
||||
'Send, update, delete messages, send ephemeral messages, add or remove reactions in Slack or trigger workflows from Slack events',
|
||||
'Send, update, delete messages, add or remove reactions, manage canvases, get channel info and user presence in Slack',
|
||||
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 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.',
|
||||
@@ -39,6 +39,10 @@ export const SlackBlock: BlockConfig<SlackResponse> = {
|
||||
{ label: 'Delete Message', id: 'delete' },
|
||||
{ label: 'Add Reaction', id: 'react' },
|
||||
{ label: 'Remove Reaction', id: 'unreact' },
|
||||
{ label: 'Get Channel Info', id: 'get_channel_info' },
|
||||
{ label: 'Get User Presence', id: 'get_user_presence' },
|
||||
{ label: 'Edit Canvas', id: 'edit_canvas' },
|
||||
{ label: 'Create Channel Canvas', id: 'create_channel_canvas' },
|
||||
],
|
||||
value: () => 'send',
|
||||
},
|
||||
@@ -142,7 +146,7 @@ export const SlackBlock: BlockConfig<SlackResponse> = {
|
||||
}
|
||||
return {
|
||||
field: 'operation',
|
||||
value: ['list_channels', 'list_users', 'get_user'],
|
||||
value: ['list_channels', 'list_users', 'get_user', 'get_user_presence', 'edit_canvas'],
|
||||
not: true,
|
||||
and: {
|
||||
field: 'destinationType',
|
||||
@@ -167,7 +171,7 @@ export const SlackBlock: BlockConfig<SlackResponse> = {
|
||||
}
|
||||
return {
|
||||
field: 'operation',
|
||||
value: ['list_channels', 'list_users', 'get_user'],
|
||||
value: ['list_channels', 'list_users', 'get_user', 'get_user_presence', 'edit_canvas'],
|
||||
not: true,
|
||||
and: {
|
||||
field: 'destinationType',
|
||||
@@ -210,8 +214,26 @@ export const SlackBlock: BlockConfig<SlackResponse> = {
|
||||
{
|
||||
id: 'ephemeralUser',
|
||||
title: 'Target User',
|
||||
type: 'user-selector',
|
||||
canonicalParamId: 'ephemeralUser',
|
||||
serviceId: 'slack',
|
||||
selectorKey: 'slack.users',
|
||||
placeholder: 'Select Slack user',
|
||||
mode: 'basic',
|
||||
dependsOn: { all: ['authMethod'], any: ['credential', 'botToken'] },
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: 'ephemeral',
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'manualEphemeralUser',
|
||||
title: 'Target User ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'User ID who will see the message (e.g., U1234567890)',
|
||||
canonicalParamId: 'ephemeralUser',
|
||||
placeholder: 'Enter Slack user ID (e.g., U1234567890)',
|
||||
mode: 'advanced',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: 'ephemeral',
|
||||
@@ -441,9 +463,27 @@ Do not include any explanations, markdown formatting, or other text outside the
|
||||
// Get User specific fields
|
||||
{
|
||||
id: 'userId',
|
||||
title: 'User',
|
||||
type: 'user-selector',
|
||||
canonicalParamId: 'userId',
|
||||
serviceId: 'slack',
|
||||
selectorKey: 'slack.users',
|
||||
placeholder: 'Select Slack user',
|
||||
mode: 'basic',
|
||||
dependsOn: { all: ['authMethod'], any: ['credential', 'botToken'] },
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: 'get_user',
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'manualUserId',
|
||||
title: 'User ID',
|
||||
type: 'short-input',
|
||||
canonicalParamId: 'userId',
|
||||
placeholder: 'Enter Slack user ID (e.g., U1234567890)',
|
||||
mode: 'advanced',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: 'get_user',
|
||||
@@ -624,6 +664,146 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
// Get Channel Info specific fields
|
||||
{
|
||||
id: 'includeNumMembers',
|
||||
title: 'Include Member Count',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Yes', id: 'true' },
|
||||
{ label: 'No', id: 'false' },
|
||||
],
|
||||
value: () => 'true',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: 'get_channel_info',
|
||||
},
|
||||
},
|
||||
// Get User Presence specific fields
|
||||
{
|
||||
id: 'presenceUserId',
|
||||
title: 'User',
|
||||
type: 'user-selector',
|
||||
canonicalParamId: 'presenceUserId',
|
||||
serviceId: 'slack',
|
||||
selectorKey: 'slack.users',
|
||||
placeholder: 'Select Slack user',
|
||||
mode: 'basic',
|
||||
dependsOn: { all: ['authMethod'], any: ['credential', 'botToken'] },
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: 'get_user_presence',
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'manualPresenceUserId',
|
||||
title: 'User ID',
|
||||
type: 'short-input',
|
||||
canonicalParamId: 'presenceUserId',
|
||||
placeholder: 'Enter Slack user ID (e.g., U1234567890)',
|
||||
mode: 'advanced',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: 'get_user_presence',
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
// Edit Canvas specific fields
|
||||
{
|
||||
id: 'editCanvasId',
|
||||
title: 'Canvas ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'Enter canvas ID (e.g., F1234ABCD)',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: 'edit_canvas',
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'canvasOperation',
|
||||
title: 'Edit Operation',
|
||||
type: 'dropdown',
|
||||
options: [
|
||||
{ label: 'Insert at Start', id: 'insert_at_start' },
|
||||
{ label: 'Insert at End', id: 'insert_at_end' },
|
||||
{ label: 'Insert After Section', id: 'insert_after' },
|
||||
{ label: 'Insert Before Section', id: 'insert_before' },
|
||||
{ label: 'Replace Section', id: 'replace' },
|
||||
{ label: 'Delete Section', id: 'delete' },
|
||||
{ label: 'Rename Canvas', id: 'rename' },
|
||||
],
|
||||
value: () => 'insert_at_end',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: 'edit_canvas',
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'canvasContent',
|
||||
title: 'Content',
|
||||
type: 'long-input',
|
||||
placeholder: 'Enter content in markdown format',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: 'edit_canvas',
|
||||
and: {
|
||||
field: 'canvasOperation',
|
||||
value: ['delete', 'rename'],
|
||||
not: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'sectionId',
|
||||
title: 'Section ID',
|
||||
type: 'short-input',
|
||||
placeholder: 'Section ID to target',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: 'edit_canvas',
|
||||
and: {
|
||||
field: 'canvasOperation',
|
||||
value: ['insert_after', 'insert_before', 'replace', 'delete'],
|
||||
},
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
id: 'canvasTitle',
|
||||
title: 'New Title',
|
||||
type: 'short-input',
|
||||
placeholder: 'Enter new canvas title',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: 'edit_canvas',
|
||||
and: { field: 'canvasOperation', value: 'rename' },
|
||||
},
|
||||
required: true,
|
||||
},
|
||||
// Create Channel Canvas specific fields
|
||||
{
|
||||
id: 'channelCanvasTitle',
|
||||
title: 'Canvas Title',
|
||||
type: 'short-input',
|
||||
placeholder: 'Enter canvas title (optional)',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: 'create_channel_canvas',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'channelCanvasContent',
|
||||
title: 'Canvas Content',
|
||||
type: 'long-input',
|
||||
placeholder: 'Enter canvas content (markdown supported)',
|
||||
condition: {
|
||||
field: 'operation',
|
||||
value: 'create_channel_canvas',
|
||||
},
|
||||
},
|
||||
...getTrigger('slack_webhook').subBlocks,
|
||||
],
|
||||
tools: {
|
||||
@@ -643,6 +823,10 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||||
'slack_delete_message',
|
||||
'slack_add_reaction',
|
||||
'slack_remove_reaction',
|
||||
'slack_get_channel_info',
|
||||
'slack_get_user_presence',
|
||||
'slack_edit_canvas',
|
||||
'slack_create_channel_canvas',
|
||||
],
|
||||
config: {
|
||||
tool: (params) => {
|
||||
@@ -677,6 +861,14 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||||
return 'slack_add_reaction'
|
||||
case 'unreact':
|
||||
return 'slack_remove_reaction'
|
||||
case 'get_channel_info':
|
||||
return 'slack_get_channel_info'
|
||||
case 'get_user_presence':
|
||||
return 'slack_get_user_presence'
|
||||
case 'edit_canvas':
|
||||
return 'slack_edit_canvas'
|
||||
case 'create_channel_canvas':
|
||||
return 'slack_create_channel_canvas'
|
||||
default:
|
||||
throw new Error(`Invalid Slack operation: ${params.operation}`)
|
||||
}
|
||||
@@ -714,6 +906,15 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||||
getMessageTimestamp,
|
||||
getThreadTimestamp,
|
||||
threadLimit,
|
||||
includeNumMembers,
|
||||
presenceUserId,
|
||||
editCanvasId,
|
||||
canvasOperation,
|
||||
canvasContent,
|
||||
sectionId,
|
||||
canvasTitle,
|
||||
channelCanvasTitle,
|
||||
channelCanvasContent,
|
||||
...rest
|
||||
} = params
|
||||
|
||||
@@ -824,10 +1025,10 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||||
|
||||
case 'download': {
|
||||
const fileId = (rest as any).fileId
|
||||
const downloadFileName = (rest as any).downloadFileName
|
||||
const fileName = (rest as any).fileName
|
||||
baseParams.fileId = fileId
|
||||
if (downloadFileName) {
|
||||
baseParams.fileName = downloadFileName
|
||||
if (fileName) {
|
||||
baseParams.fileName = fileName
|
||||
}
|
||||
break
|
||||
}
|
||||
@@ -849,6 +1050,37 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||||
baseParams.timestamp = reactionTimestamp
|
||||
baseParams.name = emojiName
|
||||
break
|
||||
|
||||
case 'get_channel_info':
|
||||
baseParams.includeNumMembers = includeNumMembers !== 'false'
|
||||
break
|
||||
|
||||
case 'get_user_presence':
|
||||
baseParams.userId = presenceUserId
|
||||
break
|
||||
|
||||
case 'edit_canvas':
|
||||
baseParams.canvasId = editCanvasId
|
||||
baseParams.operation = canvasOperation
|
||||
if (canvasContent) {
|
||||
baseParams.content = canvasContent
|
||||
}
|
||||
if (sectionId) {
|
||||
baseParams.sectionId = sectionId
|
||||
}
|
||||
if (canvasTitle) {
|
||||
baseParams.title = canvasTitle
|
||||
}
|
||||
break
|
||||
|
||||
case 'create_channel_canvas':
|
||||
if (channelCanvasTitle) {
|
||||
baseParams.title = channelCanvasTitle
|
||||
}
|
||||
if (channelCanvasContent) {
|
||||
baseParams.content = channelCanvasContent
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
return baseParams
|
||||
@@ -903,6 +1135,19 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||||
type: 'string',
|
||||
description: 'Maximum number of messages to return from thread',
|
||||
},
|
||||
// Get Channel Info inputs
|
||||
includeNumMembers: { type: 'string', description: 'Include member count (true/false)' },
|
||||
// Get User Presence inputs
|
||||
presenceUserId: { type: 'string', description: 'User ID to check presence for' },
|
||||
// Edit Canvas inputs
|
||||
editCanvasId: { type: 'string', description: 'Canvas ID to edit' },
|
||||
canvasOperation: { type: 'string', description: 'Canvas edit operation' },
|
||||
canvasContent: { type: 'string', description: 'Markdown content for canvas edit' },
|
||||
sectionId: { type: 'string', description: 'Canvas section ID to target' },
|
||||
canvasTitle: { type: 'string', description: 'New canvas title for rename' },
|
||||
// Create Channel Canvas inputs
|
||||
channelCanvasTitle: { type: 'string', description: 'Title for channel canvas' },
|
||||
channelCanvasContent: { type: 'string', description: 'Content for channel canvas' },
|
||||
},
|
||||
outputs: {
|
||||
// slack_message outputs (send operation)
|
||||
@@ -999,6 +1244,43 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
|
||||
description: 'Updated message metadata (legacy, use message object instead)',
|
||||
},
|
||||
|
||||
// slack_get_channel_info outputs (get_channel_info operation)
|
||||
channelInfo: {
|
||||
type: 'json',
|
||||
description:
|
||||
'Detailed channel object with properties: id, name, is_private, is_archived, is_member, num_members, topic, purpose, created, creator',
|
||||
},
|
||||
|
||||
// slack_get_user_presence outputs (get_user_presence operation)
|
||||
presence: {
|
||||
type: 'string',
|
||||
description: 'User presence status: "active" or "away"',
|
||||
},
|
||||
online: {
|
||||
type: 'boolean',
|
||||
description:
|
||||
'Whether user has an active client connection (only available when checking own presence)',
|
||||
},
|
||||
autoAway: {
|
||||
type: 'boolean',
|
||||
description:
|
||||
'Whether user was automatically set to away (only available when checking own presence)',
|
||||
},
|
||||
manualAway: {
|
||||
type: 'boolean',
|
||||
description:
|
||||
'Whether user manually set themselves as away (only available when checking own presence)',
|
||||
},
|
||||
connectionCount: {
|
||||
type: 'number',
|
||||
description: 'Total number of active connections (only available when checking own presence)',
|
||||
},
|
||||
lastActivity: {
|
||||
type: 'number',
|
||||
description:
|
||||
'Unix timestamp of last detected activity (only available when checking own presence)',
|
||||
},
|
||||
|
||||
// Trigger outputs (when used as webhook trigger)
|
||||
event_type: { type: 'string', description: 'Type of Slack event that triggered the workflow' },
|
||||
channel_name: { type: 'string', description: 'Human-readable channel name' },
|
||||
|
||||
@@ -1797,11 +1797,15 @@ import {
|
||||
import {
|
||||
slackAddReactionTool,
|
||||
slackCanvasTool,
|
||||
slackCreateChannelCanvasTool,
|
||||
slackDeleteMessageTool,
|
||||
slackDownloadTool,
|
||||
slackEditCanvasTool,
|
||||
slackEphemeralMessageTool,
|
||||
slackGetChannelInfoTool,
|
||||
slackGetMessageTool,
|
||||
slackGetThreadTool,
|
||||
slackGetUserPresenceTool,
|
||||
slackGetUserTool,
|
||||
slackListChannelsTool,
|
||||
slackListMembersTool,
|
||||
@@ -2613,6 +2617,10 @@ export const tools: Record<string, ToolConfig> = {
|
||||
slack_delete_message: slackDeleteMessageTool,
|
||||
slack_add_reaction: slackAddReactionTool,
|
||||
slack_remove_reaction: slackRemoveReactionTool,
|
||||
slack_get_channel_info: slackGetChannelInfoTool,
|
||||
slack_get_user_presence: slackGetUserPresenceTool,
|
||||
slack_edit_canvas: slackEditCanvasTool,
|
||||
slack_create_channel_canvas: slackCreateChannelCanvasTool,
|
||||
github_repo_info: githubRepoInfoTool,
|
||||
github_repo_info_v2: githubRepoInfoV2Tool,
|
||||
github_latest_commit: githubLatestCommitTool,
|
||||
|
||||
@@ -87,9 +87,21 @@ export const slackCanvasTool: ToolConfig<SlackCanvasParams, SlackCanvasResponse>
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
transformResponse: async (response: Response): Promise<SlackCanvasResponse> => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!data.ok) {
|
||||
return {
|
||||
success: false,
|
||||
output: {
|
||||
canvas_id: '',
|
||||
channel: '',
|
||||
title: '',
|
||||
error: data.error || 'Unknown error',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
|
||||
108
apps/sim/tools/slack/create_channel_canvas.ts
Normal file
108
apps/sim/tools/slack/create_channel_canvas.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
import type {
|
||||
SlackCreateChannelCanvasParams,
|
||||
SlackCreateChannelCanvasResponse,
|
||||
} from '@/tools/slack/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const slackCreateChannelCanvasTool: ToolConfig<
|
||||
SlackCreateChannelCanvasParams,
|
||||
SlackCreateChannelCanvasResponse
|
||||
> = {
|
||||
id: 'slack_create_channel_canvas',
|
||||
name: 'Slack Create Channel Canvas',
|
||||
description: 'Create a canvas pinned to a Slack channel as its resource hub',
|
||||
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 to create the canvas in (e.g., C1234567890)',
|
||||
},
|
||||
title: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Title for the channel canvas',
|
||||
},
|
||||
content: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Canvas content in markdown format',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://slack.com/api/conversations.canvases.create',
|
||||
method: 'POST',
|
||||
headers: (params: SlackCreateChannelCanvasParams) => ({
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${params.accessToken || params.botToken}`,
|
||||
}),
|
||||
body: (params: SlackCreateChannelCanvasParams) => {
|
||||
const body: Record<string, unknown> = {
|
||||
channel_id: params.channel.trim(),
|
||||
}
|
||||
|
||||
if (params.title) {
|
||||
body.title = params.title
|
||||
}
|
||||
|
||||
if (params.content) {
|
||||
body.document_content = {
|
||||
type: 'markdown',
|
||||
markdown: params.content,
|
||||
}
|
||||
}
|
||||
|
||||
return body
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!data.ok) {
|
||||
if (data.error === 'channel_canvas_already_exists') {
|
||||
throw new Error('A canvas already exists for this channel. Use Edit Canvas to modify it.')
|
||||
}
|
||||
throw new Error(data.error || 'Failed to create channel canvas')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
canvas_id: data.canvas_id,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
canvas_id: { type: 'string', description: 'ID of the created channel canvas' },
|
||||
},
|
||||
}
|
||||
121
apps/sim/tools/slack/edit_canvas.ts
Normal file
121
apps/sim/tools/slack/edit_canvas.ts
Normal file
@@ -0,0 +1,121 @@
|
||||
import type { SlackEditCanvasParams, SlackEditCanvasResponse } from '@/tools/slack/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const slackEditCanvasTool: ToolConfig<SlackEditCanvasParams, SlackEditCanvasResponse> = {
|
||||
id: 'slack_edit_canvas',
|
||||
name: 'Slack Edit Canvas',
|
||||
description: 'Edit an existing Slack canvas by inserting, replacing, or deleting content',
|
||||
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',
|
||||
},
|
||||
canvasId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Canvas ID to edit (e.g., F1234ABCD)',
|
||||
},
|
||||
operation: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Edit operation: insert_at_start, insert_at_end, insert_after, insert_before, replace, delete, or rename',
|
||||
},
|
||||
content: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Markdown content for the operation (required for insert/replace operations)',
|
||||
},
|
||||
sectionId: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description:
|
||||
'Section ID to target (required for insert_after, insert_before, replace, and delete)',
|
||||
},
|
||||
title: {
|
||||
type: 'string',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'New title for the canvas (only used with rename operation)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: 'https://slack.com/api/canvases.edit',
|
||||
method: 'POST',
|
||||
headers: (params: SlackEditCanvasParams) => ({
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${params.accessToken || params.botToken}`,
|
||||
}),
|
||||
body: (params: SlackEditCanvasParams) => {
|
||||
const change: Record<string, unknown> = {
|
||||
operation: params.operation,
|
||||
}
|
||||
|
||||
if (params.sectionId) {
|
||||
change.section_id = params.sectionId.trim()
|
||||
}
|
||||
|
||||
if (params.operation === 'rename' && params.title) {
|
||||
change.title_content = {
|
||||
type: 'markdown',
|
||||
markdown: params.title,
|
||||
}
|
||||
} else if (params.content && params.operation !== 'delete') {
|
||||
change.document_content = {
|
||||
type: 'markdown',
|
||||
markdown: params.content,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
canvas_id: params.canvasId.trim(),
|
||||
changes: [change],
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!data.ok) {
|
||||
throw new Error(data.error || 'Failed to edit canvas')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
content: 'Successfully edited canvas',
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
content: { type: 'string', description: 'Success message' },
|
||||
},
|
||||
}
|
||||
115
apps/sim/tools/slack/get_channel_info.ts
Normal file
115
apps/sim/tools/slack/get_channel_info.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
import type { SlackGetChannelInfoParams, SlackGetChannelInfoResponse } from '@/tools/slack/types'
|
||||
import { CHANNEL_OUTPUT_PROPERTIES } from '@/tools/slack/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const slackGetChannelInfoTool: ToolConfig<
|
||||
SlackGetChannelInfoParams,
|
||||
SlackGetChannelInfoResponse
|
||||
> = {
|
||||
id: 'slack_get_channel_info',
|
||||
name: 'Slack Get Channel Info',
|
||||
description: 'Get detailed information about a Slack channel by its ID',
|
||||
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 to get information about (e.g., C1234567890)',
|
||||
},
|
||||
includeNumMembers: {
|
||||
type: 'boolean',
|
||||
required: false,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'Whether to include the member count in the response',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: SlackGetChannelInfoParams) => {
|
||||
const url = new URL('https://slack.com/api/conversations.info')
|
||||
url.searchParams.append('channel', params.channel.trim())
|
||||
url.searchParams.append('include_num_members', String(params.includeNumMembers ?? true))
|
||||
return url.toString()
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: SlackGetChannelInfoParams) => ({
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${params.accessToken || params.botToken}`,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!data.ok) {
|
||||
if (data.error === 'channel_not_found') {
|
||||
throw new Error('Channel not found. Please check the channel ID and try again.')
|
||||
}
|
||||
if (data.error === 'missing_scope') {
|
||||
throw new Error(
|
||||
'Missing required permissions. Please reconnect your Slack account with the necessary scopes (channels:read).'
|
||||
)
|
||||
}
|
||||
throw new Error(data.error || 'Failed to get channel info from Slack')
|
||||
}
|
||||
|
||||
const channel = data.channel
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
channelInfo: {
|
||||
id: channel.id,
|
||||
name: channel.name ?? '',
|
||||
is_channel: channel.is_channel ?? false,
|
||||
is_private: channel.is_private ?? false,
|
||||
is_archived: channel.is_archived ?? false,
|
||||
is_general: channel.is_general ?? false,
|
||||
is_member: channel.is_member ?? false,
|
||||
is_shared: channel.is_shared ?? false,
|
||||
is_ext_shared: channel.is_ext_shared ?? false,
|
||||
is_org_shared: channel.is_org_shared ?? false,
|
||||
num_members: channel.num_members ?? null,
|
||||
topic: channel.topic?.value ?? '',
|
||||
purpose: channel.purpose?.value ?? '',
|
||||
created: channel.created ?? null,
|
||||
creator: channel.creator ?? null,
|
||||
updated: channel.updated ?? null,
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
channelInfo: {
|
||||
type: 'object',
|
||||
description: 'Detailed channel information',
|
||||
properties: CHANNEL_OUTPUT_PROPERTIES,
|
||||
},
|
||||
},
|
||||
}
|
||||
122
apps/sim/tools/slack/get_user_presence.ts
Normal file
122
apps/sim/tools/slack/get_user_presence.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
import type { SlackGetUserPresenceParams, SlackGetUserPresenceResponse } from '@/tools/slack/types'
|
||||
import type { ToolConfig } from '@/tools/types'
|
||||
|
||||
export const slackGetUserPresenceTool: ToolConfig<
|
||||
SlackGetUserPresenceParams,
|
||||
SlackGetUserPresenceResponse
|
||||
> = {
|
||||
id: 'slack_get_user_presence',
|
||||
name: 'Slack Get User Presence',
|
||||
description: 'Check whether a Slack user is currently active or away',
|
||||
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',
|
||||
},
|
||||
userId: {
|
||||
type: 'string',
|
||||
required: true,
|
||||
visibility: 'user-or-llm',
|
||||
description: 'User ID to check presence for (e.g., U1234567890)',
|
||||
},
|
||||
},
|
||||
|
||||
request: {
|
||||
url: (params: SlackGetUserPresenceParams) => {
|
||||
const url = new URL('https://slack.com/api/users.getPresence')
|
||||
url.searchParams.append('user', params.userId.trim())
|
||||
return url.toString()
|
||||
},
|
||||
method: 'GET',
|
||||
headers: (params: SlackGetUserPresenceParams) => ({
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: `Bearer ${params.accessToken || params.botToken}`,
|
||||
}),
|
||||
},
|
||||
|
||||
transformResponse: async (response: Response) => {
|
||||
const data = await response.json()
|
||||
|
||||
if (!data.ok) {
|
||||
if (data.error === 'user_not_found') {
|
||||
throw new Error('User not found. Please check the user ID and try again.')
|
||||
}
|
||||
if (data.error === 'missing_scope') {
|
||||
throw new Error(
|
||||
'Missing required permissions. Please reconnect your Slack account with the necessary scopes (users:read).'
|
||||
)
|
||||
}
|
||||
throw new Error(data.error || 'Failed to get user presence from Slack')
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
output: {
|
||||
presence: data.presence,
|
||||
online: data.online ?? null,
|
||||
autoAway: data.auto_away ?? null,
|
||||
manualAway: data.manual_away ?? null,
|
||||
connectionCount: data.connection_count ?? null,
|
||||
lastActivity: data.last_activity ?? null,
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
outputs: {
|
||||
presence: {
|
||||
type: 'string',
|
||||
description: 'User presence status: "active" or "away"',
|
||||
},
|
||||
online: {
|
||||
type: 'boolean',
|
||||
description:
|
||||
'Whether user has an active client connection (only available when checking own presence)',
|
||||
optional: true,
|
||||
},
|
||||
autoAway: {
|
||||
type: 'boolean',
|
||||
description:
|
||||
'Whether user was automatically set to away due to inactivity (only available when checking own presence)',
|
||||
optional: true,
|
||||
},
|
||||
manualAway: {
|
||||
type: 'boolean',
|
||||
description:
|
||||
'Whether user manually set themselves as away (only available when checking own presence)',
|
||||
optional: true,
|
||||
},
|
||||
connectionCount: {
|
||||
type: 'number',
|
||||
description:
|
||||
'Total number of active connections for the user (only available when checking own presence)',
|
||||
optional: true,
|
||||
},
|
||||
lastActivity: {
|
||||
type: 'number',
|
||||
description:
|
||||
'Unix timestamp of last detected activity (only available when checking own presence)',
|
||||
optional: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -1,11 +1,15 @@
|
||||
import { slackAddReactionTool } from '@/tools/slack/add_reaction'
|
||||
import { slackCanvasTool } from '@/tools/slack/canvas'
|
||||
import { slackCreateChannelCanvasTool } from '@/tools/slack/create_channel_canvas'
|
||||
import { slackDeleteMessageTool } from '@/tools/slack/delete_message'
|
||||
import { slackDownloadTool } from '@/tools/slack/download'
|
||||
import { slackEditCanvasTool } from '@/tools/slack/edit_canvas'
|
||||
import { slackEphemeralMessageTool } from '@/tools/slack/ephemeral_message'
|
||||
import { slackGetChannelInfoTool } from '@/tools/slack/get_channel_info'
|
||||
import { slackGetMessageTool } from '@/tools/slack/get_message'
|
||||
import { slackGetThreadTool } from '@/tools/slack/get_thread'
|
||||
import { slackGetUserTool } from '@/tools/slack/get_user'
|
||||
import { slackGetUserPresenceTool } from '@/tools/slack/get_user_presence'
|
||||
import { slackListChannelsTool } from '@/tools/slack/list_channels'
|
||||
import { slackListMembersTool } from '@/tools/slack/list_members'
|
||||
import { slackListUsersTool } from '@/tools/slack/list_users'
|
||||
@@ -17,17 +21,21 @@ import { slackUpdateMessageTool } from '@/tools/slack/update_message'
|
||||
export {
|
||||
slackMessageTool,
|
||||
slackCanvasTool,
|
||||
slackCreateChannelCanvasTool,
|
||||
slackMessageReaderTool,
|
||||
slackDownloadTool,
|
||||
slackEditCanvasTool,
|
||||
slackEphemeralMessageTool,
|
||||
slackUpdateMessageTool,
|
||||
slackDeleteMessageTool,
|
||||
slackAddReactionTool,
|
||||
slackRemoveReactionTool,
|
||||
slackGetChannelInfoTool,
|
||||
slackListChannelsTool,
|
||||
slackListMembersTool,
|
||||
slackListUsersTool,
|
||||
slackGetUserTool,
|
||||
slackGetUserPresenceTool,
|
||||
slackGetMessageTool,
|
||||
slackGetThreadTool,
|
||||
}
|
||||
|
||||
@@ -606,6 +606,29 @@ export interface SlackGetThreadParams extends SlackBaseParams {
|
||||
limit?: number
|
||||
}
|
||||
|
||||
export interface SlackGetChannelInfoParams extends SlackBaseParams {
|
||||
channel: string
|
||||
includeNumMembers?: boolean
|
||||
}
|
||||
|
||||
export interface SlackGetUserPresenceParams extends SlackBaseParams {
|
||||
userId: string
|
||||
}
|
||||
|
||||
export interface SlackEditCanvasParams extends SlackBaseParams {
|
||||
canvasId: string
|
||||
operation: string
|
||||
content?: string
|
||||
sectionId?: string
|
||||
title?: string
|
||||
}
|
||||
|
||||
export interface SlackCreateChannelCanvasParams extends SlackBaseParams {
|
||||
channel: string
|
||||
title?: string
|
||||
content?: string
|
||||
}
|
||||
|
||||
export interface SlackMessageResponse extends ToolResponse {
|
||||
output: {
|
||||
// Legacy properties for backward compatibility
|
||||
@@ -779,14 +802,20 @@ export interface SlackRemoveReactionResponse extends ToolResponse {
|
||||
export interface SlackChannel {
|
||||
id: string
|
||||
name: string
|
||||
is_channel?: boolean
|
||||
is_private: boolean
|
||||
is_archived: boolean
|
||||
is_general?: boolean
|
||||
is_member: boolean
|
||||
is_shared?: boolean
|
||||
is_ext_shared?: boolean
|
||||
is_org_shared?: boolean
|
||||
num_members?: number
|
||||
topic?: string
|
||||
purpose?: string
|
||||
created?: number
|
||||
creator?: string
|
||||
updated?: number
|
||||
}
|
||||
|
||||
export interface SlackListChannelsResponse extends ToolResponse {
|
||||
@@ -875,6 +904,35 @@ export interface SlackGetThreadResponse extends ToolResponse {
|
||||
}
|
||||
}
|
||||
|
||||
export interface SlackGetChannelInfoResponse extends ToolResponse {
|
||||
output: {
|
||||
channelInfo: SlackChannel
|
||||
}
|
||||
}
|
||||
|
||||
export interface SlackGetUserPresenceResponse extends ToolResponse {
|
||||
output: {
|
||||
presence: string
|
||||
online?: boolean | null
|
||||
autoAway?: boolean | null
|
||||
manualAway?: boolean | null
|
||||
connectionCount?: number | null
|
||||
lastActivity?: number | null
|
||||
}
|
||||
}
|
||||
|
||||
export interface SlackEditCanvasResponse extends ToolResponse {
|
||||
output: {
|
||||
content: string
|
||||
}
|
||||
}
|
||||
|
||||
export interface SlackCreateChannelCanvasResponse extends ToolResponse {
|
||||
output: {
|
||||
canvas_id: string
|
||||
}
|
||||
}
|
||||
|
||||
export type SlackResponse =
|
||||
| SlackCanvasResponse
|
||||
| SlackMessageReaderResponse
|
||||
@@ -891,3 +949,7 @@ export type SlackResponse =
|
||||
| SlackEphemeralMessageResponse
|
||||
| SlackGetMessageResponse
|
||||
| SlackGetThreadResponse
|
||||
| SlackGetChannelInfoResponse
|
||||
| SlackGetUserPresenceResponse
|
||||
| SlackEditCanvasResponse
|
||||
| SlackCreateChannelCanvasResponse
|
||||
|
||||
Reference in New Issue
Block a user