diff --git a/web/src/i18n/en.ts b/web/src/i18n/en.ts index 17fcde8d..9b957a84 100644 --- a/web/src/i18n/en.ts +++ b/web/src/i18n/en.ts @@ -2163,6 +2163,7 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re 'memory-write': 'Memory Storage', unknown: 'Unknown Node', notes: 'Sticky Note', + 'document-extractor': 'Document Extractor', clickToConfigure: 'Click to configure node parameters', nodeProperties: 'Node Properties', @@ -2361,6 +2362,9 @@ Memory Bear: After the rebellion, regional warlordism intensified for several re placeholder: 'Enter note...', removeLink: 'Remove Link', }, + 'document-extractor': { + file_selector: 'Input Variable', + }, name: 'Key', type: 'Type', value: 'Value', diff --git a/web/src/i18n/zh.ts b/web/src/i18n/zh.ts index d783bea3..862ed5d4 100644 --- a/web/src/i18n/zh.ts +++ b/web/src/i18n/zh.ts @@ -2160,6 +2160,7 @@ export const zh = { 'memory-write': '记忆储存', unknown: '未知节点', notes: '便签', + 'document-extractor': '文档提取器', clickToConfigure: '点击配置节点参数', nodeProperties: '节点属性', @@ -2361,6 +2362,9 @@ export const zh = { placeholder: '输入注释...', removeLink: '取消链接', }, + 'document-extractor': { + file_selector: '输入变量', + }, name: '键', type: '类型', value: '值', diff --git a/web/src/views/ApplicationConfig/Agent.tsx b/web/src/views/ApplicationConfig/Agent.tsx index 39fcfd62..2a8796ee 100644 --- a/web/src/views/ApplicationConfig/Agent.tsx +++ b/web/src/views/ApplicationConfig/Agent.tsx @@ -130,6 +130,7 @@ const Agent = forwardRef { + const opening_statement = form.getFieldValue(['features', 'opening_statement']) if (type === 'model') { const { default_model_config_id, capability, ...rest } = vo if (default_model_config_id !== values.default_model_config_id) { @@ -148,11 +149,18 @@ const Agent = forwardRef 0) { const filterValue = modelList.find(item => item.id === values.default_model_config_id) setDefaultModel(filterValue as Model | null) + const opening_statement = form.getFieldValue(['features', 'opening_statement']) setChatList([{ label: filterValue?.name || '', model_config_id: filterValue?.id || '', model_parameters: {...(filterValue?.config || {})} as unknown as ModelConfig, - list: [] + list: filterValue?.name ? [{ + role: 'assistant', + content: opening_statement?.statement, + meta_data: { + suggested_questions: opening_statement?.suggested_questions || [] + } + }] : [] }]) form.setFieldValue('capability', filterValue?.capability) } diff --git a/web/src/views/ApplicationConfig/components/ModelConfigModal.tsx b/web/src/views/ApplicationConfig/components/ModelConfigModal.tsx index 4ba34160..148afd5a 100644 --- a/web/src/views/ApplicationConfig/components/ModelConfigModal.tsx +++ b/web/src/views/ApplicationConfig/components/ModelConfigModal.tsx @@ -139,6 +139,7 @@ const ModelConfigModal = forwardRef( > {source !== 'multi_agent' && diff --git a/web/src/views/UserMemoryDetail/Neo4j.tsx b/web/src/views/UserMemoryDetail/Neo4j.tsx index 68f1420d..51be7c8d 100644 --- a/web/src/views/UserMemoryDetail/Neo4j.tsx +++ b/web/src/views/UserMemoryDetail/Neo4j.tsx @@ -161,10 +161,12 @@ const Neo4j: FC = () => { - - - - +
e.stopPropagation()}> + + + + +
) } diff --git a/web/src/views/Workflow/components/Editor/plugin/InitialValuePlugin.tsx b/web/src/views/Workflow/components/Editor/plugin/InitialValuePlugin.tsx index 04e8ae1d..0ebcbe77 100644 --- a/web/src/views/Workflow/components/Editor/plugin/InitialValuePlugin.tsx +++ b/web/src/views/Workflow/components/Editor/plugin/InitialValuePlugin.tsx @@ -53,7 +53,7 @@ const InitialValuePlugin: React.FC = ({ value, options const root = $getRoot(); root.clear(); - const parts = value.split(/(\{\{[^}]+\}\})/); + const parts = value.split(/(\{\{[^}]+\}\}|\n)/); if (enableLineNumbers) { const lines = value.split('\n'); @@ -63,8 +63,14 @@ const InitialValuePlugin: React.FC = ({ value, options root.append(paragraph); }); } else { - const paragraph = $createParagraphNode(); + let paragraph = $createParagraphNode(); + parts.forEach(part => { + if (part === '\n') { + root.append(paragraph); + paragraph = $createParagraphNode(); + return; + } const match = part.match(/^\{\{([^.]+)\.([^}]+)\}\}$/); const contextMatch = part.match(/^\{\{context\}\}$/); const conversationMatch = part.match(/^\{\{conv\.([^}]+)\}\}$/); @@ -78,10 +84,10 @@ const InitialValuePlugin: React.FC = ({ value, options } return } - + if (conversationMatch) { const [_, variableName] = conversationMatch; - const conversationSuggestion = optionsRef.current.find(s => + const conversationSuggestion = optionsRef.current.find(s => s.group === 'CONVERSATION' && s.label === variableName ); if (conversationSuggestion) { @@ -91,7 +97,7 @@ const InitialValuePlugin: React.FC = ({ value, options } return } - + if (match) { const [_, nodeId, label] = match; diff --git a/web/src/views/Workflow/components/Properties/CycleVarsList/index.tsx b/web/src/views/Workflow/components/Properties/CycleVarsList/index.tsx index 77ca0e61..09106a77 100644 --- a/web/src/views/Workflow/components/Properties/CycleVarsList/index.tsx +++ b/web/src/views/Workflow/components/Properties/CycleVarsList/index.tsx @@ -1,10 +1,11 @@ -import { type FC } from 'react' +import { type FC, useMemo } from 'react' import { useTranslation } from 'react-i18next'; import { Form, Select, Input, Button, InputNumber, Flex } from 'antd' import VariableSelect from '../VariableSelect' import type { Suggestion } from '../../Editor/plugin/AutocompletePlugin' import RadioGroupBtn from '../RadioGroupBtn' +import { getChildNodeVariables } from '../hooks/useVariableList' interface CycleVar { name: string; @@ -44,40 +45,14 @@ const CycleVarsList: FC = ({ const { t } = useTranslation(); const form = Form.useFormInstance(); - // 获取循环节点的子节点变量 - const getChildNodeVariables = () => { + const availableOptions = useMemo(() => { if (!selectedNode || !graphRef?.current || selectedNode.getData()?.type !== 'loop') { return options; } + const childVars = getChildNodeVariables(selectedNode, graphRef); - const loopNodeId = selectedNode.getData()?.id; - const childNodes = graphRef.current.getNodes().filter((node: any) => - node.getData()?.cycle === loopNodeId - ); - - const childVariables: Suggestion[] = []; - childNodes.forEach((childNode: any) => { - const childData = childNode.getData(); - if (childData?.config) { - Object.keys(childData.config).forEach(key => { - if (childData.config[key]?.defaultValue) { - childVariables.push({ - key: `${childData.id}.${key}`, - label: `${childData.name || childData.type}.${key}`, - type: 'output', - dataType: 'string', - value: `${childData.id}.${key}`, - nodeData: childData - }); - } - }); - } - }); - - return [...options, ...childVariables]; - }; - - const availableOptions = getChildNodeVariables(); + return options.filter(option => !childVars.some(item => item.value === option.value)) + }, [options, selectedNode, graphRef]); return ( diff --git a/web/src/views/Workflow/components/Properties/hooks/useVariableList.ts b/web/src/views/Workflow/components/Properties/hooks/useVariableList.ts index 779174ff..dbda2759 100644 --- a/web/src/views/Workflow/components/Properties/hooks/useVariableList.ts +++ b/web/src/views/Workflow/components/Properties/hooks/useVariableList.ts @@ -42,6 +42,9 @@ const NODE_VARIABLES = { 'memory-read': [ { label: 'answer', dataType: 'string', field: 'answer' }, { label: 'intermediate_outputs', dataType: 'array[object]', field: 'intermediate_outputs' } + ], + 'document-extractor': [ + { label: 'text', dataType: 'string', field: 'text' }, ] } as const; @@ -177,7 +180,8 @@ const hasOutputNodeTypes = [ 'var-aggregator', 'http-request', 'tool', - 'jinja-render' + 'jinja-render', + 'document-extractor' ]; /** diff --git a/web/src/views/Workflow/components/Properties/index.tsx b/web/src/views/Workflow/components/Properties/index.tsx index 33121a89..66b59075 100644 --- a/web/src/views/Workflow/components/Properties/index.tsx +++ b/web/src/views/Workflow/components/Properties/index.tsx @@ -636,6 +636,8 @@ const Properties: FC = ({ size="small" parentName={key} options={getFilteredVariableList(selectedNode?.data?.type, key)} + selectedNode={selectedNode} + graphRef={graphRef} /> ) diff --git a/web/src/views/Workflow/constant.ts b/web/src/views/Workflow/constant.ts index 6665bb86..cadff647 100644 --- a/web/src/views/Workflow/constant.ts +++ b/web/src/views/Workflow/constant.ts @@ -473,6 +473,16 @@ export const nodeLibrary: NodeLibrary[] = [ }, } }, + { + type: "document-extractor", icon: codeExecutionIcon, + config: { + file_selector: { + type: 'variableList', + placeholder: 'common.pleaseSelect', + onFilterVariableNames: ['sys.files'] + } + } + }, ] }, ]; @@ -858,100 +868,6 @@ export interface OutputVariable { }>; } -/** - * Output variable definitions for each node type - * Specifies what variables each node produces - */ -export const outputVariable: { [key: string]: OutputVariable } = { - start: { - sys: [ - { name: "message", type: "string" }, - { name: "conversation_id", type: "string" }, - { name: "execution_id", type: "string", }, - { name: "workspace_id", type: "string" }, - { name: "user_id", type: "string" }, - ], - define: ['variables'] - }, - end: { - }, - llm: { - default: [ - { name: "output", type: "string" }, - ] - }, - 'knowledge-retrieval': { - default: [ - { name: "output", type: "array[object]" }, - ] - }, - 'parameter-extractor': { - default: [ - { name: "__is_success", type: "number" }, - { name: "__reason", type: "string" }, - ], - define: ['params'] - }, - 'memory-read': { - default: [ - { name: "answer", type: "string" }, - { name: "intermediate_outputs", type: "array[object]" }, - ], - }, - 'memory-write': { - - }, - 'if-else': { - - }, - 'question-classifier': { - default: [ - { name: "class_name", type: "string" }, - // { name: "output", type: "string" }, - ], - }, - 'iteration': { - default: [ - // { name: "item", type: "string" }, // 仅内部使用 - { name: "output", type: "array[string]" }, - ], - }, - 'loop': { - define: ['cycle_vars'] - }, - 'cycle-start': { - - }, - 'break': { - - }, - 'var-aggregator': { - // default: [ - // { name: "output", type: "string" }, - // ], - define: ['group_variables'] - }, - 'assigner': { - - }, - 'http-request': { - default: [ - { name: "body", type: "string" }, - { name: "status_code", type: "number" }, - ], - }, - 'tool': { - default: [ - { name: "data", type: "string" }, - ], - }, - 'jinja-render': { - default: [ - { name: "output", type: "string" }, - ], - }, -} - /** * Default edge attributes configuration * Defines visual styling for edges/connections