diff --git a/apps/sim/blocks/blocks/telegram.ts b/apps/sim/blocks/blocks/telegram.ts index 3f247c525a..28fb8f22d0 100644 --- a/apps/sim/blocks/blocks/telegram.ts +++ b/apps/sim/blocks/blocks/telegram.ts @@ -1,21 +1,36 @@ import { TelegramIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' import { AuthMode } from '@/blocks/types' -import type { TelegramMessageResponse } from '@/tools/telegram/types' +import type { TelegramResponse } from '@/tools/telegram/types' -export const TelegramBlock: BlockConfig = { +export const TelegramBlock: BlockConfig = { type: 'telegram', name: 'Telegram', - description: 'Send messages through Telegram or trigger workflows from Telegram events', + description: 'Interact with Telegram', authMode: AuthMode.BotToken, longDescription: - 'Integrate Telegram into the workflow. Can send messages. Can be used in trigger mode to trigger a workflow when a message is sent to a chat.', + 'Integrate Telegram into the workflow. Can send and delete messages. Can be used in trigger mode to trigger a workflow when a message is sent to a chat.', docsLink: 'https://docs.sim.ai/tools/telegram', category: 'tools', bgColor: '#E0E0E0', icon: TelegramIcon, triggerAllowed: true, subBlocks: [ + { + id: 'operation', + title: 'Operation', + type: 'dropdown', + layout: 'full', + options: [ + { label: 'Send Message', id: 'telegram_send_message' }, + { label: 'Send Photo', id: 'telegram_send_photo' }, + { label: 'Send Video', id: 'telegram_send_video' }, + { label: 'Send Audio', id: 'telegram_send_audio' }, + { label: 'Send Animation', id: 'telegram_send_animation' }, + { label: 'Delete Message', id: 'telegram_delete_message' }, + ], + value: () => 'telegram_send_message', + }, { id: 'botToken', title: 'Bot Token', @@ -40,7 +55,7 @@ export const TelegramBlock: BlockConfig = { 1. Add your bot as a member to desired Telegram channel 2. Send any message to the channel (e.g. "I love Sim") 3. Visit https://api.telegram.org/bot/getUpdates -4. Look for the chat field in the JSON response at the very bottomwhere you'll find the chat ID`, +4. Look for the chat field in the JSON response at the very bottom where you'll find the chat ID`, required: true, }, { @@ -50,6 +65,74 @@ export const TelegramBlock: BlockConfig = { layout: 'full', placeholder: 'Enter the message to send', required: true, + condition: { field: 'operation', value: 'telegram_send_message' }, + }, + { + id: 'photo', + title: 'Photo', + type: 'short-input', + layout: 'full', + placeholder: 'Enter photo URL or file_id', + description: 'Photo to send. Pass a file_id or HTTP URL', + required: true, + condition: { field: 'operation', value: 'telegram_send_photo' }, + }, + { + id: 'video', + title: 'Video', + type: 'short-input', + layout: 'full', + placeholder: 'Enter video URL or file_id', + description: 'Video to send. Pass a file_id or HTTP URL', + required: true, + condition: { field: 'operation', value: 'telegram_send_video' }, + }, + { + id: 'audio', + title: 'Audio', + type: 'short-input', + layout: 'full', + placeholder: 'Enter audio URL or file_id', + description: 'Audio file to send. Pass a file_id or HTTP URL', + required: true, + condition: { field: 'operation', value: 'telegram_send_audio' }, + }, + { + id: 'animation', + title: 'Animation', + type: 'short-input', + layout: 'full', + placeholder: 'Enter animation URL or file_id', + description: 'Animation (GIF) to send. Pass a file_id or HTTP URL', + required: true, + condition: { field: 'operation', value: 'telegram_send_animation' }, + }, + { + id: 'caption', + title: 'Caption', + type: 'long-input', + layout: 'full', + placeholder: 'Enter optional caption', + description: 'Media caption (optional)', + condition: { + field: 'operation', + value: [ + 'telegram_send_photo', + 'telegram_send_video', + 'telegram_send_audio', + 'telegram_send_animation', + ], + }, + }, + { + id: 'messageId', + title: 'Message ID', + type: 'short-input', + layout: 'full', + placeholder: 'Enter the message ID to delete', + description: 'The unique identifier of the message you want to delete', + required: true, + condition: { field: 'operation', value: 'telegram_delete_message' }, }, // TRIGGER MODE: Trigger configuration (only shown when trigger mode is active) { @@ -62,39 +145,180 @@ export const TelegramBlock: BlockConfig = { }, ], tools: { - access: ['telegram_message'], + access: [ + 'telegram_send_message', + 'telegram_delete_message', + 'telegram_send_photo', + 'telegram_send_video', + 'telegram_send_audio', + 'telegram_send_animation', + ], + config: { + tool: (params) => { + switch (params.operation) { + case 'telegram_send_message': + return 'telegram_send_message' + case 'telegram_delete_message': + return 'telegram_delete_message' + case 'telegram_send_photo': + return 'telegram_send_photo' + case 'telegram_send_video': + return 'telegram_send_video' + case 'telegram_send_audio': + return 'telegram_send_audio' + case 'telegram_send_animation': + return 'telegram_send_animation' + default: + return 'telegram_send_message' + } + }, + params: (params) => { + if (!params.botToken) throw new Error('Bot token required for this operation') + + const chatId = (params.chatId || '').trim() + if (!chatId) { + throw new Error('Chat ID is required.') + } + + const commonParams = { + botToken: params.botToken, + chatId, + } + + switch (params.operation) { + case 'telegram_send_message': + if (!params.text) { + throw new Error('Message text is required.') + } + return { + ...commonParams, + text: params.text, + } + case 'telegram_delete_message': + if (!params.messageId) { + throw new Error('Message ID is required for delete operation.') + } + return { + ...commonParams, + messageId: params.messageId, + } + case 'telegram_send_photo': + if (!params.photo) { + throw new Error('Photo URL or file_id is required.') + } + return { + ...commonParams, + photo: params.photo, + caption: params.caption, + } + case 'telegram_send_video': + if (!params.video) { + throw new Error('Video URL or file_id is required.') + } + return { + ...commonParams, + video: params.video, + caption: params.caption, + } + case 'telegram_send_audio': + if (!params.audio) { + throw new Error('Audio URL or file_id is required.') + } + return { + ...commonParams, + audio: params.audio, + caption: params.caption, + } + case 'telegram_send_animation': + if (!params.animation) { + throw new Error('Animation URL or file_id is required.') + } + return { + ...commonParams, + animation: params.animation, + caption: params.caption, + } + default: + return { + ...commonParams, + text: params.text, + } + } + }, + }, }, inputs: { + operation: { type: 'string', description: 'Operation to perform' }, botToken: { type: 'string', description: 'Telegram bot token' }, chatId: { type: 'string', description: 'Chat identifier' }, text: { type: 'string', description: 'Message text' }, + photo: { type: 'string', description: 'Photo URL or file_id' }, + video: { type: 'string', description: 'Video URL or file_id' }, + audio: { type: 'string', description: 'Audio URL or file_id' }, + animation: { type: 'string', description: 'Animation URL or file_id' }, + caption: { type: 'string', description: 'Caption for media' }, + messageId: { type: 'string', description: 'Message ID to delete' }, }, outputs: { // Send message operation outputs ok: { type: 'boolean', description: 'API response success status' }, - result: { type: 'json', description: 'Complete message result object from Telegram API' }, + result: { + type: 'json', + description: 'Complete message result object from Telegram API', + }, + message: { type: 'string', description: 'Success or error message' }, + data: { type: 'json', description: 'Response data' }, // Specific result fields messageId: { type: 'number', description: 'Sent message ID' }, chatId: { type: 'number', description: 'Chat ID where message was sent' }, - chatType: { type: 'string', description: 'Type of chat (private, group, supergroup, channel)' }, + chatType: { + type: 'string', + description: 'Type of chat (private, group, supergroup, channel)', + }, username: { type: 'string', description: 'Chat username (if available)' }, - messageDate: { type: 'number', description: 'Unix timestamp of sent message' }, - messageText: { type: 'string', description: 'Text content of sent message' }, + messageDate: { + type: 'number', + description: 'Unix timestamp of sent message', + }, + messageText: { + type: 'string', + description: 'Text content of sent message', + }, + // Delete message outputs + deleted: { + type: 'boolean', + description: 'Whether the message was successfully deleted', + }, // Webhook trigger outputs (incoming messages) - update_id: { type: 'number', description: 'Unique identifier for the update' }, - message_id: { type: 'number', description: 'Unique message identifier from webhook' }, + update_id: { + type: 'number', + description: 'Unique identifier for the update', + }, + message_id: { + type: 'number', + description: 'Unique message identifier from webhook', + }, from_id: { type: 'number', description: 'User ID who sent the message' }, from_username: { type: 'string', description: 'Username of the sender' }, - from_first_name: { type: 'string', description: 'First name of the sender' }, + from_first_name: { + type: 'string', + description: 'First name of the sender', + }, from_last_name: { type: 'string', description: 'Last name of the sender' }, chat_id: { type: 'number', description: 'Unique identifier for the chat' }, chat_type: { type: 'string', description: 'Type of chat (private, group, supergroup, channel)', }, - chat_title: { type: 'string', description: 'Title of the chat (for groups and channels)' }, + chat_title: { + type: 'string', + description: 'Title of the chat (for groups and channels)', + }, text: { type: 'string', description: 'Message text content from webhook' }, - date: { type: 'number', description: 'Date the message was sent (Unix timestamp)' }, + date: { + type: 'number', + description: 'Date the message was sent (Unix timestamp)', + }, entities: { type: 'json', description: 'Special entities in the message (mentions, hashtags, etc.)', diff --git a/apps/sim/tools/registry.ts b/apps/sim/tools/registry.ts index 9fc727f15a..155ecd51d8 100644 --- a/apps/sim/tools/registry.ts +++ b/apps/sim/tools/registry.ts @@ -174,7 +174,14 @@ import { supabaseUpsertTool, } from '@/tools/supabase' import { tavilyExtractTool, tavilySearchTool } from '@/tools/tavily' -import { telegramMessageTool } from '@/tools/telegram' +import { + telegramDeleteMessageTool, + telegramSendAnimationTool, + telegramSendAudioTool, + telegramSendMessageTool, + telegramSendPhotoTool, + telegramSendVideoTool, +} from '@/tools/telegram' import { thinkingTool } from '@/tools/thinking' import { sendSMSTool } from '@/tools/twilio' import { typeformFilesTool, typeformInsightsTool, typeformResponsesTool } from '@/tools/typeform' @@ -323,7 +330,12 @@ export const tools: Record = { knowledge_create_document: knowledgeCreateDocumentTool, elevenlabs_tts: elevenLabsTtsTool, s3_get_object: s3GetObjectTool, - telegram_message: telegramMessageTool, + telegram_send_message: telegramSendMessageTool, + telegram_delete_message: telegramDeleteMessageTool, + telegram_send_audio: telegramSendAudioTool, + telegram_send_animation: telegramSendAnimationTool, + telegram_send_photo: telegramSendPhotoTool, + telegram_send_video: telegramSendVideoTool, clay_populate: clayPopulateTool, discord_send_message: discordSendMessageTool, discord_get_messages: discordGetMessagesTool, diff --git a/apps/sim/tools/telegram/animation.ts b/apps/sim/tools/telegram/animation.ts new file mode 100644 index 0000000000..4b728b2644 --- /dev/null +++ b/apps/sim/tools/telegram/animation.ts @@ -0,0 +1,270 @@ +import type { + TelegramMedia, + TelegramSendAnimationParams, + TelegramSendMediaResponse, +} from '@/tools/telegram/types' +import { convertMarkdownToHTML } from '@/tools/telegram/utils' +import type { ToolConfig } from '@/tools/types' + +export const telegramSendAnimationTool: ToolConfig< + TelegramSendAnimationParams, + TelegramSendMediaResponse +> = { + id: 'telegram_send_animation', + name: 'Telegram Send Animation', + description: 'Send animations (GIFs) to Telegram channels or users through the Telegram Bot API.', + version: '1.0.0', + + params: { + botToken: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Telegram Bot API Token', + }, + chatId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Target Telegram chat ID', + }, + animation: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Animation to send. Pass a file_id or HTTP URL', + }, + caption: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Animation caption (optional)', + }, + }, + + request: { + url: (params: TelegramSendAnimationParams) => + `https://api.telegram.org/bot${params.botToken}/sendAnimation`, + method: 'POST', + headers: () => ({ + 'Content-Type': 'application/json', + }), + body: (params: TelegramSendAnimationParams) => { + const body: Record = { + chat_id: params.chatId, + animation: params.animation, + } + + if (params.caption) { + body.caption = convertMarkdownToHTML(params.caption) + body.parse_mode = 'HTML' + } + + return body + }, + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + const result = data.result as TelegramMedia + return { + success: data.ok, + output: { + message: data.ok ? 'Animation sent successfully' : 'Failed to send animation', + data: result, + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Success or error message' }, + data: { + type: 'object', + description: 'Telegram message data including optional media', + properties: { + message_id: { + type: 'number', + description: 'Unique Telegram message identifier', + }, + from: { + type: 'object', + description: 'Information about the sender', + properties: { + id: { type: 'number', description: 'Sender ID' }, + is_bot: { + type: 'boolean', + description: 'Whether the chat is a bot or not', + }, + first_name: { + type: 'string', + description: "Sender's first name (if available)", + }, + username: { + type: 'string', + description: "Sender's username (if available)", + }, + }, + }, + chat: { + type: 'object', + description: 'Information about the chat where message was sent', + properties: { + id: { type: 'number', description: 'Chat ID' }, + first_name: { + type: 'string', + description: 'Chat first name (if private chat)', + }, + username: { + type: 'string', + description: 'Chat username (for private or channels)', + }, + type: { + type: 'string', + description: 'Type of chat (private, group, supergroup, or channel)', + }, + }, + }, + date: { + type: 'number', + description: 'Unix timestamp when the message was sent', + }, + text: { + type: 'string', + description: 'Text content of the sent message (if applicable)', + }, + format: { + type: 'object', + description: 'Media format information (for videos, GIFs, etc.)', + properties: { + file_name: { type: 'string', description: 'Media file name' }, + mime_type: { type: 'string', description: 'Media MIME type' }, + duration: { + type: 'number', + description: 'Duration of media in seconds', + }, + width: { type: 'number', description: 'Media width in pixels' }, + height: { type: 'number', description: 'Media height in pixels' }, + thumbnail: { + type: 'object', + description: 'Thumbnail image details', + properties: { + file_id: { type: 'string', description: 'Thumbnail file ID' }, + file_unique_id: { + type: 'string', + description: 'Unique thumbnail file identifier', + }, + file_size: { + type: 'number', + description: 'Thumbnail file size in bytes', + }, + width: { + type: 'number', + description: 'Thumbnail width in pixels', + }, + height: { + type: 'number', + description: 'Thumbnail height in pixels', + }, + }, + }, + thumb: { + type: 'object', + description: 'Secondary thumbnail details (duplicate of thumbnail)', + properties: { + file_id: { type: 'string', description: 'Thumbnail file ID' }, + file_unique_id: { + type: 'string', + description: 'Unique thumbnail file identifier', + }, + file_size: { + type: 'number', + description: 'Thumbnail file size in bytes', + }, + width: { + type: 'number', + description: 'Thumbnail width in pixels', + }, + height: { + type: 'number', + description: 'Thumbnail height in pixels', + }, + }, + }, + file_id: { type: 'string', description: 'Media file ID' }, + file_unique_id: { + type: 'string', + description: 'Unique media file identifier', + }, + file_size: { + type: 'number', + description: 'Size of media file in bytes', + }, + }, + }, + document: { + type: 'object', + description: 'Document file details if the message contains a document', + properties: { + file_name: { type: 'string', description: 'Document file name' }, + mime_type: { type: 'string', description: 'Document MIME type' }, + thumbnail: { + type: 'object', + description: 'Document thumbnail information', + properties: { + file_id: { type: 'string', description: 'Thumbnail file ID' }, + file_unique_id: { + type: 'string', + description: 'Unique thumbnail file identifier', + }, + file_size: { + type: 'number', + description: 'Thumbnail file size in bytes', + }, + width: { + type: 'number', + description: 'Thumbnail width in pixels', + }, + height: { + type: 'number', + description: 'Thumbnail height in pixels', + }, + }, + }, + thumb: { + type: 'object', + description: 'Duplicate thumbnail info (used for compatibility)', + properties: { + file_id: { type: 'string', description: 'Thumbnail file ID' }, + file_unique_id: { + type: 'string', + description: 'Unique thumbnail file identifier', + }, + file_size: { + type: 'number', + description: 'Thumbnail file size in bytes', + }, + width: { + type: 'number', + description: 'Thumbnail width in pixels', + }, + height: { + type: 'number', + description: 'Thumbnail height in pixels', + }, + }, + }, + file_id: { type: 'string', description: 'Document file ID' }, + file_unique_id: { + type: 'string', + description: 'Unique document file identifier', + }, + file_size: { + type: 'number', + description: 'Size of document file in bytes', + }, + }, + }, + }, + }, + }, +} diff --git a/apps/sim/tools/telegram/audio.ts b/apps/sim/tools/telegram/audio.ts new file mode 100644 index 0000000000..bee70fcb03 --- /dev/null +++ b/apps/sim/tools/telegram/audio.ts @@ -0,0 +1,175 @@ +import type { + TelegramAudio, + TelegramSendAudioParams, + TelegramSendAudioResponse, +} from '@/tools/telegram/types' +import { convertMarkdownToHTML } from '@/tools/telegram/utils' +import type { ToolConfig } from '@/tools/types' + +export const telegramSendAudioTool: ToolConfig = + { + id: 'telegram_send_audio', + name: 'Telegram Send Audio', + description: 'Send audio files to Telegram channels or users through the Telegram Bot API.', + version: '1.0.0', + + params: { + botToken: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Telegram Bot API Token', + }, + chatId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Target Telegram chat ID', + }, + audio: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Audio file to send. Pass a file_id or HTTP URL', + }, + caption: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Audio caption (optional)', + }, + }, + + request: { + url: (params: TelegramSendAudioParams) => + `https://api.telegram.org/bot${params.botToken}/sendAudio`, + method: 'POST', + headers: () => ({ + 'Content-Type': 'application/json', + }), + body: (params: TelegramSendAudioParams) => { + const body: Record = { + chat_id: params.chatId, + audio: params.audio, + } + + if (params.caption) { + body.caption = convertMarkdownToHTML(params.caption) + body.parse_mode = 'HTML' + } + + return body + }, + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + const result = data.result as TelegramAudio + + return { + success: data.ok, + output: { + message: data.ok ? 'Audio sent successfully' : 'Failed to send audio', + data: result, + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Success or error message' }, + data: { + type: 'object', + description: 'Telegram message data including voice/audio information', + properties: { + message_id: { + type: 'number', + description: 'Unique Telegram message identifier', + }, + from: { + type: 'object', + description: 'Information about the sender', + properties: { + id: { type: 'number', description: 'Sender ID' }, + is_bot: { + type: 'boolean', + description: 'Whether the chat is a bot or not', + }, + first_name: { + type: 'string', + description: "Sender's first name (if available)", + }, + username: { + type: 'string', + description: "Sender's username (if available)", + }, + }, + }, + chat: { + type: 'object', + description: 'Information about the chat where the message was sent', + properties: { + id: { type: 'number', description: 'Chat ID' }, + first_name: { + type: 'string', + description: 'Chat first name (if private chat)', + }, + username: { + type: 'string', + description: 'Chat username (for private or channels)', + }, + type: { + type: 'string', + description: 'Type of chat (private, group, supergroup, or channel)', + }, + }, + }, + date: { + type: 'number', + description: 'Unix timestamp when the message was sent', + }, + text: { + type: 'string', + description: 'Text content of the sent message (if applicable)', + }, + audio: { + type: 'object', + description: 'Audio file details', + properties: { + duration: { + type: 'number', + description: 'Duration of the audio in seconds', + }, + performer: { + type: 'string', + description: 'Performer of the audio', + }, + title: { + type: 'string', + description: 'Title of the audio', + }, + file_name: { + type: 'string', + description: 'Original filename of the audio', + }, + mime_type: { + type: 'string', + description: 'MIME type of the audio file', + }, + file_id: { + type: 'string', + description: 'Unique file identifier for this audio', + }, + file_unique_id: { + type: 'string', + description: 'Unique identifier across different bots for this file', + }, + file_size: { + type: 'number', + description: 'Size of the audio file in bytes', + }, + }, + }, + }, + }, + }, + } diff --git a/apps/sim/tools/telegram/delete.ts b/apps/sim/tools/telegram/delete.ts new file mode 100644 index 0000000000..73aa34fb13 --- /dev/null +++ b/apps/sim/tools/telegram/delete.ts @@ -0,0 +1,79 @@ +import type { + TelegramDeleteMessageParams, + TelegramDeleteMessageResponse, +} from '@/tools/telegram/types' +import type { ToolConfig } from '@/tools/types' + +export const telegramDeleteMessageTool: ToolConfig< + TelegramDeleteMessageParams, + TelegramDeleteMessageResponse +> = { + id: 'telegram_delete_message', + name: 'Telegram Delete Message', + description: + 'Delete messages in Telegram channels or chats through the Telegram Bot API. Requires the message ID of the message to delete.', + version: '1.0.0', + + params: { + botToken: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Telegram Bot API Token', + }, + chatId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Target Telegram chat ID', + }, + messageId: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Message ID to delete', + }, + }, + + request: { + url: (params: TelegramDeleteMessageParams) => + `https://api.telegram.org/bot${params.botToken}/deleteMessage`, + method: 'POST', + headers: () => ({ + 'Content-Type': 'application/json', + }), + body: (params: TelegramDeleteMessageParams) => ({ + chat_id: params.chatId, + message_id: params.messageId, + }), + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + return { + success: data.ok, + output: { + message: data.ok ? 'Message deleted successfully' : 'Failed to delete message', + data: { + ok: data.ok, + deleted: data.result, + }, + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Success or error message' }, + data: { + type: 'object', + description: 'Delete operation result', + properties: { + ok: { type: 'boolean', description: 'API response success status' }, + deleted: { + type: 'boolean', + description: 'Whether the message was successfully deleted', + }, + }, + }, + }, +} diff --git a/apps/sim/tools/telegram/index.ts b/apps/sim/tools/telegram/index.ts index 8b8e96974e..8e1a098f21 100644 --- a/apps/sim/tools/telegram/index.ts +++ b/apps/sim/tools/telegram/index.ts @@ -1,3 +1,15 @@ -import { telegramMessageTool } from '@/tools/telegram/message' +import { telegramSendAnimationTool } from '@/tools/telegram/animation' +import { telegramSendAudioTool } from '@/tools/telegram/audio' +import { telegramDeleteMessageTool } from '@/tools/telegram/delete' +import { telegramSendMessageTool } from '@/tools/telegram/message' +import { telegramSendPhotoTool } from '@/tools/telegram/photo' +import { telegramSendVideoTool } from '@/tools/telegram/video' -export { telegramMessageTool } +export { + telegramSendAnimationTool, + telegramSendAudioTool, + telegramDeleteMessageTool, + telegramSendMessageTool, + telegramSendPhotoTool, + telegramSendVideoTool, +} diff --git a/apps/sim/tools/telegram/message.ts b/apps/sim/tools/telegram/message.ts index 620363869d..6cb72a06ec 100644 --- a/apps/sim/tools/telegram/message.ts +++ b/apps/sim/tools/telegram/message.ts @@ -1,10 +1,17 @@ -import type { TelegramMessageParams, TelegramMessageResponse } from '@/tools/telegram/types' +import type { + TelegramMessage, + TelegramSendMessageParams, + TelegramSendMessageResponse, +} from '@/tools/telegram/types' import { convertMarkdownToHTML } from '@/tools/telegram/utils' import type { ToolConfig } from '@/tools/types' -export const telegramMessageTool: ToolConfig = { - id: 'telegram_message', - name: 'Telegram Message', +export const telegramSendMessageTool: ToolConfig< + TelegramSendMessageParams, + TelegramSendMessageResponse +> = { + id: 'telegram_send_message', + name: 'Telegram Send Message', description: 'Send messages to Telegram channels or users through the Telegram Bot API. Enables direct communication and notifications with message tracking and chat confirmation.', version: '1.0.0', @@ -31,13 +38,13 @@ export const telegramMessageTool: ToolConfig + url: (params: TelegramSendMessageParams) => `https://api.telegram.org/bot${params.botToken}/sendMessage`, method: 'POST', headers: () => ({ 'Content-Type': 'application/json', }), - body: (params: TelegramMessageParams) => ({ + body: (params: TelegramSendMessageParams) => ({ chat_id: params.chatId, text: convertMarkdownToHTML(params.text), parse_mode: 'HTML', @@ -46,18 +53,68 @@ export const telegramMessageTool: ToolConfig { const data = await response.json() + const result = data.result as TelegramMessage + return { - success: true, - output: data.result, + success: data.ok, + output: { + message: data.ok ? 'Message sent successfully' : 'Failed to send message', + data: result, + }, } }, outputs: { - success: { type: 'boolean', description: 'Telegram message send success status' }, - messageId: { type: 'number', description: 'Unique Telegram message identifier' }, - chatId: { type: 'string', description: 'Target chat ID where message was sent' }, - text: { type: 'string', description: 'Text content of the sent message' }, - timestamp: { type: 'number', description: 'Unix timestamp when message was sent' }, - from: { type: 'object', description: 'Information about the bot that sent the message' }, + message: { type: 'string', description: 'Success or error message' }, + data: { + type: 'object', + description: 'Telegram message data', + properties: { + message_id: { + type: 'number', + description: 'Unique Telegram message identifier', + }, + from: { + type: 'object', + description: 'Chat information', + properties: { + id: { type: 'number', description: 'Chat ID' }, + is_bot: { + type: 'boolean', + description: 'Whether the chat is a bot or not', + }, + first_name: { + type: 'string', + description: 'Chat username (if available)', + }, + username: { + type: 'string', + description: 'Chat title (for groups and channels)', + }, + }, + }, + chat: { + type: 'object', + description: 'Information about the bot that sent the message', + properties: { + id: { type: 'number', description: 'Bot user ID' }, + first_name: { type: 'string', description: 'Bot first name' }, + username: { type: 'string', description: 'Bot username' }, + type: { + type: 'string', + description: 'chat type private or channel', + }, + }, + }, + date: { + type: 'number', + description: 'Unix timestamp when message was sent', + }, + text: { + type: 'string', + description: 'Text content of the sent message', + }, + }, + }, }, } diff --git a/apps/sim/tools/telegram/photo.ts b/apps/sim/tools/telegram/photo.ts new file mode 100644 index 0000000000..6c1d54a15c --- /dev/null +++ b/apps/sim/tools/telegram/photo.ts @@ -0,0 +1,154 @@ +import type { + TelegramPhoto, + TelegramSendPhotoParams, + TelegramSendPhotoResponse, +} from '@/tools/telegram/types' +import { convertMarkdownToHTML } from '@/tools/telegram/utils' +import type { ToolConfig } from '@/tools/types' + +export const telegramSendPhotoTool: ToolConfig = + { + id: 'telegram_send_photo', + name: 'Telegram Send Photo', + description: 'Send photos to Telegram channels or users through the Telegram Bot API.', + version: '1.0.0', + + params: { + botToken: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Telegram Bot API Token', + }, + chatId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Target Telegram chat ID', + }, + photo: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Photo to send. Pass a file_id or HTTP URL', + }, + caption: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Photo caption (optional)', + }, + }, + + request: { + url: (params: TelegramSendPhotoParams) => + `https://api.telegram.org/bot${params.botToken}/sendPhoto`, + method: 'POST', + headers: () => ({ + 'Content-Type': 'application/json', + }), + body: (params: TelegramSendPhotoParams) => { + const body: Record = { + chat_id: params.chatId, + photo: params.photo, + } + + if (params.caption) { + body.caption = convertMarkdownToHTML(params.caption) + body.parse_mode = 'HTML' + } + + return body + }, + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + const result = data.result as TelegramPhoto + + return { + success: data.ok, + output: { + message: data.ok ? 'Photo sent successfully' : 'Failed to send photo', + data: result, + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Success or error message' }, + data: { + type: 'object', + description: 'Telegram message data including optional photo(s)', + properties: { + message_id: { + type: 'number', + description: 'Unique Telegram message identifier', + }, + from: { + type: 'object', + description: 'Chat information', + properties: { + id: { type: 'number', description: 'Chat ID' }, + is_bot: { + type: 'boolean', + description: 'Whether the chat is a bot or not', + }, + first_name: { + type: 'string', + description: 'Chat username (if available)', + }, + username: { + type: 'string', + description: 'Chat title (for groups and channels)', + }, + }, + }, + chat: { + type: 'object', + description: 'Information about the bot that sent the message', + properties: { + id: { type: 'number', description: 'Bot user ID' }, + first_name: { type: 'string', description: 'Bot first name' }, + username: { type: 'string', description: 'Bot username' }, + type: { + type: 'string', + description: 'Chat type (private, group, supergroup, channel)', + }, + }, + }, + date: { + type: 'number', + description: 'Unix timestamp when message was sent', + }, + text: { + type: 'string', + description: 'Text content of the sent message (if applicable)', + }, + photo: { + type: 'array', + description: 'List of photos included in the message', + items: { + type: 'object', + properties: { + file_id: { + type: 'string', + description: 'Unique file ID of the photo', + }, + file_unique_id: { + type: 'string', + description: 'Unique identifier for this file across different bots', + }, + file_size: { + type: 'number', + description: 'Size of the photo file in bytes', + }, + width: { type: 'number', description: 'Photo width in pixels' }, + height: { type: 'number', description: 'Photo height in pixels' }, + }, + }, + }, + }, + }, + }, + } diff --git a/apps/sim/tools/telegram/types.ts b/apps/sim/tools/telegram/types.ts index 965f61c72f..df38b18b27 100644 --- a/apps/sim/tools/telegram/types.ts +++ b/apps/sim/tools/telegram/types.ts @@ -1,23 +1,172 @@ import type { ToolResponse } from '@/tools/types' -export interface TelegramMessageParams { +export interface TelegramMessage { + message_id: number + from: { + id: number + is_bot: boolean + first_name?: string + username?: string + } + chat?: { + id: number + first_name?: string + username?: string + type?: string + } + date: number + text?: string +} + +export interface TelegramAudio extends TelegramMessage { + voice: { + duration: 2 + mime_type: string + file_id: string + file_unique_id: string + file_size: number + } +} + +export interface TelegramPhoto extends TelegramMessage { + photo?: { + file_id: string + file_unique_id: string + file_size: number + width: number + height: number + } +} + +export interface TelegramMedia extends TelegramMessage { + format?: { + file_name: string + mime_type: string + duration: number + width: number + height: number + thumbnail: { + file_id: string + file_unique_id: string + file_size: number + width: number + height: number + } + thumb: { + file_id: string + file_unique_id: string + file_size: number + width: number + height: number + } + file_id: string + file_unique_id: string + file_size: number + } + document?: { + file_name: string + mime_type: string + thumbnail: { + file_id: string + file_unique_id: string + file_size: number + width: number + height: number + } + thumb: { + file_id: string + file_unique_id: string + file_size: number + width: number + height: number + } + file_id: string + file_unique_id: string + file_size: number + } +} + +export interface TelegramAuthParams { botToken: string chatId: string +} + +export interface TelegramSendMessageParams extends TelegramAuthParams { text: string } -export interface TelegramMessageResponse extends ToolResponse { +export interface TelegramSendPhotoParams extends TelegramAuthParams { + photo: string + caption?: string +} + +export interface TelegramSendVideoParams extends TelegramAuthParams { + video: string + caption?: string +} + +export interface TelegramSendAudioParams extends TelegramAuthParams { + audio: string + caption?: string +} + +export interface TelegramSendAnimationParams extends TelegramAuthParams { + animation: string + caption?: string +} + +export interface TelegramDeleteMessageParams extends TelegramAuthParams { + messageId: number +} + +export interface TelegramSendMessageResponse extends ToolResponse { + output: { + message: string + data?: TelegramMessage + } +} + +export interface TelegramSendMediaResponse extends ToolResponse { output: { - ok: boolean - result: { - message_id: number - chat: { - id: number - type: string - username: string - } - date: number - text: string + message: string + data?: TelegramMedia + } +} + +export interface TelegramSendAudioResponse extends ToolResponse { + output: { + message: string + data?: TelegramAudio + } +} + +export interface TelegramDeleteMessageResponse extends ToolResponse { + output: { + message: string + data?: { + ok: boolean + deleted: boolean } } } + +export interface TelegramSendPhotoResponse extends ToolResponse { + output: { + message: string + data?: TelegramPhoto + } +} + +export type TelegramResponse = + | TelegramSendMessageResponse + | TelegramSendPhotoResponse + | TelegramSendAudioResponse + | TelegramSendMediaResponse + | TelegramDeleteMessageResponse + +// Legacy type for backwards compatibility +export interface TelegramMessageParams { + botToken: string + chatId: string + text: string +} diff --git a/apps/sim/tools/telegram/video.ts b/apps/sim/tools/telegram/video.ts new file mode 100644 index 0000000000..6874e9459f --- /dev/null +++ b/apps/sim/tools/telegram/video.ts @@ -0,0 +1,269 @@ +import type { + TelegramMedia, + TelegramSendMediaResponse, + TelegramSendVideoParams, +} from '@/tools/telegram/types' +import { convertMarkdownToHTML } from '@/tools/telegram/utils' +import type { ToolConfig } from '@/tools/types' + +export const telegramSendVideoTool: ToolConfig = + { + id: 'telegram_send_video', + name: 'Telegram Send Video', + description: 'Send videos to Telegram channels or users through the Telegram Bot API.', + version: '1.0.0', + + params: { + botToken: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Your Telegram Bot API Token', + }, + chatId: { + type: 'string', + required: true, + visibility: 'user-only', + description: 'Target Telegram chat ID', + }, + video: { + type: 'string', + required: true, + visibility: 'user-or-llm', + description: 'Video to send. Pass a file_id or HTTP URL', + }, + caption: { + type: 'string', + required: false, + visibility: 'user-or-llm', + description: 'Video caption (optional)', + }, + }, + + request: { + url: (params: TelegramSendVideoParams) => + `https://api.telegram.org/bot${params.botToken}/sendVideo`, + method: 'POST', + headers: () => ({ + 'Content-Type': 'application/json', + }), + body: (params: TelegramSendVideoParams) => { + const body: Record = { + chat_id: params.chatId, + video: params.video, + } + + if (params.caption) { + body.caption = convertMarkdownToHTML(params.caption) + body.parse_mode = 'HTML' + } + + return body + }, + }, + + transformResponse: async (response: Response) => { + const data = await response.json() + const result = data.result as TelegramMedia + + return { + success: data.ok, + output: { + message: data.ok ? 'Video sent successfully' : 'Failed to send video', + data: result, + }, + } + }, + + outputs: { + message: { type: 'string', description: 'Success or error message' }, + data: { + type: 'object', + description: 'Telegram message data including optional media', + properties: { + message_id: { + type: 'number', + description: 'Unique Telegram message identifier', + }, + from: { + type: 'object', + description: 'Information about the sender', + properties: { + id: { type: 'number', description: 'Sender ID' }, + is_bot: { + type: 'boolean', + description: 'Whether the chat is a bot or not', + }, + first_name: { + type: 'string', + description: "Sender's first name (if available)", + }, + username: { + type: 'string', + description: "Sender's username (if available)", + }, + }, + }, + chat: { + type: 'object', + description: 'Information about the chat where message was sent', + properties: { + id: { type: 'number', description: 'Chat ID' }, + first_name: { + type: 'string', + description: 'Chat first name (if private chat)', + }, + username: { + type: 'string', + description: 'Chat username (for private or channels)', + }, + type: { + type: 'string', + description: 'Type of chat (private, group, supergroup, or channel)', + }, + }, + }, + date: { + type: 'number', + description: 'Unix timestamp when the message was sent', + }, + text: { + type: 'string', + description: 'Text content of the sent message (if applicable)', + }, + format: { + type: 'object', + description: 'Media format information (for videos, GIFs, etc.)', + properties: { + file_name: { type: 'string', description: 'Media file name' }, + mime_type: { type: 'string', description: 'Media MIME type' }, + duration: { + type: 'number', + description: 'Duration of media in seconds', + }, + width: { type: 'number', description: 'Media width in pixels' }, + height: { type: 'number', description: 'Media height in pixels' }, + thumbnail: { + type: 'object', + description: 'Thumbnail image details', + properties: { + file_id: { type: 'string', description: 'Thumbnail file ID' }, + file_unique_id: { + type: 'string', + description: 'Unique thumbnail file identifier', + }, + file_size: { + type: 'number', + description: 'Thumbnail file size in bytes', + }, + width: { + type: 'number', + description: 'Thumbnail width in pixels', + }, + height: { + type: 'number', + description: 'Thumbnail height in pixels', + }, + }, + }, + thumb: { + type: 'object', + description: 'Secondary thumbnail details (duplicate of thumbnail)', + properties: { + file_id: { type: 'string', description: 'Thumbnail file ID' }, + file_unique_id: { + type: 'string', + description: 'Unique thumbnail file identifier', + }, + file_size: { + type: 'number', + description: 'Thumbnail file size in bytes', + }, + width: { + type: 'number', + description: 'Thumbnail width in pixels', + }, + height: { + type: 'number', + description: 'Thumbnail height in pixels', + }, + }, + }, + file_id: { type: 'string', description: 'Media file ID' }, + file_unique_id: { + type: 'string', + description: 'Unique media file identifier', + }, + file_size: { + type: 'number', + description: 'Size of media file in bytes', + }, + }, + }, + document: { + type: 'object', + description: 'Document file details if the message contains a document', + properties: { + file_name: { type: 'string', description: 'Document file name' }, + mime_type: { type: 'string', description: 'Document MIME type' }, + thumbnail: { + type: 'object', + description: 'Document thumbnail information', + properties: { + file_id: { type: 'string', description: 'Thumbnail file ID' }, + file_unique_id: { + type: 'string', + description: 'Unique thumbnail file identifier', + }, + file_size: { + type: 'number', + description: 'Thumbnail file size in bytes', + }, + width: { + type: 'number', + description: 'Thumbnail width in pixels', + }, + height: { + type: 'number', + description: 'Thumbnail height in pixels', + }, + }, + }, + thumb: { + type: 'object', + description: 'Duplicate thumbnail info (used for compatibility)', + properties: { + file_id: { type: 'string', description: 'Thumbnail file ID' }, + file_unique_id: { + type: 'string', + description: 'Unique thumbnail file identifier', + }, + file_size: { + type: 'number', + description: 'Thumbnail file size in bytes', + }, + width: { + type: 'number', + description: 'Thumbnail width in pixels', + }, + height: { + type: 'number', + description: 'Thumbnail height in pixels', + }, + }, + }, + file_id: { type: 'string', description: 'Document file ID' }, + file_unique_id: { + type: 'string', + description: 'Unique document file identifier', + }, + file_size: { + type: 'number', + description: 'Size of document file in bytes', + }, + }, + }, + }, + }, + }, + }