From c519034c8d913af7aba3060cee4b1efa31aba2e0 Mon Sep 17 00:00:00 2001 From: Vikhyath Mondreti Date: Wed, 4 Feb 2026 00:02:39 -0800 Subject: [PATCH] make run from block consistent --- .../hooks/use-workflow-execution.ts | 98 +++++++++++++++---- apps/sim/lib/mcp/shared.ts | 4 +- 2 files changed, 83 insertions(+), 19 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts index 992e0ce7e..294ead137 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution.ts @@ -1058,25 +1058,58 @@ export function useWorkflowExecution() { endedAt, }) - // Update existing console entry (created in onBlockStarted) with error data - updateConsole( - data.blockId, - { + // Check if entry exists (created in onBlockStarted) + // For container blocks like loops/parallels that fail during initialization, + // onBlockStarted is never called, so we need to create the entry here + const existingEntries = useTerminalConsoleStore.getState().entries + const hasExistingEntry = existingEntries.some( + (entry) => entry.blockId === data.blockId && entry.executionId === executionId + ) + + if (hasExistingEntry) { + // Update existing console entry + updateConsole( + data.blockId, + { + input: data.input || {}, + replaceOutput: {}, + success: false, + error: data.error, + durationMs: data.durationMs, + startedAt, + endedAt, + isRunning: false, + // Pass through iteration context for subflow grouping + iterationCurrent: data.iterationCurrent, + iterationTotal: data.iterationTotal, + iterationType: data.iterationType, + }, + executionId + ) + } else { + // Create new console entry for blocks that failed before starting + // (e.g., loop/parallel blocks with invalid configuration) + addConsole({ input: data.input || {}, - replaceOutput: {}, + output: {}, success: false, error: data.error, - durationMs: data.durationMs, - startedAt, - endedAt, + durationMs: data.durationMs || 0, + startedAt: startedAt || new Date().toISOString(), + executionOrder: data.executionOrder, + endedAt: endedAt || new Date().toISOString(), + workflowId: activeWorkflowId, + blockId: data.blockId, + executionId, + blockName: data.blockName || 'Unknown Block', + blockType: data.blockType || 'unknown', isRunning: false, // Pass through iteration context for subflow grouping iterationCurrent: data.iterationCurrent, iterationTotal: data.iterationTotal, iterationType: data.iterationType, - }, - executionId - ) + }) + } }, onStreamChunk: (data) => { @@ -1192,8 +1225,10 @@ export function useWorkflowExecution() { // Only add workflow-level error entry for: // 1. Pre-execution errors (validation) - no blocks ran - // 2. Timeout errors - no block has the error + // 2. Workflow-level errors (timeout, etc.) - no block has the error if (isPreExecutionError || !blockAlreadyHasError) { + // Determine if this is a timeout error based on the error message + const isTimeout = data.error?.toLowerCase().includes('timed out') addConsole({ input: {}, output: {}, @@ -1204,9 +1239,17 @@ export function useWorkflowExecution() { executionOrder: isPreExecutionError ? 0 : Number.MAX_SAFE_INTEGER, endedAt: new Date().toISOString(), workflowId: activeWorkflowId, - blockId: isPreExecutionError ? 'validation' : 'timeout-error', + blockId: isPreExecutionError + ? 'validation' + : isTimeout + ? 'timeout-error' + : 'execution-error', executionId, - blockName: isPreExecutionError ? 'Workflow Validation' : 'Timeout Error', + blockName: isPreExecutionError + ? 'Workflow Validation' + : isTimeout + ? 'Timeout Error' + : 'Execution Error', blockType: isPreExecutionError ? 'validation' : 'error', }) } @@ -1786,8 +1829,10 @@ export function useWorkflowExecution() { // Check if any block already has an error - don't duplicate block errors const blockAlreadyHasError = accumulatedBlockLogs.some((log) => log.error) - // Only add timeout error entry if no block has the error + // Only add execution error entry if no block has the error if (!blockAlreadyHasError) { + // Determine if this is a timeout error based on the error message + const isTimeout = data.error?.toLowerCase().includes('timed out') addConsole({ input: {}, output: {}, @@ -1798,16 +1843,33 @@ export function useWorkflowExecution() { executionOrder: Number.MAX_SAFE_INTEGER, endedAt: new Date().toISOString(), workflowId, - blockId: 'timeout-error', + blockId: isTimeout ? 'timeout-error' : 'execution-error', executionId, - blockName: 'Timeout Error', + blockName: isTimeout ? 'Timeout Error' : 'Execution Error', blockType: 'error', }) } }, - onExecutionCancelled: () => { + onExecutionCancelled: (data) => { cancelRunningEntries(workflowId) + + // Add console entry for cancellation + addConsole({ + input: {}, + output: {}, + success: false, + error: 'Execution was cancelled', + durationMs: data?.duration || 0, + startedAt: new Date(Date.now() - (data?.duration || 0)).toISOString(), + executionOrder: Number.MAX_SAFE_INTEGER, + endedAt: new Date().toISOString(), + workflowId, + blockId: 'cancelled', + executionId, + blockName: 'Execution Cancelled', + blockType: 'cancelled', + }) }, }, }) diff --git a/apps/sim/lib/mcp/shared.ts b/apps/sim/lib/mcp/shared.ts index 33d844199..eaecff1f0 100644 --- a/apps/sim/lib/mcp/shared.ts +++ b/apps/sim/lib/mcp/shared.ts @@ -32,9 +32,11 @@ export function sanitizeHeaders( /** * Client-safe MCP constants + * Note: CLIENT_TIMEOUT should match DEFAULT_EXECUTION_TIMEOUT_MS from @/lib/core/execution-limits + * (5 minutes = 300 seconds for free tier). Keep in sync if that value changes. */ export const MCP_CLIENT_CONSTANTS = { - CLIENT_TIMEOUT: 5 * 60 * 1000, + CLIENT_TIMEOUT: 5 * 60 * 1000, // 5 minutes - matches DEFAULT_EXECUTION_TIMEOUT_MS MAX_RETRIES: 3, RECONNECT_DELAY: 1000, } as const