You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

use-inspect-vars-crud-common.ts 9.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. import { fetchNodeInspectVars } from '@/service/workflow'
  2. import { useWorkflowStore } from '@/app/components/workflow/store'
  3. import type { ValueSelector } from '@/app/components/workflow/types'
  4. import type { VarInInspect } from '@/types/workflow'
  5. import { VarInInspectType } from '@/types/workflow'
  6. import { useCallback } from 'react'
  7. import {
  8. isConversationVar,
  9. isENV,
  10. isSystemVar,
  11. toNodeOutputVars,
  12. } from '@/app/components/workflow/nodes/_base/components/variable/utils'
  13. import produce from 'immer'
  14. import type { Node } from '@/app/components/workflow/types'
  15. import { useNodesInteractionsWithoutSync } from '@/app/components/workflow/hooks/use-nodes-interactions-without-sync'
  16. import { useEdgesInteractionsWithoutSync } from '@/app/components/workflow/hooks/use-edges-interactions-without-sync'
  17. import type { FlowType } from '@/types/common'
  18. import useFLow from '@/service/use-flow'
  19. import useMatchSchemaType from '../nodes/_base/components/variable/use-match-schema-type'
  20. import { useStoreApi } from 'reactflow'
  21. type Params = {
  22. flowId: string
  23. flowType: FlowType
  24. }
  25. export const useInspectVarsCrudCommon = ({
  26. flowId,
  27. flowType,
  28. }: Params) => {
  29. const workflowStore = useWorkflowStore()
  30. const store = useStoreApi()
  31. const { schemaTypeDefinitions } = useMatchSchemaType()
  32. const {
  33. useInvalidateConversationVarValues,
  34. useInvalidateSysVarValues,
  35. useResetConversationVar,
  36. useResetToLastRunValue,
  37. useDeleteAllInspectorVars,
  38. useDeleteNodeInspectorVars,
  39. useDeleteInspectVar,
  40. useEditInspectorVar,
  41. } = useFLow({ flowType })
  42. const invalidateConversationVarValues = useInvalidateConversationVarValues(flowId)
  43. const { mutateAsync: doResetConversationVar } = useResetConversationVar(flowId)
  44. const { mutateAsync: doResetToLastRunValue } = useResetToLastRunValue(flowId)
  45. const invalidateSysVarValues = useInvalidateSysVarValues(flowId)
  46. const { mutateAsync: doDeleteAllInspectorVars } = useDeleteAllInspectorVars(flowId)
  47. const { mutate: doDeleteNodeInspectorVars } = useDeleteNodeInspectorVars(flowId)
  48. const { mutate: doDeleteInspectVar } = useDeleteInspectVar(flowId)
  49. const { mutateAsync: doEditInspectorVar } = useEditInspectorVar(flowId)
  50. const { handleCancelNodeSuccessStatus } = useNodesInteractionsWithoutSync()
  51. const { handleEdgeCancelRunningStatus } = useEdgesInteractionsWithoutSync()
  52. const getNodeInspectVars = useCallback((nodeId: string) => {
  53. const { nodesWithInspectVars } = workflowStore.getState()
  54. const node = nodesWithInspectVars.find(node => node.nodeId === nodeId)
  55. return node
  56. }, [workflowStore])
  57. const getVarId = useCallback((nodeId: string, varName: string) => {
  58. const node = getNodeInspectVars(nodeId)
  59. if (!node)
  60. return undefined
  61. const varId = node.vars.find((varItem) => {
  62. return varItem.selector[1] === varName
  63. })?.id
  64. return varId
  65. }, [getNodeInspectVars])
  66. const getInspectVar = useCallback((nodeId: string, name: string): VarInInspect | undefined => {
  67. const node = getNodeInspectVars(nodeId)
  68. if (!node)
  69. return undefined
  70. const variable = node.vars.find((varItem) => {
  71. return varItem.name === name
  72. })
  73. return variable
  74. }, [getNodeInspectVars])
  75. const hasSetInspectVar = useCallback((nodeId: string, name: string, sysVars: VarInInspect[], conversationVars: VarInInspect[]) => {
  76. const isEnv = isENV([nodeId])
  77. if (isEnv) // always have value
  78. return true
  79. const isSys = isSystemVar([nodeId])
  80. if (isSys)
  81. return sysVars.some(varItem => varItem.selector?.[1]?.replace('sys.', '') === name)
  82. const isChatVar = isConversationVar([nodeId])
  83. if (isChatVar)
  84. return conversationVars.some(varItem => varItem.selector?.[1] === name)
  85. return getInspectVar(nodeId, name) !== undefined
  86. }, [getInspectVar])
  87. const hasNodeInspectVars = useCallback((nodeId: string) => {
  88. return !!getNodeInspectVars(nodeId)
  89. }, [getNodeInspectVars])
  90. const fetchInspectVarValue = useCallback(async (selector: ValueSelector) => {
  91. const {
  92. setNodeInspectVars,
  93. buildInTools,
  94. customTools,
  95. workflowTools,
  96. mcpTools,
  97. dataSourceList,
  98. } = workflowStore.getState()
  99. const nodeId = selector[0]
  100. const isSystemVar = nodeId === 'sys'
  101. const isConversationVar = nodeId === 'conversation'
  102. if (isSystemVar) {
  103. invalidateSysVarValues()
  104. return
  105. }
  106. if (isConversationVar) {
  107. invalidateConversationVarValues()
  108. return
  109. }
  110. const { getNodes } = store.getState()
  111. const nodeArr = getNodes()
  112. const currentNode = nodeArr.find(node => node.id === nodeId)
  113. const allPluginInfoList = {
  114. buildInTools,
  115. customTools,
  116. workflowTools,
  117. mcpTools,
  118. dataSourceList: dataSourceList ?? [],
  119. }
  120. const currentNodeOutputVars = toNodeOutputVars([currentNode], false, () => true, [], [], [], allPluginInfoList, schemaTypeDefinitions)
  121. const vars = await fetchNodeInspectVars(flowType, flowId, nodeId)
  122. const varsWithSchemaType = vars.map((varItem) => {
  123. const schemaType = currentNodeOutputVars[0].vars.find(v => v.variable === varItem.name)?.schemaType || ''
  124. return {
  125. ...varItem,
  126. schemaType,
  127. }
  128. })
  129. setNodeInspectVars(nodeId, varsWithSchemaType)
  130. }, [workflowStore, flowType, flowId, invalidateSysVarValues, invalidateConversationVarValues])
  131. // after last run would call this
  132. const appendNodeInspectVars = useCallback((nodeId: string, payload: VarInInspect[], allNodes: Node[]) => {
  133. const {
  134. nodesWithInspectVars,
  135. setNodesWithInspectVars,
  136. } = workflowStore.getState()
  137. const nodes = produce(nodesWithInspectVars, (draft) => {
  138. const nodeInfo = allNodes.find(node => node.id === nodeId)
  139. if (nodeInfo) {
  140. const index = draft.findIndex(node => node.nodeId === nodeId)
  141. if (index === -1) {
  142. draft.unshift({
  143. nodeId,
  144. nodeType: nodeInfo.data.type,
  145. title: nodeInfo.data.title,
  146. vars: payload,
  147. nodePayload: nodeInfo.data,
  148. })
  149. }
  150. else {
  151. draft[index].vars = payload
  152. // put the node to the topAdd commentMore actions
  153. draft.unshift(draft.splice(index, 1)[0])
  154. }
  155. }
  156. })
  157. setNodesWithInspectVars(nodes)
  158. handleCancelNodeSuccessStatus(nodeId)
  159. }, [workflowStore, handleCancelNodeSuccessStatus])
  160. const hasNodeInspectVar = useCallback((nodeId: string, varId: string) => {
  161. const { nodesWithInspectVars } = workflowStore.getState()
  162. const targetNode = nodesWithInspectVars.find(item => item.nodeId === nodeId)
  163. if (!targetNode || !targetNode.vars)
  164. return false
  165. return targetNode.vars.some(item => item.id === varId)
  166. }, [workflowStore])
  167. const deleteInspectVar = useCallback(async (nodeId: string, varId: string) => {
  168. const { deleteInspectVar } = workflowStore.getState()
  169. if (hasNodeInspectVar(nodeId, varId)) {
  170. await doDeleteInspectVar(varId)
  171. deleteInspectVar(nodeId, varId)
  172. }
  173. }, [doDeleteInspectVar, workflowStore, hasNodeInspectVar])
  174. const resetConversationVar = useCallback(async (varId: string) => {
  175. await doResetConversationVar(varId)
  176. invalidateConversationVarValues()
  177. }, [doResetConversationVar, invalidateConversationVarValues])
  178. const deleteNodeInspectorVars = useCallback(async (nodeId: string) => {
  179. const { deleteNodeInspectVars } = workflowStore.getState()
  180. if (hasNodeInspectVars(nodeId)) {
  181. await doDeleteNodeInspectorVars(nodeId)
  182. deleteNodeInspectVars(nodeId)
  183. }
  184. }, [doDeleteNodeInspectorVars, workflowStore, hasNodeInspectVars])
  185. const deleteAllInspectorVars = useCallback(async () => {
  186. const { deleteAllInspectVars } = workflowStore.getState()
  187. await doDeleteAllInspectorVars()
  188. await invalidateConversationVarValues()
  189. await invalidateSysVarValues()
  190. deleteAllInspectVars()
  191. handleEdgeCancelRunningStatus()
  192. }, [doDeleteAllInspectorVars, invalidateConversationVarValues, invalidateSysVarValues, workflowStore, handleEdgeCancelRunningStatus])
  193. const editInspectVarValue = useCallback(async (nodeId: string, varId: string, value: any) => {
  194. const { setInspectVarValue } = workflowStore.getState()
  195. await doEditInspectorVar({
  196. varId,
  197. value,
  198. })
  199. setInspectVarValue(nodeId, varId, value)
  200. if (nodeId === VarInInspectType.conversation)
  201. invalidateConversationVarValues()
  202. if (nodeId === VarInInspectType.system)
  203. invalidateSysVarValues()
  204. }, [doEditInspectorVar, invalidateConversationVarValues, invalidateSysVarValues, workflowStore])
  205. const renameInspectVarName = useCallback(async (nodeId: string, oldName: string, newName: string) => {
  206. const { renameInspectVarName } = workflowStore.getState()
  207. const varId = getVarId(nodeId, oldName)
  208. if (!varId)
  209. return
  210. const newSelector = [nodeId, newName]
  211. await doEditInspectorVar({
  212. varId,
  213. name: newName,
  214. })
  215. renameInspectVarName(nodeId, varId, newSelector)
  216. }, [doEditInspectorVar, getVarId, workflowStore])
  217. const isInspectVarEdited = useCallback((nodeId: string, name: string) => {
  218. const inspectVar = getInspectVar(nodeId, name)
  219. if (!inspectVar)
  220. return false
  221. return inspectVar.edited
  222. }, [getInspectVar])
  223. const resetToLastRunVar = useCallback(async (nodeId: string, varId: string) => {
  224. const { resetToLastRunVar } = workflowStore.getState()
  225. const isSysVar = nodeId === 'sys'
  226. const data = await doResetToLastRunValue(varId)
  227. if (isSysVar)
  228. invalidateSysVarValues()
  229. else
  230. resetToLastRunVar(nodeId, varId, data.value)
  231. }, [doResetToLastRunValue, invalidateSysVarValues, workflowStore])
  232. return {
  233. hasNodeInspectVars,
  234. hasSetInspectVar,
  235. fetchInspectVarValue,
  236. editInspectVarValue,
  237. renameInspectVarName,
  238. appendNodeInspectVars,
  239. deleteInspectVar,
  240. deleteNodeInspectorVars,
  241. deleteAllInspectorVars,
  242. isInspectVarEdited,
  243. resetToLastRunVar,
  244. invalidateSysVarValues,
  245. resetConversationVar,
  246. invalidateConversationVarValues,
  247. }
  248. }