/* * @Author: ZhaoYing * @Date: 2026-02-03 15:06:18 * @Last Modified by: ZhaoYing * @Last Modified time: 2026-02-11 12:07:20 */ import LoopNode from './components/Nodes/LoopNode'; import NormalNode from './components/Nodes/NormalNode'; import ConditionNode from './components/Nodes/ConditionNode'; import GroupStartNode from './components/Nodes/GroupStartNode'; import AddNode from './components/Nodes/AddNode' import type { PortMetadata, GroupMetadata } from '@antv/x6/lib/model/port'; import type { ReactShapeConfig } from '@antv/x6-react-shape'; // Import workflow icons import startIcon from '@/assets/images/workflow/start.png'; import endIcon from '@/assets/images/workflow/end.png'; // import answerIcon from '@/assets/images/workflow/answer.png'; import llmIcon from '@/assets/images/workflow/llm.png'; // import modelSelectionIcon from '@/assets/images/workflow/model_selection.png'; // import modelVotingIcon from '@/assets/images/workflow/model_voting.png'; import ragIcon from '@/assets/images/workflow/rag.png'; // import classificationIcon from '@/assets/images/workflow/classification.png'; import parameterExtractionIcon from '@/assets/images/workflow/parameter_extraction.png'; // import taskPlanningIcon from '@/assets/images/workflow/task_planning.png'; // import reasoningControlIcon from '@/assets/images/workflow/reasoning_control.png'; // import selfReflectionIcon from '@/assets/images/workflow/self_reflection.png'; // import memoryEnhancementIcon from '@/assets/images/workflow/memory_enhancement.png'; // import agentSchedulingIcon from '@/assets/images/workflow/agent_scheduling.png'; // import agentCollaborationIcon from '@/assets/images/workflow/agent_collaboration.png'; // import agentArbitrationIcon from '@/assets/images/workflow/agent_arbitration.png'; import conditionIcon from '@/assets/images/workflow/condition.png'; import iterationIcon from '@/assets/images/workflow/iteration.png'; import loopIcon from '@/assets/images/workflow/loop.png'; // import parallelIcon from '@/assets/images/workflow/parallel.png'; import aggregatorIcon from '@/assets/images/workflow/aggregator.png'; import httpRequestIcon from '@/assets/images/workflow/http_request.png'; import toolsIcon from '@/assets/images/workflow/tools.png'; import codeExecutionIcon from '@/assets/images/workflow/code_execution.png'; import templateRenderingIcon from '@/assets/images/workflow/template_rendering.png'; // import sensitiveDetectionIcon from '@/assets/images/workflow/sensitive_detection.png'; // import outputAuditIcon from '@/assets/images/workflow/output_audit.png'; // import selfOptimizationIcon from '@/assets/images/workflow/self_optimization.png'; // import processEvolutionIcon from '@/assets/images/workflow/process_evolution.png'; import questionClassifierIcon from '@/assets/images/workflow/question-classifier.png' import breakIcon from '@/assets/images/workflow/break.png' import assignerIcon from '@/assets/images/workflow/assigner.png' import memoryReadIcon from '@/assets/images/workflow/memory-read.png' import memoryWriteIcon from '@/assets/images/workflow/memory-write.png' import unknownIcon from '@/assets/images/workflow/unknown.svg' import { memoryConfigListUrl } from '@/api/memory' import { getModelListUrl } from '@/api/models' import type { NodeLibrary } from './types' /** * Workflow node library configuration * Defines all available node types, their icons, and configuration schemas */ export const nodeLibrary: NodeLibrary[] = [ { category: "coreNode", nodes: [ { type: "start", icon: startIcon, config: { variables: { type: 'define', sys: [ { name: "message", type: "string", readonly: true }, { name: "conversation_id", type: "string", readonly: true }, { name: "execution_id", type: "string", readonly: true }, { name: "workspace_id", type: "string", readonly: true }, { name: "user_id", type: "string", readonly: true }, { name: "files", type: "array[file]", readonly: true }, ], defaultValue: [] } } }, { type: "end", icon: endIcon, config: { output: { type: 'editor' } } }, // { type: "answer", icon: answerIcon }, ] }, { category: "aiAndCognitiveProcessing", nodes: [ { type: "llm", icon: llmIcon, config: { model_id: { type: 'customSelect', url: getModelListUrl, params: { type: 'llm,chat', pagesize: 100, is_active: true }, // llm/chat valueKey: 'id', labelKey: 'name', }, temperature: { type: 'slider', max: 2, min: 0, step: 0.1, defaultValue: 0.7 }, max_tokens: { type: 'slider', max: 32000, min: 256, step: 1, defaultValue: 2000 }, context: { type: 'variableList', placeholder: 'workflow.config.llm.contextPlaceholder' }, messages: { type: 'define', defaultValue: [ { role: 'SYSTEM', content: undefined, readonly: true }, ], placeholder: 'workflow.config.llm.messagesPlaceholder' }, memory: { type: 'memoryConfig', defaultValue: { enable: false, enable_window: false, window_size: 20 } }, vision: { type: 'switch' }, vision_input: { type: 'variableList', onFilterVariableNames: ['sys.files'] } } }, // { type: "model_selection", icon: modelSelectionIcon }, // { type: "model_voting", icon: modelVotingIcon }, { type: "knowledge-retrieval", icon: ragIcon, config: { query: { type: 'variableList', }, knowledge_retrieval: { type: 'knowledge' } } }, // { type: "classification", icon: classificationIcon }, { type: "parameter-extractor", icon: parameterExtractionIcon, config: { model_id: { type: 'customSelect', url: getModelListUrl, params: { type: 'llm,chat', pagesize: 100, is_active: true }, // llm/chat valueKey: 'id', labelKey: 'name', }, text: { type: 'variableList', filterLoopIterationVars: true, placeholder: 'workflow.config.parameter-extractor.textPlaceholder' }, params: { type: 'paramList', }, prompt: { type: 'messageEditor', isArray: false, titleVariant: 'borderless', placeholder: 'workflow.config.parameter-extractor.promptPlaceholder' }, } } ] }, { category: "cognitiveUpgrading", nodes: [ { type: "memory-read", icon: memoryReadIcon, config: { message: { type: 'editor', isArray: false }, config_id: { type: 'customSelect', url: memoryConfigListUrl, valueKey: 'config_id', labelKey: 'config_name' }, search_switch: { type: 'select', options: [ { value: '0', label: 'memoryConversation.deepThinking' }, { value: '1', label: 'memoryConversation.normalReply' }, { value: '2', label: 'memoryConversation.quickReply' }, ], needTranslation: true } } }, { type: "memory-write", icon: memoryWriteIcon, config: { message: { type: 'editor', isArray: false, hidden: true, }, messages: { type: 'messageEditor', defaultValue: [], placeholder: 'workflow.config.llm.messagesPlaceholder', isArray: true }, config_id: { type: 'customSelect', url: memoryConfigListUrl, valueKey: 'config_id', labelKey: 'config_name' } } }, ] }, // { // category: "agentCollaborationNode", // nodes: [ // { type: "agent_scheduling", icon: agentSchedulingIcon }, // { type: "agent_collaboration", icon: agentCollaborationIcon }, // { type: "agent_arbitration", icon: agentArbitrationIcon } // ] // }, { category: "flowControl", nodes: [ { type: "if-else", icon: conditionIcon, config: { cases: { type: 'caseList', defaultValue: [ { logical_operator: 'and', expressions: [] } ] } } }, { type: "question-classifier", icon: questionClassifierIcon, config: { model_id: { type: 'customSelect', url: getModelListUrl, params: { type: 'llm,chat', pagesize: 100, is_active: true }, // llm/chat valueKey: 'id', labelKey: 'name', }, input_variable: { type: 'variableList', }, categories: { type: 'categoryList', defaultValue: [ {}, {} ] }, user_supplement_prompt: { type: 'messageEditor', isArray: false, titleVariant: 'borderless' } } }, { type: "iteration", icon: iterationIcon, config: { input: { type: 'variableList', filterNodeTypes: ['knowledge-retrieval', 'iteration', 'loop', 'parameter-extractor', 'code', 'CONVERSATION'], filterVariableNames: ['message'] }, parallel: { type: 'switch', defaultValue: false }, parallel_count: { type: 'slider', min: 1, max: 10, step: 1, defaultValue: 10, dependsOn: 'parallel', dependsOnValue: true }, flatten: { // Flatten output type: 'switch', defaultValue: false }, output: { type: 'variableList', filterChildNodes: true }, output_type: { type: 'define', } }, }, { type: "loop", icon: loopIcon, config: { cycle_vars: { type: 'cycleVarsList', defaultValue: [] }, condition: { type: 'conditionList', showLabel: true, defaultValue: { logical_operator: 'and', expressions: [] } }, max_loop: { type: 'slider', min: 1, max: 100, step: 1, defaultValue: 10 }, } }, { type: "cycle-start", icon: loopIcon }, { type: "break", icon: breakIcon }, // { type: "parallel", icon: parallelIcon }, { type: "var-aggregator", icon: aggregatorIcon, config: { group: { type: 'switch', defaultValue: false }, group_variables: { type: 'groupVariableList', defaultValue: [], }, group_type: { type: 'define', } } }, { type: "assigner", icon: assignerIcon, config: { assignments: { type: 'assignmentList', filterLoopIterationVars: true } } }, ] }, { category: "externalInteraction", nodes: [ { type: "http-request", icon: httpRequestIcon, config: { method: { type: 'select', options: [ { label: 'GET', value: 'GET' }, { label: 'POST', value: 'POST' }, { label: 'HEAD', value: 'HEAD' }, { label: 'PATCH', value: 'PATCH' }, { label: 'PUT', value: 'PUT' }, { label: 'DELETE', value: 'DELETE' }, ], defaultValue: 'GET' }, url: { type: 'messageEditor', isArray: false, }, auth: { type: 'define', defaultValue: { auth_type: 'none' } }, headers: { type: 'define', defaultValue: [] }, params: { type: 'define', defaultValue: [] }, body: { type: 'define', defaultValue: { 'content_type': 'none' } }, verify_ssl: { type: 'switch', defaultValue: false }, timeouts: { type: 'define', defaultValue: {} }, retry: { type: 'switch', defaultValue: { enable: false } }, error_handle: { type: 'define', defaultValue: { method: 'none' } } } }, { type: "tool", icon: toolsIcon, config: { tool_id: { type: 'cascader' }, tool_parameters: { type: 'define' } } }, { type: "code", icon: codeExecutionIcon, config: { input_variables: { type: 'inputList', defaultValue: [{ name: 'arg1' }, { name: 'arg2' }] }, language: { type: 'select', defaultValue: 'python3' }, code: { type: 'messageEditor', isArray: false, language: ['python3', 'javascript'], titleVariant: 'borderless', defaultValue: `def main(arg1: str, arg2: str): return { "result": arg1 + arg2, }` }, output_variables: { type: 'outputList', defaultValue: [{name: 'result', type: 'string'}] }, } }, { type: "jinja-render", icon: templateRenderingIcon, config: { mapping: { type: 'mappingList', defaultValue: [{name: 'arg1'}] }, template: { type: 'messageEditor', isArray: false, language: 'jinja2', titleVariant: 'borderless', defaultValue: "{{arg1}}" }, } }, ] }, // { // category: "safetyAndCompliance", // nodes: [ // { type: "sensitive_detection", icon: sensitiveDetectionIcon }, // { type: "output_audit", icon: outputAuditIcon } // ] // }, // { // category: "evolutionAndGovernance", // nodes: [ // { type: "self_optimization", icon: selfOptimizationIcon }, // { type: "process_evolution", icon: processEvolutionIcon } // ] // }, ]; export const unknownNode = { type: 'unknown', icon: unknownIcon } export const noteNode = { type: 'notes', icon: unknownIcon } export const nodeWidth = 240; /** * Node registration library for X6 graph * Maps node shapes to their React components */ export const nodeRegisterLibrary: ReactShapeConfig[] = [ { shape: 'loop-node', width: nodeWidth, height: 120, component: LoopNode, }, { shape: 'iteration-node', width: nodeWidth, height: 120, component: LoopNode, }, { shape: 'normal-node', width: 120, height: 40, component: NormalNode, }, { shape: 'condition-node', width: nodeWidth, height: 88, component: ConditionNode, }, { shape: 'cycle-start', width: 44, height: 44, component: GroupStartNode, }, { shape: 'add-node', width: 88, height: 44, component: AddNode, }, ]; /** * Port configuration interface */ interface PortsConfig { /** Port group metadata */ groups?: GroupMetadata; /** Port item metadata array */ items?: PortMetadata[]; } /** * Node configuration interface */ interface NodeConfig { /** Node width in pixels */ width: number; /** Node height in pixels */ height: number; /** Node shape type */ shape: string; /** Port configuration */ ports?: PortsConfig; } /** Edge color for normal state */ export const edge_color = '#155EEF'; /** Edge color for selected state */ export const edge_selected_color = '#4DA8FF' /** * Unified port markup configuration * Defines SVG elements for port rendering */ export const portMarkup = [ { tagName: 'circle', selector: 'body', }, { tagName: 'text', selector: 'label', }, ]; /** * Unified port attributes configuration * Defines visual styling for ports */ export const portAttrs = { body: { r: 6, magnet: true, stroke: edge_color, strokeWidth: 2, fill: edge_color, }, label: { text: '+', fontSize: 12, fontWeight: 'bold', fill: '#FFFFFF', textAnchor: 'middle', textVerticalAnchor: 'middle', pointerEvents: 'none', }, } export const portTextAttrs = { fontSize: 12, fill: '#5B6167' } /** * Unified port group configuration * Defines port positions and attributes for different sides */ const defaultPortGroups = { // top: { position: 'top', markup: portMarkup, attrs: portAttrs }, right: { position: 'right', markup: portMarkup, attrs: portAttrs }, // bottom: { position: 'bottom', markup: portMarkup, attrs: portAttrs }, left: { position: 'left', markup: portMarkup, attrs: portAttrs }, } export const defaultAbsolutePortGroups = { // top: { position: 'top', markup: portMarkup, attrs: portAttrs }, right: { position: { name: 'absolute' }, markup: portMarkup, attrs: portAttrs }, // bottom: { position: 'bottom', markup: portMarkup, attrs: portAttrs }, left: { position: 'left', markup: portMarkup, attrs: portAttrs }, } /** * Default port items for standard nodes */ const defaultPortItems = [ // { group: 'top' }, { group: 'right' }, // { group: 'bottom' }, { group: 'left' } ]; /** * Port position arguments */ export const portArgs = { x: nodeWidth, y: 42 } /** * Graph node library configuration * Maps node types to their visual and structural properties */ export const graphNodeLibrary: Record = { iteration: { width: nodeWidth, height: 120, shape: 'iteration-node', ports: { groups: defaultPortGroups, items: defaultPortItems, }, }, loop: { width: nodeWidth, height: 120, shape: 'loop-node', ports: { groups: defaultPortGroups, items: defaultPortItems, }, }, 'if-else': { width: nodeWidth, height: 88, shape: 'condition-node', ports: { groups: defaultAbsolutePortGroups, items: [ { group: 'left' }, ...(['IF', 'ELSE'].map((text, index) => ({ group: 'right', id: `CASE${index}`, args: { ...portArgs, y: 30 * index + 42, }, attrs: { text: { text: text, ...portTextAttrs } } }))), ], }, }, 'question-classifier': { width: nodeWidth, height: 88, shape: 'condition-node', ports: { groups: defaultAbsolutePortGroups, items: [ { group: 'left' }, ...(['分类1', '分类2'].map((text, index) => ({ group: 'right', id: `CASE${index}`, args: { ...portArgs, y: 30 * index + 42, }, attrs: { text: { text: text, ...portTextAttrs } } }))), ], }, }, start: { width: nodeWidth, height: 64, shape: 'normal-node', ports: { groups: {right: { position: 'right', markup: portMarkup, attrs: portAttrs }}, items: [{ group: 'right' }], }, }, end: { width: nodeWidth, height: 64, shape: 'normal-node', ports: { groups: {left: { position: 'left', markup: portMarkup, attrs: portAttrs }}, items: [{ group: 'left' }], }, }, 'cycle-start': { width: 44, height: 44, shape: 'cycle-start', ports: { groups: {right: { position: 'right', markup: portMarkup, attrs: portAttrs }}, items: [{ group: 'right' }], }, }, 'add-node': { width: 88, height: 44, shape: 'add-node', ports: { groups: {left: { position: 'left', markup: portMarkup, attrs: portAttrs }}, items: [{ group: 'left' }], }, }, default: { width: nodeWidth, height: 64, shape: 'normal-node', ports: { groups: defaultPortGroups, items: defaultPortItems, }, }, cycleStart: { width: 44, height: 44, shape: 'cycle-start', ports: { groups: {right: { position: 'right', markup: portMarkup, attrs: portAttrs }}, items: [{ group: 'right' }], }, }, addStart: { width: 88, height: 44, shape: 'add-node', ports: { groups: {left: { position: 'left', markup: portMarkup, attrs: portAttrs }}, items: [{ group: 'left' }], }, } } /** * Output variable configuration interface */ export interface OutputVariable { /** Default output variables */ default?: Array<{ name: string; type: string; }>; /** Dynamically defined variable keys */ define?: string[]; /** System-level output variables */ sys?: Array<{ name: string; type: string; }>; /** Error-related output variables */ error?: Array<{ name: string; type: string; }>; } /** * 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 */ export const edgeAttrs = { attrs: { line: { stroke: edge_color, strokeWidth: 1, targetMarker: { name: 'block', width: 4, height: 4, }, }, }, }