| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | import { | 
					
						
							|  |  |  |   useCallback, | 
					
						
							|  |  |  |   useMemo, | 
					
						
							| 
									
										
										
										
											2025-03-24 14:30:26 +08:00
										 |  |  |   useRef, | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | } from 'react' | 
					
						
							|  |  |  | import { useTranslation } from 'react-i18next' | 
					
						
							|  |  |  | import { useStoreApi } from 'reactflow' | 
					
						
							|  |  |  | import type { | 
					
						
							| 
									
										
										
										
											2025-03-24 14:30:26 +08:00
										 |  |  |   CommonNodeType, | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |   Edge, | 
					
						
							|  |  |  |   Node, | 
					
						
							|  |  |  | } from '../types' | 
					
						
							|  |  |  | import { BlockEnum } from '../types' | 
					
						
							|  |  |  | import { useStore } from '../store' | 
					
						
							|  |  |  | import { | 
					
						
							|  |  |  |   getToolCheckParams, | 
					
						
							|  |  |  |   getValidTreeNodes, | 
					
						
							|  |  |  | } from '../utils' | 
					
						
							| 
									
										
										
										
											2024-06-14 17:08:11 +08:00
										 |  |  | import { | 
					
						
							|  |  |  |   CUSTOM_NODE, | 
					
						
							| 
									
										
										
										
											2024-08-05 18:41:08 +08:00
										 |  |  |   MAX_TREE_DEPTH, | 
					
						
							| 
									
										
										
										
											2024-06-14 17:08:11 +08:00
										 |  |  | } from '../constants' | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | import type { ToolNodeType } from '../nodes/tool/types' | 
					
						
							|  |  |  | import { useIsChatMode } from './use-workflow' | 
					
						
							|  |  |  | import { useNodesExtraData } from './use-nodes-data' | 
					
						
							|  |  |  | import { useToastContext } from '@/app/components/base/toast' | 
					
						
							|  |  |  | import { CollectionType } from '@/app/components/tools/types' | 
					
						
							|  |  |  | import { useGetLanguage } from '@/context/i18n' | 
					
						
							| 
									
										
										
										
											2025-02-17 17:05:13 +08:00
										 |  |  | import type { AgentNodeType } from '../nodes/agent/types' | 
					
						
							|  |  |  | import { useStrategyProviders } from '@/service/use-strategy' | 
					
						
							| 
									
										
										
										
											2025-02-18 18:17:41 +08:00
										 |  |  | import { canFindTool } from '@/utils' | 
					
						
							| 
									
										
										
										
											2025-03-24 14:30:26 +08:00
										 |  |  | import { useDatasetsDetailStore } from '../datasets-detail-store/store' | 
					
						
							|  |  |  | import type { KnowledgeRetrievalNodeType } from '../nodes/knowledge-retrieval/types' | 
					
						
							|  |  |  | import type { DataSet } from '@/models/datasets' | 
					
						
							|  |  |  | import { fetchDatasets } from '@/service/datasets' | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | export const useChecklist = (nodes: Node[], edges: Edge[]) => { | 
					
						
							|  |  |  |   const { t } = useTranslation() | 
					
						
							|  |  |  |   const language = useGetLanguage() | 
					
						
							|  |  |  |   const nodesExtraData = useNodesExtraData() | 
					
						
							|  |  |  |   const isChatMode = useIsChatMode() | 
					
						
							|  |  |  |   const buildInTools = useStore(s => s.buildInTools) | 
					
						
							|  |  |  |   const customTools = useStore(s => s.customTools) | 
					
						
							| 
									
										
										
										
											2024-05-27 21:57:08 +08:00
										 |  |  |   const workflowTools = useStore(s => s.workflowTools) | 
					
						
							| 
									
										
										
										
											2025-02-17 17:05:13 +08:00
										 |  |  |   const { data: strategyProviders } = useStrategyProviders() | 
					
						
							| 
									
										
										
										
											2025-03-24 14:30:26 +08:00
										 |  |  |   const datasetsDetail = useDatasetsDetailStore(s => s.datasetsDetail) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const getCheckData = useCallback((data: CommonNodeType<{}>) => { | 
					
						
							|  |  |  |     let checkData = data | 
					
						
							|  |  |  |     if (data.type === BlockEnum.KnowledgeRetrieval) { | 
					
						
							|  |  |  |       const datasetIds = (data as CommonNodeType<KnowledgeRetrievalNodeType>).dataset_ids | 
					
						
							|  |  |  |       const _datasets = datasetIds.reduce<DataSet[]>((acc, id) => { | 
					
						
							|  |  |  |         if (datasetsDetail[id]) | 
					
						
							|  |  |  |           acc.push(datasetsDetail[id]) | 
					
						
							|  |  |  |         return acc | 
					
						
							|  |  |  |       }, []) | 
					
						
							|  |  |  |       checkData = { | 
					
						
							|  |  |  |         ...data, | 
					
						
							|  |  |  |         _datasets, | 
					
						
							|  |  |  |       } as CommonNodeType<KnowledgeRetrievalNodeType> | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return checkData | 
					
						
							|  |  |  |   }, [datasetsDetail]) | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   const needWarningNodes = useMemo(() => { | 
					
						
							|  |  |  |     const list = [] | 
					
						
							| 
									
										
										
										
											2025-05-15 22:39:35 +08:00
										 |  |  |     const { validNodes } = getValidTreeNodes(nodes.filter(node => node.type === CUSTOM_NODE), edges) | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for (let i = 0; i < nodes.length; i++) { | 
					
						
							|  |  |  |       const node = nodes[i] | 
					
						
							|  |  |  |       let toolIcon | 
					
						
							|  |  |  |       let moreDataForCheckValid | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (node.data.type === BlockEnum.Tool) { | 
					
						
							|  |  |  |         const { provider_type } = node.data | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-27 21:57:08 +08:00
										 |  |  |         moreDataForCheckValid = getToolCheckParams(node.data as ToolNodeType, buildInTools, customTools, workflowTools, language) | 
					
						
							|  |  |  |         if (provider_type === CollectionType.builtIn) | 
					
						
							| 
									
										
										
										
											2025-02-18 18:17:41 +08:00
										 |  |  |           toolIcon = buildInTools.find(tool => canFindTool(tool.id, node.data.provider_id || ''))?.icon | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-27 21:57:08 +08:00
										 |  |  |         if (provider_type === CollectionType.custom) | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |           toolIcon = customTools.find(tool => tool.id === node.data.provider_id)?.icon | 
					
						
							| 
									
										
										
										
											2024-05-27 21:57:08 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (provider_type === CollectionType.workflow) | 
					
						
							|  |  |  |           toolIcon = workflowTools.find(tool => tool.id === node.data.provider_id)?.icon | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2024-06-14 17:08:11 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-17 17:05:13 +08:00
										 |  |  |       if (node.data.type === BlockEnum.Agent) { | 
					
						
							|  |  |  |         const data = node.data as AgentNodeType | 
					
						
							|  |  |  |         const isReadyForCheckValid = !!strategyProviders | 
					
						
							|  |  |  |         const provider = strategyProviders?.find(provider => provider.declaration.identity.name === data.agent_strategy_provider_name) | 
					
						
							|  |  |  |         const strategy = provider?.declaration.strategies?.find(s => s.identity.name === data.agent_strategy_name) | 
					
						
							|  |  |  |         moreDataForCheckValid = { | 
					
						
							|  |  |  |           provider, | 
					
						
							|  |  |  |           strategy, | 
					
						
							|  |  |  |           language, | 
					
						
							|  |  |  |           isReadyForCheckValid, | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-14 17:08:11 +08:00
										 |  |  |       if (node.type === CUSTOM_NODE) { | 
					
						
							| 
									
										
										
										
											2025-03-24 14:30:26 +08:00
										 |  |  |         const checkData = getCheckData(node.data) | 
					
						
							|  |  |  |         const { errorMessage } = nodesExtraData[node.data.type].checkValid(checkData, t, moreDataForCheckValid) | 
					
						
							| 
									
										
										
										
											2024-06-14 17:08:11 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (errorMessage || !validNodes.find(n => n.id === node.id)) { | 
					
						
							|  |  |  |           list.push({ | 
					
						
							|  |  |  |             id: node.id, | 
					
						
							|  |  |  |             type: node.data.type, | 
					
						
							|  |  |  |             title: node.data.title, | 
					
						
							|  |  |  |             toolIcon, | 
					
						
							|  |  |  |             unConnected: !validNodes.find(n => n.id === node.id), | 
					
						
							|  |  |  |             errorMessage, | 
					
						
							|  |  |  |           }) | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (isChatMode && !nodes.find(node => node.data.type === BlockEnum.Answer)) { | 
					
						
							|  |  |  |       list.push({ | 
					
						
							|  |  |  |         id: 'answer-need-added', | 
					
						
							|  |  |  |         type: BlockEnum.Answer, | 
					
						
							|  |  |  |         title: t('workflow.blocks.answer'), | 
					
						
							|  |  |  |         errorMessage: t('workflow.common.needAnswerNode'), | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!isChatMode && !nodes.find(node => node.data.type === BlockEnum.End)) { | 
					
						
							|  |  |  |       list.push({ | 
					
						
							|  |  |  |         id: 'end-need-added', | 
					
						
							|  |  |  |         type: BlockEnum.End, | 
					
						
							|  |  |  |         title: t('workflow.blocks.end'), | 
					
						
							|  |  |  |         errorMessage: t('workflow.common.needEndNode'), | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return list | 
					
						
							| 
									
										
										
										
											2025-05-15 22:39:35 +08:00
										 |  |  |   }, [nodes, edges, isChatMode, buildInTools, customTools, workflowTools, language, nodesExtraData, t, strategyProviders, getCheckData]) | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return needWarningNodes | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export const useChecklistBeforePublish = () => { | 
					
						
							|  |  |  |   const { t } = useTranslation() | 
					
						
							|  |  |  |   const language = useGetLanguage() | 
					
						
							|  |  |  |   const buildInTools = useStore(s => s.buildInTools) | 
					
						
							|  |  |  |   const customTools = useStore(s => s.customTools) | 
					
						
							| 
									
										
										
										
											2024-05-27 21:57:08 +08:00
										 |  |  |   const workflowTools = useStore(s => s.workflowTools) | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |   const { notify } = useToastContext() | 
					
						
							|  |  |  |   const isChatMode = useIsChatMode() | 
					
						
							|  |  |  |   const store = useStoreApi() | 
					
						
							|  |  |  |   const nodesExtraData = useNodesExtraData() | 
					
						
							| 
									
										
										
										
											2025-02-17 17:05:13 +08:00
										 |  |  |   const { data: strategyProviders } = useStrategyProviders() | 
					
						
							| 
									
										
										
										
											2025-03-24 14:30:26 +08:00
										 |  |  |   const updateDatasetsDetail = useDatasetsDetailStore(s => s.updateDatasetsDetail) | 
					
						
							|  |  |  |   const updateTime = useRef(0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const getCheckData = useCallback((data: CommonNodeType<{}>, datasets: DataSet[]) => { | 
					
						
							|  |  |  |     let checkData = data | 
					
						
							|  |  |  |     if (data.type === BlockEnum.KnowledgeRetrieval) { | 
					
						
							|  |  |  |       const datasetIds = (data as CommonNodeType<KnowledgeRetrievalNodeType>).dataset_ids | 
					
						
							|  |  |  |       const datasetsDetail = datasets.reduce<Record<string, DataSet>>((acc, dataset) => { | 
					
						
							|  |  |  |         acc[dataset.id] = dataset | 
					
						
							|  |  |  |         return acc | 
					
						
							|  |  |  |       }, {}) | 
					
						
							|  |  |  |       const _datasets = datasetIds.reduce<DataSet[]>((acc, id) => { | 
					
						
							|  |  |  |         if (datasetsDetail[id]) | 
					
						
							|  |  |  |           acc.push(datasetsDetail[id]) | 
					
						
							|  |  |  |         return acc | 
					
						
							|  |  |  |       }, []) | 
					
						
							|  |  |  |       checkData = { | 
					
						
							|  |  |  |         ...data, | 
					
						
							|  |  |  |         _datasets, | 
					
						
							|  |  |  |       } as CommonNodeType<KnowledgeRetrievalNodeType> | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return checkData | 
					
						
							|  |  |  |   }, []) | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-24 14:30:26 +08:00
										 |  |  |   const handleCheckBeforePublish = useCallback(async () => { | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |     const { | 
					
						
							|  |  |  |       getNodes, | 
					
						
							|  |  |  |       edges, | 
					
						
							|  |  |  |     } = store.getState() | 
					
						
							| 
									
										
										
										
											2024-06-14 17:08:11 +08:00
										 |  |  |     const nodes = getNodes().filter(node => node.type === CUSTOM_NODE) | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |     const { | 
					
						
							|  |  |  |       validNodes, | 
					
						
							|  |  |  |       maxDepth, | 
					
						
							| 
									
										
										
										
											2025-05-15 22:39:35 +08:00
										 |  |  |     } = getValidTreeNodes(nodes.filter(node => node.type === CUSTOM_NODE), edges) | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-05 18:41:08 +08:00
										 |  |  |     if (maxDepth > MAX_TREE_DEPTH) { | 
					
						
							|  |  |  |       notify({ type: 'error', message: t('workflow.common.maxTreeDepth', { depth: MAX_TREE_DEPTH }) }) | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |       return false | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2025-03-24 14:30:26 +08:00
										 |  |  |     // Before publish, we need to fetch datasets detail, in case of the settings of datasets have been changed
 | 
					
						
							|  |  |  |     const knowledgeRetrievalNodes = nodes.filter(node => node.data.type === BlockEnum.KnowledgeRetrieval) | 
					
						
							|  |  |  |     const allDatasetIds = knowledgeRetrievalNodes.reduce<string[]>((acc, node) => { | 
					
						
							|  |  |  |       return Array.from(new Set([...acc, ...(node.data as CommonNodeType<KnowledgeRetrievalNodeType>).dataset_ids])) | 
					
						
							|  |  |  |     }, []) | 
					
						
							|  |  |  |     let datasets: DataSet[] = [] | 
					
						
							|  |  |  |     if (allDatasetIds.length > 0) { | 
					
						
							|  |  |  |       updateTime.current = updateTime.current + 1 | 
					
						
							|  |  |  |       const currUpdateTime = updateTime.current | 
					
						
							|  |  |  |       const { data: datasetsDetail } = await fetchDatasets({ url: '/datasets', params: { page: 1, ids: allDatasetIds } }) | 
					
						
							|  |  |  |       if (datasetsDetail && datasetsDetail.length > 0) { | 
					
						
							|  |  |  |         // avoid old data to overwrite the new data
 | 
					
						
							|  |  |  |         if (currUpdateTime < updateTime.current) | 
					
						
							|  |  |  |           return false | 
					
						
							|  |  |  |         datasets = datasetsDetail | 
					
						
							|  |  |  |         updateDatasetsDetail(datasetsDetail) | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for (let i = 0; i < nodes.length; i++) { | 
					
						
							|  |  |  |       const node = nodes[i] | 
					
						
							|  |  |  |       let moreDataForCheckValid | 
					
						
							|  |  |  |       if (node.data.type === BlockEnum.Tool) | 
					
						
							| 
									
										
										
										
											2024-05-27 21:57:08 +08:00
										 |  |  |         moreDataForCheckValid = getToolCheckParams(node.data as ToolNodeType, buildInTools, customTools, workflowTools, language) | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-17 17:05:13 +08:00
										 |  |  |       if (node.data.type === BlockEnum.Agent) { | 
					
						
							|  |  |  |         const data = node.data as AgentNodeType | 
					
						
							|  |  |  |         const isReadyForCheckValid = !!strategyProviders | 
					
						
							|  |  |  |         const provider = strategyProviders?.find(provider => provider.declaration.identity.name === data.agent_strategy_provider_name) | 
					
						
							|  |  |  |         const strategy = provider?.declaration.strategies?.find(s => s.identity.name === data.agent_strategy_name) | 
					
						
							|  |  |  |         moreDataForCheckValid = { | 
					
						
							|  |  |  |           provider, | 
					
						
							|  |  |  |           strategy, | 
					
						
							|  |  |  |           language, | 
					
						
							|  |  |  |           isReadyForCheckValid, | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-24 14:30:26 +08:00
										 |  |  |       const checkData = getCheckData(node.data, datasets) | 
					
						
							|  |  |  |       const { errorMessage } = nodesExtraData[node.data.type as BlockEnum].checkValid(checkData, t, moreDataForCheckValid) | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |       if (errorMessage) { | 
					
						
							|  |  |  |         notify({ type: 'error', message: `[${node.data.title}] ${errorMessage}` }) | 
					
						
							|  |  |  |         return false | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (!validNodes.find(n => n.id === node.id)) { | 
					
						
							| 
									
										
										
										
											2024-09-07 15:59:38 +07:00
										 |  |  |         notify({ type: 'error', message: `[${node.data.title}] ${t('workflow.common.needConnectTip')}` }) | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |         return false | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (isChatMode && !nodes.find(node => node.data.type === BlockEnum.Answer)) { | 
					
						
							|  |  |  |       notify({ type: 'error', message: t('workflow.common.needAnswerNode') }) | 
					
						
							|  |  |  |       return false | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!isChatMode && !nodes.find(node => node.data.type === BlockEnum.End)) { | 
					
						
							|  |  |  |       notify({ type: 'error', message: t('workflow.common.needEndNode') }) | 
					
						
							|  |  |  |       return false | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return true | 
					
						
							| 
									
										
										
										
											2025-05-15 22:39:35 +08:00
										 |  |  |   }, [store, isChatMode, notify, t, buildInTools, customTools, workflowTools, language, nodesExtraData, strategyProviders, updateDatasetsDetail, getCheckData]) | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   return { | 
					
						
							|  |  |  |     handleCheckBeforePublish, | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } |