mirror of
https://github.com/langgenius/dify.git
synced 2026-05-06 02:18:08 +08:00
agent node
This commit is contained in:
@ -5,7 +5,6 @@ import { useTranslation } from 'react-i18next'
|
|||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import {
|
import {
|
||||||
RiArrowLeftLine,
|
RiArrowLeftLine,
|
||||||
RiArrowRightUpLine,
|
|
||||||
} from '@remixicon/react'
|
} from '@remixicon/react'
|
||||||
import {
|
import {
|
||||||
PortalToFollowElem,
|
PortalToFollowElem,
|
||||||
@ -15,6 +14,7 @@ import {
|
|||||||
import ToolTrigger from '@/app/components/plugins/plugin-detail-panel/tool-selector/tool-trigger'
|
import ToolTrigger from '@/app/components/plugins/plugin-detail-panel/tool-selector/tool-trigger'
|
||||||
import ToolItem from '@/app/components/plugins/plugin-detail-panel/tool-selector/tool-item'
|
import ToolItem from '@/app/components/plugins/plugin-detail-panel/tool-selector/tool-item'
|
||||||
import ToolPicker from '@/app/components/workflow/block-selector/tool-picker'
|
import ToolPicker from '@/app/components/workflow/block-selector/tool-picker'
|
||||||
|
import ToolForm from '@/app/components/workflow/nodes/tool/components/tool-form'
|
||||||
import Button from '@/app/components/base/button'
|
import Button from '@/app/components/base/button'
|
||||||
import Indicator from '@/app/components/header/indicator'
|
import Indicator from '@/app/components/header/indicator'
|
||||||
import ToolCredentialForm from '@/app/components/plugins/plugin-detail-panel/tool-selector/tool-credentials-form'
|
import ToolCredentialForm from '@/app/components/plugins/plugin-detail-panel/tool-selector/tool-credentials-form'
|
||||||
@ -23,8 +23,7 @@ import Textarea from '@/app/components/base/textarea'
|
|||||||
import Divider from '@/app/components/base/divider'
|
import Divider from '@/app/components/base/divider'
|
||||||
import TabSlider from '@/app/components/base/tab-slider-plain'
|
import TabSlider from '@/app/components/base/tab-slider-plain'
|
||||||
import ReasoningConfigForm from '@/app/components/plugins/plugin-detail-panel/tool-selector/reasoning-config-form'
|
import ReasoningConfigForm from '@/app/components/plugins/plugin-detail-panel/tool-selector/reasoning-config-form'
|
||||||
import Form from '@/app/components/header/account-setting/model-provider-page/model-modal/Form'
|
import { generateFormValue, toolParametersToFormSchemas } from '@/app/components/tools/utils/to-form-schema'
|
||||||
import { generateFormValue, getPlainValue, getStructureValue, toolParametersToFormSchemas } from '@/app/components/tools/utils/to-form-schema'
|
|
||||||
|
|
||||||
import { useAppContext } from '@/context/app-context'
|
import { useAppContext } from '@/context/app-context'
|
||||||
import {
|
import {
|
||||||
@ -173,11 +172,9 @@ const ToolSelector: FC<Props> = ({
|
|||||||
const paramsFormSchemas = useMemo(() => toolParametersToFormSchemas(currentToolParams), [currentToolParams])
|
const paramsFormSchemas = useMemo(() => toolParametersToFormSchemas(currentToolParams), [currentToolParams])
|
||||||
|
|
||||||
const handleSettingsFormChange = (v: Record<string, any>) => {
|
const handleSettingsFormChange = (v: Record<string, any>) => {
|
||||||
const newValue = getStructureValue(v)
|
|
||||||
|
|
||||||
const toolValue = {
|
const toolValue = {
|
||||||
...value,
|
...value,
|
||||||
settings: newValue,
|
settings: v,
|
||||||
}
|
}
|
||||||
onSelect(toolValue as any)
|
onSelect(toolValue as any)
|
||||||
}
|
}
|
||||||
@ -400,24 +397,12 @@ const ToolSelector: FC<Props> = ({
|
|||||||
{/* user settings form */}
|
{/* user settings form */}
|
||||||
{(currType === 'settings' || userSettingsOnly) && (
|
{(currType === 'settings' || userSettingsOnly) && (
|
||||||
<div className='px-4 py-2'>
|
<div className='px-4 py-2'>
|
||||||
<Form
|
<ToolForm
|
||||||
value={getPlainValue(value?.settings || {})}
|
readOnly={false}
|
||||||
|
nodeId={nodeId}
|
||||||
|
schema={settingsFormSchemas as any}
|
||||||
|
value={value?.settings || {}}
|
||||||
onChange={handleSettingsFormChange}
|
onChange={handleSettingsFormChange}
|
||||||
formSchemas={settingsFormSchemas as any}
|
|
||||||
isEditMode={true}
|
|
||||||
showOnVariableMap={{}}
|
|
||||||
validating={false}
|
|
||||||
inputClassName='bg-components-input-bg-normal hover:bg-components-input-bg-hover'
|
|
||||||
fieldMoreInfo={item => item.url
|
|
||||||
? (<a
|
|
||||||
href={item.url}
|
|
||||||
target='_blank' rel='noopener noreferrer'
|
|
||||||
className='inline-flex items-center text-xs text-text-accent'
|
|
||||||
>
|
|
||||||
{t('tools.howToGet')}
|
|
||||||
<RiArrowRightUpLine className='ml-1 h-3 w-3' />
|
|
||||||
</a>)
|
|
||||||
: null}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -7,17 +7,22 @@ import {
|
|||||||
} from '@remixicon/react'
|
} from '@remixicon/react'
|
||||||
import Tooltip from '@/app/components/base/tooltip'
|
import Tooltip from '@/app/components/base/tooltip'
|
||||||
import Switch from '@/app/components/base/switch'
|
import Switch from '@/app/components/base/switch'
|
||||||
import Input from '@/app/components/workflow/nodes/_base/components/input-support-select-var'
|
import MixedInput from '@/app/components/workflow/nodes/_base/components/input-support-select-var'
|
||||||
|
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 VarReferencePicker from '@/app/components/workflow/nodes/_base/components/variable/var-reference-picker'
|
||||||
import AppSelector from '@/app/components/plugins/plugin-detail-panel/app-selector'
|
import AppSelector from '@/app/components/plugins/plugin-detail-panel/app-selector'
|
||||||
import ModelParameterModal from '@/app/components/plugins/plugin-detail-panel/model-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 { useLanguage } from '@/app/components/header/account-setting/model-provider-page/hooks'
|
||||||
import { FormTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
import { FormTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||||
import type { Node } from 'reactflow'
|
import type { Node } from 'reactflow'
|
||||||
import type {
|
import type {
|
||||||
NodeOutPutVar,
|
NodeOutPutVar,
|
||||||
ValueSelector,
|
ValueSelector,
|
||||||
Var,
|
|
||||||
} from '@/app/components/workflow/types'
|
} from '@/app/components/workflow/types'
|
||||||
import type { ToolVarInputs } from '@/app/components/workflow/nodes/tool/types'
|
import type { ToolVarInputs } from '@/app/components/workflow/nodes/tool/types'
|
||||||
import { VarType as VarKindType } from '@/app/components/workflow/nodes/tool/types'
|
import { VarType as VarKindType } from '@/app/components/workflow/nodes/tool/types'
|
||||||
@ -46,14 +51,13 @@ const ReasoningConfigForm: React.FC<Props> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const language = useLanguage()
|
const language = useLanguage()
|
||||||
const handleAutomatic = (key: string, val: any) => {
|
const getVarKindType = (type: FormTypeEnum) => {
|
||||||
onChange({
|
if (type === FormTypeEnum.file || type === FormTypeEnum.files)
|
||||||
...value,
|
return VarKindType.variable
|
||||||
[key]: {
|
if (type === FormTypeEnum.select || type === FormTypeEnum.boolean || type === FormTypeEnum.textNumber)
|
||||||
value: val ? null : value[key]?.value,
|
return VarKindType.constant
|
||||||
auto: val ? 1 : 0,
|
if (type === FormTypeEnum.textInput || type === FormTypeEnum.secretInput)
|
||||||
},
|
return VarKindType.mixed
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const [inputsIsFocus, setInputsIsFocus] = useState<Record<string, boolean>>({})
|
const [inputsIsFocus, setInputsIsFocus] = useState<Record<string, boolean>>({})
|
||||||
@ -67,52 +71,38 @@ const ReasoningConfigForm: React.FC<Props> = ({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
const handleNotMixedTypeChange = useCallback((variable: string) => {
|
|
||||||
return (varValue: ValueSelector | string, varKindType: VarKindType) => {
|
const handleAutomatic = (key: string, val: any, type: FormTypeEnum) => {
|
||||||
const newValue = produce(value, (draft: ToolVarInputs) => {
|
onChange({
|
||||||
const target = draft[variable].value
|
...value,
|
||||||
if (target) {
|
[key]: {
|
||||||
target.type = varKindType
|
value: val ? null : { type: getVarKindType(type), value: null },
|
||||||
target.value = varValue
|
auto: val ? 1 : 0,
|
||||||
}
|
},
|
||||||
else {
|
})
|
||||||
draft[variable].value = {
|
}
|
||||||
type: varKindType,
|
const handleTypeChange = useCallback((variable: string, defaultValue: any) => {
|
||||||
value: varValue,
|
return (newType: VarKindType) => {
|
||||||
}
|
const res = produce(value, (draft: ToolVarInputs) => {
|
||||||
}
|
|
||||||
})
|
|
||||||
onChange(newValue)
|
|
||||||
}
|
|
||||||
}, [value, onChange])
|
|
||||||
const handleMixedTypeChange = useCallback((variable: string) => {
|
|
||||||
return (itemValue: string) => {
|
|
||||||
const newValue = produce(value, (draft: ToolVarInputs) => {
|
|
||||||
const target = draft[variable].value
|
|
||||||
if (target) {
|
|
||||||
target.value = itemValue
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
draft[variable].value = {
|
|
||||||
type: VarKindType.mixed,
|
|
||||||
value: itemValue,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
onChange(newValue)
|
|
||||||
}
|
|
||||||
}, [value, onChange])
|
|
||||||
const handleFileChange = useCallback((variable: string) => {
|
|
||||||
return (varValue: ValueSelector | string) => {
|
|
||||||
const newValue = produce(value, (draft: ToolVarInputs) => {
|
|
||||||
draft[variable].value = {
|
draft[variable].value = {
|
||||||
type: VarKindType.variable,
|
type: newType,
|
||||||
value: varValue,
|
value: newType === VarKindType.variable ? '' : defaultValue,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
onChange(newValue)
|
onChange(res)
|
||||||
}
|
}
|
||||||
}, [value, onChange])
|
}, [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) => {
|
const handleAppChange = useCallback((variable: string) => {
|
||||||
return (app: {
|
return (app: {
|
||||||
app_id: string
|
app_id: string
|
||||||
@ -136,6 +126,17 @@ const ReasoningConfigForm: React.FC<Props> = ({
|
|||||||
onChange(newValue)
|
onChange(newValue)
|
||||||
}
|
}
|
||||||
}, [onChange, value])
|
}, [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, {
|
const [isShowSchema, {
|
||||||
setTrue: showSchema,
|
setTrue: showSchema,
|
||||||
@ -147,6 +148,7 @@ const ReasoningConfigForm: React.FC<Props> = ({
|
|||||||
|
|
||||||
const renderField = (schema: any, showSchema: (schema: SchemaRoot, rootName: string) => void) => {
|
const renderField = (schema: any, showSchema: (schema: SchemaRoot, rootName: string) => void) => {
|
||||||
const {
|
const {
|
||||||
|
default: defaultValue,
|
||||||
variable,
|
variable,
|
||||||
label,
|
label,
|
||||||
required,
|
required,
|
||||||
@ -155,6 +157,8 @@ const ReasoningConfigForm: React.FC<Props> = ({
|
|||||||
scope,
|
scope,
|
||||||
url,
|
url,
|
||||||
input_schema,
|
input_schema,
|
||||||
|
placeholder,
|
||||||
|
options,
|
||||||
} = schema
|
} = schema
|
||||||
const auto = value[variable]?.auto
|
const auto = value[variable]?.auto
|
||||||
const tooltipContent = (tooltip && (
|
const tooltipContent = (tooltip && (
|
||||||
@ -166,28 +170,55 @@ const ReasoningConfigForm: React.FC<Props> = ({
|
|||||||
asChild={false} />
|
asChild={false} />
|
||||||
))
|
))
|
||||||
const varInput = value[variable].value
|
const varInput = value[variable].value
|
||||||
|
const isString = type === FormTypeEnum.textInput || type === FormTypeEnum.secretInput
|
||||||
const isNumber = type === FormTypeEnum.textNumber
|
const isNumber = type === FormTypeEnum.textNumber
|
||||||
const isSelect = type === FormTypeEnum.select
|
|
||||||
const isFile = type === FormTypeEnum.file || type === FormTypeEnum.files
|
|
||||||
const isObject = type === FormTypeEnum.object
|
const isObject = type === FormTypeEnum.object
|
||||||
const isArray = type === FormTypeEnum.array
|
const isArray = type === FormTypeEnum.array
|
||||||
const isShowSchemaTooltip = isObject || isArray
|
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 isAppSelector = type === FormTypeEnum.appSelector
|
||||||
const isModelSelector = type === FormTypeEnum.modelSelector
|
const isModelSelector = type === FormTypeEnum.modelSelector
|
||||||
// const isToolSelector = type === FormTypeEnum.toolSelector
|
const showTypeSwitch = isNumber || isObject || isArray
|
||||||
const isString = !isNumber && !isSelect && !isFile && !isAppSelector && !isModelSelector && !isObject && !isArray
|
const isConstant = varInput?.type === VarKindType.constant || !varInput?.type
|
||||||
const valueType = (() => {
|
const showVariableSelector = isFile || varInput?.type === VarKindType.variable
|
||||||
if (isNumber) return VarType.number
|
const targetVarType = () => {
|
||||||
if (isSelect) return VarType.string
|
if (isString)
|
||||||
if (isFile) return VarType.file
|
return VarType.string
|
||||||
if (isObject) return VarType.object
|
else if (isNumber)
|
||||||
if (isArray) return VarType.array
|
return VarType.number
|
||||||
|
else if (type === FormTypeEnum.files)
|
||||||
return VarType.string
|
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 (
|
return (
|
||||||
<div key={variable} className='space-y-1'>
|
<div key={variable} className='space-y-0.5'>
|
||||||
<div className='system-sm-semibold flex items-center justify-between py-2 text-text-secondary'>
|
<div className='system-sm-semibold flex items-center justify-between py-2 text-text-secondary'>
|
||||||
<div className='flex items-center'>
|
<div className='flex items-center'>
|
||||||
<span className={cn('code-sm-semibold max-w-[140px] truncate text-text-secondary')} title={label[language] || label.en_US}>{label[language] || label.en_US}</span>
|
<span className={cn('code-sm-semibold max-w-[140px] truncate text-text-secondary')} title={label[language] || label.en_US}>{label[language] || label.en_US}</span>
|
||||||
@ -196,8 +227,8 @@ const ReasoningConfigForm: React.FC<Props> = ({
|
|||||||
)}
|
)}
|
||||||
{tooltipContent}
|
{tooltipContent}
|
||||||
<span className='system-xs-regular mx-1 text-text-quaternary'>·</span>
|
<span className='system-xs-regular mx-1 text-text-quaternary'>·</span>
|
||||||
<span className='system-xs-regular text-text-tertiary'>{valueType}</span>
|
<span className='system-xs-regular text-text-tertiary'>{targetVarType()}</span>
|
||||||
{isShowSchemaTooltip && (
|
{isShowJSONEditor && (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
popupContent={<div className='system-xs-medium text-text-secondary'>
|
popupContent={<div className='system-xs-medium text-text-secondary'>
|
||||||
{t('workflow.nodes.agent.clickToViewParameterSchema')}
|
{t('workflow.nodes.agent.clickToViewParameterSchema')}
|
||||||
@ -213,22 +244,25 @@ const ReasoningConfigForm: React.FC<Props> = ({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div className='flex cursor-pointer items-center gap-1 rounded-[6px] border border-divider-subtle bg-background-default-lighter px-2 py-1 hover:bg-state-base-hover' onClick={() => handleAutomatic(variable, !auto)}>
|
<div className='flex cursor-pointer items-center gap-1 rounded-[6px] border border-divider-subtle bg-background-default-lighter px-2 py-1 hover:bg-state-base-hover' onClick={() => handleAutomatic(variable, !auto, type)}>
|
||||||
<span className='system-xs-medium text-text-secondary'>{t('plugin.detailPanel.toolSelector.auto')}</span>
|
<span className='system-xs-medium text-text-secondary'>{t('plugin.detailPanel.toolSelector.auto')}</span>
|
||||||
<Switch
|
<Switch
|
||||||
size='xs'
|
size='xs'
|
||||||
defaultValue={!!auto}
|
defaultValue={!!auto}
|
||||||
onChange={val => handleAutomatic(variable, val)}
|
onChange={val => handleAutomatic(variable, val, type)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{auto === 0 && (
|
{auto === 0 && (
|
||||||
<>
|
<div className={cn('gap-1', !(isShowJSONEditor && isConstant) && 'flex')}>
|
||||||
|
{showTypeSwitch && (
|
||||||
|
<FormInputTypeSwitch value={varInput?.type || VarKindType.constant} onChange={handleTypeChange(variable, defaultValue)}/>
|
||||||
|
)}
|
||||||
{isString && (
|
{isString && (
|
||||||
<Input
|
<MixedInput
|
||||||
className={cn(inputsIsFocus[variable] ? 'border-gray-300 bg-gray-50 shadow-xs' : 'border-gray-100 bg-gray-100', 'rounded-lg border px-3 py-[6px]')}
|
className={cn(inputsIsFocus[variable] ? 'border-gray-300 bg-gray-50 shadow-xs' : 'border-gray-100 bg-gray-100', 'grow rounded-lg border px-3 py-[6px]')}
|
||||||
value={varInput?.value as string || ''}
|
value={varInput?.value as string || ''}
|
||||||
onChange={handleMixedTypeChange(variable)}
|
onChange={handleValueChange(variable, type)}
|
||||||
nodesOutputVars={nodeOutputVars}
|
nodesOutputVars={nodeOutputVars}
|
||||||
availableNodes={availableNodes}
|
availableNodes={availableNodes}
|
||||||
onFocusChange={handleInputFocus(variable)}
|
onFocusChange={handleInputFocus(variable)}
|
||||||
@ -236,53 +270,50 @@ const ReasoningConfigForm: React.FC<Props> = ({
|
|||||||
placeholderClassName='!leading-[21px]'
|
placeholderClassName='!leading-[21px]'
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{/* {isString && (
|
{isNumber && isConstant && (
|
||||||
<VarReferencePicker
|
<Input
|
||||||
zIndex={1001}
|
className='h-8 grow'
|
||||||
readonly={false}
|
type='number'
|
||||||
isShowNodeName
|
|
||||||
nodeId={nodeId}
|
|
||||||
value={varInput?.value || ''}
|
value={varInput?.value || ''}
|
||||||
onChange={handleNotMixedTypeChange(variable)}
|
onChange={handleValueChange(variable, type)}
|
||||||
defaultVarKindType={VarKindType.variable}
|
placeholder={placeholder?.[language] || placeholder?.en_US}
|
||||||
filterVar={(varPayload: Var) => varPayload.type === VarType.number || varPayload.type === VarType.secret || varPayload.type === VarType.string}
|
|
||||||
/>
|
|
||||||
)} */}
|
|
||||||
{(isNumber || isSelect) && (
|
|
||||||
<VarReferencePicker
|
|
||||||
zIndex={1001}
|
|
||||||
readonly={false}
|
|
||||||
isShowNodeName
|
|
||||||
nodeId={nodeId}
|
|
||||||
value={varInput?.type === VarKindType.constant ? (varInput?.value ?? '') : (varInput?.value ?? [])}
|
|
||||||
onChange={handleNotMixedTypeChange(variable)}
|
|
||||||
defaultVarKindType={varInput?.type || (isNumber ? VarKindType.constant : VarKindType.variable)}
|
|
||||||
isSupportConstantValue
|
|
||||||
filterVar={isNumber ? (varPayload: Var) => varPayload.type === schema._type : undefined}
|
|
||||||
availableVars={isSelect ? nodeOutputVars : undefined}
|
|
||||||
schema={schema}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{(isFile || isObject || isArray) && (
|
{isBoolean && (
|
||||||
<VarReferencePicker
|
<FormInputBoolean
|
||||||
zIndex={1001}
|
value={varInput?.value as boolean}
|
||||||
readonly={false}
|
onChange={handleValueChange(variable, type)}
|
||||||
isShowNodeName
|
|
||||||
nodeId={nodeId}
|
|
||||||
value={varInput?.value || []}
|
|
||||||
onChange={handleFileChange(variable)}
|
|
||||||
defaultVarKindType={VarKindType.variable}
|
|
||||||
filterVar={(varPayload: Var) => {
|
|
||||||
if(isFile)
|
|
||||||
return varPayload.type === VarType.file || varPayload.type === VarType.arrayFile
|
|
||||||
if(isObject)
|
|
||||||
return varPayload.type === VarType.object
|
|
||||||
if(isArray)
|
|
||||||
return [VarType.array, VarType.arrayNumber, VarType.arrayString, VarType.arrayObject, VarType.arrayFile].includes(varPayload.type)
|
|
||||||
return true
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{isSelect && (
|
||||||
|
<SimpleSelect
|
||||||
|
wrapperClassName='h-8 grow'
|
||||||
|
defaultValue={varInput?.value}
|
||||||
|
items={options.filter((option: { show_on: any[] }) => {
|
||||||
|
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 && (
|
||||||
|
<div className='mt-1 w-full'>
|
||||||
|
<CodeEditor
|
||||||
|
title='JSON'
|
||||||
|
value={varInput?.value as any}
|
||||||
|
isExpand
|
||||||
|
isInNode
|
||||||
|
height={100}
|
||||||
|
language={CodeLanguage.json}
|
||||||
|
onChange={handleValueChange(variable, type)}
|
||||||
|
className='w-full'
|
||||||
|
placeholder={<div className='whitespace-pre'>{placeholder?.[language] || placeholder?.en_US}</div>}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
{isAppSelector && (
|
{isAppSelector && (
|
||||||
<AppSelector
|
<AppSelector
|
||||||
disabled={false}
|
disabled={false}
|
||||||
@ -301,7 +332,20 @@ const ReasoningConfigForm: React.FC<Props> = ({
|
|||||||
scope={scope}
|
scope={scope}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
{showVariableSelector && (
|
||||||
|
<VarReferencePicker
|
||||||
|
className='h-8 grow'
|
||||||
|
readonly={false}
|
||||||
|
isShowNodeName
|
||||||
|
nodeId={nodeId}
|
||||||
|
value={varInput?.value || []}
|
||||||
|
onChange={handleVariableSelectorChange(variable)}
|
||||||
|
filterVar={getFilterVar()}
|
||||||
|
schema={schema}
|
||||||
|
valueTypePlaceHolder={targetVarType()}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
{url && (
|
{url && (
|
||||||
<a
|
<a
|
||||||
|
|||||||
@ -64,37 +64,52 @@ export const addDefaultValue = (value: Record<string, any>, formSchemas: { varia
|
|||||||
return newValues
|
return newValues
|
||||||
}
|
}
|
||||||
|
|
||||||
export const generateFormValue = (value: Record<string, any>, formSchemas: { variable: string; default?: any }[], isReasoning = false) => {
|
const correctInitialData = (type: string, target: any, defaultValue: any) => {
|
||||||
|
if (type === 'text-input' || type === 'secret-input')
|
||||||
|
target.type = 'mixed'
|
||||||
|
|
||||||
|
if (type === 'boolean') {
|
||||||
|
if (typeof defaultValue === 'string')
|
||||||
|
target.value = defaultValue === 'true' || defaultValue === '1'
|
||||||
|
|
||||||
|
if (typeof defaultValue === 'boolean')
|
||||||
|
target.value = defaultValue
|
||||||
|
|
||||||
|
if (typeof defaultValue === 'number')
|
||||||
|
target.value = defaultValue === 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'number-input') {
|
||||||
|
if (typeof defaultValue === 'string' && defaultValue !== '')
|
||||||
|
target.value = Number.parseFloat(defaultValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'app-selector' || type === 'model-selector')
|
||||||
|
target.value = defaultValue
|
||||||
|
|
||||||
|
return target
|
||||||
|
}
|
||||||
|
|
||||||
|
export const generateFormValue = (value: Record<string, any>, formSchemas: { variable: string; default?: any; type: string }[], isReasoning = false) => {
|
||||||
const newValues = {} as any
|
const newValues = {} as any
|
||||||
formSchemas.forEach((formSchema) => {
|
formSchemas.forEach((formSchema) => {
|
||||||
const itemValue = value[formSchema.variable]
|
const itemValue = value[formSchema.variable]
|
||||||
if ((formSchema.default !== undefined) && (value === undefined || itemValue === null || itemValue === '' || itemValue === undefined)) {
|
if ((formSchema.default !== undefined) && (value === undefined || itemValue === null || itemValue === '' || itemValue === undefined)) {
|
||||||
|
const value = formSchema.default
|
||||||
newValues[formSchema.variable] = {
|
newValues[formSchema.variable] = {
|
||||||
...(isReasoning ? { value: null, auto: 1 } : { value: formSchema.default }),
|
value: {
|
||||||
|
type: 'constant',
|
||||||
|
value: formSchema.default,
|
||||||
|
},
|
||||||
|
...(isReasoning ? { auto: 1, value: null } : {}),
|
||||||
}
|
}
|
||||||
|
if (!isReasoning)
|
||||||
|
newValues[formSchema.variable].value = correctInitialData(formSchema.type, newValues[formSchema.variable].value, value)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return newValues
|
return newValues
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getPlainValue = (value: Record<string, any>) => {
|
|
||||||
const plainValue = { ...value }
|
|
||||||
Object.keys(plainValue).forEach((key) => {
|
|
||||||
plainValue[key] = value[key].value
|
|
||||||
})
|
|
||||||
return plainValue
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getStructureValue = (value: Record<string, any>) => {
|
|
||||||
const newValue = { ...value } as any
|
|
||||||
Object.keys(newValue).forEach((key) => {
|
|
||||||
newValue[key] = {
|
|
||||||
value: value[key],
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return newValue
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getConfiguredValue = (value: Record<string, any>, formSchemas: { variable: string; type: string; default?: any }[]) => {
|
export const getConfiguredValue = (value: Record<string, any>, formSchemas: { variable: string; type: string; default?: any }[]) => {
|
||||||
const newValues = { ...value }
|
const newValues = { ...value }
|
||||||
formSchemas.forEach((formSchema) => {
|
formSchemas.forEach((formSchema) => {
|
||||||
@ -105,27 +120,7 @@ export const getConfiguredValue = (value: Record<string, any>, formSchemas: { va
|
|||||||
type: 'constant',
|
type: 'constant',
|
||||||
value: formSchema.default,
|
value: formSchema.default,
|
||||||
}
|
}
|
||||||
if (formSchema.type === 'text-input' || formSchema.type === 'secret-input')
|
newValues[formSchema.variable] = correctInitialData(formSchema.type, newValues[formSchema.variable], value)
|
||||||
newValues[formSchema.variable].type = 'mixed'
|
|
||||||
|
|
||||||
if (formSchema.type === 'boolean') {
|
|
||||||
if (typeof value === 'string')
|
|
||||||
newValues[formSchema.variable].value = value === 'true' || value === '1'
|
|
||||||
|
|
||||||
if (typeof value === 'boolean')
|
|
||||||
newValues[formSchema.variable].value = value
|
|
||||||
|
|
||||||
if (typeof value === 'number')
|
|
||||||
newValues[formSchema.variable].value = value === 1
|
|
||||||
}
|
|
||||||
|
|
||||||
if (formSchema.type === 'number-input') {
|
|
||||||
if (typeof value === 'string' && value !== '')
|
|
||||||
newValues[formSchema.variable].value = Number.parseFloat(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (formSchema.type === 'app-selector' || formSchema.type === 'model-selector')
|
|
||||||
newValues[formSchema.variable] = value
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return newValues
|
return newValues
|
||||||
|
|||||||
@ -117,7 +117,7 @@ const FormInputItem: FC<Props> = ({
|
|||||||
const getVarKindType = () => {
|
const getVarKindType = () => {
|
||||||
if (isFile)
|
if (isFile)
|
||||||
return VarKindType.variable
|
return VarKindType.variable
|
||||||
if (isSelect || isAppSelector || isModelSelector || isBoolean)
|
if (isSelect || isBoolean || isNumber)
|
||||||
return VarKindType.constant
|
return VarKindType.constant
|
||||||
if (isString)
|
if (isString)
|
||||||
return VarKindType.mixed
|
return VarKindType.mixed
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import { renderI18nObject } from '@/i18n'
|
|||||||
|
|
||||||
const nodeDefault: NodeDefault<AgentNodeType> = {
|
const nodeDefault: NodeDefault<AgentNodeType> = {
|
||||||
defaultValue: {
|
defaultValue: {
|
||||||
|
version: '2',
|
||||||
},
|
},
|
||||||
getAvailablePrevNodes(isChatMode) {
|
getAvailablePrevNodes(isChatMode) {
|
||||||
return isChatMode
|
return isChatMode
|
||||||
@ -60,15 +61,28 @@ const nodeDefault: NodeDefault<AgentNodeType> = {
|
|||||||
const schemas = toolValue.schemas || []
|
const schemas = toolValue.schemas || []
|
||||||
const userSettings = toolValue.settings
|
const userSettings = toolValue.settings
|
||||||
const reasoningConfig = toolValue.parameters
|
const reasoningConfig = toolValue.parameters
|
||||||
|
const version = payload.version
|
||||||
schemas.forEach((schema: any) => {
|
schemas.forEach((schema: any) => {
|
||||||
if (schema?.required) {
|
if (schema?.required) {
|
||||||
if (schema.form === 'form' && !userSettings[schema.name]?.value) {
|
if (schema.form === 'form' && !version && !userSettings[schema.name]?.value) {
|
||||||
return {
|
return {
|
||||||
isValid: false,
|
isValid: false,
|
||||||
errorMessage: t('workflow.errorMsg.toolParameterRequired', { field: renderI18nObject(param.label, language), param: renderI18nObject(schema.label, language) }),
|
errorMessage: t('workflow.errorMsg.toolParameterRequired', { field: renderI18nObject(param.label, language), param: renderI18nObject(schema.label, language) }),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (schema.form === 'llm' && reasoningConfig[schema.name].auto === 0 && !userSettings[schema.name]?.value) {
|
if (schema.form === 'form' && version && !userSettings[schema.name]?.value.value) {
|
||||||
|
return {
|
||||||
|
isValid: false,
|
||||||
|
errorMessage: t('workflow.errorMsg.toolParameterRequired', { field: renderI18nObject(param.label, language), param: renderI18nObject(schema.label, language) }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (schema.form === 'llm' && !version && reasoningConfig[schema.name].auto === 0 && !reasoningConfig[schema.name]?.value) {
|
||||||
|
return {
|
||||||
|
isValid: false,
|
||||||
|
errorMessage: t('workflow.errorMsg.toolParameterRequired', { field: renderI18nObject(param.label, language), param: renderI18nObject(schema.label, language) }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (schema.form === 'llm' && version && reasoningConfig[schema.name].auto === 0 && !reasoningConfig[schema.name]?.value.value) {
|
||||||
return {
|
return {
|
||||||
isValid: false,
|
isValid: false,
|
||||||
errorMessage: t('workflow.errorMsg.toolParameterRequired', { field: renderI18nObject(param.label, language), param: renderI18nObject(schema.label, language) }),
|
errorMessage: t('workflow.errorMsg.toolParameterRequired', { field: renderI18nObject(param.label, language), param: renderI18nObject(schema.label, language) }),
|
||||||
|
|||||||
@ -11,6 +11,7 @@ export type AgentNodeType = CommonNodeType & {
|
|||||||
output_schema: Record<string, any>
|
output_schema: Record<string, any>
|
||||||
plugin_unique_identifier?: string
|
plugin_unique_identifier?: string
|
||||||
memory?: Memory
|
memory?: Memory
|
||||||
|
version?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum AgentFeature {
|
export enum AgentFeature {
|
||||||
|
|||||||
@ -27,6 +27,7 @@ import type { QuestionClassifierNodeType } from '../nodes/question-classifier/ty
|
|||||||
import type { IfElseNodeType } from '../nodes/if-else/types'
|
import type { IfElseNodeType } from '../nodes/if-else/types'
|
||||||
import { branchNameCorrect } from '../nodes/if-else/utils'
|
import { branchNameCorrect } from '../nodes/if-else/utils'
|
||||||
import type { IterationNodeType } from '../nodes/iteration/types'
|
import type { IterationNodeType } from '../nodes/iteration/types'
|
||||||
|
import type { AgentNodeType } from '../nodes/agent/types'
|
||||||
import type { LoopNodeType } from '../nodes/loop/types'
|
import type { LoopNodeType } from '../nodes/loop/types'
|
||||||
import type { ToolNodeType } from '../nodes/tool/types'
|
import type { ToolNodeType } from '../nodes/tool/types'
|
||||||
import {
|
import {
|
||||||
@ -304,6 +305,13 @@ export const initialNodes = (originNodes: Node[], originEdges: Edge[]) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (node.data.type === BlockEnum.Agent && !(node as Node<AgentNodeType>).data.version) {
|
||||||
|
// TODO: formatting legacy agent node data
|
||||||
|
// (node as Node<ToolNodeType>).data.version = '2'
|
||||||
|
// const toolData = (node as Node<AgentNodeType>).data.agent_parameters?.tool
|
||||||
|
// const multipleTools = (node as Node<AgentNodeType>).data.agent_parameters?.multiple_tools
|
||||||
|
}
|
||||||
|
|
||||||
return node
|
return node
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user