Fix/workflow tool incorrect parameter configurations (#3402)

Co-authored-by: Joel <iamjoel007@gmail.com>
This commit is contained in:
Yeuoly 2024-04-12 15:46:34 +08:00 committed by GitHub
parent f7f8ef257c
commit 64e395d6cf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 72 additions and 13 deletions

View File

@ -243,6 +243,19 @@ class Tool(BaseModel, ABC):
tool_parameters[parameter.name] = float(tool_parameters[parameter.name]) tool_parameters[parameter.name] = float(tool_parameters[parameter.name])
elif parameter.type == ToolParameter.ToolParameterType.BOOLEAN: elif parameter.type == ToolParameter.ToolParameterType.BOOLEAN:
if not isinstance(tool_parameters[parameter.name], bool): if not isinstance(tool_parameters[parameter.name], bool):
# check if it is a string
if isinstance(tool_parameters[parameter.name], str):
# check true false
if tool_parameters[parameter.name].lower() in ['true', 'false']:
tool_parameters[parameter.name] = tool_parameters[parameter.name].lower() == 'true'
# check 1 0
elif tool_parameters[parameter.name] in ['1', '0']:
tool_parameters[parameter.name] = tool_parameters[parameter.name] == '1'
else:
tool_parameters[parameter.name] = bool(tool_parameters[parameter.name])
elif isinstance(tool_parameters[parameter.name], int | float):
tool_parameters[parameter.name] = tool_parameters[parameter.name] != 0
else:
tool_parameters[parameter.name] = bool(tool_parameters[parameter.name]) tool_parameters[parameter.name] = bool(tool_parameters[parameter.name])
return tool_parameters return tool_parameters

View File

@ -1,10 +1,9 @@
from typing import Literal, Union from typing import Any, Literal, Union
from pydantic import BaseModel, validator from pydantic import BaseModel, validator
from core.workflow.entities.base_node_data_entities import BaseNodeData from core.workflow.entities.base_node_data_entities import BaseNodeData
ToolParameterValue = Union[str, int, float, bool]
class ToolEntity(BaseModel): class ToolEntity(BaseModel):
provider_id: str provider_id: str
@ -12,11 +11,23 @@ class ToolEntity(BaseModel):
provider_name: str # redundancy provider_name: str # redundancy
tool_name: str tool_name: str
tool_label: str # redundancy tool_label: str # redundancy
tool_configurations: dict[str, ToolParameterValue] tool_configurations: dict[str, Any]
@validator('tool_configurations', pre=True, always=True)
def validate_tool_configurations(cls, value, values):
if not isinstance(value, dict):
raise ValueError('tool_configurations must be a dictionary')
for key in values.get('tool_configurations', {}).keys():
value = values.get('tool_configurations', {}).get(key)
if not isinstance(value, str | int | float | bool):
raise ValueError(f'{key} must be a string')
return value
class ToolNodeData(BaseNodeData, ToolEntity): class ToolNodeData(BaseNodeData, ToolEntity):
class ToolInput(BaseModel): class ToolInput(BaseModel):
value: Union[ToolParameterValue, list[str]] value: Union[Any, list[str]]
type: Literal['mixed', 'variable', 'constant'] type: Literal['mixed', 'variable', 'constant']
@validator('type', pre=True, always=True) @validator('type', pre=True, always=True)
@ -25,9 +36,13 @@ class ToolNodeData(BaseNodeData, ToolEntity):
value = values.get('value') value = values.get('value')
if typ == 'mixed' and not isinstance(value, str): if typ == 'mixed' and not isinstance(value, str):
raise ValueError('value must be a string') raise ValueError('value must be a string')
elif typ == 'variable' and not isinstance(value, list): elif typ == 'variable':
if not isinstance(value, list):
raise ValueError('value must be a list') raise ValueError('value must be a list')
elif typ == 'constant' and not isinstance(value, ToolParameterValue): for val in value:
if not isinstance(val, str):
raise ValueError('value must be a list of strings')
elif typ == 'constant' and not isinstance(value, str | int | float | bool):
raise ValueError('value must be a string, int, float, or bool') raise ValueError('value must be a string, int, float, or bool')
return typ return typ

View File

@ -1,4 +1,4 @@
import { useCallback, useEffect, useState } from 'react' import { useCallback, useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import produce from 'immer' import produce from 'immer'
import { useBoolean } from 'ahooks' import { useBoolean } from 'ahooks'
@ -25,7 +25,7 @@ const useConfig = (id: string, payload: ToolNodeType) => {
const { t } = useTranslation() const { t } = useTranslation()
const language = useLanguage() const language = useLanguage()
const { inputs, setInputs } = useNodeCrud<ToolNodeType>(id, payload) const { inputs, setInputs: doSetInputs } = useNodeCrud<ToolNodeType>(id, payload)
/* /*
* tool_configurations: tool setting, not dynamic setting * tool_configurations: tool setting, not dynamic setting
* tool_parameters: tool dynamic setting(by user) * tool_parameters: tool dynamic setting(by user)
@ -58,10 +58,41 @@ const useConfig = (id: string, payload: ToolNodeType) => {
}, [currCollection?.name, hideSetAuthModal, t, handleFetchAllTools, provider_type]) }, [currCollection?.name, hideSetAuthModal, t, handleFetchAllTools, provider_type])
const currTool = currCollection?.tools.find(tool => tool.name === tool_name) const currTool = currCollection?.tools.find(tool => tool.name === tool_name)
const formSchemas = currTool ? toolParametersToFormSchemas(currTool.parameters) : [] const formSchemas = useMemo(() => {
return currTool ? toolParametersToFormSchemas(currTool.parameters) : []
}, [currTool])
const toolInputVarSchema = formSchemas.filter((item: any) => item.form === 'llm') const toolInputVarSchema = formSchemas.filter((item: any) => item.form === 'llm')
// use setting // use setting
const toolSettingSchema = formSchemas.filter((item: any) => item.form !== 'llm') 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 [notSetDefaultValue, setNotSetDefaultValue] = useState(false)
const toolSettingValue = (() => { const toolSettingValue = (() => {
if (notSetDefaultValue) if (notSetDefaultValue)