diff --git a/blocks/blocks/slack.ts b/blocks/blocks/slack.ts new file mode 100644 index 000000000..9e031a7cc --- /dev/null +++ b/blocks/blocks/slack.ts @@ -0,0 +1,57 @@ +import { SlackIcon } from '@/components/icons' +import { BlockConfig } from '../types' +import { SlackMessageResponse } from '@/tools/slack/message' + +export const SlackMessageBlock: BlockConfig = { + type: 'slack_message', + toolbar: { + title: 'Slack Message', + description: 'Send a message to Slack', + bgColor: '#611f69', + icon: SlackIcon, + category: 'advanced' + }, + tools: { + access: ['slack.message'] + }, + workflow: { + inputs: { + apiKey: { type: 'string', required: true }, + channel: { type: 'string', required: true }, + text: { type: 'string', required: true } + }, + outputs: { + response: { + type: { + ts: 'string', + channel: 'string' + } + } + }, + subBlocks: [ + { + id: 'apiKey', + title: 'OAuth Token', + type: 'short-input', + layout: 'full', + placeholder: 'Enter your Slack OAuth token', + password: true, + connectionDroppable: false + }, + { + id: 'channel', + title: 'Channel', + type: 'short-input', + layout: 'full', + placeholder: 'Enter Slack channel (e.g., #general)' + }, + { + id: 'text', + title: 'Message', + type: 'long-input', + layout: 'full', + placeholder: 'Enter your alert message' + } + ] + } +} \ No newline at end of file diff --git a/blocks/index.ts b/blocks/index.ts index f77948c50..9e51dd2f1 100644 --- a/blocks/index.ts +++ b/blocks/index.ts @@ -8,6 +8,7 @@ import { CrewAIVisionBlock } from './blocks/crewai' import { FirecrawlScrapeBlock } from './blocks/firecrawl' import { JinaBlock } from './blocks/jina' import { TranslateBlock } from './blocks/translate' +import { SlackMessageBlock } from './blocks/slack' // Export blocks for ease of use export { @@ -17,7 +18,8 @@ export { CrewAIVisionBlock, FirecrawlScrapeBlock, JinaBlock, - TranslateBlock + TranslateBlock, + SlackMessageBlock } // Registry of all block configurations @@ -28,7 +30,8 @@ const blocks: Record = { crewai_vision: CrewAIVisionBlock, firecrawl_scrape: FirecrawlScrapeBlock, jina_reader: JinaBlock, - translate: TranslateBlock + translate: TranslateBlock, + slack_message: SlackMessageBlock } // Build a reverse mapping of tools to block types diff --git a/components/icons.tsx b/components/icons.tsx index c5f4c8a0d..006667036 100644 --- a/components/icons.tsx +++ b/components/icons.tsx @@ -978,3 +978,18 @@ export const TranslateIcon = (props: SVGProps) => ( ) +export const SlackIcon = (props: SVGProps) => ( + + + + + + + + +) + diff --git a/tools/index.ts b/tools/index.ts index 6aa254eb5..b3d93d156 100644 --- a/tools/index.ts +++ b/tools/index.ts @@ -12,6 +12,8 @@ import { functionExecuteTool as functionExecute } from './function/execute' import { visionTool as crewAIVision } from './crewai/vision' import { scrapeTool } from './firecrawl/scrape' import { readUrlTool } from './jina/reader' +import { slackMessageTool } from './slack/message' + // Registry of all available tools export const tools: Record = { // AI Models @@ -33,7 +35,9 @@ export const tools: Record = { // Firecrawl Tools 'firecrawl.scrape': scrapeTool, // Jina Tools - 'jina.readurl': readUrlTool + 'jina.readurl': readUrlTool, + // Slack Tools + 'slack.message': slackMessageTool } // Get a tool by its ID diff --git a/tools/slack/message.ts b/tools/slack/message.ts new file mode 100644 index 000000000..0d838d370 --- /dev/null +++ b/tools/slack/message.ts @@ -0,0 +1,71 @@ +import { ToolConfig, ToolResponse } from '../types' + +export interface SlackMessageParams { + apiKey: string + channel: string + text: string +} + +export interface SlackMessageResponse extends ToolResponse { + output: { + ts: string + channel: string + } +} + +export const slackMessageTool: ToolConfig = { + id: 'slack.message', + name: 'Slack Message', + description: 'Send a message to a Slack channel', + version: '1.0.0', + + params: { + apiKey: { + type: 'string', + required: true, + description: 'Your Slack API token' + }, + channel: { + type: 'string', + required: true, + description: 'Target Slack channel (e.g., #general)' + }, + text: { + type: 'string', + required: true, + description: 'Message text to send' + } + }, + + request: { + url: 'https://slack.com/api/chat.postMessage', + method: 'POST', + headers: (params: SlackMessageParams) => ({ + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${params.apiKey}` + }), + body: (params: SlackMessageParams) => ({ + channel: params.channel, + text: params.text + }) + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + if (!data.ok) { + throw new Error(data.error || 'Slack API error') + } + return { + success: true, + output: { + ts: data.ts, + channel: data.channel + } + } + }, + + transformError: (error: any) => { + const message = error.message || 'Slack message failed' + return message + } +}