From a880beb1f6d6c58688ebf00fea656685ad37bf21 Mon Sep 17 00:00:00 2001 From: balibabu Date: Fri, 7 Nov 2025 11:44:22 +0800 Subject: [PATCH] Feat: Add a form for variable aggregation operators #10427 (#11095) ### What problem does this PR solve? Feat: Add a form for variable aggregation operators #10427 ### Type of change - [x] New Feature (non-breaking change which adds functionality) --- .../agent/canvas/node/retrieval-node.tsx | 4 +- .../pages/agent/canvas/node/switch-node.tsx | 4 +- .../agent/form-sheet/form-config-map.tsx | 5 ++ web/src/pages/agent/form/agent-form/index.tsx | 3 - .../structured-output-secondary-menu.tsx | 12 ++- .../agent/form/invoke-form/variable-table.tsx | 4 +- .../pages/agent/form/message-form/index.tsx | 3 - .../dynamic-group-variable.tsx | 88 +++++++++++++++++++ .../form/variable-aggregator-form/index.tsx | 81 +++++++++++++++++ .../hooks/use-build-structured-output.ts | 75 +++++++++++++++- .../pages/agent/hooks/use-get-begin-query.tsx | 32 ++++++- 11 files changed, 289 insertions(+), 22 deletions(-) create mode 100644 web/src/pages/agent/form/variable-aggregator-form/dynamic-group-variable.tsx create mode 100644 web/src/pages/agent/form/variable-aggregator-form/index.tsx diff --git a/web/src/pages/agent/canvas/node/retrieval-node.tsx b/web/src/pages/agent/canvas/node/retrieval-node.tsx index ad5bae9b1..07e84965f 100644 --- a/web/src/pages/agent/canvas/node/retrieval-node.tsx +++ b/web/src/pages/agent/canvas/node/retrieval-node.tsx @@ -7,7 +7,7 @@ import classNames from 'classnames'; import { get } from 'lodash'; import { memo } from 'react'; import { NodeHandleId } from '../../constant'; -import { useGetVariableLabelByValue } from '../../hooks/use-get-begin-query'; +import { useGetVariableLabelOrTypeByValue } from '../../hooks/use-get-begin-query'; import { CommonHandle, LeftEndHandle } from './handle'; import styles from './index.less'; import NodeHeader from './node-header'; @@ -23,7 +23,7 @@ function InnerRetrievalNode({ const knowledgeBaseIds: string[] = get(data, 'form.kb_ids', []); const { list: knowledgeList } = useFetchKnowledgeList(true); - const getLabel = useGetVariableLabelByValue(id); + const { getLabel } = useGetVariableLabelOrTypeByValue(id); return ( diff --git a/web/src/pages/agent/canvas/node/switch-node.tsx b/web/src/pages/agent/canvas/node/switch-node.tsx index d350dbdc0..006afd843 100644 --- a/web/src/pages/agent/canvas/node/switch-node.tsx +++ b/web/src/pages/agent/canvas/node/switch-node.tsx @@ -4,7 +4,7 @@ import { LogicalOperatorIcon } from '@/hooks/logic-hooks/use-build-operator-opti import { ISwitchCondition, ISwitchNode } from '@/interfaces/database/flow'; import { NodeProps, Position } from '@xyflow/react'; import { memo, useCallback } from 'react'; -import { useGetVariableLabelByValue } from '../../hooks/use-get-begin-query'; +import { useGetVariableLabelOrTypeByValue } from '../../hooks/use-get-begin-query'; import { CommonHandle, LeftEndHandle } from './handle'; import { RightHandleStyle } from './handle-icon'; import NodeHeader from './node-header'; @@ -27,7 +27,7 @@ const ConditionBlock = ({ nodeId, }: { condition: ISwitchCondition } & { nodeId: string }) => { const items = condition?.items ?? []; - const getLabel = useGetVariableLabelByValue(nodeId); + const { getLabel } = useGetVariableLabelOrTypeByValue(nodeId); const renderOperatorIcon = useCallback((operator?: string) => { const item = SwitchOperatorOptions.find((x) => x.value === operator); diff --git a/web/src/pages/agent/form-sheet/form-config-map.tsx b/web/src/pages/agent/form-sheet/form-config-map.tsx index 6634ea594..c291e4e05 100644 --- a/web/src/pages/agent/form-sheet/form-config-map.tsx +++ b/web/src/pages/agent/form-sheet/form-config-map.tsx @@ -38,6 +38,7 @@ import TokenizerForm from '../form/tokenizer-form'; import ToolForm from '../form/tool-form'; import TuShareForm from '../form/tushare-form'; import UserFillUpForm from '../form/user-fill-up-form'; +import VariableAggregatorForm from '../form/variable-aggregator-form'; import VariableAssignerForm from '../form/variable-assigner-form'; import WenCaiForm from '../form/wencai-form'; import WikipediaForm from '../form/wikipedia-form'; @@ -186,4 +187,8 @@ export const FormConfigMap = { [Operator.VariableAssigner]: { component: VariableAssignerForm, }, + + [Operator.VariableAggregator]: { + component: VariableAggregatorForm, + }, }; diff --git a/web/src/pages/agent/form/agent-form/index.tsx b/web/src/pages/agent/form/agent-form/index.tsx index d5bdd9dad..332c055bc 100644 --- a/web/src/pages/agent/form/agent-form/index.tsx +++ b/web/src/pages/agent/form/agent-form/index.tsx @@ -26,7 +26,6 @@ import { useTranslation } from 'react-i18next'; import { z } from 'zod'; import { AgentExceptionMethod, - JsonSchemaDataType, NodeHandleId, VariableType, initialAgentValues, @@ -158,7 +157,6 @@ function AgentForm({ node }: INextOperatorForm) { placeholder={t('flow.messagePlaceholder')} showToolbar={true} extraOptions={extraOptions} - types={[JsonSchemaDataType.String]} > @@ -176,7 +174,6 @@ function AgentForm({ node }: INextOperatorForm) { diff --git a/web/src/pages/agent/form/components/structured-output-secondary-menu.tsx b/web/src/pages/agent/form/components/structured-output-secondary-menu.tsx index 15e91de8b..fd56a75c9 100644 --- a/web/src/pages/agent/form/components/structured-output-secondary-menu.tsx +++ b/web/src/pages/agent/form/components/structured-output-secondary-menu.tsx @@ -53,10 +53,13 @@ export function StructuredOutputSecondaryMenu({ const renderAgentStructuredOutput = useCallback( (values: any, option: { label: ReactNode; value: string }) => { - if (isPlainObject(values) && 'properties' in values) { + const properties = + get(values, 'properties') || get(values, 'items.properties'); + + if (isPlainObject(values) && properties) { return (