diff --git a/apps/docs/content/docs/en/tools/slack.mdx b/apps/docs/content/docs/en/tools/slack.mdx index 46b5a66d8e..3054a9a4b3 100644 --- a/apps/docs/content/docs/en/tools/slack.mdx +++ b/apps/docs/content/docs/en/tools/slack.mdx @@ -73,8 +73,10 @@ Send messages to Slack channels or users through the Slack API. Supports Slack m | Parameter | Type | Description | | --------- | ---- | ----------- | +| `message` | object | Complete message object with all properties returned by Slack | | `ts` | string | Message timestamp | | `channel` | string | Channel ID where message was sent | +| `fileCount` | number | Number of files uploaded \(when files are attached\) | ### `slack_canvas` @@ -157,6 +159,7 @@ Update a message previously sent by the bot in Slack | Parameter | Type | Description | | --------- | ---- | ----------- | +| `message` | object | Complete updated message object with all properties returned by Slack | | `content` | string | Success message | | `metadata` | object | Updated message metadata | diff --git a/apps/sim/app/api/tools/slack/send-message/route.ts b/apps/sim/app/api/tools/slack/send-message/route.ts index 2470a685e5..a9f3b5f34c 100644 --- a/apps/sim/app/api/tools/slack/send-message/route.ts +++ b/apps/sim/app/api/tools/slack/send-message/route.ts @@ -78,9 +78,16 @@ export async function POST(request: NextRequest) { } logger.info(`[${requestId}] Message sent successfully`) + const messageObj = data.message || { + type: 'message', + ts: data.ts, + text: validatedData.text, + channel: data.channel, + } return NextResponse.json({ success: true, output: { + message: messageObj, ts: data.ts, channel: data.channel, }, @@ -107,9 +114,16 @@ export async function POST(request: NextRequest) { }) const data = await response.json() + const messageObj = data.message || { + type: 'message', + ts: data.ts, + text: validatedData.text, + channel: data.channel, + } return NextResponse.json({ success: true, output: { + message: messageObj, ts: data.ts, channel: data.channel, }, @@ -174,9 +188,16 @@ export async function POST(request: NextRequest) { }) const data = await response.json() + const messageObj = data.message || { + type: 'message', + ts: data.ts, + text: validatedData.text, + channel: data.channel, + } return NextResponse.json({ success: true, output: { + message: messageObj, ts: data.ts, channel: data.channel, }, @@ -211,10 +232,28 @@ export async function POST(request: NextRequest) { logger.info(`[${requestId}] Files uploaded and shared successfully`) + // For file uploads, construct a message object + const fileTs = completeData.files?.[0]?.created?.toString() || (Date.now() / 1000).toString() + const fileMessage = { + type: 'message', + ts: fileTs, + text: validatedData.text, + channel: validatedData.channel, + files: completeData.files?.map((file: any) => ({ + id: file?.id, + name: file?.name, + mimetype: file?.mimetype, + size: file?.size, + url_private: file?.url_private, + permalink: file?.permalink, + })), + } + return NextResponse.json({ success: true, output: { - ts: completeData.files?.[0]?.created || Date.now() / 1000, + message: fileMessage, + ts: fileTs, channel: validatedData.channel, fileCount: uploadedFileIds.length, }, diff --git a/apps/sim/app/api/tools/slack/update-message/route.ts b/apps/sim/app/api/tools/slack/update-message/route.ts index 2056113940..7eaab100ee 100644 --- a/apps/sim/app/api/tools/slack/update-message/route.ts +++ b/apps/sim/app/api/tools/slack/update-message/route.ts @@ -78,14 +78,22 @@ export async function POST(request: NextRequest) { timestamp: data.ts, }) + const messageObj = data.message || { + type: 'message', + ts: data.ts, + text: data.text || validatedData.text, + channel: data.channel, + } + return NextResponse.json({ success: true, output: { + message: messageObj, content: 'Message updated successfully', metadata: { channel: data.channel, timestamp: data.ts, - text: data.text, + text: data.text || validatedData.text, }, }, }) diff --git a/apps/sim/blocks/blocks/slack.ts b/apps/sim/blocks/blocks/slack.ts index c0ff5dadfc..8bdb7ac118 100644 --- a/apps/sim/blocks/blocks/slack.ts +++ b/apps/sim/blocks/blocks/slack.ts @@ -464,18 +464,29 @@ export const SlackBlock: BlockConfig = { thread_ts: { type: 'string', description: 'Thread timestamp for reply' }, }, outputs: { - // slack_message outputs + // slack_message outputs (send operation) + message: { + type: 'json', + description: + 'Complete message object with all properties: ts, text, user, channel, reactions, threads, files, attachments, blocks, stars, pins, and edit history', + }, + // Legacy properties for send operation (backward compatibility) ts: { type: 'string', description: 'Message timestamp returned by Slack API' }, channel: { type: 'string', description: 'Channel identifier where message was sent' }, + fileCount: { + type: 'number', + description: 'Number of files uploaded (when files are attached)', + }, // slack_canvas outputs canvas_id: { type: 'string', description: 'Canvas identifier for created canvases' }, title: { type: 'string', description: 'Canvas title' }, - // slack_message_reader outputs + // slack_message_reader outputs (read operation) messages: { type: 'json', - description: 'Array of message objects with text, user, timestamp, and file attachments', + description: + 'Array of message objects with comprehensive properties: text, user, timestamp, reactions, threads, files, attachments, blocks, stars, pins, and edit history', }, // slack_download outputs @@ -484,6 +495,13 @@ export const SlackBlock: BlockConfig = { description: 'Downloaded file stored in execution files', }, + // slack_update_message outputs (update operation) + content: { type: 'string', description: 'Success message for update operation' }, + metadata: { + type: 'json', + description: 'Updated message metadata (legacy, use message object instead)', + }, + // 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' }, diff --git a/apps/sim/tools/slack/message.ts b/apps/sim/tools/slack/message.ts index 049fed37ff..55d92bd874 100644 --- a/apps/sim/tools/slack/message.ts +++ b/apps/sim/tools/slack/message.ts @@ -87,7 +87,16 @@ export const slackMessageTool: ToolConfig ({ + // Core properties + type: message.type || 'message', ts: message.ts, text: message.text || '', - user: message.user || message.bot_id || 'unknown', - type: message.type || 'message', + user: message.user, + bot_id: message.bot_id, + username: message.username, + channel: message.channel, + team: message.team, + + // Thread properties + thread_ts: message.thread_ts, + parent_user_id: message.parent_user_id, + reply_count: message.reply_count, + reply_users_count: message.reply_users_count, + latest_reply: message.latest_reply, + subscribed: message.subscribed, + last_read: message.last_read, + unread_count: message.unread_count, + + // Message subtype subtype: message.subtype, + + // Reactions and interactions + reactions: message.reactions?.map((reaction: any) => ({ + name: reaction.name, + count: reaction.count, + users: reaction.users || [], + })), + is_starred: message.is_starred, + pinned_to: message.pinned_to, + + // Content attachments files: message.files?.map((file: any) => ({ id: file.id, name: file.name, mimetype: file.mimetype, size: file.size, url_private: file.url_private, + permalink: file.permalink, + mode: file.mode, })), + attachments: message.attachments, + blocks: message.blocks, + + // Metadata + edited: message.edited + ? { + user: message.edited.user, + ts: message.edited.ts, + } + : undefined, + permalink: message.permalink, })) return { @@ -118,24 +159,91 @@ export const slackMessageReaderTool: ToolConfig< items: { type: 'object', properties: { - ts: { type: 'string' }, - text: { type: 'string' }, - user: { type: 'string' }, - type: { type: 'string' }, - subtype: { type: 'string' }, + // Core properties + type: { type: 'string', description: 'Message type' }, + ts: { type: 'string', description: 'Message timestamp' }, + text: { type: 'string', description: 'Message text content' }, + user: { type: 'string', description: 'User ID who sent the message' }, + bot_id: { type: 'string', description: 'Bot ID if sent by a bot' }, + username: { type: 'string', description: 'Display username' }, + channel: { type: 'string', description: 'Channel ID' }, + team: { type: 'string', description: 'Team ID' }, + + // Thread properties + thread_ts: { type: 'string', description: 'Thread parent message timestamp' }, + parent_user_id: { type: 'string', description: 'User ID of thread parent' }, + reply_count: { type: 'number', description: 'Number of thread replies' }, + reply_users_count: { type: 'number', description: 'Number of users who replied' }, + latest_reply: { type: 'string', description: 'Timestamp of latest reply' }, + subscribed: { type: 'boolean', description: 'Whether user is subscribed to thread' }, + last_read: { type: 'string', description: 'Last read timestamp' }, + unread_count: { type: 'number', description: 'Number of unread messages' }, + + // Message subtype + subtype: { type: 'string', description: 'Message subtype' }, + + // Reactions and interactions + reactions: { + type: 'array', + description: 'Array of reactions on this message', + items: { + type: 'object', + properties: { + name: { type: 'string', description: 'Emoji name' }, + count: { type: 'number', description: 'Number of reactions' }, + users: { + type: 'array', + description: 'Array of user IDs who reacted', + items: { type: 'string' }, + }, + }, + }, + }, + is_starred: { type: 'boolean', description: 'Whether message is starred' }, + pinned_to: { + type: 'array', + description: 'Array of channel IDs where message is pinned', + items: { type: 'string' }, + }, + + // Content attachments files: { type: 'array', + description: 'Array of files attached to message', items: { type: 'object', properties: { - id: { type: 'string' }, - name: { type: 'string' }, - mimetype: { type: 'string' }, - size: { type: 'number' }, - url_private: { type: 'string' }, + id: { type: 'string', description: 'File ID' }, + name: { type: 'string', description: 'File name' }, + mimetype: { type: 'string', description: 'MIME type' }, + size: { type: 'number', description: 'File size in bytes' }, + url_private: { type: 'string', description: 'Private download URL' }, + permalink: { type: 'string', description: 'Permanent link to file' }, + mode: { type: 'string', description: 'File mode' }, }, }, }, + attachments: { + type: 'array', + description: 'Array of legacy attachments', + items: { type: 'object' }, + }, + blocks: { + type: 'array', + description: 'Array of Block Kit blocks', + items: { type: 'object' }, + }, + + // Metadata + edited: { + type: 'object', + description: 'Edit information if message was edited', + properties: { + user: { type: 'string', description: 'User ID who edited' }, + ts: { type: 'string', description: 'Edit timestamp' }, + }, + }, + permalink: { type: 'string', description: 'Permanent link to message' }, }, }, }, diff --git a/apps/sim/tools/slack/types.ts b/apps/sim/tools/slack/types.ts index a5bdbef5dd..4737f49639 100644 --- a/apps/sim/tools/slack/types.ts +++ b/apps/sim/tools/slack/types.ts @@ -51,8 +51,12 @@ export interface SlackAddReactionParams extends SlackBaseParams { export interface SlackMessageResponse extends ToolResponse { output: { + // Legacy properties for backward compatibility ts: string channel: string + fileCount?: number + // New comprehensive message object + message: SlackMessage } } @@ -64,22 +68,96 @@ export interface SlackCanvasResponse extends ToolResponse { } } +export interface SlackReaction { + name: string + count: number + users: string[] +} + +export interface SlackMessageEdited { + user: string + ts: string +} + +export interface SlackAttachment { + id?: number + fallback?: string + text?: string + pretext?: string + color?: string + fields?: Array<{ + title: string + value: string + short?: boolean + }> + author_name?: string + author_link?: string + author_icon?: string + title?: string + title_link?: string + image_url?: string + thumb_url?: string + footer?: string + footer_icon?: string + ts?: string +} + +export interface SlackBlock { + type: string + block_id?: string + [key: string]: any // Blocks can have various properties depending on type +} + +export interface SlackMessage { + // Core properties + type: string + ts: string + text: string + user?: string + bot_id?: string + username?: string + channel?: string + team?: string + + // Thread properties + thread_ts?: string + parent_user_id?: string + reply_count?: number + reply_users_count?: number + latest_reply?: string + subscribed?: boolean + last_read?: string + unread_count?: number + + // Message subtype + subtype?: string + + // Reactions and interactions + reactions?: SlackReaction[] + is_starred?: boolean + pinned_to?: string[] + + // Content attachments + files?: Array<{ + id: string + name: string + mimetype: string + size: number + url_private?: string + permalink?: string + mode?: string + }> + attachments?: SlackAttachment[] + blocks?: SlackBlock[] + + // Metadata + edited?: SlackMessageEdited + permalink?: string +} + export interface SlackMessageReaderResponse extends ToolResponse { output: { - messages: Array<{ - ts: string - text: string - user: string - type: string - subtype?: string - files?: Array<{ - id: string - name: string - mimetype: string - size: number - url_private?: string - }> - }> + messages: SlackMessage[] } } @@ -96,12 +174,15 @@ export interface SlackDownloadResponse extends ToolResponse { export interface SlackUpdateMessageResponse extends ToolResponse { output: { + // Legacy properties for backward compatibility content: string metadata: { channel: string timestamp: string text: string } + // New comprehensive message object + message: SlackMessage } } diff --git a/apps/sim/tools/slack/update_message.ts b/apps/sim/tools/slack/update_message.ts index c262878d08..27f197a36e 100644 --- a/apps/sim/tools/slack/update_message.ts +++ b/apps/sim/tools/slack/update_message.ts @@ -72,30 +72,21 @@ export const slackUpdateMessageTool: ToolConfig< const data = await response.json() if (!data.success) { - return { - success: false, - output: { - content: data.error || 'Failed to update message', - metadata: { - channel: '', - timestamp: '', - text: '', - }, - }, - error: data.error, - } + throw new Error(data.error || 'Failed to update message') } return { success: true, - output: { - content: data.output.content, - metadata: data.output.metadata, - }, + output: data.output, } }, outputs: { + message: { + type: 'object', + description: 'Complete updated message object with all properties returned by Slack', + }, + // Legacy properties for backward compatibility content: { type: 'string', description: 'Success message' }, metadata: { type: 'object',