diff --git a/apps/sim/app/resume/[workflowId]/[executionId]/resume-page-client.tsx b/apps/sim/app/resume/[workflowId]/[executionId]/resume-page-client.tsx
index 0c0a5ece36..3edd059aaf 100644
--- a/apps/sim/app/resume/[workflowId]/[executionId]/resume-page-client.tsx
+++ b/apps/sim/app/resume/[workflowId]/[executionId]/resume-page-client.tsx
@@ -6,7 +6,6 @@ import { useRouter } from 'next/navigation'
import {
Badge,
Button,
- Code,
Input,
Label,
Table,
@@ -777,15 +776,6 @@ export default function ResumeExecutionPage({
refreshSelectedDetail,
])
- const pauseResponsePreview = useMemo(() => {
- if (!selectedDetail?.pausePoint.response?.data) return '{}'
- try {
- return JSON.stringify(selectedDetail.pausePoint.response.data, null, 2)
- } catch {
- return String(selectedDetail.pausePoint.response.data)
- }
- }, [selectedDetail])
-
const isFormComplete = useMemo(() => {
if (!isHumanMode || !hasInputFormat) return true
return inputFormatFields.every((field) => {
@@ -1155,10 +1145,12 @@ export default function ResumeExecutionPage({
borderBottom: '1px solid var(--border)',
}}
>
-
+
-
+
+ No display data configured
+
)}
diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tag-dropdown/tag-dropdown.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tag-dropdown/tag-dropdown.tsx
index b58752deee..17b50aad25 100644
--- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tag-dropdown/tag-dropdown.tsx
+++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/editor/components/sub-block/components/tag-dropdown/tag-dropdown.tsx
@@ -1183,19 +1183,6 @@ export const TagDropdown: React.FC = ({
const outputPaths = getBlockOutputPaths(sourceBlock.type, mergedSubBlocks, true)
blockTags = outputPaths.map((path) => `${normalizedBlockName}.${path}`)
}
- } else if (sourceBlock.type === 'approval') {
- const dynamicOutputs = getBlockOutputPaths(sourceBlock.type, mergedSubBlocks)
-
- const isSelfReference = activeSourceBlockId === blockId
-
- if (dynamicOutputs.length > 0) {
- const allTags = dynamicOutputs.map((path) => `${normalizedBlockName}.${path}`)
- blockTags = isSelfReference ? allTags.filter((tag) => tag.endsWith('.url')) : allTags
- } else {
- const outputPaths = getBlockOutputPaths(sourceBlock.type, mergedSubBlocks)
- const allTags = outputPaths.map((path) => `${normalizedBlockName}.${path}`)
- blockTags = isSelfReference ? allTags.filter((tag) => tag.endsWith('.url')) : allTags
- }
} else if (sourceBlock.type === 'human_in_the_loop') {
const dynamicOutputs = getBlockOutputPaths(sourceBlock.type, mergedSubBlocks)
@@ -1400,13 +1387,8 @@ export const TagDropdown: React.FC = ({
if (!accessibleBlock) continue
// Skip the current block - blocks cannot reference their own outputs
- // Exception: approval and human_in_the_loop blocks can reference their own outputs
- if (
- accessibleBlockId === blockId &&
- accessibleBlock.type !== 'approval' &&
- accessibleBlock.type !== 'human_in_the_loop'
- )
- continue
+ // Exception: human_in_the_loop blocks can reference their own outputs (url, resumeEndpoint)
+ if (accessibleBlockId === blockId && accessibleBlock.type !== 'human_in_the_loop') continue
const blockConfig = getBlock(accessibleBlock.type)
@@ -1520,19 +1502,6 @@ export const TagDropdown: React.FC = ({
const outputPaths = getBlockOutputPaths(accessibleBlock.type, mergedSubBlocks, true)
blockTags = outputPaths.map((path) => `${normalizedBlockName}.${path}`)
}
- } else if (accessibleBlock.type === 'approval') {
- const dynamicOutputs = getBlockOutputPaths(accessibleBlock.type, mergedSubBlocks)
-
- const isSelfReference = accessibleBlockId === blockId
-
- if (dynamicOutputs.length > 0) {
- const allTags = dynamicOutputs.map((path) => `${normalizedBlockName}.${path}`)
- blockTags = isSelfReference ? allTags.filter((tag) => tag.endsWith('.url')) : allTags
- } else {
- const outputPaths = getBlockOutputPaths(accessibleBlock.type, mergedSubBlocks)
- const allTags = outputPaths.map((path) => `${normalizedBlockName}.${path}`)
- blockTags = isSelfReference ? allTags.filter((tag) => tag.endsWith('.url')) : allTags
- }
} else if (accessibleBlock.type === 'human_in_the_loop') {
const dynamicOutputs = getBlockOutputPaths(accessibleBlock.type, mergedSubBlocks)
diff --git a/apps/sim/blocks/blocks/agent.ts b/apps/sim/blocks/blocks/agent.ts
index 6b4fd0efba..5606406c83 100644
--- a/apps/sim/blocks/blocks/agent.ts
+++ b/apps/sim/blocks/blocks/agent.ts
@@ -769,7 +769,13 @@ Example 3 (Array Input):
outputs: {
content: { type: 'string', description: 'Generated response content' },
model: { type: 'string', description: 'Model used for generation' },
- tokens: { type: 'any', description: 'Token usage statistics' },
- toolCalls: { type: 'any', description: 'Tool calls made' },
+ tokens: { type: 'json', description: 'Token usage statistics' },
+ toolCalls: { type: 'json', description: 'Tool calls made' },
+ providerTiming: {
+ type: 'json',
+ description: 'Provider timing information',
+ hiddenFromDisplay: true,
+ },
+ cost: { type: 'number', description: 'Cost of the API call', hiddenFromDisplay: true },
},
}
diff --git a/apps/sim/blocks/blocks/human_in_the_loop.ts b/apps/sim/blocks/blocks/human_in_the_loop.ts
index df3d24a481..e1765ee5b5 100644
--- a/apps/sim/blocks/blocks/human_in_the_loop.ts
+++ b/apps/sim/blocks/blocks/human_in_the_loop.ts
@@ -162,5 +162,21 @@ export const HumanInTheLoopBlock: BlockConfig = {
type: 'string',
description: 'Resume API endpoint URL for direct curl requests',
},
+ response: {
+ type: 'json',
+ description: 'Display data shown to the approver',
+ hiddenFromDisplay: true,
+ },
+ submission: {
+ type: 'json',
+ description: 'Form submission data from the approver',
+ hiddenFromDisplay: true,
+ },
+ resumeInput: {
+ type: 'json',
+ description: 'Raw input data submitted when resuming',
+ hiddenFromDisplay: true,
+ },
+ submittedAt: { type: 'string', description: 'ISO timestamp when the workflow was resumed' },
},
}
diff --git a/apps/sim/blocks/blocks/router.ts b/apps/sim/blocks/blocks/router.ts
index fa086becb4..7da50ed98d 100644
--- a/apps/sim/blocks/blocks/router.ts
+++ b/apps/sim/blocks/blocks/router.ts
@@ -247,6 +247,7 @@ export const RouterBlock: BlockConfig = {
tokens: { type: 'json', description: 'Token usage' },
cost: { type: 'json', description: 'Cost information' },
selectedPath: { type: 'json', description: 'Selected routing path' },
+ selectedRoute: { type: 'string', description: 'Selected route ID' },
},
}
diff --git a/apps/sim/blocks/blocks/workflow.ts b/apps/sim/blocks/blocks/workflow.ts
index b1a5056b13..d30ab4c6d3 100644
--- a/apps/sim/blocks/blocks/workflow.ts
+++ b/apps/sim/blocks/blocks/workflow.ts
@@ -44,6 +44,11 @@ export const WorkflowBlock: BlockConfig = {
childWorkflowName: { type: 'string', description: 'Child workflow name' },
result: { type: 'json', description: 'Workflow execution result' },
error: { type: 'string', description: 'Error message' },
+ childTraceSpans: {
+ type: 'json',
+ description: 'Child workflow trace spans',
+ hiddenFromDisplay: true,
+ },
},
hideFromToolbar: true,
}
diff --git a/apps/sim/blocks/blocks/workflow_input.ts b/apps/sim/blocks/blocks/workflow_input.ts
index 73e3c833b6..24c3b3f670 100644
--- a/apps/sim/blocks/blocks/workflow_input.ts
+++ b/apps/sim/blocks/blocks/workflow_input.ts
@@ -43,5 +43,10 @@ export const WorkflowInputBlock: BlockConfig = {
childWorkflowName: { type: 'string', description: 'Child workflow name' },
result: { type: 'json', description: 'Workflow execution result' },
error: { type: 'string', description: 'Error message' },
+ childTraceSpans: {
+ type: 'json',
+ description: 'Child workflow trace spans',
+ hiddenFromDisplay: true,
+ },
},
}
diff --git a/apps/sim/blocks/types.ts b/apps/sim/blocks/types.ts
index cbfd20ba3a..0c03f9536d 100644
--- a/apps/sim/blocks/types.ts
+++ b/apps/sim/blocks/types.ts
@@ -157,8 +157,19 @@ export type OutputFieldDefinition =
* Uses the same condition format as subBlocks.
*/
condition?: OutputCondition
+ /**
+ * If true, this output is hidden from display in the tag dropdown and logs,
+ * but still available for resolution and execution.
+ */
+ hiddenFromDisplay?: boolean
}
+export function isHiddenFromDisplay(def: unknown): boolean {
+ return Boolean(
+ def && typeof def === 'object' && 'hiddenFromDisplay' in def && def.hiddenFromDisplay
+ )
+}
+
export interface ParamConfig {
type: ParamType
description?: string
diff --git a/apps/sim/executor/constants.ts b/apps/sim/executor/constants.ts
index ba2c2fc23b..8cfbaed582 100644
--- a/apps/sim/executor/constants.ts
+++ b/apps/sim/executor/constants.ts
@@ -1,5 +1,16 @@
import type { LoopType, ParallelType } from '@/lib/workflows/types'
+/**
+ * Runtime-injected keys for trigger blocks that should be hidden from logs/display.
+ * These are added during execution but aren't part of the block's static output schema.
+ */
+export const TRIGGER_INTERNAL_KEYS = ['webhook', 'workflowId'] as const
+export type TriggerInternalKey = (typeof TRIGGER_INTERNAL_KEYS)[number]
+
+export function isTriggerInternalKey(key: string): key is TriggerInternalKey {
+ return TRIGGER_INTERNAL_KEYS.includes(key as TriggerInternalKey)
+}
+
export enum BlockType {
PARALLEL = 'parallel',
LOOP = 'loop',
diff --git a/apps/sim/executor/execution/block-executor.ts b/apps/sim/executor/execution/block-executor.ts
index 2cc37a77e4..f159e4db0d 100644
--- a/apps/sim/executor/execution/block-executor.ts
+++ b/apps/sim/executor/execution/block-executor.ts
@@ -11,8 +11,6 @@ import {
DEFAULTS,
EDGE,
isSentinelBlockType,
- isTriggerBehavior,
- isWorkflowBlockType,
} from '@/executor/constants'
import type { DAGNode } from '@/executor/dag/builder'
import { ChildWorkflowError } from '@/executor/errors/child-workflow-error'
@@ -30,6 +28,7 @@ import type {
} from '@/executor/types'
import { streamingResponseFormatProcessor } from '@/executor/utils'
import { buildBlockExecutionError, normalizeError } from '@/executor/utils/errors'
+import { filterOutputForLog } from '@/executor/utils/output-filter'
import { validateBlockType } from '@/executor/utils/permission-check'
import type { VariableResolver } from '@/executor/variables/resolver'
import type { SerializedBlock } from '@/serializer/types'
@@ -149,13 +148,15 @@ export class BlockExecutor {
blockLog.endedAt = new Date().toISOString()
blockLog.durationMs = duration
blockLog.success = true
- blockLog.output = this.filterOutputForLog(block, normalizedOutput)
+ blockLog.output = filterOutputForLog(block.metadata?.id || '', normalizedOutput, { block })
}
this.state.setBlockOutput(node.id, normalizedOutput, duration)
if (!isSentinel) {
- const displayOutput = this.filterOutputForDisplay(block, normalizedOutput)
+ const displayOutput = filterOutputForLog(block.metadata?.id || '', normalizedOutput, {
+ block,
+ })
this.callOnBlockComplete(ctx, node, block, resolvedInputs, displayOutput, duration)
}
@@ -233,7 +234,7 @@ export class BlockExecutor {
blockLog.success = false
blockLog.error = errorMessage
blockLog.input = input
- blockLog.output = this.filterOutputForLog(block, errorOutput)
+ blockLog.output = filterOutputForLog(block.metadata?.id || '', errorOutput, { block })
}
logger.error(
@@ -246,7 +247,7 @@ export class BlockExecutor {
)
if (!isSentinel) {
- const displayOutput = this.filterOutputForDisplay(block, errorOutput)
+ const displayOutput = filterOutputForLog(block.metadata?.id || '', errorOutput, { block })
this.callOnBlockComplete(ctx, node, block, input, displayOutput, duration)
}
@@ -335,51 +336,6 @@ export class BlockExecutor {
return { result: output }
}
- private filterOutputForLog(
- block: SerializedBlock,
- output: NormalizedBlockOutput
- ): NormalizedBlockOutput {
- const blockType = block.metadata?.id
-
- if (blockType === BlockType.HUMAN_IN_THE_LOOP) {
- const filtered: NormalizedBlockOutput = {}
- for (const [key, value] of Object.entries(output)) {
- if (key.startsWith('_')) continue
- if (key === 'response') continue
- filtered[key] = value
- }
- return filtered
- }
-
- if (isTriggerBehavior(block)) {
- const filtered: NormalizedBlockOutput = {}
- const internalKeys = ['webhook', 'workflowId']
- for (const [key, value] of Object.entries(output)) {
- if (internalKeys.includes(key)) continue
- filtered[key] = value
- }
- return filtered
- }
-
- return output
- }
-
- private filterOutputForDisplay(
- block: SerializedBlock,
- output: NormalizedBlockOutput
- ): NormalizedBlockOutput {
- const filtered = this.filterOutputForLog(block, output)
-
- if (isWorkflowBlockType(block.metadata?.id)) {
- const { childTraceSpans: _, ...displayOutput } = filtered as {
- childTraceSpans?: unknown
- } & Record
- return displayOutput
- }
-
- return filtered
- }
-
private callOnBlockStart(ctx: ExecutionContext, node: DAGNode, block: SerializedBlock): void {
const blockId = node.id
const blockName = block.metadata?.name ?? blockId
diff --git a/apps/sim/executor/handlers/trigger/trigger-handler.ts b/apps/sim/executor/handlers/trigger/trigger-handler.ts
index d9be91d233..e8d14f8a73 100644
--- a/apps/sim/executor/handlers/trigger/trigger-handler.ts
+++ b/apps/sim/executor/handlers/trigger/trigger-handler.ts
@@ -1,5 +1,5 @@
import { createLogger } from '@sim/logger'
-import { BlockType, isTriggerBehavior } from '@/executor/constants'
+import { BlockType, isTriggerBehavior, isTriggerInternalKey } from '@/executor/constants'
import type { BlockHandler, ExecutionContext } from '@/executor/types'
import type { SerializedBlock } from '@/serializer/types'
@@ -33,7 +33,12 @@ export class TriggerBlockHandler implements BlockHandler {
const starterOutput = starterState.output
if (starterOutput.webhook?.data) {
- const { webhook, workflowId, ...cleanOutput } = starterOutput
+ const cleanOutput: Record = {}
+ for (const [key, value] of Object.entries(starterOutput)) {
+ if (!isTriggerInternalKey(key)) {
+ cleanOutput[key] = value
+ }
+ }
return cleanOutput
}
diff --git a/apps/sim/executor/utils/output-filter.ts b/apps/sim/executor/utils/output-filter.ts
new file mode 100644
index 0000000000..ca1e2a933a
--- /dev/null
+++ b/apps/sim/executor/utils/output-filter.ts
@@ -0,0 +1,51 @@
+import { getBlock } from '@/blocks'
+import { isHiddenFromDisplay } from '@/blocks/types'
+import { isTriggerBehavior, isTriggerInternalKey } from '@/executor/constants'
+import type { NormalizedBlockOutput } from '@/executor/types'
+import type { SerializedBlock } from '@/serializer/types'
+
+/**
+ * Filters block output for logging/display purposes.
+ * Removes internal fields and fields marked with hiddenFromDisplay.
+ *
+ * @param blockType - The block type string (e.g., 'human_in_the_loop', 'workflow')
+ * @param output - The raw block output to filter
+ * @param options - Optional configuration
+ * @param options.block - Full SerializedBlock for trigger behavior detection
+ * @param options.additionalHiddenKeys - Extra keys to filter out (e.g., 'resume')
+ */
+export function filterOutputForLog(
+ blockType: string,
+ output: NormalizedBlockOutput,
+ options?: {
+ block?: SerializedBlock
+ additionalHiddenKeys?: string[]
+ }
+): NormalizedBlockOutput {
+ const blockConfig = blockType ? getBlock(blockType) : undefined
+ const filtered: NormalizedBlockOutput = {}
+ const additionalHiddenKeys = options?.additionalHiddenKeys ?? []
+
+ for (const [key, value] of Object.entries(output)) {
+ // Skip internal keys (underscore prefix)
+ if (key.startsWith('_')) continue
+
+ if (blockConfig?.outputs && isHiddenFromDisplay(blockConfig.outputs[key])) {
+ continue
+ }
+
+ // Skip runtime-injected trigger keys not in block config
+ if (options?.block && isTriggerBehavior(options.block) && isTriggerInternalKey(key)) {
+ continue
+ }
+
+ // Skip additional hidden keys specified by caller
+ if (additionalHiddenKeys.includes(key)) {
+ continue
+ }
+
+ filtered[key] = value
+ }
+
+ return filtered
+}
diff --git a/apps/sim/lib/copilot/process-contents.ts b/apps/sim/lib/copilot/process-contents.ts
index 3b62b9197c..ff1dbf497a 100644
--- a/apps/sim/lib/copilot/process-contents.ts
+++ b/apps/sim/lib/copilot/process-contents.ts
@@ -4,6 +4,7 @@ import { createLogger } from '@sim/logger'
import { and, eq, isNull } from 'drizzle-orm'
import { loadWorkflowFromNormalizedTables } from '@/lib/workflows/persistence/utils'
import { sanitizeForCopilot } from '@/lib/workflows/sanitization/json-sanitizer'
+import { isHiddenFromDisplay } from '@/blocks/types'
import { escapeRegExp } from '@/executor/constants'
import { getUserPermissionConfig } from '@/executor/utils/permission-check'
import type { ChatContext } from '@/stores/panel/copilot/types'
@@ -397,7 +398,11 @@ async function processBlockMetadata(
category: blockConfig.category,
bgColor: blockConfig.bgColor,
inputs: blockConfig.inputs || {},
- outputs: blockConfig.outputs || {},
+ outputs: blockConfig.outputs
+ ? Object.fromEntries(
+ Object.entries(blockConfig.outputs).filter(([_, def]) => !isHiddenFromDisplay(def))
+ )
+ : {},
tools: blockConfig.tools?.access || [],
hideFromToolbar: blockConfig.hideFromToolbar,
}
diff --git a/apps/sim/lib/copilot/tools/server/blocks/get-block-config.ts b/apps/sim/lib/copilot/tools/server/blocks/get-block-config.ts
index d1acfe336c..3d6ebba173 100644
--- a/apps/sim/lib/copilot/tools/server/blocks/get-block-config.ts
+++ b/apps/sim/lib/copilot/tools/server/blocks/get-block-config.ts
@@ -6,7 +6,7 @@ import {
type GetBlockConfigResultType,
} from '@/lib/copilot/tools/shared/schemas'
import { registry as blockRegistry, getLatestBlock } from '@/blocks/registry'
-import type { SubBlockConfig } from '@/blocks/types'
+import { isHiddenFromDisplay, type SubBlockConfig } from '@/blocks/types'
import { getUserPermissionConfig } from '@/executor/utils/permission-check'
import { PROVIDER_DEFINITIONS } from '@/providers/models'
import { tools as toolsRegistry } from '@/tools/registry'
@@ -310,6 +310,7 @@ function extractTriggerOutputs(blockConfig: any): Record !isHiddenFromDisplay(def))
+ )
+ : undefined
+
metadata = {
id: blockId,
name: blockConfig.name || blockId,
@@ -262,7 +267,7 @@ export const getBlocksMetadataServerTool: BaseServerTool<
triggers,
operationInputSchema: operationParameters,
operations,
- outputs: blockConfig.outputs,
+ outputs: filteredOutputs,
}
}
diff --git a/apps/sim/lib/workflows/blocks/block-outputs.ts b/apps/sim/lib/workflows/blocks/block-outputs.ts
index b00156e0cd..f943bd174b 100644
--- a/apps/sim/lib/workflows/blocks/block-outputs.ts
+++ b/apps/sim/lib/workflows/blocks/block-outputs.ts
@@ -16,7 +16,12 @@ import {
USER_FILE_PROPERTY_TYPES,
} from '@/lib/workflows/types'
import { getBlock } from '@/blocks'
-import type { BlockConfig, OutputCondition, OutputFieldDefinition } from '@/blocks/types'
+import {
+ type BlockConfig,
+ isHiddenFromDisplay,
+ type OutputCondition,
+ type OutputFieldDefinition,
+} from '@/blocks/types'
import { getTool } from '@/tools/utils'
import { getTrigger, isTriggerValid } from '@/triggers'
@@ -86,8 +91,8 @@ function evaluateOutputCondition(
}
/**
- * Filters outputs based on their conditions.
- * Returns a new OutputDefinition with only the outputs whose conditions are met.
+ * Filters outputs based on their conditions and hiddenFromDisplay flag.
+ * Returns a new OutputDefinition with only the outputs that should be shown.
*/
function filterOutputsByCondition(
outputs: OutputDefinition,
@@ -96,6 +101,8 @@ function filterOutputsByCondition(
const filtered: OutputDefinition = {}
for (const [key, value] of Object.entries(outputs)) {
+ if (isHiddenFromDisplay(value)) continue
+
if (!value || typeof value !== 'object' || !('condition' in value)) {
filtered[key] = value
continue
@@ -105,7 +112,7 @@ function filterOutputsByCondition(
const passes = !condition || evaluateOutputCondition(condition, subBlocks)
if (passes) {
- const { condition: _, ...rest } = value
+ const { condition: _, hiddenFromDisplay: __, ...rest } = value
filtered[key] = rest
}
}
@@ -259,50 +266,26 @@ export function getBlockOutputs(
}
if (blockType === 'human_in_the_loop') {
- const hitlOutputs: OutputDefinition = {
- url: { type: 'string', description: 'Resume UI URL' },
- resumeEndpoint: {
- type: 'string',
- description: 'Resume API endpoint URL for direct curl requests',
- },
- }
-
- const normalizedInputFormat = normalizeInputFormatValue(subBlocks?.inputFormat?.value)
-
- for (const field of normalizedInputFormat) {
- const fieldName = field?.name?.trim()
- if (!fieldName) continue
-
- hitlOutputs[fieldName] = {
- type: (field?.type || 'any') as any,
- description: `Field from resume form`,
- }
- }
-
- return hitlOutputs
- }
-
- if (blockType === 'approval') {
- // Start with only url (apiUrl commented out - not accessible as output)
- const pauseResumeOutputs: OutputDefinition = {
- url: { type: 'string', description: 'Resume UI URL' },
- // apiUrl: { type: 'string', description: 'Resume API URL' }, // Commented out - not accessible as output
- }
+ // Start with block config outputs (respects hiddenFromDisplay via filterOutputsByCondition)
+ const baseOutputs = filterOutputsByCondition(
+ { ...(blockConfig.outputs || {}) } as OutputDefinition,
+ subBlocks
+ )
+ // Add inputFormat fields (resume form fields)
const normalizedInputFormat = normalizeInputFormatValue(subBlocks?.inputFormat?.value)
- // Add each input format field as a top-level output
for (const field of normalizedInputFormat) {
const fieldName = field?.name?.trim()
if (!fieldName) continue
- pauseResumeOutputs[fieldName] = {
+ baseOutputs[fieldName] = {
type: (field?.type || 'any') as any,
- description: `Field from input format`,
+ description: field?.description || `Field from resume form`,
}
}
- return pauseResumeOutputs
+ return baseOutputs
}
if (startPath === StartBlockPath.LEGACY_STARTER) {
diff --git a/apps/sim/lib/workflows/executor/human-in-the-loop-manager.ts b/apps/sim/lib/workflows/executor/human-in-the-loop-manager.ts
index fe936920e5..479ead99ac 100644
--- a/apps/sim/lib/workflows/executor/human-in-the-loop-manager.ts
+++ b/apps/sim/lib/workflows/executor/human-in-the-loop-manager.ts
@@ -9,6 +9,7 @@ import { LoggingSession } from '@/lib/logs/execution/logging-session'
import { executeWorkflowCore } from '@/lib/workflows/executor/execution-core'
import { ExecutionSnapshot } from '@/executor/execution/snapshot'
import type { ExecutionResult, PausePoint, SerializedSnapshot } from '@/executor/types'
+import { filterOutputForLog } from '@/executor/utils/output-filter'
import type { SerializedConnection } from '@/serializer/types'
const logger = createLogger('HumanInTheLoopManager')
@@ -576,13 +577,11 @@ export class PauseResumeManager {
log.blockId === contextId
)
if (blockLogIndex !== -1) {
- // Filter output for logging (exclude internal fields and response)
- const filteredOutput: Record = {}
- for (const [key, value] of Object.entries(mergedOutput)) {
- if (key.startsWith('_')) continue
- if (key === 'response') continue
- filteredOutput[key] = value
- }
+ // Filter output for logging using shared utility
+ // 'resume' is redundant with url/resumeEndpoint so we filter it out
+ const filteredOutput = filterOutputForLog('human_in_the_loop', mergedOutput, {
+ additionalHiddenKeys: ['resume'],
+ })
stateCopy.blockLogs[blockLogIndex] = {
...stateCopy.blockLogs[blockLogIndex],
blockId: stateBlockKey,