import { useCallback, useState } from 'react' import { useTranslation } from 'react-i18next' import produce from 'immer' import { RiArrowRightUpLine, RiBracesLine, } from '@remixicon/react' import Tooltip from '@/app/components/base/tooltip' import Switch from '@/app/components/base/switch' import MixedVariableTextInput from '@/app/components/workflow/nodes/tool/components/mixed-variable-text-input' import Input from '@/app/components/base/input' import FormInputTypeSwitch from '@/app/components/workflow/nodes/_base/components/form-input-type-switch' import FormInputBoolean from '@/app/components/workflow/nodes/_base/components/form-input-boolean' import { SimpleSelect } from '@/app/components/base/select' import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor' import VarReferencePicker from '@/app/components/workflow/nodes/_base/components/variable/var-reference-picker' import AppSelector from '@/app/components/plugins/plugin-detail-panel/app-selector' import ModelParameterModal from '@/app/components/plugins/plugin-detail-panel/model-selector' import { CodeLanguage } from '@/app/components/workflow/nodes/code/types' import { useLanguage } from '@/app/components/header/account-setting/model-provider-page/hooks' import { FormTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations' import type { Node } from 'reactflow' import type { NodeOutPutVar, ValueSelector, } from '@/app/components/workflow/types' import type { ToolVarInputs } from '@/app/components/workflow/nodes/tool/types' import { VarType as VarKindType } from '@/app/components/workflow/nodes/tool/types' import { VarType } from '@/app/components/workflow/types' import cn from '@/utils/classnames' import { useBoolean } from 'ahooks' import SchemaModal from './schema-modal' import type { SchemaRoot } from '@/app/components/workflow/nodes/llm/types' type Props = { value: Record onChange: (val: Record) => void schemas: any[] nodeOutputVars: NodeOutPutVar[], availableNodes: Node[], nodeId: string } const ReasoningConfigForm: React.FC = ({ value, onChange, schemas, nodeOutputVars, availableNodes, nodeId, }) => { const { t } = useTranslation() const language = useLanguage() const getVarKindType = (type: FormTypeEnum) => { if (type === FormTypeEnum.file || type === FormTypeEnum.files) return VarKindType.variable if (type === FormTypeEnum.select || type === FormTypeEnum.boolean || type === FormTypeEnum.textNumber || type === FormTypeEnum.array || type === FormTypeEnum.object) return VarKindType.constant if (type === FormTypeEnum.textInput || type === FormTypeEnum.secretInput) return VarKindType.mixed } const handleAutomatic = (key: string, val: any, type: FormTypeEnum) => { onChange({ ...value, [key]: { value: val ? null : { type: getVarKindType(type), value: null }, auto: val ? 1 : 0, }, }) } const handleTypeChange = useCallback((variable: string, defaultValue: any) => { return (newType: VarKindType) => { const res = produce(value, (draft: ToolVarInputs) => { draft[variable].value = { type: newType, value: newType === VarKindType.variable ? '' : defaultValue, } }) onChange(res) } }, [onChange, value]) const handleValueChange = useCallback((variable: string, varType: FormTypeEnum) => { return (newValue: any) => { const res = produce(value, (draft: ToolVarInputs) => { draft[variable].value = { type: getVarKindType(varType), value: newValue, } }) onChange(res) } }, [onChange, value]) const handleAppChange = useCallback((variable: string) => { return (app: { app_id: string inputs: Record files?: any[] }) => { const newValue = produce(value, (draft: ToolVarInputs) => { draft[variable].value = app as any }) onChange(newValue) } }, [onChange, value]) const handleModelChange = useCallback((variable: string) => { return (model: any) => { const newValue = produce(value, (draft: ToolVarInputs) => { draft[variable].value = { ...draft[variable].value, ...model, } as any }) onChange(newValue) } }, [onChange, value]) const handleVariableSelectorChange = useCallback((variable: string) => { return (newValue: ValueSelector | string) => { const res = produce(value, (draft: ToolVarInputs) => { draft[variable].value = { type: VarKindType.variable, value: newValue, } }) onChange(res) } }, [onChange, value]) const [isShowSchema, { setTrue: showSchema, setFalse: hideSchema, }] = useBoolean(false) const [schema, setSchema] = useState(null) const [schemaRootName, setSchemaRootName] = useState('') const renderField = (schema: any, showSchema: (schema: SchemaRoot, rootName: string) => void) => { const { default: defaultValue, variable, label, required, tooltip, type, scope, url, input_schema, placeholder, options, } = schema const auto = value[variable]?.auto const tooltipContent = (tooltip && ( {tooltip[language] || tooltip.en_US} } triggerClassName='ml-0.5 w-4 h-4' asChild={false} /> )) const varInput = value[variable].value const isString = type === FormTypeEnum.textInput || type === FormTypeEnum.secretInput const isNumber = type === FormTypeEnum.textNumber const isObject = type === FormTypeEnum.object const isArray = type === FormTypeEnum.array const isShowJSONEditor = isObject || isArray const isFile = type === FormTypeEnum.file || type === FormTypeEnum.files const isBoolean = type === FormTypeEnum.boolean const isSelect = type === FormTypeEnum.select const isAppSelector = type === FormTypeEnum.appSelector const isModelSelector = type === FormTypeEnum.modelSelector const showTypeSwitch = isNumber || isObject || isArray const isConstant = varInput?.type === VarKindType.constant || !varInput?.type const showVariableSelector = isFile || varInput?.type === VarKindType.variable const targetVarType = () => { if (isString) return VarType.string else if (isNumber) return VarType.number else if (type === FormTypeEnum.files) return VarType.arrayFile else if (type === FormTypeEnum.file) return VarType.file else if (isBoolean) return VarType.boolean else if (isObject) return VarType.object else if (isArray) return VarType.arrayObject else return VarType.string } const getFilterVar = () => { if (isNumber) return (varPayload: any) => varPayload.type === VarType.number else if (isString) return (varPayload: any) => [VarType.string, VarType.number, VarType.secret].includes(varPayload.type) else if (isFile) return (varPayload: any) => [VarType.file, VarType.arrayFile].includes(varPayload.type) else if (isBoolean) return (varPayload: any) => varPayload.type === VarType.boolean else if (isObject) return (varPayload: any) => varPayload.type === VarType.object else if (isArray) return (varPayload: any) => [VarType.array, VarType.arrayString, VarType.arrayNumber, VarType.arrayObject].includes(varPayload.type) return undefined } return (
{label[language] || label.en_US} {required && ( * )} {tooltipContent} ยท {targetVarType()} {isShowJSONEditor && ( {t('workflow.nodes.agent.clickToViewParameterSchema')}
} asChild={false}>
showSchema(input_schema as SchemaRoot, label[language] || label.en_US)} >
)}
handleAutomatic(variable, !auto, type)}> {t('plugin.detailPanel.toolSelector.auto')} handleAutomatic(variable, val, type)} />
{auto === 0 && (
{showTypeSwitch && ( )} {isString && ( )} {isNumber && isConstant && ( )} {isBoolean && ( )} {isSelect && ( { if (option.show_on.length) return option.show_on.every(showOnItem => value[showOnItem.variable] === showOnItem.value) return true }).map((option: { value: any; label: { [x: string]: any; en_US: any } }) => ({ value: option.value, name: option.label[language] || option.label.en_US }))} onSelect={item => handleValueChange(variable, type)(item.value as string)} placeholder={placeholder?.[language] || placeholder?.en_US} /> )} {isShowJSONEditor && isConstant && (
{placeholder?.[language] || placeholder?.en_US}
} />
)} {isAppSelector && ( )} {isModelSelector && ( )} {showVariableSelector && ( )} )} {url && ( {t('tools.howToGet')} )} ) } return (
{!isShowSchema && schemas.map(schema => renderField(schema, (s: SchemaRoot, rootName: string) => { setSchema(s) setSchemaRootName(rootName) showSchema() }))} {isShowSchema && ( )}
) } export default ReasoningConfigForm