+ )}
+
void
+ hideTopMenu?: boolean
+ className?: string
+ readonly?: boolean
}
const SchemaEditor: FC = ({
schema,
onUpdate,
+ hideTopMenu,
+ className,
+ readonly = false,
}) => {
return (
)
}
diff --git a/web/app/components/workflow/nodes/llm/default.ts b/web/app/components/workflow/nodes/llm/default.ts
index 92377f74b..efe7fd8b6 100644
--- a/web/app/components/workflow/nodes/llm/default.ts
+++ b/web/app/components/workflow/nodes/llm/default.ts
@@ -1,8 +1,29 @@
+// import { RETRIEVAL_OUTPUT_STRUCT } from '../../constants'
import { BlockEnum, EditionType } from '../../types'
import { type NodeDefault, type PromptItem, PromptRole } from '../../types'
import type { LLMNodeType } from './types'
import { ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS } from '@/app/components/workflow/blocks'
+const RETRIEVAL_OUTPUT_STRUCT = `{
+ "content": "",
+ "title": "",
+ "url": "",
+ "icon": "",
+ "metadata": {
+ "dataset_id": "",
+ "dataset_name": "",
+ "document_id": [],
+ "document_name": "",
+ "document_data_source_type": "",
+ "segment_id": "",
+ "segment_position": "",
+ "segment_word_count": "",
+ "segment_hit_count": "",
+ "segment_index_node_hash": "",
+ "score": ""
+ }
+}`
+
const i18nPrefix = 'workflow.errorMsg'
const nodeDefault: NodeDefault = {
@@ -27,6 +48,10 @@ const nodeDefault: NodeDefault = {
enabled: false,
},
},
+ defaultRunInputData: {
+ '#context#': [RETRIEVAL_OUTPUT_STRUCT],
+ '#files#': [],
+ },
getAvailablePrevNodes(isChatMode: boolean) {
const nodes = isChatMode
? ALL_CHAT_AVAILABLE_BLOCKS
diff --git a/web/app/components/workflow/nodes/llm/panel.tsx b/web/app/components/workflow/nodes/llm/panel.tsx
index 29fb4fb2c..04acb61ef 100644
--- a/web/app/components/workflow/nodes/llm/panel.tsx
+++ b/web/app/components/workflow/nodes/llm/panel.tsx
@@ -5,7 +5,6 @@ import MemoryConfig from '../_base/components/memory-config'
import VarReferencePicker from '../_base/components/variable/var-reference-picker'
import ConfigVision from '../_base/components/config-vision'
import useConfig from './use-config'
-import { findVariableWhenOnLLMVision } from '../utils'
import type { LLMNodeType } from './types'
import ConfigPrompt from './components/config-prompt'
import VarList from '@/app/components/workflow/nodes/_base/components/variable/var-list'
@@ -14,10 +13,7 @@ import Field from '@/app/components/workflow/nodes/_base/components/field'
import Split from '@/app/components/workflow/nodes/_base/components/split'
import ModelParameterModal from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal'
import OutputVars, { VarItem } from '@/app/components/workflow/nodes/_base/components/output-vars'
-import { InputVarType, type NodePanelProps } from '@/app/components/workflow/types'
-import BeforeRunForm from '@/app/components/workflow/nodes/_base/components/before-run-form'
-import type { Props as FormProps } from '@/app/components/workflow/nodes/_base/components/before-run-form/form'
-import ResultPanel from '@/app/components/workflow/run/result-panel'
+import type { NodePanelProps } from '@/app/components/workflow/types'
import Tooltip from '@/app/components/base/tooltip'
import Editor from '@/app/components/workflow/nodes/_base/components/prompt/editor'
import StructureOutput from './components/structure-output'
@@ -31,7 +27,6 @@ const Panel: FC> = ({
data,
}) => {
const { t } = useTranslation()
-
const {
readOnly,
inputs,
@@ -58,80 +53,16 @@ const Panel: FC> = ({
handleMemoryChange,
handleVisionResolutionEnabledChange,
handleVisionResolutionChange,
- isShowSingleRun,
- hideSingleRun,
- inputVarValues,
- setInputVarValues,
- visionFiles,
- setVisionFiles,
- contexts,
- setContexts,
- runningStatus,
isModelSupportStructuredOutput,
structuredOutputCollapsed,
setStructuredOutputCollapsed,
handleStructureOutputEnableChange,
handleStructureOutputChange,
- handleRun,
- handleStop,
- varInputs,
- runResult,
filterJinjia2InputVar,
} = useConfig(id, data)
const model = inputs.model
- const singleRunForms = (() => {
- const forms: FormProps[] = []
-
- if (varInputs.length > 0) {
- forms.push(
- {
- label: t(`${i18nPrefix}.singleRun.variable`)!,
- inputs: varInputs,
- values: inputVarValues,
- onChange: setInputVarValues,
- },
- )
- }
-
- if (inputs.context?.variable_selector && inputs.context?.variable_selector.length > 0) {
- forms.push(
- {
- label: t(`${i18nPrefix}.context`)!,
- inputs: [{
- label: '',
- variable: '#context#',
- type: InputVarType.contexts,
- required: false,
- }],
- values: { '#context#': contexts },
- onChange: keyValue => setContexts(keyValue['#context#']),
- },
- )
- }
-
- if (isVisionModel && data.vision?.enabled && data.vision?.configs?.variable_selector) {
- const currentVariable = findVariableWhenOnLLMVision(data.vision.configs.variable_selector, availableVars)
-
- forms.push(
- {
- label: t(`${i18nPrefix}.vision`)!,
- inputs: [{
- label: currentVariable?.variable as any,
- variable: '#files#',
- type: currentVariable?.formType as any,
- required: false,
- }],
- values: { '#files#': visionFiles },
- onChange: keyValue => setVisionFiles((keyValue as any)['#files#']),
- },
- )
- }
-
- return forms
- })()
-
const handleModelChange = useCallback((model: {
provider: string
modelId: string
@@ -344,18 +275,6 @@ const Panel: FC> = ({
)}
>
- {isShowSingleRun && (
- }
- />
- )}
)
}
diff --git a/web/app/components/workflow/nodes/llm/use-config.ts b/web/app/components/workflow/nodes/llm/use-config.ts
index cd2c55225..e4da65bed 100644
--- a/web/app/components/workflow/nodes/llm/use-config.ts
+++ b/web/app/components/workflow/nodes/llm/use-config.ts
@@ -16,9 +16,8 @@ import {
ModelTypeEnum,
} from '@/app/components/header/account-setting/model-provider-page/declarations'
import useNodeCrud from '@/app/components/workflow/nodes/_base/hooks/use-node-crud'
-import useOneStepRun from '@/app/components/workflow/nodes/_base/hooks/use-one-step-run'
-import { RETRIEVAL_OUTPUT_STRUCT } from '@/app/components/workflow/constants'
import { checkHasContextBlock, checkHasHistoryBlock, checkHasQueryBlock } from '@/app/components/base/prompt-editor/constants'
+import useInspectVarsCrud from '@/app/components/workflow/hooks/use-inspect-vars-crud'
const useConfig = (id: string, payload: LLMNodeType) => {
const { nodesReadOnly: readOnly } = useNodesReadOnly()
@@ -29,6 +28,8 @@ const useConfig = (id: string, payload: LLMNodeType) => {
const { inputs, setInputs: doSetInputs } = useNodeCrud
(id, payload)
const inputRef = useRef(inputs)
+ const { deleteNodeInspectorVars } = useInspectVarsCrud()
+
const setInputs = useCallback((newInputs: LLMNodeType) => {
if (newInputs.memory && !newInputs.memory.role_prefix) {
const newPayload = produce(newInputs, (draft) => {
@@ -293,14 +294,16 @@ const useConfig = (id: string, payload: LLMNodeType) => {
setInputs(newInputs)
if (enabled)
setStructuredOutputCollapsed(false)
- }, [inputs, setInputs])
+ deleteNodeInspectorVars(id)
+ }, [inputs, setInputs, deleteNodeInspectorVars, id])
const handleStructureOutputChange = useCallback((newOutput: StructuredOutput) => {
const newInputs = produce(inputs, (draft) => {
draft.structured_output = newOutput
})
setInputs(newInputs)
- }, [inputs, setInputs])
+ deleteNodeInspectorVars(id)
+ }, [inputs, setInputs, deleteNodeInspectorVars, id])
const filterInputVar = useCallback((varPayload: Var) => {
return [VarType.number, VarType.string, VarType.secret, VarType.arrayString, VarType.arrayNumber, VarType.file, VarType.arrayFile].includes(varPayload.type)
@@ -322,81 +325,6 @@ const useConfig = (id: string, payload: LLMNodeType) => {
filterVar: filterMemoryPromptVar,
})
- // single run
- const {
- isShowSingleRun,
- hideSingleRun,
- getInputVars,
- runningStatus,
- handleRun,
- handleStop,
- runInputData,
- runInputDataRef,
- setRunInputData,
- runResult,
- toVarInputs,
- } = useOneStepRun({
- id,
- data: inputs,
- defaultRunInputData: {
- '#context#': [RETRIEVAL_OUTPUT_STRUCT],
- '#files#': [],
- },
- })
-
- const inputVarValues = (() => {
- const vars: Record = {}
- Object.keys(runInputData)
- .filter(key => !['#context#', '#files#'].includes(key))
- .forEach((key) => {
- vars[key] = runInputData[key]
- })
- return vars
- })()
-
- const setInputVarValues = useCallback((newPayload: Record) => {
- const newVars = {
- ...newPayload,
- '#context#': runInputDataRef.current['#context#'],
- '#files#': runInputDataRef.current['#files#'],
- }
- setRunInputData(newVars)
- }, [runInputDataRef, setRunInputData])
-
- const contexts = runInputData['#context#']
- const setContexts = useCallback((newContexts: string[]) => {
- setRunInputData({
- ...runInputDataRef.current,
- '#context#': newContexts,
- })
- }, [runInputDataRef, setRunInputData])
-
- const visionFiles = runInputData['#files#']
- const setVisionFiles = useCallback((newFiles: any[]) => {
- setRunInputData({
- ...runInputDataRef.current,
- '#files#': newFiles,
- })
- }, [runInputDataRef, setRunInputData])
-
- const allVarStrArr = (() => {
- const arr = isChatModel ? (inputs.prompt_template as PromptItem[]).filter(item => item.edition_type !== EditionType.jinja2).map(item => item.text) : [(inputs.prompt_template as PromptItem).text]
- if (isChatMode && isChatModel && !!inputs.memory) {
- arr.push('{{#sys.query#}}')
- arr.push(inputs.memory.query_prompt_template)
- }
-
- return arr
- })()
-
- const varInputs = (() => {
- const vars = getInputVars(allVarStrArr)
- if (isShowVars)
- return [...vars, ...toVarInputs(inputs.prompt_config?.jinja2_variables || [])]
-
- return vars
- })()
-
return {
readOnly,
isChatMode,
@@ -423,24 +351,11 @@ const useConfig = (id: string, payload: LLMNodeType) => {
handleSyeQueryChange,
handleVisionResolutionEnabledChange,
handleVisionResolutionChange,
- isShowSingleRun,
- hideSingleRun,
- inputVarValues,
- setInputVarValues,
- visionFiles,
- setVisionFiles,
- contexts,
- setContexts,
- varInputs,
- runningStatus,
isModelSupportStructuredOutput,
handleStructureOutputChange,
structuredOutputCollapsed,
setStructuredOutputCollapsed,
handleStructureOutputEnableChange,
- handleRun,
- handleStop,
- runResult,
filterJinjia2InputVar,
}
}
diff --git a/web/app/components/workflow/nodes/llm/use-single-run-form-params.ts b/web/app/components/workflow/nodes/llm/use-single-run-form-params.ts
new file mode 100644
index 000000000..93a8638d0
--- /dev/null
+++ b/web/app/components/workflow/nodes/llm/use-single-run-form-params.ts
@@ -0,0 +1,198 @@
+import type { MutableRefObject } from 'react'
+import { useTranslation } from 'react-i18next'
+import type { Props as FormProps } from '@/app/components/workflow/nodes/_base/components/before-run-form/form'
+import type { InputVar, PromptItem, Var, Variable } from '@/app/components/workflow/types'
+import { InputVarType, VarType } from '@/app/components/workflow/types'
+import type { LLMNodeType } from './types'
+import { EditionType } from '../../types'
+import useNodeCrud from '../_base/hooks/use-node-crud'
+import { useIsChatMode } from '../../hooks'
+import { useCallback } from 'react'
+import useConfigVision from '../../hooks/use-config-vision'
+import { noop } from 'lodash-es'
+import { findVariableWhenOnLLMVision } from '../utils'
+import useAvailableVarList from '../_base/hooks/use-available-var-list'
+
+const i18nPrefix = 'workflow.nodes.llm'
+type Params = {
+ id: string,
+ payload: LLMNodeType,
+ runInputData: Record
+ runInputDataRef: MutableRefObject>
+ getInputVars: (textList: string[]) => InputVar[]
+ setRunInputData: (data: Record) => void
+ toVarInputs: (variables: Variable[]) => InputVar[]
+}
+const useSingleRunFormParams = ({
+ id,
+ payload,
+ runInputData,
+ runInputDataRef,
+ getInputVars,
+ setRunInputData,
+ toVarInputs,
+}: Params) => {
+ const { t } = useTranslation()
+ const { inputs } = useNodeCrud(id, payload)
+ const getVarInputs = getInputVars
+ const isChatMode = useIsChatMode()
+
+ const contexts = runInputData['#context#']
+ const setContexts = useCallback((newContexts: string[]) => {
+ setRunInputData?.({
+ ...runInputDataRef.current,
+ '#context#': newContexts,
+ })
+ }, [runInputDataRef, setRunInputData])
+
+ const visionFiles = runInputData['#files#']
+ const setVisionFiles = useCallback((newFiles: any[]) => {
+ setRunInputData?.({
+ ...runInputDataRef.current,
+ '#files#': newFiles,
+ })
+ }, [runInputDataRef, setRunInputData])
+
+ // model
+ const model = inputs.model
+ const modelMode = inputs.model?.mode
+ const isChatModel = modelMode === 'chat'
+ const {
+ isVisionModel,
+ } = useConfigVision(model, {
+ payload: inputs.vision,
+ onChange: noop,
+ })
+
+ const isShowVars = (() => {
+ if (isChatModel)
+ return (inputs.prompt_template as PromptItem[]).some(item => item.edition_type === EditionType.jinja2)
+
+ return (inputs.prompt_template as PromptItem).edition_type === EditionType.jinja2
+ })()
+
+ const filterMemoryPromptVar = useCallback((varPayload: Var) => {
+ return [VarType.arrayObject, VarType.array, VarType.number, VarType.string, VarType.secret, VarType.arrayString, VarType.arrayNumber, VarType.file, VarType.arrayFile].includes(varPayload.type)
+ }, [])
+
+ const {
+ availableVars,
+ } = useAvailableVarList(id, {
+ onlyLeafNodeVar: false,
+ filterVar: filterMemoryPromptVar,
+ })
+
+ const allVarStrArr = (() => {
+ const arr = isChatModel ? (inputs.prompt_template as PromptItem[]).filter(item => item.edition_type !== EditionType.jinja2).map(item => item.text) : [(inputs.prompt_template as PromptItem).text]
+ if (isChatMode && isChatModel && !!inputs.memory) {
+ arr.push('{{#sys.query#}}')
+ arr.push(inputs.memory.query_prompt_template)
+ }
+
+ return arr
+ })()
+ const varInputs = (() => {
+ const vars = getVarInputs(allVarStrArr) || []
+ if (isShowVars)
+ return [...vars, ...(toVarInputs ? (toVarInputs(inputs.prompt_config?.jinja2_variables || [])) : [])]
+
+ return vars
+ })()
+
+ const inputVarValues = (() => {
+ const vars: Record = {}
+ Object.keys(runInputData)
+ .filter(key => !['#context#', '#files#'].includes(key))
+ .forEach((key) => {
+ vars[key] = runInputData[key]
+ })
+ return vars
+ })()
+
+ const setInputVarValues = useCallback((newPayload: Record) => {
+ const newVars = {
+ ...newPayload,
+ '#context#': runInputDataRef.current['#context#'],
+ '#files#': runInputDataRef.current['#files#'],
+ }
+ setRunInputData?.(newVars)
+ }, [runInputDataRef, setRunInputData])
+
+ const forms = (() => {
+ const forms: FormProps[] = []
+
+ if (varInputs.length > 0) {
+ forms.push(
+ {
+ label: t(`${i18nPrefix}.singleRun.variable`)!,
+ inputs: varInputs,
+ values: inputVarValues,
+ onChange: setInputVarValues,
+ },
+ )
+ }
+
+ if (inputs.context?.variable_selector && inputs.context?.variable_selector.length > 0) {
+ forms.push(
+ {
+ label: t(`${i18nPrefix}.context`)!,
+ inputs: [{
+ label: '',
+ variable: '#context#',
+ type: InputVarType.contexts,
+ required: false,
+ }],
+ values: { '#context#': contexts },
+ onChange: keyValue => setContexts(keyValue['#context#']),
+ },
+ )
+ }
+ if (isVisionModel && payload.vision?.enabled && payload.vision?.configs?.variable_selector) {
+ const currentVariable = findVariableWhenOnLLMVision(payload.vision.configs.variable_selector, availableVars)
+
+ forms.push(
+ {
+ label: t(`${i18nPrefix}.vision`)!,
+ inputs: [{
+ label: currentVariable?.variable as any,
+ variable: '#files#',
+ type: currentVariable?.formType as any,
+ required: false,
+ }],
+ values: { '#files#': visionFiles },
+ onChange: keyValue => setVisionFiles((keyValue as any)['#files#']),
+ },
+ )
+ }
+ return forms
+ })()
+
+ const getDependentVars = () => {
+ const promptVars = varInputs.map(item => item.variable.slice(1, -1).split('.'))
+ const contextVar = payload.context.variable_selector
+ const vars = [...promptVars, contextVar]
+ if (isVisionModel && payload.vision?.enabled && payload.vision?.configs?.variable_selector) {
+ const visionVar = payload.vision.configs.variable_selector
+ vars.push(visionVar)
+ }
+ return vars
+ }
+
+ const getDependentVar = (variable: string) => {
+ if(variable === '#context#')
+ return payload.context.variable_selector
+
+ if(variable === '#files#')
+ return payload.vision.configs?.variable_selector
+
+ return false
+ }
+
+ return {
+ forms,
+ getDependentVars,
+ getDependentVar,
+ }
+}
+
+export default useSingleRunFormParams
diff --git a/web/app/components/workflow/nodes/loop/panel.tsx b/web/app/components/workflow/nodes/loop/panel.tsx
index 8114160ef..d3f06482c 100644
--- a/web/app/components/workflow/nodes/loop/panel.tsx
+++ b/web/app/components/workflow/nodes/loop/panel.tsx
@@ -1,9 +1,8 @@
import type { FC } from 'react'
-import React, { useMemo } from 'react'
+import React from 'react'
import { useTranslation } from 'react-i18next'
import { RiAddLine } from '@remixicon/react'
import Split from '../_base/components/split'
-import ResultPanel from '../../run/result-panel'
import InputNumberWithSlider from '../_base/components/input-number-with-slider'
import type { LoopNodeType } from './types'
import useConfig from './use-config'
@@ -11,10 +10,7 @@ import ConditionWrap from './components/condition-wrap'
import LoopVariable from './components/loop-variables'
import type { NodePanelProps } from '@/app/components/workflow/types'
import Field from '@/app/components/workflow/nodes/_base/components/field'
-import BeforeRunForm from '@/app/components/workflow/nodes/_base/components/before-run-form'
-import formatTracing from '@/app/components/workflow/run/utils/format-log'
-import { useLogs } from '@/app/components/workflow/run/hooks'
import { LOOP_NODE_MAX_COUNT } from '@/config'
const i18nPrefix = 'workflow.nodes.loop'
@@ -30,13 +26,6 @@ const Panel: FC> = ({
inputs,
childrenNodeVars,
loopChildrenNodes,
- isShowSingleRun,
- hideSingleRun,
- runningStatus,
- handleRun,
- handleStop,
- runResult,
- loopRunResult,
handleAddCondition,
handleUpdateCondition,
handleRemoveCondition,
@@ -51,23 +40,6 @@ const Panel: FC> = ({
handleUpdateLoopVariable,
} = useConfig(id, data)
- const nodeInfo = useMemo(() => {
- const formattedNodeInfo = formatTracing(loopRunResult, t)[0]
-
- if (runResult && formattedNodeInfo) {
- return {
- ...formattedNodeInfo,
- execution_metadata: {
- ...runResult.execution_metadata,
- ...formattedNodeInfo.execution_metadata,
- },
- }
- }
-
- return formattedNodeInfo
- }, [runResult, loopRunResult, t])
- const logsParams = useLogs()
-
return (
@@ -139,20 +111,6 @@ const Panel: FC> = ({
*/}
- {isShowSingleRun && (
-
- }
- />
- )}
)
}
diff --git a/web/app/components/workflow/nodes/loop/use-config.ts b/web/app/components/workflow/nodes/loop/use-config.ts
index fbd350c22..965fe2b39 100644
--- a/web/app/components/workflow/nodes/loop/use-config.ts
+++ b/web/app/components/workflow/nodes/loop/use-config.ts
@@ -3,7 +3,6 @@ import {
useRef,
} from 'react'
import produce from 'immer'
-import { useBoolean } from 'ahooks'
import { v4 as uuid4 } from 'uuid'
import {
useIsChatMode,
@@ -12,10 +11,9 @@ import {
useWorkflow,
} from '../../hooks'
import { ValueType, VarType } from '../../types'
-import type { ErrorHandleMode, ValueSelector, Var } from '../../types'
+import type { ErrorHandleMode, Var } from '../../types'
import useNodeCrud from '../_base/hooks/use-node-crud'
-import { getNodeInfoById, getNodeUsedVarPassToServerKey, getNodeUsedVars, isSystemVar, toNodeOutputVars } from '../_base/components/variable/utils'
-import useOneStepRun from '../_base/hooks/use-one-step-run'
+import { toNodeOutputVars } from '../_base/components/variable/utils'
import { getOperators } from './utils'
import { LogicalOperator } from './types'
import type { HandleAddCondition, HandleAddSubVariableCondition, HandleRemoveCondition, HandleToggleConditionLogicalOperator, HandleToggleSubVariableConditionLogicalOperator, HandleUpdateCondition, HandleUpdateSubVariableCondition, LoopNodeType } from './types'
@@ -47,140 +45,12 @@ const useConfig = (id: string, payload: LoopNodeType) => {
const canChooseVarNodes = [...beforeNodes, ...loopChildrenNodes]
const childrenNodeVars = toNodeOutputVars(loopChildrenNodes, isChatMode, undefined, [], conversationVariables)
- // single run
- const loopInputKey = `${id}.input_selector`
- const {
- isShowSingleRun,
- showSingleRun,
- hideSingleRun,
- toVarInputs,
- runningStatus,
- handleRun: doHandleRun,
- handleStop,
- runInputData,
- setRunInputData,
- runResult,
- loopRunResult,
- } = useOneStepRun({
- id,
- data: inputs,
- loopInputKey,
- defaultRunInputData: {
- [loopInputKey]: [''],
- },
- })
-
- const [isShowLoopDetail, {
- setTrue: doShowLoopDetail,
- setFalse: doHideLoopDetail,
- }] = useBoolean(false)
-
- const hideLoopDetail = useCallback(() => {
- hideSingleRun()
- doHideLoopDetail()
- }, [doHideLoopDetail, hideSingleRun])
-
- const showLoopDetail = useCallback(() => {
- doShowLoopDetail()
- }, [doShowLoopDetail])
-
- const backToSingleRun = useCallback(() => {
- hideLoopDetail()
- showSingleRun()
- }, [hideLoopDetail, showSingleRun])
-
const {
getIsVarFileAttribute,
} = useIsVarFileAttribute({
nodeId: id,
})
- const { usedOutVars, allVarObject } = (() => {
- const vars: ValueSelector[] = []
- const varObjs: Record = {}
- const allVarObject: Record = {}
- loopChildrenNodes.forEach((node) => {
- const nodeVars = getNodeUsedVars(node).filter(item => item && item.length > 0)
- nodeVars.forEach((varSelector) => {
- if (varSelector[0] === id) { // skip Loop node itself variable: item, index
- return
- }
- const isInLoop = isNodeInLoop(varSelector[0])
- if (isInLoop) // not pass loop inner variable
- return
-
- const varSectorStr = varSelector.join('.')
- if (!varObjs[varSectorStr]) {
- varObjs[varSectorStr] = true
- vars.push(varSelector)
- }
- let passToServerKeys = getNodeUsedVarPassToServerKey(node, varSelector)
- if (typeof passToServerKeys === 'string')
- passToServerKeys = [passToServerKeys]
-
- passToServerKeys.forEach((key: string, index: number) => {
- allVarObject[[varSectorStr, node.id, index].join(DELIMITER)] = {
- inSingleRunPassedKey: key,
- }
- })
- })
- })
- const res = toVarInputs(vars.map((item) => {
- const varInfo = getNodeInfoById(canChooseVarNodes, item[0])
- return {
- label: {
- nodeType: varInfo?.data.type,
- nodeName: varInfo?.data.title || canChooseVarNodes[0]?.data.title, // default start node title
- variable: isSystemVar(item) ? item.join('.') : item[item.length - 1],
- },
- variable: `${item.join('.')}`,
- value_selector: item,
- }
- }))
- return {
- usedOutVars: res,
- allVarObject,
- }
- })()
-
- const handleRun = useCallback((data: Record) => {
- const formattedData: Record = {}
- Object.keys(allVarObject).forEach((key) => {
- const [varSectorStr, nodeId] = key.split(DELIMITER)
- formattedData[`${nodeId}.${allVarObject[key].inSingleRunPassedKey}`] = data[varSectorStr]
- })
- formattedData[loopInputKey] = data[loopInputKey]
- doHandleRun(formattedData)
- }, [allVarObject, doHandleRun, loopInputKey])
-
- const inputVarValues = (() => {
- const vars: Record = {}
- Object.keys(runInputData)
- .filter(key => ![loopInputKey].includes(key))
- .forEach((key) => {
- vars[key] = runInputData[key]
- })
- return vars
- })()
-
- const setInputVarValues = useCallback((newPayload: Record) => {
- const newVars = {
- ...newPayload,
- [loopInputKey]: runInputData[loopInputKey],
- }
- setRunInputData(newVars)
- }, [loopInputKey, runInputData, setRunInputData])
-
- const loop = runInputData[loopInputKey]
- const setLoop = useCallback((newLoop: string[]) => {
- setRunInputData({
- ...runInputData,
- [loopInputKey]: newLoop,
- })
- }, [loopInputKey, runInputData, setRunInputData])
-
const changeErrorResponseMode = useCallback((item: { value: unknown }) => {
const newInputs = produce(inputs, (draft) => {
draft.error_handle_mode = item.value as ErrorHandleMode
@@ -342,24 +212,6 @@ const useConfig = (id: string, payload: LoopNodeType) => {
filterInputVar,
childrenNodeVars,
loopChildrenNodes,
- isShowSingleRun,
- showSingleRun,
- hideSingleRun,
- isShowLoopDetail,
- showLoopDetail,
- hideLoopDetail,
- backToSingleRun,
- runningStatus,
- handleRun,
- handleStop,
- runResult,
- inputVarValues,
- setInputVarValues,
- usedOutVars,
- loop,
- setLoop,
- loopInputKey,
- loopRunResult,
handleAddCondition,
handleRemoveCondition,
handleUpdateCondition,
diff --git a/web/app/components/workflow/nodes/loop/use-single-run-form-params.ts b/web/app/components/workflow/nodes/loop/use-single-run-form-params.ts
new file mode 100644
index 000000000..394ab9b16
--- /dev/null
+++ b/web/app/components/workflow/nodes/loop/use-single-run-form-params.ts
@@ -0,0 +1,221 @@
+import type { NodeTracing } from '@/types/workflow'
+import { useCallback, useMemo } from 'react'
+import formatTracing from '@/app/components/workflow/run/utils/format-log'
+import { useTranslation } from 'react-i18next'
+import { useIsNodeInLoop, useWorkflow } from '../../hooks'
+import { getNodeInfoById, getNodeUsedVarPassToServerKey, getNodeUsedVars, isSystemVar } from '../_base/components/variable/utils'
+import type { InputVar, ValueSelector, Variable } from '../../types'
+import type { CaseItem, Condition, LoopNodeType } from './types'
+import { ValueType } from '@/app/components/workflow/types'
+import { VALUE_SELECTOR_DELIMITER as DELIMITER } from '@/config'
+
+type Params = {
+ id: string
+ payload: LoopNodeType
+ runInputData: Record
+ runResult: NodeTracing
+ loopRunResult: NodeTracing[]
+ setRunInputData: (data: Record) => void
+ toVarInputs: (variables: Variable[]) => InputVar[]
+ varSelectorsToVarInputs: (variables: ValueSelector[]) => InputVar[]
+}
+
+const useSingleRunFormParams = ({
+ id,
+ payload,
+ runInputData,
+ runResult,
+ loopRunResult,
+ setRunInputData,
+ toVarInputs,
+ varSelectorsToVarInputs,
+}: Params) => {
+ const { t } = useTranslation()
+
+ const { isNodeInLoop } = useIsNodeInLoop(id)
+
+ const { getLoopNodeChildren, getBeforeNodesInSameBranch } = useWorkflow()
+ const loopChildrenNodes = getLoopNodeChildren(id)
+ const beforeNodes = getBeforeNodesInSameBranch(id)
+ const canChooseVarNodes = [...beforeNodes, ...loopChildrenNodes]
+
+ const { usedOutVars, allVarObject } = (() => {
+ const vars: ValueSelector[] = []
+ const varObjs: Record = {}
+ const allVarObject: Record = {}
+ loopChildrenNodes.forEach((node) => {
+ const nodeVars = getNodeUsedVars(node).filter(item => item && item.length > 0)
+ nodeVars.forEach((varSelector) => {
+ if (varSelector[0] === id) { // skip loop node itself variable: item, index
+ return
+ }
+ const isInLoop = isNodeInLoop(varSelector[0])
+ if (isInLoop) // not pass loop inner variable
+ return
+
+ const varSectorStr = varSelector.join('.')
+ if (!varObjs[varSectorStr]) {
+ varObjs[varSectorStr] = true
+ vars.push(varSelector)
+ }
+ let passToServerKeys = getNodeUsedVarPassToServerKey(node, varSelector)
+ if (typeof passToServerKeys === 'string')
+ passToServerKeys = [passToServerKeys]
+
+ passToServerKeys.forEach((key: string, index: number) => {
+ allVarObject[[varSectorStr, node.id, index].join(DELIMITER)] = {
+ inSingleRunPassedKey: key,
+ }
+ })
+ })
+ })
+
+ const res = toVarInputs(vars.map((item) => {
+ const varInfo = getNodeInfoById(canChooseVarNodes, item[0])
+ return {
+ label: {
+ nodeType: varInfo?.data.type,
+ nodeName: varInfo?.data.title || canChooseVarNodes[0]?.data.title, // default start node title
+ variable: isSystemVar(item) ? item.join('.') : item[item.length - 1],
+ },
+ variable: `${item.join('.')}`,
+ value_selector: item,
+ }
+ }))
+ return {
+ usedOutVars: res,
+ allVarObject,
+ }
+ })()
+
+ const nodeInfo = useMemo(() => {
+ const formattedNodeInfo = formatTracing(loopRunResult, t)[0]
+
+ if (runResult && formattedNodeInfo) {
+ return {
+ ...formattedNodeInfo,
+ execution_metadata: {
+ ...runResult.execution_metadata,
+ ...formattedNodeInfo.execution_metadata,
+ },
+ }
+ }
+
+ return formattedNodeInfo
+ }, [runResult, loopRunResult, t])
+
+ const setInputVarValues = useCallback((newPayload: Record) => {
+ setRunInputData(newPayload)
+ }, [setRunInputData])
+
+ const inputVarValues = (() => {
+ const vars: Record = {}
+ Object.keys(runInputData)
+ .forEach((key) => {
+ vars[key] = runInputData[key]
+ })
+ return vars
+ })()
+
+ const getVarSelectorsFromCase = (caseItem: CaseItem): ValueSelector[] => {
+ const vars: ValueSelector[] = []
+ if (caseItem.conditions && caseItem.conditions.length) {
+ caseItem.conditions.forEach((condition) => {
+ // eslint-disable-next-line ts/no-use-before-define
+ const conditionVars = getVarSelectorsFromCondition(condition)
+ vars.push(...conditionVars)
+ })
+ }
+ return vars
+ }
+
+ const getVarSelectorsFromCondition = (condition: Condition) => {
+ const vars: ValueSelector[] = []
+ if (condition.variable_selector)
+ vars.push(condition.variable_selector)
+
+ if (condition.sub_variable_condition && condition.sub_variable_condition.conditions?.length)
+ vars.push(...getVarSelectorsFromCase(condition.sub_variable_condition))
+ return vars
+ }
+
+ const forms = (() => {
+ const allInputs: ValueSelector[] = []
+ payload.break_conditions?.forEach((condition) => {
+ const vars = getVarSelectorsFromCondition(condition)
+ allInputs.push(...vars)
+ })
+
+ payload.loop_variables?.forEach((loopVariable) => {
+ if(loopVariable.value_type === ValueType.variable)
+ allInputs.push(loopVariable.value)
+ })
+ const inputVarsFromValue: InputVar[] = []
+ const varInputs = [...varSelectorsToVarInputs(allInputs), ...inputVarsFromValue]
+
+ const existVarsKey: Record = {}
+ const uniqueVarInputs: InputVar[] = []
+ varInputs.forEach((input) => {
+ if(!input)
+ return
+ if (!existVarsKey[input.variable]) {
+ existVarsKey[input.variable] = true
+ uniqueVarInputs.push(input)
+ }
+ })
+ return [
+ {
+ inputs: [...usedOutVars, ...uniqueVarInputs],
+ values: inputVarValues,
+ onChange: setInputVarValues,
+ },
+ ]
+ })()
+
+ const getVarFromCaseItem = (caseItem: CaseItem): ValueSelector[] => {
+ const vars: ValueSelector[] = []
+ if (caseItem.conditions && caseItem.conditions.length) {
+ caseItem.conditions.forEach((condition) => {
+ // eslint-disable-next-line ts/no-use-before-define
+ const conditionVars = getVarFromCondition(condition)
+ vars.push(...conditionVars)
+ })
+ }
+ return vars
+ }
+
+ const getVarFromCondition = (condition: Condition): ValueSelector[] => {
+ const vars: ValueSelector[] = []
+ if (condition.variable_selector)
+ vars.push(condition.variable_selector)
+
+ if(condition.sub_variable_condition && condition.sub_variable_condition.conditions?.length)
+ vars.push(...getVarFromCaseItem(condition.sub_variable_condition))
+ return vars
+ }
+
+ const getDependentVars = () => {
+ const vars: ValueSelector[] = usedOutVars.map(item => item.variable.split('.'))
+ payload.break_conditions?.forEach((condition) => {
+ const conditionVars = getVarFromCondition(condition)
+ vars.push(...conditionVars)
+ })
+ payload.loop_variables?.forEach((loopVariable) => {
+ if(loopVariable.value_type === ValueType.variable)
+ vars.push(loopVariable.value)
+ })
+ const hasFilterLoopVars = vars.filter(item => item[0] !== id)
+ return hasFilterLoopVars
+ }
+
+ return {
+ forms,
+ nodeInfo,
+ allVarObject,
+ getDependentVars,
+ }
+}
+
+export default useSingleRunFormParams
diff --git a/web/app/components/workflow/nodes/parameter-extractor/panel.tsx b/web/app/components/workflow/nodes/parameter-extractor/panel.tsx
index d03f1d9ff..e86a2e376 100644
--- a/web/app/components/workflow/nodes/parameter-extractor/panel.tsx
+++ b/web/app/components/workflow/nodes/parameter-extractor/panel.tsx
@@ -4,9 +4,7 @@ import { useTranslation } from 'react-i18next'
import MemoryConfig from '../_base/components/memory-config'
import VarReferencePicker from '../_base/components/variable/var-reference-picker'
import Editor from '../_base/components/prompt/editor'
-import ResultPanel from '../../run/result-panel'
import ConfigVision from '../_base/components/config-vision'
-import { findVariableWhenOnLLMVision } from '../utils'
import useConfig from './use-config'
import type { ParameterExtractorNodeType } from './types'
import ExtractParameter from './components/extract-parameter/list'
@@ -17,12 +15,10 @@ import Field from '@/app/components/workflow/nodes/_base/components/field'
import Split from '@/app/components/workflow/nodes/_base/components/split'
import ModelParameterModal from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal'
import OutputVars, { VarItem } from '@/app/components/workflow/nodes/_base/components/output-vars'
-import { InputVarType, type NodePanelProps } from '@/app/components/workflow/types'
+import type { NodePanelProps } from '@/app/components/workflow/types'
import Tooltip from '@/app/components/base/tooltip'
-import BeforeRunForm from '@/app/components/workflow/nodes/_base/components/before-run-form'
import { VarType } from '@/app/components/workflow/types'
import { FieldCollapse } from '@/app/components/workflow/nodes/_base/components/collapse'
-import type { Props as FormProps } from '@/app/components/workflow/nodes/_base/components/before-run-form/form'
const i18nPrefix = 'workflow.nodes.parameterExtractor'
const i18nCommonPrefix = 'workflow.common'
@@ -53,63 +49,13 @@ const Panel: FC> = ({
handleReasoningModeChange,
availableVars,
availableNodesWithParent,
- availableVisionVars,
- inputVarValues,
- varInputs,
isVisionModel,
handleVisionResolutionChange,
handleVisionResolutionEnabledChange,
- isShowSingleRun,
- hideSingleRun,
- runningStatus,
- handleRun,
- handleStop,
- runResult,
- setInputVarValues,
- visionFiles,
- setVisionFiles,
} = useConfig(id, data)
const model = inputs.model
- const singleRunForms = (() => {
- const forms: FormProps[] = []
-
- forms.push(
- {
- label: t('workflow.nodes.llm.singleRun.variable')!,
- inputs: [{
- label: t(`${i18nPrefix}.inputVar`)!,
- variable: 'query',
- type: InputVarType.paragraph,
- required: true,
- }, ...varInputs],
- values: inputVarValues,
- onChange: setInputVarValues,
- },
- )
-
- if (isVisionModel && data.vision?.enabled && data.vision?.configs?.variable_selector) {
- const currentVariable = findVariableWhenOnLLMVision(data.vision.configs.variable_selector, availableVisionVars)
-
- forms.push(
- {
- label: t('workflow.nodes.llm.vision')!,
- inputs: [{
- label: currentVariable?.variable as any,
- variable: '#files#',
- type: currentVariable?.formType as any,
- required: false,
- }],
- values: { '#files#': visionFiles },
- onChange: keyValue => setVisionFiles((keyValue as any)['#files#']),
- },
- )
- }
-
- return forms
- })()
-
return (
@@ -255,17 +201,6 @@ const Panel: FC> = ({
>)}
- {isShowSingleRun && (
-
}
- />
- )}
)
}
diff --git a/web/app/components/workflow/nodes/parameter-extractor/use-config.ts b/web/app/components/workflow/nodes/parameter-extractor/use-config.ts
index 045737b23..3fe42b60c 100644
--- a/web/app/components/workflow/nodes/parameter-extractor/use-config.ts
+++ b/web/app/components/workflow/nodes/parameter-extractor/use-config.ts
@@ -8,7 +8,6 @@ import {
useNodesReadOnly,
useWorkflow,
} from '../../hooks'
-import useOneStepRun from '../_base/hooks/use-one-step-run'
import useConfigVision from '../../hooks/use-config-vision'
import type { Param, ParameterExtractorNodeType, ReasoningModeType } from './types'
import { useModelListAndDefaultModelAndCurrentProviderAndModel, useTextGenerationCurrentProviderAndModelAndModelList } from '@/app/components/header/account-setting/model-provider-page/hooks'
@@ -17,8 +16,13 @@ import useNodeCrud from '@/app/components/workflow/nodes/_base/hooks/use-node-cr
import { checkHasQueryBlock } from '@/app/components/base/prompt-editor/constants'
import useAvailableVarList from '@/app/components/workflow/nodes/_base/hooks/use-available-var-list'
import { supportFunctionCall } from '@/utils/tool-call'
+import useInspectVarsCrud from '../../hooks/use-inspect-vars-crud'
const useConfig = (id: string, payload: ParameterExtractorNodeType) => {
+ const {
+ deleteNodeInspectorVars,
+ renameInspectVarName,
+ } = useInspectVarsCrud()
const { nodesReadOnly: readOnly } = useNodesReadOnly()
const { handleOutVarRenameChange } = useWorkflow()
const isChatMode = useIsChatMode()
@@ -59,9 +63,14 @@ const useConfig = (id: string, payload: ParameterExtractorNodeType) => {
})
setInputs(newInputs)
- if (moreInfo && moreInfo?.type === ChangeType.changeVarName && moreInfo.payload)
+ if (moreInfo && moreInfo?.type === ChangeType.changeVarName && moreInfo.payload) {
handleOutVarRenameChange(id, [id, moreInfo.payload.beforeKey], [id, moreInfo.payload.afterKey!])
- }, [handleOutVarRenameChange, id, inputs, setInputs])
+ renameInspectVarName(id, moreInfo.payload.beforeKey, moreInfo.payload.afterKey!)
+ }
+ else {
+ deleteNodeInspectorVars(id)
+ }
+ }, [deleteNodeInspectorVars, handleOutVarRenameChange, id, inputs, renameInspectVarName, setInputs])
const addExtractParameter = useCallback((payload: Param) => {
const newInputs = produce(inputs, (draft) => {
@@ -70,7 +79,8 @@ const useConfig = (id: string, payload: ParameterExtractorNodeType) => {
draft.parameters.push(payload)
})
setInputs(newInputs)
- }, [inputs, setInputs])
+ deleteNodeInspectorVars(id)
+ }, [deleteNodeInspectorVars, id, inputs, setInputs])
// model
const model = inputs.model || {
@@ -145,7 +155,7 @@ const useConfig = (id: string, payload: ParameterExtractorNodeType) => {
return
setModelChanged(false)
handleVisionConfigAfterModelChanged()
- // eslint-disable-next-line react-hooks/exhaustive-deps
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [isVisionModel, modelChanged])
const {
@@ -163,10 +173,6 @@ const useConfig = (id: string, payload: ParameterExtractorNodeType) => {
return [VarType.number, VarType.string].includes(varPayload.type)
}, [])
- const filterVisionInputVar = useCallback((varPayload: Var) => {
- return [VarType.file, VarType.arrayFile].includes(varPayload.type)
- }, [])
-
const {
availableVars,
availableNodesWithParent,
@@ -175,13 +181,6 @@ const useConfig = (id: string, payload: ParameterExtractorNodeType) => {
filterVar: filterInputVar,
})
- const {
- availableVars: availableVisionVars,
- } = useAvailableVarList(id, {
- onlyLeafNodeVar: false,
- filterVar: filterVisionInputVar,
- })
-
const handleCompletionParamsChange = useCallback((newParams: Record) => {
const newInputs = produce(inputs, (draft) => {
draft.model.completion_params = newParams
@@ -223,49 +222,6 @@ const useConfig = (id: string, payload: ParameterExtractorNodeType) => {
setInputs(newInputs)
}, [inputs, setInputs])
- // single run
- const {
- isShowSingleRun,
- hideSingleRun,
- getInputVars,
- runningStatus,
- handleRun,
- handleStop,
- runInputData,
- runInputDataRef,
- setRunInputData,
- runResult,
- } = useOneStepRun({
- id,
- data: inputs,
- defaultRunInputData: {
- 'query': '',
- '#files#': [],
- },
- })
-
- const varInputs = getInputVars([inputs.instruction])
- const inputVarValues = (() => {
- const vars: Record = {}
- Object.keys(runInputData)
- .forEach((key) => {
- vars[key] = runInputData[key]
- })
- return vars
- })()
-
- const setInputVarValues = useCallback((newPayload: Record) => {
- setRunInputData(newPayload)
- }, [setRunInputData])
-
- const visionFiles = runInputData['#files#']
- const setVisionFiles = useCallback((newFiles: any[]) => {
- setRunInputData({
- ...runInputDataRef.current,
- '#files#': newFiles,
- })
- }, [runInputDataRef, setRunInputData])
-
return {
readOnly,
handleInputVarChange,
@@ -283,24 +239,12 @@ const useConfig = (id: string, payload: ParameterExtractorNodeType) => {
hasSetBlockStatus,
availableVars,
availableNodesWithParent,
- availableVisionVars,
isSupportFunctionCall,
handleReasoningModeChange,
handleMemoryChange,
- varInputs,
- inputVarValues,
isVisionModel,
handleVisionResolutionEnabledChange,
handleVisionResolutionChange,
- isShowSingleRun,
- hideSingleRun,
- runningStatus,
- handleRun,
- handleStop,
- runResult,
- setInputVarValues,
- visionFiles,
- setVisionFiles,
}
}
diff --git a/web/app/components/workflow/nodes/parameter-extractor/use-single-run-form-params.ts b/web/app/components/workflow/nodes/parameter-extractor/use-single-run-form-params.ts
new file mode 100644
index 000000000..178f9e3ed
--- /dev/null
+++ b/web/app/components/workflow/nodes/parameter-extractor/use-single-run-form-params.ts
@@ -0,0 +1,148 @@
+import type { MutableRefObject } from 'react'
+import { useTranslation } from 'react-i18next'
+import type { Props as FormProps } from '@/app/components/workflow/nodes/_base/components/before-run-form/form'
+import type { InputVar, Var, Variable } from '@/app/components/workflow/types'
+import { InputVarType, VarType } from '@/app/components/workflow/types'
+import type { ParameterExtractorNodeType } from './types'
+import useNodeCrud from '../_base/hooks/use-node-crud'
+import { useCallback } from 'react'
+import useConfigVision from '../../hooks/use-config-vision'
+import { noop } from 'lodash-es'
+import { findVariableWhenOnLLMVision } from '../utils'
+import useAvailableVarList from '../_base/hooks/use-available-var-list'
+
+const i18nPrefix = 'workflow.nodes.parameterExtractor'
+
+type Params = {
+ id: string,
+ payload: ParameterExtractorNodeType,
+ runInputData: Record
+ runInputDataRef: MutableRefObject>
+ getInputVars: (textList: string[]) => InputVar[]
+ setRunInputData: (data: Record) => void
+ toVarInputs: (variables: Variable[]) => InputVar[]
+}
+const useSingleRunFormParams = ({
+ id,
+ payload,
+ runInputData,
+ runInputDataRef,
+ getInputVars,
+ setRunInputData,
+}: Params) => {
+ const { t } = useTranslation()
+ const { inputs } = useNodeCrud(id, payload)
+
+ const model = inputs.model
+
+ const {
+ isVisionModel,
+ } = useConfigVision(model, {
+ payload: inputs.vision,
+ onChange: noop,
+ })
+
+ const visionFiles = runInputData['#files#']
+ const setVisionFiles = useCallback((newFiles: any[]) => {
+ setRunInputData?.({
+ ...runInputDataRef.current,
+ '#files#': newFiles,
+ })
+ }, [runInputDataRef, setRunInputData])
+
+ const varInputs = getInputVars([inputs.instruction])
+
+ const inputVarValues = (() => {
+ const vars: Record = {}
+ Object.keys(runInputData)
+ .filter(key => !['#context#', '#files#'].includes(key))
+ .forEach((key) => {
+ vars[key] = runInputData[key]
+ })
+ return vars
+ })()
+
+ const setInputVarValues = useCallback((newPayload: Record) => {
+ const newVars = {
+ ...newPayload,
+ '#context#': runInputDataRef.current['#context#'],
+ '#files#': runInputDataRef.current['#files#'],
+ }
+ setRunInputData?.(newVars)
+ }, [runInputDataRef, setRunInputData])
+
+ const filterVisionInputVar = useCallback((varPayload: Var) => {
+ return [VarType.file, VarType.arrayFile].includes(varPayload.type)
+ }, [])
+ const {
+ availableVars: availableVisionVars,
+ } = useAvailableVarList(id, {
+ onlyLeafNodeVar: false,
+ filterVar: filterVisionInputVar,
+ })
+
+ const forms = (() => {
+ const forms: FormProps[] = []
+
+ forms.push(
+ {
+ label: t('workflow.nodes.llm.singleRun.variable')!,
+ inputs: [{
+ label: t(`${i18nPrefix}.inputVar`)!,
+ variable: 'query',
+ type: InputVarType.paragraph,
+ required: true,
+ }, ...varInputs],
+ values: inputVarValues,
+ onChange: setInputVarValues,
+ },
+ )
+
+ if (isVisionModel && payload.vision?.enabled && payload.vision?.configs?.variable_selector) {
+ const currentVariable = findVariableWhenOnLLMVision(payload.vision.configs.variable_selector, availableVisionVars)
+
+ forms.push(
+ {
+ label: t('workflow.nodes.llm.vision')!,
+ inputs: [{
+ label: currentVariable?.variable as any,
+ variable: '#files#',
+ type: currentVariable?.formType as any,
+ required: false,
+ }],
+ values: { '#files#': visionFiles },
+ onChange: keyValue => setVisionFiles((keyValue as any)['#files#']),
+ },
+ )
+ }
+
+ return forms
+ })()
+
+ const getDependentVars = () => {
+ const promptVars = varInputs.map(item => item.variable.slice(1, -1).split('.'))
+ const vars = [payload.query, ...promptVars]
+ if (isVisionModel && payload.vision?.enabled && payload.vision?.configs?.variable_selector) {
+ const visionVar = payload.vision.configs.variable_selector
+ vars.push(visionVar)
+ }
+ return vars
+ }
+
+ const getDependentVar = (variable: string) => {
+ if(variable === 'query')
+ return payload.query
+ if(variable === '#files#')
+ return payload.vision.configs?.variable_selector
+
+ return false
+ }
+
+ return {
+ forms,
+ getDependentVars,
+ getDependentVar,
+ }
+}
+
+export default useSingleRunFormParams
diff --git a/web/app/components/workflow/nodes/question-classifier/panel.tsx b/web/app/components/workflow/nodes/question-classifier/panel.tsx
index d2e0fb060..8f6f5eb76 100644
--- a/web/app/components/workflow/nodes/question-classifier/panel.tsx
+++ b/web/app/components/workflow/nodes/question-classifier/panel.tsx
@@ -3,20 +3,16 @@ import React from 'react'
import { useTranslation } from 'react-i18next'
import VarReferencePicker from '../_base/components/variable/var-reference-picker'
import ConfigVision from '../_base/components/config-vision'
-import { findVariableWhenOnLLMVision } from '../utils'
import useConfig from './use-config'
import ClassList from './components/class-list'
import AdvancedSetting from './components/advanced-setting'
import type { QuestionClassifierNodeType } from './types'
import Field from '@/app/components/workflow/nodes/_base/components/field'
import ModelParameterModal from '@/app/components/header/account-setting/model-provider-page/model-parameter-modal'
-import { InputVarType, type NodePanelProps } from '@/app/components/workflow/types'
-import BeforeRunForm from '@/app/components/workflow/nodes/_base/components/before-run-form'
-import ResultPanel from '@/app/components/workflow/run/result-panel'
+import type { NodePanelProps } from '@/app/components/workflow/types'
import Split from '@/app/components/workflow/nodes/_base/components/split'
import OutputVars, { VarItem } from '@/app/components/workflow/nodes/_base/components/output-vars'
import { FieldCollapse } from '@/app/components/workflow/nodes/_base/components/collapse'
-import type { Props as FormProps } from '@/app/components/workflow/nodes/_base/components/before-run-form/form'
const i18nPrefix = 'workflow.nodes.questionClassifiers'
@@ -38,66 +34,16 @@ const Panel: FC> = ({
hasSetBlockStatus,
availableVars,
availableNodesWithParent,
- availableVisionVars,
handleInstructionChange,
- inputVarValues,
- varInputs,
- setInputVarValues,
handleMemoryChange,
isVisionModel,
handleVisionResolutionChange,
handleVisionResolutionEnabledChange,
- isShowSingleRun,
- hideSingleRun,
- runningStatus,
- handleRun,
- handleStop,
- runResult,
filterVar,
- visionFiles,
- setVisionFiles,
} = useConfig(id, data)
const model = inputs.model
- const singleRunForms = (() => {
- const forms: FormProps[] = []
-
- forms.push(
- {
- label: t('workflow.nodes.llm.singleRun.variable')!,
- inputs: [{
- label: t(`${i18nPrefix}.inputVars`)!,
- variable: 'query',
- type: InputVarType.paragraph,
- required: true,
- }, ...varInputs],
- values: inputVarValues,
- onChange: setInputVarValues,
- },
- )
-
- if (isVisionModel && data.vision?.enabled && data.vision?.configs?.variable_selector) {
- const currentVariable = findVariableWhenOnLLMVision(data.vision.configs.variable_selector, availableVisionVars)
-
- forms.push(
- {
- label: t('workflow.nodes.llm.vision')!,
- inputs: [{
- label: currentVariable?.variable as any,
- variable: '#files#',
- type: currentVariable?.formType as any,
- required: false,
- }],
- values: { '#files#': visionFiles },
- onChange: keyValue => setVisionFiles(keyValue['#files#']),
- },
- )
- }
-
- return forms
- })()
-
return (
@@ -186,17 +132,6 @@ const Panel: FC> = ({
>
- {isShowSingleRun && (
-
}
- />
- )}
)
}
diff --git a/web/app/components/workflow/nodes/question-classifier/use-config.ts b/web/app/components/workflow/nodes/question-classifier/use-config.ts
index 7df8293b4..8eacf5b43 100644
--- a/web/app/components/workflow/nodes/question-classifier/use-config.ts
+++ b/web/app/components/workflow/nodes/question-classifier/use-config.ts
@@ -11,7 +11,6 @@ import useAvailableVarList from '../_base/hooks/use-available-var-list'
import useConfigVision from '../../hooks/use-config-vision'
import type { QuestionClassifierNodeType } from './types'
import useNodeCrud from '@/app/components/workflow/nodes/_base/hooks/use-node-crud'
-import useOneStepRun from '@/app/components/workflow/nodes/_base/hooks/use-one-step-run'
import { useModelListAndDefaultModelAndCurrentProviderAndModel } from '@/app/components/header/account-setting/model-provider-page/hooks'
import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { checkHasQueryBlock } from '@/app/components/base/prompt-editor/constants'
@@ -87,7 +86,7 @@ const useConfig = (id: string, payload: QuestionClassifierNodeType) => {
return
setModelChanged(false)
handleVisionConfigAfterModelChanged()
- // eslint-disable-next-line react-hooks/exhaustive-deps
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [isVisionModel, modelChanged])
const handleQueryVarChange = useCallback((newVar: ValueSelector | string) => {
@@ -109,7 +108,7 @@ const useConfig = (id: string, payload: QuestionClassifierNodeType) => {
query_variable_selector: inputs.query_variable_selector.length > 0 ? inputs.query_variable_selector : query_variable_selector,
})
}
- // eslint-disable-next-line react-hooks/exhaustive-deps
+ // eslint-disable-next-line react-hooks/exhaustive-deps
}, [defaultConfig])
const handleClassesChange = useCallback((newClasses: any) => {
@@ -163,59 +162,6 @@ const useConfig = (id: string, payload: QuestionClassifierNodeType) => {
setInputs(newInputs)
}, [inputs, setInputs])
- // single run
- const {
- isShowSingleRun,
- hideSingleRun,
- getInputVars,
- runningStatus,
- handleRun,
- handleStop,
- runInputData,
- runInputDataRef,
- setRunInputData,
- runResult,
- } = useOneStepRun({
- id,
- data: inputs,
- defaultRunInputData: {
- 'query': '',
- '#files#': [],
- },
- })
-
- const query = runInputData.query
- const setQuery = useCallback((newQuery: string) => {
- setRunInputData({
- ...runInputData,
- query: newQuery,
- })
- }, [runInputData, setRunInputData])
-
- const varInputs = getInputVars([inputs.instruction])
- const inputVarValues = (() => {
- const vars: Record = {
- query,
- }
- Object.keys(runInputData)
- .forEach((key) => {
- vars[key] = runInputData[key]
- })
- return vars
- })()
-
- const setInputVarValues = useCallback((newPayload: Record) => {
- setRunInputData(newPayload)
- }, [setRunInputData])
-
- const visionFiles = runInputData['#files#']
- const setVisionFiles = useCallback((newFiles: any[]) => {
- setRunInputData({
- ...runInputDataRef.current,
- '#files#': newFiles,
- })
- }, [runInputDataRef, setRunInputData])
-
const filterVar = useCallback((varPayload: Var) => {
return varPayload.type === VarType.string
}, [])
@@ -235,23 +181,10 @@ const useConfig = (id: string, payload: QuestionClassifierNodeType) => {
availableNodesWithParent,
availableVisionVars,
handleInstructionChange,
- varInputs,
- inputVarValues,
- setInputVarValues,
handleMemoryChange,
isVisionModel,
handleVisionResolutionEnabledChange,
handleVisionResolutionChange,
- isShowSingleRun,
- hideSingleRun,
- runningStatus,
- handleRun,
- handleStop,
- query,
- setQuery,
- runResult,
- visionFiles,
- setVisionFiles,
}
}
diff --git a/web/app/components/workflow/nodes/question-classifier/use-single-run-form-params.ts b/web/app/components/workflow/nodes/question-classifier/use-single-run-form-params.ts
new file mode 100644
index 000000000..66755abb6
--- /dev/null
+++ b/web/app/components/workflow/nodes/question-classifier/use-single-run-form-params.ts
@@ -0,0 +1,146 @@
+import type { MutableRefObject } from 'react'
+import { useTranslation } from 'react-i18next'
+import type { Props as FormProps } from '@/app/components/workflow/nodes/_base/components/before-run-form/form'
+import type { InputVar, Var, Variable } from '@/app/components/workflow/types'
+import { InputVarType, VarType } from '@/app/components/workflow/types'
+import type { QuestionClassifierNodeType } from './types'
+import useNodeCrud from '../_base/hooks/use-node-crud'
+import { useCallback } from 'react'
+import useConfigVision from '../../hooks/use-config-vision'
+import { noop } from 'lodash-es'
+import { findVariableWhenOnLLMVision } from '../utils'
+import useAvailableVarList from '../_base/hooks/use-available-var-list'
+
+const i18nPrefix = 'workflow.nodes.questionClassifiers'
+
+type Params = {
+ id: string,
+ payload: QuestionClassifierNodeType,
+ runInputData: Record
+ runInputDataRef: MutableRefObject>
+ getInputVars: (textList: string[]) => InputVar[]
+ setRunInputData: (data: Record) => void
+ toVarInputs: (variables: Variable[]) => InputVar[]
+}
+const useSingleRunFormParams = ({
+ id,
+ payload,
+ runInputData,
+ runInputDataRef,
+ getInputVars,
+ setRunInputData,
+}: Params) => {
+ const { t } = useTranslation()
+ const { inputs } = useNodeCrud(id, payload)
+
+ const model = inputs.model
+
+ const {
+ isVisionModel,
+ } = useConfigVision(model, {
+ payload: inputs.vision,
+ onChange: noop,
+ })
+
+ const visionFiles = runInputData['#files#']
+ const setVisionFiles = useCallback((newFiles: any[]) => {
+ setRunInputData?.({
+ ...runInputDataRef.current,
+ '#files#': newFiles,
+ })
+ }, [runInputDataRef, setRunInputData])
+
+ const varInputs = getInputVars([inputs.instruction])
+
+ const inputVarValues = (() => {
+ const vars: Record = {}
+ Object.keys(runInputData)
+ .filter(key => !['#files#'].includes(key))
+ .forEach((key) => {
+ vars[key] = runInputData[key]
+ })
+ return vars
+ })()
+
+ const setInputVarValues = useCallback((newPayload: Record) => {
+ const newVars = {
+ ...newPayload,
+ '#files#': runInputDataRef.current['#files#'],
+ }
+ setRunInputData?.(newVars)
+ }, [runInputDataRef, setRunInputData])
+
+ const filterVisionInputVar = useCallback((varPayload: Var) => {
+ return [VarType.file, VarType.arrayFile].includes(varPayload.type)
+ }, [])
+ const {
+ availableVars: availableVisionVars,
+ } = useAvailableVarList(id, {
+ onlyLeafNodeVar: false,
+ filterVar: filterVisionInputVar,
+ })
+
+ const forms = (() => {
+ const forms: FormProps[] = []
+
+ forms.push(
+ {
+ label: t('workflow.nodes.llm.singleRun.variable')!,
+ inputs: [{
+ label: t(`${i18nPrefix}.inputVars`)!,
+ variable: 'query',
+ type: InputVarType.paragraph,
+ required: true,
+ }, ...varInputs],
+ values: inputVarValues,
+ onChange: setInputVarValues,
+ },
+ )
+
+ if (isVisionModel && payload.vision?.enabled && payload.vision?.configs?.variable_selector) {
+ const currentVariable = findVariableWhenOnLLMVision(payload.vision.configs.variable_selector, availableVisionVars)
+
+ forms.push(
+ {
+ label: t('workflow.nodes.llm.vision')!,
+ inputs: [{
+ label: currentVariable?.variable as any,
+ variable: '#files#',
+ type: currentVariable?.formType as any,
+ required: false,
+ }],
+ values: { '#files#': visionFiles },
+ onChange: keyValue => setVisionFiles(keyValue['#files#']),
+ },
+ )
+ }
+ return forms
+ })()
+
+ const getDependentVars = () => {
+ const promptVars = varInputs.map(item => item.variable.slice(1, -1).split('.'))
+ const vars = [payload.query_variable_selector, ...promptVars]
+ if (isVisionModel && payload.vision?.enabled && payload.vision?.configs?.variable_selector) {
+ const visionVar = payload.vision.configs.variable_selector
+ vars.push(visionVar)
+ }
+ return vars
+ }
+
+ const getDependentVar = (variable: string) => {
+ if(variable === 'query')
+ return payload.query_variable_selector
+ if(variable === '#files#')
+ return payload.vision.configs?.variable_selector
+
+ return false
+ }
+
+ return {
+ forms,
+ getDependentVars,
+ getDependentVar,
+ }
+}
+
+export default useSingleRunFormParams
diff --git a/web/app/components/workflow/nodes/start/use-config.ts b/web/app/components/workflow/nodes/start/use-config.ts
index e30e8c283..c0ade614e 100644
--- a/web/app/components/workflow/nodes/start/use-config.ts
+++ b/web/app/components/workflow/nodes/start/use-config.ts
@@ -10,6 +10,7 @@ import {
useNodesReadOnly,
useWorkflow,
} from '@/app/components/workflow/hooks'
+import useInspectVarsCrud from '../../hooks/use-inspect-vars-crud'
const useConfig = (id: string, payload: StartNodeType) => {
const { nodesReadOnly: readOnly } = useNodesReadOnly()
@@ -18,6 +19,13 @@ const useConfig = (id: string, payload: StartNodeType) => {
const { inputs, setInputs } = useNodeCrud(id, payload)
+ const {
+ deleteNodeInspectorVars,
+ renameInspectVarName,
+ nodesWithInspectVars,
+ deleteInspectVar,
+ } = useInspectVarsCrud()
+
const [isShowAddVarModal, {
setTrue: showAddVarModal,
setFalse: hideAddVarModal,
@@ -31,6 +39,12 @@ const useConfig = (id: string, payload: StartNodeType) => {
const [removedIndex, setRemoveIndex] = useState(0)
const handleVarListChange = useCallback((newList: InputVar[], moreInfo?: { index: number; payload: MoreInfo }) => {
if (moreInfo?.payload?.type === ChangeType.remove) {
+ const varId = nodesWithInspectVars.find(node => node.nodeId === id)?.vars.find((varItem) => {
+ return varItem.name === moreInfo?.payload?.payload?.beforeKey
+ })?.id
+ if(varId)
+ deleteInspectVar(id, varId)
+
if (isVarUsedInNodes([id, moreInfo?.payload?.payload?.beforeKey || ''])) {
showRemoveVarConfirm()
setRemovedVar([id, moreInfo?.payload?.payload?.beforeKey || ''])
@@ -46,8 +60,12 @@ const useConfig = (id: string, payload: StartNodeType) => {
if (moreInfo?.payload?.type === ChangeType.changeVarName) {
const changedVar = newList[moreInfo.index]
handleOutVarRenameChange(id, [id, inputs.variables[moreInfo.index].variable], [id, changedVar.variable])
+ renameInspectVarName(id, inputs.variables[moreInfo.index].variable, changedVar.variable)
}
- }, [handleOutVarRenameChange, id, inputs, isVarUsedInNodes, setInputs, showRemoveVarConfirm])
+ else if(moreInfo?.payload?.type !== ChangeType.remove) { // edit var type
+ deleteNodeInspectorVars(id)
+ }
+ }, [deleteInspectVar, deleteNodeInspectorVars, handleOutVarRenameChange, id, inputs, isVarUsedInNodes, nodesWithInspectVars, renameInspectVarName, setInputs, showRemoveVarConfirm])
const removeVarInNode = useCallback(() => {
const newInputs = produce(inputs, (draft) => {
diff --git a/web/app/components/workflow/nodes/start/use-single-run-form-params.ts b/web/app/components/workflow/nodes/start/use-single-run-form-params.ts
new file mode 100644
index 000000000..38abbf2a6
--- /dev/null
+++ b/web/app/components/workflow/nodes/start/use-single-run-form-params.ts
@@ -0,0 +1,87 @@
+import type { MutableRefObject } from 'react'
+import { useTranslation } from 'react-i18next'
+import type { Props as FormProps } from '@/app/components/workflow/nodes/_base/components/before-run-form/form'
+import type { ValueSelector } from '@/app/components/workflow/types'
+import { type InputVar, InputVarType, type Variable } from '@/app/components/workflow/types'
+import type { StartNodeType } from './types'
+import { useIsChatMode } from '../../hooks'
+
+type Params = {
+ id: string,
+ payload: StartNodeType,
+ runInputData: Record
+ runInputDataRef: MutableRefObject>
+ getInputVars: (textList: string[]) => InputVar[]
+ setRunInputData: (data: Record) => void
+ toVarInputs: (variables: Variable[]) => InputVar[]
+}
+const useSingleRunFormParams = ({
+ id,
+ payload,
+ runInputData,
+ setRunInputData,
+}: Params) => {
+ const { t } = useTranslation()
+ const isChatMode = useIsChatMode()
+
+ const forms = (() => {
+ const forms: FormProps[] = []
+ const inputs: InputVar[] = payload.variables.map((item) => {
+ return {
+ ...item,
+ getVarValueFromDependent: true,
+ }
+ })
+
+ if (isChatMode) {
+ inputs.push({
+ label: 'sys.query',
+ variable: '#sys.query#',
+ type: InputVarType.textInput,
+ required: true,
+ })
+ }
+
+ inputs.push({
+ label: 'sys.files',
+ variable: '#sys.files#',
+ type: InputVarType.multiFiles,
+ required: false,
+ })
+
+ forms.push(
+ {
+ label: t('workflow.nodes.llm.singleRun.variable')!,
+ inputs,
+ values: runInputData,
+ onChange: setRunInputData,
+ },
+ )
+
+ return forms
+ })()
+
+ const getDependentVars = () => {
+ const inputVars = payload.variables.map((item) => {
+ return [id, item.variable]
+ })
+ const vars: ValueSelector[] = [...inputVars, ['sys', 'files']]
+
+ if (isChatMode)
+ vars.push(['sys', 'query'])
+
+ return vars
+ }
+
+ const getDependentVar = (variable: string) => {
+ return [id, variable]
+ }
+
+ return {
+ forms,
+ getDependentVars,
+ getDependentVar,
+ }
+}
+
+export default useSingleRunFormParams
diff --git a/web/app/components/workflow/nodes/template-transform/panel.tsx b/web/app/components/workflow/nodes/template-transform/panel.tsx
index e12048292..29c34ee66 100644
--- a/web/app/components/workflow/nodes/template-transform/panel.tsx
+++ b/web/app/components/workflow/nodes/template-transform/panel.tsx
@@ -14,8 +14,6 @@ import Split from '@/app/components/workflow/nodes/_base/components/split'
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor/editor-support-vars'
import OutputVars, { VarItem } from '@/app/components/workflow/nodes/_base/components/output-vars'
import type { NodePanelProps } from '@/app/components/workflow/types'
-import BeforeRunForm from '@/app/components/workflow/nodes/_base/components/before-run-form'
-import ResultPanel from '@/app/components/workflow/run/result-panel'
const i18nPrefix = 'workflow.nodes.templateTransform'
@@ -35,16 +33,6 @@ const Panel: FC> = ({
handleAddEmptyVariable,
handleCodeChange,
filterVar,
- // single run
- isShowSingleRun,
- hideSingleRun,
- runningStatus,
- handleRun,
- handleStop,
- varInputs,
- inputVarValues,
- setInputVarValues,
- runResult,
} = useConfig(id, data)
return (
@@ -106,23 +94,6 @@ const Panel: FC> = ({
>
- {isShowSingleRun && (
-