use-checklist.ts 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. import {
  2. useCallback,
  3. useMemo,
  4. } from 'react'
  5. import { useTranslation } from 'react-i18next'
  6. import { useStoreApi } from 'reactflow'
  7. import type {
  8. Edge,
  9. Node,
  10. } from '../types'
  11. import { BlockEnum } from '../types'
  12. import { useStore } from '../store'
  13. import {
  14. getToolCheckParams,
  15. getValidTreeNodes,
  16. } from '../utils'
  17. import {
  18. CUSTOM_NODE,
  19. MAX_TREE_DEPTH,
  20. } from '../constants'
  21. import type { ToolNodeType } from '../nodes/tool/types'
  22. import { useIsChatMode } from './use-workflow'
  23. import { useNodesExtraData } from './use-nodes-data'
  24. import { useToastContext } from '@/app/components/base/toast'
  25. import { CollectionType } from '@/app/components/tools/types'
  26. import { useGetLanguage } from '@/context/i18n'
  27. import type { AgentNodeType } from '../nodes/agent/types'
  28. import { useStrategyProviders } from '@/service/use-strategy'
  29. import { canFindTool } from '@/utils'
  30. export const useChecklist = (nodes: Node[], edges: Edge[]) => {
  31. const { t } = useTranslation()
  32. const language = useGetLanguage()
  33. const nodesExtraData = useNodesExtraData()
  34. const isChatMode = useIsChatMode()
  35. const buildInTools = useStore(s => s.buildInTools)
  36. const customTools = useStore(s => s.customTools)
  37. const workflowTools = useStore(s => s.workflowTools)
  38. const { data: strategyProviders } = useStrategyProviders()
  39. const needWarningNodes = useMemo(() => {
  40. const list = []
  41. const { validNodes } = getValidTreeNodes(nodes.filter(node => node.type === CUSTOM_NODE), edges)
  42. for (let i = 0; i < nodes.length; i++) {
  43. const node = nodes[i]
  44. let toolIcon
  45. let moreDataForCheckValid
  46. if (node.data.type === BlockEnum.Tool) {
  47. const { provider_type } = node.data
  48. moreDataForCheckValid = getToolCheckParams(node.data as ToolNodeType, buildInTools, customTools, workflowTools, language)
  49. if (provider_type === CollectionType.builtIn)
  50. toolIcon = buildInTools.find(tool => canFindTool(tool.id, node.data.provider_id || ''))?.icon
  51. if (provider_type === CollectionType.custom)
  52. toolIcon = customTools.find(tool => tool.id === node.data.provider_id)?.icon
  53. if (provider_type === CollectionType.workflow)
  54. toolIcon = workflowTools.find(tool => tool.id === node.data.provider_id)?.icon
  55. }
  56. if (node.data.type === BlockEnum.Agent) {
  57. const data = node.data as AgentNodeType
  58. const isReadyForCheckValid = !!strategyProviders
  59. const provider = strategyProviders?.find(provider => provider.declaration.identity.name === data.agent_strategy_provider_name)
  60. const strategy = provider?.declaration.strategies?.find(s => s.identity.name === data.agent_strategy_name)
  61. moreDataForCheckValid = {
  62. provider,
  63. strategy,
  64. language,
  65. isReadyForCheckValid,
  66. }
  67. }
  68. if (node.type === CUSTOM_NODE) {
  69. const { errorMessage } = nodesExtraData[node.data.type].checkValid(node.data, t, moreDataForCheckValid)
  70. if (errorMessage || !validNodes.find(n => n.id === node.id)) {
  71. list.push({
  72. id: node.id,
  73. type: node.data.type,
  74. title: node.data.title,
  75. toolIcon,
  76. unConnected: !validNodes.find(n => n.id === node.id),
  77. errorMessage,
  78. })
  79. }
  80. }
  81. }
  82. if (isChatMode && !nodes.find(node => node.data.type === BlockEnum.Answer)) {
  83. list.push({
  84. id: 'answer-need-added',
  85. type: BlockEnum.Answer,
  86. title: t('workflow.blocks.answer'),
  87. errorMessage: t('workflow.common.needAnswerNode'),
  88. })
  89. }
  90. if (!isChatMode && !nodes.find(node => node.data.type === BlockEnum.End)) {
  91. list.push({
  92. id: 'end-need-added',
  93. type: BlockEnum.End,
  94. title: t('workflow.blocks.end'),
  95. errorMessage: t('workflow.common.needEndNode'),
  96. })
  97. }
  98. return list
  99. }, [nodes, edges, isChatMode, buildInTools, customTools, workflowTools, language, nodesExtraData, t, strategyProviders])
  100. return needWarningNodes
  101. }
  102. export const useChecklistBeforePublish = () => {
  103. const { t } = useTranslation()
  104. const language = useGetLanguage()
  105. const buildInTools = useStore(s => s.buildInTools)
  106. const customTools = useStore(s => s.customTools)
  107. const workflowTools = useStore(s => s.workflowTools)
  108. const { notify } = useToastContext()
  109. const isChatMode = useIsChatMode()
  110. const store = useStoreApi()
  111. const nodesExtraData = useNodesExtraData()
  112. const { data: strategyProviders } = useStrategyProviders()
  113. const handleCheckBeforePublish = useCallback(() => {
  114. const {
  115. getNodes,
  116. edges,
  117. } = store.getState()
  118. const nodes = getNodes().filter(node => node.type === CUSTOM_NODE)
  119. const {
  120. validNodes,
  121. maxDepth,
  122. } = getValidTreeNodes(nodes.filter(node => node.type === CUSTOM_NODE), edges)
  123. if (maxDepth > MAX_TREE_DEPTH) {
  124. notify({ type: 'error', message: t('workflow.common.maxTreeDepth', { depth: MAX_TREE_DEPTH }) })
  125. return false
  126. }
  127. for (let i = 0; i < nodes.length; i++) {
  128. const node = nodes[i]
  129. let moreDataForCheckValid
  130. if (node.data.type === BlockEnum.Tool)
  131. moreDataForCheckValid = getToolCheckParams(node.data as ToolNodeType, buildInTools, customTools, workflowTools, language)
  132. if (node.data.type === BlockEnum.Agent) {
  133. const data = node.data as AgentNodeType
  134. const isReadyForCheckValid = !!strategyProviders
  135. const provider = strategyProviders?.find(provider => provider.declaration.identity.name === data.agent_strategy_provider_name)
  136. const strategy = provider?.declaration.strategies?.find(s => s.identity.name === data.agent_strategy_name)
  137. moreDataForCheckValid = {
  138. provider,
  139. strategy,
  140. language,
  141. isReadyForCheckValid,
  142. }
  143. }
  144. const { errorMessage } = nodesExtraData[node.data.type as BlockEnum].checkValid(node.data, t, moreDataForCheckValid)
  145. if (errorMessage) {
  146. notify({ type: 'error', message: `[${node.data.title}] ${errorMessage}` })
  147. return false
  148. }
  149. if (!validNodes.find(n => n.id === node.id)) {
  150. notify({ type: 'error', message: `[${node.data.title}] ${t('workflow.common.needConnectTip')}` })
  151. return false
  152. }
  153. }
  154. if (isChatMode && !nodes.find(node => node.data.type === BlockEnum.Answer)) {
  155. notify({ type: 'error', message: t('workflow.common.needAnswerNode') })
  156. return false
  157. }
  158. if (!isChatMode && !nodes.find(node => node.data.type === BlockEnum.End)) {
  159. notify({ type: 'error', message: t('workflow.common.needEndNode') })
  160. return false
  161. }
  162. return true
  163. }, [store, isChatMode, notify, t, buildInTools, customTools, workflowTools, language, nodesExtraData, strategyProviders])
  164. return {
  165. handleCheckBeforePublish,
  166. }
  167. }