| 
									
										
										
										
											2024-04-12 15:46:34 +08:00
										 |  |  | import { useCallback, useEffect, useMemo, useState } from 'react' | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | import { useTranslation } from 'react-i18next' | 
					
						
							|  |  |  | import produce from 'immer' | 
					
						
							|  |  |  | import { useBoolean } from 'ahooks' | 
					
						
							|  |  |  | import { useStore } from '../../store' | 
					
						
							|  |  |  | import { type ToolNodeType, type ToolVarInputs, VarType } from './types' | 
					
						
							|  |  |  | import { useLanguage } from '@/app/components/header/account-setting/model-provider-page/hooks' | 
					
						
							|  |  |  | import useNodeCrud from '@/app/components/workflow/nodes/_base/hooks/use-node-crud' | 
					
						
							|  |  |  | import { CollectionType } from '@/app/components/tools/types' | 
					
						
							|  |  |  | import { updateBuiltInToolCredential } from '@/service/tools' | 
					
						
							|  |  |  | import { addDefaultValue, toolParametersToFormSchemas } from '@/app/components/tools/utils/to-form-schema' | 
					
						
							|  |  |  | import Toast from '@/app/components/base/toast' | 
					
						
							|  |  |  | import type { Props as FormProps } from '@/app/components/workflow/nodes/_base/components/before-run-form/form' | 
					
						
							|  |  |  | import { VarType as VarVarType } from '@/app/components/workflow/types' | 
					
						
							|  |  |  | import type { InputVar, ValueSelector, Var } from '@/app/components/workflow/types' | 
					
						
							|  |  |  | import useOneStepRun from '@/app/components/workflow/nodes/_base/hooks/use-one-step-run' | 
					
						
							|  |  |  | import { | 
					
						
							|  |  |  |   useFetchToolsData, | 
					
						
							|  |  |  |   useNodesReadOnly, | 
					
						
							|  |  |  | } from '@/app/components/workflow/hooks' | 
					
						
							| 
									
										
										
										
											2025-02-18 18:17:41 +08:00
										 |  |  | import { canFindTool } from '@/utils' | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | const useConfig = (id: string, payload: ToolNodeType) => { | 
					
						
							|  |  |  |   const { nodesReadOnly: readOnly } = useNodesReadOnly() | 
					
						
							|  |  |  |   const { handleFetchAllTools } = useFetchToolsData() | 
					
						
							|  |  |  |   const { t } = useTranslation() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const language = useLanguage() | 
					
						
							| 
									
										
										
										
											2024-04-12 15:46:34 +08:00
										 |  |  |   const { inputs, setInputs: doSetInputs } = useNodeCrud<ToolNodeType>(id, payload) | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |   /* | 
					
						
							|  |  |  |   * tool_configurations: tool setting, not dynamic setting | 
					
						
							|  |  |  |   * tool_parameters: tool dynamic setting(by user) | 
					
						
							| 
									
										
										
										
											2025-02-17 17:05:13 +08:00
										 |  |  |   * output_schema: tool dynamic output | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |   */ | 
					
						
							| 
									
										
										
										
											2025-02-17 17:05:13 +08:00
										 |  |  |   const { provider_id, provider_type, tool_name, tool_configurations, output_schema } = inputs | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |   const isBuiltIn = provider_type === CollectionType.builtIn | 
					
						
							|  |  |  |   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) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const currentTools = (() => { | 
					
						
							|  |  |  |     switch (provider_type) { | 
					
						
							|  |  |  |       case CollectionType.builtIn: | 
					
						
							|  |  |  |         return buildInTools | 
					
						
							|  |  |  |       case CollectionType.custom: | 
					
						
							|  |  |  |         return customTools | 
					
						
							|  |  |  |       case CollectionType.workflow: | 
					
						
							|  |  |  |         return workflowTools | 
					
						
							|  |  |  |       default: | 
					
						
							|  |  |  |         return [] | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   })() | 
					
						
							| 
									
										
										
										
											2025-02-18 18:17:41 +08:00
										 |  |  |   const currCollection = currentTools.find(item => canFindTool(item.id, provider_id)) | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |   // Auth
 | 
					
						
							|  |  |  |   const needAuth = !!currCollection?.allow_delete | 
					
						
							|  |  |  |   const isAuthed = !!currCollection?.is_team_authorization | 
					
						
							|  |  |  |   const isShowAuthBtn = isBuiltIn && needAuth && !isAuthed | 
					
						
							|  |  |  |   const [showSetAuth, { | 
					
						
							|  |  |  |     setTrue: showSetAuthModal, | 
					
						
							|  |  |  |     setFalse: hideSetAuthModal, | 
					
						
							|  |  |  |   }] = useBoolean(false) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const handleSaveAuth = useCallback(async (value: any) => { | 
					
						
							|  |  |  |     await updateBuiltInToolCredential(currCollection?.name as string, value) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Toast.notify({ | 
					
						
							|  |  |  |       type: 'success', | 
					
						
							|  |  |  |       message: t('common.api.actionSuccess'), | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  |     handleFetchAllTools(provider_type) | 
					
						
							|  |  |  |     hideSetAuthModal() | 
					
						
							|  |  |  |   }, [currCollection?.name, hideSetAuthModal, t, handleFetchAllTools, provider_type]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const currTool = currCollection?.tools.find(tool => tool.name === tool_name) | 
					
						
							| 
									
										
										
										
											2024-04-12 15:46:34 +08:00
										 |  |  |   const formSchemas = useMemo(() => { | 
					
						
							|  |  |  |     return currTool ? toolParametersToFormSchemas(currTool.parameters) : [] | 
					
						
							|  |  |  |   }, [currTool]) | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |   const toolInputVarSchema = formSchemas.filter((item: any) => item.form === 'llm') | 
					
						
							|  |  |  |   // use setting
 | 
					
						
							|  |  |  |   const toolSettingSchema = formSchemas.filter((item: any) => item.form !== 'llm') | 
					
						
							| 
									
										
										
										
											2024-04-12 15:46:34 +08:00
										 |  |  |   const hasShouldTransferTypeSettingInput = toolSettingSchema.some(item => item.type === 'boolean' || item.type === 'number-input') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const setInputs = useCallback((value: ToolNodeType) => { | 
					
						
							|  |  |  |     if (!hasShouldTransferTypeSettingInput) { | 
					
						
							|  |  |  |       doSetInputs(value) | 
					
						
							|  |  |  |       return | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const newInputs = produce(value, (draft) => { | 
					
						
							|  |  |  |       const newConfig = { ...draft.tool_configurations } | 
					
						
							|  |  |  |       Object.keys(draft.tool_configurations).forEach((key) => { | 
					
						
							|  |  |  |         const schema = formSchemas.find(item => item.variable === key) | 
					
						
							|  |  |  |         const value = newConfig[key] | 
					
						
							|  |  |  |         if (schema?.type === 'boolean') { | 
					
						
							|  |  |  |           if (typeof value === 'string') | 
					
						
							| 
									
										
										
										
											2025-02-17 17:05:13 +08:00
										 |  |  |             newConfig[key] = Number.parseInt(value, 10) | 
					
						
							| 
									
										
										
										
											2024-04-12 15:46:34 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |           if (typeof value === 'boolean') | 
					
						
							|  |  |  |             newConfig[key] = value ? 1 : 0 | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (schema?.type === 'number-input') { | 
					
						
							|  |  |  |           if (typeof value === 'string' && value !== '') | 
					
						
							| 
									
										
										
										
											2025-02-17 17:05:13 +08:00
										 |  |  |             newConfig[key] = Number.parseFloat(value) | 
					
						
							| 
									
										
										
										
											2024-04-12 15:46:34 +08:00
										 |  |  |         } | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |       draft.tool_configurations = newConfig | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  |     doSetInputs(newInputs) | 
					
						
							|  |  |  |   }, [doSetInputs, formSchemas, hasShouldTransferTypeSettingInput]) | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |   const [notSetDefaultValue, setNotSetDefaultValue] = useState(false) | 
					
						
							|  |  |  |   const toolSettingValue = (() => { | 
					
						
							|  |  |  |     if (notSetDefaultValue) | 
					
						
							|  |  |  |       return tool_configurations | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return addDefaultValue(tool_configurations, toolSettingSchema) | 
					
						
							|  |  |  |   })() | 
					
						
							|  |  |  |   const setToolSettingValue = useCallback((value: Record<string, any>) => { | 
					
						
							|  |  |  |     setNotSetDefaultValue(true) | 
					
						
							|  |  |  |     setInputs({ | 
					
						
							|  |  |  |       ...inputs, | 
					
						
							|  |  |  |       tool_configurations: value, | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  |   }, [inputs, setInputs]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   useEffect(() => { | 
					
						
							|  |  |  |     if (!currTool) | 
					
						
							|  |  |  |       return | 
					
						
							|  |  |  |     const inputsWithDefaultValue = produce(inputs, (draft) => { | 
					
						
							|  |  |  |       if (!draft.tool_configurations || Object.keys(draft.tool_configurations).length === 0) | 
					
						
							|  |  |  |         draft.tool_configurations = addDefaultValue(tool_configurations, toolSettingSchema) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (!draft.tool_parameters) | 
					
						
							|  |  |  |         draft.tool_parameters = {} | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  |     setInputs(inputsWithDefaultValue) | 
					
						
							| 
									
										
										
										
											2024-12-16 14:33:00 +08:00
										 |  |  |     // eslint-disable-next-line react-hooks/exhaustive-deps
 | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |   }, [currTool]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // setting when call
 | 
					
						
							|  |  |  |   const setInputVar = useCallback((value: ToolVarInputs) => { | 
					
						
							|  |  |  |     setInputs({ | 
					
						
							|  |  |  |       ...inputs, | 
					
						
							|  |  |  |       tool_parameters: value, | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  |   }, [inputs, setInputs]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const [currVarIndex, setCurrVarIndex] = useState(-1) | 
					
						
							|  |  |  |   const currVarType = toolInputVarSchema[currVarIndex]?._type | 
					
						
							|  |  |  |   const handleOnVarOpen = useCallback((index: number) => { | 
					
						
							|  |  |  |     setCurrVarIndex(index) | 
					
						
							|  |  |  |   }, []) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const filterVar = useCallback((varPayload: Var) => { | 
					
						
							|  |  |  |     if (currVarType) | 
					
						
							|  |  |  |       return varPayload.type === currVarType | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return varPayload.type !== VarVarType.arrayFile | 
					
						
							|  |  |  |   }, [currVarType]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const isLoading = currTool && (isBuiltIn ? !currCollection : false) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   // single run
 | 
					
						
							|  |  |  |   const [inputVarValues, doSetInputVarValues] = useState<Record<string, any>>({}) | 
					
						
							|  |  |  |   const setInputVarValues = (value: Record<string, any>) => { | 
					
						
							|  |  |  |     doSetInputVarValues(value) | 
					
						
							| 
									
										
										
										
											2025-02-17 17:05:13 +08:00
										 |  |  |     // eslint-disable-next-line ts/no-use-before-define
 | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |     setRunInputData(value) | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   // fill single run form variable with constant value first time
 | 
					
						
							|  |  |  |   const inputVarValuesWithConstantValue = () => { | 
					
						
							|  |  |  |     const res = produce(inputVarValues, (draft) => { | 
					
						
							|  |  |  |       Object.keys(inputs.tool_parameters).forEach((key: string) => { | 
					
						
							|  |  |  |         const { type, value } = inputs.tool_parameters[key] | 
					
						
							|  |  |  |         if (type === VarType.constant && (value === undefined || value === null)) | 
					
						
							|  |  |  |           draft.tool_parameters[key].value = value | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  |     return res | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const { | 
					
						
							|  |  |  |     isShowSingleRun, | 
					
						
							|  |  |  |     hideSingleRun, | 
					
						
							|  |  |  |     getInputVars, | 
					
						
							|  |  |  |     runningStatus, | 
					
						
							|  |  |  |     setRunInputData, | 
					
						
							|  |  |  |     handleRun: doHandleRun, | 
					
						
							|  |  |  |     handleStop, | 
					
						
							|  |  |  |     runResult, | 
					
						
							|  |  |  |   } = useOneStepRun<ToolNodeType>({ | 
					
						
							|  |  |  |     id, | 
					
						
							|  |  |  |     data: inputs, | 
					
						
							|  |  |  |     defaultRunInputData: {}, | 
					
						
							|  |  |  |     moreDataForCheckValid: { | 
					
						
							|  |  |  |       toolInputsSchema: (() => { | 
					
						
							|  |  |  |         const formInputs: InputVar[] = [] | 
					
						
							|  |  |  |         toolInputVarSchema.forEach((item: any) => { | 
					
						
							|  |  |  |           formInputs.push({ | 
					
						
							|  |  |  |             label: item.label[language] || item.label.en_US, | 
					
						
							|  |  |  |             variable: item.variable, | 
					
						
							|  |  |  |             type: item.type, | 
					
						
							|  |  |  |             required: item.required, | 
					
						
							|  |  |  |           }) | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |         return formInputs | 
					
						
							|  |  |  |       })(), | 
					
						
							|  |  |  |       notAuthed: isShowAuthBtn, | 
					
						
							|  |  |  |       toolSettingSchema, | 
					
						
							|  |  |  |       language, | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |   }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const hadVarParams = Object.keys(inputs.tool_parameters) | 
					
						
							|  |  |  |     .filter(key => inputs.tool_parameters[key].type !== VarType.constant) | 
					
						
							|  |  |  |     .map(k => inputs.tool_parameters[k]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const varInputs = getInputVars(hadVarParams.map((p) => { | 
					
						
							| 
									
										
										
										
											2024-12-16 14:33:00 +08:00
										 |  |  |     if (p.type === VarType.variable) { | 
					
						
							|  |  |  |       // handle the old wrong value not crash the page
 | 
					
						
							|  |  |  |       if (!(p.value as any).join) | 
					
						
							|  |  |  |         return `{{#${p.value}#}}` | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |       return `{{#${(p.value as ValueSelector).join('.')}#}}` | 
					
						
							| 
									
										
										
										
											2024-12-16 14:33:00 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return p.value as string | 
					
						
							|  |  |  |   })) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const singleRunForms = (() => { | 
					
						
							|  |  |  |     const forms: FormProps[] = [{ | 
					
						
							|  |  |  |       inputs: varInputs, | 
					
						
							|  |  |  |       values: inputVarValuesWithConstantValue(), | 
					
						
							|  |  |  |       onChange: setInputVarValues, | 
					
						
							|  |  |  |     }] | 
					
						
							|  |  |  |     return forms | 
					
						
							|  |  |  |   })() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const handleRun = (submitData: Record<string, any>) => { | 
					
						
							|  |  |  |     const varTypeInputKeys = Object.keys(inputs.tool_parameters) | 
					
						
							|  |  |  |       .filter(key => inputs.tool_parameters[key].type === VarType.variable) | 
					
						
							|  |  |  |     const shouldAdd = varTypeInputKeys.length > 0 | 
					
						
							|  |  |  |     if (!shouldAdd) { | 
					
						
							|  |  |  |       doHandleRun(submitData) | 
					
						
							|  |  |  |       return | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     const addMissedVarData = { ...submitData } | 
					
						
							|  |  |  |     Object.keys(submitData).forEach((key) => { | 
					
						
							|  |  |  |       const value = submitData[key] | 
					
						
							|  |  |  |       varTypeInputKeys.forEach((inputKey) => { | 
					
						
							|  |  |  |         const inputValue = inputs.tool_parameters[inputKey].value as ValueSelector | 
					
						
							|  |  |  |         if (`#${inputValue.join('.')}#` === key) | 
					
						
							|  |  |  |           addMissedVarData[inputKey] = value | 
					
						
							|  |  |  |       }) | 
					
						
							|  |  |  |     }) | 
					
						
							|  |  |  |     doHandleRun(addMissedVarData) | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-02-17 17:05:13 +08:00
										 |  |  |   const outputSchema = useMemo(() => { | 
					
						
							|  |  |  |     const res: any[] = [] | 
					
						
							|  |  |  |     if (!output_schema) | 
					
						
							|  |  |  |       return [] | 
					
						
							|  |  |  |     Object.keys(output_schema.properties).forEach((outputKey) => { | 
					
						
							|  |  |  |       const output = output_schema.properties[outputKey] | 
					
						
							| 
									
										
										
										
											2025-04-18 16:53:43 +08:00
										 |  |  |       const type = output.type | 
					
						
							|  |  |  |       if (type === 'object') { | 
					
						
							|  |  |  |         res.push({ | 
					
						
							|  |  |  |           name: outputKey, | 
					
						
							|  |  |  |           value: output, | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       else { | 
					
						
							|  |  |  |         res.push({ | 
					
						
							|  |  |  |           name: outputKey, | 
					
						
							|  |  |  |           type: output.type === 'array' | 
					
						
							|  |  |  |             ? `Array[${output.items?.type.slice(0, 1).toLocaleUpperCase()}${output.items?.type.slice(1)}]` | 
					
						
							|  |  |  |             : `${output.type.slice(0, 1).toLocaleUpperCase()}${output.type.slice(1)}`, | 
					
						
							|  |  |  |           description: output.description, | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2025-02-17 17:05:13 +08:00
										 |  |  |     }) | 
					
						
							|  |  |  |     return res | 
					
						
							|  |  |  |   }, [output_schema]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-04-18 16:53:43 +08:00
										 |  |  |   const hasObjectOutput = useMemo(() => { | 
					
						
							|  |  |  |     if (!output_schema) | 
					
						
							|  |  |  |       return false | 
					
						
							|  |  |  |     const properties = output_schema.properties | 
					
						
							|  |  |  |     return Object.keys(properties).some(key => properties[key].type === 'object') | 
					
						
							|  |  |  |   }, [output_schema]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |   return { | 
					
						
							|  |  |  |     readOnly, | 
					
						
							|  |  |  |     inputs, | 
					
						
							|  |  |  |     currTool, | 
					
						
							|  |  |  |     toolSettingSchema, | 
					
						
							|  |  |  |     toolSettingValue, | 
					
						
							|  |  |  |     setToolSettingValue, | 
					
						
							|  |  |  |     toolInputVarSchema, | 
					
						
							|  |  |  |     setInputVar, | 
					
						
							|  |  |  |     handleOnVarOpen, | 
					
						
							|  |  |  |     filterVar, | 
					
						
							|  |  |  |     currCollection, | 
					
						
							|  |  |  |     isShowAuthBtn, | 
					
						
							|  |  |  |     showSetAuth, | 
					
						
							|  |  |  |     showSetAuthModal, | 
					
						
							|  |  |  |     hideSetAuthModal, | 
					
						
							|  |  |  |     handleSaveAuth, | 
					
						
							|  |  |  |     isLoading, | 
					
						
							|  |  |  |     isShowSingleRun, | 
					
						
							|  |  |  |     hideSingleRun, | 
					
						
							|  |  |  |     inputVarValues, | 
					
						
							|  |  |  |     varInputs, | 
					
						
							|  |  |  |     setInputVarValues, | 
					
						
							|  |  |  |     singleRunForms, | 
					
						
							|  |  |  |     runningStatus, | 
					
						
							|  |  |  |     handleRun, | 
					
						
							|  |  |  |     handleStop, | 
					
						
							|  |  |  |     runResult, | 
					
						
							| 
									
										
										
										
											2025-02-17 17:05:13 +08:00
										 |  |  |     outputSchema, | 
					
						
							| 
									
										
										
										
											2025-04-18 16:53:43 +08:00
										 |  |  |     hasObjectOutput, | 
					
						
							| 
									
										
										
										
											2024-04-08 18:51:46 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export default useConfig |