diff --git a/web/app/components/plugins/plugin-detail-panel/tool-selector/reasoning-config-form.tsx b/web/app/components/plugins/plugin-detail-panel/tool-selector/reasoning-config-form.tsx index c48833a640..86141eb055 100644 --- a/web/app/components/plugins/plugin-detail-panel/tool-selector/reasoning-config-form.tsx +++ b/web/app/components/plugins/plugin-detail-panel/tool-selector/reasoning-config-form.tsx @@ -36,21 +36,24 @@ type Props = { value: Record onChange: (val: Record) => void schemas: any[] - nodeOutputVars: NodeOutPutVar[] - availableNodes: Node[] - nodeId: string + nodeOutputVars?: NodeOutPutVar[] + availableNodes?: Node[] + nodeId?: string + disableVariableReference?: boolean } const ReasoningConfigForm: React.FC = ({ value, onChange, schemas, - nodeOutputVars, - availableNodes, + nodeOutputVars = [], + availableNodes = [], nodeId, + disableVariableReference = false, }) => { const { t } = useTranslation() const language = useLanguage() + const allowVariableReference = !disableVariableReference && !!nodeId const getVarKindType = (type: FormTypeEnum) => { if (type === FormTypeEnum.file || type === FormTypeEnum.files) return VarKindType.variable @@ -173,7 +176,7 @@ const ReasoningConfigForm: React.FC = ({ 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 showVariableSelector = allowVariableReference && (isFile || varInput?.type === VarKindType.variable) const targetVarType = () => { if (isString) return VarType.string @@ -252,7 +255,7 @@ const ReasoningConfigForm: React.FC = ({ {showTypeSwitch && ( )} - {isString && ( + {isString && allowVariableReference && ( = ({ availableNodes={availableNodes} /> )} + {isString && !allowVariableReference && ( + handleValueChange(variable, type)(e.target.value)} + placeholder={placeholder?.[language] || placeholder?.en_US} + /> + )} {isNumber && isConstant && ( = ({ className="h-8 grow" readonly={false} isShowNodeName - nodeId={nodeId} + nodeId={nodeId || ''} value={varInput?.value || []} onChange={handleVariableSelectorChange(variable)} filterVar={getFilterVar()} diff --git a/web/app/components/workflow/nodes/_base/components/form-input-item.tsx b/web/app/components/workflow/nodes/_base/components/form-input-item.tsx index 419f905fa5..2dfdc32ad3 100644 --- a/web/app/components/workflow/nodes/_base/components/form-input-item.tsx +++ b/web/app/components/workflow/nodes/_base/components/form-input-item.tsx @@ -9,7 +9,7 @@ import { Listbox, ListboxButton, ListboxOption, ListboxOptions } from '@headless import { ChevronDownIcon } from '@heroicons/react/20/solid' import { RiCheckLine, RiLoader4Line } from '@remixicon/react' -import { useEffect, useMemo, useState } from 'react' +import { useContext, useEffect, useMemo, useState } from 'react' import CheckboxList from '@/app/components/base/checkbox-list' import Input from '@/app/components/base/input' import { SimpleSelect } from '@/app/components/base/select' @@ -18,6 +18,8 @@ import { useLanguage } from '@/app/components/header/account-setting/model-provi import AppSelector from '@/app/components/plugins/plugin-detail-panel/app-selector' import ModelParameterModal from '@/app/components/plugins/plugin-detail-panel/model-selector' import { PluginCategoryEnum } from '@/app/components/plugins/types' +import { WorkflowContext } from '@/app/components/workflow/context' +import { HooksStoreContext } from '@/app/components/workflow/hooks-store/provider' 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 useAvailableVarList from '@/app/components/workflow/nodes/_base/hooks/use-available-var-list' @@ -47,6 +49,87 @@ type Props = { disableVariableInsertion?: boolean } +type VariableReferenceFieldsProps = { + nodeId: string + isString: boolean + showVariableSelector: boolean + readOnly: boolean + schema: CredentialFormSchema + varInput: ResourceVarInputs[string] + targetVarType: string + filterVar?: (payload: Var, selector: ValueSelector) => boolean + onValueChange: (newValue: any) => void + onVariableSelectorChange: (newValue: ValueSelector | string) => void + showManageInputField?: boolean + onManageInputField?: () => void + disableVariableInsertion?: boolean + inPanel?: boolean + currentTool?: Tool | Event + currentProvider?: ToolWithProvider | TriggerWithProvider + isFilterFileVar?: boolean +} + +const VariableReferenceFields: FC = ({ + nodeId, + isString, + showVariableSelector, + readOnly, + schema, + varInput, + targetVarType, + filterVar, + onValueChange, + onVariableSelectorChange, + showManageInputField, + onManageInputField, + disableVariableInsertion, + inPanel, + currentTool, + currentProvider, + isFilterFileVar, +}) => { + const { availableVars, availableNodesWithParent } = useAvailableVarList(nodeId, { + onlyLeafNodeVar: false, + filterVar: filterVar || (() => true), + }) + + return ( + <> + {isString && ( + + )} + {showVariableSelector && ( + + )} + + ) +} + const FormInputItem: FC = ({ readOnly, nodeId, @@ -63,6 +146,9 @@ const FormInputItem: FC = ({ disableVariableInsertion = false, }) => { const language = useLanguage() + const hooksStore = useContext(HooksStoreContext) + const workflowStore = useContext(WorkflowContext) + const canUseWorkflowHooks = !!hooksStore && !!workflowStore const [toolsOptions, setToolsOptions] = useState(null) const [isLoadingToolsOptions, setIsLoadingToolsOptions] = useState(false) @@ -89,17 +175,11 @@ const FormInputItem: FC = ({ const isDynamicSelect = type === FormTypeEnum.dynamicSelect const isAppSelector = type === FormTypeEnum.appSelector const isModelSelector = type === FormTypeEnum.modelSelector - const showTypeSwitch = isNumber || isBoolean || isObject || isArray || isSelect + const showTypeSwitch = canUseWorkflowHooks && (isNumber || isBoolean || isObject || isArray || isSelect) const isConstant = varInput?.type === VarKindType.constant || !varInput?.type - const showVariableSelector = isFile || varInput?.type === VarKindType.variable + const showVariableSelector = canUseWorkflowHooks && (isFile || varInput?.type === VarKindType.variable) const isMultipleSelect = multiple && (isSelect || isDynamicSelect) - - const { availableVars, availableNodesWithParent } = useAvailableVarList(nodeId, { - onlyLeafNodeVar: false, - filterVar: (varPayload: Var) => { - return [VarType.string, VarType.number, VarType.secret].includes(varPayload.type) - }, - }) + const canRenderVariableReference = canUseWorkflowHooks && !!nodeId const targetVarType = () => { if (isString) @@ -327,16 +407,34 @@ const FormInputItem: FC = ({ {showTypeSwitch && ( )} - {isString && ( - handleValueChange(e.target.value)} + placeholder={placeholder?.[language] || placeholder?.en_US} + disabled={readOnly} + /> + )} + {canRenderVariableReference && ( + handleVariableSelectorChange(newValue, variable)} showManageInputField={showManageInputField} onManageInputField={onManageInputField} disableVariableInsertion={disableVariableInsertion} + inPanel={inPanel} + currentTool={currentTool} + currentProvider={currentProvider} + isFilterFileVar={isBoolean} /> )} {isNumber && isConstant && ( @@ -572,23 +670,6 @@ const FormInputItem: FC = ({ scope={scope} /> )} - {showVariableSelector && ( - handleVariableSelectorChange(value, variable)} - filterVar={getFilterVar()} - schema={schema} - valueTypePlaceHolder={targetVarType()} - currentTool={currentTool} - currentProvider={currentProvider} - isFilterFileVar={isBoolean} - /> - )} ) } diff --git a/web/app/components/workflow/skill/editor/skill-editor/plugins/tool-block/component.tsx b/web/app/components/workflow/skill/editor/skill-editor/plugins/tool-block/component.tsx index 462fb421e5..41d865e449 100644 --- a/web/app/components/workflow/skill/editor/skill-editor/plugins/tool-block/component.tsx +++ b/web/app/components/workflow/skill/editor/skill-editor/plugins/tool-block/component.tsx @@ -240,8 +240,6 @@ const ToolBlockComponent: FC = ({ value={toolValue} onChange={handleToolValueChange} nodeId={undefined} - nodeOutputVars={[]} - availableNodes={[]} /> )} diff --git a/web/app/components/workflow/skill/editor/skill-editor/tool-setting/tool-settings-section.tsx b/web/app/components/workflow/skill/editor/skill-editor/tool-setting/tool-settings-section.tsx index 260bed4bc3..d7117dac0e 100644 --- a/web/app/components/workflow/skill/editor/skill-editor/tool-setting/tool-settings-section.tsx +++ b/web/app/components/workflow/skill/editor/skill-editor/tool-setting/tool-settings-section.tsx @@ -1,26 +1,23 @@ 'use client' import type { FC } from 'react' -import type { Node } from 'reactflow' import type { Tool } from '@/app/components/tools/types' import type { ToolValue } from '@/app/components/workflow/block-selector/types' -import type { NodeOutPutVar, ToolWithProvider } from '@/app/components/workflow/types' +import type { ToolWithProvider } from '@/app/components/workflow/types' import * as React from 'react' -import { useMemo, useState } from 'react' +import { useMemo } from 'react' import { useTranslation } from 'react-i18next' import Divider from '@/app/components/base/divider' -import TabSlider from '@/app/components/base/tab-slider-plain' +import { FormTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations' import ReasoningConfigForm from '@/app/components/plugins/plugin-detail-panel/tool-selector/reasoning-config-form' -import { getPlainValue, getStructureValue, toolParametersToFormSchemas } from '@/app/components/tools/utils/to-form-schema' -import ToolForm from '@/app/components/workflow/nodes/tool/components/tool-form' +import { toolParametersToFormSchemas } from '@/app/components/tools/utils/to-form-schema' +import { VarKindType } from '@/app/components/workflow/nodes/_base/types' type ToolSettingsSectionProps = { currentProvider?: ToolWithProvider currentTool?: Tool value?: ToolValue nodeId?: string - nodeOutputVars?: NodeOutPutVar[] - availableNodes?: Node[] onChange?: (value: ToolValue) => void } @@ -29,12 +26,9 @@ const ToolSettingsSection: FC = ({ currentTool, value, nodeId, - nodeOutputVars = [], - availableNodes = [], onChange, }) => { const { t } = useTranslation() - const [currType, setCurrType] = useState<'settings' | 'params'>('settings') const safeNodeId = nodeId ?? '' const currentToolSettings = useMemo(() => { @@ -52,17 +46,12 @@ const ToolSettingsSection: FC = ({ const paramsFormSchemas = useMemo(() => toolParametersToFormSchemas(currentToolParams), [currentToolParams]) const allowReasoning = !!safeNodeId - const showTabSlider = allowReasoning && currentToolSettings.length > 0 && currentToolParams.length > 0 - const userSettingsOnly = currentToolSettings.length > 0 && (!allowReasoning || !currentToolParams.length) - const reasoningConfigOnly = allowReasoning && currentToolParams.length > 0 && currentToolSettings.length === 0 - const handleSettingsFormChange = (v: Record) => { if (!value || !onChange) return - const newValue = getStructureValue(v) onChange({ ...value, - settings: newValue, + settings: v, }) } @@ -81,40 +70,51 @@ const ToolSettingsSection: FC = ({ if (!currentToolSettings.length && !currentToolParams.length) return null + const showSettingsSection = currentToolSettings.length > 0 + const showParamsSection = allowReasoning && currentToolParams.length > 0 + const getVarKindType = (type: FormTypeEnum) => { + if (type === FormTypeEnum.file || type === FormTypeEnum.files) + return VarKindType.variable + if (type === FormTypeEnum.select || type === FormTypeEnum.checkbox || type === FormTypeEnum.textNumber || type === FormTypeEnum.array || type === FormTypeEnum.object) + return VarKindType.constant + if (type === FormTypeEnum.textInput || type === FormTypeEnum.secretInput) + return VarKindType.mixed + return VarKindType.constant + } + const getSafeConfigValue = (rawValue: Record | undefined, schemas: any[]) => { + const nextValue = { ...(rawValue || {}) } + schemas.forEach((schema) => { + if (!nextValue[schema.variable]) { + nextValue[schema.variable] = { + auto: 0, + value: { + type: getVarKindType(schema.type as FormTypeEnum), + value: schema.default ?? null, + }, + } + return + } + if (nextValue[schema.variable].auto === undefined) + nextValue[schema.variable].auto = 0 + if (nextValue[schema.variable].value === undefined) { + nextValue[schema.variable].value = { + type: getVarKindType(schema.type as FormTypeEnum), + value: schema.default ?? null, + } + } + }) + return nextValue + } + return ( <> - {/* tabs */} - {showTabSlider && ( - { - setCurrType(value as 'settings' | 'params') - }} - options={[ - { value: 'settings', text: t('detailPanel.toolSelector.settings', { ns: 'plugin' })! }, - { value: 'params', text: t('detailPanel.toolSelector.params', { ns: 'plugin' })! }, - ]} - /> - )} - {showTabSlider && currType === 'params' && ( -
-
{t('detailPanel.toolSelector.paramsTip1', { ns: 'plugin' })}
-
{t('detailPanel.toolSelector.paramsTip2', { ns: 'plugin' })}
-
- )} - {/* user settings only */} - {userSettingsOnly && ( + {showSettingsSection && (
{t('detailPanel.toolSelector.settings', { ns: 'plugin' })}
)} - {/* reasoning config only */} - {reasoningConfigOnly && ( + {showParamsSection && (
{t('detailPanel.toolSelector.params', { ns: 'plugin' })}
@@ -123,28 +123,22 @@ const ToolSettingsSection: FC = ({
)} - {/* user settings form */} - {(currType === 'settings' || userSettingsOnly) && ( -
- -
- )} - {/* reasoning config form */} - {allowReasoning && (currType === 'params' || reasoningConfigOnly) && ( + {showSettingsSection && ( + )} + {showParamsSection && ( + )}