improvement(console): added iteration info to console entry for parallel/loop (#930)

This commit is contained in:
Waleed Latif
2025-08-10 16:27:39 -07:00
committed by GitHub
parent 785b86a32e
commit e271ed86b6
4 changed files with 144 additions and 13 deletions

View File

@@ -417,6 +417,14 @@ export function ConsoleEntry({ entry, consoleWidth }: ConsoleEntryProps) {
{entry.startedAt ? format(new Date(entry.startedAt), 'HH:mm:ss') : 'N/A'}
</span>
</div>
{/* Iteration tag - only show if iteration context exists */}
{entry.iterationCurrent !== undefined && entry.iterationTotal !== undefined && (
<div className='flex h-5 items-center rounded-lg bg-secondary px-2'>
<span className='font-normal text-muted-foreground text-xs leading-normal'>
{entry.iterationCurrent}/{entry.iterationTotal}
</span>
</div>
)}
{/* Input/Output tags - only show if input data exists */}
{hasInputData && (
<>

View File

@@ -1508,6 +1508,43 @@ export class Executor {
// Skip console logging for infrastructure blocks like loops and parallels
// For streaming blocks, we'll add the console entry after stream processing
if (block.metadata?.id !== BlockType.LOOP && block.metadata?.id !== BlockType.PARALLEL) {
// Determine iteration context for this block
let iterationCurrent: number | undefined
let iterationTotal: number | undefined
let iterationType: 'loop' | 'parallel' | undefined
const blockName = block.metadata?.name || 'Unnamed Block'
if (parallelInfo) {
// This is a parallel iteration
const parallelState = context.parallelExecutions?.get(parallelInfo.parallelId)
iterationCurrent = parallelInfo.iterationIndex + 1
iterationTotal = parallelState?.parallelCount
iterationType = 'parallel'
} else {
// Check if this block is inside a loop
const containingLoopId = this.resolver.loopsByBlockId?.get(block.id)
if (containingLoopId) {
const currentIteration = context.loopIterations.get(containingLoopId)
const loop = context.workflow?.loops?.[containingLoopId]
if (currentIteration !== undefined && loop) {
iterationCurrent = currentIteration
if (loop.loopType === 'forEach') {
// For forEach loops, get the total from the items
const forEachItems = context.loopItems.get(`${containingLoopId}_items`)
if (forEachItems) {
iterationTotal = Array.isArray(forEachItems)
? forEachItems.length
: Object.keys(forEachItems).length
}
} else {
// For regular loops, use the iterations count
iterationTotal = loop.iterations || 5
}
iterationType = 'loop'
}
}
}
addConsole({
input: blockLog.input,
output: blockLog.output,
@@ -1518,12 +1555,11 @@ export class Executor {
workflowId: context.workflowId,
blockId: parallelInfo ? blockId : block.id,
executionId: this.contextExtensions.executionId,
blockName: parallelInfo
? `${block.metadata?.name || 'Unnamed Block'} (iteration ${
parallelInfo.iterationIndex + 1
})`
: block.metadata?.name || 'Unnamed Block',
blockName,
blockType: block.metadata?.id || 'unknown',
iterationCurrent,
iterationTotal,
iterationType,
})
}
@@ -1578,6 +1614,43 @@ export class Executor {
// Skip console logging for infrastructure blocks like loops and parallels
if (block.metadata?.id !== BlockType.LOOP && block.metadata?.id !== BlockType.PARALLEL) {
// Determine iteration context for this block
let iterationCurrent: number | undefined
let iterationTotal: number | undefined
let iterationType: 'loop' | 'parallel' | undefined
const blockName = block.metadata?.name || 'Unnamed Block'
if (parallelInfo) {
// This is a parallel iteration
const parallelState = context.parallelExecutions?.get(parallelInfo.parallelId)
iterationCurrent = parallelInfo.iterationIndex + 1
iterationTotal = parallelState?.parallelCount
iterationType = 'parallel'
} else {
// Check if this block is inside a loop
const containingLoopId = this.resolver.getContainingLoopId(block.id)
if (containingLoopId) {
const currentIteration = context.loopIterations.get(containingLoopId)
const loop = context.workflow?.loops?.[containingLoopId]
if (currentIteration !== undefined && loop) {
iterationCurrent = currentIteration
if (loop.loopType === 'forEach') {
// For forEach loops, get the total from the items
const forEachItems = context.loopItems.get(`${containingLoopId}_items`)
if (forEachItems) {
iterationTotal = Array.isArray(forEachItems)
? forEachItems.length
: Object.keys(forEachItems).length
}
} else {
// For regular loops, use the iterations count
iterationTotal = loop.iterations || 5
}
iterationType = 'loop'
}
}
}
addConsole({
input: blockLog.input,
output: blockLog.output,
@@ -1588,12 +1661,11 @@ export class Executor {
workflowId: context.workflowId,
blockId: parallelInfo ? blockId : block.id,
executionId: this.contextExtensions.executionId,
blockName: parallelInfo
? `${block.metadata?.name || 'Unnamed Block'} (iteration ${
parallelInfo.iterationIndex + 1
})`
: block.metadata?.name || 'Unnamed Block',
blockName,
blockType: block.metadata?.id || 'unknown',
iterationCurrent,
iterationTotal,
iterationType,
})
}
@@ -1649,6 +1721,43 @@ export class Executor {
// Skip console logging for infrastructure blocks like loops and parallels
if (block.metadata?.id !== BlockType.LOOP && block.metadata?.id !== BlockType.PARALLEL) {
// Determine iteration context for this block
let iterationCurrent: number | undefined
let iterationTotal: number | undefined
let iterationType: 'loop' | 'parallel' | undefined
const blockName = block.metadata?.name || 'Unnamed Block'
if (parallelInfo) {
// This is a parallel iteration
const parallelState = context.parallelExecutions?.get(parallelInfo.parallelId)
iterationCurrent = parallelInfo.iterationIndex + 1
iterationTotal = parallelState?.parallelCount
iterationType = 'parallel'
} else {
// Check if this block is inside a loop
const containingLoopId = this.resolver.getContainingLoopId(block.id)
if (containingLoopId) {
const currentIteration = context.loopIterations.get(containingLoopId)
const loop = context.workflow?.loops?.[containingLoopId]
if (currentIteration !== undefined && loop) {
iterationCurrent = currentIteration
if (loop.loopType === 'forEach') {
// For forEach loops, get the total from the items
const forEachItems = context.loopItems.get(`${containingLoopId}_items`)
if (forEachItems) {
iterationTotal = Array.isArray(forEachItems)
? forEachItems.length
: Object.keys(forEachItems).length
}
} else {
// For regular loops, use the iterations count
iterationTotal = loop.iterations || 5
}
iterationType = 'loop'
}
}
}
addConsole({
input: blockLog.input,
output: {},
@@ -1662,10 +1771,11 @@ export class Executor {
workflowId: context.workflowId,
blockId: parallelInfo ? blockId : block.id,
executionId: this.contextExtensions.executionId,
blockName: parallelInfo
? `${block.metadata?.name || 'Unnamed Block'} (iteration ${parallelInfo.iterationIndex + 1})`
: block.metadata?.name || 'Unnamed Block',
blockName,
blockType: block.metadata?.id || 'unknown',
iterationCurrent,
iterationTotal,
iterationType,
})
}

View File

@@ -1845,4 +1845,13 @@ export class InputResolver {
return value
}
/**
* Get the containing loop ID for a block
* @param blockId - The ID of the block
* @returns The containing loop ID or undefined if not in a loop
*/
getContainingLoopId(blockId: string): string | undefined {
return this.loopsByBlockId.get(blockId)
}
}

View File

@@ -16,6 +16,10 @@ export interface ConsoleEntry {
input?: any
error?: string
warning?: string
// Iteration context for loops and parallels
iterationCurrent?: number
iterationTotal?: number
iterationType?: 'loop' | 'parallel'
}
export interface ConsoleUpdate {