@@ -42,23 +42,14 @@ export interface LoopContinuationResult {
4242}
4343
4444export class LoopOrchestrator {
45- private edgeManager : EdgeManager | null = null
46- private contextExtensions : ContextExtensions | null = null
47-
4845 constructor (
4946 private dag : DAG ,
5047 private state : BlockStateController ,
51- private resolver : VariableResolver
48+ private resolver : VariableResolver ,
49+ private contextExtensions : ContextExtensions | null = null ,
50+ private edgeManager : EdgeManager | null = null
5251 ) { }
5352
54- setContextExtensions ( contextExtensions : ContextExtensions ) : void {
55- this . contextExtensions = contextExtensions
56- }
57-
58- setEdgeManager ( edgeManager : EdgeManager ) : void {
59- this . edgeManager = edgeManager
60- }
61-
6253 initializeLoopScope ( ctx : ExecutionContext , loopId : string ) : LoopScope {
6354 const loopConfig = this . dag . loopConfigs . get ( loopId ) as SerializedLoop | undefined
6455 if ( ! loopConfig ) {
@@ -103,7 +94,7 @@ export class LoopOrchestrator {
10394 scope . loopType = 'forEach'
10495 let items : any [ ]
10596 try {
106- items = this . resolveForEachItems ( ctx , loopConfig . forEachItems )
97+ items = resolveArrayInput ( ctx , loopConfig . forEachItems , this . resolver )
10798 } catch ( error ) {
10899 const errorMessage = `ForEach loop resolution failed: ${ error instanceof Error ? error . message : String ( error ) } `
109100 logger . error ( errorMessage , { loopId, forEachItems : loopConfig . forEachItems } )
@@ -359,9 +350,8 @@ export class LoopOrchestrator {
359350 for ( const nodeId of loopConfig . nodes ) {
360351 if ( this . dag . loopConfigs . has ( nodeId ) ) {
361352 ctx . loopExecutions ?. delete ( nodeId )
362- // Delete cloned loop variants (e.g., inner-loop__obranch-N)
363- // Only delete clone entries from subflowParentMap, never the original
364- // structural entries which are needed for SSE iteration context.
353+ // Delete cloned loop variants (e.g., inner-loop__obranch-N) but not original
354+ // subflowParentMap entries which are needed for SSE iteration context.
365355 if ( ctx . loopExecutions ) {
366356 const prefix = `${ nodeId } __obranch-`
367357 for ( const key of ctx . loopExecutions . keys ( ) ) {
@@ -400,11 +390,7 @@ export class LoopOrchestrator {
400390 */
401391 private deleteParallelScopeAndClones ( parallelId : string , ctx : ExecutionContext ) : void {
402392 ctx . parallelExecutions ?. delete ( parallelId )
403- // Do NOT delete the original entry from subflowParentMap — it is a static
404- // structural mapping needed for SSE iteration context on subsequent loop
405- // iterations. Only delete __obranch-N clone entries below.
406-
407- // Delete any cloned scopes (e.g., inner-parallel__obranch-1)
393+ // Delete cloned scopes (__obranch-N) but not original subflowParentMap entries
408394 if ( ctx . parallelExecutions ) {
409395 const prefix = `${ parallelId } __obranch-`
410396 for ( const key of ctx . parallelExecutions . keys ( ) ) {
@@ -415,7 +401,6 @@ export class LoopOrchestrator {
415401 }
416402 }
417403
418- // Recurse into nested subflows within this parallel
419404 const parallelConfig = this . dag . parallelConfigs . get ( parallelId )
420405 if ( parallelConfig ?. nodes ) {
421406 for ( const nodeId of parallelConfig . nodes ) {
@@ -483,17 +468,14 @@ export class LoopOrchestrator {
483468 for ( const id of this . collectAllLoopNodeIds ( nodeId , visited ) ) {
484469 result . add ( id )
485470 }
486- // Also collect cloned loop variants (e.g., loop-1__obranch-N)
487471 this . collectClonedSubflowNodes ( nodeId , result , visited )
488472 } else if ( this . dag . parallelConfigs . has ( nodeId ) ) {
489473 for ( const id of this . collectAllParallelNodeIds ( nodeId , visited ) ) {
490474 result . add ( id )
491475 }
492- // Also collect cloned parallel variants
493476 this . collectClonedSubflowNodes ( nodeId , result , visited )
494477 } else {
495478 result . add ( nodeId )
496- // Collect ALL dynamic branch nodes (not just branch 0)
497479 this . collectAllBranchNodes ( nodeId , result )
498480 }
499481 }
@@ -605,23 +587,19 @@ export class LoopOrchestrator {
605587 return true
606588 }
607589
608- // for: skip if maxIterations is 0
609590 if ( scope . loopType === 'for' ) {
610591 if ( scope . maxIterations === 0 ) {
611592 logger . info ( 'For loop has 0 iterations, skipping loop body' , { loopId } )
612- // Set empty output for the loop
613593 this . state . setBlockOutput ( loopId , { results : [ ] } , DEFAULTS . EXECUTION_TIME )
614594 return false
615595 }
616596 return true
617597 }
618598
619- // doWhile: always execute at least once
620599 if ( scope . loopType === 'doWhile' ) {
621600 return true
622601 }
623602
624- // while: check condition before first iteration
625603 if ( scope . loopType === 'while' ) {
626604 if ( ! scope . condition ) {
627605 logger . warn ( 'No condition defined for while loop' , { loopId } )
@@ -641,10 +619,6 @@ export class LoopOrchestrator {
641619 return true
642620 }
643621
644- shouldExecuteLoopNode ( _ctx : ExecutionContext , _nodeId : string , _loopId : string ) : boolean {
645- return true
646- }
647-
648622 private async evaluateWhileCondition (
649623 ctx : ExecutionContext ,
650624 condition : string ,
@@ -663,10 +637,9 @@ export class LoopOrchestrator {
663637
664638 const evaluatedCondition = replaceValidReferences ( condition , ( match ) => {
665639 const resolved = this . resolver . resolveSingleReference ( ctx , '' , match , scope )
666- logger . info ( 'Resolved variable reference in loop condition' , {
640+ logger . debug ( 'Resolved variable reference in loop condition' , {
667641 reference : match ,
668642 resolvedValue : resolved ,
669- resolvedType : typeof resolved ,
670643 } )
671644 if ( resolved !== undefined ) {
672645 if ( typeof resolved === 'boolean' || typeof resolved === 'number' ) {
@@ -721,8 +694,4 @@ export class LoopOrchestrator {
721694 return false
722695 }
723696 }
724-
725- private resolveForEachItems ( ctx : ExecutionContext , items : any ) : any [ ] {
726- return resolveArrayInput ( ctx , items , this . resolver )
727- }
728697}
0 commit comments