import { getEffectiveBlockOutputs } from '@/lib/workflows/blocks/block-outputs' import { hasTriggerCapability } from '@/lib/workflows/triggers/trigger-utils' import { getBlock } from '@/blocks/registry' import { isTriggerBehavior, normalizeName } from '@/executor/constants' import type { ExecutionContext } from '@/executor/types' import type { OutputSchema } from '@/executor/utils/block-reference' import { extractBaseBlockId, extractBranchIndex, isBranchNodeId, } from '@/executor/utils/subflow-utils' import type { SerializedBlock } from '@/serializer/types' export interface BlockDataCollection { blockData: Record blockNameMapping: Record blockOutputSchemas: Record } interface SubBlockWithValue { value?: unknown } function paramsToSubBlocks( params: Record | undefined ): Record { if (!params) return {} const subBlocks: Record = {} for (const [key, value] of Object.entries(params)) { subBlocks[key] = { value } } return subBlocks } function getRegistrySchema(block: SerializedBlock): OutputSchema | undefined { const blockType = block.metadata?.id if (!blockType) return undefined const subBlocks = paramsToSubBlocks(block.config?.params) const blockConfig = getBlock(blockType) const isTriggerCapable = blockConfig ? hasTriggerCapability(blockConfig) : false const triggerMode = Boolean(isTriggerBehavior(block) && isTriggerCapable) const outputs = getEffectiveBlockOutputs(blockType, subBlocks, { triggerMode, preferToolOutputs: !triggerMode, includeHidden: true, }) as OutputSchema if (!outputs || Object.keys(outputs).length === 0) { return undefined } return outputs } export function getBlockSchema(block: SerializedBlock): OutputSchema | undefined { return getRegistrySchema(block) } export function collectBlockData( ctx: ExecutionContext, currentNodeId?: string ): BlockDataCollection { const blockData: Record = {} const blockNameMapping: Record = {} const blockOutputSchemas: Record = {} const branchIndex = currentNodeId && isBranchNodeId(currentNodeId) ? extractBranchIndex(currentNodeId) : null for (const [id, state] of ctx.blockStates.entries()) { if (state.output !== undefined) { blockData[id] = state.output if (branchIndex !== null && isBranchNodeId(id)) { const stateBranchIndex = extractBranchIndex(id) if (stateBranchIndex === branchIndex) { const baseId = extractBaseBlockId(id) if (blockData[baseId] === undefined) { blockData[baseId] = state.output } } } } } const workflowBlocks = ctx.workflow?.blocks ?? [] for (const block of workflowBlocks) { const id = block.id if (block.metadata?.name) { blockNameMapping[normalizeName(block.metadata.name)] = id } const schema = getBlockSchema(block) if (schema && Object.keys(schema).length > 0) { blockOutputSchemas[id] = schema } } return { blockData, blockNameMapping, blockOutputSchemas } }