From 1b8ec6710aeadc93f636ee027f9f64f7296be719 Mon Sep 17 00:00:00 2001 From: AkaraChen Date: Thu, 2 Jan 2025 11:29:10 +0800 Subject: [PATCH 01/12] feat: agent node checklist --- .../workflow/hooks/use-checklist.ts | 15 +++++++++- .../components/workflow/hooks/use-workflow.ts | 20 ++++++++++++- .../components/agent-strategy-selector.tsx | 11 ++++--- .../nodes/_base/components/agent-strategy.tsx | 9 ++++-- .../nodes/_base/components/setting-item.tsx | 8 +++-- .../nodes/agent/components/tool-icon.tsx | 8 +++-- .../workflow/nodes/agent/default.ts | 30 ++++++++++++++----- .../components/workflow/nodes/agent/node.tsx | 6 ++-- .../components/workflow/nodes/agent/panel.tsx | 8 +++-- .../components/workflow/nodes/agent/types.ts | 1 + .../components/workflow/nodes/agent/utils.ts | 5 ---- web/app/components/workflow/store.ts | 5 ++++ web/service/strategy.ts | 10 +++++++ web/service/use-strategy.ts | 6 ++-- 14 files changed, 107 insertions(+), 35 deletions(-) delete mode 100644 web/app/components/workflow/nodes/agent/utils.ts create mode 100644 web/service/strategy.ts diff --git a/web/app/components/workflow/hooks/use-checklist.ts b/web/app/components/workflow/hooks/use-checklist.ts index 36201ddfef..a018ce7cfe 100644 --- a/web/app/components/workflow/hooks/use-checklist.ts +++ b/web/app/components/workflow/hooks/use-checklist.ts @@ -24,6 +24,7 @@ import { useNodesExtraData } from './use-nodes-data' import { useToastContext } from '@/app/components/base/toast' import { CollectionType } from '@/app/components/tools/types' import { useGetLanguage } from '@/context/i18n' +import type { AgentNodeType } from '../nodes/agent/types' export const useChecklist = (nodes: Node[], edges: Edge[]) => { const { t } = useTranslation() @@ -33,6 +34,7 @@ export const useChecklist = (nodes: Node[], edges: Edge[]) => { const buildInTools = useStore(s => s.buildInTools) const customTools = useStore(s => s.customTools) const workflowTools = useStore(s => s.workflowTools) + const agentStrategies = useStore(s => s.agentStrategies) const needWarningNodes = useMemo(() => { const list = [] @@ -57,6 +59,17 @@ export const useChecklist = (nodes: Node[], edges: Edge[]) => { toolIcon = workflowTools.find(tool => tool.id === node.data.provider_id)?.icon } + if (node.data.type === BlockEnum.Agent) { + const data = node.data as AgentNodeType + const provider = agentStrategies.find(s => s.plugin_unique_identifier === data.plugin_unique_identifier) + const strategy = provider?.declaration.strategies.find(s => s.identity.name === data.agent_strategy_name) + // debugger + moreDataForCheckValid = { + provider, + strategy, + } + } + if (node.type === CUSTOM_NODE) { const { errorMessage } = nodesExtraData[node.data.type].checkValid(node.data, t, moreDataForCheckValid) @@ -92,7 +105,7 @@ export const useChecklist = (nodes: Node[], edges: Edge[]) => { } return list - }, [t, nodes, edges, nodesExtraData, buildInTools, customTools, workflowTools, language, isChatMode]) + }, [nodes, edges, isChatMode, buildInTools, customTools, workflowTools, language, nodesExtraData, t, agentStrategies]) return needWarningNodes } diff --git a/web/app/components/workflow/hooks/use-workflow.ts b/web/app/components/workflow/hooks/use-workflow.ts index 0f6ae59b6e..8ce31b8acf 100644 --- a/web/app/components/workflow/hooks/use-workflow.ts +++ b/web/app/components/workflow/hooks/use-workflow.ts @@ -58,6 +58,7 @@ import I18n from '@/context/i18n' import { CollectionType } from '@/app/components/tools/types' import { CUSTOM_ITERATION_START_NODE } from '@/app/components/workflow/nodes/iteration-start/constants' import { useWorkflowConfig } from '@/service/use-workflow' +import { fetchStrategyList } from '@/service/strategy' export const useIsChatMode = () => { const appDetail = useAppStore(s => s.appDetail) @@ -459,6 +460,21 @@ export const useFetchToolsData = () => { } } +export const useFetchAgentStrategy = () => { + const workflowStore = useWorkflowStore() + const handleFetchAllAgentStrategies = useCallback(async () => { + const agentStrategies = await fetchStrategyList() + + workflowStore.setState({ + agentStrategies: agentStrategies || [], + }) + }, [workflowStore]) + + return { + handleFetchAllAgentStrategies, + } +} + export const useWorkflowInit = () => { const workflowStore = useWorkflowStore() const { @@ -466,6 +482,7 @@ export const useWorkflowInit = () => { edges: edgesTemplate, } = useWorkflowTemplate() const { handleFetchAllTools } = useFetchToolsData() + const { handleFetchAllAgentStrategies } = useFetchAgentStrategy() const appDetail = useAppStore(state => state.appDetail)! const setSyncWorkflowDraftHash = useStore(s => s.setSyncWorkflowDraftHash) const [data, setData] = useState() @@ -545,7 +562,8 @@ export const useWorkflowInit = () => { handleFetchAllTools('builtin') handleFetchAllTools('custom') handleFetchAllTools('workflow') - }, [handleFetchPreloadData, handleFetchAllTools]) + handleFetchAllAgentStrategies() + }, [handleFetchPreloadData, handleFetchAllTools, handleFetchAllAgentStrategies]) useEffect(() => { if (data) { diff --git a/web/app/components/workflow/nodes/_base/components/agent-strategy-selector.tsx b/web/app/components/workflow/nodes/_base/components/agent-strategy-selector.tsx index 9a4944080b..1cf9fc23ef 100644 --- a/web/app/components/workflow/nodes/_base/components/agent-strategy-selector.tsx +++ b/web/app/components/workflow/nodes/_base/components/agent-strategy-selector.tsx @@ -1,5 +1,5 @@ import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem' -import { useMemo, useState } from 'react' +import { memo, useMemo, useState } from 'react' import type { Strategy } from './agent-strategy' import classNames from '@/utils/classnames' import { RiArrowDownSLine, RiArrowRightUpLine, RiErrorWarningFill } from '@remixicon/react' @@ -38,7 +38,7 @@ const ExternalNotInstallWarn = () => { function formatStrategy(input: StrategyPluginDetail[], getIcon: (i: string) => string): ToolWithProvider[] { return input.map((item) => { const res: ToolWithProvider = { - id: item.provider, + id: item.plugin_unique_identifier, author: item.declaration.identity.author, name: item.declaration.identity.name, description: item.declaration.identity.description as any, @@ -69,7 +69,7 @@ export type AgentStrategySelectorProps = { onChange: (value?: Strategy) => void, } -export const AgentStrategySelector = (props: AgentStrategySelectorProps) => { +export const AgentStrategySelector = memo((props: AgentStrategySelectorProps) => { const { value, onChange } = props const [open, setOpen] = useState(false) const [viewType, setViewType] = useState(ViewType.flat) @@ -126,6 +126,7 @@ export const AgentStrategySelector = (props: AgentStrategySelectorProps) => { agent_strategy_provider_name: tool!.provider_name, agent_strategy_label: tool!.tool_label, agent_output_schema: tool!.output_schema, + plugin_unique_identifier: tool!.provider_id, }) setOpen(false) }} @@ -147,4 +148,6 @@ export const AgentStrategySelector = (props: AgentStrategySelectorProps) => { */} -} +}) + +AgentStrategySelector.displayName = 'AgentStrategySelector' 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 454c84833b..b92f4e9d7a 100644 --- a/web/app/components/workflow/nodes/_base/components/agent-strategy.tsx +++ b/web/app/components/workflow/nodes/_base/components/agent-strategy.tsx @@ -12,7 +12,7 @@ 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 { type ComponentProps, memo } from 'react' import { useDefaultModel, useLanguage } from '@/app/components/header/account-setting/model-provider-page/hooks' import Editor from './prompt/editor' import { useWorkflowStore } from '../../../store' @@ -22,6 +22,7 @@ export type Strategy = { agent_strategy_name: string agent_strategy_label: string agent_output_schema: Record + plugin_unique_identifier: string } export type AgentStrategyProps = { @@ -47,7 +48,7 @@ type StringSchema = CustomSchema<'string', { type CustomField = ToolSelectorSchema | MultipleToolSelectorSchema | StringSchema -export const AgentStrategy = (props: AgentStrategyProps) => { +export const AgentStrategy = memo((props: AgentStrategyProps) => { const { strategy, onStrategyChange, formSchema, formValue, onFormValueChange } = props const { t } = useTranslation() const language = useLanguage() @@ -197,4 +198,6 @@ export const AgentStrategy = (props: AgentStrategyProps) => { /> } -} +}) + +AgentStrategy.displayName = 'AgentStrategy' diff --git a/web/app/components/workflow/nodes/_base/components/setting-item.tsx b/web/app/components/workflow/nodes/_base/components/setting-item.tsx index fdaadc476f..ca074ffbb7 100644 --- a/web/app/components/workflow/nodes/_base/components/setting-item.tsx +++ b/web/app/components/workflow/nodes/_base/components/setting-item.tsx @@ -1,7 +1,7 @@ import Tooltip from '@/app/components/base/tooltip' import Indicator from '@/app/components/header/indicator' import classNames from '@/utils/classnames' -import type { ComponentProps, PropsWithChildren, ReactNode } from 'react' +import { type ComponentProps, type PropsWithChildren, type ReactNode, memo } from 'react' export type SettingItemProps = PropsWithChildren<{ label: string @@ -9,7 +9,7 @@ export type SettingItemProps = PropsWithChildren<{ tooltip?: ReactNode }> -export const SettingItem = ({ label, children, status, tooltip }: SettingItemProps) => { +export const SettingItem = memo(({ label, children, status, tooltip }: SettingItemProps) => { const indicator: ComponentProps['color'] = status === 'error' ? 'red' : status === 'warning' ? 'yellow' : undefined const needTooltip = ['error', 'warning'].includes(status as any) return
@@ -23,4 +23,6 @@ export const SettingItem = ({ label, children, status, tooltip }: SettingItemPro {indicator && }
-} +}) + +SettingItem.displayName = 'SettingItem' diff --git a/web/app/components/workflow/nodes/agent/components/tool-icon.tsx b/web/app/components/workflow/nodes/agent/components/tool-icon.tsx index 893472af5e..4228c5694d 100644 --- a/web/app/components/workflow/nodes/agent/components/tool-icon.tsx +++ b/web/app/components/workflow/nodes/agent/components/tool-icon.tsx @@ -1,7 +1,7 @@ import Tooltip from '@/app/components/base/tooltip' import Indicator from '@/app/components/header/indicator' import classNames from '@/utils/classnames' -import { useMemo, useRef } from 'react' +import { memo, useMemo, useRef } from 'react' import { useAllBuiltInTools, useAllCustomTools, useAllWorkflowTools } from '@/service/use-tools' export type ToolIconProps = { @@ -10,7 +10,7 @@ export type ToolIconProps = { providerName: string } -export const ToolIcon = ({ status, tooltip, providerName }: ToolIconProps) => { +export const ToolIcon = memo(({ status, tooltip, providerName }: ToolIconProps) => { const indicator = status === 'error' ? 'red' : status === 'warning' ? 'yellow' : undefined const containerRef = useRef(null) const notSuccess = (['error', 'warning'] as Array).includes(status) @@ -41,4 +41,6 @@ export const ToolIcon = ({ status, tooltip, providerName }: ToolIconProps) => { {indicator && } -} +}) + +ToolIcon.displayName = 'ToolIcon' diff --git a/web/app/components/workflow/nodes/agent/default.ts b/web/app/components/workflow/nodes/agent/default.ts index c748379cef..d7caba3b72 100644 --- a/web/app/components/workflow/nodes/agent/default.ts +++ b/web/app/components/workflow/nodes/agent/default.ts @@ -1,3 +1,4 @@ +import type { StrategyDetail, StrategyPluginDetail } from '@/app/components/plugins/types' import { ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS } from '../../constants' import type { NodeDefault } from '../../types' import type { AgentNodeType } from './types' @@ -15,16 +16,29 @@ const nodeDefault: NodeDefault = { ? ALL_CHAT_AVAILABLE_BLOCKS : ALL_COMPLETION_AVAILABLE_BLOCKS }, - checkValid(payload, t, moreDataForCheckValid) { - let isValid = true - let errorMessages = '' - if (payload.type) { - isValid = true - errorMessages = '' + checkValid(payload, t, moreDataForCheckValid: { + strategyProvider: StrategyPluginDetail | undefined, + strategy: StrategyDetail | undefined + }) { + const { strategy } = moreDataForCheckValid + if (!strategy) { + return { + isValid: false, + errorMessage: 'Please select a strategy', + } } + for (const param of strategy.parameters) { + if (param.required && !payload.agent_parameters?.[param.name]?.value) { + return { + isValid: false, + errorMessage: `Please select ${param.name}`, + } + } + } + // TODO: tool selector valid? return { - isValid, - errorMessage: errorMessages, + isValid: true, + errorMessage: '', } }, } diff --git a/web/app/components/workflow/nodes/agent/node.tsx b/web/app/components/workflow/nodes/agent/node.tsx index cef0a4330b..15580f625e 100644 --- a/web/app/components/workflow/nodes/agent/node.tsx +++ b/web/app/components/workflow/nodes/agent/node.tsx @@ -1,4 +1,4 @@ -import { type FC, useMemo } from 'react' +import { type FC, memo, useMemo } from 'react' import type { NodeProps } from '../../types' import type { AgentNodeType } from './types' import { SettingItem } from '../_base/components/setting-item' @@ -126,4 +126,6 @@ const AgentNode: FC> = (props) => { } -export default AgentNode +AgentNode.displayName = 'AgentNode' + +export default memo(AgentNode) diff --git a/web/app/components/workflow/nodes/agent/panel.tsx b/web/app/components/workflow/nodes/agent/panel.tsx index af4ce6c863..1843031d42 100644 --- a/web/app/components/workflow/nodes/agent/panel.tsx +++ b/web/app/components/workflow/nodes/agent/panel.tsx @@ -1,5 +1,5 @@ import type { FC } from 'react' -import { useMemo } from 'react' +import { memo, useMemo } from 'react' import type { NodePanelProps } from '../../types' import type { AgentNodeType } from './types' import Field from '../_base/components/field' @@ -75,6 +75,7 @@ const AgentPanel: FC> = (props) => { agent_strategy_name: inputs.agent_strategy_name!, agent_strategy_label: inputs.agent_strategy_label!, agent_output_schema: inputs.output_schema, + plugin_unique_identifier: inputs.plugin_unique_identifier!, } : undefined} onStrategyChange={(strategy) => { setInputs({ @@ -83,6 +84,7 @@ const AgentPanel: FC> = (props) => { agent_strategy_name: strategy?.agent_strategy_name, agent_strategy_label: strategy?.agent_strategy_label, output_schema: strategy!.agent_output_schema, + plugin_unique_identifier: strategy!.plugin_unique_identifier, }) }} formSchema={currentStrategy?.parameters?.map(strategyParamToCredientialForm) || []} @@ -135,4 +137,6 @@ const AgentPanel: FC> = (props) => { } -export default AgentPanel +AgentPanel.displayName = 'AgentPanel' + +export default memo(AgentPanel) diff --git a/web/app/components/workflow/nodes/agent/types.ts b/web/app/components/workflow/nodes/agent/types.ts index e75079ae8c..1b5c96364f 100644 --- a/web/app/components/workflow/nodes/agent/types.ts +++ b/web/app/components/workflow/nodes/agent/types.ts @@ -7,4 +7,5 @@ export type AgentNodeType = CommonNodeType & { agent_strategy_label?: string agent_parameters?: ToolVarInputs output_schema: Record + plugin_unique_identifier?: string } diff --git a/web/app/components/workflow/nodes/agent/utils.ts b/web/app/components/workflow/nodes/agent/utils.ts deleted file mode 100644 index 25beff3eb2..0000000000 --- a/web/app/components/workflow/nodes/agent/utils.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type { AgentNodeType } from './types' - -export const checkNodeValid = (payload: AgentNodeType) => { - return true -} diff --git a/web/app/components/workflow/store.ts b/web/app/components/workflow/store.ts index 6bd47eaa01..b05c6676c0 100644 --- a/web/app/components/workflow/store.ts +++ b/web/app/components/workflow/store.ts @@ -22,6 +22,9 @@ import type { } from './types' import { WorkflowContext } from './context' import type { NodeTracing, VersionHistory } from '@/types/workflow' +import type { + StrategyPluginDetail, +} from '@/app/components/plugins/types' // #TODO chatVar# // const MOCK_DATA = [ @@ -98,6 +101,7 @@ type Shape = { setCustomTools: (tools: ToolWithProvider[]) => void workflowTools: ToolWithProvider[] setWorkflowTools: (tools: ToolWithProvider[]) => void + agentStrategies: StrategyPluginDetail[], clipboardElements: Node[] setClipboardElements: (clipboardElements: Node[]) => void showDebugAndPreviewPanel: boolean @@ -230,6 +234,7 @@ export const createWorkflowStore = () => { setCustomTools: customTools => set(() => ({ customTools })), workflowTools: [], setWorkflowTools: workflowTools => set(() => ({ workflowTools })), + agentStrategies: [], clipboardElements: [], setClipboardElements: clipboardElements => set(() => ({ clipboardElements })), showDebugAndPreviewPanel: false, diff --git a/web/service/strategy.ts b/web/service/strategy.ts new file mode 100644 index 0000000000..bb032ba286 --- /dev/null +++ b/web/service/strategy.ts @@ -0,0 +1,10 @@ +import type { StrategyPluginDetail } from '@/app/components/plugins/types' +import { get } from './base' + +export const fetchStrategyList = () => { + return get('/workspaces/current/agent-providers') +} + +export const fetchStrategyDetail = (agentProvider: string) => { + return get(`/workspaces/current/agent-provider/${agentProvider}`) +} diff --git a/web/service/use-strategy.ts b/web/service/use-strategy.ts index cbc09509b3..49f852ebf5 100644 --- a/web/service/use-strategy.ts +++ b/web/service/use-strategy.ts @@ -1,4 +1,3 @@ -import { get } from './base' import type { StrategyPluginDetail, } from '@/app/components/plugins/types' @@ -6,6 +5,7 @@ import { useInvalid } from './use-base' import { useQuery, } from '@tanstack/react-query' +import { fetchStrategyDetail, fetchStrategyList } from './strategy' const NAME_SPACE = 'agent_strategy' @@ -13,7 +13,7 @@ const useStrategyListKey = [NAME_SPACE, 'strategyList'] export const useStrategyProviders = () => { return useQuery({ queryKey: useStrategyListKey, - queryFn: () => get('/workspaces/current/agent-providers'), + queryFn: fetchStrategyList, }) } @@ -24,7 +24,7 @@ export const useInvalidateStrategyProviders = () => { export const useStrategyProviderDetail = (agentProvider: string) => { return useQuery({ queryKey: [NAME_SPACE, 'detail', agentProvider], - queryFn: () => get(`/workspaces/current/agent-provider/${agentProvider}`), + queryFn: () => fetchStrategyDetail(agentProvider), enabled: !!agentProvider, }) } From e112357e9133907fa6cb10324ed7c41a250b8dc7 Mon Sep 17 00:00:00 2001 From: Joel Date: Thu, 2 Jan 2025 11:00:03 +0800 Subject: [PATCH 02/12] chore: temp --- .../utils/format-log/simple-graph-to-log-struct.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 web/app/components/workflow/run/utils/format-log/simple-graph-to-log-struct.ts diff --git a/web/app/components/workflow/run/utils/format-log/simple-graph-to-log-struct.ts b/web/app/components/workflow/run/utils/format-log/simple-graph-to-log-struct.ts new file mode 100644 index 0000000000..4aea146a7f --- /dev/null +++ b/web/app/components/workflow/run/utils/format-log/simple-graph-to-log-struct.ts @@ -0,0 +1,14 @@ +const STEP_SPLIT = '->' + +/* +* : 1 -> 2 -> 3 +* iteration: (iteration, 1, [2, 3]) -> 4. (1, [2, 3]) means 1 is parent, [2, 3] is children +* parallel: 1 -> (parallel, [1,2,3], [4, (parallel: (6,7))]). +* retry: (retry, 1, [2,3]). 1 is parent, [2, 3] is retry nodes +*/ +const simpleGraphToLogStruct = (input: string): any[] => { + const list = input.split(STEP_SPLIT) + return list +} + +export default simpleGraphToLogStruct From f11ea5ae97635add7654749fc65fdfd888ffa8f3 Mon Sep 17 00:00:00 2001 From: Joel Date: Thu, 2 Jan 2025 11:37:17 +0800 Subject: [PATCH 03/12] fix: title not show all if space is enough --- web/app/components/plugins/card/base/title.tsx | 2 +- web/app/components/plugins/plugin-item/index.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/web/app/components/plugins/card/base/title.tsx b/web/app/components/plugins/card/base/title.tsx index bfdcd7fc2b..383e7b31c1 100644 --- a/web/app/components/plugins/card/base/title.tsx +++ b/web/app/components/plugins/card/base/title.tsx @@ -4,7 +4,7 @@ const Title = ({ title: string }) => { return ( -
+
{title}
) diff --git a/web/app/components/plugins/plugin-item/index.tsx b/web/app/components/plugins/plugin-item/index.tsx index 430ceae7de..d997299844 100644 --- a/web/app/components/plugins/plugin-item/index.tsx +++ b/web/app/components/plugins/plugin-item/index.tsx @@ -94,7 +94,7 @@ const PluginItem: FC = ({
{verified && <RiVerifiedBadgeLine className="shrink-0 ml-0.5 w-4 h-4 text-text-accent" />} - <Badge className='ml-1' text={source === PluginSource.github ? plugin.meta!.version : plugin.version} /> + <Badge className='shrink-0 ml-1' text={source === PluginSource.github ? plugin.meta!.version : plugin.version} /> </div> <div className='flex items-center justify-between'> <Description text={description[locale]} descriptionLineRows={1}></Description> From c1ae681b6c67073ca1e68e53dcd5ffefac6c05f7 Mon Sep 17 00:00:00 2001 From: AkaraChen <akarachen@outlook.com> Date: Thu, 2 Jan 2025 11:46:47 +0800 Subject: [PATCH 04/12] feat: agent checklist i18n --- web/app/components/workflow/hooks/use-checklist.ts | 1 + web/app/components/workflow/nodes/agent/default.ts | 7 ++++--- web/i18n/en-US/workflow.ts | 3 +++ web/i18n/zh-Hans/workflow.ts | 3 +++ 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/web/app/components/workflow/hooks/use-checklist.ts b/web/app/components/workflow/hooks/use-checklist.ts index a018ce7cfe..9646b0da87 100644 --- a/web/app/components/workflow/hooks/use-checklist.ts +++ b/web/app/components/workflow/hooks/use-checklist.ts @@ -67,6 +67,7 @@ export const useChecklist = (nodes: Node[], edges: Edge[]) => { moreDataForCheckValid = { provider, strategy, + language, } } diff --git a/web/app/components/workflow/nodes/agent/default.ts b/web/app/components/workflow/nodes/agent/default.ts index d7caba3b72..3de738ee0a 100644 --- a/web/app/components/workflow/nodes/agent/default.ts +++ b/web/app/components/workflow/nodes/agent/default.ts @@ -19,19 +19,20 @@ const nodeDefault: NodeDefault<AgentNodeType> = { checkValid(payload, t, moreDataForCheckValid: { strategyProvider: StrategyPluginDetail | undefined, strategy: StrategyDetail | undefined + language: string }) { - const { strategy } = moreDataForCheckValid + const { strategy, language } = moreDataForCheckValid if (!strategy) { return { isValid: false, - errorMessage: 'Please select a strategy', + errorMessage: t('workflow.checkList.strategyNotSelected'), } } for (const param of strategy.parameters) { if (param.required && !payload.agent_parameters?.[param.name]?.value) { return { isValid: false, - errorMessage: `Please select ${param.name}`, + errorMessage: t('workflow.errorMsg.fieldRequired', { field: param.label[language] }), } } } diff --git a/web/i18n/en-US/workflow.ts b/web/i18n/en-US/workflow.ts index 5b5df3843e..583d30f2c1 100644 --- a/web/i18n/en-US/workflow.ts +++ b/web/i18n/en-US/workflow.ts @@ -747,6 +747,9 @@ const translation = { json: 'agent generated json', }, }, + checkList: { + strategyNotSelected: 'Strategy not selected', + }, }, tracing: { stopBy: 'Stop by {{user}}', diff --git a/web/i18n/zh-Hans/workflow.ts b/web/i18n/zh-Hans/workflow.ts index a86c746b3e..57b53d0644 100644 --- a/web/i18n/zh-Hans/workflow.ts +++ b/web/i18n/zh-Hans/workflow.ts @@ -746,6 +746,9 @@ const translation = { }, json: 'agent 生成的json', }, + checkList: { + strategyNotSelected: '未选择策略', + }, }, }, tracing: { From c6c388fbdac2bb457a051011f035f8b4e1b3d725 Mon Sep 17 00:00:00 2001 From: AkaraChen <akarachen@outlook.com> Date: Thu, 2 Jan 2025 13:58:30 +0800 Subject: [PATCH 05/12] feat: agent checklist i18n --- .../nodes/_base/components/agent-strategy.tsx | 17 +++++++++-------- .../components/workflow/nodes/agent/default.ts | 4 ++-- web/hooks/use-i18n.ts | 14 ++++++++++++++ 3 files changed, 25 insertions(+), 10 deletions(-) create mode 100644 web/hooks/use-i18n.ts 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 b92f4e9d7a..01aed3728b 100644 --- a/web/app/components/workflow/nodes/_base/components/agent-strategy.tsx +++ b/web/app/components/workflow/nodes/_base/components/agent-strategy.tsx @@ -13,9 +13,10 @@ import ToolSelector from '@/app/components/plugins/plugin-detail-panel/tool-sele import MultipleToolSelector from '@/app/components/plugins/plugin-detail-panel/multiple-tool-selector' import Field from './field' import { type ComponentProps, memo } from 'react' -import { useDefaultModel, useLanguage } from '@/app/components/header/account-setting/model-provider-page/hooks' +import { useDefaultModel } from '@/app/components/header/account-setting/model-provider-page/hooks' import Editor from './prompt/editor' import { useWorkflowStore } from '../../../store' +import { useRenderI18nObject } from '@/hooks/use-i18n' export type Strategy = { agent_strategy_provider_name: string @@ -51,8 +52,8 @@ type CustomField = ToolSelectorSchema | MultipleToolSelectorSchema | StringSchem export const AgentStrategy = memo((props: AgentStrategyProps) => { const { strategy, onStrategyChange, formSchema, formValue, onFormValueChange } = props const { t } = useTranslation() - const language = useLanguage() const defaultModel = useDefaultModel(ModelTypeEnum.textGeneration) + const renderI18nObject = useRenderI18nObject() const workflowStore = useWorkflowStore() const { setControlPromptEditorRerenderKey, @@ -71,7 +72,7 @@ export const AgentStrategy = memo((props: AgentStrategyProps) => { const onChange = (value: number) => { props.onChange({ ...props.value, [schema.variable]: value }) } - return <Field title={def.label[language]} tooltip={def.tooltip?.[language]} inline> + return <Field title={renderI18nObject(def.label)} tooltip={def.tooltip && renderI18nObject(def.tooltip)} inline> <div className='flex w-[200px] items-center gap-3'> <Slider value={value} @@ -104,7 +105,7 @@ export const AgentStrategy = memo((props: AgentStrategyProps) => { props.onChange({ ...props.value, [schema.variable]: value }) } return ( - <Field title={schema.label[language]} tooltip={schema.tooltip?.[language]}> + <Field title={renderI18nObject(schema.label)} tooltip={schema.tooltip && renderI18nObject(schema.tooltip)}> <ToolSelector scope={schema.scope} value={value} @@ -123,8 +124,8 @@ export const AgentStrategy = memo((props: AgentStrategyProps) => { <MultipleToolSelector scope={schema.scope} value={value || []} - label={schema.label[language]} - tooltip={schema.tooltip?.[language]} + label={renderI18nObject(schema.label)} + tooltip={schema.tooltip && renderI18nObject(schema.tooltip)} onChange={onChange} supportCollapse /> @@ -143,12 +144,12 @@ export const AgentStrategy = memo((props: AgentStrategyProps) => { value={value} onChange={onChange} onGenerated={handleGenerated} - title={schema.label[language]} + title={renderI18nObject(schema.label)} headerClassName='bg-transparent px-0 text-text-secondary system-sm-semibold-uppercase' containerClassName='bg-transparent' gradientBorder={false} isSupportPromptGenerator={!!schema.auto_generate?.type} - titleTooltip={schema.tooltip?.[language]} + titleTooltip={schema.tooltip && renderI18nObject(schema.tooltip)} editorContainerClassName='px-0' isSupportJinja={schema.template?.enabled} varList={[]} diff --git a/web/app/components/workflow/nodes/agent/default.ts b/web/app/components/workflow/nodes/agent/default.ts index 3de738ee0a..da1cba4adc 100644 --- a/web/app/components/workflow/nodes/agent/default.ts +++ b/web/app/components/workflow/nodes/agent/default.ts @@ -2,6 +2,7 @@ import type { StrategyDetail, StrategyPluginDetail } from '@/app/components/plug import { ALL_CHAT_AVAILABLE_BLOCKS, ALL_COMPLETION_AVAILABLE_BLOCKS } from '../../constants' import type { NodeDefault } from '../../types' import type { AgentNodeType } from './types' +import { renderI18nObject } from '@/hooks/use-i18n' const nodeDefault: NodeDefault<AgentNodeType> = { defaultValue: { @@ -32,11 +33,10 @@ const nodeDefault: NodeDefault<AgentNodeType> = { if (param.required && !payload.agent_parameters?.[param.name]?.value) { return { isValid: false, - errorMessage: t('workflow.errorMsg.fieldRequired', { field: param.label[language] }), + errorMessage: t('workflow.errorMsg.fieldRequired', { field: renderI18nObject(param.label, language) }), } } } - // TODO: tool selector valid? return { isValid: true, errorMessage: '', diff --git a/web/hooks/use-i18n.ts b/web/hooks/use-i18n.ts new file mode 100644 index 0000000000..261293c86d --- /dev/null +++ b/web/hooks/use-i18n.ts @@ -0,0 +1,14 @@ +import { useLanguage } from '@/app/components/header/account-setting/model-provider-page/hooks' + +export const renderI18nObject = (obj: Record<string, string>, language: string) => { + if (obj?.[language]) return obj[language] + if (obj?.en_US) return obj.en_US + return Object.values(obj)[0] +} + +export const useRenderI18nObject = () => { + const language = useLanguage() + return (obj: Record<string, string>) => { + return renderI18nObject(obj, language) + } +} From 55aad3718da65c5d39f1a4e5d9c9414985db705d Mon Sep 17 00:00:00 2001 From: Joel <iamjoel007@gmail.com> Date: Thu, 2 Jan 2025 14:09:35 +0800 Subject: [PATCH 06/12] fix: multi loop nodes remove children error --- .../run/utils/format-log/agent/data.ts | 12 ++++---- .../run/utils/format-log/agent/index.ts | 30 ++++++++++--------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/web/app/components/workflow/run/utils/format-log/agent/data.ts b/web/app/components/workflow/run/utils/format-log/agent/data.ts index d64670a015..a1e06bf63b 100644 --- a/web/app/components/workflow/run/utils/format-log/agent/data.ts +++ b/web/app/components/workflow/run/utils/format-log/agent/data.ts @@ -1,5 +1,4 @@ import { BlockEnum } from '@/app/components/workflow/types' -import { has } from 'immer/dist/internal' export const agentNodeData = (() => { const node = { @@ -120,7 +119,6 @@ export const oneStepCircle = (() => { ], }], } - })() export const multiStepsCircle = (() => { @@ -138,13 +136,13 @@ export const multiStepsCircle = (() => { { id: '1', parent_id: '4', label: 'Node 1' }, { id: '2', parent_id: '1', label: 'Node 2' }, { id: '4', parent_id: '2', label: 'Node 4' }, - // { id: '1', parent_id: '4', label: 'Node 1' }, - // { id: '2', parent_id: '1', label: 'Node 2' }, - // { id: '4', parent_id: '2', label: 'Node 4' }, + { id: '1', parent_id: '4', label: 'Node 1' }, + { id: '2', parent_id: '1', label: 'Node 2' }, + { id: '4', parent_id: '2', label: 'Node 4' }, ], }, } - + // 1 -> [2(4(1(2(4...)))), 3] return { in: [node], expect: [{ @@ -165,7 +163,7 @@ export const multiStepsCircle = (() => { label: 'Node 4', children: [], hasCircle: true, - } + }, ], }, { 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 65c7f6d36e..c1f3afc20a 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 @@ -5,24 +5,26 @@ import { cloneDeep } from 'lodash-es' const supportedAgentLogNodes = [BlockEnum.Agent, BlockEnum.Tool] const remove = (node: AgentLogItemWithChildren, removeId: string) => { - const { children } = node - if (!children || children.length === 0) { + let { children } = node + if (!children || children.length === 0) return + + const hasCircle = !!children.find(c => c.id === removeId) + if (hasCircle) { + node.hasCircle = true + node.children = node.children.filter(c => c.id !== removeId) + children = node.children } - children.forEach((child, index) => { - if (child.id === removeId) { - node.hasCircle = true - children.splice(index, 1) - return - } + + children.forEach((child) => { remove(child, removeId) }) } const removeRepeatedSiblings = (list: AgentLogItemWithChildren[]) => { - if (!list || list.length === 0) { + if (!list || list.length === 0) return [] - } + const result: AgentLogItemWithChildren[] = [] const addedItemIds: string[] = [] list.forEach((item) => { @@ -35,19 +37,18 @@ const removeRepeatedSiblings = (list: AgentLogItemWithChildren[]) => { } const removeCircleLogItem = (log: AgentLogItemWithChildren) => { - let newLog = cloneDeep(log) + const newLog = cloneDeep(log) newLog.children = removeRepeatedSiblings(newLog.children) let { id, children } = newLog - if (!children || children.length === 0) { + if (!children || children.length === 0) return log - } + // check one step circle const hasOneStepCircle = !!children.find(c => c.id === id) if (hasOneStepCircle) { newLog.hasCircle = true newLog.children = newLog.children.filter(c => c.id !== id) children = newLog.children - } children.forEach((child, index) => { @@ -85,6 +86,7 @@ const format = (list: NodeTracing[]): NodeTracing[] => { let removedCircleTree: AgentLogItemWithChildren[] = [] if (supportedAgentLogNodes.includes(item.node_type) && item.execution_metadata?.agent_log && item.execution_metadata?.agent_log.length > 0) treeList = listToTree(item.execution_metadata.agent_log) + // console.log(JSON.stringify(treeList)) removedCircleTree = treeList.length > 0 ? treeList.map(t => removeCircleLogItem(t)) : [] item.agentLog = removedCircleTree From c469da20205a7245ab39eadfa5301d1239f0d56c Mon Sep 17 00:00:00 2001 From: Joel <iamjoel007@gmail.com> Date: Thu, 2 Jan 2025 14:22:04 +0800 Subject: [PATCH 07/12] fix: handle install title and descript may caused i18n problem --- web/app/components/plugins/card/index.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web/app/components/plugins/card/index.tsx b/web/app/components/plugins/card/index.tsx index 235f4d4953..ff86a3c39c 100644 --- a/web/app/components/plugins/card/index.tsx +++ b/web/app/components/plugins/card/index.tsx @@ -12,6 +12,7 @@ import cn from '@/utils/classnames' import { useGetLanguage } from '@/context/i18n' import { getLanguage } from '@/i18n/language' import { useCategories } from '../hooks' +import { renderI18nObject } from '@/hooks/use-i18n' export type Props = { className?: string @@ -47,7 +48,7 @@ const Card = ({ const isBundle = !['plugin', 'model', 'tool', 'extension', 'agent_strategy'].includes(type) const cornerMark = isBundle ? categoriesMap.bundle?.label : categoriesMap[category]?.label const getLocalizedText = (obj: Record<string, string> | undefined) => - obj?.[locale] || obj?.['en-US'] || obj?.en_US || '' + obj ? renderI18nObject(obj, locale) : '' const wrapClassName = cn('relative p-4 pb-3 border-[0.5px] border-components-panel-border bg-components-panel-on-panel-item-bg hover-bg-components-panel-on-panel-item-bg rounded-xl shadow-xs', className) if (isLoading) { From add6dff7897aced65f2a39861566b32755148d3c Mon Sep 17 00:00:00 2001 From: AkaraChen <akarachen@outlook.com> Date: Thu, 2 Jan 2025 14:27:19 +0800 Subject: [PATCH 08/12] feat: agent node check install strategy --- web/app/components/workflow/nodes/agent/node.tsx | 15 ++++++++++++--- .../components/workflow/nodes/agent/use-config.ts | 10 ++++++++-- web/i18n/en-US/workflow.ts | 1 + web/i18n/zh-Hans/workflow.ts | 1 + 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/web/app/components/workflow/nodes/agent/node.tsx b/web/app/components/workflow/nodes/agent/node.tsx index 15580f625e..2cf9c67233 100644 --- a/web/app/components/workflow/nodes/agent/node.tsx +++ b/web/app/components/workflow/nodes/agent/node.tsx @@ -10,6 +10,7 @@ import useConfig from './use-config' import { useTranslation } from 'react-i18next' import { FormTypeEnum, ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations' import { useModelList } from '@/app/components/header/account-setting/model-provider-page/hooks' +import { useRenderI18nObject } from '@/hooks/use-i18n' const useAllModel = () => { const { data: textGeneration } = useModelList(ModelTypeEnum.textGeneration) @@ -32,7 +33,8 @@ const useAllModel = () => { } const AgentNode: FC<NodeProps<AgentNodeType>> = (props) => { - const { inputs, currentStrategy } = useConfig(props.id, props.data) + const { inputs, currentStrategy, currentStrategyStatus, pluginDetail } = useConfig(props.id, props.data) + const renderI18nObject = useRenderI18nObject() const { t } = useTranslation() const modelList = useAllModel() const models = useMemo(() => { @@ -87,9 +89,16 @@ const AgentNode: FC<NodeProps<AgentNodeType>> = (props) => { {inputs.agent_strategy_name ? <SettingItem label={t('workflow.nodes.agent.strategy.shortLabel')} - status='error' - tooltip={t('workflow.nodes.agent.strategyNotInstallTooltip', { + status={ + ['plugin-not-found', 'strategy-not-found'].includes(currentStrategyStatus) + ? 'error' + : undefined + } + tooltip={t(`workflow.nodes.agent.${currentStrategyStatus === 'plugin-not-found' ? 'strategyNotInstallTooltip' : 'strategyNotFoundInPlugin'}`, { strategy: inputs.agent_strategy_label, + plugin: pluginDetail?.declaration.label + ? renderI18nObject(pluginDetail?.declaration.label) + : undefined, })} > {inputs.agent_strategy_label} diff --git a/web/app/components/workflow/nodes/agent/use-config.ts b/web/app/components/workflow/nodes/agent/use-config.ts index a1f96e33a2..e880b90e1c 100644 --- a/web/app/components/workflow/nodes/agent/use-config.ts +++ b/web/app/components/workflow/nodes/agent/use-config.ts @@ -8,6 +8,7 @@ import { } from '@/app/components/workflow/hooks' import { useMemo } from 'react' import { type ToolVarInputs, VarType } from '../tool/types' +import { useCheckInstalled } from '@/service/use-plugins' const useConfig = (id: string, payload: AgentNodeType) => { const { nodesReadOnly: readOnly } = useNodesReadOnly() @@ -20,16 +21,20 @@ const useConfig = (id: string, payload: AgentNodeType) => { const strategyProvider = useStrategyProviderDetail( inputs.agent_strategy_provider_name || '', ) - const currentStrategy = strategyProvider.data?.declaration.strategies.find( str => str.identity.name === inputs.agent_strategy_name, ) - const currentStrategyStatus = useMemo(() => { + const currentStrategyStatus: 'loading' | 'plugin-not-found' | 'strategy-not-found' | 'success' = useMemo(() => { if (strategyProvider.isLoading) return 'loading' if (strategyProvider.isError) return 'plugin-not-found' if (!currentStrategy) return 'strategy-not-found' return 'success' }, [currentStrategy, strategyProvider]) + const pluginId = inputs.agent_strategy_provider_name?.split('/').splice(0, 2).join('/') + const pluginDetail = useCheckInstalled({ + pluginIds: [pluginId || ''], + enabled: Boolean(pluginId), + }) const formData = useMemo(() => { return Object.fromEntries( Object.entries(inputs.agent_parameters || {}).map(([key, value]) => { @@ -91,6 +96,7 @@ const useConfig = (id: string, payload: AgentNodeType) => { onFormChange, currentStrategyStatus, strategyProvider: strategyProvider.data, + pluginDetail: pluginDetail.data?.plugins.at(0), isShowSingleRun, showSingleRun, diff --git a/web/i18n/en-US/workflow.ts b/web/i18n/en-US/workflow.ts index 583d30f2c1..4b8d2e1452 100644 --- a/web/i18n/en-US/workflow.ts +++ b/web/i18n/en-US/workflow.ts @@ -732,6 +732,7 @@ const translation = { toolNotInstallTooltip: '{{tool}} is not installed', toolNotAuthorizedTooltip: '{{tool}} Not Authorized', strategyNotInstallTooltip: '{{strategy}} is not installed', + strategyNotFoundInPlugin: '{{strategy}} is not found in {{plugin}}', modelSelectorTooltips: { deprecated: 'This model is deprecated', }, diff --git a/web/i18n/zh-Hans/workflow.ts b/web/i18n/zh-Hans/workflow.ts index 57b53d0644..635d9cf3ce 100644 --- a/web/i18n/zh-Hans/workflow.ts +++ b/web/i18n/zh-Hans/workflow.ts @@ -732,6 +732,7 @@ const translation = { toolNotInstallTooltip: '{{tool}} 未安装', toolNotAuthorizedTooltip: '{{tool}} 未授权', strategyNotInstallTooltip: '{{strategy}} 未安装', + strategyNotFoundInPlugin: '在 {{plugin}} 中未找到 {{strategy}}', modelSelectorTooltips: { deprecated: '此模型已弃用', }, From 0ed4ec5cd0f7483b4e6bfc3e977bfb8268ff5d05 Mon Sep 17 00:00:00 2001 From: AkaraChen <akarachen@outlook.com> Date: Thu, 2 Jan 2025 14:48:40 +0800 Subject: [PATCH 09/12] fix: agent strategy selector show workflow --- web/app/components/workflow/block-selector/index-bar.tsx | 5 ++++- .../block-selector/tool/tool-list-tree-view/list.tsx | 5 ++++- web/app/components/workflow/block-selector/tools.tsx | 1 - web/i18n/en-US/workflow.ts | 1 + web/i18n/zh-Hans/workflow.ts | 1 + 5 files changed, 10 insertions(+), 3 deletions(-) diff --git a/web/app/components/workflow/block-selector/index-bar.tsx b/web/app/components/workflow/block-selector/index-bar.tsx index 3c5bf8d6e2..8d4b3de10e 100644 --- a/web/app/components/workflow/block-selector/index-bar.tsx +++ b/web/app/components/workflow/block-selector/index-bar.tsx @@ -6,6 +6,7 @@ import classNames from '@/utils/classnames' export const CUSTOM_GROUP_NAME = '@@@custom@@@' export const WORKFLOW_GROUP_NAME = '@@@workflow@@@' +export const AGENT_GROUP_NAME = '@@@agent@@@' /* { A: { @@ -46,8 +47,10 @@ export const groupItems = (items: ToolWithProvider[], getFirstChar: (item: ToolW groupName = item.author else if (item.type === CollectionType.custom) groupName = CUSTOM_GROUP_NAME - else + else if (item.type === CollectionType.workflow) groupName = WORKFLOW_GROUP_NAME + else + groupName = AGENT_GROUP_NAME if (!acc[letter][groupName]) acc[letter][groupName] = [] diff --git a/web/app/components/workflow/block-selector/tool/tool-list-tree-view/list.tsx b/web/app/components/workflow/block-selector/tool/tool-list-tree-view/list.tsx index 8bf5095833..a8fd34b98a 100644 --- a/web/app/components/workflow/block-selector/tool/tool-list-tree-view/list.tsx +++ b/web/app/components/workflow/block-selector/tool/tool-list-tree-view/list.tsx @@ -6,7 +6,7 @@ import type { BlockEnum } from '../../../types' import type { ToolDefaultValue } from '../../types' import Item from './item' import { useTranslation } from 'react-i18next' -import { CUSTOM_GROUP_NAME, WORKFLOW_GROUP_NAME } from '../../index-bar' +import { AGENT_GROUP_NAME, CUSTOM_GROUP_NAME, WORKFLOW_GROUP_NAME } from '../../index-bar' type Props = { payload: Record<string, ToolWithProvider[]> @@ -27,6 +27,9 @@ const ToolListTreeView: FC<Props> = ({ if (name === WORKFLOW_GROUP_NAME) return t('workflow.tabs.workflowTool') + if (name === AGENT_GROUP_NAME) + return t('workflow.tabs.agent') + return name }, [t]) diff --git a/web/app/components/workflow/block-selector/tools.tsx b/web/app/components/workflow/block-selector/tools.tsx index 060f6dfa2c..5b5d1da20b 100644 --- a/web/app/components/workflow/block-selector/tools.tsx +++ b/web/app/components/workflow/block-selector/tools.tsx @@ -60,7 +60,6 @@ const Blocks = ({ Object.keys(withLetterAndGroupViewToolsData[letter]).forEach((groupName) => { if (!result[groupName]) result[groupName] = [] - result[groupName].push(...withLetterAndGroupViewToolsData[letter][groupName]) }) }) diff --git a/web/i18n/en-US/workflow.ts b/web/i18n/en-US/workflow.ts index 4b8d2e1452..c2f9685036 100644 --- a/web/i18n/en-US/workflow.ts +++ b/web/i18n/en-US/workflow.ts @@ -218,6 +218,7 @@ const translation = { 'transform': 'Transform', 'utilities': 'Utilities', 'noResult': 'No match found', + 'agent': 'Agent Strategy', }, blocks: { 'start': 'Start', diff --git a/web/i18n/zh-Hans/workflow.ts b/web/i18n/zh-Hans/workflow.ts index 635d9cf3ce..c72e97b588 100644 --- a/web/i18n/zh-Hans/workflow.ts +++ b/web/i18n/zh-Hans/workflow.ts @@ -218,6 +218,7 @@ const translation = { 'transform': '转换', 'utilities': '工具', 'noResult': '未找到匹配项', + 'agent': 'Agent 策略', }, blocks: { 'start': '开始', From a432fcfd5e8492eea8918983843253d54f951467 Mon Sep 17 00:00:00 2001 From: zxhlyh <jasonapring2015@outlook.com> Date: Thu, 2 Jan 2025 14:55:42 +0800 Subject: [PATCH 10/12] agent node single run --- web/app/components/workflow/nodes/agent/use-config.ts | 4 +++- web/app/components/workflow/utils.ts | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/web/app/components/workflow/nodes/agent/use-config.ts b/web/app/components/workflow/nodes/agent/use-config.ts index e880b90e1c..95f7bdca98 100644 --- a/web/app/components/workflow/nodes/agent/use-config.ts +++ b/web/app/components/workflow/nodes/agent/use-config.ts @@ -75,7 +75,9 @@ const useConfig = (id: string, payload: AgentNodeType) => { defaultRunInputData: {}, }) const allVarStrArr = (() => { - const arr = [''] + const arr = currentStrategy?.parameters.filter(item => item.type === 'string').map((item) => { + return formData[item.name] + }) || [] return arr })() diff --git a/web/app/components/workflow/utils.ts b/web/app/components/workflow/utils.ts index 46ac4ce1c6..bdf096491e 100644 --- a/web/app/components/workflow/utils.ts +++ b/web/app/components/workflow/utils.ts @@ -395,6 +395,7 @@ export const canRunBySingle = (nodeType: BlockEnum) => { || nodeType === BlockEnum.Tool || nodeType === BlockEnum.ParameterExtractor || nodeType === BlockEnum.Iteration + || nodeType === BlockEnum.Agent } type ConnectedSourceOrTargetNodesChange = { From 336b26569b8b693087d76fff90e420260829d131 Mon Sep 17 00:00:00 2001 From: AkaraChen <akarachen@outlook.com> Date: Thu, 2 Jan 2025 15:03:18 +0800 Subject: [PATCH 11/12] feat: agent form string type support var --- .../nodes/_base/components/agent-strategy.tsx | 8 ++++- .../components/workflow/nodes/agent/panel.tsx | 5 +++ .../workflow/nodes/agent/use-config.ts | 31 ++++++++++++++++++- 3 files changed, 42 insertions(+), 2 deletions(-) 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 01aed3728b..4ec46a6d61 100644 --- a/web/app/components/workflow/nodes/_base/components/agent-strategy.tsx +++ b/web/app/components/workflow/nodes/_base/components/agent-strategy.tsx @@ -17,6 +17,8 @@ import { useDefaultModel } from '@/app/components/header/account-setting/model-p import Editor from './prompt/editor' import { useWorkflowStore } from '../../../store' import { useRenderI18nObject } from '@/hooks/use-i18n' +import type { NodeOutPutVar } from '../../../types' +import type { Node } from 'reactflow' export type Strategy = { agent_strategy_provider_name: string @@ -32,6 +34,8 @@ export type AgentStrategyProps = { formSchema: CredentialFormSchema[] formValue: ToolVarInputs onFormValueChange: (value: ToolVarInputs) => void + nodeOutputVars?: NodeOutPutVar[], + availableNodes?: Node[], } type CustomSchema<Type, Field = {}> = Omit<CredentialFormSchema, 'type'> & { type: Type } & Field @@ -50,7 +54,7 @@ type StringSchema = CustomSchema<'string', { type CustomField = ToolSelectorSchema | MultipleToolSelectorSchema | StringSchema export const AgentStrategy = memo((props: AgentStrategyProps) => { - const { strategy, onStrategyChange, formSchema, formValue, onFormValueChange } = props + const { strategy, onStrategyChange, formSchema, formValue, onFormValueChange, nodeOutputVars, availableNodes } = props const { t } = useTranslation() const defaultModel = useDefaultModel(ModelTypeEnum.textGeneration) const renderI18nObject = useRenderI18nObject() @@ -151,6 +155,8 @@ export const AgentStrategy = memo((props: AgentStrategyProps) => { isSupportPromptGenerator={!!schema.auto_generate?.type} titleTooltip={schema.tooltip && renderI18nObject(schema.tooltip)} editorContainerClassName='px-0' + availableNodes={availableNodes} + nodesOutputVars={nodeOutputVars} isSupportJinja={schema.template?.enabled} varList={[]} modelConfig={ diff --git a/web/app/components/workflow/nodes/agent/panel.tsx b/web/app/components/workflow/nodes/agent/panel.tsx index 1843031d42..ab8ff1c4b9 100644 --- a/web/app/components/workflow/nodes/agent/panel.tsx +++ b/web/app/components/workflow/nodes/agent/panel.tsx @@ -33,6 +33,9 @@ const AgentPanel: FC<NodePanelProps<AgentNodeType>> = (props) => { formData, onFormChange, + availableNodesWithParent, + availableVars, + isShowSingleRun, hideSingleRun, runningStatus, @@ -90,6 +93,8 @@ const AgentPanel: FC<NodePanelProps<AgentNodeType>> = (props) => { formSchema={currentStrategy?.parameters?.map(strategyParamToCredientialForm) || []} formValue={formData} onFormValueChange={onFormChange} + nodeOutputVars={availableVars} + availableNodes={availableNodesWithParent} /> </Field> <div> diff --git a/web/app/components/workflow/nodes/agent/use-config.ts b/web/app/components/workflow/nodes/agent/use-config.ts index e880b90e1c..0714309d18 100644 --- a/web/app/components/workflow/nodes/agent/use-config.ts +++ b/web/app/components/workflow/nodes/agent/use-config.ts @@ -6,9 +6,12 @@ import type { AgentNodeType } from './types' import { useNodesReadOnly, } from '@/app/components/workflow/hooks' -import { useMemo } from 'react' +import { useCallback, useMemo } from 'react' import { type ToolVarInputs, VarType } from '../tool/types' import { useCheckInstalled } from '@/service/use-plugins' +import type { Var } from '../../types' +import { VarType as VarKindType } from '../../types' +import useAvailableVarList from '../_base/hooks/use-available-var-list' const useConfig = (id: string, payload: AgentNodeType) => { const { nodesReadOnly: readOnly } = useNodesReadOnly() @@ -56,6 +59,30 @@ const useConfig = (id: string, payload: AgentNodeType) => { }) } + // vars + + const filterMemoryPromptVar = useCallback((varPayload: Var) => { + return [ + VarKindType.arrayObject, + VarKindType.array, + VarKindType.number, + VarKindType.string, + VarKindType.secret, + VarKindType.arrayString, + VarKindType.arrayNumber, + VarKindType.file, + VarKindType.arrayFile, + ].includes(varPayload.type) + }, []) + + const { + availableVars, + availableNodesWithParent, + } = useAvailableVarList(id, { + onlyLeafNodeVar: false, + filterVar: filterMemoryPromptVar, + }) + // single run const { isShowSingleRun, @@ -97,6 +124,8 @@ const useConfig = (id: string, payload: AgentNodeType) => { currentStrategyStatus, strategyProvider: strategyProvider.data, pluginDetail: pluginDetail.data?.plugins.at(0), + availableVars, + availableNodesWithParent, isShowSingleRun, showSingleRun, From a514bde4285cbcc8ecb2e56a3e979df76326a47a Mon Sep 17 00:00:00 2001 From: zxhlyh <jasonapring2015@outlook.com> Date: Thu, 2 Jan 2025 15:50:12 +0800 Subject: [PATCH 12/12] fix: marketplace page size --- web/service/use-plugins.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/service/use-plugins.ts b/web/service/use-plugins.ts index 5ad7d831d9..785e158261 100644 --- a/web/service/use-plugins.ts +++ b/web/service/use-plugins.ts @@ -300,7 +300,7 @@ export const useMutationPluginsFromMarketplace = () => { exclude, type, page = 1, - pageSize = 20, + pageSize = 40, } = pluginsSearchParams return postMarketplace<{ data: PluginsFromMarketplaceResponse }>('/plugins/search/basic', { body: {