diff --git a/web/app/components/workflow/constants.ts b/web/app/components/workflow/constants.ts index 975a8d5ed5..4723294445 100644 --- a/web/app/components/workflow/constants.ts +++ b/web/app/components/workflow/constants.ts @@ -249,7 +249,7 @@ export const LLM_OUTPUT_STRUCT: Var[] = [ variable: 'text', type: VarType.string, }, - + USAGE, ] export const KNOWLEDGE_RETRIEVAL_OUTPUT_STRUCT: Var[] = [ diff --git a/web/app/components/workflow/nodes/_base/components/selector.tsx b/web/app/components/workflow/nodes/_base/components/selector.tsx index 2cf7a5720b..05e5be406e 100644 --- a/web/app/components/workflow/nodes/_base/components/selector.tsx +++ b/web/app/components/workflow/nodes/_base/components/selector.tsx @@ -11,6 +11,8 @@ type Item = { } type Props = { trigger?: JSX.Element + DropDownIcon?: any + noLeft?: boolean options: Item[] value: string onChange: (value: any) => void @@ -24,6 +26,8 @@ type Props = { const TypeSelector: FC = ({ trigger, + DropDownIcon = ChevronSelectorVertical, + noLeft, options: list, value, onChange, @@ -41,7 +45,7 @@ const TypeSelector: FC = ({ setHide() }, ref) return ( -
+
{trigger ? (
= ({ onClick={toggleShow} className={cn(showOption && 'bg-black/5', 'flex items-center h-5 pl-1 pr-0.5 rounded-md text-xs font-semibold text-gray-700 cursor-pointer hover:bg-black/5')}>
{item?.label}
- +
)} diff --git a/web/app/components/workflow/nodes/_base/components/variable/var-list.tsx b/web/app/components/workflow/nodes/_base/components/variable/var-list.tsx index 8ed0707e88..a96090133a 100644 --- a/web/app/components/workflow/nodes/_base/components/variable/var-list.tsx +++ b/web/app/components/workflow/nodes/_base/components/variable/var-list.tsx @@ -4,13 +4,15 @@ import React, { useCallback } from 'react' import produce from 'immer' import RemoveButton from '../remove-button' import VarReferencePicker from './var-reference-picker' -import type { ValueSelector, Variable } from '@/app/components/workflow/types' +import { type ValueSelector, type Variable } from '@/app/components/workflow/types' +import { VarType as VarKindType } from '@/app/components/workflow/nodes/tool/types' type Props = { nodeId: string readonly: boolean list: Variable[] onChange: (list: Variable[]) => void + isSupportConstantValue?: boolean } const VarList: FC = ({ @@ -18,6 +20,7 @@ const VarList: FC = ({ readonly, list, onChange, + isSupportConstantValue, }) => { const handleVarNameChange = useCallback((index: number) => { return (e: React.ChangeEvent) => { @@ -29,11 +32,21 @@ const VarList: FC = ({ }, [list, onChange]) const handleVarReferenceChange = useCallback((index: number) => { - return (value: ValueSelector) => { + return (value: ValueSelector | string, varKindType: VarKindType) => { const newList = produce(list, (draft) => { - draft[index].value_selector = value - if (!draft[index].variable) - draft[index].variable = value[value.length - 1] + if (!isSupportConstantValue || varKindType === VarKindType.selector) { + draft[index].value_selector = value as ValueSelector + if (isSupportConstantValue) + draft[index].variable_type = VarKindType.selector + + if (!draft[index].variable) + draft[index].variable = value[value.length - 1] + } + else { + draft[index].variable_type = VarKindType.static + draft[index].value_selector = value as ValueSelector + draft[index].value = value as string + } }) onChange(newList) } @@ -63,8 +76,10 @@ const VarList: FC = ({ readonly={readonly} isShowNodeName className='grow' - value={item.value_selector} + value={item.variable_type === VarKindType.static ? (item.value || '') : (item.value_selector || [])} + isSupportConstantValue={isSupportConstantValue} onChange={handleVarReferenceChange(index)} + defaultVarKindType={item.variable_type} /> void + value: ValueSelector | string + onChange: (value: ValueSelector | string, varKindType: VarKindType) => void + isSupportConstantValue?: boolean + defaultVarKindType?: VarKindType } export const getNodeInfoById = (nodes: any, id: string) => { @@ -38,31 +44,38 @@ export const getNodeInfoById = (nodes: any, id: string) => { const VarReferencePicker: FC = ({ nodeId, + width, readonly, className, isShowNodeName, value, onChange, + isSupportConstantValue, + defaultVarKindType = VarKindType.static, }) => { const isChatMode = useIsChatMode() - + const [varKindType, setVarKindType] = useState(defaultVarKindType) + const isConstant = isSupportConstantValue && varKindType === VarKindType.static const { getTreeLeafNodes, getBeforeNodesInSameBranch } = useWorkflow() const availableNodes = getBeforeNodesInSameBranch(nodeId) const outputVars = toNodeOutputVars(availableNodes, isChatMode) const [open, setOpen] = useState(false) - const hasValue = value.length > 0 + const hasValue = !isConstant && value.length > 0 const outputVarNodeId = hasValue ? value[0] : '' const outputVarNode = hasValue ? getNodeInfoById(availableNodes, outputVarNodeId)?.data : null const varName = hasValue ? value[value.length - 1] : '' const getVarType = () => { + if (isConstant) + return 'undefined' + const targetVar = outputVars.find(v => v.nodeId === outputVarNodeId) if (!targetVar) return 'undefined' let type: VarType = VarType.string - let curr: any = targetVar.vars - value.slice(1).forEach((key, i) => { + let curr: any = targetVar.vars; + (value as ValueSelector).slice(1).forEach((key, i) => { const isLast = i === value.length - 2 curr = curr.find((v: any) => v.variable === key) if (isLast) { @@ -76,6 +89,38 @@ const VarReferencePicker: FC = ({ return type } + const varKindTypes = [ + { + label: 'Variable', + value: VarKindType.selector, + }, + { + label: 'Constant', + value: VarKindType.static, + }, + ] + + const handleVarKindTypeChange = useCallback((value: VarKindType) => { + setVarKindType(value) + if (value === VarKindType.static) + onChange('', value) + else + onChange([], value) + }, [varKindType]) + const inputRef = useRef(null) + const [isFocus, setIsFocus] = useState(false) + const [controlFocus, setControlFocus] = useState(0) + useEffect(() => { + if (controlFocus && inputRef.current) { + inputRef.current.focus() + setIsFocus(true) + } + }, [controlFocus]) + + const handleStaticChange = useCallback((e: React.ChangeEvent) => { + onChange(e.target.value as string, varKindType) + }, [onChange, varKindType]) + return (
= ({ onOpenChange={setOpen} placement='bottom-start' > - setOpen(!open)} className='!flex'> -
-
- {hasValue && ( - <> - {isShowNodeName && ( -
-
- + !isConstant && setOpen(!open)} className='!flex'> +
+ {isSupportConstantValue + ?
{ + e.stopPropagation() + setOpen(false) + }} className='mr-1 flex items-center space-x-1'> + +
+
+ :
+ +
} + {isConstant + ? ( + setIsFocus(true)} + onBlur={() => setIsFocus(false)} + /> + ) + : ( +
+ {hasValue && ( + <> + {isShowNodeName && ( +
+
+ +
+
{outputVarNode?.title}
+ +
+ )} +
+ +
{varName}
-
{outputVarNode?.title}
- -
+
{getVarType()}
+ )} -
- -
{varName}
-
-
{getVarType()}
- +
)} -
- { - onChange(value) - setOpen(false) - }} - /> + {!isConstant && ( + { + onChange(value, varKindType) + setOpen(false) + }} + itemWidth={width} + /> + )} -
+
) } export default React.memo(VarReferencePicker) diff --git a/web/app/components/workflow/nodes/_base/components/variable/var-reference-popup.tsx b/web/app/components/workflow/nodes/_base/components/variable/var-reference-popup.tsx index cb788e31c2..fdbe9e788e 100644 --- a/web/app/components/workflow/nodes/_base/components/variable/var-reference-popup.tsx +++ b/web/app/components/workflow/nodes/_base/components/variable/var-reference-popup.tsx @@ -13,6 +13,7 @@ type ObjectChildrenProps = { data: Var[] objPath: string[] onChange: (value: ValueSelector) => void + itemWidth?: number } type ItemProps = { @@ -21,6 +22,7 @@ type ItemProps = { objPath: string[] itemData: Var onChange: (value: ValueSelector) => void + itemWidth?: number } const Item: FC = ({ @@ -29,6 +31,7 @@ const Item: FC = ({ objPath, itemData, onChange, + itemWidth, }) => { const isObj = itemData.type === VarType.object && itemData.children && itemData.children.length > 0 const itemRef = useRef(null) @@ -40,7 +43,11 @@ const Item: FC = ({ return (
@@ -59,6 +66,7 @@ const Item: FC = ({ objPath={[...objPath, itemData.variable]} data={itemData.children as Var[]} onChange={onChange} + itemWidth={itemWidth} /> )}
@@ -71,11 +79,15 @@ const ObjectChildren: FC = ({ objPath, data, onChange, + itemWidth, }) => { const currObjPath = objPath return ( -
+
{title}.{currObjPath.join('.')}
{ data?.map((v, i) => ( @@ -96,14 +108,17 @@ const ObjectChildren: FC = ({ type Props = { vars: NodeOutPutVar[] onChange: (value: ValueSelector) => void + itemWidth?: number } const VarReferencePopup: FC = ({ - vars, onChange, + itemWidth, }) => { return ( -
+
{vars.map((item, i) => (
{item.title}
@@ -115,6 +130,7 @@ const VarReferencePopup: FC = ({ objPath={[]} itemData={v} onChange={onChange} + itemWidth={itemWidth} /> ))}
diff --git a/web/app/components/workflow/nodes/tool/components/input-var-list.tsx b/web/app/components/workflow/nodes/tool/components/input-var-list.tsx index c737730ba1..7bc0d79431 100644 --- a/web/app/components/workflow/nodes/tool/components/input-var-list.tsx +++ b/web/app/components/workflow/nodes/tool/components/input-var-list.tsx @@ -3,7 +3,8 @@ import type { FC } from 'react' import React, { useCallback } from 'react' import produce from 'immer' import type { ToolVarInput } from '../types' -import { VarType } from '../types' +import { VarType as VarKindType } from '../types' +import { type ValueSelector } from '@/app/components/workflow/types' import type { CredentialFormSchema } from '@/app/components/header/account-setting/model-provider-page/declarations' import { FormTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations' import { useLanguage } from '@/app/components/header/account-setting/model-provider-page/hooks' @@ -15,6 +16,7 @@ type Props = { schema: CredentialFormSchema[] value: ToolVarInput[] onChange: (value: ToolVarInput[]) => void + isSupportConstantValue?: boolean } const InputVarList: FC = ({ @@ -23,6 +25,7 @@ const InputVarList: FC = ({ schema, value, onChange, + isSupportConstantValue, }) => { const language = useLanguage() @@ -35,17 +38,26 @@ const InputVarList: FC = ({ })() const handleChange = useCallback((variable: string) => { - return (varValue: any) => { + return (varValue: ValueSelector | string, varKindType: VarKindType) => { const newValue = produce(value, (draft: ToolVarInput[]) => { const target = draft.find(item => item.variable === variable) if (target) { - target.value_selector = varValue // TODO: support constant value + if (!isSupportConstantValue || varKindType === VarKindType.selector) { + if (isSupportConstantValue) + target.variable_type = VarKindType.selector + + target.value_selector = varValue as ValueSelector + } + else { + target.variable_type = VarKindType.static + target.value = varValue as string + } } else { draft.push({ variable, - variable_type: VarType.selector, // TODO: support constant value - value_selector: varValue, + variable_type: VarKindType.static, + value: '', }) } }) @@ -74,9 +86,12 @@ const InputVarList: FC = ({ {tooltip &&
{tooltip[language] || tooltip.en_US}
}
diff --git a/web/app/components/workflow/nodes/tool/panel.tsx b/web/app/components/workflow/nodes/tool/panel.tsx index 349284b9c1..9ba8b861c2 100644 --- a/web/app/components/workflow/nodes/tool/panel.tsx +++ b/web/app/components/workflow/nodes/tool/panel.tsx @@ -82,6 +82,7 @@ const Panel: FC> = ({ schema={toolInputVarSchema as any} value={inputs.tool_parameters} onChange={setInputVar} + isSupportConstantValue /> )} diff --git a/web/app/components/workflow/types.ts b/web/app/components/workflow/types.ts index ed05bba221..66c59dc23b 100644 --- a/web/app/components/workflow/types.ts +++ b/web/app/components/workflow/types.ts @@ -3,6 +3,7 @@ import type { Node as ReactFlowNode, } from 'reactflow' import type { ToolDefaultValue } from '@/app/components/workflow/block-selector/types' +import type { VarType as VarKindType } from '@/app/components/workflow/nodes/tool/types' export enum BlockEnum { Start = 'start', @@ -57,6 +58,8 @@ export type ValueSelector = string[] // [nodeId, key | obj key path] export type Variable = { variable: string value_selector: ValueSelector + variable_type?: VarKindType + value?: string } export type VariableWithValue = {