Spaces:
Running
Running
import { useCallback, useEffect, useMemo, useState } from 'react' | |
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' | |
const useConfig = (id: string, payload: ToolNodeType) => { | |
const { nodesReadOnly: readOnly } = useNodesReadOnly() | |
const { handleFetchAllTools } = useFetchToolsData() | |
const { t } = useTranslation() | |
const language = useLanguage() | |
const { inputs, setInputs: doSetInputs } = useNodeCrud<ToolNodeType>(id, payload) | |
/* | |
* tool_configurations: tool setting, not dynamic setting | |
* tool_parameters: tool dynamic setting(by user) | |
*/ | |
const { provider_id, provider_type, tool_name, tool_configurations } = inputs | |
const isBuiltIn = provider_type === CollectionType.builtIn | |
const buildInTools = useStore(s => s.buildInTools) | |
const customTools = useStore(s => s.customTools) | |
const currentTools = isBuiltIn ? buildInTools : customTools | |
const currCollection = currentTools.find(item => item.id === provider_id) | |
// 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) | |
const formSchemas = useMemo(() => { | |
return currTool ? toolParametersToFormSchemas(currTool.parameters) : [] | |
}, [currTool]) | |
const toolInputVarSchema = formSchemas.filter((item: any) => item.form === 'llm') | |
// use setting | |
const toolSettingSchema = formSchemas.filter((item: any) => item.form !== 'llm') | |
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') | |
newConfig[key] = parseInt(value, 10) | |
if (typeof value === 'boolean') | |
newConfig[key] = value ? 1 : 0 | |
} | |
if (schema?.type === 'number-input') { | |
if (typeof value === 'string' && value !== '') | |
newConfig[key] = parseFloat(value) | |
} | |
}) | |
draft.tool_configurations = newConfig | |
}) | |
doSetInputs(newInputs) | |
}, [doSetInputs, formSchemas, hasShouldTransferTypeSettingInput]) | |
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) | |
// eslint-disable-next-line react-hooks/exhaustive-deps | |
}, [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) | |
// eslint-disable-next-line @typescript-eslint/no-use-before-define | |
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) => { | |
if (p.type === VarType.variable) | |
return `{{#${(p.value as ValueSelector).join('.')}#}}` | |
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) | |
} | |
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, | |
} | |
} | |
export default useConfig | |