From d517bceda28d62e61367eabfbc87fcf1d139302b Mon Sep 17 00:00:00 2001 From: zhaoying Date: Fri, 10 Apr 2026 12:03:02 +0800 Subject: [PATCH 1/6] fix(web): object/array[object] add format check --- web/src/i18n/en.ts | 1 + web/src/i18n/zh.ts | 1 + .../AddChatVariable/ChatVariableModal.tsx | 16 ++++++++++++++-- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/web/src/i18n/en.ts b/web/src/i18n/en.ts index 3d24c0d0..d7b7c617 100644 --- a/web/src/i18n/en.ts +++ b/web/src/i18n/en.ts @@ -2239,6 +2239,7 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re addvariable: 'Chat Variables', addChatVariable: 'Add Chat Variable', editChatVariable: 'Edit Chat Variable', + invalidJSON: 'Invalid JSON format', config: { llm: { diff --git a/web/src/i18n/zh.ts b/web/src/i18n/zh.ts index f5e3653a..55860e46 100644 --- a/web/src/i18n/zh.ts +++ b/web/src/i18n/zh.ts @@ -2200,6 +2200,7 @@ export const zh = { addvariable: '会话变量', addChatVariable: '添加会话变量', editChatVariable: '编辑会话变量', + invalidJSON: 'JSON 格式不正确', config: { llm: { diff --git a/web/src/views/Workflow/components/AddChatVariable/ChatVariableModal.tsx b/web/src/views/Workflow/components/AddChatVariable/ChatVariableModal.tsx index ff773a9e..e948aabf 100644 --- a/web/src/views/Workflow/components/AddChatVariable/ChatVariableModal.tsx +++ b/web/src/views/Workflow/components/AddChatVariable/ChatVariableModal.tsx @@ -124,7 +124,7 @@ const ChatVariableModal = forwardRef ) : ( - + { + if (!value) return Promise.resolve(); + try { JSON.parse(value); return Promise.resolve(); } + catch { return Promise.reject(t('workflow.invalidJSON')); } + } + } : {} + ]} + > {type === 'number' ? : type === 'boolean' From 9a926a8398cd1d512d2ace38f9bccd2854c720a4 Mon Sep 17 00:00:00 2001 From: zhaoying Date: Fri, 10 Apr 2026 16:24:36 +0800 Subject: [PATCH 2/6] feat(web): workflow variable type --- web/src/i18n/en.ts | 5 ++ web/src/i18n/zh.ts | 5 ++ .../AddChatVariable/ChatVariableModal.tsx | 2 +- .../Workflow/components/PortClickHandler.tsx | 2 +- .../components/Properties/CaseList/index.tsx | 78 +++++++++++++---- .../Properties/ConditionList/index.tsx | 54 ++++++++++-- .../Properties/CycleVarsList/index.tsx | 14 ++++ .../Properties/HttpRequest/EditableTable.tsx | 45 +++++++++- .../Properties/HttpRequest/index.tsx | 76 +++++++++++++++-- .../Properties/ToolConfig/index.tsx | 59 +++++++------ .../Workflow/components/Properties/index.tsx | 83 +++++++++++++++++-- 11 files changed, 356 insertions(+), 67 deletions(-) diff --git a/web/src/i18n/en.ts b/web/src/i18n/en.ts index d7b7c617..6e7f1465 100644 --- a/web/src/i18n/en.ts +++ b/web/src/i18n/en.ts @@ -2342,6 +2342,11 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re "eq": 'Is', "ne": 'Is Not', }, + file: { + "empty": 'Not Exist', + "not_empty": 'Exists', + eq: 'All Are' + }, else_desc: 'Used to define the logic that should be executed when the if condition is not met.', unset: 'Condition Not Set', set: 'Set', diff --git a/web/src/i18n/zh.ts b/web/src/i18n/zh.ts index 55860e46..acd06cdc 100644 --- a/web/src/i18n/zh.ts +++ b/web/src/i18n/zh.ts @@ -2303,6 +2303,11 @@ export const zh = { "eq": '是', "ne": '不是', }, + file: { + "empty": '不存在', + "not_empty": '存在', + eq: '全都是' + }, else_desc: '用于定义当 if 条件不满足时应执行的逻辑。', unset: '条件未设置', set: '已设置', diff --git a/web/src/views/Workflow/components/AddChatVariable/ChatVariableModal.tsx b/web/src/views/Workflow/components/AddChatVariable/ChatVariableModal.tsx index e948aabf..5666f3ab 100644 --- a/web/src/views/Workflow/components/AddChatVariable/ChatVariableModal.tsx +++ b/web/src/views/Workflow/components/AddChatVariable/ChatVariableModal.tsx @@ -5,7 +5,7 @@ * @Last Modified time: 2026-04-08 11:05:34 */ import { forwardRef, useImperativeHandle, useState, useRef, useMemo } from 'react'; -import { Form, Input, Select, InputNumber, Button, Row, Col, Flex, Spin } from 'antd'; +import { Form, Input, Select, InputNumber, Button, Row, Col, Flex } from 'antd'; import { PlusOutlined } from '@ant-design/icons'; import { useTranslation } from 'react-i18next'; diff --git a/web/src/views/Workflow/components/PortClickHandler.tsx b/web/src/views/Workflow/components/PortClickHandler.tsx index b556ffab..cb3e16c4 100644 --- a/web/src/views/Workflow/components/PortClickHandler.tsx +++ b/web/src/views/Workflow/components/PortClickHandler.tsx @@ -328,7 +328,7 @@ const PortClickHandler: React.FC = ({ graph }) => { }; const content = ( - + {nodeLibrary.map((category) => { const sourceNodeData = sourceNode?.getData(); const isChildOfLoop = sourceNodeData?.cycle && graph?.getNodes().find((n: any) => n.getData()?.id === sourceNodeData.cycle && n.getData()?.type === 'loop'); diff --git a/web/src/views/Workflow/components/Properties/CaseList/index.tsx b/web/src/views/Workflow/components/Properties/CaseList/index.tsx index e1583ca0..40353f64 100644 --- a/web/src/views/Workflow/components/Properties/CaseList/index.tsx +++ b/web/src/views/Workflow/components/Properties/CaseList/index.tsx @@ -4,7 +4,7 @@ * @Last Modified by: ZhaoYing * @Last Modified time: 2026-03-25 15:23:45 */ -import { type FC } from 'react' +import { useMemo, type FC } from 'react' import clsx from 'clsx' import { useTranslation } from 'react-i18next'; import { Form, Button, Select, Space, Divider, InputNumber, type SelectProps, Flex, Row, Col } from 'antd' @@ -15,7 +15,7 @@ import Editor from '../../Editor' import { edgeAttrs, nodeWidth } from '../../../constant' import RbButton from '@/components/RbButton'; import RadioGroupBtn from '../RadioGroupBtn' -import { calcConditionNodeTotalHeight, getConditionNodeCasePortY } from '../../../utils' +import { calcConditionNodeTotalHeight, getConditionNodeCasePortY } from '../../../utils'; interface CaseListProps { value?: Array<{ logical_operator: 'and' | 'or'; expressions: { left: string; operator: string; right: string; input_type?: string; }[] }>; @@ -49,6 +49,34 @@ const operatorsObj: { [key: string]: SelectProps['options'] } = { boolean: [ { value: 'eq', label: 'workflow.config.if-else.boolean.eq' }, { value: 'ne', label: 'workflow.config.if-else.boolean.ne' }, + ], + object: [ + { value: 'eq', label: 'workflow.config.if-else.boolean.eq' }, + { value: 'ne', label: 'workflow.config.if-else.boolean.ne' }, + { value: 'empty', label: 'workflow.config.if-else.empty' }, + { value: 'not_empty', label: 'workflow.config.if-else.not_empty' }, + ], + file: [ + { value: 'empty', label: 'workflow.config.if-else.file.empty' }, + { value: 'not_empty', label: 'workflow.config.if-else.file.not_empty' }, + ], + // TODO:包含、不包含、全都是 + 'array[file]': [ + { value: 'empty', label: 'workflow.config.if-else.empty' }, + { value: 'not_empty', label: 'workflow.config.if-else.not_empty' }, + // { value: 'eq', label: 'workflow.config.if-else.eq' }, + // { value: 'contains', label: 'workflow.config.if-else.contains' }, + // { value: 'not_contains', label: 'workflow.config.if-else.not_contains' }, + ], + 'array': [ + { value: 'contains', label: 'workflow.config.if-else.contains' }, + { value: 'not_contains', label: 'workflow.config.if-else.not_contains' }, + { value: 'empty', label: 'workflow.config.if-else.empty' }, + { value: 'not_empty', label: 'workflow.config.if-else.not_empty' }, + ], + 'array[object]': [ + { value: 'empty', label: 'workflow.config.if-else.empty' }, + { value: 'not_empty', label: 'workflow.config.if-else.not_empty' }, ] } @@ -247,6 +275,22 @@ const CaseList: FC = ({ form.setFieldValue([name, caseIndex, 'expressions', conditionIndex, 'right'], undefined); }; + const filterNumberOptions = useMemo(() => { + const filterList: Suggestion[] = [] + options.forEach(vo => { + if (vo.children && vo.children?.length > 0) { + filterList.push({ + ...vo, + children: vo.children.filter(child => child.dataType === 'number') + }) + } else if (vo.dataType === 'number') { + filterList.push(vo) + } + }) + + return filterList + }, [options]) + return ( <> @@ -284,11 +328,15 @@ const CaseList: FC = ({ const currentCase = cases[caseIndex] || {}; const currentExpression = currentCase.expressions?.[conditionIndex] || {}; const currentOperator = currentExpression.operator; - const hideRightField = currentOperator === 'empty' || currentOperator === 'not_empty'; const leftFieldValue = currentExpression.left; const leftFieldOption = options.find(option => `{{${option.value}}}` === leftFieldValue); const leftFieldType = leftFieldOption?.dataType; - const operatorList = operatorsObj[leftFieldType || 'default'] || operatorsObj.default || []; + const hideRightField = currentOperator === 'empty' || currentOperator === 'not_empty' || leftFieldType === 'file' || leftFieldType === 'array[object]' || leftFieldType === 'array[file]'; + const operatorList = leftFieldType && operatorsObj[leftFieldType] + ? operatorsObj[leftFieldType] + : leftFieldType && leftFieldType?.includes('array') + ? operatorsObj.array + : operatorsObj.default; const inputType = leftFieldType === 'number' ? currentExpression.input_type : undefined; return ( @@ -312,7 +360,7 @@ const CaseList: FC = ({ = ({ {inputType === 'variable' ? vo.dataType === 'number')} + options={filterNumberOptions} allowClear={false} variant="borderless" size="small" /> : form.setFieldValue([name, caseIndex, 'expressions', conditionIndex, 'right'], value)} - /> + placeholder={t('common.pleaseEnter')} + variant="borderless" + className="rb:w-full!" + onChange={(value) => form.setFieldValue([name, caseIndex, 'expressions', conditionIndex, 'right'], value)} + /> } : ( - {leftFieldType === 'boolean' - ? + {['boolean', 'array[boolean]'].includes(leftFieldType as string) + ? : } diff --git a/web/src/views/Workflow/components/Properties/ConditionList/index.tsx b/web/src/views/Workflow/components/Properties/ConditionList/index.tsx index cad32e37..ddf92971 100644 --- a/web/src/views/Workflow/components/Properties/ConditionList/index.tsx +++ b/web/src/views/Workflow/components/Properties/ConditionList/index.tsx @@ -1,4 +1,4 @@ -import { type FC } from 'react' +import { type FC, useMemo } from 'react' import clsx from 'clsx' import { useTranslation } from 'react-i18next'; import { Form, Button, Select, InputNumber, Input, Divider, type SelectProps, Flex, Space, Row, Col } from 'antd' @@ -47,6 +47,18 @@ const operatorsObj: { [key: string]: SelectProps['options'] } = { { value: 'ne', label: 'workflow.config.if-else.boolean.ne' }, { value: 'empty', label: 'workflow.config.if-else.empty' }, { value: 'not_empty', label: 'workflow.config.if-else.not_empty' }, + ], + // 为空、不为空 + object: [ + { value: 'empty', label: 'workflow.config.if-else.empty' }, + { value: 'not_empty', label: 'workflow.config.if-else.not_empty' }, + ], + // 包含、不包含、为空、不为空 + 'array': [ + { value: 'contains', label: 'workflow.config.if-else.contains' }, + { value: 'not_contains', label: 'workflow.config.if-else.not_contains' }, + { value: 'empty', label: 'workflow.config.if-else.empty' }, + { value: 'not_empty', label: 'workflow.config.if-else.not_empty' }, ] } @@ -81,6 +93,23 @@ const ConditionList: FC = ({ const currentValue = form.getFieldValue([parentName, 'logical_operator']); form.setFieldValue([parentName, 'logical_operator'], currentValue === 'and' ? 'or' : 'and'); }; + + const getNumVariable = useMemo(() => { + const filterList: Suggestion[] = [] + options.forEach(variable => { + if (variable.dataType === 'number') { + filterList.push(variable) + } else if (variable.dataType === 'file') { + filterList.push({ + ...variable, + disabled: true, + children: variable.children?.filter(child => child.dataType === 'number') + }) + } + }) + + return filterList + }, [options]) return ( <> @@ -125,11 +154,19 @@ const ConditionList: FC = ({ const expressions = form.getFieldValue([parentName, 'expressions']) || []; const currentExpression = expressions[index] || {}; const currentOperator = currentExpression.operator; - const hideRightField = currentOperator === 'empty' || currentOperator === 'not_empty'; const leftFieldValue = currentExpression.left; const leftFieldOption = options.find(option => `{{${option.value}}}` === leftFieldValue); const leftFieldType = leftFieldOption?.dataType; - const operatorList = operatorsObj[leftFieldType || 'default'] || operatorsObj.default || []; + const hideRightField = currentOperator === 'empty' || currentOperator === 'not_empty' || ['array[object]', 'object'].includes(leftFieldType as string); + const operatorList = leftFieldType && ['array[object]', 'object'].includes(leftFieldType) + ? operatorsObj.object + : leftFieldType && ['array[boolean]', 'boolean'].includes(leftFieldType) + ? operatorsObj.boolean + : leftFieldType && operatorsObj[leftFieldType] + ? operatorsObj[leftFieldType] + : leftFieldType?.includes('array') + ? operatorsObj.array + : operatorsObj.default const inputType = leftFieldType === 'number' ? currentExpression.input_type : undefined; return ( = ({ - vo.value.includes('sys.') || + !['file', 'array[file]'].includes(vo.dataType) && + (vo.value.includes('sys.') || vo.value.includes('conv.') || vo.nodeData.type === 'loop' || - (vo.nodeData.cycle && vo.nodeData.cycle === selectedNode?.id) + (vo.nodeData.cycle && vo.nodeData.cycle === selectedNode?.id)) )} size="small" allowClear={false} @@ -163,7 +201,7 @@ const ConditionList: FC = ({ } diff --git a/web/src/views/Workflow/components/Properties/CycleVarsList/index.tsx b/web/src/views/Workflow/components/Properties/CycleVarsList/index.tsx index 09106a77..5d1138f0 100644 --- a/web/src/views/Workflow/components/Properties/CycleVarsList/index.tsx +++ b/web/src/views/Workflow/components/Properties/CycleVarsList/index.tsx @@ -6,6 +6,7 @@ import VariableSelect from '../VariableSelect' import type { Suggestion } from '../../Editor/plugin/AutocompletePlugin' import RadioGroupBtn from '../RadioGroupBtn' import { getChildNodeVariables } from '../hooks/useVariableList' +import CodeMirrorEditor from '@/components/CodeMirrorEditor'; interface CycleVar { name: string; @@ -28,11 +29,17 @@ const types = [ 'string', 'number', 'boolean', + 'object', 'array[string]', 'array[number]', 'array[boolean]', 'array[object]' ] +const object_placeholder = `# example +# { +# "name": "redbear", +# "age": 2 +# }` const CycleVarsList: FC = ({ value = [], @@ -144,6 +151,13 @@ const CycleVarsList: FC = ({ { value: true, label: 'True' }, { value: false, label: 'False' }]} /> + : currentType === 'object' + ? : ( = ({ : options }, [options, filterBooleanType]) + const namefilterOptions = useMemo(() => { + const filterList: Suggestion[] = []; + options.forEach(vo => { + if (vo.dataType === 'file') { + filterList.push({ + ...vo, + disabled: true, + children: vo.children?.filter(child => child.dataType !== 'boolean') + }) + } else if (vo.dataType !== 'array[file]') { + filterList.push(vo) + } + }) + + return filterList + }, [options]) + const valueFilterOptions = (type?: string) => { + let filterOptions: Suggestion[] = [] + options.forEach(vo => { + if (type === 'file' && vo.dataType === 'file') { + filterOptions.push({ + ...vo, + children: [] + }) + } else if (type === 'file' && vo.dataType === 'array[file]') { + filterOptions.push(vo) + } else if (vo.dataType === 'file') { + filterOptions.push({ + ...vo, + disabled: true + }) + } else { + filterOptions.push(vo) + } + }) + + return filterOptions + } + const getColumns = (remove: (index: number) => void): TableProps['columns'] => { const hasType = typeOptions.length > 0; const contentClassName = hasType ? 'rb:w-[110px]!' : "rb:w-[148px]!" @@ -57,7 +96,7 @@ const EditableTable: FC = ({ render: (_: any, __: TableRow, index: number) => ( !option.dataType.includes('file'))} + options={namefilterOptions} type="input" className={contentClassName} size={size} @@ -105,9 +144,7 @@ const EditableTable: FC = ({ > {(form) => { const currentType = form.getFieldValue([...Array.isArray(parentName) ? parentName : [parentName], index, 'type']); - const filteredOptions = currentType === 'file' - ? booleanFilterOptions.filter(option => option.dataType.includes('file')) - : booleanFilterOptions.filter(option => !option.dataType.includes('file')); + const filteredOptions = valueFilterOptions(currentType) return ( diff --git a/web/src/views/Workflow/components/Properties/HttpRequest/index.tsx b/web/src/views/Workflow/components/Properties/HttpRequest/index.tsx index a02549bd..b032016b 100644 --- a/web/src/views/Workflow/components/Properties/HttpRequest/index.tsx +++ b/web/src/views/Workflow/components/Properties/HttpRequest/index.tsx @@ -4,7 +4,7 @@ * @Last Modified by: ZhaoYing * @Last Modified time: 2026-04-02 17:17:06 */ -import { type FC, useRef, useState } from "react"; +import { type FC, useMemo, useRef, useState } from "react"; import { useTranslation } from 'react-i18next' import { Form, Row, Col, Select, Button, Divider, InputNumber, Switch, Input, Flex, Radio } from 'antd' import { CaretDownOutlined, CaretRightOutlined, SettingOutlined } from '@ant-design/icons'; @@ -84,6 +84,64 @@ const HttpRequest: FC<{ options: Suggestion[]; selectedNode?: any; graphRef?: an setCollapsed((prev: boolean) => !prev) } + const filterVariables = useMemo(() => { + const filterList: Suggestion[] = [] + options.forEach(variable => { + if (['number', 'string'].includes(variable.dataType)) { + filterList.push(variable) + } else if (variable.dataType === 'file') { + filterList.push({ + ...variable, + disabled: true, + children: variable.children?.filter(child => ['number', 'string'].includes(child.dataType)) + }) + } + }) + + return filterList + }, [options]) + const filterVariablesWithFile = useMemo(() => { + const filterList: Suggestion[] = [] + options.forEach(variable => { + if (['number', 'string', 'file', 'array[file]'].includes(variable.dataType)) { + filterList.push(variable) + } + }) + + return filterList + }, [options]) + const jsonRawFilterVariables = useMemo(() => { + const filterList: Suggestion[] = [] + options.forEach(variable => { + if (['number', 'string', 'array[string]', 'array[number]'].includes(variable.dataType)) { + filterList.push(variable) + } else if (variable.dataType === 'file') { + filterList.push({ + ...variable, + disabled: true, + children: variable.children?.filter(child => ['number', 'string', 'file', 'array[string]', 'array[number]'].includes(child.dataType)) + }) + } + }) + + return filterList + }, [options]) + const fileFilterVariables = useMemo(() => { + const filterList: Suggestion[] = [] + options.forEach(variable => { + if (['array[file]'].includes(variable.dataType)) { + filterList.push(variable) + } else if (variable.dataType === 'file') { + filterList.push({ + ...variable, + children: [] + }) + } + }) + + return filterList + }, [options]) + return ( <> @@ -117,7 +175,7 @@ const HttpRequest: FC<{ options: Suggestion[]; selectedNode?: any; graphRef?: an vo.dataType === 'string' || vo.dataType === 'number')} + options={filterVariables} variant="outlined" type="input" size="small" @@ -134,7 +192,7 @@ const HttpRequest: FC<{ options: Suggestion[]; selectedNode?: any; graphRef?: an size="small" parentName="headers" title="HEADERS" - options={options.filter(vo => vo.dataType === 'string' || vo.dataType === 'number')} + options={filterVariables} /> @@ -143,7 +201,7 @@ const HttpRequest: FC<{ options: Suggestion[]; selectedNode?: any; graphRef?: an size="small" parentName="params" title="PARAMS" - options={options.filter(vo => vo.dataType === 'string' || vo.dataType === 'number')} + options={filterVariables} /> @@ -167,7 +225,7 @@ const HttpRequest: FC<{ options: Suggestion[]; selectedNode?: any; graphRef?: an vo.dataType === 'string' || vo.dataType === 'number' || vo.dataType.includes('file'))} + options={filterVariablesWithFile} typeOptions={[ { label: 'text', value: 'text' }, { label: 'file', value: 'file' } @@ -180,7 +238,7 @@ const HttpRequest: FC<{ options: Suggestion[]; selectedNode?: any; graphRef?: an vo.dataType === 'string' || vo.dataType === 'number')} + options={filterVariablesWithFile} filterBooleanType={true} /> @@ -190,7 +248,7 @@ const HttpRequest: FC<{ options: Suggestion[]; selectedNode?: any; graphRef?: an vo.dataType === 'string' || vo.dataType === 'number')} + options={jsonRawFilterVariables} isArray={false} title="JSON" titleVariant="borderless" @@ -204,7 +262,7 @@ const HttpRequest: FC<{ options: Suggestion[]; selectedNode?: any; graphRef?: an vo.dataType === 'string' || vo.dataType === 'number')} + options={jsonRawFilterVariables} isArray={false} title="RAW TEXT" titleVariant="borderless" @@ -220,7 +278,7 @@ const HttpRequest: FC<{ options: Suggestion[]; selectedNode?: any; graphRef?: an vo.dataType.includes('file'))} + options={fileFilterVariables} type="input" size="small" height={28} diff --git a/web/src/views/Workflow/components/Properties/ToolConfig/index.tsx b/web/src/views/Workflow/components/Properties/ToolConfig/index.tsx index ba1e9a5f..ce30ee8f 100644 --- a/web/src/views/Workflow/components/Properties/ToolConfig/index.tsx +++ b/web/src/views/Workflow/components/Properties/ToolConfig/index.tsx @@ -163,25 +163,45 @@ const ToolConfig: FC<{ options: Suggestion[]; }> = ({ form.setFieldsValue(inititalValue) } - const getNumberOptions = useMemo(() => { - const list: Suggestion[] = [] + // string -> string + // integer -> number + // number -> number + // boolean -> boolean【只能选true/false】 + // array -> array[file]/array[object]/array[string]/array[number]/array[boolean] + // object -> object/file + const getFilterOptions = (type: string) => { + const filterList: Suggestion[] = []; options.forEach(vo => { - if (vo.children && vo?.children?.length > 0) { - const filterChild = vo.children.filter(child => child.dataType === 'number') + if (vo.children && vo.children?.length > 0) { + const childOptions = vo.children?.filter(child => child.dataType === type || (type === 'integer' && child.dataType === 'number')) - if (filterChild.length > 0) { - list.push({ ...vo, disabled: vo.dataType !== 'number', children: filterChild }) - } else if (vo.dataType === 'number') { - list.push({ ...vo, children: [] }) + if (vo.dataType === type + || (type === 'integer' && vo.dataType === 'number') + || (type === 'array' && vo.dataType.includes(type)) + || (type === 'object' && vo.dataType === 'object') + ) { + filterList.push({ + ...vo, + children: childOptions + }) + } else if (childOptions.length > 0) { + filterList.push({ + ...vo, + disabled: true, + children: childOptions + }) } - } else if (vo.dataType === 'number') { - list.push({ ...vo }) + } else if (vo.dataType === type + || (type === 'integer' && vo.dataType === 'number') + || (type === 'array' && vo.dataType.includes(type)) + || (type === 'object' && vo.dataType === 'object')) { + filterList.push(vo) } }) - console.log('options', options, list) - return list - }, [options]) + + return filterList + } return ( <> @@ -205,7 +225,7 @@ const ToolConfig: FC<{ options: Suggestion[]; }> = ({ - {parameter.name} + {parameter.name} ({parameter.type})
@@ -220,21 +240,12 @@ const ToolConfig: FC<{ options: Suggestion[]; }> = ({ ?