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-config.ts 7.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. import { useCallback, useEffect, useMemo, useState } from 'react'
  2. import { useTranslation } from 'react-i18next'
  3. import produce from 'immer'
  4. import { useBoolean } from 'ahooks'
  5. import { useStore } from '../../store'
  6. import type { ToolNodeType, ToolVarInputs } from './types'
  7. import { useLanguage } from '@/app/components/header/account-setting/model-provider-page/hooks'
  8. import useNodeCrud from '@/app/components/workflow/nodes/_base/hooks/use-node-crud'
  9. import { CollectionType } from '@/app/components/tools/types'
  10. import { updateBuiltInToolCredential } from '@/service/tools'
  11. import {
  12. getConfiguredValue,
  13. toolParametersToFormSchemas,
  14. } from '@/app/components/tools/utils/to-form-schema'
  15. import Toast from '@/app/components/base/toast'
  16. import type { InputVar } from '@/app/components/workflow/types'
  17. import {
  18. useFetchToolsData,
  19. useNodesReadOnly,
  20. } from '@/app/components/workflow/hooks'
  21. import { canFindTool } from '@/utils'
  22. const useConfig = (id: string, payload: ToolNodeType) => {
  23. const { nodesReadOnly: readOnly } = useNodesReadOnly()
  24. const { handleFetchAllTools } = useFetchToolsData()
  25. const { t } = useTranslation()
  26. const language = useLanguage()
  27. const { inputs, setInputs: doSetInputs } = useNodeCrud<ToolNodeType>(id, payload)
  28. /*
  29. * tool_configurations: tool setting, not dynamic setting (form type = form)
  30. * tool_parameters: tool dynamic setting(form type = llm)
  31. * output_schema: tool dynamic output
  32. */
  33. const { provider_id, provider_type, tool_name, tool_configurations, output_schema, tool_parameters } = inputs
  34. const isBuiltIn = provider_type === CollectionType.builtIn
  35. const buildInTools = useStore(s => s.buildInTools)
  36. const customTools = useStore(s => s.customTools)
  37. const workflowTools = useStore(s => s.workflowTools)
  38. const mcpTools = useStore(s => s.mcpTools)
  39. const currentTools = useMemo(() => {
  40. switch (provider_type) {
  41. case CollectionType.builtIn:
  42. return buildInTools
  43. case CollectionType.custom:
  44. return customTools
  45. case CollectionType.workflow:
  46. return workflowTools
  47. case CollectionType.mcp:
  48. return mcpTools
  49. default:
  50. return []
  51. }
  52. }, [buildInTools, customTools, mcpTools, provider_type, workflowTools])
  53. const currCollection = currentTools.find(item => canFindTool(item.id, provider_id))
  54. // Auth
  55. const needAuth = !!currCollection?.allow_delete
  56. const isAuthed = !!currCollection?.is_team_authorization
  57. const isShowAuthBtn = isBuiltIn && needAuth && !isAuthed
  58. const [showSetAuth, {
  59. setTrue: showSetAuthModal,
  60. setFalse: hideSetAuthModal,
  61. }] = useBoolean(false)
  62. const handleSaveAuth = useCallback(async (value: any) => {
  63. await updateBuiltInToolCredential(currCollection?.name as string, value)
  64. Toast.notify({
  65. type: 'success',
  66. message: t('common.api.actionSuccess'),
  67. })
  68. handleFetchAllTools(provider_type)
  69. hideSetAuthModal()
  70. }, [currCollection?.name, hideSetAuthModal, t, handleFetchAllTools, provider_type])
  71. const currTool = currCollection?.tools.find(tool => tool.name === tool_name)
  72. const formSchemas = useMemo(() => {
  73. return currTool ? toolParametersToFormSchemas(currTool.parameters) : []
  74. }, [currTool])
  75. const toolInputVarSchema = formSchemas.filter((item: any) => item.form === 'llm')
  76. // use setting
  77. const toolSettingSchema = formSchemas.filter((item: any) => item.form !== 'llm')
  78. const hasShouldTransferTypeSettingInput = toolSettingSchema.some(item => item.type === 'boolean' || item.type === 'number-input')
  79. const setInputs = useCallback((value: ToolNodeType) => {
  80. if (!hasShouldTransferTypeSettingInput) {
  81. doSetInputs(value)
  82. return
  83. }
  84. const newInputs = produce(value, (draft) => {
  85. const newConfig = { ...draft.tool_configurations }
  86. Object.keys(draft.tool_configurations).forEach((key) => {
  87. const schema = formSchemas.find(item => item.variable === key)
  88. const value = newConfig[key]
  89. if (schema?.type === 'boolean') {
  90. if (typeof value === 'string')
  91. newConfig[key] = value === 'true' || value === '1'
  92. if (typeof value === 'number')
  93. newConfig[key] = value === 1
  94. }
  95. if (schema?.type === 'number-input') {
  96. if (typeof value === 'string' && value !== '')
  97. newConfig[key] = Number.parseFloat(value)
  98. }
  99. })
  100. draft.tool_configurations = newConfig
  101. })
  102. doSetInputs(newInputs)
  103. }, [doSetInputs, formSchemas, hasShouldTransferTypeSettingInput])
  104. const [notSetDefaultValue, setNotSetDefaultValue] = useState(false)
  105. const toolSettingValue = useMemo(() => {
  106. if (notSetDefaultValue)
  107. return tool_configurations
  108. return getConfiguredValue(tool_configurations, toolSettingSchema)
  109. }, [notSetDefaultValue, toolSettingSchema, tool_configurations])
  110. const setToolSettingValue = useCallback((value: Record<string, any>) => {
  111. setNotSetDefaultValue(true)
  112. setInputs({
  113. ...inputs,
  114. tool_configurations: value,
  115. })
  116. }, [inputs, setInputs])
  117. const formattingParameters = () => {
  118. const inputsWithDefaultValue = produce(inputs, (draft) => {
  119. if (!draft.tool_configurations || Object.keys(draft.tool_configurations).length === 0)
  120. draft.tool_configurations = getConfiguredValue(tool_configurations, toolSettingSchema)
  121. if (!draft.tool_parameters || Object.keys(draft.tool_parameters).length === 0)
  122. draft.tool_parameters = getConfiguredValue(tool_parameters, toolInputVarSchema)
  123. })
  124. return inputsWithDefaultValue
  125. }
  126. useEffect(() => {
  127. if (!currTool)
  128. return
  129. const inputsWithDefaultValue = formattingParameters()
  130. setInputs(inputsWithDefaultValue)
  131. // eslint-disable-next-line react-hooks/exhaustive-deps
  132. }, [currTool])
  133. // setting when call
  134. const setInputVar = useCallback((value: ToolVarInputs) => {
  135. setInputs({
  136. ...inputs,
  137. tool_parameters: value,
  138. })
  139. }, [inputs, setInputs])
  140. const isLoading = currTool && (isBuiltIn ? !currCollection : false)
  141. const getMoreDataForCheckValid = () => {
  142. return {
  143. toolInputsSchema: (() => {
  144. const formInputs: InputVar[] = []
  145. toolInputVarSchema.forEach((item: any) => {
  146. formInputs.push({
  147. label: item.label[language] || item.label.en_US,
  148. variable: item.variable,
  149. type: item.type,
  150. required: item.required,
  151. })
  152. })
  153. return formInputs
  154. })(),
  155. notAuthed: isShowAuthBtn,
  156. toolSettingSchema,
  157. language,
  158. }
  159. }
  160. const outputSchema = useMemo(() => {
  161. const res: any[] = []
  162. if (!output_schema)
  163. return []
  164. Object.keys(output_schema.properties).forEach((outputKey) => {
  165. const output = output_schema.properties[outputKey]
  166. const type = output.type
  167. if (type === 'object') {
  168. res.push({
  169. name: outputKey,
  170. value: output,
  171. })
  172. }
  173. else {
  174. res.push({
  175. name: outputKey,
  176. type: output.type === 'array'
  177. ? `Array[${output.items?.type.slice(0, 1).toLocaleUpperCase()}${output.items?.type.slice(1)}]`
  178. : `${output.type.slice(0, 1).toLocaleUpperCase()}${output.type.slice(1)}`,
  179. description: output.description,
  180. })
  181. }
  182. })
  183. return res
  184. }, [output_schema])
  185. const hasObjectOutput = useMemo(() => {
  186. if (!output_schema)
  187. return false
  188. const properties = output_schema.properties
  189. return Object.keys(properties).some(key => properties[key].type === 'object')
  190. }, [output_schema])
  191. return {
  192. readOnly,
  193. inputs,
  194. currTool,
  195. toolSettingSchema,
  196. toolSettingValue,
  197. setToolSettingValue,
  198. toolInputVarSchema,
  199. setInputVar,
  200. currCollection,
  201. isShowAuthBtn,
  202. showSetAuth,
  203. showSetAuthModal,
  204. hideSetAuthModal,
  205. handleSaveAuth,
  206. isLoading,
  207. outputSchema,
  208. hasObjectOutput,
  209. getMoreDataForCheckValid,
  210. }
  211. }
  212. export default useConfig