From a8b6062f0e7eefe277c33b70e2ac8353768b932a Mon Sep 17 00:00:00 2001 From: Joel Date: Mon, 21 Apr 2025 17:39:54 +0800 Subject: [PATCH] feat: llm support new run and types --- web/app/components/workflow/constants.ts | 2 + .../_base/components/workflow-panel/index.tsx | 11 +++-- .../nodes/_base/hooks/use-one-step-run.ts | 4 +- .../components/workflow/nodes/llm/default.ts | 25 ++++++++++ .../components/workflow/nodes/llm/panel.tsx | 41 ++++++---------- .../workflow/nodes/llm/use-config.ts | 49 +++++-------------- web/app/components/workflow/types.ts | 1 + web/types/workflow.ts | 7 ++- 8 files changed, 71 insertions(+), 69 deletions(-) diff --git a/web/app/components/workflow/constants.ts b/web/app/components/workflow/constants.ts index cdfd963cfa..4cf0c307d0 100644 --- a/web/app/components/workflow/constants.ts +++ b/web/app/components/workflow/constants.ts @@ -31,6 +31,7 @@ type NodesExtraData = { getAvailablePrevNodes: (isChatMode: boolean) => BlockEnum[] getAvailableNextNodes: (isChatMode: boolean) => BlockEnum[] checkValid: any + defaultRunInputData?: Record } export const NODES_EXTRA_DATA: Record = { [BlockEnum.Start]: { @@ -68,6 +69,7 @@ export const NODES_EXTRA_DATA: Record = { getAvailablePrevNodes: LLMDefault.getAvailablePrevNodes, getAvailableNextNodes: LLMDefault.getAvailableNextNodes, checkValid: LLMDefault.checkValid, + defaultRunInputData: LLMDefault.defaultRunInputData, }, [BlockEnum.KnowledgeRetrieval]: { author: 'Dify', diff --git a/web/app/components/workflow/nodes/_base/components/workflow-panel/index.tsx b/web/app/components/workflow/nodes/_base/components/workflow-panel/index.tsx index 683566d5cc..6748ba7082 100644 --- a/web/app/components/workflow/nodes/_base/components/workflow-panel/index.tsx +++ b/web/app/components/workflow/nodes/_base/components/workflow-panel/index.tsx @@ -6,10 +6,10 @@ import { cloneElement, memo, useCallback, - useRef, - useState, useEffect, useMemo, + useRef, + useState, } from 'react' import { RiCloseLine, @@ -56,6 +56,7 @@ import type { PanelExposedType } from '@/types/workflow' import BeforeRunForm from '../before-run-form' import { sleep } from '@/utils' import { debounce } from 'lodash-es' +import { NODES_EXTRA_DATA } from '@/app/components/workflow/constants' type BasePanelProps = { children: ReactNode @@ -147,13 +148,15 @@ const BasePanel: FC = ({ handleRun, handleStop, runInputData, + runInputDataRef, setRunInputData: doSetRunInputData, runResult, getInputVars, + toVarInputs, } = useOneStepRun({ id, data, - defaultRunInputData: {}, + defaultRunInputData: NODES_EXTRA_DATA[data.type]?.defaultRunInputData || {}, }) const [singleRunParams, setSingleRunParams] = useState(undefined) @@ -256,9 +259,11 @@ const BasePanel: FC = ({ data, panelProps: { getInputVars, + toVarInputs, runInputData, setRunInputData, runResult, + runInputDataRef, }, ref: childPanelRef, })} diff --git a/web/app/components/workflow/nodes/_base/hooks/use-one-step-run.ts b/web/app/components/workflow/nodes/_base/hooks/use-one-step-run.ts index f23af5812c..2f650b611a 100644 --- a/web/app/components/workflow/nodes/_base/hooks/use-one-step-run.ts +++ b/web/app/components/workflow/nodes/_base/hooks/use-one-step-run.ts @@ -32,7 +32,7 @@ import LoopDefault from '@/app/components/workflow/nodes/loop/default' import { ssePost } from '@/service/base' import { noop } from 'lodash-es' import { getInputVars as doGetInputVars } from '@/app/components/base/prompt-editor/constants' -import type { NodeTracing } from '@/types/workflow' +import type { NodeRunResult, NodeTracing } from '@/types/workflow' const { checkValid: checkLLMValid } = LLMDefault const { checkValid: checkKnowledgeRetrievalValid } = KnowledgeRetrievalDefault const { checkValid: checkIfElseValid } = IfElseDefault @@ -152,7 +152,7 @@ const useOneStepRun = ({ }, []) const iterationTimes = iteratorInputKey ? runInputData[iteratorInputKey].length : 0 const loopTimes = loopInputKey ? runInputData[loopInputKey].length : 0 - const [runResult, setRunResult] = useState(null) + const [runResult, setRunResult] = useState(null) const { handleNodeDataUpdate }: { handleNodeDataUpdate: (data: any) => void } = useNodeDataUpdate() const [canShowSingleRun, setCanShowSingleRun] = useState(false) diff --git a/web/app/components/workflow/nodes/llm/default.ts b/web/app/components/workflow/nodes/llm/default.ts index 92377f74b8..efe7fd8b64 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 0cf72c4724..9307b0967c 100644 --- a/web/app/components/workflow/nodes/llm/panel.tsx +++ b/web/app/components/workflow/nodes/llm/panel.tsx @@ -1,5 +1,4 @@ -import type { FC } from 'react' -import React, { useCallback } from 'react' +import React, { forwardRef, useCallback, useImperativeHandle } from 'react' import { useTranslation } from 'react-i18next' import MemoryConfig from '../_base/components/memory-config' import VarReferencePicker from '../_base/components/variable/var-reference-picker' @@ -15,28 +14,28 @@ 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 Tooltip from '@/app/components/base/tooltip' import Editor from '@/app/components/workflow/nodes/_base/components/prompt/editor' import useCurrentVars from '../../hooks/use-current-vars' import StructureOutput from './components/structure-output' import Switch from '@/app/components/base/switch' import { RiAlertFill, RiQuestionLine } from '@remixicon/react' +import type { PanelExposedType } from '@/types/workflow' const i18nPrefix = 'workflow.nodes.llm' -const Panel: FC> = ({ +const Panel = forwardRef>(({ id, data, -}) => { + panelProps, +}, ref) => { const { t } = useTranslation() const { currentVars, getLastRunInfos, } = useCurrentVars() - console.log(currentVars, getLastRunInfos()) + // console.log(currentVars, getLastRunInfos()) const { readOnly, inputs, @@ -63,26 +62,20 @@ 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) + } = useConfig(id, data, panelProps) const model = inputs.model @@ -147,6 +140,12 @@ const Panel: FC> = ({ // eslint-disable-next-line react-hooks/exhaustive-deps }, []) + useImperativeHandle(ref, () => ({ + singleRunParams: { + forms: singleRunForms, + }, + })) + return (
@@ -348,20 +347,8 @@ const Panel: FC> = ({ )} - {isShowSingleRun && ( - } - /> - )}
) -} +}) export default React.memo(Panel) diff --git a/web/app/components/workflow/nodes/llm/use-config.ts b/web/app/components/workflow/nodes/llm/use-config.ts index 13db9e4031..89c43f1601 100644 --- a/web/app/components/workflow/nodes/llm/use-config.ts +++ b/web/app/components/workflow/nodes/llm/use-config.ts @@ -16,11 +16,16 @@ 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 type { PanelProps } from '@/types/workflow' + +const useConfig = (id: string, payload: LLMNodeType, panelProps?: PanelProps) => { + const getVarInputs = panelProps?.getInputVars + const toVarInputs = panelProps?.toVarInputs + const runInputData = panelProps?.runInputData || {} + const runInputDataRef = panelProps?.runInputDataRef || { current: {} } + const setRunInputData = panelProps?.setRunInputData -const useConfig = (id: string, payload: LLMNodeType) => { const { nodesReadOnly: readOnly } = useNodesReadOnly() const isChatMode = useIsChatMode() @@ -322,28 +327,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) @@ -360,12 +343,12 @@ const useConfig = (id: string, payload: LLMNodeType) => { '#context#': runInputDataRef.current['#context#'], '#files#': runInputDataRef.current['#files#'], } - setRunInputData(newVars) + setRunInputData?.(newVars) }, [runInputDataRef, setRunInputData]) const contexts = runInputData['#context#'] const setContexts = useCallback((newContexts: string[]) => { - setRunInputData({ + setRunInputData?.({ ...runInputDataRef.current, '#context#': newContexts, }) @@ -373,7 +356,7 @@ const useConfig = (id: string, payload: LLMNodeType) => { const visionFiles = runInputData['#files#'] const setVisionFiles = useCallback((newFiles: any[]) => { - setRunInputData({ + setRunInputData?.({ ...runInputDataRef.current, '#files#': newFiles, }) @@ -390,9 +373,9 @@ const useConfig = (id: string, payload: LLMNodeType) => { })() const varInputs = (() => { - const vars = getInputVars(allVarStrArr) + const vars = getVarInputs?.(allVarStrArr) || [] if (isShowVars) - return [...vars, ...toVarInputs(inputs.prompt_config?.jinja2_variables || [])] + return [...vars, ...(toVarInputs ? (toVarInputs(inputs.prompt_config?.jinja2_variables || [])) : [])] return vars })() @@ -423,8 +406,6 @@ const useConfig = (id: string, payload: LLMNodeType) => { handleSyeQueryChange, handleVisionResolutionEnabledChange, handleVisionResolutionChange, - isShowSingleRun, - hideSingleRun, inputVarValues, setInputVarValues, visionFiles, @@ -432,15 +413,11 @@ const useConfig = (id: string, payload: LLMNodeType) => { contexts, setContexts, varInputs, - runningStatus, isModelSupportStructuredOutput, handleStructureOutputChange, structuredOutputCollapsed, setStructuredOutputCollapsed, handleStructureOutputEnableChange, - handleRun, - handleStop, - runResult, filterJinjia2InputVar, } } diff --git a/web/app/components/workflow/types.ts b/web/app/components/workflow/types.ts index 2f75e6bf2c..8fe41ae89f 100644 --- a/web/app/components/workflow/types.ts +++ b/web/app/components/workflow/types.ts @@ -295,6 +295,7 @@ export type Block = { export type NodeDefault = { defaultValue: Partial + defaultRunInputData: Record getAvailablePrevNodes: (isChatMode: boolean) => BlockEnum[] getAvailableNextNodes: (isChatMode: boolean) => BlockEnum[] checkValid: (payload: T, t: any, moreDataForCheckValid?: any) => { isValid: boolean; errorMessage?: string } diff --git a/web/types/workflow.ts b/web/types/workflow.ts index cc0f255e04..2628ac2cc7 100644 --- a/web/types/workflow.ts +++ b/web/types/workflow.ts @@ -1,9 +1,10 @@ import type { Viewport } from 'reactflow' -import type { BlockEnum, ConversationVariable, Edge, EnvironmentVariable, InputVar, Node } from '@/app/components/workflow/types' +import type { BlockEnum, ConversationVariable, Edge, EnvironmentVariable, InputVar, Node, Variable } from '@/app/components/workflow/types' import type { TransferMethod } from '@/types/app' import type { ErrorHandleTypeEnum } from '@/app/components/workflow/nodes/_base/components/error-handle/types' import type { BeforeRunFormProps } from '@/app/components/workflow/nodes/_base/components/before-run-form' import type { SpecialResultPanelProps } from '@/app/components/workflow/run/special-result-panel' +import type { MutableRefObject } from 'react' export type AgentLogItem = { node_execution_id: string, @@ -361,7 +362,11 @@ export type PanelExposedType = { export type PanelProps = { getInputVars: (textList: string[]) => InputVar[] + toVarInputs: (variables: Variable[]) => InputVar[] runInputData: Record + runInputDataRef: MutableRefObject> setRunInputData: (data: Record) => void runResult: any } + +export type NodeRunResult = NodeTracing