diff --git a/web/app/components/workflow/block-selector/index-bar.tsx b/web/app/components/workflow/block-selector/index-bar.tsx index d932239bcb..3c5bf8d6e2 100644 --- a/web/app/components/workflow/block-selector/index-bar.tsx +++ b/web/app/components/workflow/block-selector/index-bar.tsx @@ -2,6 +2,7 @@ import { pinyin } from 'pinyin-pro' import type { FC, RefObject } from 'react' import type { ToolWithProvider } from '../types' import { CollectionType } from '../../tools/types' +import classNames from '@/utils/classnames' export const CUSTOM_GROUP_NAME = '@@@custom@@@' export const WORKFLOW_GROUP_NAME = '@@@workflow@@@' @@ -69,16 +70,17 @@ export const groupItems = (items: ToolWithProvider[], getFirstChar: (item: ToolW type IndexBarProps = { letters: string[] itemRefs: RefObject<{ [key: string]: HTMLElement | null }> + className?: string } -const IndexBar: FC = ({ letters, itemRefs }) => { +const IndexBar: FC = ({ letters, itemRefs, className }) => { const handleIndexClick = (letter: string) => { const element = itemRefs.current?.[letter] if (element) element.scrollIntoView({ behavior: 'smooth' }) } return ( -
+
{letters.map(letter => (
handleIndexClick(letter)}> diff --git a/web/app/components/workflow/block-selector/tools.tsx b/web/app/components/workflow/block-selector/tools.tsx index 244e3e6813..d15a499dc3 100644 --- a/web/app/components/workflow/block-selector/tools.tsx +++ b/web/app/components/workflow/block-selector/tools.tsx @@ -12,6 +12,7 @@ import Empty from '@/app/components/tools/add-tool-modal/empty' import { useGetLanguage } from '@/context/i18n' import ToolListTreeView from './tool/tool-list-tree-view/list' import ToolListFlatView from './tool/tool-list-flat-view/list' +import classNames from '@/utils/classnames' type ToolsProps = { showWorkflowEmpty: boolean @@ -19,6 +20,8 @@ type ToolsProps = { tools: ToolWithProvider[] viewType: ViewType hasSearchText: boolean + className?: string + indexBarClassName?: string } const Blocks = ({ showWorkflowEmpty, @@ -26,6 +29,8 @@ const Blocks = ({ tools, viewType, hasSearchText, + className, + indexBarClassName, }: ToolsProps) => { const { t } = useTranslation() const language = useGetLanguage() @@ -75,7 +80,7 @@ const Blocks = ({ const toolRefs = useRef({}) return ( -
+
{ !tools.length && !showWorkflowEmpty && (
{t('workflow.tabs.noResult')}
@@ -103,7 +108,7 @@ const Blocks = ({ ) )} - {isShowLetterIndex && } + {isShowLetterIndex && }
) } 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 e7dbfbf3d5..7baa6182ec 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 { useState } from 'react' +import { useMemo, useState } from 'react' import type { Strategy } from './agent-strategy' import classNames from '@/utils/classnames' import { RiArrowDownSLine, RiArrowRightUpLine, RiErrorWarningFill } from '@remixicon/react' @@ -7,10 +7,10 @@ import { useAllBuiltInTools } from '@/service/use-tools' import Tooltip from '@/app/components/base/tooltip' import Link from 'next/link' import { InstallPluginButton } from './install-plugin-button' -import SearchInput from '@/app/components/base/search-input' import ViewTypeSelect, { ViewType } from '../../../block-selector/view-type-select' -import Tools from '../../../block-selector/tools' +import SearchInput from '@/app/components/base/search-input' import { MARKETPLACE_URL_PREFIX } from '@/config' +import Tools from '../../../block-selector/tools' const ExternalNotInstallWarn = () => { // TODO: add i18n label @@ -40,18 +40,23 @@ export const AgentStrategySelector = (props: AgentStrategySelectorProps) => { const [open, setOpen] = useState(false) const list = useAllBuiltInTools() const [viewType, setViewType] = useState(ViewType.flat) + const [query, setQuery] = useState('') + const filteredTools = useMemo(() => { + if (!list.data) return [] + return list.data.filter(tool => tool.name.toLowerCase().includes(query.toLowerCase())) + }, [query, list.data]) // TODO: should be replaced by real data const isExternalInstalled = true return -
setOpen(true)}> +
setOpen(o => !o)}> {/* eslint-disable-next-line @next/next/no-img-element */} - {list.data && coll, )?.icon as string} - width={24} - height={24} + width={20} + height={20} className='rounded-md border-[0.5px] border-components-panel-border-subtle bg-background-default-dodge' alt='icon' />} @@ -60,21 +65,21 @@ export const AgentStrategySelector = (props: AgentStrategySelectorProps) => { > {value?.agent_strategy_name || 'Select agentic strategy'}

-
+ {value &&
e.stopPropagation()} size={'small'} /> {isExternalInstalled ? : } -
+
}
- -
+ +
- +
-
+
{ onChange({ @@ -86,16 +91,20 @@ export const AgentStrategySelector = (props: AgentStrategySelectorProps) => { }} hasSearchText={false} showWorkflowEmpty + className='max-w-none' + indexBarClassName='top-0 xl:top-36' /> -
+
Find more in - {/** //TODO: replace URL */} Marketplace
+ {/*
+ aaa +
*/}
} 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 0981f8b7d6..ee24ac3d6a 100644 --- a/web/app/components/workflow/nodes/_base/components/agent-strategy.tsx +++ b/web/app/components/workflow/nodes/_base/components/agent-strategy.tsx @@ -3,6 +3,8 @@ import type { ToolVarInputs } from '../../tool/types' import ListEmpty from '@/app/components/base/list-empty' import { AgentStrategySelector } from './agent-strategy-selector' import Link from 'next/link' +import { useTranslation } from 'react-i18next' +import InputVarList from '../../tool/components/input-var-list' export type Strategy = { agent_strategy_provider_name: string @@ -17,21 +19,36 @@ export type AgentStrategyProps = { formSchema: CredentialFormSchema[] formValue: ToolVarInputs onFormValueChange: (value: ToolVarInputs) => void + /** + * @description use for get available vars + */ + nodeId: string } export const AgentStrategy = (props: AgentStrategyProps) => { - const { strategy, onStrategyChange, formSchema, formValue, onFormValueChange } = props + const { strategy, onStrategyChange, formSchema, formValue, onFormValueChange, nodeId } = props + const { t } = useTranslation() return
{ strategy - ?
+ ?
+ +
// TODO: list empty need a icon : - After configuring the agentic strategy, this node will automatically load the remaining configurations. The strategy will affect the mechanism of multi-step tool reasoning.
- Learn more + {t('workflow.nodes.agent.strategy.configureTipDesc')}
+ + {t('workflow.nodes.agent.learnMore')} +
} /> } 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 865f445d38..9e6e86844c 100644 --- a/web/app/components/workflow/nodes/_base/components/setting-item.tsx +++ b/web/app/components/workflow/nodes/_base/components/setting-item.tsx @@ -1,19 +1,26 @@ +import Tooltip from '@/app/components/base/tooltip' import Indicator from '@/app/components/header/indicator' -import type { ComponentProps, PropsWithChildren } from 'react' +import classNames from '@/utils/classnames' +import type { ComponentProps, PropsWithChildren, ReactNode } from 'react' export type SettingItemProps = PropsWithChildren<{ label: string - indicator?: ComponentProps['color'] + status?: 'error' | 'warning' + tooltip?: ReactNode }> -export const SettingItem = ({ label, children, indicator }: SettingItemProps) => { - return
-
+export const SettingItem = ({ 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
+
{label}
-
- {children} -
+ +
+ {children} +
+
{indicator && }
} diff --git a/web/app/components/workflow/nodes/agent/node.tsx b/web/app/components/workflow/nodes/agent/node.tsx index 3dc61ddb41..dbc968de93 100644 --- a/web/app/components/workflow/nodes/agent/node.tsx +++ b/web/app/components/workflow/nodes/agent/node.tsx @@ -5,20 +5,21 @@ import { SettingItem } from '../_base/components/setting-item' import ModelSelector from '@/app/components/header/account-setting/model-provider-page/model-selector' import { Group, GroupLabel } from '../_base/components/group' import { ToolIcon } from './components/tool-icon' +import useConfig from './use-config' const AgentNode: FC> = (props) => { - const strategySelected = true + const { inputs } = useConfig(props.id, props.data) return
- {strategySelected - // TODO: add tooltip for this - ? - ReAct + {inputs.agent_strategy_name + ? + {inputs.agent_strategy_name} : } - + Model - }> + } + > > = (props) => { const { inputs, setInputs } = useNodeCrud(props.id, props.data) const [iter, setIter] = [inputs.max_iterations, (value: number) => { @@ -15,7 +267,7 @@ const AgentPanel: FC> = (props) => { max_iterations: value, }) }] - return <> + return
> = (props) => { agent_parameters: strategy?.agent_parameters, }) }} - formSchema={[]} - formValue={{}} - onFormValueChange={console.error} + formSchema={mockSchema as any} + formValue={inputs.agent_parameters || {}} + onFormValueChange={value => setInputs({ + ...inputs, + agent_parameters: value, + })} + nodeId={props.id} /> @@ -55,7 +311,7 @@ const AgentPanel: FC> = (props) => { />
- +
} export default AgentPanel diff --git a/web/i18n/en-US/workflow.ts b/web/i18n/en-US/workflow.ts index 8ead4696ce..d651f038c6 100644 --- a/web/i18n/en-US/workflow.ts +++ b/web/i18n/en-US/workflow.ts @@ -256,7 +256,7 @@ const translation = { 'parameter-extractor': 'Use LLM to extract structured parameters from natural language for tool invocations or HTTP requests.', 'document-extractor': 'Used to parse uploaded documents into text content that is easily understandable by LLM.', 'list-operator': 'Used to filter or sort array content.', - 'agent': 'TODO: add text here', + 'agent': 'Invoking large language models to answer questions or process natural language', }, operator: { zoomIn: 'Zoom In', @@ -697,6 +697,13 @@ const translation = { last_record: 'Last record', }, }, + agent: { + strategy: { + configureTip: 'Please configure agentic strategy.', + configureTipDesc: 'After configuring the agentic strategy, this node will automatically load the remaining configurations. The strategy will affect the mechanism of multi-step tool reasoning. ', + }, + learnMore: 'Learn more', + }, }, tracing: { stopBy: 'Stop by {{user}}', diff --git a/web/i18n/zh-Hans/workflow.ts b/web/i18n/zh-Hans/workflow.ts index 93276648e9..37e84d5ee6 100644 --- a/web/i18n/zh-Hans/workflow.ts +++ b/web/i18n/zh-Hans/workflow.ts @@ -256,7 +256,7 @@ const translation = { 'parameter-extractor': '利用 LLM 从自然语言内推理提取出结构化参数,用于后置的工具调用或 HTTP 请求。', 'document-extractor': '用于将用户上传的文档解析为 LLM 便于理解的文本内容。', 'list-operator': '用于过滤或排序数组内容。', - 'agent': 'TODO: Agent', + 'agent': '调用大型语言模型回答问题或处理自然语言', }, operator: { zoomIn: '放大', @@ -697,6 +697,13 @@ const translation = { last_record: '最后一条记录', }, }, + agent: { + strategy: { + configureTip: '请配置 Agent 策略。', + configureTipDesc: '配置完成后,此节点将自动加载剩余配置。策略将影响多步工具推理的机制。', + }, + learnMore: '了解更多', + }, }, tracing: { stopBy: '由{{user}}终止',