diff --git a/apps/sim/blocks/blocks/discord.ts b/apps/sim/blocks/blocks/discord.ts index 94c27d448..79331eaac 100644 --- a/apps/sim/blocks/blocks/discord.ts +++ b/apps/sim/blocks/blocks/discord.ts @@ -1,6 +1,7 @@ import { DiscordIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' import { AuthMode } from '@/blocks/types' +import { normalizeFileInput } from '@/blocks/utils' import type { DiscordResponse } from '@/tools/discord/types' export const DiscordBlock: BlockConfig = { @@ -579,17 +580,11 @@ export const DiscordBlock: BlockConfig = { switch (params.operation) { case 'discord_send_message': { - const fileParam = params.attachmentFiles || params.files - const normalizedFiles = fileParam - ? Array.isArray(fileParam) - ? fileParam - : [fileParam] - : undefined return { ...commonParams, channelId: params.channelId, content: params.content, - files: normalizedFiles, + files: normalizeFileInput(params.attachmentFiles || params.files), } } case 'discord_get_messages': diff --git a/apps/sim/blocks/blocks/jira.ts b/apps/sim/blocks/blocks/jira.ts index c2e64ce1e..3d67b3902 100644 --- a/apps/sim/blocks/blocks/jira.ts +++ b/apps/sim/blocks/blocks/jira.ts @@ -1,6 +1,7 @@ import { JiraIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' import { AuthMode } from '@/blocks/types' +import { normalizeFileInput } from '@/blocks/utils' import type { JiraResponse } from '@/tools/jira/types' import { getTrigger } from '@/triggers' @@ -869,11 +870,10 @@ Return ONLY the comment text - no explanations.`, if (!effectiveIssueKey) { throw new Error('Issue Key is required to add attachments.') } - const fileParam = params.attachmentFiles || params.files - if (!fileParam || (Array.isArray(fileParam) && fileParam.length === 0)) { + const normalizedFiles = normalizeFileInput(params.attachmentFiles || params.files) + if (!normalizedFiles || normalizedFiles.length === 0) { throw new Error('At least one attachment file is required.') } - const normalizedFiles = Array.isArray(fileParam) ? fileParam : [fileParam] return { ...baseParams, issueKey: effectiveIssueKey, diff --git a/apps/sim/blocks/blocks/microsoft_teams.ts b/apps/sim/blocks/blocks/microsoft_teams.ts index 04cb2d242..44324e426 100644 --- a/apps/sim/blocks/blocks/microsoft_teams.ts +++ b/apps/sim/blocks/blocks/microsoft_teams.ts @@ -1,6 +1,7 @@ import { MicrosoftTeamsIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' import { AuthMode } from '@/blocks/types' +import { normalizeFileInput } from '@/blocks/utils' import type { MicrosoftTeamsResponse } from '@/tools/microsoft_teams/types' import { getTrigger } from '@/triggers' @@ -344,10 +345,9 @@ export const MicrosoftTeamsBlock: BlockConfig = { } // Add files if provided - const fileParam = attachmentFiles || files - if (fileParam && (operation === 'write_chat' || operation === 'write_channel')) { - const normalizedFiles = Array.isArray(fileParam) ? fileParam : [fileParam] - if (normalizedFiles.length > 0) { + if (operation === 'write_chat' || operation === 'write_channel') { + const normalizedFiles = normalizeFileInput(attachmentFiles || files) + if (normalizedFiles) { baseParams.files = normalizedFiles } } diff --git a/apps/sim/blocks/blocks/slack.ts b/apps/sim/blocks/blocks/slack.ts index 0ce640032..68e0a7a27 100644 --- a/apps/sim/blocks/blocks/slack.ts +++ b/apps/sim/blocks/blocks/slack.ts @@ -1,6 +1,7 @@ import { SlackIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' import { AuthMode } from '@/blocks/types' +import { normalizeFileInput } from '@/blocks/utils' import type { SlackResponse } from '@/tools/slack/types' import { getTrigger } from '@/triggers' @@ -620,12 +621,9 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`, if (threadTs) { baseParams.thread_ts = threadTs } - const fileParam = attachmentFiles || files - if (fileParam) { - const normalizedFiles = Array.isArray(fileParam) ? fileParam : [fileParam] - if (normalizedFiles.length > 0) { - baseParams.files = normalizedFiles - } + const normalizedFiles = normalizeFileInput(attachmentFiles || files) + if (normalizedFiles) { + baseParams.files = normalizedFiles } break } diff --git a/apps/sim/blocks/blocks/telegram.ts b/apps/sim/blocks/blocks/telegram.ts index 65b18677a..8cdb9ae72 100644 --- a/apps/sim/blocks/blocks/telegram.ts +++ b/apps/sim/blocks/blocks/telegram.ts @@ -1,6 +1,7 @@ import { TelegramIcon } from '@/components/icons' import type { BlockConfig } from '@/blocks/types' import { AuthMode } from '@/blocks/types' +import { normalizeFileInput } from '@/blocks/utils' import type { TelegramResponse } from '@/tools/telegram/types' import { getTrigger } from '@/triggers' @@ -312,16 +313,9 @@ export const TelegramBlock: BlockConfig = { } } case 'telegram_send_document': { - // Handle file upload - const fileParam = params.attachmentFiles || params.files - const normalizedFiles = fileParam - ? Array.isArray(fileParam) - ? fileParam - : [fileParam] - : undefined return { ...commonParams, - files: normalizedFiles, + files: normalizeFileInput(params.attachmentFiles || params.files), caption: params.caption, } } diff --git a/apps/sim/blocks/utils.ts b/apps/sim/blocks/utils.ts index 52ddbf3b9..cb7d5b418 100644 --- a/apps/sim/blocks/utils.ts +++ b/apps/sim/blocks/utils.ts @@ -249,3 +249,37 @@ export function createVersionedToolSelector> } } } + +/** + * Normalizes file input from block params. + * Handles the case where template resolution JSON.stringify's arrays/objects + * when they're placed in short-input fields (advanced mode). + * + * @param fileParam - The file parameter which could be: + * - undefined/null (no files) + * - An array of file objects (basic mode or properly resolved) + * - A single file object + * - A JSON string of file(s) (from advanced mode template resolution) + * @returns Normalized array of file objects, or undefined if no files + */ +export function normalizeFileInput(fileParam: unknown): object[] | undefined { + if (!fileParam) return undefined + + if (typeof fileParam === 'string') { + try { + fileParam = JSON.parse(fileParam) + } catch { + return undefined + } + } + + if (Array.isArray(fileParam)) { + return fileParam.length > 0 ? fileParam : undefined + } + + if (typeof fileParam === 'object' && fileParam !== null) { + return [fileParam] + } + + return undefined +}