@doclo/flows 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/flow-builder.ts","../src/flow-registry.ts","../src/serialization.ts","../src/composite-nodes.ts","../src/validation.ts","../src/multi-provider-flow.ts","../src/vlm-direct-flow.ts"],"sourcesContent":["import { runPipeline, type OCRProvider, type LLMJsonProvider, type DocumentIR } from \"@doclo/core\";\nimport { parseNode, extractNode } from \"@doclo/nodes\";\nimport { simpleSchema } from \"./schemas\";\n\n// Export schemas\nexport * from \"./schemas\";\n\n// Export new flow builder API\nexport {\n createFlow,\n isSingleFlowResult,\n isBatchFlowResult,\n type FlowContext,\n type FlowProgressCallbacks,\n type FlowValidationResult,\n type BuiltFlow,\n type FlowOptions,\n type FlowRunOptions,\n type BatchFlowResult,\n} from \"./flow-builder\";\nexport { parse, split, categorize, extract, chunk, combine, trigger } from \"@doclo/nodes\";\n\n// Re-export observability types for flow hooks\nexport type {\n ObservabilityConfig,\n FlowStartContext,\n FlowEndContext,\n FlowErrorContext,\n FlowStats,\n StepStartContext,\n StepEndContext,\n StepErrorContext,\n ConsensusStartContext,\n ConsensusRunContext,\n ConsensusCompleteContext,\n BatchStartContext,\n BatchItemContext,\n BatchItemEndContext,\n BatchEndContext,\n ProviderRequestContext,\n ProviderResponseContext,\n ProviderRetryContext,\n CircuitBreakerContext,\n TraceContext,\n ExecutionContext,\n CustomMetric,\n} from \"@doclo/core/observability\";\n\n// Export flow registry\nexport {\n FLOW_REGISTRY,\n registerFlow,\n getFlow,\n hasFlow,\n unregisterFlow,\n clearRegistry,\n listFlows,\n getFlowCount,\n type FlowBuilder\n} from \"./flow-registry\";\n\n// Export serialization\nexport * from \"./serialization\";\n\n// Export composite nodes\nexport * from \"./composite-nodes\";\n\n// Export validation\nexport * from \"./validation\";\n\n// Re-export utilities from core for convenience\nexport { bufferToDataUri, bufferToBase64 } from \"@doclo/core\";\n\n// Export legacy flows (kept as examples)\nexport { buildMultiProviderFlow } from \"./multi-provider-flow\";\nexport { buildVLMDirectFlow } from \"./vlm-direct-flow\";\n\nexport function buildTwoProviderFlow(opts: { ocr: OCRProvider; llmA: LLMJsonProvider; llmB: LLMJsonProvider }) {\n const parse = parseNode({ ocr: opts.ocr });\n\n const mkPrompt = (ir: DocumentIR) =>\n`Extract JSON matching the schema fields: vessel, port, quantity_mt.\nDocument (first page preview):\n${ir.pages[0]?.lines.slice(0, 50).map(l => l.text).join('\\n')}`;\n\n const extractA = extractNode({ llm: opts.llmA, schema: simpleSchema, makePrompt: mkPrompt });\n const extractB = extractNode({ llm: opts.llmB, schema: simpleSchema, makePrompt: mkPrompt });\n\n return {\n async run(input: { url?: string; base64?: string }) {\n const parsed = await runPipeline([parse], input);\n const ir = parsed.output as DocumentIR;\n\n const [resA, resB] = await Promise.all([\n runPipeline([extractA], ir),\n runPipeline([extractB], ir)\n ]);\n\n return {\n ir,\n outputA: resA.output,\n outputB: resB.output,\n metrics: [...parsed.metrics, ...resA.metrics, ...resB.metrics],\n artifacts: {\n parse: parsed.artifacts.parse,\n extractA: resA.artifacts.extract,\n extractB: resB.artifacts.extract\n }\n };\n }\n };\n}\n","import {\n runPipeline,\n FlowExecutionError,\n aggregateMetrics,\n getNodeTypeName,\n validateNodeConnection,\n getSuggestedConnections,\n canStartForEachItemFlow,\n getValidForEachStarters,\n getProviderById,\n validateFlowInputFormat,\n type NodeDef,\n type FlowInput,\n type FlowInputValidation,\n type FlowResult,\n type StepMetric,\n type FlowContext,\n type NodeTypeName,\n type NodeCtx,\n type OutputNodeConfig,\n type AcceptedMimeType,\n type FlowStepLocation\n} from \"@doclo/core\";\nimport { shouldSkipValidation } from \"@doclo/core/runtime/env\";\n\nimport { output as createOutputNode } from \"@doclo/nodes\";\n\nimport type {\n ObservabilityConfig,\n ExecutionContext,\n TraceContext,\n FlowStartContext,\n FlowEndContext,\n FlowErrorContext,\n FlowStats,\n StepStartContext,\n StepEndContext,\n StepErrorContext,\n BatchStartContext,\n BatchItemContext,\n BatchItemEndContext,\n BatchEndContext,\n} from \"@doclo/core/observability\";\n\nimport {\n mergeConfig,\n shouldSample,\n TraceContextManager,\n generateExecutionId,\n executeHook,\n buildStepAttributes,\n generateSpanId,\n} from \"@doclo/core/observability\";\n\n/**\n * Progress callback options for flow execution\n */\nexport interface FlowProgressCallbacks {\n /** Called when a step starts execution */\n onStepStart?: (stepId: string, stepIndex: number, stepType: string) => void;\n /** Called when a step completes successfully */\n onStepComplete?: (stepId: string, stepIndex: number, stepType: string, durationMs: number) => void;\n /** Called when a step fails with an error */\n onStepError?: (stepId: string, stepIndex: number, stepType: string, error: Error) => void;\n}\n\n/**\n * Validation error for a flow step\n */\nexport interface FlowValidationError {\n stepId: string;\n stepIndex: number;\n stepType: string;\n message: string;\n}\n\n/**\n * Result of flow validation\n */\nexport interface FlowValidationResult {\n valid: boolean;\n errors: FlowValidationError[];\n warnings: string[];\n}\n\n// FlowContext is now exported from @doclo/core\nexport type { FlowContext } from \"@doclo/core\";\n\n/**\n * Batch result type returned when flow has multiple outputs\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type BatchFlowResult = { results: FlowResult<any>[] };\n\n/**\n * Type representing the built flow object returned by Flow.build()\n */\n/**\n * Options for running a built flow\n */\nexport interface FlowRunOptions {\n /** Progress callbacks for step execution */\n callbacks?: FlowProgressCallbacks;\n /** Initial artifacts to merge into the flow context (for forEach child flows) */\n initialArtifacts?: Record<string, any>;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type BuiltFlow<TInput = any, TOutput = any> = {\n run: (input: TInput, callbacksOrOptions?: FlowProgressCallbacks | FlowRunOptions) => Promise<FlowResult<TOutput> | BatchFlowResult>;\n validate: () => FlowValidationResult;\n};\n\n/**\n * Type guard to check if a flow result is a single result (not batch)\n */\nexport function isSingleFlowResult<T>(result: FlowResult<T> | BatchFlowResult): result is FlowResult<T> {\n return 'output' in result && 'artifacts' in result;\n}\n\n/**\n * Type guard to check if a flow result is a batch result\n */\nexport function isBatchFlowResult(result: FlowResult<unknown> | BatchFlowResult): result is BatchFlowResult {\n return 'results' in result && Array.isArray(result.results);\n}\n\n/**\n * Type helper to extract the unwrapped input type from a wrapped type.\n * If T has an 'input' property, returns the type of that property.\n * Otherwise returns T unchanged.\n *\n * This matches the runtime behavior where conditionals receive wrapped data\n * but pass unwrapped data to the selected node.\n */\ntype UnwrapInput<T> = T extends { input: infer I } ? I : T;\n\ntype StepConfig<I, O> = {\n type: 'step';\n id: string;\n name?: string;\n node: NodeDef<I, O>;\n};\n\ntype ConditionalConfig<I, O> = {\n type: 'conditional';\n id: string;\n name?: string;\n condition: (data: I, context?: FlowContext) => NodeDef<UnwrapInput<I>, O>;\n};\n\ntype ForEachConfig<I, O> = {\n type: 'forEach';\n id: string;\n name?: string;\n childFlow: (item: any) => Flow<any, O>;\n};\n\ntype FlowStep = StepConfig<any, any> | ConditionalConfig<any, any> | ForEachConfig<any, any>;\n\n/**\n * Normalizes various input formats to FlowInput format\n * Handles:\n * - FlowInput objects: { base64, url, pages, bounds }\n * - Data URLs: \"data:application/pdf;base64,...\"\n * - HTTP URLs: \"https://...\"\n * - Raw base64 strings\n * - Objects with wrapper fields like { input: FlowInput }\n */\nfunction normalizeFlowInput(input: any): any {\n // Null or undefined - return as is\n if (input == null) {\n return input;\n }\n\n // Already a FlowInput object - return as is\n if (typeof input === 'object' && (input.base64 || input.url)) {\n return input;\n }\n\n // String input - detect format\n if (typeof input === 'string') {\n // Data URL - keep as data URL (providers handle this)\n if (input.startsWith('data:')) {\n return { base64: input };\n }\n\n // HTTP/HTTPS URL\n if (input.startsWith('http://') || input.startsWith('https://')) {\n return { url: input };\n }\n\n // Assume raw base64 string\n return { base64: input };\n }\n\n // Other object types - return as is (might be DocumentIR, string, etc.)\n return input;\n}\n\n/**\n * Options for creating a flow\n */\nexport interface FlowOptions {\n /** Observability configuration */\n observability?: ObservabilityConfig;\n /** User metadata to include in all observability contexts */\n metadata?: Record<string, unknown>;\n /**\n * Input format validation configuration.\n * Allows specifying accepted MIME types for early validation\n * before flow execution begins.\n */\n inputValidation?: FlowInputValidation;\n}\n\n/**\n * Flow builder class for creating document processing pipelines.\n * @template TInput - The input type for the flow\n * @template TOutput - The output type for the flow\n */\nexport class Flow<TInput = any, TOutput = any> {\n private steps: FlowStep[] = [];\n private observability?: ObservabilityConfig;\n private metadata?: Record<string, unknown>;\n private inputValidation?: FlowInputValidation;\n private traceContextManager?: TraceContextManager;\n private currentExecution?: ExecutionContext;\n\n constructor(options?: FlowOptions) {\n if (options?.observability) {\n this.observability = mergeConfig(options.observability);\n this.traceContextManager = new TraceContextManager(this.observability);\n }\n if (options?.metadata) {\n this.metadata = options.metadata;\n }\n if (options?.inputValidation) {\n this.inputValidation = options.inputValidation;\n }\n }\n\n /**\n * Set accepted input formats for this flow (fluent API).\n * Validates input format before flow execution begins.\n *\n * @param formats - List of accepted MIME types (e.g., ['application/pdf', 'image/jpeg'])\n * @returns This flow instance for chaining\n *\n * @example\n * ```typescript\n * const pdfOnlyFlow = createFlow()\n * .acceptFormats(['application/pdf'])\n * .step('parse', parse({ provider }))\n * .build();\n *\n * // Throws FlowInputValidationError if input is not a PDF\n * await pdfOnlyFlow.run({ base64: jpegBase64 });\n * ```\n */\n acceptFormats(formats: AcceptedMimeType[]): Flow<TInput, TOutput> {\n this.inputValidation = { acceptedFormats: formats };\n return this;\n }\n\n /**\n * Add a sequential step to the flow\n */\n step<TStepOutput>(id: string, node: NodeDef<TOutput, TStepOutput>, name?: string): Flow<TInput, TStepOutput> {\n this.steps.push({\n type: 'step',\n id,\n name,\n node\n });\n return this as any;\n }\n\n /**\n * Add a conditional step that chooses a node based on input data\n *\n * IMPORTANT: Conditionals must return a NODE, not a promise or executed flow.\n * The SDK will execute the returned node for you.\n *\n * The condition function receives the full wrapped data (e.g., { input, quality })\n * but the returned node should accept the unwrapped input (e.g., just FlowInput).\n * The SDK automatically unwraps the data before passing it to the selected node.\n *\n * ✅ CORRECT - Return a node (declarative):\n * ```typescript\n * .step('qualify', qualify({ provider, levels: ['low', 'medium', 'high'] }))\n * .conditional('parse', (data) => {\n * // data is { input: FlowInput, quality: string }\n * if (data.quality === 'high') {\n * return parse({ provider: fastProvider }); // Return the node\n * }\n * return parse({ provider: accurateProvider }); // Return the node\n * })\n * ```\n *\n * ❌ INCORRECT - Do NOT return a promise (imperative):\n * ```typescript\n * .conditional('parse', (data) => {\n * // This will throw an error!\n * return createFlow()\n * .step('parse', parse({ provider }))\n * .build()\n * .run(data.input) // ❌ Don't call .run() here!\n * .then(r => r.output);\n * })\n * ```\n *\n * 🆕 NEW - Access previous step outputs via context:\n * ```typescript\n * .step('categorize', categorize({ provider, categories }))\n * .conditional('parse', (data) => parse({ provider }))\n * .conditional('extract', (data, context) => {\n * // Access category from earlier step via context.artifacts\n * const category = context?.artifacts.categorize?.category;\n * return extract({ provider, schema: SCHEMAS[category] });\n * })\n * ```\n *\n * Use the declarative pattern (return nodes) for consistent flow execution,\n * proper error tracking, and accurate metrics collection.\n */\n conditional<TConditionalOutput>(\n id: string,\n condition: (data: TOutput, context?: FlowContext) => NodeDef<UnwrapInput<TOutput>, TConditionalOutput>,\n name?: string\n ): Flow<TInput, TConditionalOutput> {\n this.steps.push({\n type: 'conditional',\n id,\n name,\n condition\n });\n return this as any;\n }\n\n /**\n * Process each item from previous step (which must return an array) with a child flow\n * Each item is processed in parallel as its own isolated run\n */\n forEach<TItem, TForEachOutput>(\n id: string,\n childFlow: (item: TItem) => Flow<TItem, TForEachOutput>,\n name?: string\n ): Flow<TInput, FlowResult<TForEachOutput>[]> {\n this.steps.push({\n type: 'forEach',\n id,\n name,\n childFlow\n });\n return this as any;\n }\n\n /**\n * Add an explicit output node to mark which data to return from the flow\n *\n * By default, flows return the output of the last step. Use output nodes to:\n * - Return data from earlier steps\n * - Return multiple named outputs\n * - Transform outputs before returning\n *\n * @param config - Output configuration\n * @returns Flow with output node added\n *\n * @example\n * // Single output\n * .output({ name: 'invoice_data' })\n *\n * // Select specific source\n * .output({ name: 'result', source: 'step2' })\n *\n * // Multiple outputs\n * .step('extract1', extract({ provider, schema1 }))\n * .output({ name: 'summary', source: 'extract1' })\n * .step('extract2', extract({ provider, schema2 }))\n * .output({ name: 'details', source: 'extract2' })\n */\n output<TOutputShape = TOutput>(config?: OutputNodeConfig): Flow<TInput, TOutputShape> {\n // Normalize and validate name\n const name = config?.name?.trim();\n\n // Use provided name or generate unique default\n const stepId = name || this.generateOutputStepId();\n\n this.steps.push({\n type: 'step',\n id: stepId,\n node: createOutputNode({\n ...config,\n name: stepId // Ensure name matches step ID\n })\n });\n\n return this as any;\n }\n\n /**\n * Get current execution context\n *\n * Returns null if not currently executing.\n */\n getExecutionContext(): ExecutionContext | null {\n return this.currentExecution ?? null;\n }\n\n /**\n * Get current trace context\n *\n * Returns null if not currently executing or observability not configured.\n */\n getTraceContext(): TraceContext | null {\n return this.traceContextManager?.getTraceContext() ?? null;\n }\n\n /**\n * Set a custom attribute on the current execution\n *\n * Custom attributes appear in execution context and can be accessed by hooks.\n */\n setCustomAttribute(key: string, value: unknown): void {\n if (this.currentExecution) {\n this.currentExecution.customAttributes[key] = value;\n }\n }\n\n /**\n * Record a custom metric for the current execution\n *\n * Custom metrics appear in execution context and can be accessed by hooks.\n */\n recordMetric(name: string, value: number, unit?: string): void {\n if (this.currentExecution) {\n this.currentExecution.customMetrics.push({\n name,\n value,\n unit,\n timestamp: Date.now(),\n });\n }\n }\n\n /**\n * Build and return the executable flow\n */\n build(): BuiltFlow<TInput, TOutput> {\n return {\n run: async (input: TInput, callbacksOrOptions?: FlowProgressCallbacks | FlowRunOptions) => {\n // Support both legacy callback-only signature and new options object\n let callbacks: FlowProgressCallbacks | undefined;\n let initialArtifacts: Record<string, any> | undefined;\n\n if (callbacksOrOptions) {\n if ('callbacks' in callbacksOrOptions || 'initialArtifacts' in callbacksOrOptions) {\n // New options object format\n callbacks = (callbacksOrOptions as FlowRunOptions).callbacks;\n initialArtifacts = (callbacksOrOptions as FlowRunOptions).initialArtifacts;\n } else {\n // Legacy callbacks format\n callbacks = callbacksOrOptions as FlowProgressCallbacks;\n }\n }\n\n return this.execute(input, callbacks, initialArtifacts);\n },\n validate: () => {\n return this.validate();\n }\n };\n }\n\n /**\n * Generate a unique step ID for unnamed output nodes\n * Prevents duplicate IDs when multiple .output() calls without names\n */\n private generateOutputStepId(): string {\n let counter = 0;\n let candidateId = 'output';\n\n // Check if 'output' is already taken\n while (this.steps.some(step => step.id === candidateId)) {\n counter++;\n candidateId = `output_${counter}`;\n }\n\n return candidateId;\n }\n\n /**\n * Validate the flow configuration\n */\n private validate(): FlowValidationResult {\n const errors: FlowValidationError[] = [];\n const warnings: string[] = [];\n\n // Check if flow has at least one step\n if (this.steps.length === 0) {\n errors.push({\n stepId: '<flow>',\n stepIndex: -1,\n stepType: 'flow',\n message: 'Flow has no steps. Add at least one step using .step(), .conditional(), or .forEach()'\n });\n }\n\n // Validate each step\n for (let stepIndex = 0; stepIndex < this.steps.length; stepIndex++) {\n const step = this.steps[stepIndex];\n\n // Check for duplicate step IDs\n const duplicateIndex = this.steps.findIndex((s, i) => i !== stepIndex && s.id === step.id);\n if (duplicateIndex !== -1) {\n errors.push({\n stepId: step.id,\n stepIndex,\n stepType: step.type,\n message: `Duplicate step ID \"${step.id}\" found at indices ${stepIndex} and ${duplicateIndex}`\n });\n }\n\n // Validate step-specific configuration\n if (step.type === 'step') {\n if (!step.node) {\n errors.push({\n stepId: step.id,\n stepIndex,\n stepType: step.type,\n message: 'Step node is missing. Use parse(), qualify(), categorize(), extract(), or split()'\n });\n }\n // Note: We don't check typeof === 'function' because NodeDef can be various structures\n // TypeScript already ensures type safety at compile time\n } else if (step.type === 'conditional') {\n if (!step.condition || typeof step.condition !== 'function') {\n errors.push({\n stepId: step.id,\n stepIndex,\n stepType: step.type,\n message: 'Conditional must have a condition function'\n });\n }\n } else if (step.type === 'forEach') {\n if (!step.childFlow || typeof step.childFlow !== 'function') {\n errors.push({\n stepId: step.id,\n stepIndex,\n stepType: step.type,\n message: 'forEach must have a childFlow function'\n });\n }\n\n // Warn if forEach is not preceded by a step that could produce an array\n if (stepIndex === 0) {\n warnings.push(`forEach step \"${step.id}\" at index ${stepIndex} is the first step - ensure input is an array`);\n }\n }\n\n // Check for empty step IDs\n if (!step.id || step.id.trim() === '') {\n errors.push({\n stepId: '<empty>',\n stepIndex,\n stepType: step.type,\n message: 'Step ID cannot be empty'\n });\n }\n }\n\n // Type compatibility validation (skip if DOCLO_SKIP_VALIDATION is set)\n if (!shouldSkipValidation()) {\n this.validateTypeCompatibility(errors, warnings);\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings\n };\n }\n\n /**\n * Validate type compatibility between consecutive steps\n */\n private validateTypeCompatibility(errors: FlowValidationError[], warnings: string[]): void {\n for (let i = 0; i < this.steps.length - 1; i++) {\n const currentStep = this.steps[i];\n const nextStep = this.steps[i + 1];\n\n // Only validate step → step connections (not conditional or forEach)\n if (currentStep.type === 'step' && nextStep.type === 'step') {\n const sourceType = getNodeTypeName(currentStep.node);\n const targetType = getNodeTypeName(nextStep.node);\n\n // Skip if either node type is unknown (custom nodes)\n if (!sourceType || !targetType) {\n continue;\n }\n\n // Check if source node has forEach capability (split node)\n const forEachEnabled = false; // TODO: Detect forEach from node config\n\n // Validate connection\n const validation = validateNodeConnection(sourceType, targetType, forEachEnabled);\n\n if (!validation.valid) {\n errors.push({\n stepId: currentStep.id,\n stepIndex: i,\n stepType: currentStep.type,\n message: `Invalid connection: ${sourceType} → ${targetType}. ${validation.reason || 'Types incompatible'}`,\n });\n\n // Add suggestions as warnings\n if (validation.suggestions && validation.suggestions.length > 0) {\n warnings.push(`Suggestions for step \"${currentStep.id}\":`);\n validation.suggestions.forEach(s => warnings.push(` ${s}`));\n }\n } else if (validation.warning) {\n // Add runtime validation warning\n warnings.push(`Step \"${currentStep.id}\" → \"${nextStep.id}\": ${validation.warning}`);\n }\n }\n\n // Validate forEach requirements\n if (currentStep.type === 'step' && nextStep.type === 'forEach') {\n const sourceType = getNodeTypeName(currentStep.node);\n if (sourceType) {\n const sourceInfo = currentStep.node.__meta;\n const outputsArray = sourceInfo?.outputsArray;\n\n // Check if source outputs array\n const isArrayOutput = typeof outputsArray === 'function'\n ? outputsArray(null) // Can't access config here, so pass null\n : outputsArray;\n\n if (!isArrayOutput) {\n warnings.push(\n `forEach step \"${nextStep.id}\" requires array input. ` +\n `Previous step \"${currentStep.id}\" (${sourceType}) may not output an array. ` +\n `Ensure ${sourceType} is configured to output an array (e.g., parse with chunked:true).`\n );\n }\n\n // Validate forEach itemFlow starting node\n if (nextStep.childFlow && typeof nextStep.childFlow === 'function') {\n try {\n // Try to build the child flow to inspect its first step\n const childFlowInstance = nextStep.childFlow(null as any);\n\n // Access the steps array if available (Flow class internal structure)\n const childSteps = (childFlowInstance as any).steps;\n\n if (childSteps && Array.isArray(childSteps) && childSteps.length > 0) {\n const firstStep = childSteps[0];\n\n // Validate the first step is a regular step (not forEach/conditional)\n if (firstStep.type === 'step') {\n const firstNodeType = getNodeTypeName(firstStep.node);\n\n if (firstNodeType) {\n // Validate that this node can start forEach itemFlow\n const validation = canStartForEachItemFlow(sourceType, firstNodeType);\n\n if (!validation.valid) {\n errors.push({\n stepId: nextStep.id,\n stepIndex: i + 1,\n stepType: 'forEach',\n message: `Invalid forEach itemFlow starter: ${validation.reason || `${firstNodeType} cannot start forEach itemFlow after ${sourceType}`}`\n });\n\n // Add suggestions as warnings\n if (validation.suggestions && validation.suggestions.length > 0) {\n warnings.push(`Suggestions for forEach \"${nextStep.id}\":`);\n validation.suggestions.forEach(s => warnings.push(` ${s}`));\n }\n }\n }\n } else if (firstStep.type === 'forEach') {\n // Nested forEach is not allowed for split\n if (sourceType === 'split') {\n errors.push({\n stepId: nextStep.id,\n stepIndex: i + 1,\n stepType: 'forEach',\n message: 'Invalid forEach itemFlow: Cannot nest forEach operations. Split nodes cannot appear in forEach itemFlow.'\n });\n }\n }\n }\n } catch (error) {\n // If we can't inspect the child flow, add a warning but don't block\n warnings.push(\n `forEach step \"${nextStep.id}\": Unable to validate itemFlow structure. ` +\n `Ensure the first node in itemFlow is compatible with ${sourceType} output. ` +\n `Valid starters: ${getValidForEachStarters(sourceType).join(', ')}`\n );\n }\n }\n }\n }\n }\n\n // Check for efficiency anti-patterns\n this.checkEfficiencyPatterns(warnings);\n }\n\n /**\n * Check for inefficient flow patterns and add warnings.\n *\n * Detects patterns like:\n * - parse() → extract(raw-document-provider): The extract provider ignores parse output\n */\n private checkEfficiencyPatterns(warnings: string[]): void {\n for (let i = 0; i < this.steps.length - 1; i++) {\n const current = this.steps[i];\n const next = this.steps[i + 1];\n\n // Only check step → step connections\n if (current.type !== 'step' || next.type !== 'step') continue;\n\n const currNodeType = getNodeTypeName(current.node);\n const nextNodeType = getNodeTypeName(next.node);\n\n // Detect: parse() → extract(raw-document-provider)\n if (currNodeType === 'parse' && nextNodeType === 'extract') {\n const extractProvider = this.getProviderFromNode(next.node);\n\n if (extractProvider) {\n const metadata = getProviderById(extractProvider);\n\n if (metadata?.inputRequirements?.inputType === 'raw-document') {\n warnings.push(\n `Efficiency warning: Step \"${current.id}\" (parse) output may be ignored. ` +\n `\"${metadata.name}\" processes raw documents directly, not parsed text. ` +\n `Consider: (1) Remove the parse step, or (2) Use an LLM provider for extraction that can use parsed text.`\n );\n }\n }\n }\n }\n }\n\n /**\n * Extract provider ID from a node definition.\n * Returns undefined if provider cannot be determined.\n */\n private getProviderFromNode(node: NodeDef<any, any>): string | undefined {\n // Try to get provider from node config\n const config = (node as any).__meta?.config;\n if (config?.provider) {\n // Provider can be a string ID or a provider object\n if (typeof config.provider === 'string') {\n return config.provider;\n }\n // If provider is an object, it might have an id or name property\n if (typeof config.provider === 'object') {\n return config.provider.id ?? config.provider.name;\n }\n }\n return undefined;\n }\n\n /**\n * Execute the flow with optional progress callbacks\n */\n private async execute(input: any, callbacks?: FlowProgressCallbacks, initialArtifacts?: Record<string, any>): Promise<any> {\n const flowStartTime = Date.now();\n // Merge initial artifacts if provided (used for passing original source to forEach child flows)\n const artifacts: Record<string, any> = initialArtifacts ? { ...initialArtifacts } : {};\n const metrics: StepMetric[] = [];\n const completedSteps: string[] = [];\n const outputs: Record<string, any> = {}; // Store output node results\n let lastNonOutputData: any = null; // Track data from last non-output step\n\n // Initialize observability\n let executionId: string | undefined;\n let traceContext: TraceContext | undefined;\n let sampled = false;\n\n if (this.observability) {\n // Determine if this execution should be sampled\n sampled = shouldSample(this.observability);\n\n // Initialize trace context\n if (this.traceContextManager && sampled) {\n traceContext = this.traceContextManager.initialize(sampled);\n }\n\n // Generate execution ID\n const execIdGenerator = this.observability.generateExecutionId ?? generateExecutionId;\n executionId = execIdGenerator();\n\n // Initialize execution context for tracking\n this.currentExecution = {\n flowId: 'flow', // TODO: Add flowId to Flow class\n executionId,\n startTime: flowStartTime,\n status: 'running',\n customAttributes: {},\n customMetrics: [],\n };\n\n // Call onFlowStart hook\n if (sampled && traceContext) {\n const flowStartContext: FlowStartContext = {\n flowId: 'flow', // TODO: Add flowId\n flowVersion: '0.0.1',\n executionId,\n timestamp: flowStartTime,\n input,\n config: {}, // TODO: Capture flow config\n metadata: this.metadata,\n sdkVersion: '0.0.1',\n observabilityVersion: this.observability.observabilityVersion ?? '1.0.0',\n traceContext,\n };\n\n await executeHook(this.observability.onFlowStart, {\n hookName: 'onFlowStart',\n config: this.observability,\n context: flowStartContext,\n });\n }\n }\n\n // Normalize input format to handle various input types\n // (data URLs, HTTP URLs, raw base64, FlowInput objects)\n let currentData = normalizeFlowInput(input);\n\n // Store original flow input for source reference in extract nodes\n // This enables inputMode='ir+source' to access the original document\n artifacts.__flowInput = currentData;\n\n // Validate input format if configured\n if (this.inputValidation?.acceptedFormats?.length) {\n const dataUrl = currentData?.base64 || currentData?.url;\n if (dataUrl) {\n // This will throw FlowInputValidationError if format doesn't match\n validateFlowInputFormat(dataUrl, this.inputValidation.acceptedFormats);\n }\n }\n\n // Wrap execution in try-catch for flow-level error handling\n try {\n\n for (let stepIndex = 0; stepIndex < this.steps.length; stepIndex++) {\n const step = this.steps[stepIndex];\n const stepStartTime = Date.now();\n\n // Generate span ID for this step\n const stepSpanId = this.traceContextManager && sampled ? generateSpanId() : undefined;\n\n // Notify step start (old callbacks)\n callbacks?.onStepStart?.(step.id, stepIndex, step.type);\n\n // Call onStepStart hook (new observability)\n if (this.observability && sampled && traceContext && executionId && stepSpanId) {\n const stepStartContext: StepStartContext = {\n flowId: 'flow',\n executionId,\n stepId: step.id,\n stepIndex,\n stepType: (step as StepConfig<any, any>).node?.key ?? step.type,\n stepName: step.name ?? step.id,\n timestamp: stepStartTime,\n provider: undefined, // Will be populated from step config if available\n model: undefined,\n config: {},\n input: currentData,\n isConsensusEnabled: false, // TODO: Check step config for consensus\n isRetry: false,\n metadata: this.metadata,\n traceContext,\n spanId: stepSpanId,\n };\n\n await executeHook(this.observability.onStepStart, {\n hookName: 'onStepStart',\n config: this.observability,\n context: stepStartContext,\n });\n }\n\n try {\n if (step.type === 'step') {\n // Check if this is an output node\n const isOutputNode = (step.node as any)?.__meta?.isOutputNode === true;\n const outputName = (step.node as any)?.__meta?.outputName?.trim() || step.id;\n\n interface StepResult {\n output: unknown;\n artifacts: Record<string, unknown>;\n metrics: StepMetric[];\n }\n\n let result: StepResult;\n\n if (isOutputNode) {\n // Output nodes need access to flow-level artifacts\n // Execute directly with custom context instead of using runPipeline\n const ctx: NodeCtx = {\n stepId: step.id,\n artifacts,\n emit: (k: string, v: unknown) => { artifacts[k] = v; },\n metrics: { push: (m: StepMetric) => metrics.push(m) },\n observability: this.observability && sampled ? {\n config: this.observability,\n flowId: 'flow',\n executionId,\n stepId: step.id,\n stepIndex,\n traceContext,\n metadata: this.metadata,\n } : undefined\n };\n\n const outputData = await step.node.run(currentData, ctx);\n result = { output: outputData, artifacts: {}, metrics: [] };\n\n // Store the output node result\n outputs[outputName] = outputData;\n artifacts[step.id] = outputData;\n completedSteps.push(step.id);\n\n // Notify step complete (old callbacks)\n const stepDuration = Date.now() - stepStartTime;\n callbacks?.onStepComplete?.(step.id, stepIndex, step.type, stepDuration);\n\n // Call onStepEnd hook (new observability) - output nodes\n if (this.observability && sampled && traceContext && executionId && stepSpanId) {\n const stepEndContext: StepEndContext = {\n flowId: 'flow',\n executionId,\n stepId: step.id,\n stepIndex,\n timestamp: Date.now(),\n startTime: stepStartTime,\n duration: stepDuration,\n output: outputData,\n usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 },\n cost: 0,\n metricKind: 'prep', // Output nodes are prep steps (no API call)\n otelAttributes: buildStepAttributes({\n stepType: step.node?.key ?? step.type,\n }),\n metadata: this.metadata,\n traceContext,\n spanId: stepSpanId,\n };\n\n await executeHook(this.observability.onStepEnd, {\n hookName: 'onStepEnd',\n config: this.observability,\n context: stepEndContext,\n });\n }\n\n // Pass through the last non-output data to the next step\n // (output nodes don't change the data flow, they just mark outputs)\n currentData = lastNonOutputData !== null ? lastNonOutputData : currentData;\n } else {\n // Regular sequential step - pass flow artifacts for source access\n result = await runPipeline([step.node], currentData, this.observability && sampled ? {\n config: this.observability,\n flowId: 'flow',\n executionId,\n stepId: step.id,\n stepIndex,\n traceContext,\n metadata: this.metadata,\n } : {\n // Always pass stepId for metrics tracking, even without observability\n stepId: step.id\n }, artifacts);\n\n // Store the original output in artifacts (preserve wrapped data)\n artifacts[step.id] = result.output;\n metrics.push(...result.metrics);\n completedSteps.push(step.id);\n\n // Notify step complete (old callbacks)\n const stepDuration = Date.now() - stepStartTime;\n callbacks?.onStepComplete?.(step.id, stepIndex, step.type, stepDuration);\n\n // Call onStepEnd hook (new observability) - regular steps\n if (this.observability && sampled && traceContext && executionId && stepSpanId) {\n // Find metrics by type\n const leafMetrics = result.metrics.filter(m => m.metadata?.kind === 'leaf');\n const wrapperMetric = result.metrics.find(m => m.metadata?.kind === 'wrapper');\n\n // Find leaf metrics that belong to this step\n const stepLeafMetrics = result.metrics.filter(m =>\n m.configStepId === step.id && m.metadata?.kind === 'leaf'\n );\n\n // If there are MULTIPLE leaf metrics for this step, it's consensus runs (pure wrapper)\n // If there's exactly ONE leaf metric for this step, that's the step's own work\n const isConsensus = stepLeafMetrics.length > 1;\n const stepOwnLeafMetric = isConsensus ? undefined : stepLeafMetrics[0];\n\n // Determine if there are child metrics (from branch flows, etc.)\n const hasOtherChildMetrics = result.metrics.some(m => m.configStepId !== step.id);\n const hasChildMetrics = isConsensus || hasOtherChildMetrics || leafMetrics.length > 1;\n\n let metricKind: 'leaf' | 'wrapper' | 'prep';\n let ownDuration: number;\n let ownCost: number;\n let ownInputTokens: number;\n let ownOutputTokens: number;\n let ownCacheCreationTokens: number | undefined;\n let ownCacheReadTokens: number | undefined;\n\n if (isConsensus) {\n // Consensus: multiple leaf metrics = pure wrapper (children report via onConsensusRunComplete)\n metricKind = 'wrapper';\n ownDuration = wrapperMetric?.metadata?.overheadMs ?? 0;\n ownCost = 0;\n ownInputTokens = 0;\n ownOutputTokens = 0;\n ownCacheCreationTokens = undefined;\n ownCacheReadTokens = undefined;\n } else if (stepOwnLeafMetric) {\n // Step has its own API call (e.g., categorize in conditional, single extract)\n // It's a wrapper if it ALSO has child metrics\n metricKind = hasOtherChildMetrics ? 'wrapper' : 'leaf';\n ownDuration = stepOwnLeafMetric.ms ?? 0;\n ownCost = stepOwnLeafMetric.costUSD ?? 0;\n ownInputTokens = stepOwnLeafMetric.inputTokens ?? 0;\n ownOutputTokens = stepOwnLeafMetric.outputTokens ?? 0;\n ownCacheCreationTokens = stepOwnLeafMetric.cacheCreationInputTokens;\n ownCacheReadTokens = stepOwnLeafMetric.cacheReadInputTokens;\n } else if (wrapperMetric || hasChildMetrics) {\n // Pure wrapper - no own API call, just orchestration\n metricKind = 'wrapper';\n ownDuration = wrapperMetric?.metadata?.overheadMs ?? 0;\n ownCost = 0;\n ownInputTokens = 0;\n ownOutputTokens = 0;\n ownCacheCreationTokens = undefined;\n ownCacheReadTokens = undefined;\n } else {\n // No metrics = prep step (e.g., output node)\n metricKind = 'prep';\n ownDuration = stepDuration;\n ownCost = 0;\n ownInputTokens = 0;\n ownOutputTokens = 0;\n ownCacheCreationTokens = undefined;\n ownCacheReadTokens = undefined;\n }\n\n // Get provider/model from first metric (all consensus runs use same provider)\n const firstMetric = result.metrics.length > 0 ? result.metrics[0] : undefined;\n\n const stepEndContext: StepEndContext = {\n flowId: 'flow',\n executionId,\n stepId: step.id,\n stepIndex,\n timestamp: Date.now(),\n startTime: stepStartTime,\n duration: ownDuration,\n output: result.output,\n usage: {\n inputTokens: ownInputTokens,\n outputTokens: ownOutputTokens,\n totalTokens: ownInputTokens + ownOutputTokens,\n cacheCreationInputTokens: ownCacheCreationTokens,\n cacheReadInputTokens: ownCacheReadTokens,\n },\n cost: ownCost,\n metricKind,\n otelAttributes: buildStepAttributes({\n stepType: step.node?.key ?? step.type,\n provider: firstMetric?.provider,\n model: firstMetric?.model,\n inputTokens: ownInputTokens,\n outputTokens: ownOutputTokens,\n }),\n metadata: this.metadata,\n traceContext,\n spanId: stepSpanId,\n };\n\n await executeHook(this.observability.onStepEnd, {\n hookName: 'onStepEnd',\n config: this.observability,\n context: stepEndContext,\n });\n }\n\n // Regular node - save this as the last non-output data\n lastNonOutputData = result.output;\n\n // Auto-unwrap ONLY if next step is a regular step (not conditional/forEach)\n // Conditionals need the wrapped data to make decisions\n // This preserves { input, quality/category } for final output and conditionals\n const hasNextStep = stepIndex < this.steps.length - 1;\n const nextStep = hasNextStep ? this.steps[stepIndex + 1] : null;\n const shouldUnwrap = hasNextStep &&\n nextStep?.type === 'step' &&\n result.output &&\n typeof result.output === 'object' &&\n 'input' in result.output;\n\n if (shouldUnwrap) {\n currentData = (result.output as Record<string, unknown>).input;\n } else {\n currentData = result.output;\n }\n }\n } else if (step.type === 'conditional') {\n // Conditional step - choose node based on current data\n // Pass the FULL wrapped data to the condition function\n // (it needs access to quality/category for decision making)\n // Also pass context with artifacts and metrics for accessing previous step outputs\n const context: FlowContext = {\n artifacts: { ...artifacts },\n metrics: [...metrics]\n };\n const node = step.condition(currentData, context);\n\n // Validate that the condition function returned a valid NodeDef\n // NodeDef is an object with { key: string; run: function }\n if (!node || typeof node !== 'object' || !node.key || typeof node.run !== 'function') {\n throw new Error(\n `Conditional step \"${step.id}\" must return a node (e.g., parse(), categorize(), extract()). ` +\n `Got: ${typeof node}${node && typeof node === 'object' ? ` with keys: ${Object.keys(node).join(', ')}` : ''}. ` +\n `\\n\\nA valid node must have 'key' and 'run' properties.` +\n `\\n\\nIncorrect: .conditional('step', () => flow.run(...).then(r => r.output))` +\n `\\nCorrect: .conditional('step', () => parse({ provider }))`\n );\n }\n\n // Auto-unwrap when executing the node (if data has 'input' field)\n // The selected node should receive just the input\n const nodeInput = currentData && typeof currentData === 'object' && 'input' in currentData\n ? currentData.input\n : currentData;\n\n const result = await runPipeline([node], nodeInput, this.observability && sampled ? {\n config: this.observability,\n flowId: 'flow',\n executionId,\n stepId: step.id,\n stepIndex,\n traceContext,\n metadata: this.metadata,\n } : undefined);\n\n // Store the original output in artifacts\n artifacts[step.id] = result.output;\n metrics.push(...result.metrics);\n completedSteps.push(step.id);\n\n // Notify step complete\n const stepDuration = Date.now() - stepStartTime;\n callbacks?.onStepComplete?.(step.id, stepIndex, step.type, stepDuration);\n\n // Call onStepEnd hook (new observability) - conditional steps\n if (this.observability && sampled && traceContext && executionId && stepSpanId) {\n // Find metrics by type\n const leafMetrics = result.metrics.filter(m => m.metadata?.kind === 'leaf');\n const wrapperMetric = result.metrics.find(m => m.metadata?.kind === 'wrapper');\n\n // Find leaf metrics that belong to this step\n const stepLeafMetrics = result.metrics.filter(m =>\n m.configStepId === step.id && m.metadata?.kind === 'leaf'\n );\n\n // If there are MULTIPLE leaf metrics for this step, it's consensus runs (pure wrapper)\n // If there's exactly ONE leaf metric for this step, that's the step's own work\n const isConsensus = stepLeafMetrics.length > 1;\n const stepOwnLeafMetric = isConsensus ? undefined : stepLeafMetrics[0];\n\n // Determine if there are child metrics (from branch flows, etc.)\n const hasOtherChildMetrics = result.metrics.some(m => m.configStepId !== step.id);\n const hasChildMetrics = isConsensus || hasOtherChildMetrics || leafMetrics.length > 1;\n\n let metricKind: 'leaf' | 'wrapper' | 'prep';\n let ownDuration: number;\n let ownCost: number;\n let ownInputTokens: number;\n let ownOutputTokens: number;\n let ownCacheCreationTokens: number | undefined;\n let ownCacheReadTokens: number | undefined;\n\n if (isConsensus) {\n // Consensus: multiple leaf metrics = pure wrapper (children report via onConsensusRunComplete)\n metricKind = 'wrapper';\n ownDuration = wrapperMetric?.metadata?.overheadMs ?? 0;\n ownCost = 0;\n ownInputTokens = 0;\n ownOutputTokens = 0;\n ownCacheCreationTokens = undefined;\n ownCacheReadTokens = undefined;\n } else if (stepOwnLeafMetric) {\n // Step has its own API call (e.g., categorize in conditional)\n // It's a wrapper if it ALSO has child metrics\n metricKind = hasOtherChildMetrics ? 'wrapper' : 'leaf';\n ownDuration = stepOwnLeafMetric.ms ?? 0;\n ownCost = stepOwnLeafMetric.costUSD ?? 0;\n ownInputTokens = stepOwnLeafMetric.inputTokens ?? 0;\n ownOutputTokens = stepOwnLeafMetric.outputTokens ?? 0;\n ownCacheCreationTokens = stepOwnLeafMetric.cacheCreationInputTokens;\n ownCacheReadTokens = stepOwnLeafMetric.cacheReadInputTokens;\n } else if (wrapperMetric || hasChildMetrics) {\n // Pure wrapper - no own API call, just orchestration\n metricKind = 'wrapper';\n ownDuration = wrapperMetric?.metadata?.overheadMs ?? 0;\n ownCost = 0;\n ownInputTokens = 0;\n ownOutputTokens = 0;\n ownCacheCreationTokens = undefined;\n ownCacheReadTokens = undefined;\n } else {\n // No metrics = prep step\n metricKind = 'prep';\n ownDuration = stepDuration;\n ownCost = 0;\n ownInputTokens = 0;\n ownOutputTokens = 0;\n ownCacheCreationTokens = undefined;\n ownCacheReadTokens = undefined;\n }\n\n // Get provider/model from first metric\n const firstMetric = result.metrics.length > 0 ? result.metrics[0] : undefined;\n\n const stepEndContext: StepEndContext = {\n flowId: 'flow',\n executionId,\n stepId: step.id,\n stepIndex,\n timestamp: Date.now(),\n startTime: stepStartTime,\n duration: ownDuration,\n output: result.output,\n usage: {\n inputTokens: ownInputTokens,\n outputTokens: ownOutputTokens,\n totalTokens: ownInputTokens + ownOutputTokens,\n cacheCreationInputTokens: ownCacheCreationTokens,\n cacheReadInputTokens: ownCacheReadTokens,\n },\n cost: ownCost,\n metricKind,\n otelAttributes: buildStepAttributes({\n stepType: 'conditional',\n provider: firstMetric?.provider,\n model: firstMetric?.model,\n inputTokens: ownInputTokens,\n outputTokens: ownOutputTokens,\n }),\n metadata: this.metadata,\n traceContext,\n spanId: stepSpanId,\n };\n\n await executeHook(this.observability.onStepEnd, {\n hookName: 'onStepEnd',\n config: this.observability,\n context: stepEndContext,\n });\n }\n\n // Track as non-output data\n lastNonOutputData = result.output;\n\n // Update currentData for next step (no need to unwrap here, handled in next iteration)\n currentData = result.output;\n } else if (step.type === 'forEach') {\n // forEach step - process array items in parallel\n if (!Array.isArray(currentData)) {\n throw new Error(`forEach step \"${step.id}\" requires array input, got ${typeof currentData}`);\n }\n\n const items = currentData;\n const batchId = executionId ? `${executionId}-batch-${stepIndex}` : `batch-${stepIndex}`;\n const batchStartTime = Date.now();\n\n // onBatchStart hook\n if (this.observability && sampled && traceContext && executionId) {\n const batchStartContext: BatchStartContext = {\n flowId: 'flow',\n executionId,\n batchId,\n stepId: step.id,\n totalItems: items.length,\n timestamp: batchStartTime,\n metadata: this.metadata,\n traceContext,\n };\n await executeHook(this.observability.onBatchStart, {\n hookName: 'onBatchStart',\n config: this.observability,\n context: batchStartContext,\n });\n }\n\n const results = await Promise.allSettled(\n items.map(async (item: any, itemIndex: number) => {\n const itemStartTime = Date.now();\n const itemSpanId = this.traceContextManager && sampled ? generateSpanId() : undefined;\n\n // onBatchItemStart hook\n if (this.observability && sampled && traceContext && executionId) {\n const batchItemContext: BatchItemContext = {\n flowId: 'flow',\n executionId,\n batchId,\n stepId: step.id,\n itemIndex,\n totalItems: items.length,\n timestamp: itemStartTime,\n item,\n metadata: this.metadata,\n traceContext,\n };\n await executeHook(this.observability.onBatchItemStart, {\n hookName: 'onBatchItemStart',\n config: this.observability,\n context: batchItemContext,\n });\n }\n\n try {\n const childFlow = step.childFlow(item);\n const builtFlow = childFlow.build();\n\n // If item is a SplitDocument (has .input property), pass the input to the child flow\n // Otherwise pass the item itself\n const flowInput = item && typeof item === 'object' && 'input' in item ? item.input : item;\n\n // Pass original flow input to child flow for extract node's useOriginalSource option\n // __flowInput will be the segment source, __originalFlowInput is the pre-split source\n const childInitialArtifacts = {\n __originalFlowInput: artifacts.__flowInput, // Original source before split\n };\n\n const result = await builtFlow.run(flowInput, { initialArtifacts: childInitialArtifacts });\n\n // Handle both FlowResult and { results: FlowResult[] }\n let itemResult;\n if ('results' in result && Array.isArray(result.results)) {\n // Child flow has forEach - aggregate metrics and artifacts from results\n const aggregatedMetrics = (result.results || []).flatMap((r: any) => (r && r.metrics) || []);\n const aggregatedArtifacts = (result.results || []).map((r: any) => r && r.artifacts);\n itemResult = {\n output: (result.results || []).map((r: any) => r && r.output),\n metrics: aggregatedMetrics,\n artifacts: aggregatedArtifacts\n };\n } else {\n // Regular flow result - cast to access properties\n const flowResult = result as FlowResult<any>;\n itemResult = {\n output: flowResult.output,\n metrics: flowResult.metrics || [],\n artifacts: flowResult.artifacts || {}\n };\n }\n\n // onBatchItemEnd hook (success)\n if (this.observability && sampled && traceContext && executionId) {\n const batchItemEndContext: BatchItemEndContext = {\n flowId: 'flow',\n executionId,\n batchId,\n stepId: step.id,\n itemIndex,\n totalItems: items.length,\n item,\n timestamp: Date.now(),\n duration: Date.now() - itemStartTime,\n result: itemResult.output,\n status: 'success',\n metadata: this.metadata,\n traceContext,\n };\n await executeHook(this.observability.onBatchItemEnd, {\n hookName: 'onBatchItemEnd',\n config: this.observability,\n context: batchItemEndContext,\n });\n }\n\n return itemResult;\n } catch (error) {\n // Log the full error for debugging\n console.error('[forEach error]', error);\n\n // onBatchItemEnd hook (error)\n if (this.observability && sampled && traceContext && executionId) {\n const batchItemEndContext: BatchItemEndContext = {\n flowId: 'flow',\n executionId,\n batchId,\n stepId: step.id,\n itemIndex,\n totalItems: items.length,\n item,\n timestamp: Date.now(),\n duration: Date.now() - itemStartTime,\n result: null,\n status: 'failed',\n error: error instanceof Error ? error : new Error(String(error)),\n metadata: this.metadata,\n traceContext,\n };\n await executeHook(this.observability.onBatchItemEnd, {\n hookName: 'onBatchItemEnd',\n config: this.observability,\n context: batchItemEndContext,\n });\n }\n\n return {\n output: null,\n error: (error as Error).message || String(error),\n metrics: [],\n artifacts: {}\n };\n }\n })\n );\n\n // Convert Promise.allSettled results to FlowResult[]\n const flowResults = results.map((result, index) => {\n if (result.status === 'fulfilled') {\n return result.value;\n } else {\n return {\n output: null,\n error: result.reason,\n metrics: [],\n artifacts: {}\n };\n }\n });\n\n artifacts[step.id] = flowResults.map(r => r.artifacts);\n metrics.push(...flowResults.flatMap(r => r.metrics));\n completedSteps.push(step.id);\n\n // onBatchEnd hook\n const successfulCount = flowResults.filter(r => !r.error).length;\n const failedCount = flowResults.filter(r => r.error).length;\n\n if (this.observability && sampled && traceContext && executionId) {\n const batchEndContext: BatchEndContext = {\n flowId: 'flow',\n executionId,\n batchId,\n stepId: step.id,\n timestamp: Date.now(),\n startTime: batchStartTime,\n duration: Date.now() - batchStartTime,\n totalItems: items.length,\n successfulItems: successfulCount,\n failedItems: failedCount,\n results: flowResults.map(r => r.output),\n metadata: this.metadata,\n traceContext,\n };\n await executeHook(this.observability.onBatchEnd, {\n hookName: 'onBatchEnd',\n config: this.observability,\n context: batchEndContext,\n });\n }\n\n // Notify step complete\n const stepDuration = Date.now() - stepStartTime;\n callbacks?.onStepComplete?.(step.id, stepIndex, step.type, stepDuration);\n\n // Return results array\n return {\n results: flowResults,\n metrics,\n aggregated: aggregateMetrics(metrics),\n artifacts\n };\n }\n } catch (error) {\n // Wrap error with flow execution context\n const err = error instanceof Error ? error : new Error(String(error));\n\n // Notify step error (old callbacks)\n callbacks?.onStepError?.(step.id, stepIndex, step.type, err);\n\n // Call onStepError hook (new observability)\n if (this.observability && sampled && traceContext && executionId && stepSpanId) {\n const stepErrorTime = Date.now();\n const stepErrorContext: StepErrorContext = {\n flowId: 'flow',\n executionId,\n stepId: step.id,\n stepIndex,\n timestamp: stepErrorTime,\n startTime: stepStartTime,\n duration: stepErrorTime - stepStartTime,\n error: err,\n errorCode: (err as any).code,\n willRetry: false, // TODO: Determine if will retry\n metadata: this.metadata,\n traceContext,\n spanId: stepSpanId,\n };\n\n await executeHook(this.observability.onStepError, {\n hookName: 'onStepError',\n config: this.observability,\n context: stepErrorContext,\n });\n }\n\n // Check if the error is from a nested flow\n const isNestedFlowError = err instanceof FlowExecutionError;\n\n // Build helpful error message with context\n // Only add completedStepsStr for the outermost error (avoid duplicates)\n const completedStepsStr = isNestedFlowError\n ? '' // Inner error already has this context\n : (completedSteps.length > 0\n ? `\\n Completed steps: ${completedSteps.join(' → ')}`\n : '\\n No steps completed before failure');\n\n const artifactsStr = Object.keys(artifacts).length > 0\n ? `\\n Partial results available in: ${Object.keys(artifacts).join(', ')}`\n : '';\n\n // Aggregate all completed steps across flow boundaries\n const allCompleted = isNestedFlowError\n ? [...(err.allCompletedSteps || err.completedSteps), ...completedSteps]\n : completedSteps;\n\n // Build flow path (extend nested path or create new)\n const flowPath: FlowStepLocation[] = isNestedFlowError && err.flowPath\n ? [...err.flowPath, { stepId: step.id, stepIndex, stepType: step.type }]\n : [{ stepId: step.id, stepIndex, stepType: step.type }];\n\n // Get root cause message for cleaner error display\n const errorMessage = isNestedFlowError\n ? err.getRootCause().message\n : err.message;\n\n throw new FlowExecutionError(\n `Flow execution failed at step \"${step.id}\" (index ${stepIndex}, type: ${step.type})` +\n `\\n Error: ${errorMessage}` +\n completedStepsStr +\n artifactsStr,\n step.id,\n stepIndex,\n step.type,\n completedSteps,\n isNestedFlowError ? err.originalError : err,\n artifacts, // Include partial artifacts for debugging\n flowPath,\n allCompleted\n );\n }\n }\n\n // Determine final output based on whether output nodes were used\n const hasOutputNodes = Object.keys(outputs).length > 0;\n\n let result: any;\n if (hasOutputNodes) {\n // If there are output nodes, use them for the output\n const outputCount = Object.keys(outputs).length;\n\n if (outputCount === 1) {\n // Single output node - return both output and outputs for flexibility\n const singleOutput = Object.values(outputs)[0];\n result = {\n output: singleOutput,\n outputs,\n metrics,\n aggregated: aggregateMetrics(metrics),\n artifacts\n };\n } else {\n // Multiple output nodes - return outputs object\n result = {\n output: outputs, // For backward compatibility, set output to outputs\n outputs,\n metrics,\n aggregated: aggregateMetrics(metrics),\n artifacts\n };\n }\n } else {\n // No output nodes - use traditional last-step-as-output behavior\n result = {\n output: currentData,\n metrics,\n aggregated: aggregateMetrics(metrics),\n artifacts\n };\n }\n\n // Call onFlowEnd hook\n if (this.observability && sampled && traceContext && executionId) {\n const flowEndTime = Date.now();\n const aggregated = aggregateMetrics(metrics);\n\n const flowStats: FlowStats = {\n stepsTotal: this.steps.length,\n stepsCompleted: completedSteps.length,\n stepsFailed: 0,\n totalTokens: aggregated.totalInputTokens + aggregated.totalOutputTokens,\n totalCost: aggregated.totalCostUSD,\n };\n\n const flowEndContext: FlowEndContext = {\n flowId: 'flow',\n executionId,\n timestamp: flowEndTime,\n startTime: flowStartTime,\n duration: flowEndTime - flowStartTime,\n output: result.output,\n stats: flowStats,\n metadata: this.metadata,\n traceContext,\n };\n\n await executeHook(this.observability.onFlowEnd, {\n hookName: 'onFlowEnd',\n config: this.observability,\n context: flowEndContext,\n });\n\n // Update execution context\n if (this.currentExecution) {\n this.currentExecution.status = 'completed';\n }\n }\n\n return result;\n\n } catch (error) {\n // Call onFlowError hook\n if (this.observability && sampled && traceContext && executionId) {\n const flowErrorTime = Date.now();\n const aggregated = aggregateMetrics(metrics);\n\n const flowStats: FlowStats = {\n stepsTotal: this.steps.length,\n stepsCompleted: completedSteps.length,\n stepsFailed: 1,\n totalTokens: aggregated.totalInputTokens + aggregated.totalOutputTokens,\n totalCost: aggregated.totalCostUSD,\n };\n\n // Find failed step index\n const failedStepIndex = completedSteps.length; // Next step after last completed\n\n const flowErrorContext: FlowErrorContext = {\n flowId: 'flow',\n executionId,\n timestamp: flowErrorTime,\n startTime: flowStartTime,\n duration: flowErrorTime - flowStartTime,\n error: error as Error,\n errorCode: (error as any).code,\n failedAtStepIndex: failedStepIndex,\n partialStats: flowStats,\n metadata: this.metadata,\n traceContext,\n };\n\n await executeHook(this.observability.onFlowError, {\n hookName: 'onFlowError',\n config: this.observability,\n context: flowErrorContext,\n });\n\n // Update execution context\n if (this.currentExecution) {\n this.currentExecution.status = 'failed';\n }\n }\n\n // Re-throw the original error\n throw error;\n }\n }\n}\n\n/**\n * Create a new flow builder\n *\n * @param options - Flow configuration options including observability and metadata\n * @example\n * ```typescript\n * const flow = createFlow({\n * observability: {\n * onFlowStart: (ctx) => console.log('Flow started:', ctx.flowId),\n * onStepEnd: (ctx) => console.log('Step done:', ctx.stepId, ctx.duration),\n * },\n * metadata: { environment: 'production', userId: 'user_123' }\n * });\n * ```\n */\nexport function createFlow<TInput = FlowInput>(options?: FlowOptions): Flow<TInput, TInput> {\n return new Flow<TInput, TInput>(options);\n}\n","/**\n * Flow Registry for Serializable Trigger Nodes\n *\n * This registry allows flows to be referenced by string IDs in serialized configs.\n * Used by the config API (serializable version) of trigger nodes.\n *\n * ## Usage\n *\n * ### Registration\n * ```typescript\n * import { registerFlow } from '@doclo/flows';\n * import { createFlow } from '@doclo/flows';\n * import { parse, extract } from '@doclo/nodes';\n *\n * // Register a flow builder\n * registerFlow('invoice-processing-v2', (providers) =>\n * createFlow()\n * .step('parse', parse({ provider: providers.ocr }))\n * .step('extract', extract({ provider: providers.vlm, schema: invoiceSchema }))\n * );\n * ```\n *\n * ### Retrieval\n * ```typescript\n * import { getFlow } from '@doclo/flows';\n *\n * const flowBuilder = getFlow('invoice-processing-v2');\n * if (flowBuilder) {\n * const flow = flowBuilder(myProviders);\n * const result = await flow.build().run(input);\n * }\n * ```\n *\n * ### Serialization\n * ```typescript\n * import { buildFlowFromConfig } from '@doclo/flows';\n *\n * const flowDef = {\n * version: '1.0.0',\n * steps: [\n * {\n * type: 'step',\n * nodeType: 'trigger',\n * config: {\n * type: 'trigger',\n * flowRef: 'invoice-processing-v2' // References registered flow\n * }\n * }\n * ]\n * };\n *\n * const flow = buildFlowFromConfig(flowDef, { providers, flows: FLOW_REGISTRY });\n * ```\n */\n\nimport type { ProviderRegistry } from '@doclo/nodes';\nimport type { BuiltFlow } from './flow-builder';\n\n/**\n * Flow builder function signature\n * Takes optional provider registry and returns a Flow instance with build() method\n *\n * A FlowBuilder is a function that:\n * 1. Accepts an optional ProviderRegistry (for provider injection/override)\n * 2. Returns a Flow instance (from createFlow()) that has a build() method\n * 3. The build() method returns a BuiltFlow with run() and validate()\n */\nexport type FlowBuilder<TInput = any, TOutput = any> = (providers?: ProviderRegistry) => {\n build: () => BuiltFlow<TInput, TOutput>;\n};\n\n/**\n * Global flow registry\n * Maps flow IDs to flow builder functions\n */\nexport const FLOW_REGISTRY = new Map<string, FlowBuilder>();\n\n/**\n * Register a flow builder in the global registry\n *\n * @param id - Unique identifier for the flow\n * @param builder - Flow builder function that accepts providers\n *\n * @example\n * ```typescript\n * registerFlow('invoice-processing', (providers) =>\n * createFlow()\n * .step('parse', parse({ provider: providers.ocr }))\n * .step('extract', extract({ provider: providers.vlm, schema }))\n * );\n * ```\n */\nexport function registerFlow<TInput = any, TOutput = any>(\n id: string,\n builder: FlowBuilder<TInput, TOutput>\n): void {\n if (FLOW_REGISTRY.has(id)) {\n console.warn(`[Flow Registry] Overwriting existing flow: ${id}`);\n }\n FLOW_REGISTRY.set(id, builder);\n}\n\n/**\n * Get a flow builder from the registry\n *\n * @param id - Flow identifier\n * @returns Flow builder function or undefined if not found\n *\n * @example\n * ```typescript\n * const builder = getFlow('invoice-processing');\n * if (builder) {\n * const flow = builder(providers);\n * const result = await flow.build().run(input);\n * }\n * ```\n */\nexport function getFlow<TInput = any, TOutput = any>(\n id: string\n): FlowBuilder<TInput, TOutput> | undefined {\n return FLOW_REGISTRY.get(id) as FlowBuilder<TInput, TOutput> | undefined;\n}\n\n/**\n * Check if a flow is registered\n *\n * @param id - Flow identifier\n * @returns true if flow is registered\n */\nexport function hasFlow(id: string): boolean {\n return FLOW_REGISTRY.has(id);\n}\n\n/**\n * Unregister a flow from the registry\n *\n * @param id - Flow identifier\n * @returns true if flow was removed, false if it didn't exist\n */\nexport function unregisterFlow(id: string): boolean {\n return FLOW_REGISTRY.delete(id);\n}\n\n/**\n * Clear all registered flows\n * Useful for testing or resetting state\n */\nexport function clearRegistry(): void {\n FLOW_REGISTRY.clear();\n}\n\n/**\n * Get all registered flow IDs\n *\n * @returns Array of flow identifiers\n */\nexport function listFlows(): string[] {\n return Array.from(FLOW_REGISTRY.keys());\n}\n\n/**\n * Get the number of registered flows\n *\n * @returns Number of flows in registry\n */\nexport function getFlowCount(): number {\n return FLOW_REGISTRY.size;\n}\n","/**\n * Flow Serialization\n *\n * Provides serialization/deserialization for doclo-sdk flows.\n * Supports all flow types: sequential steps, conditional branches, and forEach loops.\n *\n * Limitations:\n * - Provider instances must be reconstructed at runtime\n */\n\nimport type { NodeDef, VLMProvider, OCRProvider, JSONSchemaNode, FlowContext, FlowInput } from \"@doclo/core\";\nimport { createFlow, type FlowOptions, type Flow, type BuiltFlow } from './flow-builder.js';\nimport { parse, extract, split, categorize, trigger, output } from '@doclo/nodes';\nimport { createConditionalCompositeNode, createForEachCompositeNode } from './composite-nodes.js';\n\n/**\n * Union type for providers used in flow serialization\n */\ntype FlowProvider = VLMProvider | OCRProvider;\n\n/**\n * JSON value type for literal field mappings\n */\ntype JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue };\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyNodeDef = NodeDef<any, any>;\n\n/**\n * Serializable input validation configuration\n */\nexport type SerializableInputValidation = {\n /**\n * List of accepted MIME types.\n * If specified, input must match one of these types or validation fails.\n */\n acceptedFormats?: Array<\n | 'application/pdf'\n | 'image/jpeg'\n | 'image/png'\n | 'image/gif'\n | 'image/webp'\n >;\n /**\n * Whether to throw on validation failure.\n * @default true\n */\n throwOnInvalid?: boolean;\n};\n\n/**\n * Serializable flow definition\n */\nexport type SerializableFlow = {\n version: string;\n steps: SerializableStep[];\n /**\n * Optional input format validation configuration.\n * Allows specifying accepted MIME types for early validation.\n */\n inputValidation?: SerializableInputValidation;\n};\n\n/**\n * Serializable step definition\n */\nexport type SerializableStep =\n | SerializableStandardStep\n | SerializableConditionalStep\n | SerializableForEachStep;\n\n/**\n * Standard sequential step\n */\nexport type SerializableStandardStep = {\n type: 'step';\n id: string;\n name?: string;\n nodeType: 'parse' | 'extract' | 'split' | 'categorize' | 'trigger' | 'output';\n config: NodeConfig;\n};\n\n/**\n * Flow reference (alternative to inline SerializableFlow)\n * Used to reduce JSON nesting depth for complex flows\n */\nexport type FlowReference = {\n flowRef: string;\n};\n\n/**\n * Conditional step (categorize + branches)\n *\n * Branches can be either inline flows or references to separate flows.\n * Use references to avoid hitting database JSON nesting limits (e.g., Convex's 16-level limit).\n */\nexport type SerializableConditionalStep = {\n type: 'conditional';\n id: string;\n name?: string;\n nodeType: 'categorize';\n config: CategorizeConfig;\n branches: Record<string, SerializableFlow | FlowReference>;\n};\n\n/**\n * ForEach step (split + item flow)\n *\n * itemFlow can be either an inline flow or a reference to a separate flow.\n * Use references to avoid hitting database JSON nesting limits.\n */\nexport type SerializableForEachStep = {\n type: 'forEach';\n id: string;\n name?: string;\n nodeType: 'split';\n config: SplitConfig;\n itemFlow: SerializableFlow | FlowReference;\n};\n\n/**\n * Input mapping configuration for trigger nodes\n * Declarative alternatives to mapInput functions (for serialization)\n */\nexport type InputMappingConfig =\n | { type: 'passthrough' } // Use input as-is (default)\n | { type: 'unwrap' } // Unwrap { input: X } → X\n | { type: 'artifact'; path: string } // Get from context.artifacts by path\n | { type: 'merge'; artifactPath: string } // Merge input with artifact\n | { type: 'construct'; fields: Record<string, FieldMapping> }; // Build new object\n\nexport type FieldMapping =\n | { source: 'input'; path?: string } // Get from input (optionally by path)\n | { source: 'artifact'; path: string } // Get from artifacts by path\n | { source: 'literal'; value: JsonValue }; // Static value\n\n/**\n * Node configuration (without provider instances)\n */\nexport type NodeConfig =\n | ParseConfig\n | ExtractConfig\n | SplitConfig\n | CategorizeConfig\n | TriggerConfig\n | OutputConfig;\n\nexport type ParseConfig = {\n type: 'parse';\n providerRef: string;\n consensus?: {\n runs: number;\n strategy?: 'majority' | 'unanimous';\n onTie?: 'random' | 'fail' | 'retry';\n };\n maxTokens?: number;\n};\n\nexport type ExtractConfig = {\n type: 'extract';\n providerRef: string;\n schema: JSONSchemaNode;\n consensus?: {\n runs: number;\n strategy?: 'majority' | 'unanimous';\n onTie?: 'random' | 'fail' | 'retry';\n };\n reasoning?: {\n enabled?: boolean;\n effort?: 'low' | 'medium' | 'high';\n max_tokens?: number;\n };\n maxTokens?: number;\n};\n\nexport type SplitConfig = {\n type: 'split';\n providerRef: string;\n /**\n * Simple category definitions (recommended).\n * Each category can be a string or an object with name and optional description.\n */\n categories?: (string | { name: string; description?: string })[];\n /**\n * @deprecated Use `categories` instead. Full schema definitions for backwards compatibility.\n */\n schemas?: Record<string, JSONSchemaNode>;\n includeOther?: boolean;\n consensus?: {\n runs: number;\n strategy?: 'majority' | 'unanimous';\n onTie?: 'random' | 'fail' | 'retry';\n };\n schemaRef?: string; // Reference to schema asset (e.g., \"document-split@2.0.0\")\n maxTokens?: number;\n};\n\nexport type CategorizeConfig = {\n type: 'categorize';\n providerRef: string;\n categories: string[];\n consensus?: {\n runs: number;\n strategy?: 'majority' | 'unanimous';\n onTie?: 'random' | 'fail' | 'retry';\n };\n promptRef?: string; // Reference to prompt asset (e.g., \"default-categorize@1.0.0\")\n maxTokens?: number;\n};\n\nexport type TriggerConfig = {\n type: 'trigger';\n flowRef: string; // Reference to registered flow\n providerOverrides?: Record<string, string>; // Map child provider refs to parent refs\n inputMapping?: InputMappingConfig; // Declarative input transformation\n mergeMetrics?: boolean; // Merge child metrics (default: true)\n timeout?: number; // Timeout in milliseconds\n};\n\nexport type OutputConfig = {\n type: 'output';\n name?: string; // Output name (for multi-output flows)\n source?: string | string[]; // Source step ID(s) to pull from\n transform?: 'first' | 'last' | 'merge' | 'pick'; // Transformation strategy (custom not serializable)\n fields?: string[]; // Fields to pick (when transform: 'pick')\n};\n\n/**\n * Provider registry for deserialization\n */\nexport type ProviderRegistry = Record<string, FlowProvider>;\n\n/**\n * Extract node metadata from a node (if available)\n * Note: This is a best-effort extraction since nodes don't currently\n * expose their config. Returns null for nodes without metadata.\n */\nexport function extractNodeMetadata(node: NodeDef<unknown, unknown>): { nodeType: string; config: NodeConfig } | null {\n // Nodes created with the @doclo/nodes functions don't expose config\n // This is a limitation of the current architecture\n // For now, we return null and require manual config specification\n return null;\n}\n\n/**\n * Validation error for flow serialization\n */\nexport class FlowSerializationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'FlowSerializationError';\n }\n}\n\n/**\n * Flow registry type\n * Maps flow IDs to SerializableFlow objects (from database/Convex)\n */\nexport type FlowRegistry = Record<string, SerializableFlow>;\n\n/**\n * Type guard to check if a value is a FlowReference\n */\nexport function isFlowReference(value: SerializableFlow | FlowReference): value is FlowReference {\n return typeof value === 'object' && value !== null && 'flowRef' in value && typeof value.flowRef === 'string';\n}\n\n/**\n * Resolve a flow reference to a SerializableFlow\n *\n * @param flowOrRef - Either an inline flow or a flow reference\n * @param flows - Flow registry to resolve references from\n * @returns SerializableFlow\n * @throws FlowSerializationError if reference cannot be resolved\n */\nexport function resolveFlowReference(\n flowOrRef: SerializableFlow | FlowReference,\n flows?: FlowRegistry\n): SerializableFlow {\n if (isFlowReference(flowOrRef)) {\n if (!flows) {\n throw new FlowSerializationError(\n `Flow reference \"${flowOrRef.flowRef}\" found but no flow registry provided`\n );\n }\n\n const resolvedFlow = flows[flowOrRef.flowRef];\n if (!resolvedFlow) {\n throw new FlowSerializationError(\n `Flow reference \"${flowOrRef.flowRef}\" not found in registry. Available flows: ${Object.keys(flows).join(', ')}`\n );\n }\n\n return resolvedFlow;\n }\n\n return flowOrRef;\n}\n\n/**\n * Build a flow from a serializable definition\n *\n * @param flowDef - Serializable flow definition\n * @param providers - Provider registry (map of provider refs to provider instances)\n * @param flows - Optional flow registry for:\n * - Trigger nodes (map of flow refs to flow builders)\n * - Conditional branches (when using flowRef instead of inline SerializableFlow)\n * - ForEach itemFlow (when using flowRef instead of inline SerializableFlow)\n * @returns Executable flow\n *\n * @example\n * ```typescript\n * const flowDef: SerializableFlow = {\n * version: '1.0.0',\n * steps: [\n * {\n * type: 'step',\n * id: 'parse',\n * nodeType: 'parse',\n * config: { type: 'parse', providerRef: 'ocr' }\n * },\n * {\n * type: 'step',\n * id: 'extract',\n * nodeType: 'extract',\n * config: {\n * type: 'extract',\n * providerRef: 'llm',\n * schema: { ... }\n * }\n * }\n * ]\n * };\n *\n * const providers = {\n * ocr: suryaProvider,\n * llm: geminiProvider\n * };\n *\n * const flow = buildFlowFromConfig(flowDef, providers);\n * ```\n */\nexport function buildFlowFromConfig(\n flowDef: SerializableFlow,\n providers: ProviderRegistry,\n flows?: FlowRegistry,\n options?: FlowOptions\n): BuiltFlow<FlowInput, unknown> {\n // Validate version\n if (flowDef.version !== '1.0.0') {\n throw new FlowSerializationError(`Unsupported flow version: ${flowDef.version}`);\n }\n\n // Merge inputValidation from flowDef with options (flowDef takes precedence)\n const mergedOptions: FlowOptions = {\n ...options,\n inputValidation: flowDef.inputValidation ?? options?.inputValidation\n };\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let flow: Flow<any, any> = createFlow(mergedOptions);\n\n for (const step of flowDef.steps) {\n if (step.type === 'step') {\n // Standard sequential step\n const node = createNodeFromConfig(step.nodeType, step.config, providers, flows);\n flow = flow.step(step.id, node, step.name);\n\n } else if (step.type === 'conditional') {\n // Create composite node that handles categorize + branch execution\n const node = createConditionalCompositeNode({\n stepId: step.id,\n categorizeConfig: step.config,\n branches: step.branches,\n providers,\n flows: flows || {}\n });\n flow = flow.step(step.id, node, step.name);\n\n } else if (step.type === 'forEach') {\n // Create composite node that handles split + forEach execution\n const node = createForEachCompositeNode({\n stepId: step.id,\n splitConfig: step.config,\n itemFlow: step.itemFlow,\n providers,\n flows: flows || {}\n });\n flow = flow.step(step.id, node, step.name);\n\n } else {\n // Exhaustive check - this should be unreachable\n const exhaustiveCheck: never = step;\n throw new FlowSerializationError(`Unknown step type: ${(exhaustiveCheck as SerializableStep).type}`);\n }\n }\n\n return flow.build();\n}\n\n/**\n * Helper to safely traverse a nested object by path\n */\nfunction getByPath(obj: unknown, path: string[]): unknown {\n return path.reduce((current: unknown, key: string) => {\n if (current && typeof current === 'object' && key in current) {\n return (current as Record<string, unknown>)[key];\n }\n return undefined;\n }, obj);\n}\n\n/**\n * Create an input mapper function from declarative config\n * Uses 'any' for input/context to match the expected function signature in trigger nodes\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction createInputMapper(mappingConfig: InputMappingConfig): (input: any, context: FlowContext) => unknown {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (input: any, context: FlowContext) => {\n switch (mappingConfig.type) {\n case 'passthrough':\n return input;\n\n case 'unwrap':\n if (input && typeof input === 'object' && 'input' in input) {\n return (input as Record<string, unknown>).input;\n }\n return input;\n\n case 'artifact': {\n const pathParts = mappingConfig.path.split('.');\n return getByPath(context.artifacts, pathParts);\n }\n\n case 'merge': {\n const pathParts = mappingConfig.artifactPath.split('.');\n const artifactValue = getByPath(context.artifacts, pathParts);\n if (typeof input === 'object' && input !== null && typeof artifactValue === 'object' && artifactValue !== null) {\n return { ...input, ...artifactValue };\n }\n return input;\n }\n\n case 'construct': {\n const result: Record<string, unknown> = {};\n for (const [fieldName, fieldMapping] of Object.entries(mappingConfig.fields)) {\n switch (fieldMapping.source) {\n case 'input':\n if (fieldMapping.path) {\n const pathParts = fieldMapping.path.split('.');\n result[fieldName] = getByPath(input, pathParts);\n } else {\n result[fieldName] = input;\n }\n break;\n\n case 'artifact': {\n const pathParts = fieldMapping.path.split('.');\n result[fieldName] = getByPath(context.artifacts, pathParts);\n break;\n }\n\n case 'literal':\n result[fieldName] = fieldMapping.value;\n break;\n }\n }\n return result;\n }\n\n default:\n return input;\n }\n };\n}\n\n/**\n * Type guard to check if config has providerRef\n */\nfunction hasProviderRef(config: NodeConfig): config is NodeConfig & { providerRef: string } {\n return 'providerRef' in config && typeof config.providerRef === 'string';\n}\n\n/**\n * Helper to create a node from config\n */\nfunction createNodeFromConfig(\n nodeType: string,\n config: NodeConfig,\n providers: ProviderRegistry,\n flows?: FlowRegistry\n): AnyNodeDef {\n // For trigger nodes, flowRef is required instead of providerRef\n if (nodeType === 'trigger') {\n const cfg = config as TriggerConfig;\n\n if (!flows || !flows[cfg.flowRef]) {\n throw new FlowSerializationError(\n `Flow \"${cfg.flowRef}\" not found in flow registry. ` +\n `Available flows: ${flows ? Object.keys(flows).join(', ') : 'none'}`\n );\n }\n\n // Map provider overrides\n const overrideProviders: Record<string, FlowProvider> = {};\n if (cfg.providerOverrides) {\n for (const [childRef, parentRef] of Object.entries(cfg.providerOverrides)) {\n if (!providers[parentRef]) {\n throw new FlowSerializationError(\n `Provider \"${parentRef}\" not found in provider registry. ` +\n `Available providers: ${Object.keys(providers).join(', ')}`\n );\n }\n overrideProviders[childRef] = providers[parentRef];\n }\n }\n\n // Get flow builder from registry\n const flowBuilder = flows[cfg.flowRef];\n\n return trigger({\n flow: flowBuilder,\n flowId: cfg.flowRef,\n providers: Object.keys(overrideProviders).length > 0 ? overrideProviders : undefined,\n mapInput: cfg.inputMapping ? createInputMapper(cfg.inputMapping) : undefined,\n mergeMetrics: cfg.mergeMetrics,\n timeout: cfg.timeout\n });\n }\n\n // For output nodes, no provider is required (they pull from artifacts)\n if (nodeType === 'output') {\n const cfg = config as OutputConfig;\n return output({\n name: cfg.name,\n source: cfg.source,\n transform: cfg.transform,\n fields: cfg.fields\n });\n }\n\n // For other nodes, providerRef is required\n if (!hasProviderRef(config)) {\n throw new FlowSerializationError(\n `Config for node type \"${nodeType}\" is missing providerRef`\n );\n }\n\n const provider = providers[config.providerRef];\n if (!provider) {\n throw new FlowSerializationError(\n `Provider \"${config.providerRef}\" not found in registry. ` +\n `Available providers: ${Object.keys(providers).join(', ')}`\n );\n }\n\n switch (nodeType) {\n case 'parse': {\n const cfg = config as ParseConfig;\n // parse expects OCRProvider\n return parse({\n provider: provider as OCRProvider,\n consensus: cfg.consensus,\n maxTokens: cfg.maxTokens\n });\n }\n\n case 'extract': {\n const cfg = config as ExtractConfig;\n // extract expects VLMProvider\n return extract({\n provider: provider as VLMProvider,\n schema: cfg.schema,\n consensus: cfg.consensus,\n reasoning: cfg.reasoning,\n maxTokens: cfg.maxTokens\n });\n }\n\n case 'split': {\n const cfg = config as SplitConfig;\n // split expects VLMProvider\n return split({\n provider: provider as VLMProvider,\n // Support both categories (new) and schemas (legacy)\n ...(cfg.categories && { categories: cfg.categories }),\n ...(cfg.schemas && { schemas: cfg.schemas }),\n ...(cfg.schemaRef && { schemaRef: cfg.schemaRef }),\n includeOther: cfg.includeOther,\n consensus: cfg.consensus,\n maxTokens: cfg.maxTokens\n });\n }\n\n case 'categorize': {\n const cfg = config as CategorizeConfig;\n // categorize expects VLMProvider\n return categorize({\n provider: provider as VLMProvider,\n categories: cfg.categories,\n consensus: cfg.consensus,\n maxTokens: cfg.maxTokens\n });\n }\n\n default:\n throw new FlowSerializationError(`Unknown node type: ${nodeType}`);\n }\n}\n\n/**\n * Helper to create a serializable flow definition\n *\n * @example\n * ```typescript\n * const flowDef = defineFlowConfig({\n * version: '1.0.0',\n * steps: [\n * {\n * type: 'step',\n * id: 'parse',\n * nodeType: 'parse',\n * config: { type: 'parse', providerRef: 'ocr' }\n * }\n * ]\n * });\n *\n * // Save to database\n * await db.flows.create({ definition: JSON.stringify(flowDef) });\n *\n * // Later, load and build\n * const loaded = JSON.parse(row.definition);\n * const flow = buildFlowFromConfig(loaded, providers);\n * ```\n */\nexport function defineFlowConfig(config: Omit<SerializableFlow, 'version'>): SerializableFlow {\n return {\n version: '1.0.0',\n ...config\n };\n}\n","/**\n * Composite nodes for conditional and forEach execution\n *\n * These nodes wrap complex multi-step operations (categorize + branch, split + forEach)\n * into single logical steps with proper observability, metrics, and error handling.\n */\n\nimport type { NodeDef, StepMetric, VLMProvider, FlowResult, NodeCtx, FlowInput, SplitDocument, FlowStepLocation } from '@doclo/core';\nimport { FlowExecutionError } from '@doclo/core';\nimport { buildFlowFromConfig, type ProviderRegistry } from './serialization.js';\nimport type { SerializableFlow, FlowReference, CategorizeConfig, SplitConfig } from './serialization.js';\nimport { categorize, split } from '@doclo/nodes';\nimport { isSingleFlowResult, type BatchFlowResult } from './flow-builder.js';\n\n/**\n * Flow registry type\n * Maps flow IDs to SerializableFlow objects (from database/Convex)\n */\ntype FlowRegistry = Record<string, SerializableFlow>;\n\n/**\n * Parse provider name in format \"provider:model\" to separate fields\n * Example: \"google:gemini-2.5-flash\" -> { provider: \"google\", model: \"gemini-2.5-flash\" }\n */\nfunction parseProviderName(name: string): { provider: string; model: string } {\n const colonIndex = name.indexOf(':');\n if (colonIndex === -1) {\n // No colon found, treat entire name as provider\n return { provider: name, model: 'unknown' };\n }\n return {\n provider: name.substring(0, colonIndex),\n model: name.substring(colonIndex + 1)\n };\n}\n\n/**\n * Parse reference string in format \"id@version\" to extract id and version\n * @example \"my-prompt@1.2.0\" -> { id: \"my-prompt\", version: \"1.2.0\" }\n * @example \"my-prompt\" -> { id: \"my-prompt\", version: undefined }\n */\nfunction parseRef(refString: string | undefined): { id: string; version: string | undefined } | null {\n if (!refString) return null;\n\n const atIndex = refString.indexOf('@');\n if (atIndex === -1) {\n return { id: refString, version: undefined };\n }\n\n return {\n id: refString.substring(0, atIndex),\n version: refString.substring(atIndex + 1)\n };\n}\n\n/**\n * Helper function to flatten child flow metrics by prefixing step names\n * Follows the pattern from trigger node (packages/nodes/src/trigger.ts:253-276)\n */\nfunction flattenMetrics(\n childMetrics: StepMetric[],\n prefix: string\n): StepMetric[] {\n return childMetrics.map(m => ({\n ...m,\n step: `${prefix}.${m.step}`,\n // @ts-ignore - Add metadata for nested metrics (not in official type but works at runtime)\n nested: true\n }));\n}\n\n/**\n * Configuration for conditional composite node\n */\nexport interface ConditionalCompositeConfig {\n stepId: string;\n categorizeConfig: CategorizeConfig;\n branches: Record<string, SerializableFlow | FlowReference>;\n providers: ProviderRegistry;\n flows: FlowRegistry;\n}\n\n/**\n * Creates a composite node that:\n * 1. Executes a categorize node to determine the category\n * 2. Selects and executes the appropriate branch flow\n * 3. Returns the branch flow's output\n *\n * Includes full observability, metrics merging, and error context.\n */\nexport function createConditionalCompositeNode(\n config: ConditionalCompositeConfig\n): NodeDef<FlowInput, unknown> {\n const { stepId, categorizeConfig, branches, providers, flows } = config;\n\n return {\n key: 'conditional-composite',\n run: async (input: FlowInput, ctx?: NodeCtx) => {\n const t0 = Date.now();\n let selectedCategory: string | undefined;\n let phase: 'categorize' | 'branch' = 'categorize';\n\n try {\n // === PHASE 1: CATEGORIZE ===\n // Build categorize node\n // Cast to VLMProvider since categorize requires VLM capabilities\n const categorizeNode = categorize({\n ...categorizeConfig,\n provider: providers[categorizeConfig.providerRef] as VLMProvider,\n categories: categorizeConfig.categories || Object.keys(branches)\n });\n\n // Execute categorize node (track metrics to get cost)\n const categorizeT0 = Date.now();\n const categorizeCostTracker: StepMetric[] = [];\n const categorizeCtx: NodeCtx = {\n stepId: stepId, // Use composite step's ID so categorize metric is attributed to this step\n metrics: { push: (m: StepMetric) => categorizeCostTracker.push(m) },\n artifacts: ctx?.artifacts ?? {},\n emit: ctx?.emit ?? (() => {}), // No-op if emit not provided\n observability: ctx?.observability\n };\n const categorizeResult = await categorizeNode.run(input, categorizeCtx);\n selectedCategory = categorizeResult.category;\n\n // Push categorize metric to main context\n categorizeCostTracker.forEach(m => ctx?.metrics?.push(m));\n\n // Store category decision in artifacts\n if (ctx?.emit) {\n ctx.emit(`${stepId}:category`, selectedCategory);\n }\n\n // === PHASE 2: ROUTE TO BRANCH ===\n phase = 'branch';\n\n // Check if branch exists\n if (!branches[selectedCategory]) {\n throw new Error(\n `No branch defined for category \"${selectedCategory}\". ` +\n `Available branches: ${Object.keys(branches).join(', ')}`\n );\n }\n\n // Resolve flow reference to actual flow definition\n const branchFlowDef = resolveBranchFlow(branches[selectedCategory], flows);\n\n // Build the branch flow with observability options\n const branchFlow = buildFlowFromConfig(\n branchFlowDef,\n providers,\n flows,\n ctx?.observability?.config ? {\n observability: ctx.observability.config,\n metadata: {\n ...ctx.observability?.metadata,\n parentNode: stepId,\n phase: 'branch',\n category: selectedCategory\n }\n } : undefined\n );\n\n // Execute branch flow\n const branchT0 = Date.now();\n const branchResultRaw = await branchFlow.run(input);\n\n // Type guard to ensure we have a single flow result\n if (!isSingleFlowResult(branchResultRaw)) {\n throw new Error('Branch flow returned batch result instead of single result');\n }\n const branchResult = branchResultRaw;\n\n // Merge branch flow metrics\n if (ctx?.metrics && branchResult.metrics) {\n const branchMetrics = flattenMetrics(\n branchResult.metrics,\n `${stepId}.branch.${selectedCategory}`\n );\n branchMetrics.forEach(m => ctx.metrics.push(m));\n }\n\n // Store branch output in artifacts\n if (ctx?.emit) {\n ctx.emit(`${stepId}:branchOutput`, branchResult.output);\n ctx.emit(`${stepId}:branchArtifacts`, branchResult.artifacts);\n }\n\n // === PHASE 3: COMPLETE ===\n // Calculate aggregate cost from categorize + branch operations\n const categorizeCost = categorizeCostTracker.reduce((sum: number, m: StepMetric) => sum + (m.costUSD ?? 0), 0);\n const branchCost = branchResult.metrics\n ? branchResult.metrics.reduce((sum: number, m: StepMetric) => sum + (m.costUSD ?? 0), 0)\n : 0;\n const aggregateCost = categorizeCost + branchCost;\n\n // Calculate duration breakdown\n const totalMs = Date.now() - t0;\n const categorizeMs = categorizeCostTracker.reduce((sum: number, m: StepMetric) => sum + (m.ms ?? 0), 0);\n const branchMs = branchResult.metrics\n ? branchResult.metrics.reduce((sum: number, m: StepMetric) => sum + (m.ms ?? 0), 0)\n : 0;\n const overheadMs = totalMs - categorizeMs - branchMs; // Pure wrapper overhead\n\n // Add composite node overhead metric\n if (ctx?.metrics) {\n const provider = providers[categorizeConfig.providerRef];\n const { provider: providerName, model } = parseProviderName(provider.name ?? '');\n\n // Extract promptId and promptVersion from promptRef if present\n const promptRefData = parseRef(categorizeConfig.promptRef);\n\n const wrapperMetric: StepMetric = {\n step: stepId,\n configStepId: ctx.stepId,\n startMs: t0,\n provider: providerName,\n model,\n ms: totalMs,\n costUSD: aggregateCost, // Total cost from categorize + branch\n attemptNumber: 1, // Composite wrappers don't retry, always 1\n metadata: {\n kind: 'wrapper', // Distinguish wrapper from leaf metrics\n type: 'conditional',\n rollup: true, // Duration includes child work\n overheadMs, // Pure wrapper overhead (flow orchestration)\n category: selectedCategory,\n branchStepCount: branchResult.metrics?.length || 0,\n branchFlowId: typeof branches[selectedCategory] === 'object' && 'flowRef' in branches[selectedCategory]\n ? (branches[selectedCategory] as FlowReference).flowRef\n : 'inline',\n // Include prompt metadata if available\n ...(promptRefData && {\n promptId: promptRefData.id,\n ...(promptRefData.version && { promptVersion: promptRefData.version })\n })\n }\n };\n\n ctx.metrics.push(wrapperMetric);\n }\n\n // Return branch output (transparent to next step)\n return branchResult.output;\n\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n const isNestedFlowError = err instanceof FlowExecutionError;\n\n // Add error metric\n if (ctx?.metrics) {\n ctx.metrics.push({\n step: stepId,\n configStepId: ctx.stepId,\n startMs: t0,\n ms: Date.now() - t0,\n costUSD: 0,\n attemptNumber: 1,\n // @ts-ignore - Add error field\n error: err.message,\n metadata: {\n kind: 'wrapper',\n type: 'conditional',\n failed: true,\n category: selectedCategory,\n failedPhase: phase\n }\n });\n }\n\n // Build flow path with branch context\n const flowPath: FlowStepLocation[] = [{\n stepId,\n stepIndex: 0,\n stepType: 'conditional',\n branch: selectedCategory || undefined\n }];\n\n // If inner error is FlowExecutionError, extend its path\n if (isNestedFlowError && err.flowPath) {\n flowPath.push(...err.flowPath);\n }\n\n // Get the root cause message for cleaner error display\n const rootCauseMessage = isNestedFlowError\n ? err.getRootCause().message\n : err.message;\n\n // Throw FlowExecutionError with full context\n throw new FlowExecutionError(\n `Conditional step \"${stepId}\" failed` +\n `${selectedCategory ? ` (category: ${selectedCategory})` : ''}` +\n ` in phase: ${phase}` +\n `\\n Error: ${rootCauseMessage}`,\n stepId,\n 0,\n 'conditional',\n [],\n isNestedFlowError ? err.originalError : err,\n undefined,\n flowPath,\n isNestedFlowError ? err.allCompletedSteps : undefined\n );\n }\n }\n };\n}\n\n/**\n * Configuration for forEach composite node\n */\nexport interface ForEachCompositeConfig {\n stepId: string;\n splitConfig: SplitConfig;\n itemFlow: SerializableFlow | FlowReference;\n providers: ProviderRegistry;\n flows: FlowRegistry;\n}\n\n/**\n * Creates a composite node that:\n * 1. Executes a split node to get an array of items\n * 2. Executes the item flow for each item in parallel\n * 3. Returns aggregated results\n *\n * Includes full observability, metrics merging, and error context.\n */\nexport function createForEachCompositeNode(\n config: ForEachCompositeConfig\n): NodeDef<FlowInput, unknown[]> {\n const { stepId, splitConfig, itemFlow, providers, flows } = config;\n\n return {\n key: 'forEach-composite',\n run: async (input: FlowInput, ctx?: NodeCtx) => {\n const t0 = Date.now();\n let items: SplitDocument[] | undefined;\n let phase: 'split' | 'forEach' = 'split';\n\n try {\n // === PHASE 1: SPLIT ===\n // Build split node\n // Cast to VLMProvider since split requires VLM capabilities\n const splitNode = split({\n provider: providers[splitConfig.providerRef] as VLMProvider,\n ...splitConfig\n });\n\n // Execute split node (track metrics to get cost)\n const splitT0 = Date.now();\n const splitCostTracker: StepMetric[] = [];\n const splitCtx: NodeCtx = {\n stepId: stepId, // Use composite step's ID for attribution\n metrics: { push: (m: StepMetric) => splitCostTracker.push(m) },\n artifacts: ctx?.artifacts ?? {},\n emit: ctx?.emit ?? (() => {}), // No-op if emit not provided\n observability: ctx?.observability\n };\n const splitResult = await splitNode.run(input, splitCtx);\n items = splitResult; // Split node returns array directly\n\n // Push split metric to main context\n splitCostTracker.forEach(m => ctx?.metrics?.push(m));\n\n if (!Array.isArray(items)) {\n throw new Error(\n `Split node did not return an array. Got: ${typeof items}`\n );\n }\n\n // Store item count in artifacts\n if (ctx?.emit) {\n ctx.emit(`${stepId}:itemCount`, items.length);\n }\n\n // === PHASE 2: FOR EACH ===\n phase = 'forEach';\n\n // Resolve flow reference to actual flow definition\n const itemFlowDef = resolveBranchFlow(itemFlow, flows);\n\n // Track all item flow results to aggregate costs\n const itemFlowResults: FlowResult<unknown>[] = [];\n\n // Execute item flow for each item in parallel\n const results = await Promise.allSettled(\n items.map(async (item, index) => {\n // Build item flow with observability options\n const flow = buildFlowFromConfig(\n itemFlowDef,\n providers,\n flows,\n ctx?.observability?.config ? {\n observability: ctx.observability.config,\n metadata: {\n ...ctx.observability?.metadata,\n parentNode: stepId,\n phase: 'forEach',\n itemIndex: index,\n totalItems: items!.length\n }\n } : undefined\n );\n\n // Execute item flow\n // Pass the split document's input field (which contains url/base64/pages/bounds)\n const itemT0 = Date.now();\n const resultRaw = await flow.run(item.input);\n\n // Type guard to ensure we have a single flow result\n if (!isSingleFlowResult(resultRaw)) {\n throw new Error('Item flow returned batch result instead of single result');\n }\n const result = resultRaw;\n\n // Store result for cost aggregation\n itemFlowResults.push(result);\n\n // Merge item flow metrics\n if (ctx?.metrics && result.metrics) {\n const itemMetrics = flattenMetrics(\n result.metrics,\n `${stepId}.item[${index}]`\n );\n itemMetrics.forEach(m => ctx.metrics.push(m));\n }\n\n return result.output;\n })\n );\n\n // === PHASE 3: AGGREGATE ===\n // Count successes and failures\n const successCount = results.filter(r => r.status === 'fulfilled').length;\n const failureCount = results.filter(r => r.status === 'rejected').length;\n\n // Calculate aggregate cost from split + all item flows\n const splitCost = splitCostTracker.reduce((sum: number, m: StepMetric) => sum + (m.costUSD ?? 0), 0);\n const itemsCost = itemFlowResults.reduce((sum: number, result: FlowResult<unknown>) => {\n const itemCost = result.metrics\n ? result.metrics.reduce((s: number, m: StepMetric) => s + (m.costUSD ?? 0), 0)\n : 0;\n return sum + itemCost;\n }, 0);\n const aggregateCost = splitCost + itemsCost;\n\n // Calculate duration breakdown\n const totalMs = Date.now() - t0;\n const splitMs = splitCostTracker.reduce((sum: number, m: StepMetric) => sum + (m.ms ?? 0), 0);\n const itemsMs = itemFlowResults.reduce((sum: number, result: FlowResult<unknown>) => {\n const itemMs = result.metrics\n ? result.metrics.reduce((s: number, m: StepMetric) => s + (m.ms ?? 0), 0)\n : 0;\n return sum + itemMs;\n }, 0);\n const overheadMs = totalMs - splitMs - itemsMs; // Pure wrapper overhead\n\n // Store results in artifacts\n if (ctx?.emit) {\n ctx.emit(`${stepId}:results`, results);\n ctx.emit(`${stepId}:successCount`, successCount);\n ctx.emit(`${stepId}:failureCount`, failureCount);\n }\n\n // Add composite node overhead metric\n if (ctx?.metrics) {\n const provider = providers[splitConfig.providerRef];\n const { provider: providerName, model } = parseProviderName(provider.name ?? '');\n\n // Extract schemaId and schemaVersion from schemaRef if present\n const schemaRefData = parseRef(splitConfig.schemaRef);\n\n ctx.metrics.push({\n step: stepId,\n configStepId: ctx.stepId,\n startMs: t0,\n provider: providerName,\n model,\n ms: totalMs,\n costUSD: aggregateCost, // Total cost from split + all items\n attemptNumber: 1, // Composite wrappers don't retry, always 1\n metadata: {\n kind: 'wrapper', // Distinguish wrapper from leaf metrics\n type: 'forEach',\n rollup: true, // Duration includes child work\n overheadMs, // Pure wrapper overhead (flow orchestration)\n itemCount: items.length,\n successCount,\n failureCount,\n itemFlowId: typeof itemFlow === 'object' && 'flowRef' in itemFlow\n ? (itemFlow as FlowReference).flowRef\n : 'inline',\n // Include schema metadata if available\n ...(schemaRefData && {\n schemaId: schemaRefData.id,\n ...(schemaRefData.version && { schemaVersion: schemaRefData.version })\n })\n }\n });\n }\n\n // Return results in forEach format (matching runtime API)\n return results;\n\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n const isNestedFlowError = err instanceof FlowExecutionError;\n\n // Add error metric\n if (ctx?.metrics) {\n ctx.metrics.push({\n step: stepId,\n configStepId: ctx.stepId,\n startMs: t0,\n ms: Date.now() - t0,\n costUSD: 0,\n attemptNumber: 1,\n // @ts-ignore - Add error field\n error: err.message,\n metadata: {\n kind: 'wrapper',\n type: 'forEach',\n failed: true,\n itemCount: items?.length,\n failedPhase: phase\n }\n });\n }\n\n // Build flow path with forEach context\n const flowPath: FlowStepLocation[] = [{\n stepId,\n stepIndex: 0,\n stepType: 'forEach'\n }];\n\n // If inner error is FlowExecutionError, extend its path\n if (isNestedFlowError && err.flowPath) {\n flowPath.push(...err.flowPath);\n }\n\n // Get the root cause message for cleaner error display\n const rootCauseMessage = isNestedFlowError\n ? err.getRootCause().message\n : err.message;\n\n // Throw FlowExecutionError with full context\n throw new FlowExecutionError(\n `ForEach step \"${stepId}\" failed` +\n `${items ? ` (itemCount: ${items.length})` : ''}` +\n ` in phase: ${phase}` +\n `\\n Error: ${rootCauseMessage}`,\n stepId,\n 0,\n 'forEach',\n [],\n isNestedFlowError ? err.originalError : err,\n undefined,\n flowPath,\n isNestedFlowError ? err.allCompletedSteps : undefined\n );\n }\n }\n };\n}\n\n/**\n * Helper function to resolve flow references\n *\n * Resolves flow references from the registry (database-driven flows).\n * The registry contains SerializableFlow objects, not flow builder functions.\n */\nfunction resolveBranchFlow(\n flowOrRef: SerializableFlow | FlowReference,\n flows: FlowRegistry\n): SerializableFlow {\n // Check if it's a flow reference\n if (typeof flowOrRef === 'object' && flowOrRef !== null && 'flowRef' in flowOrRef) {\n const flowRef = (flowOrRef as FlowReference).flowRef;\n\n if (!flows[flowRef]) {\n throw new Error(\n `Flow reference \"${flowRef}\" not found in registry. ` +\n `Available flows: ${Object.keys(flows).join(', ')}`\n );\n }\n\n // Return the serializable flow directly from registry\n // (flows are already SerializableFlow objects from database/Convex)\n return flows[flowRef];\n }\n\n // It's an inline flow, return as-is\n return flowOrRef as SerializableFlow;\n}\n","/**\n * Flow Validation\n *\n * Provides validation for flow configurations before execution.\n */\n\nimport type { JSONSchemaNode } from '@doclo/core';\nimport type {\n SerializableFlow,\n NodeConfig,\n SerializableConditionalStep,\n SerializableForEachStep,\n ExtractConfig,\n SplitConfig,\n CategorizeConfig,\n TriggerConfig,\n OutputConfig,\n FlowReference\n} from './serialization.js';\nimport { isDebugValidation } from '@doclo/core/runtime/env';\n\n/**\n * Validate JSON Schema structure (Edge Runtime compatible)\n *\n * This is a lightweight validator that checks basic JSON Schema structure\n * without using AJV's code generation (which breaks Edge Runtime).\n *\n * @param schema - JSON Schema object to validate\n * @param depth - Current recursion depth (internal parameter)\n * @returns Error message if invalid, null if valid\n */\nfunction validateJSONSchemaStructure(schema: unknown, depth: number = 0): string | null {\n const MAX_DEPTH = 50; // Prevent DoS via deeply nested schemas\n\n // Check recursion depth to prevent DoS attacks\n if (depth > MAX_DEPTH) {\n return `Schema nesting depth exceeds maximum (${MAX_DEPTH})`;\n }\n\n if (!schema || typeof schema !== 'object' || Array.isArray(schema)) {\n return 'Schema must be an object';\n }\n\n // Type narrowed schema as Record for property access\n const schemaObj = schema as Record<string, unknown>;\n\n // Check for basic JSON Schema properties\n if (!schemaObj.type || typeof schemaObj.type !== 'string') {\n return 'Schema missing \"type\" property';\n }\n\n const validTypes = ['object', 'array', 'string', 'number', 'integer', 'boolean', 'null'];\n if (!validTypes.includes(schemaObj.type)) {\n return `Invalid schema type: \"${schemaObj.type}\". Must be one of: ${validTypes.join(', ')}`;\n }\n\n // Validate object schemas\n if (schemaObj.type === 'object') {\n if (schemaObj.properties && typeof schemaObj.properties !== 'object') {\n return 'Schema properties must be an object';\n }\n\n if (schemaObj.required && !Array.isArray(schemaObj.required)) {\n return 'Schema required must be an array';\n }\n\n // Recursively validate nested properties\n if (schemaObj.properties && typeof schemaObj.properties === 'object' && !Array.isArray(schemaObj.properties)) {\n const properties = schemaObj.properties as Record<string, unknown>;\n for (const [propName, propSchema] of Object.entries(properties)) {\n const propError = validateJSONSchemaStructure(propSchema, depth + 1);\n if (propError) {\n return `Invalid schema for property \"${propName}\": ${propError}`;\n }\n }\n }\n }\n\n // Validate array schemas\n if (schemaObj.type === 'array') {\n if (!schemaObj.items) {\n return 'Array schema missing \"items\" property';\n }\n\n const itemsError = validateJSONSchemaStructure(schemaObj.items, depth + 1);\n if (itemsError) {\n return `Invalid array items schema: ${itemsError}`;\n }\n }\n\n return null;\n}\n\n/**\n * Calculate JSON nesting depth for a flow\n *\n * This calculates the actual JSON nesting depth when the flow is serialized,\n * which is important for Convex and other databases with nesting limits.\n *\n * Each logical nesting level adds multiple JSON levels:\n * - Conditional step: +5 levels (branches → category → flow → steps → step)\n * - ForEach step: +4 levels (itemFlow → flow → steps → step)\n * - Standard step with schema: +4 levels (config → schema → properties → field)\n *\n * @param flow - Flow definition to analyze\n * @param currentDepth - Current depth (used for recursion)\n * @returns Maximum JSON nesting depth\n */\nfunction calculateFlowNestingDepth(flow: SerializableFlow, currentDepth: number = 1): number {\n // Start at depth 1 for the root flow object\n // +1 for steps array\n let maxDepth = currentDepth + 1;\n\n for (const step of flow.steps) {\n // +1 for step object itself\n let stepDepth = currentDepth + 2;\n\n if (step.type === 'conditional') {\n // Conditional: step → branches (obj) → category → flow/flowRef\n // Type narrowing: step is SerializableConditionalStep\n const conditionalStep = step as SerializableConditionalStep;\n if (conditionalStep.branches) {\n for (const branchFlowOrRef of Object.values(conditionalStep.branches)) {\n // Check if it's a flow reference\n if ('flowRef' in branchFlowOrRef) {\n // Flow reference: branches (+1) → category (+1) → flowRef object (+1) = +3 from step\n // This is much shallower than inline flows!\n maxDepth = Math.max(maxDepth, stepDepth + 3);\n } else {\n // Inline flow: branches (+1) → category (+1) → flow → steps → nested step = +5+ levels\n const branchDepth = calculateFlowNestingDepth(branchFlowOrRef, stepDepth + 2);\n maxDepth = Math.max(maxDepth, branchDepth);\n }\n }\n }\n } else if (step.type === 'forEach') {\n // ForEach: step → itemFlow (obj or ref)\n // Type narrowing: step is SerializableForEachStep\n const forEachStep = step as SerializableForEachStep;\n if (forEachStep.itemFlow) {\n const itemFlowOrRef = forEachStep.itemFlow;\n\n // Check if it's a flow reference\n if ('flowRef' in itemFlowOrRef) {\n // Flow reference: itemFlow (+1) → flowRef object (+1) = +2 from step\n maxDepth = Math.max(maxDepth, stepDepth + 2);\n } else {\n // Inline flow: itemFlow (+1) → flow → steps → nested step = +4+ levels\n const itemDepth = calculateFlowNestingDepth(itemFlowOrRef, stepDepth + 1);\n maxDepth = Math.max(maxDepth, itemDepth);\n }\n }\n } else {\n // Standard step: check for schema depth\n const config = step.config;\n\n // config object (+1)\n let configDepth = stepDepth + 1;\n\n // If has schema: schema (+1) → properties (+1) → field (+1) → type/items (+1)\n // That's +4 levels for a typical schema\n if ('schema' in config && config.schema) {\n configDepth += 4; // Typical schema nesting\n }\n\n // If has schemas (for split): similar depth\n if ('schemas' in config && config.schemas) {\n configDepth += 4;\n }\n\n maxDepth = Math.max(maxDepth, configDepth);\n }\n }\n\n return maxDepth;\n}\n\n/**\n * Validation result\n */\nexport type ValidationResult = {\n valid: boolean;\n errors: ValidationError[];\n warnings: ValidationWarning[];\n};\n\n/**\n * Validation error\n */\nexport type ValidationError = {\n type: 'missing_provider' | 'invalid_schema' | 'invalid_config' | 'version_mismatch';\n stepId?: string;\n message: string;\n details?: Record<string, unknown>;\n};\n\n/**\n * Validation warning\n */\nexport type ValidationWarning = {\n type: 'deprecated' | 'performance' | 'best_practice';\n stepId?: string;\n message: string;\n details?: Record<string, unknown>;\n};\n\n/**\n * Provider instance used for validation (minimal interface)\n */\ninterface ValidationProviderInstance {\n name?: string;\n // Providers can have additional properties\n [key: string]: unknown;\n}\n\n/**\n * Validation options\n */\nexport type ValidationOptions = {\n checkProviders?: boolean; // Check if providers exist in registry\n checkSchemas?: boolean; // Validate JSON schemas\n checkVersion?: boolean; // Check flow version compatibility\n providers?: Record<string, ValidationProviderInstance>; // Provider registry for validation\n};\n\n/**\n * Validate a serializable flow definition\n *\n * @param flowDef - Flow definition to validate\n * @param options - Validation options\n * @returns Validation result with errors and warnings\n *\n * @example\n * ```typescript\n * const result = validateFlow(flowDef, {\n * checkProviders: true,\n * checkSchemas: true,\n * providers: { ocr: suryaProvider, llm: geminiProvider }\n * });\n *\n * if (!result.valid) {\n * console.error('Flow validation failed:', result.errors);\n * }\n * ```\n */\nexport function validateFlow(\n flowDef: SerializableFlow,\n options: ValidationOptions = {}\n): ValidationResult {\n const errors: ValidationError[] = [];\n const warnings: ValidationWarning[] = [];\n\n // Default options\n const opts = {\n checkProviders: true,\n checkSchemas: true,\n checkVersion: true,\n ...options\n };\n\n // Validate version\n if (opts.checkVersion) {\n if (!flowDef.version) {\n errors.push({\n type: 'version_mismatch',\n message: 'Flow definition missing version field'\n });\n } else if (flowDef.version !== '1.0.0') {\n errors.push({\n type: 'version_mismatch',\n message: `Unsupported flow version: ${flowDef.version}. Expected: 1.0.0`,\n details: { version: flowDef.version }\n });\n }\n }\n\n // Validate steps\n if (!flowDef.steps || !Array.isArray(flowDef.steps)) {\n errors.push({\n type: 'invalid_config',\n message: 'Flow definition missing or invalid steps array'\n });\n return { valid: false, errors, warnings };\n }\n\n if (flowDef.steps.length === 0) {\n warnings.push({\n type: 'best_practice',\n message: 'Flow has no steps defined'\n });\n }\n\n // Check nesting depth to prevent Convex 16-level limit issues\n const nestingDepth = calculateFlowNestingDepth(flowDef);\n if (nestingDepth > 14) {\n errors.push({\n type: 'invalid_config',\n message: `Flow nesting depth (${nestingDepth} levels) exceeds recommended maximum (14 levels). This will cause issues with Convex and other databases with 16-level JSON nesting limits. Consider using flow references (flowRef) to reduce nesting depth.`,\n details: { nestingDepth, limit: 14 }\n });\n } else if (nestingDepth > 12) {\n warnings.push({\n type: 'performance',\n message: `Flow nesting depth (${nestingDepth} levels) is approaching the database limit (16 levels). Consider using flow references to reduce complexity.`,\n details: { nestingDepth, warningThreshold: 12 }\n });\n }\n\n // Validate each step\n for (const step of flowDef.steps) {\n const stepId = step.id || 'unknown';\n\n // Validate step type\n if (!step.type) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Step missing type field'\n });\n continue;\n }\n\n // Validate conditional and forEach specific fields\n if (step.type === 'conditional') {\n const conditionalStep = step as SerializableConditionalStep;\n if (!conditionalStep.branches || typeof conditionalStep.branches !== 'object') {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Conditional step missing or invalid branches field'\n });\n } else {\n // Recursively validate each branch flow (or flow reference)\n for (const [category, branchFlowOrRef] of Object.entries(conditionalStep.branches)) {\n // Check if it's a flow reference\n if ('flowRef' in branchFlowOrRef) {\n // Validate flowRef format\n const flowRef = (branchFlowOrRef as FlowReference).flowRef;\n if (typeof flowRef !== 'string' || flowRef.trim() === '') {\n errors.push({\n type: 'invalid_config',\n stepId: `${stepId}.${category}`,\n message: `Branch \"${category}\": flowRef must be a non-empty string`\n });\n }\n // Note: We don't resolve and validate referenced flows here to avoid circular dependencies\n // The flow registry should be validated separately if needed\n } else {\n // Inline flow - validate recursively\n const branchResult = validateFlow(branchFlowOrRef as SerializableFlow, options);\n for (const error of branchResult.errors) {\n errors.push({\n ...error,\n stepId: `${stepId}.${category}`,\n message: `Branch \"${category}\": ${error.message}`\n });\n }\n for (const warning of branchResult.warnings) {\n warnings.push({\n ...warning,\n stepId: `${stepId}.${category}`,\n message: `Branch \"${category}\": ${warning.message}`\n });\n }\n }\n }\n }\n } else if (step.type === 'forEach') {\n const forEachStep = step as SerializableForEachStep;\n if (!forEachStep.itemFlow) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'ForEach step missing itemFlow field'\n });\n } else {\n const itemFlowOrRef = forEachStep.itemFlow;\n\n // Check if it's a flow reference\n if ('flowRef' in itemFlowOrRef) {\n // Validate flowRef format\n const flowRef = (itemFlowOrRef as FlowReference).flowRef;\n if (typeof flowRef !== 'string' || flowRef.trim() === '') {\n errors.push({\n type: 'invalid_config',\n stepId: `${stepId}.itemFlow`,\n message: `itemFlow: flowRef must be a non-empty string`\n });\n }\n // Note: We don't resolve and validate referenced flows here to avoid circular dependencies\n } else {\n // Inline flow - recursively validate item flow\n const itemResult = validateFlow(itemFlowOrRef as SerializableFlow, options);\n for (const error of itemResult.errors) {\n errors.push({\n ...error,\n stepId: `${stepId}.itemFlow`,\n message: `Item flow: ${error.message}`\n });\n }\n for (const warning of itemResult.warnings) {\n warnings.push({\n ...warning,\n stepId: `${stepId}.itemFlow`,\n message: `Item flow: ${warning.message}`\n });\n }\n }\n }\n }\n\n // Validate node type\n const validNodeTypes = ['parse', 'extract', 'split', 'categorize', 'trigger', 'output'];\n if (!step.nodeType || !validNodeTypes.includes(step.nodeType)) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: `Invalid node type: ${step.nodeType}. Must be one of: ${validNodeTypes.join(', ')}`,\n details: { nodeType: step.nodeType }\n });\n continue;\n }\n\n // Validate config exists\n if (!step.config) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Step missing config field'\n });\n continue;\n }\n\n const config = step.config as NodeConfig;\n\n // Helper to check if config has providerRef (for configs that need it)\n const hasProviderRef = (cfg: NodeConfig): cfg is NodeConfig & { providerRef: string } => {\n return 'providerRef' in cfg && typeof cfg.providerRef === 'string';\n };\n\n // Validate provider reference (not applicable for trigger and output nodes)\n if (step.nodeType !== 'trigger' && step.nodeType !== 'output') {\n if (!hasProviderRef(config)) {\n errors.push({\n type: 'missing_provider',\n stepId,\n message: 'Step config missing providerRef'\n });\n } else if (opts.checkProviders && opts.providers) {\n if (!opts.providers[config.providerRef]) {\n errors.push({\n type: 'missing_provider',\n stepId,\n message: `Provider \"${config.providerRef}\" not found in registry`,\n details: {\n providerRef: config.providerRef,\n availableProviders: Object.keys(opts.providers)\n }\n });\n }\n }\n }\n\n // Validate node-specific config\n if (opts.checkSchemas) {\n switch (step.nodeType) {\n case 'extract': {\n const cfg = config as ExtractConfig;\n if (!cfg.schema) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Extract node missing schema'\n });\n } else {\n // Validate JSON schema structure\n const schemaError = validateJSONSchemaStructure(cfg.schema);\n if (schemaError) {\n errors.push({\n type: 'invalid_schema',\n stepId,\n message: `Invalid JSON schema: ${schemaError}`,\n details: { schema: cfg.schema as Record<string, unknown> }\n });\n }\n }\n\n // Check reasoning config if present\n if (cfg.reasoning) {\n if (cfg.reasoning.effort && !['low', 'medium', 'high'].includes(cfg.reasoning.effort)) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: `Invalid reasoning effort: ${cfg.reasoning.effort}. Must be: low, medium, or high`\n });\n }\n }\n break;\n }\n\n case 'split': {\n const cfg = config as SplitConfig;\n const hasCategories = cfg.categories && Array.isArray(cfg.categories);\n const hasSchemas = cfg.schemas && typeof cfg.schemas === 'object';\n const hasSchemaRef = cfg.schemaRef && typeof cfg.schemaRef === 'string';\n\n // Must have at least one: categories, schemas, or schemaRef\n if (!hasCategories && !hasSchemas && !hasSchemaRef) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Split node requires either categories, schemas, or schemaRef'\n });\n }\n\n // Cannot have both categories and schemas\n if (hasCategories && hasSchemas) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Split node cannot have both categories and schemas. Use categories (recommended) or schemas, not both.'\n });\n }\n\n // Validate categories if provided\n if (hasCategories) {\n if (cfg.categories!.length === 0) {\n warnings.push({\n type: 'best_practice',\n stepId,\n message: 'Split node has no categories defined'\n });\n } else {\n // Validate each category is either a string or { name: string; description?: string }\n for (let i = 0; i < cfg.categories!.length; i++) {\n const cat = cfg.categories![i];\n if (typeof cat !== 'string' && (cat === null || typeof cat !== 'object' || !cat.name)) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: `Split node category at index ${i} must be a string or an object with a 'name' property`\n });\n }\n }\n }\n }\n\n // Validate schemas if provided (legacy path)\n if (hasSchemas && !hasCategories) {\n for (const [schemaName, schema] of Object.entries(cfg.schemas!)) {\n const schemaError = validateJSONSchemaStructure(schema);\n if (schemaError) {\n errors.push({\n type: 'invalid_schema',\n stepId,\n message: `Invalid JSON schema for \"${schemaName}\": ${schemaError}`,\n details: { schemaName, schema: schema as Record<string, unknown> }\n });\n }\n }\n\n if (Object.keys(cfg.schemas!).length === 0) {\n warnings.push({\n type: 'best_practice',\n stepId,\n message: 'Split node has no schemas defined'\n });\n }\n }\n break;\n }\n\n case 'categorize': {\n const cfg = config as CategorizeConfig;\n if (!cfg.categories) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Categorize node missing categories'\n });\n } else if (!Array.isArray(cfg.categories)) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Categorize node categories must be an array'\n });\n } else if (cfg.categories.length === 0) {\n warnings.push({\n type: 'best_practice',\n stepId,\n message: 'Categorize node has no categories defined'\n });\n }\n break;\n }\n\n case 'trigger': {\n const cfg = config as TriggerConfig;\n\n // Validate flowRef is present\n if (!cfg.flowRef) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Trigger node missing flowRef'\n });\n }\n\n // Validate providerOverrides if present\n if (cfg.providerOverrides) {\n if (typeof cfg.providerOverrides !== 'object') {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Trigger node providerOverrides must be an object'\n });\n } else if (opts.checkProviders && opts.providers) {\n // Validate that override refs exist in provider registry\n for (const [childRef, parentRef] of Object.entries(cfg.providerOverrides)) {\n if (!opts.providers[parentRef]) {\n errors.push({\n type: 'missing_provider',\n stepId,\n message: `Provider override \"${parentRef}\" not found in registry`,\n details: {\n childRef,\n parentRef,\n availableProviders: Object.keys(opts.providers)\n }\n });\n }\n }\n }\n }\n\n // Validate inputMapping if present\n if (cfg.inputMapping) {\n if (!cfg.inputMapping.type) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Trigger node inputMapping missing type field'\n });\n } else {\n const validMappingTypes = ['passthrough', 'unwrap', 'artifact', 'merge', 'construct'];\n if (!validMappingTypes.includes(cfg.inputMapping.type)) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: `Invalid inputMapping type: ${cfg.inputMapping.type}. Must be one of: ${validMappingTypes.join(', ')}`\n });\n }\n\n // Type-specific validation\n if (cfg.inputMapping.type === 'artifact' && !('path' in cfg.inputMapping)) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Trigger node inputMapping type \"artifact\" requires path field'\n });\n }\n if (cfg.inputMapping.type === 'merge' && !('artifactPath' in cfg.inputMapping)) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Trigger node inputMapping type \"merge\" requires artifactPath field'\n });\n }\n if (cfg.inputMapping.type === 'construct' && !('fields' in cfg.inputMapping)) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Trigger node inputMapping type \"construct\" requires fields object'\n });\n }\n }\n }\n\n // Validate timeout if present\n if (cfg.timeout !== undefined) {\n if (typeof cfg.timeout !== 'number' || cfg.timeout <= 0) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Trigger node timeout must be a positive number'\n });\n }\n }\n\n // Validate mergeMetrics if present\n if (cfg.mergeMetrics !== undefined && typeof cfg.mergeMetrics !== 'boolean') {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Trigger node mergeMetrics must be a boolean'\n });\n }\n\n break;\n }\n\n case 'output': {\n const cfg = config as OutputConfig;\n\n // Validate transform type if present\n if (cfg.transform) {\n const validTransforms = ['first', 'last', 'merge', 'pick'];\n if (!validTransforms.includes(cfg.transform)) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: `Invalid output transform: ${cfg.transform}. Must be one of: ${validTransforms.join(', ')}`\n });\n }\n\n // Validate that 'pick' transform has fields\n if (cfg.transform === 'pick' && (!cfg.fields || cfg.fields.length === 0)) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Output transform \"pick\" requires fields array'\n });\n }\n }\n\n // Validate fields if present\n if (cfg.fields && !Array.isArray(cfg.fields)) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Output fields must be an array'\n });\n }\n\n // Validate source if present\n if (cfg.source) {\n if (typeof cfg.source !== 'string' && !Array.isArray(cfg.source)) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Output source must be a string or array of strings'\n });\n } else if (Array.isArray(cfg.source) && cfg.source.length === 0) {\n warnings.push({\n type: 'best_practice',\n stepId,\n message: 'Output source array is empty'\n });\n }\n }\n\n break;\n }\n }\n\n // Validate consensus config if present\n if ('consensus' in config && config.consensus) {\n const consensus = config.consensus;\n\n if (!consensus.runs || consensus.runs < 1) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Consensus runs must be >= 1'\n });\n }\n\n if (consensus.strategy && !['majority', 'unanimous'].includes(consensus.strategy)) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: `Invalid consensus strategy: ${consensus.strategy}. Must be: majority or unanimous`\n });\n }\n\n if (consensus.onTie && !['random', 'fail', 'retry'].includes(consensus.onTie)) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: `Invalid consensus onTie: ${consensus.onTie}. Must be: random, fail, or retry`\n });\n }\n\n if (consensus.runs > 1) {\n warnings.push({\n type: 'performance',\n stepId,\n message: `Consensus with ${consensus.runs} runs will execute the step ${consensus.runs} times`\n });\n }\n }\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings\n };\n}\n\n/**\n * Validate and throw if invalid\n *\n * @param flowDef - Flow definition to validate\n * @param options - Validation options\n * @throws ValidationError if flow is invalid\n */\nexport function validateFlowOrThrow(\n flowDef: SerializableFlow,\n options: ValidationOptions = {}\n): void {\n const result = validateFlow(flowDef, options);\n\n if (!result.valid) {\n const errorMessages = result.errors.map(e =>\n e.stepId ? `[${e.stepId}] ${e.message}` : e.message\n ).join('\\n');\n\n throw new Error(`Flow validation failed:\\n${errorMessages}`);\n }\n\n // Log warnings if present\n if (result.warnings.length > 0 && isDebugValidation()) {\n console.warn('[Flow Validation] Warnings:');\n for (const warning of result.warnings) {\n const prefix = warning.stepId ? `[${warning.stepId}]` : '';\n console.warn(` ${prefix} ${warning.message}`);\n }\n }\n}\n","import { runPipeline, type OCRProvider, type DocumentIR } from \"@doclo/core\";\nimport { parseNode, extractNode } from \"@doclo/nodes\";\nimport { simpleSchema } from \"./schemas\";\nimport { buildLLMProvider } from \"@doclo/providers-llm\";\n\n/**\n * Build a flow with automatic fallback between multiple LLM providers\n *\n * Example usage:\n * ```\n * const flow = buildMultiProviderFlow({\n * ocr: suryaProvider({ endpoint, apiKey }),\n * llmConfigs: [\n * { provider: 'openai', model: 'gpt-4.1', apiKey: process.env.OPENAI_KEY },\n * { provider: 'anthropic', model: 'claude-haiku-4.5', apiKey: process.env.ANTHROPIC_KEY, via: 'openrouter' },\n * { provider: 'google', model: 'gemini-2.5-flash', apiKey: process.env.GOOGLE_KEY }\n * ],\n * maxRetries: 2\n * });\n * ```\n */\nexport function buildMultiProviderFlow(opts: {\n ocr: OCRProvider;\n llmConfigs: Array<{\n provider: 'openai' | 'anthropic' | 'google' | 'xai';\n model: string;\n apiKey: string;\n via?: 'openrouter' | 'native';\n baseUrl?: string;\n }>;\n maxRetries?: number;\n retryDelay?: number;\n circuitBreakerThreshold?: number;\n}) {\n const parse = parseNode({ ocr: opts.ocr });\n\n // Build LLM provider with fallback support\n // buildLLMProvider returns CoreVLMProvider directly (no adapter needed)\n const coreLLMProvider = buildLLMProvider({\n providers: opts.llmConfigs,\n maxRetries: opts.maxRetries ?? 2,\n retryDelay: opts.retryDelay ?? 1000,\n useExponentialBackoff: true,\n circuitBreakerThreshold: opts.circuitBreakerThreshold ?? 3\n });\n\n const mkPrompt = (ir: DocumentIR) =>\n `Extract JSON matching the schema fields: vessel, port, quantity_mt.\nDocument (first page preview):\n${ir.pages[0]?.lines.slice(0, 50).map(l => l.text).join('\\n')}`;\n\n const extract = extractNode({\n llm: coreLLMProvider,\n schema: simpleSchema,\n makePrompt: mkPrompt\n });\n\n return {\n async run(input: { url?: string; base64?: string }) {\n const parsed = await runPipeline([parse], input);\n const ir = parsed.output as DocumentIR;\n\n const result = await runPipeline([extract], ir);\n\n return {\n ir,\n output: result.output,\n metrics: [...parsed.metrics, ...result.metrics],\n artifacts: {\n parse: parsed.artifacts.parse,\n extract: result.artifacts.extract\n }\n };\n }\n };\n}\n","import { runPipeline } from \"@doclo/core\";\nimport { node } from \"@doclo/core\";\nimport { simpleSchema } from \"./schemas\";\nimport { buildLLMProvider } from \"@doclo/providers-llm\";\n\n/**\n * Build a flow that uses VLM (Vision Language Model) for direct extraction\n * Skips OCR entirely - sends image/PDF directly to the vision model\n *\n * Pros:\n * - Faster (one API call instead of two)\n * - Can understand layout, tables, charts visually\n * - No OCR errors/artifacts\n *\n * Cons:\n * - More expensive (vision tokens cost more)\n * - Limited to models with vision capabilities\n */\nexport function buildVLMDirectFlow(opts: {\n llmConfigs: Array<{\n provider: 'openai' | 'anthropic' | 'google' | 'xai';\n model: string;\n apiKey: string;\n via?: 'openrouter' | 'native';\n baseUrl?: string;\n }>;\n maxRetries?: number;\n retryDelay?: number;\n circuitBreakerThreshold?: number;\n}) {\n // Build LLM provider with vision support\n // buildLLMProvider returns CoreVLMProvider directly (no adapter needed)\n const coreLLMProvider = buildLLMProvider({\n providers: opts.llmConfigs,\n maxRetries: opts.maxRetries ?? 2,\n retryDelay: opts.retryDelay ?? 1000,\n useExponentialBackoff: true,\n circuitBreakerThreshold: opts.circuitBreakerThreshold ?? 3\n });\n\n // Create VLM extraction node\n const vlmExtract = node<{ url?: string; base64?: string }, any>(\n \"vlm_extract\",\n async (input, ctx) => {\n const t0 = Date.now();\n\n // Build multimodal prompt with proper format for OpenRouter\n const prompt: any = {\n text: `You are a document data extraction expert. Extract the following fields from this maritime document:\n- vessel: The vessel/ship name\n- port: The port name or location\n- quantity_mt: The quantity in metric tons (MT)\n\nReturn ONLY a JSON object with these fields. Use null if a field is not found.`\n };\n\n // Determine if it's a PDF or image based on data\n let isPDF = false;\n\n if (input.url) {\n isPDF = input.url.endsWith('.pdf') || input.url.toLowerCase().includes('.pdf');\n } else if (input.base64) {\n // Check if base64 data URL indicates PDF\n isPDF = input.base64.startsWith('data:application/pdf');\n }\n\n // Add file/image to prompt based on type\n if (isPDF) {\n // For PDFs, use 'pdfs' array\n prompt.pdfs = [];\n if (input.url) {\n // If it's a data URL (base64), extract the base64 part\n if (input.url.startsWith('data:')) {\n const base64Data = input.url.replace(/^data:application\\/pdf;base64,/, '');\n prompt.pdfs.push({ base64: base64Data });\n } else {\n // Regular URL\n prompt.pdfs.push({ url: input.url });\n }\n } else if (input.base64) {\n // Extract base64 data if it's a data URL, otherwise use as-is\n const base64Data = input.base64.startsWith('data:')\n ? input.base64.replace(/^data:application\\/pdf;base64,/, '')\n : input.base64;\n prompt.pdfs.push({ base64: base64Data });\n }\n } else {\n // For images, use 'images' array\n prompt.images = [];\n if (input.url) {\n // If it's a data URL (base64), extract the base64 part\n if (input.url.startsWith('data:')) {\n const base64Data = input.url.replace(/^data:image\\/[^;]+;base64,/, '');\n const mimeType = input.url.match(/^data:(image\\/[^;]+);/)?.[1] || 'image/jpeg';\n prompt.images.push({ base64: base64Data, mimeType });\n } else {\n // Regular URL\n prompt.images.push({ url: input.url, mimeType: 'image/jpeg' });\n }\n } else if (input.base64) {\n // Extract base64 data if it's a data URL, otherwise use as-is\n const base64Data = input.base64.startsWith('data:')\n ? input.base64.replace(/^data:image\\/[^;]+;base64,/, '')\n : input.base64;\n const mimeType = input.base64.startsWith('data:')\n ? input.base64.match(/^data:(image\\/[^;]+);/)?.[1] || 'image/jpeg'\n : 'image/jpeg';\n prompt.images.push({ base64: base64Data, mimeType });\n }\n }\n\n const { json, costUSD, inputTokens, outputTokens, cacheCreationInputTokens, cacheReadInputTokens } = await coreLLMProvider.completeJson({\n prompt,\n schema: simpleSchema\n });\n\n ctx.metrics.push({\n step: \"vlm_extract\",\n startMs: t0,\n provider: coreLLMProvider.name,\n model: 'unknown',\n ms: Date.now() - t0,\n costUSD,\n inputTokens,\n outputTokens,\n cacheCreationInputTokens,\n cacheReadInputTokens,\n attemptNumber: 1,\n metadata: { kind: 'leaf' }\n });\n\n return json;\n }\n );\n\n return {\n async run(input: { url?: string; base64?: string }) {\n const result = await runPipeline([vlmExtract], input);\n\n return {\n output: result.output,\n metrics: result.metrics,\n artifacts: {\n vlm_extract: result.artifacts.vlm_extract\n }\n };\n }\n };\n}\n"],"mappings":"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","names":["runPipeline","parseNode","extractNode","node","result","parse","split","categorize","extract","trigger","split","categorize","FlowExecutionError","FlowExecutionError","node","split","categorize","hasProviderRef","runPipeline","parse","extract","runPipeline","runPipeline","buildLLMProvider","runPipeline","parse","parseNode","extractNode","runPipeline"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/flow-builder.ts","../src/flow-registry.ts","../src/serialization.ts","../src/composite-nodes.ts","../src/validation.ts","../src/multi-provider-flow.ts","../src/vlm-direct-flow.ts"],"sourcesContent":["import { runPipeline, type OCRProvider, type LLMJsonProvider, type DocumentIR } from \"@doclo/core\";\nimport { parseNode, extractNode } from \"@doclo/nodes\";\nimport { simpleSchema } from \"./schemas\";\n\n// Export schemas\nexport * from \"./schemas\";\n\n// Export new flow builder API\nexport {\n createFlow,\n isSingleFlowResult,\n isBatchFlowResult,\n type FlowContext,\n type FlowProgressCallbacks,\n type FlowValidationResult,\n type BuiltFlow,\n type FlowOptions,\n type FlowRunOptions,\n type BatchFlowResult,\n} from \"./flow-builder\";\nexport { parse, split, categorize, extract, chunk, combine, trigger } from \"@doclo/nodes\";\n\n// Re-export observability types for flow hooks\nexport type {\n ObservabilityConfig,\n FlowStartContext,\n FlowEndContext,\n FlowErrorContext,\n FlowStats,\n StepStartContext,\n StepEndContext,\n StepErrorContext,\n ConsensusStartContext,\n ConsensusRunContext,\n ConsensusCompleteContext,\n BatchStartContext,\n BatchItemContext,\n BatchItemEndContext,\n BatchEndContext,\n ProviderRequestContext,\n ProviderResponseContext,\n ProviderRetryContext,\n CircuitBreakerContext,\n TraceContext,\n ExecutionContext,\n CustomMetric,\n} from \"@doclo/core/observability\";\n\n// Export flow registry\nexport {\n FLOW_REGISTRY,\n registerFlow,\n getFlow,\n hasFlow,\n unregisterFlow,\n clearRegistry,\n listFlows,\n getFlowCount,\n type FlowBuilder\n} from \"./flow-registry\";\n\n// Export serialization\nexport * from \"./serialization\";\n\n// Export composite nodes\nexport * from \"./composite-nodes\";\n\n// Export validation\nexport * from \"./validation\";\n\n// Re-export utilities from core for convenience\nexport { bufferToDataUri, bufferToBase64 } from \"@doclo/core\";\n\n// Export legacy flows (kept as examples)\nexport { buildMultiProviderFlow } from \"./multi-provider-flow\";\nexport { buildVLMDirectFlow } from \"./vlm-direct-flow\";\n\nexport function buildTwoProviderFlow(opts: { ocr: OCRProvider; llmA: LLMJsonProvider; llmB: LLMJsonProvider }) {\n const parse = parseNode({ ocr: opts.ocr });\n\n const mkPrompt = (ir: DocumentIR) =>\n`Extract JSON matching the schema fields: vessel, port, quantity_mt.\nDocument (first page preview):\n${ir.pages[0]?.lines.slice(0, 50).map(l => l.text).join('\\n')}`;\n\n const extractA = extractNode({ llm: opts.llmA, schema: simpleSchema, makePrompt: mkPrompt });\n const extractB = extractNode({ llm: opts.llmB, schema: simpleSchema, makePrompt: mkPrompt });\n\n return {\n async run(input: { url?: string; base64?: string }) {\n const parsed = await runPipeline([parse], input);\n const ir = parsed.output as DocumentIR;\n\n const [resA, resB] = await Promise.all([\n runPipeline([extractA], ir),\n runPipeline([extractB], ir)\n ]);\n\n return {\n ir,\n outputA: resA.output,\n outputB: resB.output,\n metrics: [...parsed.metrics, ...resA.metrics, ...resB.metrics],\n artifacts: {\n parse: parsed.artifacts.parse,\n extractA: resA.artifacts.extract,\n extractB: resB.artifacts.extract\n }\n };\n }\n };\n}\n","import {\n runPipeline,\n FlowExecutionError,\n aggregateMetrics,\n getNodeTypeName,\n validateNodeConnection,\n getSuggestedConnections,\n canStartForEachItemFlow,\n getValidForEachStarters,\n getProviderById,\n validateFlowInputFormat,\n type NodeDef,\n type FlowInput,\n type FlowInputValidation,\n type FlowResult,\n type StepMetric,\n type FlowContext,\n type NodeTypeName,\n type NodeCtx,\n type OutputNodeConfig,\n type AcceptedMimeType,\n type FlowStepLocation\n} from \"@doclo/core\";\nimport { shouldSkipValidation } from \"@doclo/core/runtime/env\";\n\nimport { output as createOutputNode } from \"@doclo/nodes\";\n\nimport type {\n ObservabilityConfig,\n ExecutionContext,\n TraceContext,\n FlowStartContext,\n FlowEndContext,\n FlowErrorContext,\n FlowStats,\n StepStartContext,\n StepEndContext,\n StepErrorContext,\n BatchStartContext,\n BatchItemContext,\n BatchItemEndContext,\n BatchEndContext,\n} from \"@doclo/core/observability\";\n\nimport {\n mergeConfig,\n shouldSample,\n TraceContextManager,\n generateExecutionId,\n executeHook,\n buildStepAttributes,\n generateSpanId,\n} from \"@doclo/core/observability\";\n\n/**\n * Progress callback options for flow execution\n */\nexport interface FlowProgressCallbacks {\n /** Called when a step starts execution */\n onStepStart?: (stepId: string, stepIndex: number, stepType: string) => void;\n /** Called when a step completes successfully */\n onStepComplete?: (stepId: string, stepIndex: number, stepType: string, durationMs: number) => void;\n /** Called when a step fails with an error */\n onStepError?: (stepId: string, stepIndex: number, stepType: string, error: Error) => void;\n}\n\n/**\n * Validation error for a flow step\n */\nexport interface FlowValidationError {\n stepId: string;\n stepIndex: number;\n stepType: string;\n message: string;\n}\n\n/**\n * Result of flow validation\n */\nexport interface FlowValidationResult {\n valid: boolean;\n errors: FlowValidationError[];\n warnings: string[];\n}\n\n// FlowContext is now exported from @doclo/core\nexport type { FlowContext } from \"@doclo/core\";\n\n/**\n * Batch result type returned when flow has multiple outputs\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type BatchFlowResult = { results: FlowResult<any>[] };\n\n/**\n * Type representing the built flow object returned by Flow.build()\n */\n/**\n * Options for running a built flow\n */\nexport interface FlowRunOptions {\n /** Progress callbacks for step execution */\n callbacks?: FlowProgressCallbacks;\n /** Initial artifacts to merge into the flow context (for forEach child flows) */\n initialArtifacts?: Record<string, any>;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type BuiltFlow<TInput = any, TOutput = any> = {\n run: (input: TInput, callbacksOrOptions?: FlowProgressCallbacks | FlowRunOptions) => Promise<FlowResult<TOutput> | BatchFlowResult>;\n validate: () => FlowValidationResult;\n};\n\n/**\n * Type guard to check if a flow result is a single result (not batch)\n */\nexport function isSingleFlowResult<T>(result: FlowResult<T> | BatchFlowResult): result is FlowResult<T> {\n return 'output' in result && 'artifacts' in result;\n}\n\n/**\n * Type guard to check if a flow result is a batch result\n */\nexport function isBatchFlowResult(result: FlowResult<unknown> | BatchFlowResult): result is BatchFlowResult {\n return 'results' in result && Array.isArray(result.results);\n}\n\n/**\n * Type helper to extract the unwrapped input type from a wrapped type.\n * If T has an 'input' property, returns the type of that property.\n * Otherwise returns T unchanged.\n *\n * This matches the runtime behavior where conditionals receive wrapped data\n * but pass unwrapped data to the selected node.\n */\ntype UnwrapInput<T> = T extends { input: infer I } ? I : T;\n\ntype StepConfig<I, O> = {\n type: 'step';\n id: string;\n name?: string;\n node: NodeDef<I, O>;\n};\n\ntype ConditionalConfig<I, O> = {\n type: 'conditional';\n id: string;\n name?: string;\n condition: (data: I, context?: FlowContext) => NodeDef<UnwrapInput<I>, O>;\n};\n\ntype ForEachConfig<I, O> = {\n type: 'forEach';\n id: string;\n name?: string;\n childFlow: (item: any) => Flow<any, O>;\n};\n\ntype FlowStep = StepConfig<any, any> | ConditionalConfig<any, any> | ForEachConfig<any, any>;\n\n/**\n * Normalizes various input formats to FlowInput format\n * Handles:\n * - FlowInput objects: { base64, url, pages, bounds }\n * - Data URLs: \"data:application/pdf;base64,...\"\n * - HTTP URLs: \"https://...\"\n * - Raw base64 strings\n * - Objects with wrapper fields like { input: FlowInput }\n */\nfunction normalizeFlowInput(input: any): any {\n // Null or undefined - return as is\n if (input == null) {\n return input;\n }\n\n // Already a FlowInput object - return as is\n if (typeof input === 'object' && (input.base64 || input.url)) {\n return input;\n }\n\n // String input - detect format\n if (typeof input === 'string') {\n // Data URL - keep as data URL (providers handle this)\n if (input.startsWith('data:')) {\n return { base64: input };\n }\n\n // HTTP/HTTPS URL\n if (input.startsWith('http://') || input.startsWith('https://')) {\n return { url: input };\n }\n\n // Assume raw base64 string\n return { base64: input };\n }\n\n // Other object types - return as is (might be DocumentIR, string, etc.)\n return input;\n}\n\n/**\n * Filters out internal artifacts (prefixed with __) from the result.\n * Internal artifacts like __flowInput and __originalFlowInput are used\n * during execution but should not be exposed in the final result.\n */\nfunction filterInternalArtifacts(artifacts: Record<string, any>): Record<string, any> {\n const filtered: Record<string, any> = {};\n for (const [key, value] of Object.entries(artifacts)) {\n if (!key.startsWith('__')) {\n filtered[key] = value;\n }\n }\n return filtered;\n}\n\n/**\n * Options for creating a flow\n */\nexport interface FlowOptions {\n /** Observability configuration */\n observability?: ObservabilityConfig;\n /** User metadata to include in all observability contexts */\n metadata?: Record<string, unknown>;\n /**\n * Input format validation configuration.\n * Allows specifying accepted MIME types for early validation\n * before flow execution begins.\n */\n inputValidation?: FlowInputValidation;\n}\n\n/**\n * Flow builder class for creating document processing pipelines.\n * @template TInput - The input type for the flow\n * @template TOutput - The output type for the flow\n */\nexport class Flow<TInput = any, TOutput = any> {\n private steps: FlowStep[] = [];\n private observability?: ObservabilityConfig;\n private metadata?: Record<string, unknown>;\n private inputValidation?: FlowInputValidation;\n private traceContextManager?: TraceContextManager;\n private currentExecution?: ExecutionContext;\n\n constructor(options?: FlowOptions) {\n if (options?.observability) {\n this.observability = mergeConfig(options.observability);\n this.traceContextManager = new TraceContextManager(this.observability);\n }\n if (options?.metadata) {\n this.metadata = options.metadata;\n }\n if (options?.inputValidation) {\n this.inputValidation = options.inputValidation;\n }\n }\n\n /**\n * Set accepted input formats for this flow (fluent API).\n * Validates input format before flow execution begins.\n *\n * @param formats - List of accepted MIME types (e.g., ['application/pdf', 'image/jpeg'])\n * @returns This flow instance for chaining\n *\n * @example\n * ```typescript\n * const pdfOnlyFlow = createFlow()\n * .acceptFormats(['application/pdf'])\n * .step('parse', parse({ provider }))\n * .build();\n *\n * // Throws FlowInputValidationError if input is not a PDF\n * await pdfOnlyFlow.run({ base64: jpegBase64 });\n * ```\n */\n acceptFormats(formats: AcceptedMimeType[]): Flow<TInput, TOutput> {\n this.inputValidation = { acceptedFormats: formats };\n return this;\n }\n\n /**\n * Add a sequential step to the flow\n */\n step<TStepOutput>(id: string, node: NodeDef<TOutput, TStepOutput>, name?: string): Flow<TInput, TStepOutput> {\n this.steps.push({\n type: 'step',\n id,\n name,\n node\n });\n return this as any;\n }\n\n /**\n * Add a conditional step that chooses a node based on input data\n *\n * IMPORTANT: Conditionals must return a NODE, not a promise or executed flow.\n * The SDK will execute the returned node for you.\n *\n * The condition function receives the full wrapped data (e.g., { input, quality })\n * but the returned node should accept the unwrapped input (e.g., just FlowInput).\n * The SDK automatically unwraps the data before passing it to the selected node.\n *\n * ✅ CORRECT - Return a node (declarative):\n * ```typescript\n * .step('qualify', qualify({ provider, levels: ['low', 'medium', 'high'] }))\n * .conditional('parse', (data) => {\n * // data is { input: FlowInput, quality: string }\n * if (data.quality === 'high') {\n * return parse({ provider: fastProvider }); // Return the node\n * }\n * return parse({ provider: accurateProvider }); // Return the node\n * })\n * ```\n *\n * ❌ INCORRECT - Do NOT return a promise (imperative):\n * ```typescript\n * .conditional('parse', (data) => {\n * // This will throw an error!\n * return createFlow()\n * .step('parse', parse({ provider }))\n * .build()\n * .run(data.input) // ❌ Don't call .run() here!\n * .then(r => r.output);\n * })\n * ```\n *\n * 🆕 NEW - Access previous step outputs via context:\n * ```typescript\n * .step('categorize', categorize({ provider, categories }))\n * .conditional('parse', (data) => parse({ provider }))\n * .conditional('extract', (data, context) => {\n * // Access category from earlier step via context.artifacts\n * const category = context?.artifacts.categorize?.category;\n * return extract({ provider, schema: SCHEMAS[category] });\n * })\n * ```\n *\n * Use the declarative pattern (return nodes) for consistent flow execution,\n * proper error tracking, and accurate metrics collection.\n */\n conditional<TConditionalOutput>(\n id: string,\n condition: (data: TOutput, context?: FlowContext) => NodeDef<UnwrapInput<TOutput>, TConditionalOutput>,\n name?: string\n ): Flow<TInput, TConditionalOutput> {\n this.steps.push({\n type: 'conditional',\n id,\n name,\n condition\n });\n return this as any;\n }\n\n /**\n * Process each item from previous step (which must return an array) with a child flow\n * Each item is processed in parallel as its own isolated run\n */\n forEach<TItem, TForEachOutput>(\n id: string,\n childFlow: (item: TItem) => Flow<TItem, TForEachOutput>,\n name?: string\n ): Flow<TInput, FlowResult<TForEachOutput>[]> {\n this.steps.push({\n type: 'forEach',\n id,\n name,\n childFlow\n });\n return this as any;\n }\n\n /**\n * Add an explicit output node to mark which data to return from the flow\n *\n * By default, flows return the output of the last step. Use output nodes to:\n * - Return data from earlier steps\n * - Return multiple named outputs\n * - Transform outputs before returning\n *\n * @param config - Output configuration\n * @returns Flow with output node added\n *\n * @example\n * // Single output\n * .output({ name: 'invoice_data' })\n *\n * // Select specific source\n * .output({ name: 'result', source: 'step2' })\n *\n * // Multiple outputs\n * .step('extract1', extract({ provider, schema1 }))\n * .output({ name: 'summary', source: 'extract1' })\n * .step('extract2', extract({ provider, schema2 }))\n * .output({ name: 'details', source: 'extract2' })\n */\n output<TOutputShape = TOutput>(config?: OutputNodeConfig): Flow<TInput, TOutputShape> {\n // Normalize and validate name\n const name = config?.name?.trim();\n\n // Use provided name or generate unique default\n const stepId = name || this.generateOutputStepId();\n\n this.steps.push({\n type: 'step',\n id: stepId,\n node: createOutputNode({\n ...config,\n name: stepId // Ensure name matches step ID\n })\n });\n\n return this as any;\n }\n\n /**\n * Get current execution context\n *\n * Returns null if not currently executing.\n */\n getExecutionContext(): ExecutionContext | null {\n return this.currentExecution ?? null;\n }\n\n /**\n * Get current trace context\n *\n * Returns null if not currently executing or observability not configured.\n */\n getTraceContext(): TraceContext | null {\n return this.traceContextManager?.getTraceContext() ?? null;\n }\n\n /**\n * Set a custom attribute on the current execution\n *\n * Custom attributes appear in execution context and can be accessed by hooks.\n */\n setCustomAttribute(key: string, value: unknown): void {\n if (this.currentExecution) {\n this.currentExecution.customAttributes[key] = value;\n }\n }\n\n /**\n * Record a custom metric for the current execution\n *\n * Custom metrics appear in execution context and can be accessed by hooks.\n */\n recordMetric(name: string, value: number, unit?: string): void {\n if (this.currentExecution) {\n this.currentExecution.customMetrics.push({\n name,\n value,\n unit,\n timestamp: Date.now(),\n });\n }\n }\n\n /**\n * Build and return the executable flow\n */\n build(): BuiltFlow<TInput, TOutput> {\n return {\n run: async (input: TInput, callbacksOrOptions?: FlowProgressCallbacks | FlowRunOptions) => {\n // Support both legacy callback-only signature and new options object\n let callbacks: FlowProgressCallbacks | undefined;\n let initialArtifacts: Record<string, any> | undefined;\n\n if (callbacksOrOptions) {\n if ('callbacks' in callbacksOrOptions || 'initialArtifacts' in callbacksOrOptions) {\n // New options object format\n callbacks = (callbacksOrOptions as FlowRunOptions).callbacks;\n initialArtifacts = (callbacksOrOptions as FlowRunOptions).initialArtifacts;\n } else {\n // Legacy callbacks format\n callbacks = callbacksOrOptions as FlowProgressCallbacks;\n }\n }\n\n return this.execute(input, callbacks, initialArtifacts);\n },\n validate: () => {\n return this.validate();\n }\n };\n }\n\n /**\n * Generate a unique step ID for unnamed output nodes\n * Prevents duplicate IDs when multiple .output() calls without names\n */\n private generateOutputStepId(): string {\n let counter = 0;\n let candidateId = 'output';\n\n // Check if 'output' is already taken\n while (this.steps.some(step => step.id === candidateId)) {\n counter++;\n candidateId = `output_${counter}`;\n }\n\n return candidateId;\n }\n\n /**\n * Validate the flow configuration\n */\n private validate(): FlowValidationResult {\n const errors: FlowValidationError[] = [];\n const warnings: string[] = [];\n\n // Check if flow has at least one step\n if (this.steps.length === 0) {\n errors.push({\n stepId: '<flow>',\n stepIndex: -1,\n stepType: 'flow',\n message: 'Flow has no steps. Add at least one step using .step(), .conditional(), or .forEach()'\n });\n }\n\n // Validate each step\n for (let stepIndex = 0; stepIndex < this.steps.length; stepIndex++) {\n const step = this.steps[stepIndex];\n\n // Check for duplicate step IDs\n const duplicateIndex = this.steps.findIndex((s, i) => i !== stepIndex && s.id === step.id);\n if (duplicateIndex !== -1) {\n errors.push({\n stepId: step.id,\n stepIndex,\n stepType: step.type,\n message: `Duplicate step ID \"${step.id}\" found at indices ${stepIndex} and ${duplicateIndex}`\n });\n }\n\n // Validate step-specific configuration\n if (step.type === 'step') {\n if (!step.node) {\n errors.push({\n stepId: step.id,\n stepIndex,\n stepType: step.type,\n message: 'Step node is missing. Use parse(), qualify(), categorize(), extract(), or split()'\n });\n }\n // Note: We don't check typeof === 'function' because NodeDef can be various structures\n // TypeScript already ensures type safety at compile time\n } else if (step.type === 'conditional') {\n if (!step.condition || typeof step.condition !== 'function') {\n errors.push({\n stepId: step.id,\n stepIndex,\n stepType: step.type,\n message: 'Conditional must have a condition function'\n });\n }\n } else if (step.type === 'forEach') {\n if (!step.childFlow || typeof step.childFlow !== 'function') {\n errors.push({\n stepId: step.id,\n stepIndex,\n stepType: step.type,\n message: 'forEach must have a childFlow function'\n });\n }\n\n // Warn if forEach is not preceded by a step that could produce an array\n if (stepIndex === 0) {\n warnings.push(`forEach step \"${step.id}\" at index ${stepIndex} is the first step - ensure input is an array`);\n }\n }\n\n // Check for empty step IDs\n if (!step.id || step.id.trim() === '') {\n errors.push({\n stepId: '<empty>',\n stepIndex,\n stepType: step.type,\n message: 'Step ID cannot be empty'\n });\n }\n }\n\n // Type compatibility validation (skip if DOCLO_SKIP_VALIDATION is set)\n if (!shouldSkipValidation()) {\n this.validateTypeCompatibility(errors, warnings);\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings\n };\n }\n\n /**\n * Validate type compatibility between consecutive steps\n */\n private validateTypeCompatibility(errors: FlowValidationError[], warnings: string[]): void {\n for (let i = 0; i < this.steps.length - 1; i++) {\n const currentStep = this.steps[i];\n const nextStep = this.steps[i + 1];\n\n // Only validate step → step connections (not conditional or forEach)\n if (currentStep.type === 'step' && nextStep.type === 'step') {\n const sourceType = getNodeTypeName(currentStep.node);\n const targetType = getNodeTypeName(nextStep.node);\n\n // Skip if either node type is unknown (custom nodes)\n if (!sourceType || !targetType) {\n continue;\n }\n\n // Check if source node has forEach capability (split node)\n const forEachEnabled = false; // TODO: Detect forEach from node config\n\n // Validate connection\n const validation = validateNodeConnection(sourceType, targetType, forEachEnabled);\n\n if (!validation.valid) {\n errors.push({\n stepId: currentStep.id,\n stepIndex: i,\n stepType: currentStep.type,\n message: `Invalid connection: ${sourceType} → ${targetType}. ${validation.reason || 'Types incompatible'}`,\n });\n\n // Add suggestions as warnings\n if (validation.suggestions && validation.suggestions.length > 0) {\n warnings.push(`Suggestions for step \"${currentStep.id}\":`);\n validation.suggestions.forEach(s => warnings.push(` ${s}`));\n }\n } else if (validation.warning) {\n // Add runtime validation warning\n warnings.push(`Step \"${currentStep.id}\" → \"${nextStep.id}\": ${validation.warning}`);\n }\n }\n\n // Validate forEach requirements\n if (currentStep.type === 'step' && nextStep.type === 'forEach') {\n const sourceType = getNodeTypeName(currentStep.node);\n if (sourceType) {\n const sourceInfo = currentStep.node.__meta;\n const outputsArray = sourceInfo?.outputsArray;\n\n // Check if source outputs array\n const isArrayOutput = typeof outputsArray === 'function'\n ? outputsArray(null) // Can't access config here, so pass null\n : outputsArray;\n\n if (!isArrayOutput) {\n warnings.push(\n `forEach step \"${nextStep.id}\" requires array input. ` +\n `Previous step \"${currentStep.id}\" (${sourceType}) may not output an array. ` +\n `Ensure ${sourceType} is configured to output an array (e.g., parse with chunked:true).`\n );\n }\n\n // Validate forEach itemFlow starting node\n if (nextStep.childFlow && typeof nextStep.childFlow === 'function') {\n try {\n // Try to build the child flow to inspect its first step\n const childFlowInstance = nextStep.childFlow(null as any);\n\n // Access the steps array if available (Flow class internal structure)\n const childSteps = (childFlowInstance as any).steps;\n\n if (childSteps && Array.isArray(childSteps) && childSteps.length > 0) {\n const firstStep = childSteps[0];\n\n // Validate the first step is a regular step (not forEach/conditional)\n if (firstStep.type === 'step') {\n const firstNodeType = getNodeTypeName(firstStep.node);\n\n if (firstNodeType) {\n // Validate that this node can start forEach itemFlow\n const validation = canStartForEachItemFlow(sourceType, firstNodeType);\n\n if (!validation.valid) {\n errors.push({\n stepId: nextStep.id,\n stepIndex: i + 1,\n stepType: 'forEach',\n message: `Invalid forEach itemFlow starter: ${validation.reason || `${firstNodeType} cannot start forEach itemFlow after ${sourceType}`}`\n });\n\n // Add suggestions as warnings\n if (validation.suggestions && validation.suggestions.length > 0) {\n warnings.push(`Suggestions for forEach \"${nextStep.id}\":`);\n validation.suggestions.forEach(s => warnings.push(` ${s}`));\n }\n }\n }\n } else if (firstStep.type === 'forEach') {\n // Nested forEach is not allowed for split\n if (sourceType === 'split') {\n errors.push({\n stepId: nextStep.id,\n stepIndex: i + 1,\n stepType: 'forEach',\n message: 'Invalid forEach itemFlow: Cannot nest forEach operations. Split nodes cannot appear in forEach itemFlow.'\n });\n }\n }\n }\n } catch (error) {\n // If we can't inspect the child flow, add a warning but don't block\n warnings.push(\n `forEach step \"${nextStep.id}\": Unable to validate itemFlow structure. ` +\n `Ensure the first node in itemFlow is compatible with ${sourceType} output. ` +\n `Valid starters: ${getValidForEachStarters(sourceType).join(', ')}`\n );\n }\n }\n }\n }\n }\n\n // Check for efficiency anti-patterns\n this.checkEfficiencyPatterns(warnings);\n }\n\n /**\n * Check for inefficient flow patterns and add warnings.\n *\n * Detects patterns like:\n * - parse() → extract(raw-document-provider): The extract provider ignores parse output\n */\n private checkEfficiencyPatterns(warnings: string[]): void {\n for (let i = 0; i < this.steps.length - 1; i++) {\n const current = this.steps[i];\n const next = this.steps[i + 1];\n\n // Only check step → step connections\n if (current.type !== 'step' || next.type !== 'step') continue;\n\n const currNodeType = getNodeTypeName(current.node);\n const nextNodeType = getNodeTypeName(next.node);\n\n // Detect: parse() → extract(raw-document-provider)\n if (currNodeType === 'parse' && nextNodeType === 'extract') {\n const extractProvider = this.getProviderFromNode(next.node);\n\n if (extractProvider) {\n const metadata = getProviderById(extractProvider);\n\n if (metadata?.inputRequirements?.inputType === 'raw-document') {\n warnings.push(\n `Efficiency warning: Step \"${current.id}\" (parse) output may be ignored. ` +\n `\"${metadata.name}\" processes raw documents directly, not parsed text. ` +\n `Consider: (1) Remove the parse step, or (2) Use an LLM provider for extraction that can use parsed text.`\n );\n }\n }\n }\n }\n }\n\n /**\n * Extract provider ID from a node definition.\n * Returns undefined if provider cannot be determined.\n */\n private getProviderFromNode(node: NodeDef<any, any>): string | undefined {\n // Try to get provider from node config\n const config = (node as any).__meta?.config;\n if (config?.provider) {\n // Provider can be a string ID or a provider object\n if (typeof config.provider === 'string') {\n return config.provider;\n }\n // If provider is an object, it might have an id or name property\n if (typeof config.provider === 'object') {\n return config.provider.id ?? config.provider.name;\n }\n }\n return undefined;\n }\n\n /**\n * Execute the flow with optional progress callbacks\n */\n private async execute(input: any, callbacks?: FlowProgressCallbacks, initialArtifacts?: Record<string, any>): Promise<any> {\n const flowStartTime = Date.now();\n // Merge initial artifacts if provided (used for passing original source to forEach child flows)\n const artifacts: Record<string, any> = initialArtifacts ? { ...initialArtifacts } : {};\n const metrics: StepMetric[] = [];\n const completedSteps: string[] = [];\n const outputs: Record<string, any> = {}; // Store output node results\n let lastNonOutputData: any = null; // Track data from last non-output step\n\n // Initialize observability\n let executionId: string | undefined;\n let traceContext: TraceContext | undefined;\n let sampled = false;\n\n if (this.observability) {\n // Determine if this execution should be sampled\n sampled = shouldSample(this.observability);\n\n // Initialize trace context\n if (this.traceContextManager && sampled) {\n traceContext = this.traceContextManager.initialize(sampled);\n }\n\n // Generate execution ID\n const execIdGenerator = this.observability.generateExecutionId ?? generateExecutionId;\n executionId = execIdGenerator();\n\n // Initialize execution context for tracking\n this.currentExecution = {\n flowId: 'flow', // TODO: Add flowId to Flow class\n executionId,\n startTime: flowStartTime,\n status: 'running',\n customAttributes: {},\n customMetrics: [],\n };\n\n // Call onFlowStart hook\n if (sampled && traceContext) {\n const flowStartContext: FlowStartContext = {\n flowId: 'flow', // TODO: Add flowId\n flowVersion: '0.0.1',\n executionId,\n timestamp: flowStartTime,\n input,\n config: {}, // TODO: Capture flow config\n metadata: this.metadata,\n sdkVersion: '0.0.1',\n observabilityVersion: this.observability.observabilityVersion ?? '1.0.0',\n traceContext,\n };\n\n await executeHook(this.observability.onFlowStart, {\n hookName: 'onFlowStart',\n config: this.observability,\n context: flowStartContext,\n });\n }\n }\n\n // Normalize input format to handle various input types\n // (data URLs, HTTP URLs, raw base64, FlowInput objects)\n let currentData = normalizeFlowInput(input);\n\n // Store original flow input for source reference in extract nodes\n // This enables inputMode='ir+source' to access the original document\n artifacts.__flowInput = currentData;\n\n // Validate input format if configured\n if (this.inputValidation?.acceptedFormats?.length) {\n const dataUrl = currentData?.base64 || currentData?.url;\n if (dataUrl) {\n // This will throw FlowInputValidationError if format doesn't match\n validateFlowInputFormat(dataUrl, this.inputValidation.acceptedFormats);\n }\n }\n\n // Wrap execution in try-catch for flow-level error handling\n try {\n\n for (let stepIndex = 0; stepIndex < this.steps.length; stepIndex++) {\n const step = this.steps[stepIndex];\n const stepStartTime = Date.now();\n\n // Generate span ID for this step\n const stepSpanId = this.traceContextManager && sampled ? generateSpanId() : undefined;\n\n // Notify step start (old callbacks)\n callbacks?.onStepStart?.(step.id, stepIndex, step.type);\n\n // Call onStepStart hook (new observability)\n if (this.observability && sampled && traceContext && executionId && stepSpanId) {\n const stepStartContext: StepStartContext = {\n flowId: 'flow',\n executionId,\n stepId: step.id,\n stepIndex,\n stepType: (step as StepConfig<any, any>).node?.key ?? step.type,\n stepName: step.name ?? step.id,\n timestamp: stepStartTime,\n provider: undefined, // Will be populated from step config if available\n model: undefined,\n config: {},\n input: currentData,\n isConsensusEnabled: false, // TODO: Check step config for consensus\n isRetry: false,\n metadata: this.metadata,\n traceContext,\n spanId: stepSpanId,\n };\n\n await executeHook(this.observability.onStepStart, {\n hookName: 'onStepStart',\n config: this.observability,\n context: stepStartContext,\n });\n }\n\n try {\n if (step.type === 'step') {\n // Check if this is an output node\n const isOutputNode = (step.node as any)?.__meta?.isOutputNode === true;\n const outputName = (step.node as any)?.__meta?.outputName?.trim() || step.id;\n\n interface StepResult {\n output: unknown;\n artifacts: Record<string, unknown>;\n metrics: StepMetric[];\n }\n\n let result: StepResult;\n\n if (isOutputNode) {\n // Output nodes need access to flow-level artifacts\n // Execute directly with custom context instead of using runPipeline\n const ctx: NodeCtx = {\n stepId: step.id,\n artifacts,\n emit: (k: string, v: unknown) => { artifacts[k] = v; },\n metrics: { push: (m: StepMetric) => metrics.push(m) },\n observability: this.observability && sampled ? {\n config: this.observability,\n flowId: 'flow',\n executionId,\n stepId: step.id,\n stepIndex,\n traceContext,\n metadata: this.metadata,\n } : undefined\n };\n\n const outputData = await step.node.run(currentData, ctx);\n result = { output: outputData, artifacts: {}, metrics: [] };\n\n // Store the output node result\n outputs[outputName] = outputData;\n artifacts[step.id] = outputData;\n completedSteps.push(step.id);\n\n // Notify step complete (old callbacks)\n const stepDuration = Date.now() - stepStartTime;\n callbacks?.onStepComplete?.(step.id, stepIndex, step.type, stepDuration);\n\n // Call onStepEnd hook (new observability) - output nodes\n if (this.observability && sampled && traceContext && executionId && stepSpanId) {\n const stepEndContext: StepEndContext = {\n flowId: 'flow',\n executionId,\n stepId: step.id,\n stepIndex,\n timestamp: Date.now(),\n startTime: stepStartTime,\n duration: stepDuration,\n output: outputData,\n usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 },\n cost: 0,\n metricKind: 'prep', // Output nodes are prep steps (no API call)\n otelAttributes: buildStepAttributes({\n stepType: step.node?.key ?? step.type,\n }),\n metadata: this.metadata,\n traceContext,\n spanId: stepSpanId,\n };\n\n await executeHook(this.observability.onStepEnd, {\n hookName: 'onStepEnd',\n config: this.observability,\n context: stepEndContext,\n });\n }\n\n // Pass through the last non-output data to the next step\n // (output nodes don't change the data flow, they just mark outputs)\n currentData = lastNonOutputData !== null ? lastNonOutputData : currentData;\n } else {\n // Regular sequential step - pass flow artifacts for source access\n result = await runPipeline([step.node], currentData, this.observability && sampled ? {\n config: this.observability,\n flowId: 'flow',\n executionId,\n stepId: step.id,\n stepIndex,\n traceContext,\n metadata: this.metadata,\n } : {\n // Always pass stepId for metrics tracking, even without observability\n stepId: step.id\n }, artifacts);\n\n // Store the original output in artifacts (preserve wrapped data)\n artifacts[step.id] = result.output;\n metrics.push(...result.metrics);\n completedSteps.push(step.id);\n\n // Notify step complete (old callbacks)\n const stepDuration = Date.now() - stepStartTime;\n callbacks?.onStepComplete?.(step.id, stepIndex, step.type, stepDuration);\n\n // Call onStepEnd hook (new observability) - regular steps\n if (this.observability && sampled && traceContext && executionId && stepSpanId) {\n // Find metrics by type\n const leafMetrics = result.metrics.filter(m => m.metadata?.kind === 'leaf');\n const wrapperMetric = result.metrics.find(m => m.metadata?.kind === 'wrapper');\n\n // Find leaf metrics that belong to this step\n const stepLeafMetrics = result.metrics.filter(m =>\n m.configStepId === step.id && m.metadata?.kind === 'leaf'\n );\n\n // If there are MULTIPLE leaf metrics for this step, it's consensus runs (pure wrapper)\n // If there's exactly ONE leaf metric for this step, that's the step's own work\n const isConsensus = stepLeafMetrics.length > 1;\n const stepOwnLeafMetric = isConsensus ? undefined : stepLeafMetrics[0];\n\n // Determine if there are child metrics (from branch flows, etc.)\n const hasOtherChildMetrics = result.metrics.some(m => m.configStepId !== step.id);\n const hasChildMetrics = isConsensus || hasOtherChildMetrics || leafMetrics.length > 1;\n\n let metricKind: 'leaf' | 'wrapper' | 'prep';\n let ownDuration: number;\n let ownCost: number;\n let ownInputTokens: number;\n let ownOutputTokens: number;\n let ownCacheCreationTokens: number | undefined;\n let ownCacheReadTokens: number | undefined;\n\n if (isConsensus) {\n // Consensus: multiple leaf metrics = pure wrapper (children report via onConsensusRunComplete)\n metricKind = 'wrapper';\n ownDuration = wrapperMetric?.metadata?.overheadMs ?? 0;\n ownCost = 0;\n ownInputTokens = 0;\n ownOutputTokens = 0;\n ownCacheCreationTokens = undefined;\n ownCacheReadTokens = undefined;\n } else if (stepOwnLeafMetric) {\n // Step has its own API call (e.g., categorize in conditional, single extract)\n // It's a wrapper if it ALSO has child metrics\n metricKind = hasOtherChildMetrics ? 'wrapper' : 'leaf';\n ownDuration = stepOwnLeafMetric.ms ?? 0;\n ownCost = stepOwnLeafMetric.costUSD ?? 0;\n ownInputTokens = stepOwnLeafMetric.inputTokens ?? 0;\n ownOutputTokens = stepOwnLeafMetric.outputTokens ?? 0;\n ownCacheCreationTokens = stepOwnLeafMetric.cacheCreationInputTokens;\n ownCacheReadTokens = stepOwnLeafMetric.cacheReadInputTokens;\n } else if (wrapperMetric || hasChildMetrics) {\n // Pure wrapper - no own API call, just orchestration\n metricKind = 'wrapper';\n ownDuration = wrapperMetric?.metadata?.overheadMs ?? 0;\n ownCost = 0;\n ownInputTokens = 0;\n ownOutputTokens = 0;\n ownCacheCreationTokens = undefined;\n ownCacheReadTokens = undefined;\n } else {\n // No metrics = prep step (e.g., output node)\n metricKind = 'prep';\n ownDuration = stepDuration;\n ownCost = 0;\n ownInputTokens = 0;\n ownOutputTokens = 0;\n ownCacheCreationTokens = undefined;\n ownCacheReadTokens = undefined;\n }\n\n // Get provider/model from first metric (all consensus runs use same provider)\n const firstMetric = result.metrics.length > 0 ? result.metrics[0] : undefined;\n\n const stepEndContext: StepEndContext = {\n flowId: 'flow',\n executionId,\n stepId: step.id,\n stepIndex,\n timestamp: Date.now(),\n startTime: stepStartTime,\n duration: ownDuration,\n output: result.output,\n usage: {\n inputTokens: ownInputTokens,\n outputTokens: ownOutputTokens,\n totalTokens: ownInputTokens + ownOutputTokens,\n cacheCreationInputTokens: ownCacheCreationTokens,\n cacheReadInputTokens: ownCacheReadTokens,\n },\n cost: ownCost,\n metricKind,\n otelAttributes: buildStepAttributes({\n stepType: step.node?.key ?? step.type,\n provider: firstMetric?.provider,\n model: firstMetric?.model,\n inputTokens: ownInputTokens,\n outputTokens: ownOutputTokens,\n }),\n metadata: this.metadata,\n traceContext,\n spanId: stepSpanId,\n };\n\n await executeHook(this.observability.onStepEnd, {\n hookName: 'onStepEnd',\n config: this.observability,\n context: stepEndContext,\n });\n }\n\n // Regular node - save this as the last non-output data\n lastNonOutputData = result.output;\n\n // Auto-unwrap ONLY if next step is a regular step (not conditional/forEach)\n // Conditionals need the wrapped data to make decisions\n // This preserves { input, quality/category } for final output and conditionals\n const hasNextStep = stepIndex < this.steps.length - 1;\n const nextStep = hasNextStep ? this.steps[stepIndex + 1] : null;\n const shouldUnwrap = hasNextStep &&\n nextStep?.type === 'step' &&\n result.output &&\n typeof result.output === 'object' &&\n 'input' in result.output;\n\n if (shouldUnwrap) {\n currentData = (result.output as Record<string, unknown>).input;\n } else {\n currentData = result.output;\n }\n }\n } else if (step.type === 'conditional') {\n // Conditional step - choose node based on current data\n // Pass the FULL wrapped data to the condition function\n // (it needs access to quality/category for decision making)\n // Also pass context with artifacts and metrics for accessing previous step outputs\n const context: FlowContext = {\n artifacts: { ...artifacts },\n metrics: [...metrics]\n };\n const node = step.condition(currentData, context);\n\n // Validate that the condition function returned a valid NodeDef\n // NodeDef is an object with { key: string; run: function }\n if (!node || typeof node !== 'object' || !node.key || typeof node.run !== 'function') {\n throw new Error(\n `Conditional step \"${step.id}\" must return a node (e.g., parse(), categorize(), extract()). ` +\n `Got: ${typeof node}${node && typeof node === 'object' ? ` with keys: ${Object.keys(node).join(', ')}` : ''}. ` +\n `\\n\\nA valid node must have 'key' and 'run' properties.` +\n `\\n\\nIncorrect: .conditional('step', () => flow.run(...).then(r => r.output))` +\n `\\nCorrect: .conditional('step', () => parse({ provider }))`\n );\n }\n\n // Auto-unwrap when executing the node (if data has 'input' field)\n // The selected node should receive just the input\n const nodeInput = currentData && typeof currentData === 'object' && 'input' in currentData\n ? currentData.input\n : currentData;\n\n const result = await runPipeline([node], nodeInput, this.observability && sampled ? {\n config: this.observability,\n flowId: 'flow',\n executionId,\n stepId: step.id,\n stepIndex,\n traceContext,\n metadata: this.metadata,\n } : undefined);\n\n // Store the original output in artifacts\n artifacts[step.id] = result.output;\n metrics.push(...result.metrics);\n completedSteps.push(step.id);\n\n // Notify step complete\n const stepDuration = Date.now() - stepStartTime;\n callbacks?.onStepComplete?.(step.id, stepIndex, step.type, stepDuration);\n\n // Call onStepEnd hook (new observability) - conditional steps\n if (this.observability && sampled && traceContext && executionId && stepSpanId) {\n // Find metrics by type\n const leafMetrics = result.metrics.filter(m => m.metadata?.kind === 'leaf');\n const wrapperMetric = result.metrics.find(m => m.metadata?.kind === 'wrapper');\n\n // Find leaf metrics that belong to this step\n const stepLeafMetrics = result.metrics.filter(m =>\n m.configStepId === step.id && m.metadata?.kind === 'leaf'\n );\n\n // If there are MULTIPLE leaf metrics for this step, it's consensus runs (pure wrapper)\n // If there's exactly ONE leaf metric for this step, that's the step's own work\n const isConsensus = stepLeafMetrics.length > 1;\n const stepOwnLeafMetric = isConsensus ? undefined : stepLeafMetrics[0];\n\n // Determine if there are child metrics (from branch flows, etc.)\n const hasOtherChildMetrics = result.metrics.some(m => m.configStepId !== step.id);\n const hasChildMetrics = isConsensus || hasOtherChildMetrics || leafMetrics.length > 1;\n\n let metricKind: 'leaf' | 'wrapper' | 'prep';\n let ownDuration: number;\n let ownCost: number;\n let ownInputTokens: number;\n let ownOutputTokens: number;\n let ownCacheCreationTokens: number | undefined;\n let ownCacheReadTokens: number | undefined;\n\n if (isConsensus) {\n // Consensus: multiple leaf metrics = pure wrapper (children report via onConsensusRunComplete)\n metricKind = 'wrapper';\n ownDuration = wrapperMetric?.metadata?.overheadMs ?? 0;\n ownCost = 0;\n ownInputTokens = 0;\n ownOutputTokens = 0;\n ownCacheCreationTokens = undefined;\n ownCacheReadTokens = undefined;\n } else if (stepOwnLeafMetric) {\n // Step has its own API call (e.g., categorize in conditional)\n // It's a wrapper if it ALSO has child metrics\n metricKind = hasOtherChildMetrics ? 'wrapper' : 'leaf';\n ownDuration = stepOwnLeafMetric.ms ?? 0;\n ownCost = stepOwnLeafMetric.costUSD ?? 0;\n ownInputTokens = stepOwnLeafMetric.inputTokens ?? 0;\n ownOutputTokens = stepOwnLeafMetric.outputTokens ?? 0;\n ownCacheCreationTokens = stepOwnLeafMetric.cacheCreationInputTokens;\n ownCacheReadTokens = stepOwnLeafMetric.cacheReadInputTokens;\n } else if (wrapperMetric || hasChildMetrics) {\n // Pure wrapper - no own API call, just orchestration\n metricKind = 'wrapper';\n ownDuration = wrapperMetric?.metadata?.overheadMs ?? 0;\n ownCost = 0;\n ownInputTokens = 0;\n ownOutputTokens = 0;\n ownCacheCreationTokens = undefined;\n ownCacheReadTokens = undefined;\n } else {\n // No metrics = prep step\n metricKind = 'prep';\n ownDuration = stepDuration;\n ownCost = 0;\n ownInputTokens = 0;\n ownOutputTokens = 0;\n ownCacheCreationTokens = undefined;\n ownCacheReadTokens = undefined;\n }\n\n // Get provider/model from first metric\n const firstMetric = result.metrics.length > 0 ? result.metrics[0] : undefined;\n\n const stepEndContext: StepEndContext = {\n flowId: 'flow',\n executionId,\n stepId: step.id,\n stepIndex,\n timestamp: Date.now(),\n startTime: stepStartTime,\n duration: ownDuration,\n output: result.output,\n usage: {\n inputTokens: ownInputTokens,\n outputTokens: ownOutputTokens,\n totalTokens: ownInputTokens + ownOutputTokens,\n cacheCreationInputTokens: ownCacheCreationTokens,\n cacheReadInputTokens: ownCacheReadTokens,\n },\n cost: ownCost,\n metricKind,\n otelAttributes: buildStepAttributes({\n stepType: 'conditional',\n provider: firstMetric?.provider,\n model: firstMetric?.model,\n inputTokens: ownInputTokens,\n outputTokens: ownOutputTokens,\n }),\n metadata: this.metadata,\n traceContext,\n spanId: stepSpanId,\n };\n\n await executeHook(this.observability.onStepEnd, {\n hookName: 'onStepEnd',\n config: this.observability,\n context: stepEndContext,\n });\n }\n\n // Track as non-output data\n lastNonOutputData = result.output;\n\n // Update currentData for next step (no need to unwrap here, handled in next iteration)\n currentData = result.output;\n } else if (step.type === 'forEach') {\n // forEach step - process array items in parallel\n if (!Array.isArray(currentData)) {\n throw new Error(`forEach step \"${step.id}\" requires array input, got ${typeof currentData}`);\n }\n\n const items = currentData;\n const batchId = executionId ? `${executionId}-batch-${stepIndex}` : `batch-${stepIndex}`;\n const batchStartTime = Date.now();\n\n // onBatchStart hook\n if (this.observability && sampled && traceContext && executionId) {\n const batchStartContext: BatchStartContext = {\n flowId: 'flow',\n executionId,\n batchId,\n stepId: step.id,\n totalItems: items.length,\n timestamp: batchStartTime,\n metadata: this.metadata,\n traceContext,\n };\n await executeHook(this.observability.onBatchStart, {\n hookName: 'onBatchStart',\n config: this.observability,\n context: batchStartContext,\n });\n }\n\n const results = await Promise.allSettled(\n items.map(async (item: any, itemIndex: number) => {\n const itemStartTime = Date.now();\n const itemSpanId = this.traceContextManager && sampled ? generateSpanId() : undefined;\n\n // onBatchItemStart hook\n if (this.observability && sampled && traceContext && executionId) {\n const batchItemContext: BatchItemContext = {\n flowId: 'flow',\n executionId,\n batchId,\n stepId: step.id,\n itemIndex,\n totalItems: items.length,\n timestamp: itemStartTime,\n item,\n metadata: this.metadata,\n traceContext,\n };\n await executeHook(this.observability.onBatchItemStart, {\n hookName: 'onBatchItemStart',\n config: this.observability,\n context: batchItemContext,\n });\n }\n\n try {\n const childFlow = step.childFlow(item);\n const builtFlow = childFlow.build();\n\n // If item is a SplitDocument (has .input property), pass the input to the child flow\n // Otherwise pass the item itself\n const flowInput = item && typeof item === 'object' && 'input' in item ? item.input : item;\n\n // Pass original flow input to child flow for extract node's useOriginalSource option\n // __flowInput will be the segment source, __originalFlowInput is the pre-split source\n const childInitialArtifacts = {\n __originalFlowInput: artifacts.__flowInput, // Original source before split\n };\n\n const result = await builtFlow.run(flowInput, { initialArtifacts: childInitialArtifacts });\n\n // Handle both FlowResult and { results: FlowResult[] }\n let itemResult;\n if ('results' in result && Array.isArray(result.results)) {\n // Child flow has forEach - aggregate metrics and artifacts from results\n const aggregatedMetrics = (result.results || []).flatMap((r: any) => (r && r.metrics) || []);\n const aggregatedArtifacts = (result.results || []).map((r: any) => r && r.artifacts);\n itemResult = {\n output: (result.results || []).map((r: any) => r && r.output),\n metrics: aggregatedMetrics,\n artifacts: aggregatedArtifacts\n };\n } else {\n // Regular flow result - cast to access properties\n const flowResult = result as FlowResult<any>;\n itemResult = {\n output: flowResult.output,\n metrics: flowResult.metrics || [],\n artifacts: flowResult.artifacts || {}\n };\n }\n\n // onBatchItemEnd hook (success)\n if (this.observability && sampled && traceContext && executionId) {\n const batchItemEndContext: BatchItemEndContext = {\n flowId: 'flow',\n executionId,\n batchId,\n stepId: step.id,\n itemIndex,\n totalItems: items.length,\n item,\n timestamp: Date.now(),\n duration: Date.now() - itemStartTime,\n result: itemResult.output,\n status: 'success',\n metadata: this.metadata,\n traceContext,\n };\n await executeHook(this.observability.onBatchItemEnd, {\n hookName: 'onBatchItemEnd',\n config: this.observability,\n context: batchItemEndContext,\n });\n }\n\n return itemResult;\n } catch (error) {\n // Log the full error for debugging\n console.error('[forEach error]', error);\n\n // onBatchItemEnd hook (error)\n if (this.observability && sampled && traceContext && executionId) {\n const batchItemEndContext: BatchItemEndContext = {\n flowId: 'flow',\n executionId,\n batchId,\n stepId: step.id,\n itemIndex,\n totalItems: items.length,\n item,\n timestamp: Date.now(),\n duration: Date.now() - itemStartTime,\n result: null,\n status: 'failed',\n error: error instanceof Error ? error : new Error(String(error)),\n metadata: this.metadata,\n traceContext,\n };\n await executeHook(this.observability.onBatchItemEnd, {\n hookName: 'onBatchItemEnd',\n config: this.observability,\n context: batchItemEndContext,\n });\n }\n\n return {\n output: null,\n error: (error as Error).message || String(error),\n metrics: [],\n artifacts: {}\n };\n }\n })\n );\n\n // Convert Promise.allSettled results to FlowResult[]\n const flowResults = results.map((result, index) => {\n if (result.status === 'fulfilled') {\n return result.value;\n } else {\n return {\n output: null,\n error: result.reason,\n metrics: [],\n artifacts: {}\n };\n }\n });\n\n artifacts[step.id] = flowResults.map(r => r.artifacts);\n metrics.push(...flowResults.flatMap(r => r.metrics));\n completedSteps.push(step.id);\n\n // onBatchEnd hook\n const successfulCount = flowResults.filter(r => !r.error).length;\n const failedCount = flowResults.filter(r => r.error).length;\n\n if (this.observability && sampled && traceContext && executionId) {\n const batchEndContext: BatchEndContext = {\n flowId: 'flow',\n executionId,\n batchId,\n stepId: step.id,\n timestamp: Date.now(),\n startTime: batchStartTime,\n duration: Date.now() - batchStartTime,\n totalItems: items.length,\n successfulItems: successfulCount,\n failedItems: failedCount,\n results: flowResults.map(r => r.output),\n metadata: this.metadata,\n traceContext,\n };\n await executeHook(this.observability.onBatchEnd, {\n hookName: 'onBatchEnd',\n config: this.observability,\n context: batchEndContext,\n });\n }\n\n // Notify step complete\n const stepDuration = Date.now() - stepStartTime;\n callbacks?.onStepComplete?.(step.id, stepIndex, step.type, stepDuration);\n\n // Return results array\n return {\n results: flowResults,\n metrics,\n aggregated: aggregateMetrics(metrics),\n artifacts: filterInternalArtifacts(artifacts)\n };\n }\n } catch (error) {\n // Wrap error with flow execution context\n const err = error instanceof Error ? error : new Error(String(error));\n\n // Notify step error (old callbacks)\n callbacks?.onStepError?.(step.id, stepIndex, step.type, err);\n\n // Call onStepError hook (new observability)\n if (this.observability && sampled && traceContext && executionId && stepSpanId) {\n const stepErrorTime = Date.now();\n const stepErrorContext: StepErrorContext = {\n flowId: 'flow',\n executionId,\n stepId: step.id,\n stepIndex,\n timestamp: stepErrorTime,\n startTime: stepStartTime,\n duration: stepErrorTime - stepStartTime,\n error: err,\n errorCode: (err as any).code,\n willRetry: false, // TODO: Determine if will retry\n metadata: this.metadata,\n traceContext,\n spanId: stepSpanId,\n };\n\n await executeHook(this.observability.onStepError, {\n hookName: 'onStepError',\n config: this.observability,\n context: stepErrorContext,\n });\n }\n\n // Check if the error is from a nested flow\n const isNestedFlowError = err instanceof FlowExecutionError;\n\n // Build helpful error message with context\n // Only add completedStepsStr for the outermost error (avoid duplicates)\n const completedStepsStr = isNestedFlowError\n ? '' // Inner error already has this context\n : (completedSteps.length > 0\n ? `\\n Completed steps: ${completedSteps.join(' → ')}`\n : '\\n No steps completed before failure');\n\n const artifactsStr = Object.keys(artifacts).length > 0\n ? `\\n Partial results available in: ${Object.keys(artifacts).join(', ')}`\n : '';\n\n // Aggregate all completed steps across flow boundaries\n const allCompleted = isNestedFlowError\n ? [...(err.allCompletedSteps || err.completedSteps), ...completedSteps]\n : completedSteps;\n\n // Build flow path (extend nested path or create new)\n const flowPath: FlowStepLocation[] = isNestedFlowError && err.flowPath\n ? [...err.flowPath, { stepId: step.id, stepIndex, stepType: step.type }]\n : [{ stepId: step.id, stepIndex, stepType: step.type }];\n\n // Get root cause message for cleaner error display\n const errorMessage = isNestedFlowError\n ? err.getRootCause().message\n : err.message;\n\n throw new FlowExecutionError(\n `Flow execution failed at step \"${step.id}\" (index ${stepIndex}, type: ${step.type})` +\n `\\n Error: ${errorMessage}` +\n completedStepsStr +\n artifactsStr,\n step.id,\n stepIndex,\n step.type,\n completedSteps,\n isNestedFlowError ? err.originalError : err,\n artifacts, // Include partial artifacts for debugging\n flowPath,\n allCompleted\n );\n }\n }\n\n // Determine final output based on whether output nodes were used\n const hasOutputNodes = Object.keys(outputs).length > 0;\n\n let result: any;\n if (hasOutputNodes) {\n // If there are output nodes, use them for the output\n const outputCount = Object.keys(outputs).length;\n\n if (outputCount === 1) {\n // Single output node - return both output and outputs for flexibility\n const singleOutput = Object.values(outputs)[0];\n result = {\n output: singleOutput,\n outputs,\n metrics,\n aggregated: aggregateMetrics(metrics),\n artifacts: filterInternalArtifacts(artifacts)\n };\n } else {\n // Multiple output nodes - return outputs object\n result = {\n output: outputs, // For backward compatibility, set output to outputs\n outputs,\n metrics,\n aggregated: aggregateMetrics(metrics),\n artifacts: filterInternalArtifacts(artifacts)\n };\n }\n } else {\n // No output nodes - use traditional last-step-as-output behavior\n result = {\n output: currentData,\n metrics,\n aggregated: aggregateMetrics(metrics),\n artifacts: filterInternalArtifacts(artifacts)\n };\n }\n\n // Call onFlowEnd hook\n if (this.observability && sampled && traceContext && executionId) {\n const flowEndTime = Date.now();\n const aggregated = aggregateMetrics(metrics);\n\n const flowStats: FlowStats = {\n stepsTotal: this.steps.length,\n stepsCompleted: completedSteps.length,\n stepsFailed: 0,\n totalTokens: aggregated.totalInputTokens + aggregated.totalOutputTokens,\n totalCost: aggregated.totalCostUSD,\n };\n\n const flowEndContext: FlowEndContext = {\n flowId: 'flow',\n executionId,\n timestamp: flowEndTime,\n startTime: flowStartTime,\n duration: flowEndTime - flowStartTime,\n output: result.output,\n stats: flowStats,\n metadata: this.metadata,\n traceContext,\n };\n\n await executeHook(this.observability.onFlowEnd, {\n hookName: 'onFlowEnd',\n config: this.observability,\n context: flowEndContext,\n });\n\n // Update execution context\n if (this.currentExecution) {\n this.currentExecution.status = 'completed';\n }\n }\n\n return result;\n\n } catch (error) {\n // Call onFlowError hook\n if (this.observability && sampled && traceContext && executionId) {\n const flowErrorTime = Date.now();\n const aggregated = aggregateMetrics(metrics);\n\n const flowStats: FlowStats = {\n stepsTotal: this.steps.length,\n stepsCompleted: completedSteps.length,\n stepsFailed: 1,\n totalTokens: aggregated.totalInputTokens + aggregated.totalOutputTokens,\n totalCost: aggregated.totalCostUSD,\n };\n\n // Find failed step index\n const failedStepIndex = completedSteps.length; // Next step after last completed\n\n const flowErrorContext: FlowErrorContext = {\n flowId: 'flow',\n executionId,\n timestamp: flowErrorTime,\n startTime: flowStartTime,\n duration: flowErrorTime - flowStartTime,\n error: error as Error,\n errorCode: (error as any).code,\n failedAtStepIndex: failedStepIndex,\n partialStats: flowStats,\n metadata: this.metadata,\n traceContext,\n };\n\n await executeHook(this.observability.onFlowError, {\n hookName: 'onFlowError',\n config: this.observability,\n context: flowErrorContext,\n });\n\n // Update execution context\n if (this.currentExecution) {\n this.currentExecution.status = 'failed';\n }\n }\n\n // Re-throw the original error\n throw error;\n }\n }\n}\n\n/**\n * Create a new flow builder\n *\n * @param options - Flow configuration options including observability and metadata\n * @example\n * ```typescript\n * const flow = createFlow({\n * observability: {\n * onFlowStart: (ctx) => console.log('Flow started:', ctx.flowId),\n * onStepEnd: (ctx) => console.log('Step done:', ctx.stepId, ctx.duration),\n * },\n * metadata: { environment: 'production', userId: 'user_123' }\n * });\n * ```\n */\nexport function createFlow<TInput = FlowInput>(options?: FlowOptions): Flow<TInput, TInput> {\n return new Flow<TInput, TInput>(options);\n}\n","/**\n * Flow Registry for Serializable Trigger Nodes\n *\n * This registry allows flows to be referenced by string IDs in serialized configs.\n * Used by the config API (serializable version) of trigger nodes.\n *\n * ## Usage\n *\n * ### Registration\n * ```typescript\n * import { registerFlow } from '@doclo/flows';\n * import { createFlow } from '@doclo/flows';\n * import { parse, extract } from '@doclo/nodes';\n *\n * // Register a flow builder\n * registerFlow('invoice-processing-v2', (providers) =>\n * createFlow()\n * .step('parse', parse({ provider: providers.ocr }))\n * .step('extract', extract({ provider: providers.vlm, schema: invoiceSchema }))\n * );\n * ```\n *\n * ### Retrieval\n * ```typescript\n * import { getFlow } from '@doclo/flows';\n *\n * const flowBuilder = getFlow('invoice-processing-v2');\n * if (flowBuilder) {\n * const flow = flowBuilder(myProviders);\n * const result = await flow.build().run(input);\n * }\n * ```\n *\n * ### Serialization\n * ```typescript\n * import { buildFlowFromConfig } from '@doclo/flows';\n *\n * const flowDef = {\n * version: '1.0.0',\n * steps: [\n * {\n * type: 'step',\n * nodeType: 'trigger',\n * config: {\n * type: 'trigger',\n * flowRef: 'invoice-processing-v2' // References registered flow\n * }\n * }\n * ]\n * };\n *\n * const flow = buildFlowFromConfig(flowDef, { providers, flows: FLOW_REGISTRY });\n * ```\n */\n\nimport type { ProviderRegistry } from '@doclo/nodes';\nimport type { BuiltFlow } from './flow-builder';\n\n/**\n * Flow builder function signature\n * Takes optional provider registry and returns a Flow instance with build() method\n *\n * A FlowBuilder is a function that:\n * 1. Accepts an optional ProviderRegistry (for provider injection/override)\n * 2. Returns a Flow instance (from createFlow()) that has a build() method\n * 3. The build() method returns a BuiltFlow with run() and validate()\n */\nexport type FlowBuilder<TInput = any, TOutput = any> = (providers?: ProviderRegistry) => {\n build: () => BuiltFlow<TInput, TOutput>;\n};\n\n/**\n * Global flow registry\n * Maps flow IDs to flow builder functions\n */\nexport const FLOW_REGISTRY = new Map<string, FlowBuilder>();\n\n/**\n * Register a flow builder in the global registry\n *\n * @param id - Unique identifier for the flow\n * @param builder - Flow builder function that accepts providers\n *\n * @example\n * ```typescript\n * registerFlow('invoice-processing', (providers) =>\n * createFlow()\n * .step('parse', parse({ provider: providers.ocr }))\n * .step('extract', extract({ provider: providers.vlm, schema }))\n * );\n * ```\n */\nexport function registerFlow<TInput = any, TOutput = any>(\n id: string,\n builder: FlowBuilder<TInput, TOutput>\n): void {\n if (FLOW_REGISTRY.has(id)) {\n console.warn(`[Flow Registry] Overwriting existing flow: ${id}`);\n }\n FLOW_REGISTRY.set(id, builder);\n}\n\n/**\n * Get a flow builder from the registry\n *\n * @param id - Flow identifier\n * @returns Flow builder function or undefined if not found\n *\n * @example\n * ```typescript\n * const builder = getFlow('invoice-processing');\n * if (builder) {\n * const flow = builder(providers);\n * const result = await flow.build().run(input);\n * }\n * ```\n */\nexport function getFlow<TInput = any, TOutput = any>(\n id: string\n): FlowBuilder<TInput, TOutput> | undefined {\n return FLOW_REGISTRY.get(id) as FlowBuilder<TInput, TOutput> | undefined;\n}\n\n/**\n * Check if a flow is registered\n *\n * @param id - Flow identifier\n * @returns true if flow is registered\n */\nexport function hasFlow(id: string): boolean {\n return FLOW_REGISTRY.has(id);\n}\n\n/**\n * Unregister a flow from the registry\n *\n * @param id - Flow identifier\n * @returns true if flow was removed, false if it didn't exist\n */\nexport function unregisterFlow(id: string): boolean {\n return FLOW_REGISTRY.delete(id);\n}\n\n/**\n * Clear all registered flows\n * Useful for testing or resetting state\n */\nexport function clearRegistry(): void {\n FLOW_REGISTRY.clear();\n}\n\n/**\n * Get all registered flow IDs\n *\n * @returns Array of flow identifiers\n */\nexport function listFlows(): string[] {\n return Array.from(FLOW_REGISTRY.keys());\n}\n\n/**\n * Get the number of registered flows\n *\n * @returns Number of flows in registry\n */\nexport function getFlowCount(): number {\n return FLOW_REGISTRY.size;\n}\n","/**\n * Flow Serialization\n *\n * Provides serialization/deserialization for doclo-sdk flows.\n * Supports all flow types: sequential steps, conditional branches, and forEach loops.\n *\n * Limitations:\n * - Provider instances must be reconstructed at runtime\n */\n\nimport type { NodeDef, VLMProvider, OCRProvider, JSONSchemaNode, FlowContext, FlowInput } from \"@doclo/core\";\nimport { createFlow, type FlowOptions, type Flow, type BuiltFlow } from './flow-builder.js';\nimport { parse, extract, split, categorize, trigger, output } from '@doclo/nodes';\nimport { createConditionalCompositeNode, createForEachCompositeNode, createRouteCompositeNode } from './composite-nodes.js';\n\n/**\n * Union type for providers used in flow serialization\n */\ntype FlowProvider = VLMProvider | OCRProvider;\n\n/**\n * JSON value type for literal field mappings\n */\ntype JsonValue = string | number | boolean | null | JsonValue[] | { [key: string]: JsonValue };\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype AnyNodeDef = NodeDef<any, any>;\n\n/**\n * Serializable input validation configuration\n */\nexport type SerializableInputValidation = {\n /**\n * List of accepted MIME types.\n * If specified, input must match one of these types or validation fails.\n */\n acceptedFormats?: Array<\n | 'application/pdf'\n | 'image/jpeg'\n | 'image/png'\n | 'image/gif'\n | 'image/webp'\n >;\n /**\n * Whether to throw on validation failure.\n * @default true\n */\n throwOnInvalid?: boolean;\n};\n\n/**\n * Serializable flow definition\n */\nexport type SerializableFlow = {\n version: string;\n steps: SerializableStep[];\n /**\n * Optional input format validation configuration.\n * Allows specifying accepted MIME types for early validation.\n */\n inputValidation?: SerializableInputValidation;\n};\n\n/**\n * Serializable step definition\n */\nexport type SerializableStep =\n | SerializableStandardStep\n | SerializableConditionalStep\n | SerializableForEachStep\n | SerializableRouteStep;\n\n/**\n * Standard sequential step\n */\nexport type SerializableStandardStep = {\n type: 'step';\n id: string;\n name?: string;\n nodeType: 'parse' | 'extract' | 'split' | 'categorize' | 'trigger' | 'output';\n config: NodeConfig;\n};\n\n/**\n * Flow reference (alternative to inline SerializableFlow)\n * Used to reduce JSON nesting depth for complex flows\n */\nexport type FlowReference = {\n flowRef: string;\n};\n\n/**\n * Conditional step (categorize + branches)\n *\n * Branches can be either inline flows or references to separate flows.\n * Use references to avoid hitting database JSON nesting limits (e.g., Convex's 16-level limit).\n */\nexport type SerializableConditionalStep = {\n type: 'conditional';\n id: string;\n name?: string;\n nodeType: 'categorize';\n config: CategorizeConfig;\n branches: Record<string, SerializableFlow | FlowReference>;\n};\n\n/**\n * ForEach step (split + item flow)\n *\n * itemFlow can be either an inline flow or a reference to a separate flow.\n * Use references to avoid hitting database JSON nesting limits.\n */\nexport type SerializableForEachStep = {\n type: 'forEach';\n id: string;\n name?: string;\n nodeType: 'split';\n config: SplitConfig;\n itemFlow: SerializableFlow | FlowReference;\n};\n\n/**\n * Route branch configuration\n * Maps multiple MIME types to a single branch\n */\nexport type RouteBranchConfig = {\n /**\n * MIME types that route to this branch.\n * Supports exact matches (e.g., 'application/pdf')\n * and glob patterns (e.g., 'image/*')\n */\n mimeTypes: string[];\n /**\n * Optional description for documentation/debugging\n */\n description?: string;\n};\n\n/**\n * Route step configuration\n * Routes documents based on detected MIME type (no provider required)\n */\nexport type RouteConfig = {\n type: 'route';\n /**\n * Branch definitions mapping branch names to MIME type configurations.\n * Order matters for matching - first matching branch wins.\n */\n branches: Record<string, RouteBranchConfig>;\n};\n\n/**\n * Route step (MIME-based routing + branches)\n *\n * Unlike conditional (which uses VLM categorization), route uses\n * deterministic MIME detection from magic bytes - no provider needed.\n *\n * Branches can be either inline flows or references to separate flows.\n * Use references to avoid hitting database JSON nesting limits.\n */\nexport type SerializableRouteStep = {\n type: 'route';\n id: string;\n name?: string;\n nodeType: 'route';\n config: RouteConfig;\n branches: Record<string, SerializableFlow | FlowReference>;\n /**\n * Fallback branch for unmatched MIME types.\n * If not provided and no branch matches, throws error with details.\n */\n others?: SerializableFlow | FlowReference;\n};\n\n/**\n * Input mapping configuration for trigger nodes\n * Declarative alternatives to mapInput functions (for serialization)\n */\nexport type InputMappingConfig =\n | { type: 'passthrough' } // Use input as-is (default)\n | { type: 'unwrap' } // Unwrap { input: X } → X\n | { type: 'artifact'; path: string } // Get from context.artifacts by path\n | { type: 'merge'; artifactPath: string } // Merge input with artifact\n | { type: 'construct'; fields: Record<string, FieldMapping> }; // Build new object\n\nexport type FieldMapping =\n | { source: 'input'; path?: string } // Get from input (optionally by path)\n | { source: 'artifact'; path: string } // Get from artifacts by path\n | { source: 'literal'; value: JsonValue }; // Static value\n\n/**\n * Node configuration (without provider instances)\n */\nexport type NodeConfig =\n | ParseConfig\n | ExtractConfig\n | SplitConfig\n | CategorizeConfig\n | TriggerConfig\n | OutputConfig;\n\nexport type ParseConfig = {\n type: 'parse';\n providerRef: string;\n consensus?: {\n runs: number;\n strategy?: 'majority' | 'unanimous';\n onTie?: 'random' | 'fail' | 'retry';\n };\n maxTokens?: number;\n promptRef?: string; // Reference to prompt asset (e.g., \"default-parse@1.0.0\")\n promptVariables?: Record<string, any>; // Variables to pass to the prompt template\n additionalInstructions?: string; // Additional instructions to append to the prompt\n};\n\nexport type ExtractConfig = {\n type: 'extract';\n providerRef: string;\n schema: JSONSchemaNode;\n consensus?: {\n runs: number;\n strategy?: 'majority' | 'unanimous';\n onTie?: 'random' | 'fail' | 'retry';\n };\n reasoning?: {\n enabled?: boolean;\n effort?: 'low' | 'medium' | 'high';\n max_tokens?: number;\n };\n maxTokens?: number;\n promptRef?: string; // Reference to prompt asset (e.g., \"default-extraction@1.0.0\")\n promptVariables?: Record<string, any>; // Variables to pass to the prompt template\n additionalInstructions?: string; // Additional instructions to append to the prompt\n};\n\nexport type SplitConfig = {\n type: 'split';\n providerRef: string;\n /**\n * Simple category definitions (recommended).\n * Each category can be a string or an object with name and optional description.\n */\n categories?: (string | { name: string; description?: string })[];\n /**\n * @deprecated Use `categories` instead. Full schema definitions for backwards compatibility.\n */\n schemas?: Record<string, JSONSchemaNode>;\n includeOther?: boolean;\n consensus?: {\n runs: number;\n strategy?: 'majority' | 'unanimous';\n onTie?: 'random' | 'fail' | 'retry';\n };\n schemaRef?: string; // Reference to schema asset (e.g., \"document-split@2.0.0\")\n maxTokens?: number;\n};\n\nexport type CategorizeConfig = {\n type: 'categorize';\n providerRef: string;\n categories: string[];\n consensus?: {\n runs: number;\n strategy?: 'majority' | 'unanimous';\n onTie?: 'random' | 'fail' | 'retry';\n };\n promptRef?: string; // Reference to prompt asset (e.g., \"default-categorize@1.0.0\")\n promptVariables?: Record<string, any>; // Variables to pass to the prompt template\n additionalInstructions?: string; // Additional instructions to append to the prompt\n maxTokens?: number;\n};\n\nexport type TriggerConfig = {\n type: 'trigger';\n flowRef: string; // Reference to registered flow\n providerOverrides?: Record<string, string>; // Map child provider refs to parent refs\n inputMapping?: InputMappingConfig; // Declarative input transformation\n mergeMetrics?: boolean; // Merge child metrics (default: true)\n timeout?: number; // Timeout in milliseconds\n};\n\nexport type OutputConfig = {\n type: 'output';\n name?: string; // Output name (for multi-output flows)\n source?: string | string[]; // Source step ID(s) to pull from\n transform?: 'first' | 'last' | 'merge' | 'pick'; // Transformation strategy (custom not serializable)\n fields?: string[]; // Fields to pick (when transform: 'pick')\n};\n\n/**\n * Provider registry for deserialization\n */\nexport type ProviderRegistry = Record<string, FlowProvider>;\n\n/**\n * Extract node metadata from a node (if available)\n * Note: This is a best-effort extraction since nodes don't currently\n * expose their config. Returns null for nodes without metadata.\n */\nexport function extractNodeMetadata(node: NodeDef<unknown, unknown>): { nodeType: string; config: NodeConfig } | null {\n // Nodes created with the @doclo/nodes functions don't expose config\n // This is a limitation of the current architecture\n // For now, we return null and require manual config specification\n return null;\n}\n\n/**\n * Validation error for flow serialization\n */\nexport class FlowSerializationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'FlowSerializationError';\n }\n}\n\n/**\n * Flow registry type\n * Maps flow IDs to SerializableFlow objects (from database/Convex)\n */\nexport type FlowRegistry = Record<string, SerializableFlow>;\n\n/**\n * Type guard to check if a value is a FlowReference\n */\nexport function isFlowReference(value: SerializableFlow | FlowReference): value is FlowReference {\n return typeof value === 'object' && value !== null && 'flowRef' in value && typeof value.flowRef === 'string';\n}\n\n/**\n * Resolve a flow reference to a SerializableFlow\n *\n * @param flowOrRef - Either an inline flow or a flow reference\n * @param flows - Flow registry to resolve references from\n * @returns SerializableFlow\n * @throws FlowSerializationError if reference cannot be resolved\n */\nexport function resolveFlowReference(\n flowOrRef: SerializableFlow | FlowReference,\n flows?: FlowRegistry\n): SerializableFlow {\n if (isFlowReference(flowOrRef)) {\n if (!flows) {\n throw new FlowSerializationError(\n `Flow reference \"${flowOrRef.flowRef}\" found but no flow registry provided`\n );\n }\n\n const resolvedFlow = flows[flowOrRef.flowRef];\n if (!resolvedFlow) {\n throw new FlowSerializationError(\n `Flow reference \"${flowOrRef.flowRef}\" not found in registry. Available flows: ${Object.keys(flows).join(', ')}`\n );\n }\n\n return resolvedFlow;\n }\n\n return flowOrRef;\n}\n\n/**\n * Build a flow from a serializable definition\n *\n * @param flowDef - Serializable flow definition\n * @param providers - Provider registry (map of provider refs to provider instances)\n * @param flows - Optional flow registry for:\n * - Trigger nodes (map of flow refs to flow builders)\n * - Conditional branches (when using flowRef instead of inline SerializableFlow)\n * - ForEach itemFlow (when using flowRef instead of inline SerializableFlow)\n * @returns Executable flow\n *\n * @example\n * ```typescript\n * const flowDef: SerializableFlow = {\n * version: '1.0.0',\n * steps: [\n * {\n * type: 'step',\n * id: 'parse',\n * nodeType: 'parse',\n * config: { type: 'parse', providerRef: 'ocr' }\n * },\n * {\n * type: 'step',\n * id: 'extract',\n * nodeType: 'extract',\n * config: {\n * type: 'extract',\n * providerRef: 'llm',\n * schema: { ... }\n * }\n * }\n * ]\n * };\n *\n * const providers = {\n * ocr: suryaProvider,\n * llm: geminiProvider\n * };\n *\n * const flow = buildFlowFromConfig(flowDef, providers);\n * ```\n */\nexport function buildFlowFromConfig(\n flowDef: SerializableFlow,\n providers: ProviderRegistry,\n flows?: FlowRegistry,\n options?: FlowOptions\n): BuiltFlow<FlowInput, unknown> {\n // Validate version\n if (flowDef.version !== '1.0.0') {\n throw new FlowSerializationError(`Unsupported flow version: ${flowDef.version}`);\n }\n\n // Merge inputValidation from flowDef with options (flowDef takes precedence)\n const mergedOptions: FlowOptions = {\n ...options,\n inputValidation: flowDef.inputValidation ?? options?.inputValidation\n };\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let flow: Flow<any, any> = createFlow(mergedOptions);\n\n for (const step of flowDef.steps) {\n if (step.type === 'step') {\n // Standard sequential step\n const node = createNodeFromConfig(step.nodeType, step.config, providers, flows);\n flow = flow.step(step.id, node, step.name);\n\n } else if (step.type === 'conditional') {\n // Create composite node that handles categorize + branch execution\n const node = createConditionalCompositeNode({\n stepId: step.id,\n categorizeConfig: step.config,\n branches: step.branches,\n providers,\n flows: flows || {}\n });\n flow = flow.step(step.id, node, step.name);\n\n } else if (step.type === 'forEach') {\n // Create composite node that handles split + forEach execution\n const node = createForEachCompositeNode({\n stepId: step.id,\n splitConfig: step.config,\n itemFlow: step.itemFlow,\n providers,\n flows: flows || {}\n });\n flow = flow.step(step.id, node, step.name);\n\n } else if (step.type === 'route') {\n // Create composite node that handles MIME detection + branch routing\n const node = createRouteCompositeNode({\n stepId: step.id,\n routeConfig: step.config,\n branches: step.branches,\n others: step.others,\n providers,\n flows: flows || {}\n });\n flow = flow.step(step.id, node, step.name);\n\n } else {\n // Exhaustive check - this should be unreachable\n const exhaustiveCheck: never = step;\n throw new FlowSerializationError(`Unknown step type: ${(exhaustiveCheck as SerializableStep).type}`);\n }\n }\n\n return flow.build();\n}\n\n/**\n * Helper to safely traverse a nested object by path\n */\nfunction getByPath(obj: unknown, path: string[]): unknown {\n return path.reduce((current: unknown, key: string) => {\n if (current && typeof current === 'object' && key in current) {\n return (current as Record<string, unknown>)[key];\n }\n return undefined;\n }, obj);\n}\n\n/**\n * Create an input mapper function from declarative config\n * Uses 'any' for input/context to match the expected function signature in trigger nodes\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction createInputMapper(mappingConfig: InputMappingConfig): (input: any, context: FlowContext) => unknown {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n return (input: any, context: FlowContext) => {\n switch (mappingConfig.type) {\n case 'passthrough':\n return input;\n\n case 'unwrap':\n if (input && typeof input === 'object' && 'input' in input) {\n return (input as Record<string, unknown>).input;\n }\n return input;\n\n case 'artifact': {\n const pathParts = mappingConfig.path.split('.');\n return getByPath(context.artifacts, pathParts);\n }\n\n case 'merge': {\n const pathParts = mappingConfig.artifactPath.split('.');\n const artifactValue = getByPath(context.artifacts, pathParts);\n if (typeof input === 'object' && input !== null && typeof artifactValue === 'object' && artifactValue !== null) {\n return { ...input, ...artifactValue };\n }\n return input;\n }\n\n case 'construct': {\n const result: Record<string, unknown> = {};\n for (const [fieldName, fieldMapping] of Object.entries(mappingConfig.fields)) {\n switch (fieldMapping.source) {\n case 'input':\n if (fieldMapping.path) {\n const pathParts = fieldMapping.path.split('.');\n result[fieldName] = getByPath(input, pathParts);\n } else {\n result[fieldName] = input;\n }\n break;\n\n case 'artifact': {\n const pathParts = fieldMapping.path.split('.');\n result[fieldName] = getByPath(context.artifacts, pathParts);\n break;\n }\n\n case 'literal':\n result[fieldName] = fieldMapping.value;\n break;\n }\n }\n return result;\n }\n\n default:\n return input;\n }\n };\n}\n\n/**\n * Type guard to check if config has providerRef\n */\nfunction hasProviderRef(config: NodeConfig): config is NodeConfig & { providerRef: string } {\n return 'providerRef' in config && typeof config.providerRef === 'string';\n}\n\n/**\n * Helper to create a node from config\n */\nfunction createNodeFromConfig(\n nodeType: string,\n config: NodeConfig,\n providers: ProviderRegistry,\n flows?: FlowRegistry\n): AnyNodeDef {\n // For trigger nodes, flowRef is required instead of providerRef\n if (nodeType === 'trigger') {\n const cfg = config as TriggerConfig;\n\n if (!flows || !flows[cfg.flowRef]) {\n throw new FlowSerializationError(\n `Flow \"${cfg.flowRef}\" not found in flow registry. ` +\n `Available flows: ${flows ? Object.keys(flows).join(', ') : 'none'}`\n );\n }\n\n // Map provider overrides\n const overrideProviders: Record<string, FlowProvider> = {};\n if (cfg.providerOverrides) {\n for (const [childRef, parentRef] of Object.entries(cfg.providerOverrides)) {\n if (!providers[parentRef]) {\n throw new FlowSerializationError(\n `Provider \"${parentRef}\" not found in provider registry. ` +\n `Available providers: ${Object.keys(providers).join(', ')}`\n );\n }\n overrideProviders[childRef] = providers[parentRef];\n }\n }\n\n // Get flow builder from registry\n const flowBuilder = flows[cfg.flowRef];\n\n return trigger({\n flow: flowBuilder,\n flowId: cfg.flowRef,\n providers: Object.keys(overrideProviders).length > 0 ? overrideProviders : undefined,\n mapInput: cfg.inputMapping ? createInputMapper(cfg.inputMapping) : undefined,\n mergeMetrics: cfg.mergeMetrics,\n timeout: cfg.timeout\n });\n }\n\n // For output nodes, no provider is required (they pull from artifacts)\n if (nodeType === 'output') {\n const cfg = config as OutputConfig;\n return output({\n name: cfg.name,\n source: cfg.source,\n transform: cfg.transform,\n fields: cfg.fields\n });\n }\n\n // For other nodes, providerRef is required\n if (!hasProviderRef(config)) {\n throw new FlowSerializationError(\n `Config for node type \"${nodeType}\" is missing providerRef`\n );\n }\n\n const provider = providers[config.providerRef];\n if (!provider) {\n throw new FlowSerializationError(\n `Provider \"${config.providerRef}\" not found in registry. ` +\n `Available providers: ${Object.keys(providers).join(', ')}`\n );\n }\n\n switch (nodeType) {\n case 'parse': {\n const cfg = config as ParseConfig;\n // parse expects OCRProvider\n return parse({\n provider: provider as OCRProvider,\n consensus: cfg.consensus,\n maxTokens: cfg.maxTokens,\n promptRef: cfg.promptRef,\n promptVariables: cfg.promptVariables,\n additionalInstructions: cfg.additionalInstructions\n });\n }\n\n case 'extract': {\n const cfg = config as ExtractConfig;\n // extract expects VLMProvider\n return extract({\n provider: provider as VLMProvider,\n schema: cfg.schema,\n consensus: cfg.consensus,\n reasoning: cfg.reasoning,\n maxTokens: cfg.maxTokens,\n promptRef: cfg.promptRef,\n promptVariables: cfg.promptVariables,\n additionalInstructions: cfg.additionalInstructions\n });\n }\n\n case 'split': {\n const cfg = config as SplitConfig;\n // split expects VLMProvider\n return split({\n provider: provider as VLMProvider,\n // Support both categories (new) and schemas (legacy)\n ...(cfg.categories && { categories: cfg.categories }),\n ...(cfg.schemas && { schemas: cfg.schemas }),\n ...(cfg.schemaRef && { schemaRef: cfg.schemaRef }),\n includeOther: cfg.includeOther,\n consensus: cfg.consensus,\n maxTokens: cfg.maxTokens\n });\n }\n\n case 'categorize': {\n const cfg = config as CategorizeConfig;\n // categorize expects VLMProvider\n return categorize({\n provider: provider as VLMProvider,\n categories: cfg.categories,\n consensus: cfg.consensus,\n maxTokens: cfg.maxTokens,\n promptRef: cfg.promptRef,\n promptVariables: cfg.promptVariables,\n additionalInstructions: cfg.additionalInstructions\n });\n }\n\n default:\n throw new FlowSerializationError(`Unknown node type: ${nodeType}`);\n }\n}\n\n/**\n * Helper to create a serializable flow definition\n *\n * @example\n * ```typescript\n * const flowDef = defineFlowConfig({\n * version: '1.0.0',\n * steps: [\n * {\n * type: 'step',\n * id: 'parse',\n * nodeType: 'parse',\n * config: { type: 'parse', providerRef: 'ocr' }\n * }\n * ]\n * });\n *\n * // Save to database\n * await db.flows.create({ definition: JSON.stringify(flowDef) });\n *\n * // Later, load and build\n * const loaded = JSON.parse(row.definition);\n * const flow = buildFlowFromConfig(loaded, providers);\n * ```\n */\nexport function defineFlowConfig(config: Omit<SerializableFlow, 'version'>): SerializableFlow {\n return {\n version: '1.0.0',\n ...config\n };\n}\n","/**\n * Composite nodes for conditional and forEach execution\n *\n * These nodes wrap complex multi-step operations (categorize + branch, split + forEach)\n * into single logical steps with proper observability, metrics, and error handling.\n */\n\nimport type { NodeDef, StepMetric, VLMProvider, FlowResult, NodeCtx, FlowInput, SplitDocument, FlowStepLocation } from '@doclo/core';\nimport { FlowExecutionError } from '@doclo/core';\nimport { buildFlowFromConfig, type ProviderRegistry } from './serialization.js';\nimport type { SerializableFlow, FlowReference, CategorizeConfig, SplitConfig, RouteConfig, RouteBranchConfig } from './serialization.js';\nimport { detectMimeTypeFromBase64Async, detectMimeTypeFromBase64 } from '@doclo/core';\nimport { categorize, split } from '@doclo/nodes';\nimport { isSingleFlowResult, type BatchFlowResult } from './flow-builder.js';\n\n/**\n * Flow registry type\n * Maps flow IDs to SerializableFlow objects (from database/Convex)\n */\ntype FlowRegistry = Record<string, SerializableFlow>;\n\n/**\n * Parse provider name in format \"provider:model\" to separate fields\n * Example: \"google:gemini-2.5-flash\" -> { provider: \"google\", model: \"gemini-2.5-flash\" }\n */\nfunction parseProviderName(name: string): { provider: string; model: string } {\n const colonIndex = name.indexOf(':');\n if (colonIndex === -1) {\n // No colon found, treat entire name as provider\n return { provider: name, model: 'unknown' };\n }\n return {\n provider: name.substring(0, colonIndex),\n model: name.substring(colonIndex + 1)\n };\n}\n\n/**\n * Parse reference string in format \"id@version\" to extract id and version\n * @example \"my-prompt@1.2.0\" -> { id: \"my-prompt\", version: \"1.2.0\" }\n * @example \"my-prompt\" -> { id: \"my-prompt\", version: undefined }\n */\nfunction parseRef(refString: string | undefined): { id: string; version: string | undefined } | null {\n if (!refString) return null;\n\n const atIndex = refString.indexOf('@');\n if (atIndex === -1) {\n return { id: refString, version: undefined };\n }\n\n return {\n id: refString.substring(0, atIndex),\n version: refString.substring(atIndex + 1)\n };\n}\n\n/**\n * Helper function to flatten child flow metrics by prefixing step names\n * Follows the pattern from trigger node (packages/nodes/src/trigger.ts:253-276)\n */\nfunction flattenMetrics(\n childMetrics: StepMetric[],\n prefix: string\n): StepMetric[] {\n return childMetrics.map(m => ({\n ...m,\n step: `${prefix}.${m.step}`,\n // @ts-ignore - Add metadata for nested metrics (not in official type but works at runtime)\n nested: true\n }));\n}\n\n/**\n * Configuration for conditional composite node\n */\nexport interface ConditionalCompositeConfig {\n stepId: string;\n categorizeConfig: CategorizeConfig;\n branches: Record<string, SerializableFlow | FlowReference>;\n providers: ProviderRegistry;\n flows: FlowRegistry;\n}\n\n/**\n * Creates a composite node that:\n * 1. Executes a categorize node to determine the category\n * 2. Selects and executes the appropriate branch flow\n * 3. Returns the branch flow's output\n *\n * Includes full observability, metrics merging, and error context.\n */\nexport function createConditionalCompositeNode(\n config: ConditionalCompositeConfig\n): NodeDef<FlowInput, unknown> {\n const { stepId, categorizeConfig, branches, providers, flows } = config;\n\n return {\n key: 'conditional-composite',\n run: async (input: FlowInput, ctx?: NodeCtx) => {\n const t0 = Date.now();\n let selectedCategory: string | undefined;\n let phase: 'categorize' | 'branch' = 'categorize';\n\n try {\n // === PHASE 1: CATEGORIZE ===\n // Build categorize node\n // Cast to VLMProvider since categorize requires VLM capabilities\n const categorizeNode = categorize({\n ...categorizeConfig,\n provider: providers[categorizeConfig.providerRef] as VLMProvider,\n categories: categorizeConfig.categories || Object.keys(branches)\n });\n\n // Execute categorize node (track metrics to get cost)\n const categorizeT0 = Date.now();\n const categorizeCostTracker: StepMetric[] = [];\n const categorizeCtx: NodeCtx = {\n stepId: stepId, // Use composite step's ID so categorize metric is attributed to this step\n metrics: { push: (m: StepMetric) => categorizeCostTracker.push(m) },\n artifacts: ctx?.artifacts ?? {},\n emit: ctx?.emit ?? (() => {}), // No-op if emit not provided\n observability: ctx?.observability\n };\n const categorizeResult = await categorizeNode.run(input, categorizeCtx);\n selectedCategory = categorizeResult.category;\n\n // Push categorize metric to main context\n categorizeCostTracker.forEach(m => ctx?.metrics?.push(m));\n\n // Store category decision in artifacts\n if (ctx?.emit) {\n ctx.emit(`${stepId}:category`, selectedCategory);\n }\n\n // === PHASE 2: ROUTE TO BRANCH ===\n phase = 'branch';\n\n // Check if branch exists\n if (!branches[selectedCategory]) {\n throw new Error(\n `No branch defined for category \"${selectedCategory}\". ` +\n `Available branches: ${Object.keys(branches).join(', ')}`\n );\n }\n\n // Resolve flow reference to actual flow definition\n const branchFlowDef = resolveBranchFlow(branches[selectedCategory], flows);\n\n // Build the branch flow with observability options\n const branchFlow = buildFlowFromConfig(\n branchFlowDef,\n providers,\n flows,\n ctx?.observability?.config ? {\n observability: ctx.observability.config,\n metadata: {\n ...ctx.observability?.metadata,\n parentNode: stepId,\n phase: 'branch',\n category: selectedCategory\n }\n } : undefined\n );\n\n // Execute branch flow\n const branchT0 = Date.now();\n const branchResultRaw = await branchFlow.run(input);\n\n // Type guard to ensure we have a single flow result\n if (!isSingleFlowResult(branchResultRaw)) {\n throw new Error('Branch flow returned batch result instead of single result');\n }\n const branchResult = branchResultRaw;\n\n // Merge branch flow metrics\n if (ctx?.metrics && branchResult.metrics) {\n const branchMetrics = flattenMetrics(\n branchResult.metrics,\n `${stepId}.branch.${selectedCategory}`\n );\n branchMetrics.forEach(m => ctx.metrics.push(m));\n }\n\n // Store branch output in artifacts\n if (ctx?.emit) {\n ctx.emit(`${stepId}:branchOutput`, branchResult.output);\n ctx.emit(`${stepId}:branchArtifacts`, branchResult.artifacts);\n }\n\n // === PHASE 3: COMPLETE ===\n // Calculate aggregate cost from categorize + branch operations\n const categorizeCost = categorizeCostTracker.reduce((sum: number, m: StepMetric) => sum + (m.costUSD ?? 0), 0);\n const branchCost = branchResult.metrics\n ? branchResult.metrics.reduce((sum: number, m: StepMetric) => sum + (m.costUSD ?? 0), 0)\n : 0;\n const aggregateCost = categorizeCost + branchCost;\n\n // Calculate duration breakdown\n const totalMs = Date.now() - t0;\n const categorizeMs = categorizeCostTracker.reduce((sum: number, m: StepMetric) => sum + (m.ms ?? 0), 0);\n const branchMs = branchResult.metrics\n ? branchResult.metrics.reduce((sum: number, m: StepMetric) => sum + (m.ms ?? 0), 0)\n : 0;\n const overheadMs = totalMs - categorizeMs - branchMs; // Pure wrapper overhead\n\n // Add composite node overhead metric\n if (ctx?.metrics) {\n const provider = providers[categorizeConfig.providerRef];\n const { provider: providerName, model } = parseProviderName(provider.name ?? '');\n\n // Extract promptId and promptVersion from promptRef if present\n const promptRefData = parseRef(categorizeConfig.promptRef);\n\n const wrapperMetric: StepMetric = {\n step: stepId,\n configStepId: ctx.stepId,\n startMs: t0,\n provider: providerName,\n model,\n ms: totalMs,\n costUSD: aggregateCost, // Total cost from categorize + branch\n attemptNumber: 1, // Composite wrappers don't retry, always 1\n metadata: {\n kind: 'wrapper', // Distinguish wrapper from leaf metrics\n type: 'conditional',\n rollup: true, // Duration includes child work\n overheadMs, // Pure wrapper overhead (flow orchestration)\n category: selectedCategory,\n branchStepCount: branchResult.metrics?.length || 0,\n branchFlowId: typeof branches[selectedCategory] === 'object' && 'flowRef' in branches[selectedCategory]\n ? (branches[selectedCategory] as FlowReference).flowRef\n : 'inline',\n // Include prompt metadata if available\n ...(promptRefData && {\n promptId: promptRefData.id,\n ...(promptRefData.version && { promptVersion: promptRefData.version })\n })\n }\n };\n\n ctx.metrics.push(wrapperMetric);\n }\n\n // Return branch output (transparent to next step)\n return branchResult.output;\n\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n const isNestedFlowError = err instanceof FlowExecutionError;\n\n // Add error metric\n if (ctx?.metrics) {\n ctx.metrics.push({\n step: stepId,\n configStepId: ctx.stepId,\n startMs: t0,\n ms: Date.now() - t0,\n costUSD: 0,\n attemptNumber: 1,\n // @ts-ignore - Add error field\n error: err.message,\n metadata: {\n kind: 'wrapper',\n type: 'conditional',\n failed: true,\n category: selectedCategory,\n failedPhase: phase\n }\n });\n }\n\n // Build flow path with branch context\n const flowPath: FlowStepLocation[] = [{\n stepId,\n stepIndex: 0,\n stepType: 'conditional',\n branch: selectedCategory || undefined\n }];\n\n // If inner error is FlowExecutionError, extend its path\n if (isNestedFlowError && err.flowPath) {\n flowPath.push(...err.flowPath);\n }\n\n // Get the root cause message for cleaner error display\n const rootCauseMessage = isNestedFlowError\n ? err.getRootCause().message\n : err.message;\n\n // Throw FlowExecutionError with full context\n throw new FlowExecutionError(\n `Conditional step \"${stepId}\" failed` +\n `${selectedCategory ? ` (category: ${selectedCategory})` : ''}` +\n ` in phase: ${phase}` +\n `\\n Error: ${rootCauseMessage}`,\n stepId,\n 0,\n 'conditional',\n [],\n isNestedFlowError ? err.originalError : err,\n undefined,\n flowPath,\n isNestedFlowError ? err.allCompletedSteps : undefined\n );\n }\n }\n };\n}\n\n/**\n * Configuration for forEach composite node\n */\nexport interface ForEachCompositeConfig {\n stepId: string;\n splitConfig: SplitConfig;\n itemFlow: SerializableFlow | FlowReference;\n providers: ProviderRegistry;\n flows: FlowRegistry;\n}\n\n/**\n * Creates a composite node that:\n * 1. Executes a split node to get an array of items\n * 2. Executes the item flow for each item in parallel\n * 3. Returns aggregated results\n *\n * Includes full observability, metrics merging, and error context.\n */\nexport function createForEachCompositeNode(\n config: ForEachCompositeConfig\n): NodeDef<FlowInput, unknown[]> {\n const { stepId, splitConfig, itemFlow, providers, flows } = config;\n\n return {\n key: 'forEach-composite',\n run: async (input: FlowInput, ctx?: NodeCtx) => {\n const t0 = Date.now();\n let items: SplitDocument[] | undefined;\n let phase: 'split' | 'forEach' = 'split';\n\n try {\n // === PHASE 1: SPLIT ===\n // Build split node\n // Cast to VLMProvider since split requires VLM capabilities\n const splitNode = split({\n provider: providers[splitConfig.providerRef] as VLMProvider,\n ...splitConfig\n });\n\n // Execute split node (track metrics to get cost)\n const splitT0 = Date.now();\n const splitCostTracker: StepMetric[] = [];\n const splitCtx: NodeCtx = {\n stepId: stepId, // Use composite step's ID for attribution\n metrics: { push: (m: StepMetric) => splitCostTracker.push(m) },\n artifacts: ctx?.artifacts ?? {},\n emit: ctx?.emit ?? (() => {}), // No-op if emit not provided\n observability: ctx?.observability\n };\n const splitResult = await splitNode.run(input, splitCtx);\n items = splitResult; // Split node returns array directly\n\n // Push split metric to main context\n splitCostTracker.forEach(m => ctx?.metrics?.push(m));\n\n if (!Array.isArray(items)) {\n throw new Error(\n `Split node did not return an array. Got: ${typeof items}`\n );\n }\n\n // Store item count in artifacts\n if (ctx?.emit) {\n ctx.emit(`${stepId}:itemCount`, items.length);\n }\n\n // === PHASE 2: FOR EACH ===\n phase = 'forEach';\n\n // Resolve flow reference to actual flow definition\n const itemFlowDef = resolveBranchFlow(itemFlow, flows);\n\n // Track all item flow results to aggregate costs\n const itemFlowResults: FlowResult<unknown>[] = [];\n\n // Execute item flow for each item in parallel\n const results = await Promise.allSettled(\n items.map(async (item, index) => {\n // Build item flow with observability options\n const flow = buildFlowFromConfig(\n itemFlowDef,\n providers,\n flows,\n ctx?.observability?.config ? {\n observability: ctx.observability.config,\n metadata: {\n ...ctx.observability?.metadata,\n parentNode: stepId,\n phase: 'forEach',\n itemIndex: index,\n totalItems: items!.length\n }\n } : undefined\n );\n\n // Execute item flow\n // Pass the split document's input field (which contains url/base64/pages/bounds)\n const itemT0 = Date.now();\n const resultRaw = await flow.run(item.input);\n\n // Type guard to ensure we have a single flow result\n if (!isSingleFlowResult(resultRaw)) {\n throw new Error('Item flow returned batch result instead of single result');\n }\n const result = resultRaw;\n\n // Store result for cost aggregation\n itemFlowResults.push(result);\n\n // Merge item flow metrics\n if (ctx?.metrics && result.metrics) {\n const itemMetrics = flattenMetrics(\n result.metrics,\n `${stepId}.item[${index}]`\n );\n itemMetrics.forEach(m => ctx.metrics.push(m));\n }\n\n return result.output;\n })\n );\n\n // === PHASE 3: AGGREGATE ===\n // Count successes and failures\n const successCount = results.filter(r => r.status === 'fulfilled').length;\n const failureCount = results.filter(r => r.status === 'rejected').length;\n\n // Calculate aggregate cost from split + all item flows\n const splitCost = splitCostTracker.reduce((sum: number, m: StepMetric) => sum + (m.costUSD ?? 0), 0);\n const itemsCost = itemFlowResults.reduce((sum: number, result: FlowResult<unknown>) => {\n const itemCost = result.metrics\n ? result.metrics.reduce((s: number, m: StepMetric) => s + (m.costUSD ?? 0), 0)\n : 0;\n return sum + itemCost;\n }, 0);\n const aggregateCost = splitCost + itemsCost;\n\n // Calculate duration breakdown\n const totalMs = Date.now() - t0;\n const splitMs = splitCostTracker.reduce((sum: number, m: StepMetric) => sum + (m.ms ?? 0), 0);\n const itemsMs = itemFlowResults.reduce((sum: number, result: FlowResult<unknown>) => {\n const itemMs = result.metrics\n ? result.metrics.reduce((s: number, m: StepMetric) => s + (m.ms ?? 0), 0)\n : 0;\n return sum + itemMs;\n }, 0);\n const overheadMs = totalMs - splitMs - itemsMs; // Pure wrapper overhead\n\n // Store results in artifacts\n if (ctx?.emit) {\n ctx.emit(`${stepId}:results`, results);\n ctx.emit(`${stepId}:successCount`, successCount);\n ctx.emit(`${stepId}:failureCount`, failureCount);\n }\n\n // Add composite node overhead metric\n if (ctx?.metrics) {\n const provider = providers[splitConfig.providerRef];\n const { provider: providerName, model } = parseProviderName(provider.name ?? '');\n\n // Extract schemaId and schemaVersion from schemaRef if present\n const schemaRefData = parseRef(splitConfig.schemaRef);\n\n ctx.metrics.push({\n step: stepId,\n configStepId: ctx.stepId,\n startMs: t0,\n provider: providerName,\n model,\n ms: totalMs,\n costUSD: aggregateCost, // Total cost from split + all items\n attemptNumber: 1, // Composite wrappers don't retry, always 1\n metadata: {\n kind: 'wrapper', // Distinguish wrapper from leaf metrics\n type: 'forEach',\n rollup: true, // Duration includes child work\n overheadMs, // Pure wrapper overhead (flow orchestration)\n itemCount: items.length,\n successCount,\n failureCount,\n itemFlowId: typeof itemFlow === 'object' && 'flowRef' in itemFlow\n ? (itemFlow as FlowReference).flowRef\n : 'inline',\n // Include schema metadata if available\n ...(schemaRefData && {\n schemaId: schemaRefData.id,\n ...(schemaRefData.version && { schemaVersion: schemaRefData.version })\n })\n }\n });\n }\n\n // Return results in forEach format (matching runtime API)\n return results;\n\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n const isNestedFlowError = err instanceof FlowExecutionError;\n\n // Add error metric\n if (ctx?.metrics) {\n ctx.metrics.push({\n step: stepId,\n configStepId: ctx.stepId,\n startMs: t0,\n ms: Date.now() - t0,\n costUSD: 0,\n attemptNumber: 1,\n // @ts-ignore - Add error field\n error: err.message,\n metadata: {\n kind: 'wrapper',\n type: 'forEach',\n failed: true,\n itemCount: items?.length,\n failedPhase: phase\n }\n });\n }\n\n // Build flow path with forEach context\n const flowPath: FlowStepLocation[] = [{\n stepId,\n stepIndex: 0,\n stepType: 'forEach'\n }];\n\n // If inner error is FlowExecutionError, extend its path\n if (isNestedFlowError && err.flowPath) {\n flowPath.push(...err.flowPath);\n }\n\n // Get the root cause message for cleaner error display\n const rootCauseMessage = isNestedFlowError\n ? err.getRootCause().message\n : err.message;\n\n // Throw FlowExecutionError with full context\n throw new FlowExecutionError(\n `ForEach step \"${stepId}\" failed` +\n `${items ? ` (itemCount: ${items.length})` : ''}` +\n ` in phase: ${phase}` +\n `\\n Error: ${rootCauseMessage}`,\n stepId,\n 0,\n 'forEach',\n [],\n isNestedFlowError ? err.originalError : err,\n undefined,\n flowPath,\n isNestedFlowError ? err.allCompletedSteps : undefined\n );\n }\n }\n };\n}\n\n/**\n * Helper function to resolve flow references\n *\n * Resolves flow references from the registry (database-driven flows).\n * The registry contains SerializableFlow objects, not flow builder functions.\n */\nfunction resolveBranchFlow(\n flowOrRef: SerializableFlow | FlowReference,\n flows: FlowRegistry\n): SerializableFlow {\n // Check if it's a flow reference\n if (typeof flowOrRef === 'object' && flowOrRef !== null && 'flowRef' in flowOrRef) {\n const flowRef = (flowOrRef as FlowReference).flowRef;\n\n if (!flows[flowRef]) {\n throw new Error(\n `Flow reference \"${flowRef}\" not found in registry. ` +\n `Available flows: ${Object.keys(flows).join(', ')}`\n );\n }\n\n // Return the serializable flow directly from registry\n // (flows are already SerializableFlow objects from database/Convex)\n return flows[flowRef];\n }\n\n // It's an inline flow, return as-is\n return flowOrRef as SerializableFlow;\n}\n\n/**\n * Configuration for route composite node\n */\nexport interface RouteCompositeConfig {\n stepId: string;\n routeConfig: RouteConfig;\n branches: Record<string, SerializableFlow | FlowReference>;\n others?: SerializableFlow | FlowReference;\n providers: ProviderRegistry;\n flows: FlowRegistry;\n}\n\n/**\n * Match a MIME type against a pattern\n * Supports exact match and glob patterns (e.g., 'image/*')\n */\nfunction matchesMimePattern(mimeType: string, pattern: string): boolean {\n if (pattern === mimeType) return true;\n\n // Handle glob patterns like 'image/*' or 'application/*'\n if (pattern.endsWith('/*')) {\n const prefix = pattern.slice(0, -2); // Remove '/*'\n return mimeType.startsWith(prefix + '/');\n }\n\n return false;\n}\n\n/**\n * Find matching branch for a MIME type\n * Returns the first branch name that matches, or undefined if none match\n */\nfunction findMatchingBranch(\n mimeType: string,\n branches: Record<string, RouteBranchConfig>\n): string | undefined {\n for (const [branchName, config] of Object.entries(branches)) {\n for (const pattern of config.mimeTypes) {\n if (matchesMimePattern(mimeType, pattern)) {\n return branchName;\n }\n }\n }\n return undefined;\n}\n\n/**\n * Extract base64 data from a data URI or return as-is if already raw base64\n */\nfunction extractBase64Data(input: string): string {\n if (input.startsWith('data:')) {\n const commaIndex = input.indexOf(',');\n if (commaIndex !== -1) {\n return input.substring(commaIndex + 1);\n }\n }\n return input;\n}\n\n/**\n * Creates a composite node that:\n * 1. Detects MIME type from input (base64 or URL)\n * 2. Routes to appropriate branch based on MIME type\n * 3. Returns the branch flow's output\n *\n * No provider required - uses deterministic MIME detection from magic bytes.\n */\nexport function createRouteCompositeNode(\n config: RouteCompositeConfig\n): NodeDef<FlowInput, unknown> {\n const { stepId, routeConfig, branches, others, providers, flows } = config;\n\n return {\n key: 'route-composite',\n run: async (input: FlowInput, ctx?: NodeCtx) => {\n const t0 = Date.now();\n let detectedMimeType: string | undefined;\n let selectedBranch: string | undefined;\n let phase: 'detect' | 'route' | 'branch' = 'detect';\n\n try {\n // === PHASE 1: DETECT MIME TYPE ===\n let base64Data: string | undefined;\n\n if (input.base64) {\n base64Data = extractBase64Data(input.base64);\n } else if (input.url) {\n // For URL inputs, we need to fetch the content first to detect MIME type\n // This is a read-only fetch operation\n const response = await fetch(input.url);\n if (!response.ok) {\n throw new Error(`Failed to fetch URL: ${response.status} ${response.statusText}`);\n }\n const arrayBuffer = await response.arrayBuffer();\n const bytes = new Uint8Array(arrayBuffer);\n // Convert to base64 for MIME detection\n let binary = '';\n for (let i = 0; i < bytes.byteLength; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n base64Data = btoa(binary);\n } else {\n throw new Error(\n 'Route node requires either url or base64 input for MIME detection'\n );\n }\n\n // Detect MIME type from actual file content (magic bytes)\n try {\n detectedMimeType = await detectMimeTypeFromBase64Async(base64Data);\n } catch {\n // Fallback to sync detection if async fails\n try {\n detectedMimeType = detectMimeTypeFromBase64(base64Data);\n } catch (syncErr) {\n throw new Error(\n `Unable to detect MIME type from input. ` +\n `Ensure the document is a supported format. ` +\n `Error: ${syncErr instanceof Error ? syncErr.message : String(syncErr)}`\n );\n }\n }\n\n // Emit detection result\n if (ctx?.emit) {\n ctx.emit(`${stepId}:detectedMimeType`, detectedMimeType);\n }\n\n // === PHASE 2: ROUTE TO BRANCH ===\n phase = 'route';\n\n selectedBranch = findMatchingBranch(detectedMimeType, routeConfig.branches);\n\n // Check for 'others' fallback\n if (!selectedBranch && others) {\n selectedBranch = 'others';\n }\n\n // Check for no match\n if (!selectedBranch) {\n const availableBranches = Object.entries(routeConfig.branches)\n .map(([name, cfg]) => `${name}: [${cfg.mimeTypes.join(', ')}]`)\n .join('; ');\n throw new Error(\n `No branch matches MIME type \"${detectedMimeType}\". ` +\n `Available branches: ${availableBranches}. ` +\n `Add an 'others' fallback branch to handle unmatched types.`\n );\n }\n\n // Emit routing decision\n if (ctx?.emit) {\n ctx.emit(`${stepId}:selectedBranch`, selectedBranch);\n }\n\n // === PHASE 3: EXECUTE BRANCH ===\n phase = 'branch';\n\n // Get branch flow (handle 'others' separately)\n const branchFlowOrRef = selectedBranch === 'others'\n ? others\n : branches[selectedBranch];\n\n if (!branchFlowOrRef) {\n throw new Error(\n `Branch \"${selectedBranch}\" not found in route configuration`\n );\n }\n\n // Resolve flow reference\n const branchFlowDef = resolveBranchFlow(branchFlowOrRef, flows);\n\n // Build the branch flow with observability options\n const branchFlow = buildFlowFromConfig(\n branchFlowDef,\n providers,\n flows,\n ctx?.observability?.config ? {\n observability: ctx.observability.config,\n metadata: {\n ...ctx.observability?.metadata,\n parentNode: stepId,\n phase: 'branch',\n detectedMimeType,\n selectedBranch\n }\n } : undefined\n );\n\n // Execute branch flow\n const branchT0 = Date.now();\n const branchResultRaw = await branchFlow.run(input);\n\n // Type guard to ensure we have a single flow result\n if (!isSingleFlowResult(branchResultRaw)) {\n throw new Error('Branch flow returned batch result instead of single result');\n }\n const branchResult = branchResultRaw;\n\n // Merge branch flow metrics\n if (ctx?.metrics && branchResult.metrics) {\n const branchMetrics = flattenMetrics(\n branchResult.metrics,\n `${stepId}.branch.${selectedBranch}`\n );\n branchMetrics.forEach(m => ctx.metrics.push(m));\n }\n\n // Store branch output in artifacts\n if (ctx?.emit) {\n ctx.emit(`${stepId}:branchOutput`, branchResult.output);\n ctx.emit(`${stepId}:branchArtifacts`, branchResult.artifacts);\n }\n\n // === PHASE 4: COMPLETE ===\n // Calculate aggregate cost from branch operations (no provider cost for MIME detection)\n const branchCost = branchResult.metrics\n ? branchResult.metrics.reduce((sum: number, m: StepMetric) => sum + (m.costUSD ?? 0), 0)\n : 0;\n\n // Calculate duration breakdown\n const totalMs = Date.now() - t0;\n const branchMs = branchResult.metrics\n ? branchResult.metrics.reduce((sum: number, m: StepMetric) => sum + (m.ms ?? 0), 0)\n : 0;\n const overheadMs = totalMs - branchMs; // Pure wrapper overhead (MIME detection + routing)\n\n // Add composite node wrapper metric\n if (ctx?.metrics) {\n const wrapperMetric: StepMetric = {\n step: stepId,\n configStepId: ctx.stepId,\n startMs: t0,\n provider: 'internal', // No external provider - uses built-in MIME detection\n model: 'mime-detection',\n ms: totalMs,\n costUSD: branchCost, // Total cost from branch (MIME detection is free)\n attemptNumber: 1, // Composite wrappers don't retry, always 1\n metadata: {\n kind: 'wrapper', // Distinguish wrapper from leaf metrics\n type: 'route',\n rollup: true, // Duration includes child work\n overheadMs, // Pure wrapper overhead (MIME detection + routing)\n detectedMimeType,\n selectedBranch,\n branchStepCount: branchResult.metrics?.length || 0,\n branchFlowId: selectedBranch === 'others'\n ? (others && typeof others === 'object' && 'flowRef' in others\n ? (others as FlowReference).flowRef\n : 'inline')\n : (typeof branches[selectedBranch] === 'object' && 'flowRef' in branches[selectedBranch]\n ? (branches[selectedBranch] as FlowReference).flowRef\n : 'inline')\n }\n };\n\n ctx.metrics.push(wrapperMetric);\n }\n\n // Return branch output (transparent to next step)\n return branchResult.output;\n\n } catch (error) {\n const err = error instanceof Error ? error : new Error(String(error));\n const isNestedFlowError = err instanceof FlowExecutionError;\n\n // Add error metric\n if (ctx?.metrics) {\n ctx.metrics.push({\n step: stepId,\n configStepId: ctx.stepId,\n startMs: t0,\n ms: Date.now() - t0,\n costUSD: 0,\n attemptNumber: 1,\n // @ts-ignore - Add error field\n error: err.message,\n metadata: {\n kind: 'wrapper',\n type: 'route',\n failed: true,\n detectedMimeType,\n selectedBranch,\n failedPhase: phase\n }\n });\n }\n\n // Build flow path with route context\n const flowPath: FlowStepLocation[] = [{\n stepId,\n stepIndex: 0,\n stepType: 'route',\n branch: selectedBranch || undefined\n }];\n\n // If inner error is FlowExecutionError, extend its path\n if (isNestedFlowError && err.flowPath) {\n flowPath.push(...err.flowPath);\n }\n\n // Get the root cause message for cleaner error display\n const rootCauseMessage = isNestedFlowError\n ? err.getRootCause().message\n : err.message;\n\n // Throw FlowExecutionError with full context\n throw new FlowExecutionError(\n `Route step \"${stepId}\" failed` +\n `${detectedMimeType ? ` (mimeType: ${detectedMimeType})` : ''}` +\n `${selectedBranch ? ` (branch: ${selectedBranch})` : ''}` +\n ` in phase: ${phase}` +\n `\\n Error: ${rootCauseMessage}`,\n stepId,\n 0,\n 'route',\n [],\n isNestedFlowError ? err.originalError : err,\n undefined,\n flowPath,\n isNestedFlowError ? err.allCompletedSteps : undefined\n );\n }\n }\n };\n}\n","/**\n * Flow Validation\n *\n * Provides validation for flow configurations before execution.\n */\n\nimport type { JSONSchemaNode } from '@doclo/core';\nimport type {\n SerializableFlow,\n NodeConfig,\n SerializableConditionalStep,\n SerializableForEachStep,\n SerializableRouteStep,\n ExtractConfig,\n SplitConfig,\n CategorizeConfig,\n TriggerConfig,\n OutputConfig,\n RouteConfig,\n FlowReference\n} from './serialization.js';\nimport { isDebugValidation } from '@doclo/core/runtime/env';\n\n/**\n * Validate JSON Schema structure (Edge Runtime compatible)\n *\n * This is a lightweight validator that checks basic JSON Schema structure\n * without using AJV's code generation (which breaks Edge Runtime).\n *\n * @param schema - JSON Schema object to validate\n * @param depth - Current recursion depth (internal parameter)\n * @returns Error message if invalid, null if valid\n */\nfunction validateJSONSchemaStructure(schema: unknown, depth: number = 0): string | null {\n const MAX_DEPTH = 50; // Prevent DoS via deeply nested schemas\n\n // Check recursion depth to prevent DoS attacks\n if (depth > MAX_DEPTH) {\n return `Schema nesting depth exceeds maximum (${MAX_DEPTH})`;\n }\n\n if (!schema || typeof schema !== 'object' || Array.isArray(schema)) {\n return 'Schema must be an object';\n }\n\n // Type narrowed schema as Record for property access\n const schemaObj = schema as Record<string, unknown>;\n\n // Check for basic JSON Schema properties\n if (!schemaObj.type || typeof schemaObj.type !== 'string') {\n return 'Schema missing \"type\" property';\n }\n\n const validTypes = ['object', 'array', 'string', 'number', 'integer', 'boolean', 'null'];\n if (!validTypes.includes(schemaObj.type)) {\n return `Invalid schema type: \"${schemaObj.type}\". Must be one of: ${validTypes.join(', ')}`;\n }\n\n // Validate object schemas\n if (schemaObj.type === 'object') {\n if (schemaObj.properties && typeof schemaObj.properties !== 'object') {\n return 'Schema properties must be an object';\n }\n\n if (schemaObj.required && !Array.isArray(schemaObj.required)) {\n return 'Schema required must be an array';\n }\n\n // Recursively validate nested properties\n if (schemaObj.properties && typeof schemaObj.properties === 'object' && !Array.isArray(schemaObj.properties)) {\n const properties = schemaObj.properties as Record<string, unknown>;\n for (const [propName, propSchema] of Object.entries(properties)) {\n const propError = validateJSONSchemaStructure(propSchema, depth + 1);\n if (propError) {\n return `Invalid schema for property \"${propName}\": ${propError}`;\n }\n }\n }\n }\n\n // Validate array schemas\n if (schemaObj.type === 'array') {\n if (!schemaObj.items) {\n return 'Array schema missing \"items\" property';\n }\n\n const itemsError = validateJSONSchemaStructure(schemaObj.items, depth + 1);\n if (itemsError) {\n return `Invalid array items schema: ${itemsError}`;\n }\n }\n\n return null;\n}\n\n/**\n * Calculate JSON nesting depth for a flow\n *\n * This calculates the actual JSON nesting depth when the flow is serialized,\n * which is important for Convex and other databases with nesting limits.\n *\n * Each logical nesting level adds multiple JSON levels:\n * - Conditional step: +5 levels (branches → category → flow → steps → step)\n * - ForEach step: +4 levels (itemFlow → flow → steps → step)\n * - Standard step with schema: +4 levels (config → schema → properties → field)\n *\n * @param flow - Flow definition to analyze\n * @param currentDepth - Current depth (used for recursion)\n * @returns Maximum JSON nesting depth\n */\nfunction calculateFlowNestingDepth(flow: SerializableFlow, currentDepth: number = 1): number {\n // Start at depth 1 for the root flow object\n // +1 for steps array\n let maxDepth = currentDepth + 1;\n\n for (const step of flow.steps) {\n // +1 for step object itself\n let stepDepth = currentDepth + 2;\n\n if (step.type === 'conditional') {\n // Conditional: step → branches (obj) → category → flow/flowRef\n // Type narrowing: step is SerializableConditionalStep\n const conditionalStep = step as SerializableConditionalStep;\n if (conditionalStep.branches) {\n for (const branchFlowOrRef of Object.values(conditionalStep.branches)) {\n // Check if it's a flow reference\n if ('flowRef' in branchFlowOrRef) {\n // Flow reference: branches (+1) → category (+1) → flowRef object (+1) = +3 from step\n // This is much shallower than inline flows!\n maxDepth = Math.max(maxDepth, stepDepth + 3);\n } else {\n // Inline flow: branches (+1) → category (+1) → flow → steps → nested step = +5+ levels\n const branchDepth = calculateFlowNestingDepth(branchFlowOrRef, stepDepth + 2);\n maxDepth = Math.max(maxDepth, branchDepth);\n }\n }\n }\n } else if (step.type === 'route') {\n // Route: step → branches (obj) → branchName → flow/flowRef\n // Type narrowing: step is SerializableRouteStep\n const routeStep = step as SerializableRouteStep;\n if (routeStep.branches) {\n for (const branchFlowOrRef of Object.values(routeStep.branches)) {\n if ('flowRef' in branchFlowOrRef) {\n maxDepth = Math.max(maxDepth, stepDepth + 3);\n } else {\n const branchDepth = calculateFlowNestingDepth(branchFlowOrRef, stepDepth + 2);\n maxDepth = Math.max(maxDepth, branchDepth);\n }\n }\n }\n // Also check 'others' branch\n if (routeStep.others) {\n if ('flowRef' in routeStep.others) {\n maxDepth = Math.max(maxDepth, stepDepth + 3);\n } else {\n const othersDepth = calculateFlowNestingDepth(routeStep.others, stepDepth + 2);\n maxDepth = Math.max(maxDepth, othersDepth);\n }\n }\n } else if (step.type === 'forEach') {\n // ForEach: step → itemFlow (obj or ref)\n // Type narrowing: step is SerializableForEachStep\n const forEachStep = step as SerializableForEachStep;\n if (forEachStep.itemFlow) {\n const itemFlowOrRef = forEachStep.itemFlow;\n\n // Check if it's a flow reference\n if ('flowRef' in itemFlowOrRef) {\n // Flow reference: itemFlow (+1) → flowRef object (+1) = +2 from step\n maxDepth = Math.max(maxDepth, stepDepth + 2);\n } else {\n // Inline flow: itemFlow (+1) → flow → steps → nested step = +4+ levels\n const itemDepth = calculateFlowNestingDepth(itemFlowOrRef, stepDepth + 1);\n maxDepth = Math.max(maxDepth, itemDepth);\n }\n }\n } else {\n // Standard step: check for schema depth\n const config = step.config;\n\n // config object (+1)\n let configDepth = stepDepth + 1;\n\n // If has schema: schema (+1) → properties (+1) → field (+1) → type/items (+1)\n // That's +4 levels for a typical schema\n if ('schema' in config && config.schema) {\n configDepth += 4; // Typical schema nesting\n }\n\n // If has schemas (for split): similar depth\n if ('schemas' in config && config.schemas) {\n configDepth += 4;\n }\n\n maxDepth = Math.max(maxDepth, configDepth);\n }\n }\n\n return maxDepth;\n}\n\n/**\n * Validation result\n */\nexport type ValidationResult = {\n valid: boolean;\n errors: ValidationError[];\n warnings: ValidationWarning[];\n};\n\n/**\n * Validation error\n */\nexport type ValidationError = {\n type: 'missing_provider' | 'invalid_schema' | 'invalid_config' | 'version_mismatch';\n stepId?: string;\n message: string;\n details?: Record<string, unknown>;\n};\n\n/**\n * Validation warning\n */\nexport type ValidationWarning = {\n type: 'deprecated' | 'performance' | 'best_practice';\n stepId?: string;\n message: string;\n details?: Record<string, unknown>;\n};\n\n/**\n * Provider instance used for validation (minimal interface)\n */\ninterface ValidationProviderInstance {\n name?: string;\n // Providers can have additional properties\n [key: string]: unknown;\n}\n\n/**\n * Validation options\n */\nexport type ValidationOptions = {\n checkProviders?: boolean; // Check if providers exist in registry\n checkSchemas?: boolean; // Validate JSON schemas\n checkVersion?: boolean; // Check flow version compatibility\n providers?: Record<string, ValidationProviderInstance>; // Provider registry for validation\n};\n\n/**\n * Validate a serializable flow definition\n *\n * @param flowDef - Flow definition to validate\n * @param options - Validation options\n * @returns Validation result with errors and warnings\n *\n * @example\n * ```typescript\n * const result = validateFlow(flowDef, {\n * checkProviders: true,\n * checkSchemas: true,\n * providers: { ocr: suryaProvider, llm: geminiProvider }\n * });\n *\n * if (!result.valid) {\n * console.error('Flow validation failed:', result.errors);\n * }\n * ```\n */\nexport function validateFlow(\n flowDef: SerializableFlow,\n options: ValidationOptions = {}\n): ValidationResult {\n const errors: ValidationError[] = [];\n const warnings: ValidationWarning[] = [];\n\n // Default options\n const opts = {\n checkProviders: true,\n checkSchemas: true,\n checkVersion: true,\n ...options\n };\n\n // Validate version\n if (opts.checkVersion) {\n if (!flowDef.version) {\n errors.push({\n type: 'version_mismatch',\n message: 'Flow definition missing version field'\n });\n } else if (flowDef.version !== '1.0.0') {\n errors.push({\n type: 'version_mismatch',\n message: `Unsupported flow version: ${flowDef.version}. Expected: 1.0.0`,\n details: { version: flowDef.version }\n });\n }\n }\n\n // Validate steps\n if (!flowDef.steps || !Array.isArray(flowDef.steps)) {\n errors.push({\n type: 'invalid_config',\n message: 'Flow definition missing or invalid steps array'\n });\n return { valid: false, errors, warnings };\n }\n\n if (flowDef.steps.length === 0) {\n warnings.push({\n type: 'best_practice',\n message: 'Flow has no steps defined'\n });\n }\n\n // Check nesting depth to prevent Convex 16-level limit issues\n const nestingDepth = calculateFlowNestingDepth(flowDef);\n if (nestingDepth > 14) {\n errors.push({\n type: 'invalid_config',\n message: `Flow nesting depth (${nestingDepth} levels) exceeds recommended maximum (14 levels). This will cause issues with Convex and other databases with 16-level JSON nesting limits. Consider using flow references (flowRef) to reduce nesting depth.`,\n details: { nestingDepth, limit: 14 }\n });\n } else if (nestingDepth > 12) {\n warnings.push({\n type: 'performance',\n message: `Flow nesting depth (${nestingDepth} levels) is approaching the database limit (16 levels). Consider using flow references to reduce complexity.`,\n details: { nestingDepth, warningThreshold: 12 }\n });\n }\n\n // Validate each step\n for (const step of flowDef.steps) {\n const stepId = step.id || 'unknown';\n\n // Validate step type\n if (!step.type) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Step missing type field'\n });\n continue;\n }\n\n // Validate conditional and forEach specific fields\n if (step.type === 'conditional') {\n const conditionalStep = step as SerializableConditionalStep;\n if (!conditionalStep.branches || typeof conditionalStep.branches !== 'object') {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Conditional step missing or invalid branches field'\n });\n } else {\n // Recursively validate each branch flow (or flow reference)\n for (const [category, branchFlowOrRef] of Object.entries(conditionalStep.branches)) {\n // Check if it's a flow reference\n if ('flowRef' in branchFlowOrRef) {\n // Validate flowRef format\n const flowRef = (branchFlowOrRef as FlowReference).flowRef;\n if (typeof flowRef !== 'string' || flowRef.trim() === '') {\n errors.push({\n type: 'invalid_config',\n stepId: `${stepId}.${category}`,\n message: `Branch \"${category}\": flowRef must be a non-empty string`\n });\n }\n // Note: We don't resolve and validate referenced flows here to avoid circular dependencies\n // The flow registry should be validated separately if needed\n } else {\n // Inline flow - validate recursively\n const branchResult = validateFlow(branchFlowOrRef as SerializableFlow, options);\n for (const error of branchResult.errors) {\n errors.push({\n ...error,\n stepId: `${stepId}.${category}`,\n message: `Branch \"${category}\": ${error.message}`\n });\n }\n for (const warning of branchResult.warnings) {\n warnings.push({\n ...warning,\n stepId: `${stepId}.${category}`,\n message: `Branch \"${category}\": ${warning.message}`\n });\n }\n }\n }\n }\n } else if (step.type === 'forEach') {\n const forEachStep = step as SerializableForEachStep;\n if (!forEachStep.itemFlow) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'ForEach step missing itemFlow field'\n });\n } else {\n const itemFlowOrRef = forEachStep.itemFlow;\n\n // Check if it's a flow reference\n if ('flowRef' in itemFlowOrRef) {\n // Validate flowRef format\n const flowRef = (itemFlowOrRef as FlowReference).flowRef;\n if (typeof flowRef !== 'string' || flowRef.trim() === '') {\n errors.push({\n type: 'invalid_config',\n stepId: `${stepId}.itemFlow`,\n message: `itemFlow: flowRef must be a non-empty string`\n });\n }\n // Note: We don't resolve and validate referenced flows here to avoid circular dependencies\n } else {\n // Inline flow - recursively validate item flow\n const itemResult = validateFlow(itemFlowOrRef as SerializableFlow, options);\n for (const error of itemResult.errors) {\n errors.push({\n ...error,\n stepId: `${stepId}.itemFlow`,\n message: `Item flow: ${error.message}`\n });\n }\n for (const warning of itemResult.warnings) {\n warnings.push({\n ...warning,\n stepId: `${stepId}.itemFlow`,\n message: `Item flow: ${warning.message}`\n });\n }\n }\n }\n } else if (step.type === 'route') {\n const routeStep = step as SerializableRouteStep;\n\n // Validate branches exist\n if (!routeStep.branches || typeof routeStep.branches !== 'object') {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Route step missing or invalid branches field'\n });\n } else if (Object.keys(routeStep.branches).length === 0) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Route step must have at least one branch'\n });\n }\n\n // Validate config.branches match step.branches\n if (routeStep.config?.branches && routeStep.branches) {\n for (const branchName of Object.keys(routeStep.config.branches)) {\n if (!routeStep.branches[branchName]) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: `Branch \"${branchName}\" defined in config but missing flow definition`\n });\n }\n }\n\n // Validate MIME type patterns\n for (const [branchName, branchConfig] of Object.entries(routeStep.config.branches)) {\n if (!branchConfig.mimeTypes || branchConfig.mimeTypes.length === 0) {\n errors.push({\n type: 'invalid_config',\n stepId: `${stepId}.${branchName}`,\n message: `Branch \"${branchName}\" has no MIME types defined`\n });\n } else {\n // Validate MIME type format\n for (const mimeType of branchConfig.mimeTypes) {\n // MIME types should contain '/' or be a glob pattern ending with '/*'\n if (!mimeType.includes('/')) {\n errors.push({\n type: 'invalid_config',\n stepId: `${stepId}.${branchName}`,\n message: `Invalid MIME type pattern: \"${mimeType}\". Expected format: \"type/subtype\" or \"type/*\"`\n });\n }\n }\n }\n }\n }\n\n // Recursively validate each branch flow\n if (routeStep.branches) {\n for (const [branchName, branchFlowOrRef] of Object.entries(routeStep.branches)) {\n if ('flowRef' in branchFlowOrRef) {\n // Validate flowRef format\n const flowRef = (branchFlowOrRef as FlowReference).flowRef;\n if (typeof flowRef !== 'string' || flowRef.trim() === '') {\n errors.push({\n type: 'invalid_config',\n stepId: `${stepId}.${branchName}`,\n message: `Branch \"${branchName}\": flowRef must be a non-empty string`\n });\n }\n } else {\n // Inline flow - validate recursively\n const branchResult = validateFlow(branchFlowOrRef as SerializableFlow, options);\n for (const error of branchResult.errors) {\n errors.push({\n ...error,\n stepId: `${stepId}.${branchName}`,\n message: `Branch \"${branchName}\": ${error.message}`\n });\n }\n for (const warning of branchResult.warnings) {\n warnings.push({\n ...warning,\n stepId: `${stepId}.${branchName}`,\n message: `Branch \"${branchName}\": ${warning.message}`\n });\n }\n }\n }\n }\n\n // Validate others branch if present\n if (routeStep.others) {\n if ('flowRef' in routeStep.others) {\n const flowRef = (routeStep.others as FlowReference).flowRef;\n if (typeof flowRef !== 'string' || flowRef.trim() === '') {\n errors.push({\n type: 'invalid_config',\n stepId: `${stepId}.others`,\n message: 'Others branch flowRef must be a non-empty string'\n });\n }\n } else {\n const othersResult = validateFlow(routeStep.others as SerializableFlow, options);\n for (const error of othersResult.errors) {\n errors.push({\n ...error,\n stepId: `${stepId}.others`,\n message: `Others branch: ${error.message}`\n });\n }\n for (const warning of othersResult.warnings) {\n warnings.push({\n ...warning,\n stepId: `${stepId}.others`,\n message: `Others branch: ${warning.message}`\n });\n }\n }\n }\n }\n\n // Validate node type\n const validNodeTypes = ['parse', 'extract', 'split', 'categorize', 'trigger', 'output', 'route'];\n if (!step.nodeType || !validNodeTypes.includes(step.nodeType)) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: `Invalid node type: ${step.nodeType}. Must be one of: ${validNodeTypes.join(', ')}`,\n details: { nodeType: step.nodeType }\n });\n continue;\n }\n\n // Validate config exists\n if (!step.config) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Step missing config field'\n });\n continue;\n }\n\n const config = step.config as NodeConfig;\n\n // Helper to check if config has providerRef (for configs that need it)\n const hasProviderRef = (cfg: NodeConfig): cfg is NodeConfig & { providerRef: string } => {\n return 'providerRef' in cfg && typeof cfg.providerRef === 'string';\n };\n\n // Validate provider reference (not applicable for trigger, output, and route nodes)\n if (step.nodeType !== 'trigger' && step.nodeType !== 'output' && step.nodeType !== 'route') {\n if (!hasProviderRef(config)) {\n errors.push({\n type: 'missing_provider',\n stepId,\n message: 'Step config missing providerRef'\n });\n } else if (opts.checkProviders && opts.providers) {\n if (!opts.providers[config.providerRef]) {\n errors.push({\n type: 'missing_provider',\n stepId,\n message: `Provider \"${config.providerRef}\" not found in registry`,\n details: {\n providerRef: config.providerRef,\n availableProviders: Object.keys(opts.providers)\n }\n });\n }\n }\n }\n\n // Validate node-specific config\n if (opts.checkSchemas) {\n switch (step.nodeType) {\n case 'extract': {\n const cfg = config as ExtractConfig;\n if (!cfg.schema) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Extract node missing schema'\n });\n } else {\n // Validate JSON schema structure\n const schemaError = validateJSONSchemaStructure(cfg.schema);\n if (schemaError) {\n errors.push({\n type: 'invalid_schema',\n stepId,\n message: `Invalid JSON schema: ${schemaError}`,\n details: { schema: cfg.schema as Record<string, unknown> }\n });\n }\n }\n\n // Check reasoning config if present\n if (cfg.reasoning) {\n if (cfg.reasoning.effort && !['low', 'medium', 'high'].includes(cfg.reasoning.effort)) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: `Invalid reasoning effort: ${cfg.reasoning.effort}. Must be: low, medium, or high`\n });\n }\n }\n break;\n }\n\n case 'split': {\n const cfg = config as SplitConfig;\n const hasCategories = cfg.categories && Array.isArray(cfg.categories);\n const hasSchemas = cfg.schemas && typeof cfg.schemas === 'object';\n const hasSchemaRef = cfg.schemaRef && typeof cfg.schemaRef === 'string';\n\n // Must have at least one: categories, schemas, or schemaRef\n if (!hasCategories && !hasSchemas && !hasSchemaRef) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Split node requires either categories, schemas, or schemaRef'\n });\n }\n\n // Cannot have both categories and schemas\n if (hasCategories && hasSchemas) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Split node cannot have both categories and schemas. Use categories (recommended) or schemas, not both.'\n });\n }\n\n // Validate categories if provided\n if (hasCategories) {\n if (cfg.categories!.length === 0) {\n warnings.push({\n type: 'best_practice',\n stepId,\n message: 'Split node has no categories defined'\n });\n } else {\n // Validate each category is either a string or { name: string; description?: string }\n for (let i = 0; i < cfg.categories!.length; i++) {\n const cat = cfg.categories![i];\n if (typeof cat !== 'string' && (cat === null || typeof cat !== 'object' || !cat.name)) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: `Split node category at index ${i} must be a string or an object with a 'name' property`\n });\n }\n }\n }\n }\n\n // Validate schemas if provided (legacy path)\n if (hasSchemas && !hasCategories) {\n for (const [schemaName, schema] of Object.entries(cfg.schemas!)) {\n const schemaError = validateJSONSchemaStructure(schema);\n if (schemaError) {\n errors.push({\n type: 'invalid_schema',\n stepId,\n message: `Invalid JSON schema for \"${schemaName}\": ${schemaError}`,\n details: { schemaName, schema: schema as Record<string, unknown> }\n });\n }\n }\n\n if (Object.keys(cfg.schemas!).length === 0) {\n warnings.push({\n type: 'best_practice',\n stepId,\n message: 'Split node has no schemas defined'\n });\n }\n }\n break;\n }\n\n case 'categorize': {\n const cfg = config as CategorizeConfig;\n if (!cfg.categories) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Categorize node missing categories'\n });\n } else if (!Array.isArray(cfg.categories)) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Categorize node categories must be an array'\n });\n } else if (cfg.categories.length === 0) {\n warnings.push({\n type: 'best_practice',\n stepId,\n message: 'Categorize node has no categories defined'\n });\n }\n break;\n }\n\n case 'trigger': {\n const cfg = config as TriggerConfig;\n\n // Validate flowRef is present\n if (!cfg.flowRef) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Trigger node missing flowRef'\n });\n }\n\n // Validate providerOverrides if present\n if (cfg.providerOverrides) {\n if (typeof cfg.providerOverrides !== 'object') {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Trigger node providerOverrides must be an object'\n });\n } else if (opts.checkProviders && opts.providers) {\n // Validate that override refs exist in provider registry\n for (const [childRef, parentRef] of Object.entries(cfg.providerOverrides)) {\n if (!opts.providers[parentRef]) {\n errors.push({\n type: 'missing_provider',\n stepId,\n message: `Provider override \"${parentRef}\" not found in registry`,\n details: {\n childRef,\n parentRef,\n availableProviders: Object.keys(opts.providers)\n }\n });\n }\n }\n }\n }\n\n // Validate inputMapping if present\n if (cfg.inputMapping) {\n if (!cfg.inputMapping.type) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Trigger node inputMapping missing type field'\n });\n } else {\n const validMappingTypes = ['passthrough', 'unwrap', 'artifact', 'merge', 'construct'];\n if (!validMappingTypes.includes(cfg.inputMapping.type)) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: `Invalid inputMapping type: ${cfg.inputMapping.type}. Must be one of: ${validMappingTypes.join(', ')}`\n });\n }\n\n // Type-specific validation\n if (cfg.inputMapping.type === 'artifact' && !('path' in cfg.inputMapping)) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Trigger node inputMapping type \"artifact\" requires path field'\n });\n }\n if (cfg.inputMapping.type === 'merge' && !('artifactPath' in cfg.inputMapping)) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Trigger node inputMapping type \"merge\" requires artifactPath field'\n });\n }\n if (cfg.inputMapping.type === 'construct' && !('fields' in cfg.inputMapping)) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Trigger node inputMapping type \"construct\" requires fields object'\n });\n }\n }\n }\n\n // Validate timeout if present\n if (cfg.timeout !== undefined) {\n if (typeof cfg.timeout !== 'number' || cfg.timeout <= 0) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Trigger node timeout must be a positive number'\n });\n }\n }\n\n // Validate mergeMetrics if present\n if (cfg.mergeMetrics !== undefined && typeof cfg.mergeMetrics !== 'boolean') {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Trigger node mergeMetrics must be a boolean'\n });\n }\n\n break;\n }\n\n case 'output': {\n const cfg = config as OutputConfig;\n\n // Validate transform type if present\n if (cfg.transform) {\n const validTransforms = ['first', 'last', 'merge', 'pick'];\n if (!validTransforms.includes(cfg.transform)) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: `Invalid output transform: ${cfg.transform}. Must be one of: ${validTransforms.join(', ')}`\n });\n }\n\n // Validate that 'pick' transform has fields\n if (cfg.transform === 'pick' && (!cfg.fields || cfg.fields.length === 0)) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Output transform \"pick\" requires fields array'\n });\n }\n }\n\n // Validate fields if present\n if (cfg.fields && !Array.isArray(cfg.fields)) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Output fields must be an array'\n });\n }\n\n // Validate source if present\n if (cfg.source) {\n if (typeof cfg.source !== 'string' && !Array.isArray(cfg.source)) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Output source must be a string or array of strings'\n });\n } else if (Array.isArray(cfg.source) && cfg.source.length === 0) {\n warnings.push({\n type: 'best_practice',\n stepId,\n message: 'Output source array is empty'\n });\n }\n }\n\n break;\n }\n }\n\n // Validate consensus config if present\n if ('consensus' in config && config.consensus) {\n const consensus = config.consensus;\n\n if (!consensus.runs || consensus.runs < 1) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: 'Consensus runs must be >= 1'\n });\n }\n\n if (consensus.strategy && !['majority', 'unanimous'].includes(consensus.strategy)) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: `Invalid consensus strategy: ${consensus.strategy}. Must be: majority or unanimous`\n });\n }\n\n if (consensus.onTie && !['random', 'fail', 'retry'].includes(consensus.onTie)) {\n errors.push({\n type: 'invalid_config',\n stepId,\n message: `Invalid consensus onTie: ${consensus.onTie}. Must be: random, fail, or retry`\n });\n }\n\n if (consensus.runs > 1) {\n warnings.push({\n type: 'performance',\n stepId,\n message: `Consensus with ${consensus.runs} runs will execute the step ${consensus.runs} times`\n });\n }\n }\n }\n }\n\n return {\n valid: errors.length === 0,\n errors,\n warnings\n };\n}\n\n/**\n * Validate and throw if invalid\n *\n * @param flowDef - Flow definition to validate\n * @param options - Validation options\n * @throws ValidationError if flow is invalid\n */\nexport function validateFlowOrThrow(\n flowDef: SerializableFlow,\n options: ValidationOptions = {}\n): void {\n const result = validateFlow(flowDef, options);\n\n if (!result.valid) {\n const errorMessages = result.errors.map(e =>\n e.stepId ? `[${e.stepId}] ${e.message}` : e.message\n ).join('\\n');\n\n throw new Error(`Flow validation failed:\\n${errorMessages}`);\n }\n\n // Log warnings if present\n if (result.warnings.length > 0 && isDebugValidation()) {\n console.warn('[Flow Validation] Warnings:');\n for (const warning of result.warnings) {\n const prefix = warning.stepId ? `[${warning.stepId}]` : '';\n console.warn(` ${prefix} ${warning.message}`);\n }\n }\n}\n","import { runPipeline, type OCRProvider, type DocumentIR } from \"@doclo/core\";\nimport { parseNode, extractNode } from \"@doclo/nodes\";\nimport { simpleSchema } from \"./schemas\";\nimport { buildLLMProvider } from \"@doclo/providers-llm\";\n\n/**\n * Build a flow with automatic fallback between multiple LLM providers\n *\n * Example usage:\n * ```\n * const flow = buildMultiProviderFlow({\n * ocr: suryaProvider({ endpoint, apiKey }),\n * llmConfigs: [\n * { provider: 'openai', model: 'gpt-4.1', apiKey: process.env.OPENAI_KEY },\n * { provider: 'anthropic', model: 'claude-haiku-4.5', apiKey: process.env.ANTHROPIC_KEY, via: 'openrouter' },\n * { provider: 'google', model: 'gemini-2.5-flash', apiKey: process.env.GOOGLE_KEY }\n * ],\n * maxRetries: 2\n * });\n * ```\n */\nexport function buildMultiProviderFlow(opts: {\n ocr: OCRProvider;\n llmConfigs: Array<{\n provider: 'openai' | 'anthropic' | 'google' | 'xai';\n model: string;\n apiKey: string;\n via?: 'openrouter' | 'native';\n baseUrl?: string;\n }>;\n maxRetries?: number;\n retryDelay?: number;\n circuitBreakerThreshold?: number;\n}) {\n const parse = parseNode({ ocr: opts.ocr });\n\n // Build LLM provider with fallback support\n // buildLLMProvider returns CoreVLMProvider directly (no adapter needed)\n const coreLLMProvider = buildLLMProvider({\n providers: opts.llmConfigs,\n maxRetries: opts.maxRetries ?? 2,\n retryDelay: opts.retryDelay ?? 1000,\n useExponentialBackoff: true,\n circuitBreakerThreshold: opts.circuitBreakerThreshold ?? 3\n });\n\n const mkPrompt = (ir: DocumentIR) =>\n `Extract JSON matching the schema fields: vessel, port, quantity_mt.\nDocument (first page preview):\n${ir.pages[0]?.lines.slice(0, 50).map(l => l.text).join('\\n')}`;\n\n const extract = extractNode({\n llm: coreLLMProvider,\n schema: simpleSchema,\n makePrompt: mkPrompt\n });\n\n return {\n async run(input: { url?: string; base64?: string }) {\n const parsed = await runPipeline([parse], input);\n const ir = parsed.output as DocumentIR;\n\n const result = await runPipeline([extract], ir);\n\n return {\n ir,\n output: result.output,\n metrics: [...parsed.metrics, ...result.metrics],\n artifacts: {\n parse: parsed.artifacts.parse,\n extract: result.artifacts.extract\n }\n };\n }\n };\n}\n","import { runPipeline } from \"@doclo/core\";\nimport { node } from \"@doclo/core\";\nimport { simpleSchema } from \"./schemas\";\nimport { buildLLMProvider } from \"@doclo/providers-llm\";\n\n/**\n * Build a flow that uses VLM (Vision Language Model) for direct extraction\n * Skips OCR entirely - sends image/PDF directly to the vision model\n *\n * Pros:\n * - Faster (one API call instead of two)\n * - Can understand layout, tables, charts visually\n * - No OCR errors/artifacts\n *\n * Cons:\n * - More expensive (vision tokens cost more)\n * - Limited to models with vision capabilities\n */\nexport function buildVLMDirectFlow(opts: {\n llmConfigs: Array<{\n provider: 'openai' | 'anthropic' | 'google' | 'xai';\n model: string;\n apiKey: string;\n via?: 'openrouter' | 'native';\n baseUrl?: string;\n }>;\n maxRetries?: number;\n retryDelay?: number;\n circuitBreakerThreshold?: number;\n}) {\n // Build LLM provider with vision support\n // buildLLMProvider returns CoreVLMProvider directly (no adapter needed)\n const coreLLMProvider = buildLLMProvider({\n providers: opts.llmConfigs,\n maxRetries: opts.maxRetries ?? 2,\n retryDelay: opts.retryDelay ?? 1000,\n useExponentialBackoff: true,\n circuitBreakerThreshold: opts.circuitBreakerThreshold ?? 3\n });\n\n // Create VLM extraction node\n const vlmExtract = node<{ url?: string; base64?: string }, any>(\n \"vlm_extract\",\n async (input, ctx) => {\n const t0 = Date.now();\n\n // Build multimodal prompt with proper format for OpenRouter\n const prompt: any = {\n text: `You are a document data extraction expert. Extract the following fields from this maritime document:\n- vessel: The vessel/ship name\n- port: The port name or location\n- quantity_mt: The quantity in metric tons (MT)\n\nReturn ONLY a JSON object with these fields. Use null if a field is not found.`\n };\n\n // Determine if it's a PDF or image based on data\n let isPDF = false;\n\n if (input.url) {\n isPDF = input.url.endsWith('.pdf') || input.url.toLowerCase().includes('.pdf');\n } else if (input.base64) {\n // Check if base64 data URL indicates PDF\n isPDF = input.base64.startsWith('data:application/pdf');\n }\n\n // Add file/image to prompt based on type\n if (isPDF) {\n // For PDFs, use 'pdfs' array\n prompt.pdfs = [];\n if (input.url) {\n // If it's a data URL (base64), extract the base64 part\n if (input.url.startsWith('data:')) {\n const base64Data = input.url.replace(/^data:application\\/pdf;base64,/, '');\n prompt.pdfs.push({ base64: base64Data });\n } else {\n // Regular URL\n prompt.pdfs.push({ url: input.url });\n }\n } else if (input.base64) {\n // Extract base64 data if it's a data URL, otherwise use as-is\n const base64Data = input.base64.startsWith('data:')\n ? input.base64.replace(/^data:application\\/pdf;base64,/, '')\n : input.base64;\n prompt.pdfs.push({ base64: base64Data });\n }\n } else {\n // For images, use 'images' array\n prompt.images = [];\n if (input.url) {\n // If it's a data URL (base64), extract the base64 part\n if (input.url.startsWith('data:')) {\n const base64Data = input.url.replace(/^data:image\\/[^;]+;base64,/, '');\n const mimeType = input.url.match(/^data:(image\\/[^;]+);/)?.[1] || 'image/jpeg';\n prompt.images.push({ base64: base64Data, mimeType });\n } else {\n // Regular URL\n prompt.images.push({ url: input.url, mimeType: 'image/jpeg' });\n }\n } else if (input.base64) {\n // Extract base64 data if it's a data URL, otherwise use as-is\n const base64Data = input.base64.startsWith('data:')\n ? input.base64.replace(/^data:image\\/[^;]+;base64,/, '')\n : input.base64;\n const mimeType = input.base64.startsWith('data:')\n ? input.base64.match(/^data:(image\\/[^;]+);/)?.[1] || 'image/jpeg'\n : 'image/jpeg';\n prompt.images.push({ base64: base64Data, mimeType });\n }\n }\n\n const { json, costUSD, inputTokens, outputTokens, cacheCreationInputTokens, cacheReadInputTokens } = await coreLLMProvider.completeJson({\n prompt,\n schema: simpleSchema\n });\n\n ctx.metrics.push({\n step: \"vlm_extract\",\n startMs: t0,\n provider: coreLLMProvider.name,\n model: 'unknown',\n ms: Date.now() - t0,\n costUSD,\n inputTokens,\n outputTokens,\n cacheCreationInputTokens,\n cacheReadInputTokens,\n attemptNumber: 1,\n metadata: { kind: 'leaf' }\n });\n\n return json;\n }\n );\n\n return {\n async run(input: { url?: string; base64?: string }) {\n const result = await runPipeline([vlmExtract], input);\n\n return {\n output: result.output,\n metrics: result.metrics,\n artifacts: {\n vlm_extract: result.artifacts.vlm_extract\n }\n };\n }\n };\n}\n"],"mappings":"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","names":["runPipeline","parseNode","extractNode","node","result","parse","split","categorize","extract","trigger","split","categorize","FlowExecutionError","FlowExecutionError","node","split","categorize","hasProviderRef","runPipeline","parse","extract","runPipeline","runPipeline","buildLLMProvider","runPipeline","parse","parseNode","extractNode","runPipeline"]}