From 3a5170716bdd97064692703bf9304973677a6217 Mon Sep 17 00:00:00 2001 From: Joel Date: Fri, 27 Dec 2024 16:29:06 +0800 Subject: [PATCH 01/11] fix: pararllel title --- .../run/utils/format-log/parallel/index.ts | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/web/app/components/workflow/run/utils/format-log/parallel/index.ts b/web/app/components/workflow/run/utils/format-log/parallel/index.ts index a341362e10..f49c71f8c5 100644 --- a/web/app/components/workflow/run/utils/format-log/parallel/index.ts +++ b/web/app/components/workflow/run/utils/format-log/parallel/index.ts @@ -1,22 +1,25 @@ import { BlockEnum } from '@/app/components/workflow/types' import type { NodeTracing } from '@/types/workflow' -function printNodeStructure(node: NodeTracing, level: number) { - const indent = ' '.repeat(level) +function printNodeStructure(node: NodeTracing, depth: number) { + const indent = ' '.repeat(depth) console.log(`${indent}${node.title}`) if (node.parallelDetail?.children) { node.parallelDetail.children.forEach((child) => { - printNodeStructure(child, level + 1) + printNodeStructure(child, depth + 1) }) } } function addTitle({ - list, level, parallelNumRecord, + list, depth, belongParallelIndexInfo, }: { - list: NodeTracing[], level: number, parallelNumRecord: Record + list: NodeTracing[], + depth: number, + belongParallelIndexInfo?: string, }, t: any) { let branchIndex = 0 + const hasMoreThanOneParallel = list.filter(node => node.parallelDetail?.isParallelStartNode).length > 1 list.forEach((node) => { const parallel_id = node.parallel_id ?? node.execution_metadata?.parallel_id ?? null const parallel_start_node_id = node.parallel_start_node_id ?? node.execution_metadata?.parallel_start_node_id ?? null @@ -26,15 +29,20 @@ function addTitle({ return const isParallelStartNode = node.parallelDetail?.isParallelStartNode - if (isParallelStartNode) - parallelNumRecord.num++ - const letter = parallelNumRecord.num > 1 ? String.fromCharCode(64 + level) : '' - const parallelLevelInfo = `${parallelNumRecord.num}${letter}` + const parallelIndexLetter = (() => { + if (!isParallelStartNode || !hasMoreThanOneParallel) + return '' + + const index = 1 + list.filter(node => node.parallelDetail?.isParallelStartNode).findIndex(item => item.node_id === node.node_id) + return String.fromCharCode(64 + index) + })() + + const parallelIndexInfo = `${depth}${parallelIndexLetter}` if (isParallelStartNode) { node.parallelDetail!.isParallelStartNode = true - node.parallelDetail!.parallelTitle = `${t('workflow.common.parallel')}-${parallelLevelInfo}` + node.parallelDetail!.parallelTitle = `${t('workflow.common.parallel')}-${parallelIndexInfo}` } const isBrachStartNode = parallel_start_node_id === node.node_id @@ -47,14 +55,14 @@ function addTitle({ } } - node.parallelDetail!.branchTitle = `${t('workflow.common.branch')}-${parallelLevelInfo}-${branchLetter}` + node.parallelDetail!.branchTitle = `${t('workflow.common.branch')}-${belongParallelIndexInfo}-${branchLetter}` } if (node.parallelDetail?.children && node.parallelDetail.children.length > 0) { addTitle({ list: node.parallelDetail.children, - level: level + 1, - parallelNumRecord, + depth: depth + 1, + belongParallelIndexInfo: parallelIndexInfo, }, t) } }) @@ -144,14 +152,9 @@ const format = (list: NodeTracing[], t: any): NodeTracing[] => { // console.log(`----- p: ${now} end -----`) // }) - const parallelNumRecord: Record = { - num: 0, - } - addTitle({ list: filteredInParallelSubNodes, - level: 1, - parallelNumRecord, + depth: 1, }, t) return filteredInParallelSubNodes From 573c8f909cca646e10b4f8f0f494e87e6bbe323f Mon Sep 17 00:00:00 2001 From: JzoNg Date: Fri, 27 Dec 2024 16:30:19 +0800 Subject: [PATCH 02/11] add multiple tool selector --- .../model-provider-page/declarations.ts | 1 + .../model-provider-page/model-modal/Form.tsx | 31 ++++++- .../plugins/plugin-detail-panel/index.tsx | 20 ++--- .../multiple-tool-selector/index.tsx | 85 ++++++++++++++++++- .../tool-selector/index.tsx | 15 ++-- .../nodes/_base/components/agent-strategy.tsx | 22 ++++- web/i18n/en-US/plugin.ts | 1 + web/i18n/zh-Hans/plugin.ts | 1 + 8 files changed, 149 insertions(+), 27 deletions(-) diff --git a/web/app/components/header/account-setting/model-provider-page/declarations.ts b/web/app/components/header/account-setting/model-provider-page/declarations.ts index 8f0adb1259..4500ebc1f7 100644 --- a/web/app/components/header/account-setting/model-provider-page/declarations.ts +++ b/web/app/components/header/account-setting/model-provider-page/declarations.ts @@ -17,6 +17,7 @@ export enum FormTypeEnum { file = 'file', modelSelector = 'model-selector', toolSelector = 'tool-selector', + multiToolSelector = 'array[tools]', appSelector = 'app-selector', } diff --git a/web/app/components/header/account-setting/model-provider-page/model-modal/Form.tsx b/web/app/components/header/account-setting/model-provider-page/model-modal/Form.tsx index b7a9a69870..b357c2cb49 100644 --- a/web/app/components/header/account-setting/model-provider-page/model-modal/Form.tsx +++ b/web/app/components/header/account-setting/model-provider-page/model-modal/Form.tsx @@ -19,6 +19,7 @@ import Tooltip from '@/app/components/base/tooltip' import Radio from '@/app/components/base/radio' import ModelParameterModal from '@/app/components/plugins/plugin-detail-panel/model-selector' import ToolSelector from '@/app/components/plugins/plugin-detail-panel/tool-selector' +import MultipleToolSelector from '@/app/components/plugins/plugin-detail-panel/multiple-tool-selector' import AppSelector from '@/app/components/plugins/plugin-detail-panel/app-selector' import RadioE from '@/app/components/base/radio/ui' @@ -328,7 +329,35 @@ function Form< scope={scope} disabled={readonly} value={value[variable]} - onSelect={item => handleFormChange(variable, item as any)} /> + onSelect={item => handleFormChange(variable, item as any)} + onDelete={() => handleFormChange(variable, null as any)} + /> + {fieldMoreInfo?.(formSchema)} + {validating && changeKey === variable && } + + ) + } + + if (formSchema.type === FormTypeEnum.multiToolSelector) { + const { + variable, + label, + tooltip, + required, + scope, + } = formSchema as (CredentialFormSchemaTextInput | CredentialFormSchemaSecretInput) + + return ( +
+ handleFormChange(variable, item as any)} + /> {fieldMoreInfo?.(formSchema)} {validating && changeKey === variable && }
diff --git a/web/app/components/plugins/plugin-detail-panel/index.tsx b/web/app/components/plugins/plugin-detail-panel/index.tsx index d14c0d96be..150158e42c 100644 --- a/web/app/components/plugins/plugin-detail-panel/index.tsx +++ b/web/app/components/plugins/plugin-detail-panel/index.tsx @@ -7,7 +7,6 @@ import ActionList from './action-list' import ModelList from './model-list' import AgentStrategyList from './agent-strategy-list' import Drawer from '@/app/components/base/drawer' -import ToolSelector from '@/app/components/plugins/plugin-detail-panel/tool-selector' import type { PluginDetail } from '@/app/components/plugins/types' import cn from '@/utils/classnames' @@ -33,9 +32,6 @@ const PluginDetailPanel: FC = ({ console.log('tool change', val) setValue(val) } - const testDelete = () => { - setValue(undefined) - } if (!detail) return null @@ -62,15 +58,13 @@ const PluginDetailPanel: FC = ({ {!!detail.declaration.agent_strategy && } {!!detail.declaration.endpoint && } {!!detail.declaration.model && } - {false && ( -
- testChange(item)} - onDelete={testDelete} - /> -
- )} + {/*
+ +
*/} )} diff --git a/web/app/components/plugins/plugin-detail-panel/multiple-tool-selector/index.tsx b/web/app/components/plugins/plugin-detail-panel/multiple-tool-selector/index.tsx index bbf5a8a1ef..47c6833369 100644 --- a/web/app/components/plugins/plugin-detail-panel/multiple-tool-selector/index.tsx +++ b/web/app/components/plugins/plugin-detail-panel/multiple-tool-selector/index.tsx @@ -1,12 +1,91 @@ import React from 'react' +import { useTranslation } from 'react-i18next' +import { + RiAddLine, + RiArrowDropDownLine, + RiQuestionLine, +} from '@remixicon/react' +import type { ToolValue } from '@/app/components/plugins/plugin-detail-panel/tool-selector' +import ActionButton from '@/app/components/base/action-button' +import Tooltip from '@/app/components/base/tooltip' +import Divider from '@/app/components/base/divider' +import cn from '@/utils/classnames' type Props = { - value: any[] + disabled?: boolean + value: ToolValue[] + label: string + required?: boolean + tooltip?: any + supportCollapse?: boolean + onChange: (value: ToolValue[]) => void + scope?: string } -const MultipleToolSelector = ({ value }: Props) => { +const MultipleToolSelector = ({ + value, + label, + required, + tooltip, + supportCollapse, +}: Props) => { + const { t } = useTranslation() + const [collapse, setCollapse] = React.useState(false) + + const handleCollapse = () => { + if (supportCollapse) + setCollapse(!collapse) + } + return ( -
+ <> +
+
+
{label}
+ {required &&
*
} + {tooltip && ( + +
+
+ )} + {supportCollapse && ( +
+ +
+ )} +
+ {value.length > 0 && ( + <> +
+ {`${value.length}/${value.length}`} + {t('appDebug.agent.tools.enabled')} +
+ + + )} + {}}> + + +
+ {!collapse && ( + <> + {value.length === 0 && ( +
{t('plugin.detailPanel.toolSelector.empty')}
+ )} + + )} + ) } diff --git a/web/app/components/plugins/plugin-detail-panel/tool-selector/index.tsx b/web/app/components/plugins/plugin-detail-panel/tool-selector/index.tsx index 3e7993f761..7bf6165971 100644 --- a/web/app/components/plugins/plugin-detail-panel/tool-selector/index.tsx +++ b/web/app/components/plugins/plugin-detail-panel/tool-selector/index.tsx @@ -40,13 +40,16 @@ import type { } from '@floating-ui/react' import cn from '@/utils/classnames' +export type ToolValue = { + provider_name: string + tool_name: string + parameters?: Record + enabled?: boolean + extra?: Record +} + type Props = { - value?: { - provider_name: string - tool_name: string - parameters?: Record - extra?: Record - } + value?: ToolValue disabled?: boolean placement?: Placement offset?: OffsetOptions diff --git a/web/app/components/workflow/nodes/_base/components/agent-strategy.tsx b/web/app/components/workflow/nodes/_base/components/agent-strategy.tsx index 3f0b05b8e6..c156aac671 100644 --- a/web/app/components/workflow/nodes/_base/components/agent-strategy.tsx +++ b/web/app/components/workflow/nodes/_base/components/agent-strategy.tsx @@ -10,6 +10,7 @@ import { Agent } from '@/app/components/base/icons/src/vender/workflow' import { InputNumber } from '@/app/components/base/input-number' import Slider from '@/app/components/base/slider' import ToolSelector from '@/app/components/plugins/plugin-detail-panel/tool-selector' +import MultipleToolSelector from '@/app/components/plugins/plugin-detail-panel/multiple-tool-selector' import Field from './field' import type { ComponentProps } from 'react' import { useLanguage } from '@/app/components/header/account-setting/model-provider-page/hooks' @@ -160,18 +161,31 @@ export const AgentStrategy = (props: AgentStrategyProps) => { props.onChange({ ...props.value, [schema.variable]: value }) } return ( - + onChange(item)} + onDelete={() => onChange(null)} /> ) } case 'array[tools]': { - return - multiple tool selector TODO - + const value = props.value[schema.variable] + const onChange = (value: any) => { + props.onChange({ ...props.value, [schema.variable]: value }) + } + return ( + + ) } } } diff --git a/web/i18n/en-US/plugin.ts b/web/i18n/en-US/plugin.ts index 38ec6d9be7..a706f8f042 100644 --- a/web/i18n/en-US/plugin.ts +++ b/web/i18n/en-US/plugin.ts @@ -73,6 +73,7 @@ const translation = { placeholder: 'Select a tool...', auth: 'AUTHORIZATION', settings: 'TOOL SETTINGS', + empty: 'Click the \'+\' button to add tools. You can add multiple tools.', }, configureApp: 'Configure App', configureModel: 'Configure model', diff --git a/web/i18n/zh-Hans/plugin.ts b/web/i18n/zh-Hans/plugin.ts index 8185f37b40..4b7c764d9f 100644 --- a/web/i18n/zh-Hans/plugin.ts +++ b/web/i18n/zh-Hans/plugin.ts @@ -73,6 +73,7 @@ const translation = { placeholder: '选择工具', auth: '授权', settings: '工具设置', + empty: '点击 "+" 按钮添加工具。您可以添加多个工具。', }, configureApp: '应用设置', configureModel: '模型设置', From 0108b28305348e7fabbdbcba63a558d52d4a33bf Mon Sep 17 00:00:00 2001 From: AkaraChen Date: Fri, 27 Dec 2024 16:39:18 +0800 Subject: [PATCH 03/11] feat: model list on agent node --- .../components/workflow/nodes/agent/node.tsx | 46 ++++++++++++------- .../components/workflow/nodes/agent/types.ts | 2 +- 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/web/app/components/workflow/nodes/agent/node.tsx b/web/app/components/workflow/nodes/agent/node.tsx index 2a55566f58..c64baf3b19 100644 --- a/web/app/components/workflow/nodes/agent/node.tsx +++ b/web/app/components/workflow/nodes/agent/node.tsx @@ -9,6 +9,7 @@ import { ToolIcon } from './components/tool-icon' import useConfig from './use-config' import { useTranslation } from 'react-i18next' import { useInstalledPluginList } from '@/service/use-plugins' +import { FormTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations' const AgentNode: FC> = (props) => { const { inputs, currentStrategy } = useConfig(props.id, props.data) @@ -16,11 +17,28 @@ const AgentNode: FC> = (props) => { const pluginList = useInstalledPluginList() // TODO: Implement models const models = useMemo(() => { - const models = [] + if (!inputs) return [] + const models = currentStrategy?.parameters + .filter(param => param.type === FormTypeEnum.modelSelector) + .flatMap((param) => { + const item = inputs.agent_parameters?.[param.name] + if (!item) { + if (param.required) + return null + else + return [] + } + return { + provider: item.provider, + model: item.model, + param: param.name, + } + }) || [] + return models // if selected, show in node // if required and not selected, show empty selector // if not required and not selected, show nothing - }, [currentStrategy, inputs.agent_parameters]) + }, [currentStrategy, inputs]) const tools = useMemo(() => { const tools: Array = [] @@ -49,24 +67,20 @@ const AgentNode: FC> = (props) => { {inputs.agent_strategy_label} : } - {t('workflow.nodes.agent.model')} } > - - - - + {models.map((model) => { + return + })} + } {t('workflow.nodes.agent.toolbox')} }> diff --git a/web/app/components/workflow/nodes/agent/types.ts b/web/app/components/workflow/nodes/agent/types.ts index 20da43f66a..c3351c1d9d 100644 --- a/web/app/components/workflow/nodes/agent/types.ts +++ b/web/app/components/workflow/nodes/agent/types.ts @@ -5,7 +5,7 @@ export type AgentNodeType = CommonNodeType & { agent_strategy_provider_name?: string agent_strategy_name?: string agent_strategy_label?: string - agent_parameters?: ToolVarInputs, + agent_parameters?: Record agent_configurations?: Record output_schema: Record } From da2982ba9834f0ba5c32b376d81f5c678030bd65 Mon Sep 17 00:00:00 2001 From: AkaraChen Date: Fri, 27 Dec 2024 16:45:46 +0800 Subject: [PATCH 04/11] feat: model list on agent node --- .../components/workflow/nodes/agent/node.tsx | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/web/app/components/workflow/nodes/agent/node.tsx b/web/app/components/workflow/nodes/agent/node.tsx index c64baf3b19..3cfde2e64d 100644 --- a/web/app/components/workflow/nodes/agent/node.tsx +++ b/web/app/components/workflow/nodes/agent/node.tsx @@ -18,26 +18,24 @@ const AgentNode: FC> = (props) => { // TODO: Implement models const models = useMemo(() => { if (!inputs) return [] + // if selected, show in node + // if required and not selected, show empty selector + // if not required and not selected, show nothing const models = currentStrategy?.parameters .filter(param => param.type === FormTypeEnum.modelSelector) - .flatMap((param) => { + .reduce((acc, param) => { const item = inputs.agent_parameters?.[param.name] if (!item) { - if (param.required) - return null - else - return [] - } - return { - provider: item.provider, - model: item.model, - param: param.name, + if (param.required) { + acc.push({ param: param.name }) + return acc + } + else { return acc } } - }) || [] + acc.push({ provider: item.provider, model: item.model, param: param.name }) + return acc + }, [] as Array<{ param: string } | { provider: string, model: string, param: string }>) || [] return models - // if selected, show in node - // if required and not selected, show empty selector - // if not required and not selected, show nothing }, [currentStrategy, inputs]) const tools = useMemo(() => { @@ -78,6 +76,7 @@ const AgentNode: FC> = (props) => { key={model?.param || Math.random()} modelList={[]} defaultModel={model || undefined} + readonly /> })} } From 3d5620dfb39a3e97321c9db7939f28f1577b009a Mon Sep 17 00:00:00 2001 From: Joel Date: Fri, 27 Dec 2024 16:46:56 +0800 Subject: [PATCH 05/11] fix: parallel start node not insert into the right place --- .../run/utils/format-log/parallel/index.ts | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/web/app/components/workflow/run/utils/format-log/parallel/index.ts b/web/app/components/workflow/run/utils/format-log/parallel/index.ts index f49c71f8c5..9501eec7ec 100644 --- a/web/app/components/workflow/run/utils/format-log/parallel/index.ts +++ b/web/app/components/workflow/run/utils/format-log/parallel/index.ts @@ -78,7 +78,7 @@ const format = (list: NodeTracing[], t: any): NodeTracing[] => { const parallel_id = node.parallel_id ?? node.execution_metadata?.parallel_id ?? null const parent_parallel_id = node.parent_parallel_id ?? node.execution_metadata?.parent_parallel_id ?? null const branchStartNodeId = node.parallel_start_node_id ?? node.execution_metadata?.parallel_start_node_id ?? null - const parent_parallel_start_node_id = node.parent_parallel_start_node_id ?? node.execution_metadata?.parent_parallel_start_node_id ?? null + const parentParallelBranchStartNodeId = node.parent_parallel_start_node_id ?? node.execution_metadata?.parent_parallel_start_node_id ?? null const isNotInParallel = !parallel_id || node.node_type === BlockEnum.End if (isNotInParallel) return @@ -95,16 +95,24 @@ const format = (list: NodeTracing[], t: any): NodeTracing[] => { if (isRootLevel) return - const parentParallelStartNode = result.find(item => item.node_id === parent_parallel_start_node_id) - // append to parent parallel start node + const parentParallelStartNode = result.find(item => item.node_id === parentParallelBranchStartNodeId) + // append to parent parallel start node and after the same branch if (parentParallelStartNode) { if (!parentParallelStartNode?.parallelDetail) { parentParallelStartNode!.parallelDetail = { children: [], } } - if (parentParallelStartNode!.parallelDetail.children) - parentParallelStartNode!.parallelDetail.children.push(node) + if (parentParallelStartNode!.parallelDetail.children) { + const sameBranchNodesLastIndex = parentParallelStartNode.parallelDetail.children.findLastIndex((node) => { + const currStartNodeId = node.parallel_start_node_id ?? node.execution_metadata?.parallel_start_node_id ?? null + return currStartNodeId === parentParallelBranchStartNodeId + }) + if (sameBranchNodesLastIndex !== -1) + parentParallelStartNode!.parallelDetail.children.splice(sameBranchNodesLastIndex + 1, 0, node) + else + parentParallelStartNode!.parallelDetail.children.push(node) + } } return } From de48a1c7e9b6850bd89e958af91a5b5779e59a08 Mon Sep 17 00:00:00 2001 From: AkaraChen Date: Fri, 27 Dec 2024 16:48:16 +0800 Subject: [PATCH 06/11] fix: type error --- web/app/components/workflow/nodes/agent/node.tsx | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/web/app/components/workflow/nodes/agent/node.tsx b/web/app/components/workflow/nodes/agent/node.tsx index 3cfde2e64d..626f38b11f 100644 --- a/web/app/components/workflow/nodes/agent/node.tsx +++ b/web/app/components/workflow/nodes/agent/node.tsx @@ -72,10 +72,15 @@ const AgentNode: FC> = (props) => { > {models.map((model) => { return })} From 6a2a7aca9b0fe930d63ac7441984b07767dfcc5a Mon Sep 17 00:00:00 2001 From: Joel Date: Fri, 27 Dec 2024 16:52:06 +0800 Subject: [PATCH 07/11] chore: tool node support agent logs --- .../components/workflow/run/utils/format-log/agent/index.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/web/app/components/workflow/run/utils/format-log/agent/index.ts b/web/app/components/workflow/run/utils/format-log/agent/index.ts index 7bbe0aa57f..255dc16c5c 100644 --- a/web/app/components/workflow/run/utils/format-log/agent/index.ts +++ b/web/app/components/workflow/run/utils/format-log/agent/index.ts @@ -1,6 +1,8 @@ import { BlockEnum } from '@/app/components/workflow/types' import type { AgentLogItem, AgentLogItemWithChildren, NodeTracing } from '@/types/workflow' +const supportedAgentLogNodes = [BlockEnum.Agent, BlockEnum.Tool] + const listToTree = (logs: AgentLogItem[]) => { if (!logs || logs.length === 0) return [] @@ -24,7 +26,7 @@ const listToTree = (logs: AgentLogItem[]) => { } const format = (list: NodeTracing[]): NodeTracing[] => { const result: NodeTracing[] = list.map((item) => { - if (item.node_type === BlockEnum.Agent && item.execution_metadata?.agent_log && item.execution_metadata?.agent_log.length > 0) + if (supportedAgentLogNodes.includes(item.node_type) && item.execution_metadata?.agent_log && item.execution_metadata?.agent_log.length > 0) item.agentLog = listToTree(item.execution_metadata.agent_log) return item From a863e9f674cc3906710354434034cfc1eed7cad6 Mon Sep 17 00:00:00 2001 From: zxhlyh Date: Fri, 27 Dec 2024 17:21:39 +0800 Subject: [PATCH 08/11] refact workflow run log --- .../nodes/_base/hooks/use-one-step-run.ts | 53 +++++++++++----- .../workflow/nodes/iteration/panel.tsx | 61 ++++++++++++------- .../iteration-log/iteration-log-trigger.tsx | 41 ++++--------- 3 files changed, 91 insertions(+), 64 deletions(-) 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 3f7bf1987d..d8a2b745db 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 @@ -142,7 +142,7 @@ const useOneStepRun = ({ const { handleNodeDataUpdate }: { handleNodeDataUpdate: (data: any) => void } = useNodeDataUpdate() const [canShowSingleRun, setCanShowSingleRun] = useState(false) const isShowSingleRun = data._isSingleRun && canShowSingleRun - const [iterationRunResult, setIterationRunResult] = useState([]) + const [iterationRunResult, setIterationRunResult] = useState([]) useEffect(() => { if (!checkValid) { @@ -173,7 +173,7 @@ const useOneStepRun = ({ const workflowStore = useWorkflowStore() useEffect(() => { workflowStore.getState().setShowSingleRunPanel(!!isShowSingleRun) - }, [isShowSingleRun]) + }, [isShowSingleRun, workflowStore]) const hideSingleRun = () => { handleNodeDataUpdate({ @@ -211,7 +211,7 @@ const useOneStepRun = ({ } else { setIterationRunResult([]) - let _iterationResult: NodeTracing[][] = [] + let _iterationResult: NodeTracing[] = [] let _runResult: any = null ssePost( getIterationSingleNodeRunUrl(isChatMode, appId!, id), @@ -231,27 +231,43 @@ const useOneStepRun = ({ _runResult.created_by = iterationData.created_by.name setRunResult(_runResult) }, - onIterationNext: () => { - // iteration next trigger time is triggered one more time than iterationTimes - if (_iterationResult.length >= iterationTimes!) - return - + onIterationStart: (params) => { const newIterationRunResult = produce(_iterationResult, (draft) => { - draft.push([]) + draft.push({ + ...params.data, + status: NodeRunningStatus.Running, + }) }) _iterationResult = newIterationRunResult setIterationRunResult(newIterationRunResult) }, + onIterationNext: () => { + // iteration next trigger time is triggered one more time than iterationTimes + if (_iterationResult.length >= iterationTimes!) + return _iterationResult.length >= iterationTimes! + }, onIterationFinish: (params) => { _runResult = params.data setRunResult(_runResult) + const iterationRunResult = _iterationResult + const currentIndex = iterationRunResult.findIndex(trace => trace.id === params.data.id) + const newIterationRunResult = produce(iterationRunResult, (draft) => { + if (currentIndex > -1) { + draft[currentIndex] = { + ...draft[currentIndex], + ...data, + } + } + }) + _iterationResult = newIterationRunResult + setIterationRunResult(newIterationRunResult) }, onNodeStarted: (params) => { const newIterationRunResult = produce(_iterationResult, (draft) => { - draft[draft.length - 1].push({ + draft.push({ ...params.data, status: NodeRunningStatus.Running, - } as NodeTracing) + }) }) _iterationResult = newIterationRunResult setIterationRunResult(newIterationRunResult) @@ -260,18 +276,25 @@ const useOneStepRun = ({ const iterationRunResult = _iterationResult const { data } = params - const currentIndex = iterationRunResult[iterationRunResult.length - 1].findIndex(trace => trace.node_id === data.node_id) + const currentIndex = iterationRunResult.findIndex(trace => trace.id === data.id) const newIterationRunResult = produce(iterationRunResult, (draft) => { if (currentIndex > -1) { - draft[draft.length - 1][currentIndex] = { + draft[currentIndex] = { + ...draft[currentIndex], ...data, - status: NodeRunningStatus.Succeeded, - } as NodeTracing + } } }) _iterationResult = newIterationRunResult setIterationRunResult(newIterationRunResult) }, + onNodeRetry: (params) => { + const newIterationRunResult = produce(_iterationResult, (draft) => { + draft.push(params.data) + }) + _iterationResult = newIterationRunResult + setIterationRunResult(newIterationRunResult) + }, onError: () => { handleNodeDataUpdate({ id, diff --git a/web/app/components/workflow/nodes/iteration/panel.tsx b/web/app/components/workflow/nodes/iteration/panel.tsx index 83402e9cad..89f4d59734 100644 --- a/web/app/components/workflow/nodes/iteration/panel.tsx +++ b/web/app/components/workflow/nodes/iteration/panel.tsx @@ -1,13 +1,9 @@ import type { FC } from 'react' import React from 'react' import { useTranslation } from 'react-i18next' -import { - RiArrowRightSLine, -} from '@remixicon/react' import VarReferencePicker from '../_base/components/variable/var-reference-picker' import Split from '../_base/components/split' import ResultPanel from '../../run/result-panel' -import { IterationResultPanel } from '../../run/iteration-log' import { MAX_ITERATION_PARALLEL_NUM, MIN_ITERATION_PARALLEL_NUM } from '../../constants' import type { IterationNodeType } from './types' import useConfig from './use-config' @@ -18,6 +14,12 @@ import Switch from '@/app/components/base/switch' import Select from '@/app/components/base/select' import Slider from '@/app/components/base/slider' import Input from '@/app/components/base/input' +import formatTracing from '@/app/components/workflow/run/utils/format-log' +import { + IterationLogTrigger, + IterationResultPanel, +} from '@/app/components/workflow/run/iteration-log' +import { useLogs } from '@/app/components/workflow/run/hooks' const i18nPrefix = 'workflow.nodes.iteration' @@ -50,9 +52,6 @@ const Panel: FC> = ({ handleOutputVarChange, isShowSingleRun, hideSingleRun, - isShowIterationDetail, - backToSingleRun, - showIterationDetail, runningStatus, handleRun, handleStop, @@ -69,6 +68,14 @@ const Panel: FC> = ({ changeParallelNums, } = useConfig(id, data) + const nodeInfo = formatTracing(iterationRunResult, t)[0] + const { + showIteratingDetail, + iterationResultList, + setShowIteratingDetailFalse, + handleShowIterationResultList, + } = useLogs() + return (
@@ -165,24 +172,36 @@ const Panel: FC> = ({ onStop={handleStop} result={
-
-
-
{t(`${i18nPrefix}.iteration`, { count: iterationRunResult.length })}
- -
- -
- + { + !showIteratingDetail && ( + <> + { + nodeInfo && ( +
+ + +
+ ) + } + + + ) + } + { + showIteratingDetail && ( + + ) + }
} /> )} - {isShowIterationDetail && ( - - )}
) } diff --git a/web/app/components/workflow/run/iteration-log/iteration-log-trigger.tsx b/web/app/components/workflow/run/iteration-log/iteration-log-trigger.tsx index 350c15c2b8..93c6495216 100644 --- a/web/app/components/workflow/run/iteration-log/iteration-log-trigger.tsx +++ b/web/app/components/workflow/run/iteration-log/iteration-log-trigger.tsx @@ -6,17 +6,14 @@ import type { NodeTracing, } from '@/types/workflow' import { Iteration } from '@/app/components/base/icons/src/vender/workflow' -import Split from '@/app/components/workflow/nodes/_base/components/split' type IterationLogTriggerProps = { nodeInfo: NodeTracing onShowIterationResultList: (iterationResultList: NodeTracing[][], iterationResultDurationMap: IterationDurationMap) => void - justShowIterationNavArrow?: boolean } const IterationLogTrigger = ({ nodeInfo, onShowIterationResultList, - justShowIterationNavArrow, }: IterationLogTriggerProps) => { const { t } = useTranslation() const getErrorCount = (details: NodeTracing[][] | undefined) => { @@ -41,31 +38,19 @@ const IterationLogTrigger = ({ onShowIterationResultList(nodeInfo.details || [], nodeInfo?.iterDurationMap || nodeInfo.execution_metadata?.iteration_duration_map || {}) } return ( -
- - -
+ ) } From 3c853633928e6cff1737cbc48b9ed4041d9279d1 Mon Sep 17 00:00:00 2001 From: JzoNg Date: Fri, 27 Dec 2024 17:29:21 +0800 Subject: [PATCH 09/11] multiple tool selector --- .../plugins/plugin-detail-panel/index.tsx | 17 +++-- .../multiple-tool-selector/index.tsx | 68 +++++++++++++++++-- .../tool-selector/index.tsx | 37 +++++++--- .../tool-selector/tool-item.tsx | 17 +++-- 4 files changed, 111 insertions(+), 28 deletions(-) diff --git a/web/app/components/plugins/plugin-detail-panel/index.tsx b/web/app/components/plugins/plugin-detail-panel/index.tsx index 150158e42c..57aa24bf84 100644 --- a/web/app/components/plugins/plugin-detail-panel/index.tsx +++ b/web/app/components/plugins/plugin-detail-panel/index.tsx @@ -7,6 +7,7 @@ import ActionList from './action-list' import ModelList from './model-list' import AgentStrategyList from './agent-strategy-list' import Drawer from '@/app/components/base/drawer' +import MultipleToolSelector from '@/app/components/plugins/plugin-detail-panel/multiple-tool-selector' import type { PluginDetail } from '@/app/components/plugins/types' import cn from '@/utils/classnames' @@ -58,13 +59,15 @@ const PluginDetailPanel: FC = ({ {!!detail.declaration.agent_strategy && } {!!detail.declaration.endpoint && } {!!detail.declaration.model && } - {/*
- -
*/} + {false && ( +
+ +
+ )}
)} diff --git a/web/app/components/plugins/plugin-detail-panel/multiple-tool-selector/index.tsx b/web/app/components/plugins/plugin-detail-panel/multiple-tool-selector/index.tsx index 47c6833369..a6532ae6f7 100644 --- a/web/app/components/plugins/plugin-detail-panel/multiple-tool-selector/index.tsx +++ b/web/app/components/plugins/plugin-detail-panel/multiple-tool-selector/index.tsx @@ -5,10 +5,11 @@ import { RiArrowDropDownLine, RiQuestionLine, } from '@remixicon/react' -import type { ToolValue } from '@/app/components/plugins/plugin-detail-panel/tool-selector' +import ToolSelector from '@/app/components/plugins/plugin-detail-panel/tool-selector' import ActionButton from '@/app/components/base/action-button' import Tooltip from '@/app/components/base/tooltip' import Divider from '@/app/components/base/divider' +import type { ToolValue } from '@/app/components/plugins/plugin-detail-panel/tool-selector' import cn from '@/utils/classnames' type Props = { @@ -18,25 +19,57 @@ type Props = { required?: boolean tooltip?: any supportCollapse?: boolean - onChange: (value: ToolValue[]) => void scope?: string + onChange: (value: ToolValue[]) => void } const MultipleToolSelector = ({ + disabled, value, label, required, tooltip, supportCollapse, + scope, + onChange, }: Props) => { const { t } = useTranslation() + // collapse control const [collapse, setCollapse] = React.useState(false) - const handleCollapse = () => { if (supportCollapse) setCollapse(!collapse) } + // add tool + const [open, setOpen] = React.useState(false) + const handleAdd = (val: ToolValue) => { + const newValue = [...value, val] + // deduplication + const deduplication = newValue.reduce((acc, cur) => { + if (!acc.find(item => item.provider_name === cur.provider_name && item.tool_name === cur.tool_name)) + acc.push(cur) + return acc + }, [] as ToolValue[]) + // update value + onChange(deduplication) + setOpen(false) + } + + // delete tool + const handleDelete = (index: number) => { + const newValue = [...value] + newValue.splice(index, 1) + onChange(newValue) + } + + // configure tool + const handleConfigure = (val: ToolValue, index: number) => { + const newValue = [...value] + newValue[index] = val + onChange(newValue) + } + return ( <>
@@ -74,15 +107,38 @@ const MultipleToolSelector = ({ )} - {}}> - - + {!disabled && ( + setOpen(!open)}> + + + )}
{!collapse && ( <> + + } + /> {value.length === 0 && (
{t('plugin.detailPanel.toolSelector.empty')}
)} + {value.length > 0 && value.map((item, index) => ( +
+ handleConfigure(item, index)} + onDelete={() => handleDelete(index)} + supportEnableSwitch + /> +
+ ))} )} diff --git a/web/app/components/plugins/plugin-detail-panel/tool-selector/index.tsx b/web/app/components/plugins/plugin-detail-panel/tool-selector/index.tsx index 7bf6165971..d21a0a1ded 100644 --- a/web/app/components/plugins/plugin-detail-panel/tool-selector/index.tsx +++ b/web/app/components/plugins/plugin-detail-panel/tool-selector/index.tsx @@ -49,10 +49,11 @@ export type ToolValue = { } type Props = { - value?: ToolValue disabled?: boolean placement?: Placement offset?: OffsetOptions + scope?: string + value?: ToolValue onSelect: (tool: { provider_name: string tool_name: string @@ -60,8 +61,11 @@ type Props = { extra?: Record }) => void onDelete?: () => void + supportEnableSwitch?: boolean supportAddCustomTool?: boolean - scope?: string + trigger?: React.ReactNode + controlledState?: boolean + onControlledStateChange?: (state: boolean) => void } const ToolSelector: FC = ({ value, @@ -71,6 +75,10 @@ const ToolSelector: FC = ({ onSelect, onDelete, scope, + supportEnableSwitch, + trigger, + controlledState, + onControlledStateChange, }) => { const { t } = useTranslation() const [isShow, onShowChange] = useState(false) @@ -98,14 +106,13 @@ const ToolSelector: FC = ({ provider_name: tool.provider_id, tool_name: tool.tool_name, parameters: paramValues, + enabled: tool.is_team_authorization, extra: { description: '', }, } onSelect(toolValue) setIsShowChooseTool(false) - // if (tool.provider_type === CollectionType.builtIn && tool.is_team_authorization) - // onShowChange(false) } const handleDescriptionChange = (e: React.ChangeEvent) => { @@ -133,6 +140,13 @@ const ToolSelector: FC = ({ onSelect(toolValue as any) } + const handleEnabledChange = (state: boolean) => { + onSelect({ + ...value, + enabled: state, + } as any) + } + // authorization const { isCurrentWorkspaceManager } = useAppContext() const [isShowSettingAuth, setShowSettingAuth] = useState(false) @@ -155,14 +169,15 @@ const ToolSelector: FC = ({ - {!value?.provider_name && ( + {trigger} + {!trigger && !value?.provider_name && ( = ({ provider={currentProvider} /> )} - {value?.provider_name && ( + {!trigger && value?.provider_name && ( setShowSettingAuth(true)} - // uninstalled + // uninstalled TODO + // isError TODO errorTip={

{t('workflow.nodes.agent.pluginNotInstalled')}

{t('workflow.nodes.agent.pluginNotInstalledDesc')}

diff --git a/web/app/components/plugins/plugin-detail-panel/tool-selector/tool-item.tsx b/web/app/components/plugins/plugin-detail-panel/tool-selector/tool-item.tsx index a20e0d6e6f..f2ff56d07b 100644 --- a/web/app/components/plugins/plugin-detail-panel/tool-selector/tool-item.tsx +++ b/web/app/components/plugins/plugin-detail-panel/tool-selector/tool-item.tsx @@ -77,7 +77,10 @@ const ToolItem = ({ )}
{ + e.stopPropagation() + onDelete?.() + }} onMouseOver={() => setIsDeleting(true)} onMouseLeave={() => setIsDeleting(false)} > @@ -85,11 +88,13 @@ const ToolItem = ({
{!isError && !uninstalled && !noAuth && showSwitch && ( - +
e.stopPropagation()}> + +
)} {!isError && !uninstalled && noAuth && ( - - ) - } +
+ { + isIterationNode && handleShowIterationResultList && ( + + ) + } + { + isRetryNode && onShowRetryDetail && ( + + ) + } + { + isAgentNode && onShowAgentResultList && ( + + ) + } +
void - retryResultList: NodeTracing[] +export type SpecialResultPanelProps = { + showRetryDetail?: boolean + setShowRetryDetailFalse?: () => void + retryResultList?: NodeTracing[] - showIteratingDetail: boolean - setShowIteratingDetailFalse: () => void - iterationResultList: NodeTracing[][] - iterationResultDurationMap: IterationDurationMap + showIteratingDetail?: boolean + setShowIteratingDetailFalse?: () => void + iterationResultList?: NodeTracing[][] + iterationResultDurationMap?: IterationDurationMap - agentResultList: AgentLogItemWithChildren[] - setAgentResultList: (list: AgentLogItemWithChildren[]) => void + agentResultList?: AgentLogItemWithChildren[] + setAgentResultList?: (list: AgentLogItemWithChildren[]) => void } const SpecialResultPanel = ({ showRetryDetail, @@ -36,7 +36,7 @@ const SpecialResultPanel = ({ return ( <> { - showRetryDetail && ( + !!showRetryDetail && !!retryResultList?.length && setShowRetryDetailFalse && ( = ({ onShowIterationDetail={handleShowIterationResultList} onShowRetryDetail={handleShowRetryResultList} onShowAgentResultList={setAgentResultList} - justShowIterationNavArrow={true} - justShowRetryNavArrow={true} hideInfo={hideNodeInfo} hideProcessDetail={hideNodeProcessDetail} />