import { createLogger } from '@sim/logger' import { toError } from '@sim/utils/errors' import { getBlock } from '@/blocks/index' import { isMcpTool } from '@/executor/constants' import type { BlockHandler, ExecutionContext } from '@/executor/types' import type { SerializedBlock } from '@/serializer/types' import { executeTool } from '@/tools' import { getTool } from '@/tools/utils' const logger = createLogger('GenericBlockHandler') export class GenericBlockHandler implements BlockHandler { canHandle(block: SerializedBlock): boolean { return true } async execute( ctx: ExecutionContext, block: SerializedBlock, inputs: Record ): Promise { const isMcp = block.config.tool ? isMcpTool(block.config.tool) : false let tool = null if (!isMcp) { tool = getTool(block.config.tool) if (!tool) { throw new Error(`Tool not found: ${block.config.tool}`) } } let finalInputs = { ...inputs } const blockType = block.metadata?.id if (blockType) { const blockConfig = getBlock(blockType) if (blockConfig?.tools?.config?.params) { const transformedParams = blockConfig.tools.config.params(inputs) finalInputs = { ...inputs, ...transformedParams } } if (blockConfig?.inputs) { for (const [key, inputSchema] of Object.entries(blockConfig.inputs)) { const value = finalInputs[key] if (typeof value === 'string' && value.trim().length > 0) { const inputType = typeof inputSchema === 'object' ? inputSchema.type : inputSchema if (inputType === 'json' || inputType === 'array') { try { finalInputs[key] = JSON.parse(value.trim()) } catch (error) { logger.warn(`Failed to parse ${inputType} field "${key}":`, { error: toError(error).message, }) } } } } } } try { const result = await executeTool( block.config.tool, { ...finalInputs, _context: { workflowId: ctx.workflowId, workspaceId: ctx.workspaceId, executionId: ctx.executionId, userId: ctx.userId, isDeployedContext: ctx.isDeployedContext, enforceCredentialAccess: ctx.enforceCredentialAccess, }, }, { executionContext: ctx } ) if (!result.success) { const errorDetails = [] if (result.error) errorDetails.push(result.error) const errorMessage = errorDetails.length > 0 ? errorDetails.join(' - ') : `Block execution of ${tool?.name || block.config.tool} failed with no error message` const error = new Error(errorMessage) Object.assign(error, { toolId: block.config.tool, toolName: tool?.name || 'Unknown tool', blockId: block.id, blockName: block.metadata?.name || 'Unnamed Block', output: result.output || {}, timestamp: new Date().toISOString(), }) throw error } return result.output } catch (error: any) { if (!error.message || error.message === 'undefined (undefined)') { let errorMessage = `Block execution of ${tool?.name || block.config.tool} failed` if (block.metadata?.name) { errorMessage += `: ${block.metadata.name}` } if (error.status) { errorMessage += ` (Status: ${error.status})` } error.message = errorMessage } if (typeof error === 'object' && error !== null) { if (!error.toolId) error.toolId = block.config.tool if (!error.blockName) error.blockName = block.metadata?.name || 'Unnamed Block' } throw error } } }