use-checklist.ts 6.6 KB

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