From c23fe3b67f311ab0c19125a6f3bb701249e92d7d Mon Sep 17 00:00:00 2001 From: Joel Date: Thu, 26 Dec 2024 18:38:59 +0800 Subject: [PATCH] chore: format --- .../workflow/header/view-history.tsx | 2 +- web/app/components/workflow/run/index.tsx | 2 +- .../components/workflow/run/tracing-panel.tsx | 158 ++---------------- .../workflow/run/utils/format-log/index.ts | 17 +- .../utils/format-log/parallel/index.backup.ts | 132 +++++++++++++++ .../run/utils/format-log/parallel/index.ts | 127 ++++++++++++++ web/types/workflow.ts | 10 +- 7 files changed, 294 insertions(+), 154 deletions(-) create mode 100644 web/app/components/workflow/run/utils/format-log/parallel/index.backup.ts diff --git a/web/app/components/workflow/header/view-history.tsx b/web/app/components/workflow/header/view-history.tsx index a18ddad65d..82d8a302c5 100644 --- a/web/app/components/workflow/header/view-history.tsx +++ b/web/app/components/workflow/header/view-history.tsx @@ -202,7 +202,7 @@ const ViewHistory = ({ {`Test ${isChatMode ? 'Chat' : 'Run'}#${item.sequence_number}`}
- {item.created_by_account.name} · {formatTimeFromNow((item.finished_at || item.created_at) * 1000)} + {item.created_by_account?.name} · {formatTimeFromNow((item.finished_at || item.created_at) * 1000)}
diff --git a/web/app/components/workflow/run/index.tsx b/web/app/components/workflow/run/index.tsx index 557fb8b06e..c1249f7224 100644 --- a/web/app/components/workflow/run/index.tsx +++ b/web/app/components/workflow/run/index.tsx @@ -61,7 +61,7 @@ const RunPanel: FC = ({ hideResult, activeTab = 'RESULT', runID, getRe const { data: nodeList } = await fetchTracingList({ url: `/apps/${appID}/workflow-runs/${runID}/node-executions`, }) - setList(formatNodeList(nodeList)) + setList(formatNodeList(nodeList, t)) } catch (err) { notify({ diff --git a/web/app/components/workflow/run/tracing-panel.tsx b/web/app/components/workflow/run/tracing-panel.tsx index 109283c511..f8af35219b 100644 --- a/web/app/components/workflow/run/tracing-panel.tsx +++ b/web/app/components/workflow/run/tracing-panel.tsx @@ -11,13 +11,9 @@ import { RiArrowDownSLine, RiMenu4Line, } from '@remixicon/react' -import { useTranslation } from 'react-i18next' import { useLogs } from './hooks' import NodePanel from './node' import SpecialResultPanel from './special-result-panel' -import { - BlockEnum, -} from '@/app/components/workflow/types' import type { NodeTracing } from '@/types/workflow' type TracingPanelProps = { @@ -27,145 +23,14 @@ type TracingPanelProps = { hideNodeProcessDetail?: boolean } -type TracingNodeProps = { - id: string - uniqueId: string - isParallel: boolean - data: NodeTracing | null - children: TracingNodeProps[] - parallelTitle?: string - branchTitle?: string - hideNodeInfo?: boolean - hideNodeProcessDetail?: boolean -} - -function buildLogTree(nodes: NodeTracing[], t: (key: string) => string): TracingNodeProps[] { - const rootNodes: TracingNodeProps[] = [] - const parallelStacks: { [key: string]: TracingNodeProps } = {} - const levelCounts: { [key: string]: number } = {} - const parallelChildCounts: { [key: string]: Set } = {} - let uniqueIdCounter = 0 - const getUniqueId = () => { - uniqueIdCounter++ - return `unique-${uniqueIdCounter}` - } - - const getParallelTitle = (parentId: string | null): string => { - const levelKey = parentId || 'root' - if (!levelCounts[levelKey]) - levelCounts[levelKey] = 0 - - levelCounts[levelKey]++ - - const parentTitle = parentId ? parallelStacks[parentId]?.parallelTitle : '' - const levelNumber = parentTitle ? Number.parseInt(parentTitle.split('-')[1]) + 1 : 1 - const letter = parallelChildCounts[levelKey]?.size > 1 ? String.fromCharCode(64 + levelCounts[levelKey]) : '' - return `${t('workflow.common.parallel')}-${levelNumber}${letter}` - } - - const getBranchTitle = (parentId: string | null, branchNum: number): string => { - const levelKey = parentId || 'root' - const parentTitle = parentId ? parallelStacks[parentId]?.parallelTitle : '' - const levelNumber = parentTitle ? Number.parseInt(parentTitle.split('-')[1]) + 1 : 1 - const letter = parallelChildCounts[levelKey]?.size > 1 ? String.fromCharCode(64 + levelCounts[levelKey]) : '' - const branchLetter = String.fromCharCode(64 + branchNum) - return `${t('workflow.common.branch')}-${levelNumber}${letter}-${branchLetter}` - } - - // Count parallel children (for figuring out if we need to use letters) - for (const node of nodes) { - const parent_parallel_id = node.parent_parallel_id ?? node.execution_metadata?.parent_parallel_id ?? null - const parallel_id = node.parallel_id ?? node.execution_metadata?.parallel_id ?? null - - if (parallel_id) { - const parentKey = parent_parallel_id || 'root' - if (!parallelChildCounts[parentKey]) - parallelChildCounts[parentKey] = new Set() - - parallelChildCounts[parentKey].add(parallel_id) - } - } - - for (const node of nodes) { - const parallel_id = node.parallel_id ?? node.execution_metadata?.parallel_id ?? null - const parent_parallel_id = node.parent_parallel_id ?? node.execution_metadata?.parent_parallel_id ?? null - const parallel_start_node_id = node.parallel_start_node_id ?? node.execution_metadata?.parallel_start_node_id ?? null - const parent_parallel_start_node_id = node.parent_parallel_start_node_id ?? node.execution_metadata?.parent_parallel_start_node_id ?? null - - if (!parallel_id || node.node_type === BlockEnum.End) { - rootNodes.push({ - id: node.id, - uniqueId: getUniqueId(), - isParallel: false, - data: node, - children: [], - }) - } - else { - if (!parallelStacks[parallel_id]) { - const newParallelGroup: TracingNodeProps = { - id: parallel_id, - uniqueId: getUniqueId(), - isParallel: true, - data: null, - children: [], - parallelTitle: '', - } - parallelStacks[parallel_id] = newParallelGroup - - if (parent_parallel_id && parallelStacks[parent_parallel_id]) { - const sameBranchIndex = parallelStacks[parent_parallel_id].children.findLastIndex(c => - c.data?.execution_metadata?.parallel_start_node_id === parent_parallel_start_node_id || c.data?.parallel_start_node_id === parent_parallel_start_node_id, - ) - parallelStacks[parent_parallel_id].children.splice(sameBranchIndex + 1, 0, newParallelGroup) - newParallelGroup.parallelTitle = getParallelTitle(parent_parallel_id) - } - else { - newParallelGroup.parallelTitle = getParallelTitle(parent_parallel_id) - rootNodes.push(newParallelGroup) - } - } - const branchTitle = parallel_start_node_id === node.node_id ? getBranchTitle(parent_parallel_id, parallelStacks[parallel_id].children.length + 1) : '' - if (branchTitle) { - parallelStacks[parallel_id].children.push({ - id: node.id, - uniqueId: getUniqueId(), - isParallel: false, - data: node, - children: [], - branchTitle, - }) - } - else { - let sameBranchIndex = parallelStacks[parallel_id].children.findLastIndex(c => - c.data?.execution_metadata?.parallel_start_node_id === parallel_start_node_id || c.data?.parallel_start_node_id === parallel_start_node_id, - ) - if (parallelStacks[parallel_id].children[sameBranchIndex + 1]?.isParallel) - sameBranchIndex++ - - parallelStacks[parallel_id].children.splice(sameBranchIndex + 1, 0, { - id: node.id, - uniqueId: getUniqueId(), - isParallel: false, - data: node, - children: [], - branchTitle, - }) - } - } - } - - return rootNodes -} - const TracingPanel: FC = ({ list, className, hideNodeInfo = false, hideNodeProcessDetail = false, }) => { - const { t } = useTranslation() - const treeNodes = buildLogTree(list, t) + const treeNodes = list + console.log(treeNodes) const [collapsedNodes, setCollapsedNodes] = useState>(new Set()) const [hoveredParallel, setHoveredParallel] = useState(null) @@ -219,13 +84,16 @@ const TracingPanel: FC = ({ setAgentResultList, } = useLogs() - const renderNode = (node: TracingNodeProps) => { - if (node.isParallel) { + + const renderNode = (node: NodeTracing) => { + const isParallelFirstNode = !!node.parallelDetail?.isParallelStartNode + if (isParallelFirstNode) { + const parallelDetail = node.parallelDetail! const isCollapsed = collapsedNodes.has(node.id) const isHovered = hoveredParallel === node.id return (
handleParallelMouseEnter(node.id)} @@ -242,7 +110,7 @@ const TracingPanel: FC = ({ {isHovered ? : }
- {node.parallelTitle} + {parallelDetail.parallelTitle}
= ({ 'absolute top-0 bottom-0 left-[5px] w-[2px]', isHovered ? 'bg-text-accent-secondary' : 'bg-divider-subtle', )}>
- {node.children.map(renderNode)} + {parallelDetail.children!.map(renderNode)}
) @@ -262,12 +130,12 @@ const TracingPanel: FC = ({ else { const isHovered = hoveredParallel === node.id return ( -
+
- {node.branchTitle} + {node?.parallelDetail?.branchTitle}
{ +const formatToTracingNodeList = (list: NodeTracing[], t: any) => { const allItems = [...list].reverse() - const formattedIterationList = formatIterationNode(allItems) - const formattedRetryList = formatRetryNode(formattedIterationList) - const formattedAgentList = formatAgentNode(formattedRetryList) + /* + * First handle not change list structure node + * Because Handle struct node will put the node in different + */ + 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) + const formattedParallelList = formatParallelNode(formattedIterationList, t) - const result = formattedAgentList + const result = formattedParallelList // console.log(allItems) // console.log(result) diff --git a/web/app/components/workflow/run/utils/format-log/parallel/index.backup.ts b/web/app/components/workflow/run/utils/format-log/parallel/index.backup.ts new file mode 100644 index 0000000000..f30d03c839 --- /dev/null +++ b/web/app/components/workflow/run/utils/format-log/parallel/index.backup.ts @@ -0,0 +1,132 @@ +import type { NodeTracing } from '@/types/workflow' + +type TracingNodeProps = { + id: string + uniqueId: string + isParallel: boolean + data: NodeTracing | null + children: TracingNodeProps[] + parallelTitle?: string + branchTitle?: string + hideNodeInfo?: boolean + hideNodeProcessDetail?: boolean +} + +function buildLogTree(nodes: NodeTracing[], t: (key: string) => string): TracingNodeProps[] { + const rootNodes: TracingNodeProps[] = [] + const parallelStacks: { [key: string]: TracingNodeProps } = {} + const levelCounts: { [key: string]: number } = {} + const parallelChildCounts: { [key: string]: Set } = {} + let uniqueIdCounter = 0 + const getUniqueId = () => { + uniqueIdCounter++ + return `unique-${uniqueIdCounter}` + } + + const getParallelTitle = (parentId: string | null): string => { + const levelKey = parentId || 'root' + if (!levelCounts[levelKey]) + levelCounts[levelKey] = 0 + + levelCounts[levelKey]++ + + const parentTitle = parentId ? parallelStacks[parentId]?.parallelTitle : '' + const levelNumber = parentTitle ? Number.parseInt(parentTitle.split('-')[1]) + 1 : 1 + const letter = parallelChildCounts[levelKey]?.size > 1 ? String.fromCharCode(64 + levelCounts[levelKey]) : '' + return `${t('workflow.common.parallel')}-${levelNumber}${letter}` + } + + const getBranchTitle = (parentId: string | null, branchNum: number): string => { + const levelKey = parentId || 'root' + const parentTitle = parentId ? parallelStacks[parentId]?.parallelTitle : '' + const levelNumber = parentTitle ? Number.parseInt(parentTitle.split('-')[1]) + 1 : 1 + const letter = parallelChildCounts[levelKey]?.size > 1 ? String.fromCharCode(64 + levelCounts[levelKey]) : '' + const branchLetter = String.fromCharCode(64 + branchNum) + return `${t('workflow.common.branch')}-${levelNumber}${letter}-${branchLetter}` + } + + // Count parallel children (for figuring out if we need to use letters) + for (const node of nodes) { + const parent_parallel_id = node.parent_parallel_id ?? node.execution_metadata?.parent_parallel_id ?? null + const parallel_id = node.parallel_id ?? node.execution_metadata?.parallel_id ?? null + + if (parallel_id) { + const parentKey = parent_parallel_id || 'root' + if (!parallelChildCounts[parentKey]) + parallelChildCounts[parentKey] = new Set() + + parallelChildCounts[parentKey].add(parallel_id) + } + } + + for (const node of nodes) { + const parallel_id = node.parallel_id ?? node.execution_metadata?.parallel_id ?? null + const parent_parallel_id = node.parent_parallel_id ?? node.execution_metadata?.parent_parallel_id ?? null + const parallel_start_node_id = node.parallel_start_node_id ?? node.execution_metadata?.parallel_start_node_id ?? null + const parent_parallel_start_node_id = node.parent_parallel_start_node_id ?? node.execution_metadata?.parent_parallel_start_node_id ?? null + + if (!parallel_id || node.node_type === BlockEnum.End) { + rootNodes.push({ + id: node.id, + uniqueId: getUniqueId(), + isParallel: false, + data: node, + children: [], + }) + } + else { + if (!parallelStacks[parallel_id]) { + const newParallelGroup: TracingNodeProps = { + id: parallel_id, + uniqueId: getUniqueId(), + isParallel: true, + data: null, + children: [], + parallelTitle: '', + } + parallelStacks[parallel_id] = newParallelGroup + + if (parent_parallel_id && parallelStacks[parent_parallel_id]) { + const sameBranchIndex = parallelStacks[parent_parallel_id].children.findLastIndex(c => + c.data?.execution_metadata?.parallel_start_node_id === parent_parallel_start_node_id || c.data?.parallel_start_node_id === parent_parallel_start_node_id, + ) + parallelStacks[parent_parallel_id].children.splice(sameBranchIndex + 1, 0, newParallelGroup) + newParallelGroup.parallelTitle = getParallelTitle(parent_parallel_id) + } + else { + newParallelGroup.parallelTitle = getParallelTitle(parent_parallel_id) + rootNodes.push(newParallelGroup) + } + } + const branchTitle = parallel_start_node_id === node.node_id ? getBranchTitle(parent_parallel_id, parallelStacks[parallel_id].children.length + 1) : '' + if (branchTitle) { + parallelStacks[parallel_id].children.push({ + id: node.id, + uniqueId: getUniqueId(), + isParallel: false, + data: node, + children: [], + branchTitle, + }) + } + else { + let sameBranchIndex = parallelStacks[parallel_id].children.findLastIndex(c => + c.data?.execution_metadata?.parallel_start_node_id === parallel_start_node_id || c.data?.parallel_start_node_id === parallel_start_node_id, + ) + if (parallelStacks[parallel_id].children[sameBranchIndex + 1]?.isParallel) + sameBranchIndex++ + + parallelStacks[parallel_id].children.splice(sameBranchIndex + 1, 0, { + id: node.id, + uniqueId: getUniqueId(), + isParallel: false, + data: node, + children: [], + branchTitle, + }) + } + } + } + + return rootNodes +} diff --git a/web/app/components/workflow/run/utils/format-log/parallel/index.ts b/web/app/components/workflow/run/utils/format-log/parallel/index.ts index e69de29bb2..214285d39b 100644 --- a/web/app/components/workflow/run/utils/format-log/parallel/index.ts +++ b/web/app/components/workflow/run/utils/format-log/parallel/index.ts @@ -0,0 +1,127 @@ +import { BlockEnum } from '@/app/components/workflow/types' +import type { NodeTracing } from '@/types/workflow' + +function addTitle({ + list, level, parallelNumRecord, +}: { + list: NodeTracing[], level: number, parallelNumRecord: Record +}, t: any) { + let branchIndex = 0 + list.forEach((node) => { + const parallel_id = node.parallel_id ?? node.execution_metadata?.parallel_id ?? null + const parallel_start_node_id = node.parallel_start_node_id ?? node.execution_metadata?.parallel_start_node_id ?? null + + const isNotInParallel = !parallel_id || node.node_type === BlockEnum.End + if (isNotInParallel) + return + + const isParallelStartNode = node.parallelDetail?.isParallelStartNode + if (isParallelStartNode) + parallelNumRecord.num++ + + const letter = parallelNumRecord.num > 1 ? String.fromCharCode(64 + level) : '' + const parallelLevelInfo = `${parallelNumRecord.num}${letter}` + + if (isParallelStartNode) { + node.parallelDetail!.isParallelStartNode = true + node.parallelDetail!.parallelTitle = `${t('workflow.common.parallel')}-${parallelLevelInfo}` + } + + const isBrachStartNode = parallel_start_node_id === node.node_id + if (isBrachStartNode) { + branchIndex++ + const branchLetter = String.fromCharCode(64 + branchIndex) + if (!node.parallelDetail) { + node.parallelDetail = { + branchTitle: '', + } + } + + node.parallelDetail!.branchTitle = `${t('workflow.common.branch')}-${parallelLevelInfo}-${branchLetter}` + } + + if (node.parallelDetail?.children && node.parallelDetail.children.length > 0) { + addTitle({ + list: node.parallelDetail.children, + level: level + 1, + parallelNumRecord, + }, t) + } + }) +} + +// list => group by parallel_id(parallel tree). +const format = (list: NodeTracing[], t: any): NodeTracing[] => { + const result: NodeTracing[] = [...list] + const parallelFirstNodeMap: Record = {} + // list to tree by parent_parallel_start_node_id and parallel_start_node_id + result.forEach((node) => { + const parallel_id = node.parallel_id ?? node.execution_metadata?.parallel_id ?? null + const parent_parallel_id = node.parent_parallel_id ?? node.execution_metadata?.parent_parallel_id ?? null + const parent_parallel_start_node_id = node.parent_parallel_start_node_id ?? node.execution_metadata?.parent_parallel_start_node_id ?? null + const isNotInParallel = !parallel_id || node.node_type === BlockEnum.End + if (isNotInParallel) + return + + const isParallelStartNode = !parallelFirstNodeMap[parallel_id] + if (isParallelStartNode) { + const selfNode = { ...node } + node.parallelDetail = { + isParallelStartNode: true, + children: [selfNode], + } + parallelFirstNodeMap[parallel_id] = node.node_id + const isRootLevel = !parent_parallel_id + if (isRootLevel) + return + + const parentParallelStartNode = result.find(item => item.node_id === parent_parallel_start_node_id) + // append to parent parallel start node + if (parentParallelStartNode) { + if (!parentParallelStartNode?.parallelDetail) { + parentParallelStartNode!.parallelDetail = { + children: [], + } + } + if (parentParallelStartNode!.parallelDetail.children) + parentParallelStartNode!.parallelDetail.children.push(node) + } + } + + // append to parallel start node + const parallelStartNode = result.find(item => item.node_id === parallelFirstNodeMap[parallel_id]) + if (parallelStartNode && parallelStartNode.parallelDetail && parallelStartNode!.parallelDetail!.children) + parallelStartNode!.parallelDetail!.children.push(node) + }) + + const filteredInParallelSubNodes = result.filter((node) => { + const parallel_id = node.parallel_id ?? node.execution_metadata?.parallel_id ?? null + const isNotInParallel = !parallel_id || node.node_type === BlockEnum.End + if (isNotInParallel) + return true + + const parent_parallel_id = node.parent_parallel_id ?? node.execution_metadata?.parent_parallel_id ?? null + + if (parent_parallel_id) + return false + + const isParallelStartNode = node.parallelDetail?.isParallelStartNode + if (!isParallelStartNode) + return false + + return true + }) + + const parallelNumRecord: Record = { + num: 0, + } + + addTitle({ + list: filteredInParallelSubNodes, + level: 1, + parallelNumRecord, + }, t) + + return filteredInParallelSubNodes +} +export default format diff --git a/web/types/workflow.ts b/web/types/workflow.ts index c89f5536a0..29fc91b06b 100644 --- a/web/types/workflow.ts +++ b/web/types/workflow.ts @@ -68,12 +68,18 @@ export type NodeTracing = { expand?: boolean // for UI details?: NodeTracing[][] // iteration detail retryDetail?: NodeTracing[] // retry detail - agentLog?: AgentLogItemWithChildren[] + retry_index?: number + parallelDetail?: { // parallel detail. if is in parallel, this field will be set + isParallelStartNode?: boolean + parallelTitle?: string + branchTitle?: string + children?: NodeTracing[] + } parallel_id?: string parallel_start_node_id?: string parent_parallel_id?: string parent_parallel_start_node_id?: string - retry_index?: number + agentLog?: AgentLogItemWithChildren[] // agent log } export type FetchWorkflowDraftResponse = {