diff --git a/apps/sim/blocks/blocks/discord.ts b/apps/sim/blocks/blocks/discord.ts index 074041e2f01..82c90160505 100644 --- a/apps/sim/blocks/blocks/discord.ts +++ b/apps/sim/blocks/blocks/discord.ts @@ -29,10 +29,12 @@ export const DiscordBlock: BlockConfig = { { label: 'Get User Information', id: 'discord_get_user' }, { label: 'Edit Message', id: 'discord_edit_message' }, { label: 'Delete Message', id: 'discord_delete_message' }, + { label: 'Bulk Delete Messages', id: 'discord_bulk_delete_messages' }, { label: 'Add Reaction', id: 'discord_add_reaction' }, { label: 'Remove Reaction', id: 'discord_remove_reaction' }, { label: 'Pin Message', id: 'discord_pin_message' }, { label: 'Unpin Message', id: 'discord_unpin_message' }, + { label: 'Get Pinned Messages', id: 'discord_get_pinned_messages' }, { label: 'Create Thread', id: 'discord_create_thread' }, { label: 'Join Thread', id: 'discord_join_thread' }, { label: 'Leave Thread', id: 'discord_leave_thread' }, @@ -41,11 +43,13 @@ export const DiscordBlock: BlockConfig = { { label: 'Update Channel', id: 'discord_update_channel' }, { label: 'Delete Channel', id: 'discord_delete_channel' }, { label: 'Get Channel', id: 'discord_get_channel' }, + { label: 'List Channels', id: 'discord_list_channels' }, { label: 'Create Role', id: 'discord_create_role' }, { label: 'Update Role', id: 'discord_update_role' }, { label: 'Delete Role', id: 'discord_delete_role' }, { label: 'Assign Role', id: 'discord_assign_role' }, { label: 'Remove Role', id: 'discord_remove_role' }, + { label: 'List Roles', id: 'discord_list_roles' }, { label: 'Kick Member', id: 'discord_kick_member' }, { label: 'Ban Member', id: 'discord_ban_member' }, { label: 'Unban Member', id: 'discord_unban_member' }, @@ -92,10 +96,12 @@ export const DiscordBlock: BlockConfig = { 'discord_get_messages', 'discord_edit_message', 'discord_delete_message', + 'discord_bulk_delete_messages', 'discord_add_reaction', 'discord_remove_reaction', 'discord_pin_message', 'discord_unpin_message', + 'discord_get_pinned_messages', 'discord_create_thread', 'discord_update_channel', 'discord_delete_channel', @@ -121,10 +127,35 @@ export const DiscordBlock: BlockConfig = { 'discord_remove_reaction', 'discord_pin_message', 'discord_unpin_message', - 'discord_create_thread', ], }, }, + // Message ID (optional) - for creating a thread from an existing message + { + id: 'messageId', + title: 'Message ID', + type: 'short-input', + placeholder: 'Enter message ID (leave empty for a standalone thread)', + condition: { + field: 'operation', + value: ['discord_create_thread'], + }, + }, + // Message IDs - for bulk delete + { + id: 'messageIds', + title: 'Message IDs', + type: 'long-input', + placeholder: 'Comma-separated message IDs to delete (2-100)', + required: true, + condition: { field: 'operation', value: 'discord_bulk_delete_messages' }, + wandConfig: { + enabled: true, + prompt: + 'Generate a comma-separated list of Discord message IDs (2-100 numeric snowflake IDs) based on the context: {context}. Return ONLY the comma-separated list - no explanations, no extra text.', + placeholder: 'Describe which messages to delete', + }, + }, // Content - for send/edit message { id: 'content', @@ -133,7 +164,19 @@ export const DiscordBlock: BlockConfig = { placeholder: 'Enter message content...', condition: { field: 'operation', - value: ['discord_send_message', 'discord_edit_message', 'discord_execute_webhook'], + value: ['discord_send_message', 'discord_edit_message'], + }, + }, + // Content (required) - for executing a webhook + { + id: 'content', + title: 'Message Content', + type: 'long-input', + placeholder: 'Enter message content...', + required: true, + condition: { + field: 'operation', + value: ['discord_execute_webhook'], }, }, // Emoji - for reaction operations @@ -141,24 +184,24 @@ export const DiscordBlock: BlockConfig = { id: 'emoji', title: 'Emoji', type: 'short-input', - placeholder: 'Enter emoji (e.g., 👍 or custom:123456789)', + placeholder: 'Enter emoji (e.g., 👍 or emoji_name:123456789012345678 for custom emoji)', required: true, condition: { field: 'operation', value: ['discord_add_reaction', 'discord_remove_reaction'], }, }, - // User ID - for user/member operations + // User ID (required) - for user/member operations { id: 'userId', title: 'User ID', type: 'short-input', placeholder: 'Enter Discord user ID', + required: true, condition: { field: 'operation', value: [ 'discord_get_user', - 'discord_remove_reaction', 'discord_assign_role', 'discord_remove_role', 'discord_kick_member', @@ -169,6 +212,17 @@ export const DiscordBlock: BlockConfig = { ], }, }, + // User ID (optional) - to remove a specific user's reaction + { + id: 'userId', + title: 'User ID', + type: 'short-input', + placeholder: 'Enter Discord user ID (leave empty to remove your own reaction)', + condition: { + field: 'operation', + value: ['discord_remove_reaction'], + }, + }, // Thread ID - for thread operations { id: 'threadId', @@ -329,6 +383,24 @@ export const DiscordBlock: BlockConfig = { placeholder: 'Number of messages (default: 10, max: 100)', condition: { field: 'operation', value: 'discord_get_messages' }, }, + // Limit (for get pinned messages) + { + id: 'limit', + title: 'Pin Limit', + type: 'short-input', + placeholder: 'Number of pins per page (default: 50, max: 50)', + mode: 'advanced', + condition: { field: 'operation', value: 'discord_get_pinned_messages' }, + }, + // Before (pagination cursor for get pinned messages) + { + id: 'before', + title: 'Before', + type: 'short-input', + placeholder: 'Return pins before this ISO8601 timestamp (for paging)', + mode: 'advanced', + condition: { field: 'operation', value: 'discord_get_pinned_messages' }, + }, // Auto Archive Duration (for threads) { id: 'autoArchiveDuration', @@ -346,6 +418,22 @@ export const DiscordBlock: BlockConfig = { value: ['discord_create_thread'], }, }, + // Thread Visibility (for create_thread, standalone threads only) + { + id: 'threadVisibility', + title: 'Thread Visibility', + type: 'dropdown', + options: [ + { label: 'Public - visible to everyone in the channel', id: 'public' }, + { label: 'Private - invite-only', id: 'private' }, + ], + value: () => 'public', + mode: 'advanced', + condition: { + field: 'operation', + value: ['discord_create_thread'], + }, + }, // Channel Type (for create_channel) { id: 'channelType', @@ -354,6 +442,7 @@ export const DiscordBlock: BlockConfig = { options: [ { label: 'Text Channel', id: '0' }, { label: 'Voice Channel', id: '2' }, + { label: 'Category', id: '4' }, { label: 'Announcement Channel', id: '5' }, { label: 'Stage Channel', id: '13' }, { label: 'Forum Channel', id: '15' }, @@ -537,10 +626,12 @@ export const DiscordBlock: BlockConfig = { 'discord_get_user', 'discord_edit_message', 'discord_delete_message', + 'discord_bulk_delete_messages', 'discord_add_reaction', 'discord_remove_reaction', 'discord_pin_message', 'discord_unpin_message', + 'discord_get_pinned_messages', 'discord_create_thread', 'discord_join_thread', 'discord_leave_thread', @@ -549,11 +640,13 @@ export const DiscordBlock: BlockConfig = { 'discord_update_channel', 'discord_delete_channel', 'discord_get_channel', + 'discord_list_channels', 'discord_create_role', 'discord_update_role', 'discord_delete_role', 'discord_assign_role', 'discord_remove_role', + 'discord_list_roles', 'discord_kick_member', 'discord_ban_member', 'discord_unban_member', @@ -612,6 +705,22 @@ export const DiscordBlock: BlockConfig = { channelId: params.channelId, messageId: params.messageId, } + case 'discord_bulk_delete_messages': + return { + ...commonParams, + channelId: params.channelId, + messageIds: String(params.messageIds || '') + .split(',') + .map((id: string) => id.trim()) + .filter(Boolean), + } + case 'discord_get_pinned_messages': + return { + ...commonParams, + channelId: params.channelId, + ...(params.limit && { limit: Math.min(Math.max(1, Number(params.limit)), 50) }), + ...(params.before?.trim() && { before: params.before.trim() }), + } case 'discord_add_reaction': case 'discord_remove_reaction': return { @@ -619,7 +728,7 @@ export const DiscordBlock: BlockConfig = { channelId: params.channelId, messageId: params.messageId, emoji: params.emoji, - ...(params.userId && { userId: params.userId }), + ...(params.userId?.trim() && { userId: params.userId.trim() }), } case 'discord_pin_message': case 'discord_unpin_message': @@ -633,10 +742,13 @@ export const DiscordBlock: BlockConfig = { ...commonParams, channelId: params.channelId, name: params.name, - ...(params.messageId && { messageId: params.messageId }), + ...(params.messageId?.trim() && { messageId: params.messageId.trim() }), ...(params.autoArchiveDuration && { autoArchiveDuration: Number(params.autoArchiveDuration), }), + ...(params.threadVisibility !== undefined && { + isPublic: params.threadVisibility !== 'private', + }), } case 'discord_join_thread': case 'discord_leave_thread': @@ -665,6 +777,8 @@ export const DiscordBlock: BlockConfig = { case 'discord_delete_channel': case 'discord_get_channel': return { ...commonParams, channelId: params.channelId } + case 'discord_list_channels': + return commonParams case 'discord_create_role': return { ...commonParams, @@ -695,6 +809,8 @@ export const DiscordBlock: BlockConfig = { userId: params.userId, roleId: params.roleId, } + case 'discord_list_roles': + return commonParams case 'discord_kick_member': case 'discord_unban_member': return { @@ -708,7 +824,7 @@ export const DiscordBlock: BlockConfig = { userId: params.userId, ...(params.reason && { reason: params.reason }), ...(params.deleteMessageDays && { - deleteMessageDays: Number(params.deleteMessageDays), + deleteMessageSeconds: Number(params.deleteMessageDays) * 86400, }), } case 'discord_get_member': @@ -761,6 +877,10 @@ export const DiscordBlock: BlockConfig = { serverId: { type: 'string', description: 'Discord server identifier' }, channelId: { type: 'string', description: 'Discord channel identifier' }, messageId: { type: 'string', description: 'Discord message identifier' }, + messageIds: { + type: 'string', + description: 'Comma-separated message IDs to bulk delete (2-100)', + }, threadId: { type: 'string', description: 'Discord thread identifier' }, userId: { type: 'string', description: 'Discord user identifier' }, roleId: { type: 'string', description: 'Discord role identifier' }, @@ -777,7 +897,12 @@ export const DiscordBlock: BlockConfig = { archived: { type: 'string', description: 'Archive status (true/false)' }, files: { type: 'array', description: 'Files to attach (canonical param)' }, limit: { type: 'number', description: 'Message limit' }, + before: { type: 'string', description: 'Return pins before this ISO8601 timestamp' }, autoArchiveDuration: { type: 'number', description: 'Thread auto-archive duration in minutes' }, + threadVisibility: { + type: 'string', + description: 'Visibility for a new standalone thread (public/private)', + }, channelType: { type: 'number', description: 'Discord channel type (0=text, 2=voice, etc.)' }, parentId: { type: 'string', description: 'Parent category ID for channel' }, hoist: { type: 'boolean', description: 'Whether to display role members separately' }, diff --git a/apps/sim/lib/oauth/utils.ts b/apps/sim/lib/oauth/utils.ts index 17ff65e51fb..6d903a6cd1c 100644 --- a/apps/sim/lib/oauth/utils.ts +++ b/apps/sim/lib/oauth/utils.ts @@ -242,13 +242,6 @@ export const SCOPE_DESCRIPTIONS: Record = { 'GroupMember.ReadWrite.All': 'Read and write all group memberships', 'Directory.Read.All': 'Read directory data', - // Discord scopes - identify: 'Read Discord user', - bot: 'Read Discord bot', - 'messages.read': 'Read Discord messages', - guilds: 'Read Discord guilds', - 'guilds.members.read': 'Read Discord guild members', - // Reddit scopes identity: 'Access Reddit identity', submit: 'Submit posts and comments', diff --git a/apps/sim/tools/discord/add_reaction.ts b/apps/sim/tools/discord/add_reaction.ts index 7b7c5b88805..42afc9a7394 100644 --- a/apps/sim/tools/discord/add_reaction.ts +++ b/apps/sim/tools/discord/add_reaction.ts @@ -46,11 +46,11 @@ export const discordAddReactionTool: ToolConfig< request: { url: (params: DiscordAddReactionParams) => { const encodedEmoji = encodeURIComponent(params.emoji) - return `https://discord.com/api/v10/channels/${params.channelId}/messages/${params.messageId}/reactions/${encodedEmoji}/@me` + return `https://discord.com/api/v10/channels/${params.channelId.trim()}/messages/${params.messageId.trim()}/reactions/${encodedEmoji}/@me` }, method: 'PUT', headers: (params) => ({ - Authorization: `Bot ${params.botToken}`, + Authorization: `Bot ${params.botToken.trim()}`, }), }, diff --git a/apps/sim/tools/discord/archive_thread.ts b/apps/sim/tools/discord/archive_thread.ts index ae9c379a4fa..67f7b79e01a 100644 --- a/apps/sim/tools/discord/archive_thread.ts +++ b/apps/sim/tools/discord/archive_thread.ts @@ -42,12 +42,12 @@ export const discordArchiveThreadTool: ToolConfig< request: { url: (params: DiscordArchiveThreadParams) => { - return `https://discord.com/api/v10/channels/${params.threadId}` + return `https://discord.com/api/v10/channels/${params.threadId.trim()}` }, method: 'PATCH', headers: (params) => ({ 'Content-Type': 'application/json', - Authorization: `Bot ${params.botToken}`, + Authorization: `Bot ${params.botToken.trim()}`, }), body: (params: DiscordArchiveThreadParams) => { return { diff --git a/apps/sim/tools/discord/assign_role.ts b/apps/sim/tools/discord/assign_role.ts index c5d23634f0b..2fd161707b8 100644 --- a/apps/sim/tools/discord/assign_role.ts +++ b/apps/sim/tools/discord/assign_role.ts @@ -37,11 +37,11 @@ export const discordAssignRoleTool: ToolConfig { - return `https://discord.com/api/v10/guilds/${params.serverId}/members/${params.userId}/roles/${params.roleId}` + return `https://discord.com/api/v10/guilds/${params.serverId.trim()}/members/${params.userId.trim()}/roles/${params.roleId.trim()}` }, method: 'PUT', headers: (params) => ({ - Authorization: `Bot ${params.botToken}`, + Authorization: `Bot ${params.botToken.trim()}`, }), }, diff --git a/apps/sim/tools/discord/ban_member.ts b/apps/sim/tools/discord/ban_member.ts index 54a850e953c..e998f04cf28 100644 --- a/apps/sim/tools/discord/ban_member.ts +++ b/apps/sim/tools/discord/ban_member.ts @@ -32,23 +32,23 @@ export const discordBanMemberTool: ToolConfig { - return `https://discord.com/api/v10/guilds/${params.serverId}/bans/${params.userId}` + return `https://discord.com/api/v10/guilds/${params.serverId.trim()}/bans/${params.userId.trim()}` }, method: 'PUT', headers: (params) => { const headers: Record = { 'Content-Type': 'application/json', - Authorization: `Bot ${params.botToken}`, + Authorization: `Bot ${params.botToken.trim()}`, } if (params.reason) { headers['X-Audit-Log-Reason'] = encodeURIComponent(params.reason) @@ -57,8 +57,8 @@ export const discordBanMemberTool: ToolConfig { const body: any = {} - if (params.deleteMessageDays !== undefined) { - body.delete_message_days = Number(params.deleteMessageDays) + if (params.deleteMessageSeconds !== undefined) { + body.delete_message_seconds = Number(params.deleteMessageSeconds) } return body }, diff --git a/apps/sim/tools/discord/bulk_delete_messages.ts b/apps/sim/tools/discord/bulk_delete_messages.ts new file mode 100644 index 00000000000..e73065e3a6c --- /dev/null +++ b/apps/sim/tools/discord/bulk_delete_messages.ts @@ -0,0 +1,78 @@ +import type { + DiscordBulkDeleteMessagesParams, + DiscordBulkDeleteMessagesResponse, +} from '@/tools/discord/types' +import type { ToolConfig } from '@/tools/types' + +export const discordBulkDeleteMessagesTool: ToolConfig< + DiscordBulkDeleteMessagesParams, + DiscordBulkDeleteMessagesResponse +> = { + id: 'discord_bulk_delete_messages', + name: 'Discord Bulk Delete Messages', + description: 'Delete 2-100 messages from a Discord channel in a single request', + version: '1.0.0', + + params: { + botToken: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The bot token for authentication', + }, + channelId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Discord channel ID to delete messages from, e.g., 123456789012345678', + }, + messageIds: { + type: 'json', + required: true, + visibility: 'user-or-llm', + description: + 'Array of 2-100 message IDs to delete. Messages older than 2 weeks cannot be bulk deleted.', + }, + serverId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Discord server ID (guild ID), e.g., 123456789012345678', + }, + }, + + request: { + url: (params: DiscordBulkDeleteMessagesParams) => { + return `https://discord.com/api/v10/channels/${params.channelId.trim()}/messages/bulk-delete` + }, + method: 'POST', + headers: (params) => ({ + 'Content-Type': 'application/json', + Authorization: `Bot ${params.botToken.trim()}`, + }), + body: (params: DiscordBulkDeleteMessagesParams) => { + const messages = (Array.isArray(params.messageIds) ? params.messageIds : [params.messageIds]) + .map((id) => String(id).trim()) + .filter(Boolean) + if (messages.length < 2 || messages.length > 100) { + throw new Error( + `Discord requires 2-100 message IDs for bulk delete, got ${messages.length}` + ) + } + return { messages } + }, + }, + + transformResponse: async () => { + return { + success: true, + output: { + message: 'Messages deleted successfully', + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Success or error message' }, + }, +} diff --git a/apps/sim/tools/discord/create_channel.ts b/apps/sim/tools/discord/create_channel.ts index 98b217ba9af..40f8a6cd8b7 100644 --- a/apps/sim/tools/discord/create_channel.ts +++ b/apps/sim/tools/discord/create_channel.ts @@ -54,12 +54,12 @@ export const discordCreateChannelTool: ToolConfig< request: { url: (params: DiscordCreateChannelParams) => { - return `https://discord.com/api/v10/guilds/${params.serverId}/channels` + return `https://discord.com/api/v10/guilds/${params.serverId.trim()}/channels` }, method: 'POST', headers: (params) => ({ 'Content-Type': 'application/json', - Authorization: `Bot ${params.botToken}`, + Authorization: `Bot ${params.botToken.trim()}`, }), body: (params: DiscordCreateChannelParams) => { const body: any = { diff --git a/apps/sim/tools/discord/create_invite.ts b/apps/sim/tools/discord/create_invite.ts index ff1148f1e58..87b945322c3 100644 --- a/apps/sim/tools/discord/create_invite.ts +++ b/apps/sim/tools/discord/create_invite.ts @@ -51,12 +51,12 @@ export const discordCreateInviteTool: ToolConfig< request: { url: (params: DiscordCreateInviteParams) => { - return `https://discord.com/api/v10/channels/${params.channelId}/invites` + return `https://discord.com/api/v10/channels/${params.channelId.trim()}/invites` }, method: 'POST', headers: (params) => ({ 'Content-Type': 'application/json', - Authorization: `Bot ${params.botToken}`, + Authorization: `Bot ${params.botToken.trim()}`, }), body: (params: DiscordCreateInviteParams) => { const body: any = {} diff --git a/apps/sim/tools/discord/create_role.ts b/apps/sim/tools/discord/create_role.ts index 7a68dcdf11f..bbd558990af 100644 --- a/apps/sim/tools/discord/create_role.ts +++ b/apps/sim/tools/discord/create_role.ts @@ -49,12 +49,12 @@ export const discordCreateRoleTool: ToolConfig { - return `https://discord.com/api/v10/guilds/${params.serverId}/roles` + return `https://discord.com/api/v10/guilds/${params.serverId.trim()}/roles` }, method: 'POST', headers: (params) => ({ 'Content-Type': 'application/json', - Authorization: `Bot ${params.botToken}`, + Authorization: `Bot ${params.botToken.trim()}`, }), body: (params: DiscordCreateRoleParams) => { const body: any = { diff --git a/apps/sim/tools/discord/create_thread.ts b/apps/sim/tools/discord/create_thread.ts index 51ecfa24677..b69fd5318a0 100644 --- a/apps/sim/tools/discord/create_thread.ts +++ b/apps/sim/tools/discord/create_thread.ts @@ -42,6 +42,13 @@ export const discordCreateThreadTool: ToolConfig< visibility: 'user-or-llm', description: 'Duration in minutes to auto-archive the thread (60, 1440, 4320, 10080)', }, + isPublic: { + type: 'boolean', + required: false, + visibility: 'user-or-llm', + description: + 'Whether the standalone thread is public (visible to everyone in the channel) or private. Ignored when creating a thread from an existing message, which always inherits the parent channel visibility. Defaults to public if omitted.', + }, serverId: { type: 'string', required: true, @@ -52,15 +59,16 @@ export const discordCreateThreadTool: ToolConfig< request: { url: (params: DiscordCreateThreadParams) => { - if (params.messageId) { - return `https://discord.com/api/v10/channels/${params.channelId}/messages/${params.messageId}/threads` + const messageId = params.messageId?.trim() + if (messageId) { + return `https://discord.com/api/v10/channels/${params.channelId.trim()}/messages/${messageId}/threads` } - return `https://discord.com/api/v10/channels/${params.channelId}/threads` + return `https://discord.com/api/v10/channels/${params.channelId.trim()}/threads` }, method: 'POST', headers: (params) => ({ 'Content-Type': 'application/json', - Authorization: `Bot ${params.botToken}`, + Authorization: `Bot ${params.botToken.trim()}`, }), body: (params: DiscordCreateThreadParams) => { const body: any = { @@ -69,6 +77,11 @@ export const discordCreateThreadTool: ToolConfig< if (params.autoArchiveDuration) { body.auto_archive_duration = Number(params.autoArchiveDuration) } + // Standalone threads (no source message) default to PRIVATE_THREAD per the Discord API + // unless `type` is explicitly set, so pin it to PUBLIC_THREAD (11) unless the caller opts out. + if (!params.messageId?.trim()) { + body.type = params.isPublic === false ? 12 : 11 + } return body }, }, diff --git a/apps/sim/tools/discord/create_webhook.ts b/apps/sim/tools/discord/create_webhook.ts index fb006adcd64..c0920debff3 100644 --- a/apps/sim/tools/discord/create_webhook.ts +++ b/apps/sim/tools/discord/create_webhook.ts @@ -42,12 +42,12 @@ export const discordCreateWebhookTool: ToolConfig< request: { url: (params: DiscordCreateWebhookParams) => { - return `https://discord.com/api/v10/channels/${params.channelId}/webhooks` + return `https://discord.com/api/v10/channels/${params.channelId.trim()}/webhooks` }, method: 'POST', headers: (params) => ({ 'Content-Type': 'application/json', - Authorization: `Bot ${params.botToken}`, + Authorization: `Bot ${params.botToken.trim()}`, }), body: (params: DiscordCreateWebhookParams) => { return { diff --git a/apps/sim/tools/discord/delete_channel.ts b/apps/sim/tools/discord/delete_channel.ts index a4204b2d4fc..914e1f09096 100644 --- a/apps/sim/tools/discord/delete_channel.ts +++ b/apps/sim/tools/discord/delete_channel.ts @@ -36,24 +36,36 @@ export const discordDeleteChannelTool: ToolConfig< request: { url: (params: DiscordDeleteChannelParams) => { - return `https://discord.com/api/v10/channels/${params.channelId}` + return `https://discord.com/api/v10/channels/${params.channelId.trim()}` }, method: 'DELETE', headers: (params) => ({ - Authorization: `Bot ${params.botToken}`, + Authorization: `Bot ${params.botToken.trim()}`, }), }, transformResponse: async (response) => { + const data = await response.json() return { success: true, output: { message: 'Channel deleted successfully', + data, }, } }, outputs: { message: { type: 'string', description: 'Success or error message' }, + data: { + type: 'object', + description: 'The deleted channel, as returned by Discord', + properties: { + id: { type: 'string', description: 'Channel ID' }, + name: { type: 'string', description: 'Channel name' }, + type: { type: 'number', description: 'Channel type' }, + guild_id: { type: 'string', description: 'Server ID' }, + }, + }, }, } diff --git a/apps/sim/tools/discord/delete_invite.ts b/apps/sim/tools/discord/delete_invite.ts index fb86e3612bd..f58be5d5390 100644 --- a/apps/sim/tools/discord/delete_invite.ts +++ b/apps/sim/tools/discord/delete_invite.ts @@ -33,11 +33,11 @@ export const discordDeleteInviteTool: ToolConfig< request: { url: (params: DiscordDeleteInviteParams) => { - return `https://discord.com/api/v10/invites/${params.inviteCode}` + return `https://discord.com/api/v10/invites/${params.inviteCode.trim()}` }, method: 'DELETE', headers: (params) => ({ - Authorization: `Bot ${params.botToken}`, + Authorization: `Bot ${params.botToken.trim()}`, }), }, diff --git a/apps/sim/tools/discord/delete_message.ts b/apps/sim/tools/discord/delete_message.ts index 32e1afec1ef..551335b34e4 100644 --- a/apps/sim/tools/discord/delete_message.ts +++ b/apps/sim/tools/discord/delete_message.ts @@ -42,11 +42,11 @@ export const discordDeleteMessageTool: ToolConfig< request: { url: (params: DiscordDeleteMessageParams) => { - return `https://discord.com/api/v10/channels/${params.channelId}/messages/${params.messageId}` + return `https://discord.com/api/v10/channels/${params.channelId.trim()}/messages/${params.messageId.trim()}` }, method: 'DELETE', headers: (params) => ({ - Authorization: `Bot ${params.botToken}`, + Authorization: `Bot ${params.botToken.trim()}`, }), }, diff --git a/apps/sim/tools/discord/delete_role.ts b/apps/sim/tools/discord/delete_role.ts index 28dc63010af..83b1c190abc 100644 --- a/apps/sim/tools/discord/delete_role.ts +++ b/apps/sim/tools/discord/delete_role.ts @@ -31,11 +31,11 @@ export const discordDeleteRoleTool: ToolConfig { - return `https://discord.com/api/v10/guilds/${params.serverId}/roles/${params.roleId}` + return `https://discord.com/api/v10/guilds/${params.serverId.trim()}/roles/${params.roleId.trim()}` }, method: 'DELETE', headers: (params) => ({ - Authorization: `Bot ${params.botToken}`, + Authorization: `Bot ${params.botToken.trim()}`, }), }, diff --git a/apps/sim/tools/discord/delete_webhook.ts b/apps/sim/tools/discord/delete_webhook.ts index a1d33994cc2..0b5169999cd 100644 --- a/apps/sim/tools/discord/delete_webhook.ts +++ b/apps/sim/tools/discord/delete_webhook.ts @@ -36,11 +36,11 @@ export const discordDeleteWebhookTool: ToolConfig< request: { url: (params: DiscordDeleteWebhookParams) => { - return `https://discord.com/api/v10/webhooks/${params.webhookId}` + return `https://discord.com/api/v10/webhooks/${params.webhookId.trim()}` }, method: 'DELETE', headers: (params) => ({ - Authorization: `Bot ${params.botToken}`, + Authorization: `Bot ${params.botToken.trim()}`, }), }, diff --git a/apps/sim/tools/discord/edit_message.ts b/apps/sim/tools/discord/edit_message.ts index 313023b02b8..82856f13f78 100644 --- a/apps/sim/tools/discord/edit_message.ts +++ b/apps/sim/tools/discord/edit_message.ts @@ -45,12 +45,12 @@ export const discordEditMessageTool: ToolConfig< request: { url: (params: DiscordEditMessageParams) => { - return `https://discord.com/api/v10/channels/${params.channelId}/messages/${params.messageId}` + return `https://discord.com/api/v10/channels/${params.channelId.trim()}/messages/${params.messageId.trim()}` }, method: 'PATCH', headers: (params) => ({ 'Content-Type': 'application/json', - Authorization: `Bot ${params.botToken}`, + Authorization: `Bot ${params.botToken.trim()}`, }), body: (params: DiscordEditMessageParams) => { const body: any = {} diff --git a/apps/sim/tools/discord/execute_webhook.ts b/apps/sim/tools/discord/execute_webhook.ts index 1e84301acd8..fefd16fa8f3 100644 --- a/apps/sim/tools/discord/execute_webhook.ts +++ b/apps/sim/tools/discord/execute_webhook.ts @@ -48,7 +48,7 @@ export const discordExecuteWebhookTool: ToolConfig< request: { url: (params: DiscordExecuteWebhookParams) => { - return `https://discord.com/api/v10/webhooks/${params.webhookId}/${params.webhookToken}?wait=true` + return `https://discord.com/api/v10/webhooks/${params.webhookId.trim()}/${params.webhookToken.trim()}?wait=true` }, method: 'POST', headers: () => ({ diff --git a/apps/sim/tools/discord/get_channel.ts b/apps/sim/tools/discord/get_channel.ts index 1815067c776..a7d19219006 100644 --- a/apps/sim/tools/discord/get_channel.ts +++ b/apps/sim/tools/discord/get_channel.ts @@ -31,11 +31,11 @@ export const discordGetChannelTool: ToolConfig { - return `https://discord.com/api/v10/channels/${params.channelId}` + return `https://discord.com/api/v10/channels/${params.channelId.trim()}` }, method: 'GET', headers: (params) => ({ - Authorization: `Bot ${params.botToken}`, + Authorization: `Bot ${params.botToken.trim()}`, }), }, diff --git a/apps/sim/tools/discord/get_invite.ts b/apps/sim/tools/discord/get_invite.ts index 27e0868174a..54efd3e78de 100644 --- a/apps/sim/tools/discord/get_invite.ts +++ b/apps/sim/tools/discord/get_invite.ts @@ -30,11 +30,11 @@ export const discordGetInviteTool: ToolConfig { - return `https://discord.com/api/v10/invites/${params.inviteCode}?with_counts=true` + return `https://discord.com/api/v10/invites/${params.inviteCode.trim()}?with_counts=true` }, method: 'GET', headers: (params) => ({ - Authorization: `Bot ${params.botToken}`, + Authorization: `Bot ${params.botToken.trim()}`, }), }, diff --git a/apps/sim/tools/discord/get_member.ts b/apps/sim/tools/discord/get_member.ts index f2b774c0f36..11c9a3bc1e3 100644 --- a/apps/sim/tools/discord/get_member.ts +++ b/apps/sim/tools/discord/get_member.ts @@ -30,11 +30,11 @@ export const discordGetMemberTool: ToolConfig { - return `https://discord.com/api/v10/guilds/${params.serverId}/members/${params.userId}` + return `https://discord.com/api/v10/guilds/${params.serverId.trim()}/members/${params.userId.trim()}` }, method: 'GET', headers: (params) => ({ - Authorization: `Bot ${params.botToken}`, + Authorization: `Bot ${params.botToken.trim()}`, }), }, diff --git a/apps/sim/tools/discord/get_messages.ts b/apps/sim/tools/discord/get_messages.ts index 98747d998c9..29c250df0d1 100644 --- a/apps/sim/tools/discord/get_messages.ts +++ b/apps/sim/tools/discord/get_messages.ts @@ -34,7 +34,7 @@ export const discordGetMessagesTool: ToolConfig< request: { url: (params: DiscordGetMessagesParams) => { const limit = params.limit ? Number(params.limit) : 10 - return `https://discord.com/api/v10/channels/${params.channelId}/messages?limit=${Math.min(limit, 100)}` + return `https://discord.com/api/v10/channels/${params.channelId.trim()}/messages?limit=${Math.min(limit, 100)}` }, method: 'GET', headers: (params) => { @@ -43,7 +43,7 @@ export const discordGetMessagesTool: ToolConfig< } if (params.botToken) { - headers.Authorization = `Bot ${params.botToken}` + headers.Authorization = `Bot ${params.botToken.trim()}` } return headers diff --git a/apps/sim/tools/discord/get_pinned_messages.ts b/apps/sim/tools/discord/get_pinned_messages.ts new file mode 100644 index 00000000000..f7737d77d73 --- /dev/null +++ b/apps/sim/tools/discord/get_pinned_messages.ts @@ -0,0 +1,102 @@ +import type { + DiscordGetPinnedMessagesParams, + DiscordGetPinnedMessagesResponse, + DiscordMessage, +} from '@/tools/discord/types' +import type { ToolConfig } from '@/tools/types' + +export const discordGetPinnedMessagesTool: ToolConfig< + DiscordGetPinnedMessagesParams, + DiscordGetPinnedMessagesResponse +> = { + id: 'discord_get_pinned_messages', + name: 'Discord Get Pinned Messages', + description: 'Retrieve all pinned messages in a Discord channel', + version: '1.0.0', + + params: { + botToken: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The bot token for authentication', + }, + channelId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: + 'The Discord channel ID to retrieve pinned messages from, e.g., 123456789012345678', + }, + limit: { + type: 'number', + required: false, + visibility: 'user-or-llm', + description: 'Maximum number of pins to return per page (1-50). Defaults to 50.', + }, + before: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: + 'Return pins created before this ISO8601 timestamp, for paging past the first 50 results', + }, + }, + + request: { + url: (params: DiscordGetPinnedMessagesParams) => { + const query = new URLSearchParams() + if (params.limit) query.set('limit', String(Math.min(Math.max(1, Number(params.limit)), 50))) + if (params.before) query.set('before', params.before) + const queryString = query.toString() + return `https://discord.com/api/v10/channels/${params.channelId.trim()}/messages/pins${queryString ? `?${queryString}` : ''}` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bot ${params.botToken.trim()}`, + }), + }, + + transformResponse: async (response) => { + const result = await response.json() + const items: Array<{ message: DiscordMessage; pinned_at: string }> = result.items ?? [] + return { + success: true, + output: { + message: `Retrieved ${items.length} pinned messages from Discord channel`, + data: items.map((item) => ({ ...item.message, pinned_at: item.pinned_at })), + hasMore: result.has_more ?? false, + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Success or error message' }, + data: { + type: 'array', + description: 'Array of pinned Discord messages', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Message ID' }, + content: { type: 'string', description: 'Message content' }, + channel_id: { type: 'string', description: 'Channel ID' }, + timestamp: { type: 'string', description: 'Message timestamp' }, + pinned_at: { type: 'string', description: 'When the message was pinned' }, + author: { + type: 'object', + description: 'Message author information', + properties: { + id: { type: 'string', description: 'Author user ID' }, + username: { type: 'string', description: 'Author username' }, + }, + }, + }, + }, + }, + hasMore: { + type: 'boolean', + description: 'Whether more pinned messages exist beyond this page', + }, + }, +} diff --git a/apps/sim/tools/discord/get_server.ts b/apps/sim/tools/discord/get_server.ts index f5f84e9a9bc..8e612654b86 100644 --- a/apps/sim/tools/discord/get_server.ts +++ b/apps/sim/tools/discord/get_server.ts @@ -28,7 +28,7 @@ export const discordGetServerTool: ToolConfig - `https://discord.com/api/v10/guilds/${params.serverId}`, + `https://discord.com/api/v10/guilds/${params.serverId.trim()}?with_counts=true`, method: 'GET', headers: (params: DiscordGetServerParams) => { const headers: Record = { @@ -36,7 +36,7 @@ export const discordGetServerTool: ToolConfig `https://discord.com/api/v10/users/${params.userId}`, + url: (params: DiscordGetUserParams) => + `https://discord.com/api/v10/users/${params.userId.trim()}`, method: 'GET', headers: (params: DiscordGetUserParams) => { const headers: Record = { @@ -35,7 +36,7 @@ export const discordGetUserTool: ToolConfig { - return `https://discord.com/api/v10/webhooks/${params.webhookId}` + return `https://discord.com/api/v10/webhooks/${params.webhookId.trim()}` }, method: 'GET', headers: (params) => ({ - Authorization: `Bot ${params.botToken}`, + Authorization: `Bot ${params.botToken.trim()}`, }), }, diff --git a/apps/sim/tools/discord/index.ts b/apps/sim/tools/discord/index.ts index b6d1615a150..7cac5217ba7 100644 --- a/apps/sim/tools/discord/index.ts +++ b/apps/sim/tools/discord/index.ts @@ -2,6 +2,7 @@ import { discordAddReactionTool } from '@/tools/discord/add_reaction' import { discordArchiveThreadTool } from '@/tools/discord/archive_thread' import { discordAssignRoleTool } from '@/tools/discord/assign_role' import { discordBanMemberTool } from '@/tools/discord/ban_member' +import { discordBulkDeleteMessagesTool } from '@/tools/discord/bulk_delete_messages' import { discordCreateChannelTool } from '@/tools/discord/create_channel' import { discordCreateInviteTool } from '@/tools/discord/create_invite' import { discordCreateRoleTool } from '@/tools/discord/create_role' @@ -18,12 +19,15 @@ import { discordGetChannelTool } from '@/tools/discord/get_channel' import { discordGetInviteTool } from '@/tools/discord/get_invite' import { discordGetMemberTool } from '@/tools/discord/get_member' import { discordGetMessagesTool } from '@/tools/discord/get_messages' +import { discordGetPinnedMessagesTool } from '@/tools/discord/get_pinned_messages' import { discordGetServerTool } from '@/tools/discord/get_server' import { discordGetUserTool } from '@/tools/discord/get_user' import { discordGetWebhookTool } from '@/tools/discord/get_webhook' import { discordJoinThreadTool } from '@/tools/discord/join_thread' import { discordKickMemberTool } from '@/tools/discord/kick_member' import { discordLeaveThreadTool } from '@/tools/discord/leave_thread' +import { discordListChannelsTool } from '@/tools/discord/list_channels' +import { discordListRolesTool } from '@/tools/discord/list_roles' import { discordPinMessageTool } from '@/tools/discord/pin_message' import { discordRemoveReactionTool } from '@/tools/discord/remove_reaction' import { discordRemoveRoleTool } from '@/tools/discord/remove_role' @@ -41,10 +45,12 @@ export { discordGetUserTool, discordEditMessageTool, discordDeleteMessageTool, + discordBulkDeleteMessagesTool, discordAddReactionTool, discordRemoveReactionTool, discordPinMessageTool, discordUnpinMessageTool, + discordGetPinnedMessagesTool, discordCreateThreadTool, discordJoinThreadTool, discordLeaveThreadTool, @@ -53,11 +59,13 @@ export { discordUpdateChannelTool, discordDeleteChannelTool, discordGetChannelTool, + discordListChannelsTool, discordCreateRoleTool, discordUpdateRoleTool, discordDeleteRoleTool, discordAssignRoleTool, discordRemoveRoleTool, + discordListRolesTool, discordKickMemberTool, discordBanMemberTool, discordUnbanMemberTool, diff --git a/apps/sim/tools/discord/join_thread.ts b/apps/sim/tools/discord/join_thread.ts index c220f994cd5..58caf12693b 100644 --- a/apps/sim/tools/discord/join_thread.ts +++ b/apps/sim/tools/discord/join_thread.ts @@ -31,11 +31,11 @@ export const discordJoinThreadTool: ToolConfig { - return `https://discord.com/api/v10/channels/${params.threadId}/thread-members/@me` + return `https://discord.com/api/v10/channels/${params.threadId.trim()}/thread-members/@me` }, method: 'PUT', headers: (params) => ({ - Authorization: `Bot ${params.botToken}`, + Authorization: `Bot ${params.botToken.trim()}`, }), }, diff --git a/apps/sim/tools/discord/kick_member.ts b/apps/sim/tools/discord/kick_member.ts index 06a6050e833..8c865a1e8b6 100644 --- a/apps/sim/tools/discord/kick_member.ts +++ b/apps/sim/tools/discord/kick_member.ts @@ -37,12 +37,12 @@ export const discordKickMemberTool: ToolConfig { - return `https://discord.com/api/v10/guilds/${params.serverId}/members/${params.userId}` + return `https://discord.com/api/v10/guilds/${params.serverId.trim()}/members/${params.userId.trim()}` }, method: 'DELETE', headers: (params) => { const headers: Record = { - Authorization: `Bot ${params.botToken}`, + Authorization: `Bot ${params.botToken.trim()}`, } if (params.reason) { headers['X-Audit-Log-Reason'] = encodeURIComponent(params.reason) diff --git a/apps/sim/tools/discord/leave_thread.ts b/apps/sim/tools/discord/leave_thread.ts index 6744bbac0f6..3011b408358 100644 --- a/apps/sim/tools/discord/leave_thread.ts +++ b/apps/sim/tools/discord/leave_thread.ts @@ -33,11 +33,11 @@ export const discordLeaveThreadTool: ToolConfig< request: { url: (params: DiscordLeaveThreadParams) => { - return `https://discord.com/api/v10/channels/${params.threadId}/thread-members/@me` + return `https://discord.com/api/v10/channels/${params.threadId.trim()}/thread-members/@me` }, method: 'DELETE', headers: (params) => ({ - Authorization: `Bot ${params.botToken}`, + Authorization: `Bot ${params.botToken.trim()}`, }), }, diff --git a/apps/sim/tools/discord/list_channels.ts b/apps/sim/tools/discord/list_channels.ts new file mode 100644 index 00000000000..0507779a416 --- /dev/null +++ b/apps/sim/tools/discord/list_channels.ts @@ -0,0 +1,67 @@ +import type { DiscordListChannelsParams, DiscordListChannelsResponse } from '@/tools/discord/types' +import type { ToolConfig } from '@/tools/types' + +export const discordListChannelsTool: ToolConfig< + DiscordListChannelsParams, + DiscordListChannelsResponse +> = { + id: 'discord_list_channels', + name: 'Discord List Channels', + description: 'List all channels in a Discord server', + version: '1.0.0', + + params: { + botToken: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The bot token for authentication', + }, + serverId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Discord server ID (guild ID), e.g., 123456789012345678', + }, + }, + + request: { + url: (params: DiscordListChannelsParams) => { + return `https://discord.com/api/v10/guilds/${params.serverId.trim()}/channels` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bot ${params.botToken.trim()}`, + }), + }, + + transformResponse: async (response) => { + const channels = await response.json() + return { + success: true, + output: { + message: `Retrieved ${channels.length} channels from Discord server`, + data: channels, + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Success or error message' }, + data: { + type: 'array', + description: 'Array of Discord channels in the server', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Channel ID' }, + name: { type: 'string', description: 'Channel name' }, + type: { type: 'number', description: 'Channel type' }, + topic: { type: 'string', description: 'Channel topic' }, + parent_id: { type: 'string', description: 'Parent category ID' }, + position: { type: 'number', description: 'Sort position within the channel list' }, + }, + }, + }, + }, +} diff --git a/apps/sim/tools/discord/list_roles.ts b/apps/sim/tools/discord/list_roles.ts new file mode 100644 index 00000000000..dffae85fb4c --- /dev/null +++ b/apps/sim/tools/discord/list_roles.ts @@ -0,0 +1,64 @@ +import type { DiscordListRolesParams, DiscordListRolesResponse } from '@/tools/discord/types' +import type { ToolConfig } from '@/tools/types' + +export const discordListRolesTool: ToolConfig = { + id: 'discord_list_roles', + name: 'Discord List Roles', + description: 'List all roles in a Discord server', + version: '1.0.0', + + params: { + botToken: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'The bot token for authentication', + }, + serverId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'The Discord server ID (guild ID), e.g., 123456789012345678', + }, + }, + + request: { + url: (params: DiscordListRolesParams) => { + return `https://discord.com/api/v10/guilds/${params.serverId.trim()}/roles` + }, + method: 'GET', + headers: (params) => ({ + Authorization: `Bot ${params.botToken.trim()}`, + }), + }, + + transformResponse: async (response) => { + const roles = await response.json() + return { + success: true, + output: { + message: `Retrieved ${roles.length} roles from Discord server`, + data: roles, + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Success or error message' }, + data: { + type: 'array', + description: 'Array of Discord roles in the server', + items: { + type: 'object', + properties: { + id: { type: 'string', description: 'Role ID' }, + name: { type: 'string', description: 'Role name' }, + color: { type: 'number', description: 'Role color' }, + hoist: { type: 'boolean', description: 'Whether role is hoisted' }, + position: { type: 'number', description: 'Role position in the hierarchy' }, + mentionable: { type: 'boolean', description: 'Whether role is mentionable' }, + }, + }, + }, + }, +} diff --git a/apps/sim/tools/discord/pin_message.ts b/apps/sim/tools/discord/pin_message.ts index 0d2d7fec8bf..d526b3387d6 100644 --- a/apps/sim/tools/discord/pin_message.ts +++ b/apps/sim/tools/discord/pin_message.ts @@ -37,11 +37,11 @@ export const discordPinMessageTool: ToolConfig { - return `https://discord.com/api/v10/channels/${params.channelId}/pins/${params.messageId}` + return `https://discord.com/api/v10/channels/${params.channelId.trim()}/pins/${params.messageId.trim()}` }, method: 'PUT', headers: (params) => ({ - Authorization: `Bot ${params.botToken}`, + Authorization: `Bot ${params.botToken.trim()}`, }), }, diff --git a/apps/sim/tools/discord/remove_reaction.ts b/apps/sim/tools/discord/remove_reaction.ts index aeebea1e254..e03924d16e1 100644 --- a/apps/sim/tools/discord/remove_reaction.ts +++ b/apps/sim/tools/discord/remove_reaction.ts @@ -56,12 +56,13 @@ export const discordRemoveReactionTool: ToolConfig< request: { url: (params: DiscordRemoveReactionParams) => { const encodedEmoji = encodeURIComponent(params.emoji) - const userPart = params.userId ? `/${params.userId}` : '/@me' - return `https://discord.com/api/v10/channels/${params.channelId}/messages/${params.messageId}/reactions/${encodedEmoji}${userPart}` + const userId = params.userId?.trim() + const userPart = userId ? `/${userId}` : '/@me' + return `https://discord.com/api/v10/channels/${params.channelId.trim()}/messages/${params.messageId.trim()}/reactions/${encodedEmoji}${userPart}` }, method: 'DELETE', headers: (params) => ({ - Authorization: `Bot ${params.botToken}`, + Authorization: `Bot ${params.botToken.trim()}`, }), }, diff --git a/apps/sim/tools/discord/remove_role.ts b/apps/sim/tools/discord/remove_role.ts index 47fcd4c536e..889b86f5283 100644 --- a/apps/sim/tools/discord/remove_role.ts +++ b/apps/sim/tools/discord/remove_role.ts @@ -37,11 +37,11 @@ export const discordRemoveRoleTool: ToolConfig { - return `https://discord.com/api/v10/guilds/${params.serverId}/members/${params.userId}/roles/${params.roleId}` + return `https://discord.com/api/v10/guilds/${params.serverId.trim()}/members/${params.userId.trim()}/roles/${params.roleId.trim()}` }, method: 'DELETE', headers: (params) => ({ - Authorization: `Bot ${params.botToken}`, + Authorization: `Bot ${params.botToken.trim()}`, }), }, diff --git a/apps/sim/tools/discord/send_message.ts b/apps/sim/tools/discord/send_message.ts index abe95515d3b..0fe172fff8e 100644 --- a/apps/sim/tools/discord/send_message.ts +++ b/apps/sim/tools/discord/send_message.ts @@ -51,8 +51,8 @@ export const discordSendMessageTool: ToolConfig< }), body: (params: DiscordSendMessageParams) => { return { - botToken: params.botToken, - channelId: params.channelId, + botToken: params.botToken.trim(), + channelId: params.channelId.trim(), content: params.content || 'Message sent from Sim', files: params.files || null, } diff --git a/apps/sim/tools/discord/types.ts b/apps/sim/tools/discord/types.ts index c42844c6c51..353311d63db 100644 --- a/apps/sim/tools/discord/types.ts +++ b/apps/sim/tools/discord/types.ts @@ -1,7 +1,7 @@ import type { UserFile } from '@/executor/types' import type { ToolFileData } from '@/tools/types' -interface DiscordMessage { +export interface DiscordMessage { id: string content: string channel_id: string @@ -33,8 +33,8 @@ export interface DiscordGuild { description?: string owner_id: string roles: any[] - channels?: any[] - member_count?: number + approximate_member_count?: number + approximate_presence_count?: number } export interface DiscordUser { @@ -193,6 +193,7 @@ export interface DiscordCreateThreadParams extends DiscordAuthParams { name: string messageId?: string autoArchiveDuration?: number + isPublic?: boolean } export interface DiscordCreateThreadResponse extends BaseDiscordResponse { @@ -269,6 +270,7 @@ export interface DiscordDeleteChannelParams extends DiscordAuthParams { export interface DiscordDeleteChannelResponse extends BaseDiscordResponse { output: { message: string + data?: any } } @@ -360,7 +362,7 @@ export interface DiscordKickMemberResponse extends BaseDiscordResponse { export interface DiscordBanMemberParams extends DiscordAuthParams { userId: string reason?: string - deleteMessageDays?: number + deleteMessageSeconds?: number } export interface DiscordBanMemberResponse extends BaseDiscordResponse { @@ -489,6 +491,50 @@ export interface DiscordDeleteWebhookResponse extends BaseDiscordResponse { } } +// Channel / role listing operations +export type DiscordListChannelsParams = DiscordAuthParams + +export interface DiscordListChannelsResponse extends BaseDiscordResponse { + output: { + message: string + data?: any[] + } +} + +export type DiscordListRolesParams = DiscordAuthParams + +export interface DiscordListRolesResponse extends BaseDiscordResponse { + output: { + message: string + data?: any[] + } +} + +export interface DiscordGetPinnedMessagesParams extends DiscordAuthParams { + channelId: string + limit?: number + before?: string +} + +export interface DiscordGetPinnedMessagesResponse extends BaseDiscordResponse { + output: { + message: string + data?: Array + hasMore?: boolean + } +} + +export interface DiscordBulkDeleteMessagesParams extends DiscordAuthParams { + channelId: string + messageIds: string[] +} + +export interface DiscordBulkDeleteMessagesResponse extends BaseDiscordResponse { + output: { + message: string + } +} + export type DiscordResponse = | DiscordSendMessageResponse | DiscordGetMessagesResponse @@ -525,3 +571,7 @@ export type DiscordResponse = | DiscordExecuteWebhookResponse | DiscordGetWebhookResponse | DiscordDeleteWebhookResponse + | DiscordListChannelsResponse + | DiscordListRolesResponse + | DiscordGetPinnedMessagesResponse + | DiscordBulkDeleteMessagesResponse diff --git a/apps/sim/tools/discord/unban_member.ts b/apps/sim/tools/discord/unban_member.ts index 86eda6d46b7..dc3ed0f3456 100644 --- a/apps/sim/tools/discord/unban_member.ts +++ b/apps/sim/tools/discord/unban_member.ts @@ -39,12 +39,12 @@ export const discordUnbanMemberTool: ToolConfig< request: { url: (params: DiscordUnbanMemberParams) => { - return `https://discord.com/api/v10/guilds/${params.serverId}/bans/${params.userId}` + return `https://discord.com/api/v10/guilds/${params.serverId.trim()}/bans/${params.userId.trim()}` }, method: 'DELETE', headers: (params) => { const headers: Record = { - Authorization: `Bot ${params.botToken}`, + Authorization: `Bot ${params.botToken.trim()}`, } if (params.reason) { headers['X-Audit-Log-Reason'] = encodeURIComponent(params.reason) diff --git a/apps/sim/tools/discord/unpin_message.ts b/apps/sim/tools/discord/unpin_message.ts index eb68d2368a8..5ba2b894832 100644 --- a/apps/sim/tools/discord/unpin_message.ts +++ b/apps/sim/tools/discord/unpin_message.ts @@ -39,11 +39,11 @@ export const discordUnpinMessageTool: ToolConfig< request: { url: (params: DiscordUnpinMessageParams) => { - return `https://discord.com/api/v10/channels/${params.channelId}/pins/${params.messageId}` + return `https://discord.com/api/v10/channels/${params.channelId.trim()}/pins/${params.messageId.trim()}` }, method: 'DELETE', headers: (params) => ({ - Authorization: `Bot ${params.botToken}`, + Authorization: `Bot ${params.botToken.trim()}`, }), }, diff --git a/apps/sim/tools/discord/update_channel.ts b/apps/sim/tools/discord/update_channel.ts index 82d915edb86..786f99a45bb 100644 --- a/apps/sim/tools/discord/update_channel.ts +++ b/apps/sim/tools/discord/update_channel.ts @@ -48,12 +48,12 @@ export const discordUpdateChannelTool: ToolConfig< request: { url: (params: DiscordUpdateChannelParams) => { - return `https://discord.com/api/v10/channels/${params.channelId}` + return `https://discord.com/api/v10/channels/${params.channelId.trim()}` }, method: 'PATCH', headers: (params) => ({ 'Content-Type': 'application/json', - Authorization: `Bot ${params.botToken}`, + Authorization: `Bot ${params.botToken.trim()}`, }), body: (params: DiscordUpdateChannelParams) => { const body: any = {} diff --git a/apps/sim/tools/discord/update_member.ts b/apps/sim/tools/discord/update_member.ts index e5b3490cc76..9a24f21a698 100644 --- a/apps/sim/tools/discord/update_member.ts +++ b/apps/sim/tools/discord/update_member.ts @@ -51,12 +51,12 @@ export const discordUpdateMemberTool: ToolConfig< request: { url: (params: DiscordUpdateMemberParams) => { - return `https://discord.com/api/v10/guilds/${params.serverId}/members/${params.userId}` + return `https://discord.com/api/v10/guilds/${params.serverId.trim()}/members/${params.userId.trim()}` }, method: 'PATCH', headers: (params) => ({ 'Content-Type': 'application/json', - Authorization: `Bot ${params.botToken}`, + Authorization: `Bot ${params.botToken.trim()}`, }), body: (params: DiscordUpdateMemberParams) => { const body: any = {} diff --git a/apps/sim/tools/discord/update_role.ts b/apps/sim/tools/discord/update_role.ts index d4d86af5fcc..cf45f1e8a91 100644 --- a/apps/sim/tools/discord/update_role.ts +++ b/apps/sim/tools/discord/update_role.ts @@ -55,12 +55,12 @@ export const discordUpdateRoleTool: ToolConfig { - return `https://discord.com/api/v10/guilds/${params.serverId}/roles/${params.roleId}` + return `https://discord.com/api/v10/guilds/${params.serverId.trim()}/roles/${params.roleId.trim()}` }, method: 'PATCH', headers: (params) => ({ 'Content-Type': 'application/json', - Authorization: `Bot ${params.botToken}`, + Authorization: `Bot ${params.botToken.trim()}`, }), body: (params: DiscordUpdateRoleParams) => { const body: any = {} diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index f32edc49219..4f0be7e7035 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -732,6 +732,7 @@ import { discordArchiveThreadTool, discordAssignRoleTool, discordBanMemberTool, + discordBulkDeleteMessagesTool, discordCreateChannelTool, discordCreateInviteTool, discordCreateRoleTool, @@ -748,12 +749,15 @@ import { discordGetInviteTool, discordGetMemberTool, discordGetMessagesTool, + discordGetPinnedMessagesTool, discordGetServerTool, discordGetUserTool, discordGetWebhookTool, discordJoinThreadTool, discordKickMemberTool, discordLeaveThreadTool, + discordListChannelsTool, + discordListRolesTool, discordPinMessageTool, discordRemoveReactionTool, discordRemoveRoleTool, @@ -7256,10 +7260,12 @@ export const tools: Record = { discord_get_user: discordGetUserTool, discord_edit_message: discordEditMessageTool, discord_delete_message: discordDeleteMessageTool, + discord_bulk_delete_messages: discordBulkDeleteMessagesTool, discord_add_reaction: discordAddReactionTool, discord_remove_reaction: discordRemoveReactionTool, discord_pin_message: discordPinMessageTool, discord_unpin_message: discordUnpinMessageTool, + discord_get_pinned_messages: discordGetPinnedMessagesTool, discord_create_thread: discordCreateThreadTool, discord_join_thread: discordJoinThreadTool, discord_leave_thread: discordLeaveThreadTool, @@ -7268,11 +7274,13 @@ export const tools: Record = { discord_update_channel: discordUpdateChannelTool, discord_delete_channel: discordDeleteChannelTool, discord_get_channel: discordGetChannelTool, + discord_list_channels: discordListChannelsTool, discord_create_role: discordCreateRoleTool, discord_update_role: discordUpdateRoleTool, discord_delete_role: discordDeleteRoleTool, discord_assign_role: discordAssignRoleTool, discord_remove_role: discordRemoveRoleTool, + discord_list_roles: discordListRolesTool, discord_kick_member: discordKickMemberTool, discord_ban_member: discordBanMemberTool, discord_unban_member: discordUnbanMemberTool,