diff --git a/web/app/components/workflow/run/utils/format-log/index.ts b/web/app/components/workflow/run/utils/format-log/index.ts index df7947594a..4f97814e46 100644 --- a/web/app/components/workflow/run/utils/format-log/index.ts +++ b/web/app/components/workflow/run/utils/format-log/index.ts @@ -1,16 +1,83 @@ import type { NodeTracing } from '@/types/workflow' -import formatIterationNode from './iteration' -import formatLoopNode from './loop' +import { addChildrenToIterationNode } from './iteration' +import { addChildrenToLoopNode } from './loop' import formatParallelNode from './parallel' import formatRetryNode from './retry' import formatAgentNode from './agent' import { cloneDeep } from 'lodash-es' import { BlockEnum } from '../../../types' -import { orderBy } from 'lodash-es' + +const formatIterationAndLoopNode = (list: NodeTracing[], t: any) => { + const clonedList = cloneDeep(list) + + // Identify all loop and iteration nodes + const loopNodeIds = clonedList + .filter(item => item.node_type === BlockEnum.Loop) + .map(item => item.node_id) + + const iterationNodeIds = clonedList + .filter(item => item.node_type === BlockEnum.Iteration) + .map(item => item.node_id) + + // Identify all child nodes for both loop and iteration + const loopChildrenNodeIds = clonedList + .filter(item => item.execution_metadata?.loop_id && loopNodeIds.includes(item.execution_metadata.loop_id)) + .map(item => item.node_id) + + const iterationChildrenNodeIds = clonedList + .filter(item => item.execution_metadata?.iteration_id && iterationNodeIds.includes(item.execution_metadata.iteration_id)) + .map(item => item.node_id) + + // Filter out child nodes as they will be included in their parent nodes + const result = clonedList + .filter(item => !loopChildrenNodeIds.includes(item.node_id) && !iterationChildrenNodeIds.includes(item.node_id)) + .map((item) => { + // Process Loop nodes + if (item.node_type === BlockEnum.Loop) { + const childrenNodes = clonedList.filter(child => child.execution_metadata?.loop_id === item.node_id) + const error = childrenNodes.find(child => child.status === 'failed') + if (error) { + item.status = 'failed' + item.error = error.error + } + const addedChildrenList = addChildrenToLoopNode(item, childrenNodes) + + // Handle parallel nodes in loop node + if (addedChildrenList.details && addedChildrenList.details.length > 0) { + addedChildrenList.details = addedChildrenList.details.map((row) => { + return formatParallelNode(row, t) + }) + } + return addedChildrenList + } + + // Process Iteration nodes + if (item.node_type === BlockEnum.Iteration) { + const childrenNodes = clonedList.filter(child => child.execution_metadata?.iteration_id === item.node_id) + const error = childrenNodes.find(child => child.status === 'failed') + if (error) { + item.status = 'failed' + item.error = error.error + } + const addedChildrenList = addChildrenToIterationNode(item, childrenNodes) + + // Handle parallel nodes in iteration node + if (addedChildrenList.details && addedChildrenList.details.length > 0) { + addedChildrenList.details = addedChildrenList.details.map((row) => { + return formatParallelNode(row, t) + }) + } + return addedChildrenList + } + + return item + }) + + return result +} const formatToTracingNodeList = (list: NodeTracing[], t: any) => { const allItems = cloneDeep([...list]).sort((a, b) => a.index - b.index) - const loopRelatedListIds = allItems.filter(item => (!!item.execution_metadata?.loop_id || item.node_type === BlockEnum.Loop)).map(x => x.id) /* * First handle not change list structure node * Because Handle struct node will put the node in different @@ -18,10 +85,8 @@ const formatToTracingNodeList = (list: NodeTracing[], t: any) => { const formattedAgentList = formatAgentNode(allItems) const formattedRetryList = formatRetryNode(formattedAgentList) // retry one node // would change the structure of the list. Iteration and parallel can include each other. - const formattedIterationList = formatIterationNode(formattedRetryList.filter(item => !loopRelatedListIds.includes(item.id)), t) - const formattedLoopList = formatLoopNode(formattedRetryList.filter(item => loopRelatedListIds.includes(item.id)), t) - const orderedNodeList = orderBy([...formattedIterationList, ...formattedLoopList], 'finished_at', 'asc') - const formattedParallelList = formatParallelNode(orderedNodeList, t) + const formattedLoopAndIterationList = formatIterationAndLoopNode(formattedRetryList, t) + const formattedParallelList = formatParallelNode(formattedLoopAndIterationList, t) const result = formattedParallelList // console.log(allItems) diff --git a/web/app/components/workflow/run/utils/format-log/iteration/index.ts b/web/app/components/workflow/run/utils/format-log/iteration/index.ts index d923d46783..d0224d0259 100644 --- a/web/app/components/workflow/run/utils/format-log/iteration/index.ts +++ b/web/app/components/workflow/run/utils/format-log/iteration/index.ts @@ -1,7 +1,8 @@ import { BlockEnum } from '@/app/components/workflow/types' import type { NodeTracing } from '@/types/workflow' import formatParallelNode from '../parallel' -function addChildrenToIterationNode(iterationNode: NodeTracing, childrenNodes: NodeTracing[]): NodeTracing { + +export function addChildrenToIterationNode(iterationNode: NodeTracing, childrenNodes: NodeTracing[]): NodeTracing { const details: NodeTracing[][] = [] childrenNodes.forEach((item, index) => { if (!item.execution_metadata) return diff --git a/web/app/components/workflow/run/utils/format-log/loop/index.ts b/web/app/components/workflow/run/utils/format-log/loop/index.ts index 257cc689d5..b12e12e48f 100644 --- a/web/app/components/workflow/run/utils/format-log/loop/index.ts +++ b/web/app/components/workflow/run/utils/format-log/loop/index.ts @@ -1,7 +1,8 @@ import { BlockEnum } from '@/app/components/workflow/types' import type { NodeTracing } from '@/types/workflow' import formatParallelNode from '../parallel' -function addChildrenToLoopNode(loopNode: NodeTracing, childrenNodes: NodeTracing[]): NodeTracing { + +export function addChildrenToLoopNode(loopNode: NodeTracing, childrenNodes: NodeTracing[]): NodeTracing { const details: NodeTracing[][] = [] childrenNodes.forEach((item) => { if (!item.execution_metadata) return