digitalsee-ai-flow-cli 0.9.24-beta → 0.9.29-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +146 -2
- package/dist/api/client.js +9 -0
- package/dist/api/flow.js +4 -1
- package/dist/api/node.js +78 -7
- package/dist/api/trigger.js +242 -0
- package/dist/commands/flow/account.js +439 -1
- package/dist/commands/flow/analyze.js +10 -2
- package/dist/commands/flow/export.js +29 -4
- package/dist/commands/flow/helpers.js +439 -53
- package/dist/commands/flow/node.js +290 -32
- package/dist/commands/flow/offline.js +3 -2
- package/dist/commands/flow/trigger.js +190 -0
- package/dist/commands/flow/validate.js +57 -0
- package/dist/commands/flow/variables.js +1 -0
- package/dist/commands/flow.js +2 -0
- package/dist/constants/node-type.js +23 -0
- package/dist/services/classicNodePorts.js +167 -368
- package/dist/services/fieldTypeRegistry.js +496 -0
- package/dist/services/flowAnalyzer.js +8 -1
- package/dist/services/flowValidator.js +145 -0
- package/dist/services/portValidator.js +76 -70
- package/dist/services/skillGenerator.js +236 -194
- package/dist/services/triggerConfig.js +252 -0
- package/dist/utils/conditionRules.js +128 -0
- package/dist/utils/format.js +268 -168
- package/dist/utils/nodeEnvelope.js +128 -0
- package/dist/utils/switchBranch.js +83 -0
- package/dist/utils/updateCheck.js +50 -6
- package/package.json +1 -1
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.CLASSIC_PORT_TYPES = exports.LEGACY_HANDLE_NAME_MAP = void 0;
|
|
4
4
|
exports.normalizeLegacyHandleName = normalizeLegacyHandleName;
|
|
5
|
-
exports.
|
|
5
|
+
exports.resolveSwitchBranchOutputs = resolveSwitchBranchOutputs;
|
|
6
6
|
exports.resolveClassicNodePorts = resolveClassicNodePorts;
|
|
7
|
-
exports.
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
7
|
+
exports.isClassicSelfConnectionAllowed = isClassicSelfConnectionAllowed;
|
|
8
|
+
const nodeEnvelope_1 = require("@/utils/nodeEnvelope");
|
|
9
|
+
const switchBranch_1 = require("@/utils/switchBranch");
|
|
10
|
+
/**
|
|
11
|
+
* 经典节点静态端口表(对齐 rcs nodeTypeRegistry.tsx CLASSIC_DESCRIPTORS)。
|
|
12
|
+
*
|
|
13
|
+
* 覆盖 legacy 节点(无 action_key/action_ver)的端口校验回退:
|
|
14
|
+
* - ConditionNode:出桩 true/false(max=1)
|
|
15
|
+
* - LoopNode / SelfLoopNode:出桩 done/loop(max=1),loop→input 自环允许
|
|
16
|
+
* - AgentNode / BrowserNode:底部 ai_model/ai_memory/ai_tool slave 入桩
|
|
17
|
+
* - MCP 系:MCPServer/MCP_TRIGGER_NODE(builtin_mcp 出桩)、BuiltinMCP、
|
|
18
|
+
* MCP_TOOL/MCP_TOOLS_NODE(builtin_mcp 入桩 + main 出桩)
|
|
19
|
+
* - SwitchNode:动态分支端口 = branches[].id + default-branch
|
|
20
|
+
*/
|
|
16
21
|
/**
|
|
17
22
|
* 废弃 handle 名迁移表(对齐 RCS useDataLoading REPLACE_HANDLE_MAP):
|
|
18
23
|
* 旧数据的 sourceHandle/targetHandle 可能仍是 chat_model/memory/tools,
|
|
@@ -29,385 +34,179 @@ function normalizeLegacyHandleName(handle) {
|
|
|
29
34
|
return undefined;
|
|
30
35
|
return exports.LEGACY_HANDLE_NAME_MAP[handle] ?? handle;
|
|
31
36
|
}
|
|
32
|
-
/**
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
* 指向 AI 子节点顶部 input 桩。ai_tool 允许多协议(临时兼容,对齐 RCS)
|
|
58
|
-
*/
|
|
59
|
-
const AGENT_INPUTS = [{ name: 'input', displayName: '输入' }];
|
|
60
|
-
const AGENT_OUTPUTS = [
|
|
61
|
-
{ name: 'output', displayName: '输出', maxConnections: 1 },
|
|
62
|
-
{ name: 'ai_model', displayName: 'Chat Model', type: 'AI_LANGUAGE_MODEL', maxConnections: 1 },
|
|
63
|
-
{ name: 'ai_memory', displayName: 'Memory', type: 'AI_MEMORY', maxConnections: 1 },
|
|
37
|
+
/** rcs NodeProtocol(enums/node.ts)取值 */
|
|
38
|
+
exports.CLASSIC_PORT_TYPES = {
|
|
39
|
+
MAIN: 'main',
|
|
40
|
+
AI_LANGUAGE_MODEL: 'AI_LANGUAGE_MODEL',
|
|
41
|
+
AI_VECTOR_STORE: 'AI_VECTORSTORE',
|
|
42
|
+
AI_MEMORY: 'AI_MEMORY',
|
|
43
|
+
AI_TOOL: 'AI_TOOL',
|
|
44
|
+
BUILTIN_MCP: 'BUILTIN_MCP',
|
|
45
|
+
MCP_SERVER: 'MCP_SERVER',
|
|
46
|
+
};
|
|
47
|
+
const port = (p) => ({
|
|
48
|
+
name: p.name,
|
|
49
|
+
type: p.type ?? exports.CLASSIC_PORT_TYPES.MAIN,
|
|
50
|
+
maxConnections: p.max === undefined ? null : p.max,
|
|
51
|
+
});
|
|
52
|
+
const ports = (list) => list.map(port);
|
|
53
|
+
const MAIN_IN = { name: 'input', max: 1 };
|
|
54
|
+
const MAIN_OUT = { name: 'output', max: 1 };
|
|
55
|
+
const LOOP_SELF_CONNECTIONS = [{ source: 'loop', target: 'input' }];
|
|
56
|
+
/** Agent/Browser 底部 slave 入桩(协议对齐 rcs AGENT_INPUTS/BROWSER_INPUTS)。
|
|
57
|
+
* ai_tool 为多协议桩(RCS 6fc6de5 后):AI_TOOL 与 BUILTIN_MCP 链路均合法 */
|
|
58
|
+
const AI_SLAVE_INPUTS = [
|
|
59
|
+
MAIN_IN,
|
|
60
|
+
{ name: 'ai_model', type: exports.CLASSIC_PORT_TYPES.AI_LANGUAGE_MODEL, max: 1 },
|
|
61
|
+
{ name: 'ai_memory', type: exports.CLASSIC_PORT_TYPES.AI_MEMORY, max: 1 },
|
|
64
62
|
{
|
|
65
63
|
name: 'ai_tool',
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
maxConnections: 10,
|
|
64
|
+
type: `${exports.CLASSIC_PORT_TYPES.AI_TOOL},${exports.CLASSIC_PORT_TYPES.BUILTIN_MCP}`,
|
|
65
|
+
max: 1,
|
|
69
66
|
},
|
|
70
67
|
];
|
|
71
|
-
/**
|
|
72
|
-
const
|
|
73
|
-
const
|
|
74
|
-
{ name: '
|
|
75
|
-
{ name: 'ai_model', displayName: 'Chat Model', type: 'AI_LANGUAGE_MODEL', maxConnections: 1 },
|
|
68
|
+
/** MCPServer / MCP_TRIGGER_NODE:顶部 MCP_SERVER 入桩,底部 BUILTIN_MCP 出桩(不限连接数) */
|
|
69
|
+
const MCP_SERVER_INPUTS = [{ name: 'input', type: exports.CLASSIC_PORT_TYPES.MCP_SERVER }];
|
|
70
|
+
const MCP_SERVER_OUTPUTS = [
|
|
71
|
+
{ name: 'builtin_mcp', type: exports.CLASSIC_PORT_TYPES.BUILTIN_MCP },
|
|
76
72
|
];
|
|
77
|
-
/**
|
|
78
|
-
const
|
|
79
|
-
name: 'input',
|
|
80
|
-
displayName: '输入',
|
|
81
|
-
type: protocol,
|
|
82
|
-
maxConnections,
|
|
83
|
-
});
|
|
84
|
-
/**
|
|
85
|
-
* MCP 网关系列(RCS 6fc6de5 后):builtin_mcp 顶部入桩(TARGET,BUILTIN_MCP 协议,max 1),
|
|
86
|
-
* 连线源为 Agent ai_tool(多协议含 BUILTIN_MCP)等
|
|
87
|
-
*/
|
|
88
|
-
const MCP_BUILTIN_MCP_INPUTS = [
|
|
89
|
-
{ name: 'builtin_mcp', displayName: '输入', type: 'BUILTIN_MCP', maxConnections: 1 },
|
|
90
|
-
];
|
|
91
|
-
/** BuiltinMCP:builtin_mcp 入桩 max 1,output 主出桩 max 10(协议 main) */
|
|
73
|
+
/** BuiltinMCP:顶部 main 入桩,底部 BUILTIN_MCP 出桩(max=1) */
|
|
74
|
+
const BUILTIN_MCP_INPUTS = [MAIN_IN];
|
|
92
75
|
const BUILTIN_MCP_OUTPUTS = [
|
|
93
|
-
{ name: '
|
|
94
|
-
];
|
|
95
|
-
/** MCPTool / MCP_TOOLS_NODE:BUILTIN_MCP 入桩,main 出桩 */
|
|
96
|
-
const MCP_TOOL_INPUTS = [
|
|
97
|
-
{ name: 'input', displayName: '输入', type: 'BUILTIN_MCP' },
|
|
76
|
+
{ name: 'builtin_mcp', type: exports.CLASSIC_PORT_TYPES.BUILTIN_MCP, max: 1 },
|
|
98
77
|
];
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
];
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
exports.CLASSIC_NODE_DESCRIPTORS = {
|
|
111
|
-
StartEventNode: {
|
|
112
|
-
nodeType: 'StartEventNode',
|
|
113
|
-
label: '触发器节点',
|
|
114
|
-
description: '流程触发起点,无输入端口,单输出口',
|
|
115
|
-
inputs: EMPTY_PORTS,
|
|
116
|
-
outputs: TRIGGER_OUTPUTS,
|
|
117
|
-
},
|
|
118
|
-
ActionNode: {
|
|
119
|
-
nodeType: 'ActionNode',
|
|
120
|
-
label: '动作节点',
|
|
121
|
-
description: '常规动作节点;MCP return-variable 协议形态无输出端口',
|
|
122
|
-
inputs: ACTION_INPUTS,
|
|
123
|
-
outputs: ACTION_OUTPUTS,
|
|
124
|
-
byProtocol: NO_OUTPUT_PROTOCOLS,
|
|
125
|
-
},
|
|
126
|
-
ConditionNode: {
|
|
127
|
-
nodeType: 'ConditionNode',
|
|
128
|
-
label: '条件节点',
|
|
129
|
-
description: '条件分支,true/false 双出口',
|
|
130
|
-
inputs: ACTION_INPUTS,
|
|
131
|
-
outputs: CONDITION_OUTPUTS,
|
|
132
|
-
},
|
|
133
|
-
LoopNode: {
|
|
134
|
-
nodeType: 'LoopNode',
|
|
135
|
-
label: '循环节点',
|
|
136
|
-
description: '循环控制,done 出口走完流程,loop 出口配合 input 形成自环',
|
|
137
|
-
inputs: ACTION_INPUTS,
|
|
138
|
-
outputs: LOOP_OUTPUTS,
|
|
139
|
-
autoConnect: LOOP_AUTO_CONNECT,
|
|
140
|
-
},
|
|
141
|
-
SelfLoopNode: {
|
|
142
|
-
nodeType: 'SelfLoopNode',
|
|
143
|
-
label: '自环节点',
|
|
144
|
-
description: '自循环控制,loop → input 自环边为必需结构',
|
|
145
|
-
inputs: ACTION_INPUTS,
|
|
146
|
-
outputs: LOOP_OUTPUTS,
|
|
147
|
-
autoConnect: LOOP_AUTO_CONNECT,
|
|
148
|
-
},
|
|
149
|
-
SwitchNode: {
|
|
150
|
-
nodeType: 'SwitchNode',
|
|
151
|
-
label: '多分支节点',
|
|
152
|
-
description: '多路由分支;输出端口来自 properties.branches[].id(实例派生),default-branch 固定兜底',
|
|
153
|
-
inputs: ACTION_INPUTS,
|
|
154
|
-
outputs: SWITCH_DEFAULT_OUTPUTS,
|
|
155
|
-
},
|
|
156
|
-
AgentNode: {
|
|
157
|
-
nodeType: 'AgentNode',
|
|
158
|
-
label: 'Agent 节点',
|
|
159
|
-
description: 'AI Agent;底部 slave 桩(ai_model/ai_memory/ai_tool)为连线源,指向 AI 子节点顶部 input 桩;ai_tool 支持多协议(AI_TOOL,KNOWLEDGE,MCP_SERVER,BUILTIN_MCP)',
|
|
160
|
-
inputs: AGENT_INPUTS,
|
|
161
|
-
outputs: AGENT_OUTPUTS,
|
|
162
|
-
},
|
|
163
|
-
BrowserNode: {
|
|
164
|
-
nodeType: 'BrowserNode',
|
|
165
|
-
label: '浏览器节点',
|
|
166
|
-
description: 'AI 浏览器操作;ai_model slave 桩为连线源,指向 AISubNode 顶部 input 桩(协议 AI_LANGUAGE_MODEL)',
|
|
167
|
-
inputs: BROWSER_INPUTS,
|
|
168
|
-
outputs: BROWSER_OUTPUTS,
|
|
169
|
-
},
|
|
170
|
-
AISubNode: {
|
|
171
|
-
nodeType: 'AISubNode',
|
|
172
|
-
label: 'AI 配置子节点',
|
|
173
|
-
description: 'AI 配置子节点(模型/记忆/工具);顶部 input 桩接收 Agent slave 桩连线,协议随类型(AI_TOOL 形态 max 10)',
|
|
174
|
-
inputs: [aiSubInput('AI_LANGUAGE_MODEL', 1)],
|
|
175
|
-
outputs: EMPTY_PORTS,
|
|
176
|
-
byProtocol: {
|
|
177
|
-
AI_MEMORY: { inputs: [aiSubInput('AI_MEMORY')] },
|
|
178
|
-
AI_TOOL: { inputs: [aiSubInput('AI_TOOL', 10)] },
|
|
179
|
-
},
|
|
180
|
-
},
|
|
181
|
-
VectorStoreNode: {
|
|
182
|
-
nodeType: 'VectorStoreNode',
|
|
183
|
-
label: '向量存储节点',
|
|
184
|
-
description: '向量存储子节点;protocol=AI_VECTORSTORE 时顶部 input 桩接收 Agent slave 桩连线',
|
|
185
|
-
inputs: EMPTY_PORTS,
|
|
186
|
-
outputs: EMPTY_PORTS,
|
|
187
|
-
byProtocol: {
|
|
188
|
-
// 注意拼写:对齐 RCS NodeProtocol.AI_VECTOR_STORE = 'AI_VECTORSTORE'
|
|
189
|
-
AI_VECTORSTORE: { inputs: [aiSubInput('AI_VECTORSTORE')] },
|
|
190
|
-
},
|
|
191
|
-
},
|
|
192
|
-
MCPServerNode: {
|
|
193
|
-
nodeType: 'MCPServerNode',
|
|
194
|
-
label: 'MCP 服务节点',
|
|
195
|
-
description: '旧 MCP 网关服务;builtin_mcp 入桩(BUILTIN_MCP 协议)max 1,无出桩',
|
|
196
|
-
inputs: MCP_BUILTIN_MCP_INPUTS,
|
|
197
|
-
outputs: EMPTY_PORTS,
|
|
198
|
-
},
|
|
199
|
-
MCP_TRIGGER_NODE: {
|
|
200
|
-
nodeType: 'MCP_TRIGGER_NODE',
|
|
201
|
-
label: 'MCP 网关触发节点',
|
|
202
|
-
description: '旧 MCP 网关触发形态;builtin_mcp 入桩(BUILTIN_MCP 协议)max 1,无出桩',
|
|
203
|
-
inputs: MCP_BUILTIN_MCP_INPUTS,
|
|
204
|
-
outputs: EMPTY_PORTS,
|
|
205
|
-
},
|
|
206
|
-
BuiltinMCPNode: {
|
|
207
|
-
nodeType: 'BuiltinMCPNode',
|
|
208
|
-
label: '内置 MCP 节点',
|
|
209
|
-
description: '内置 MCP 工具节点;builtin_mcp 入桩(BUILTIN_MCP 协议)max 1,output 主出桩 max 10',
|
|
210
|
-
inputs: MCP_BUILTIN_MCP_INPUTS,
|
|
211
|
-
outputs: BUILTIN_MCP_OUTPUTS,
|
|
212
|
-
},
|
|
213
|
-
MCPToolNode: {
|
|
214
|
-
nodeType: 'MCPToolNode',
|
|
215
|
-
label: 'MCP 工具节点',
|
|
216
|
-
description: 'MCP 工具调用;BUILTIN_MCP 入桩,MCP return-variable 形态无出桩',
|
|
217
|
-
inputs: MCP_TOOL_INPUTS,
|
|
218
|
-
outputs: MCP_TOOL_OUTPUTS,
|
|
219
|
-
byProtocol: NO_OUTPUT_PROTOCOLS,
|
|
220
|
-
},
|
|
221
|
-
MCP_TOOLS_NODE: {
|
|
222
|
-
nodeType: 'MCP_TOOLS_NODE',
|
|
223
|
-
label: 'MCP 网关工具列表节点',
|
|
224
|
-
description: 'MCP 网关工具列表形态,端口与 MCPToolNode 一致',
|
|
225
|
-
inputs: MCP_TOOL_INPUTS,
|
|
226
|
-
outputs: MCP_TOOL_OUTPUTS,
|
|
227
|
-
byProtocol: NO_OUTPUT_PROTOCOLS,
|
|
228
|
-
},
|
|
229
|
-
StickyNoteNode: {
|
|
230
|
-
nodeType: 'StickyNoteNode',
|
|
231
|
-
label: '便签节点',
|
|
232
|
-
description: '画布便签,无端口',
|
|
233
|
-
inputs: EMPTY_PORTS,
|
|
234
|
-
outputs: EMPTY_PORTS,
|
|
235
|
-
},
|
|
236
|
-
};
|
|
237
|
-
function toNodeSchemaPort(spec) {
|
|
238
|
-
return {
|
|
239
|
-
name: spec.name,
|
|
240
|
-
display_name: spec.displayName,
|
|
241
|
-
type: spec.type ?? 'main',
|
|
242
|
-
...(spec.maxConnections !== undefined && spec.maxConnections !== null
|
|
243
|
-
? { max_connections: spec.maxConnections }
|
|
244
|
-
: {}),
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
|
-
/** node_type 是否命中内置表 */
|
|
248
|
-
function isClassicNodeType(nodeType) {
|
|
249
|
-
return (Boolean(nodeType) &&
|
|
250
|
-
Object.prototype.hasOwnProperty.call(exports.CLASSIC_NODE_DESCRIPTORS, nodeType));
|
|
251
|
-
}
|
|
252
|
-
/**
|
|
253
|
-
* 按 (node_type, protocol) 解析端口声明。
|
|
254
|
-
* protocol 缺失或未命中 byProtocol 时回退 type 级默认;未知 node_type 返回 null。
|
|
255
|
-
*/
|
|
256
|
-
function resolveClassicNodePorts(node) {
|
|
257
|
-
const descriptor = node.node_type ? exports.CLASSIC_NODE_DESCRIPTORS[node.node_type] : undefined;
|
|
258
|
-
if (!descriptor)
|
|
259
|
-
return null;
|
|
260
|
-
const protocol = node.protocol?.trim();
|
|
261
|
-
if (protocol) {
|
|
262
|
-
const override = descriptor.byProtocol?.[protocol];
|
|
263
|
-
if (override) {
|
|
264
|
-
return {
|
|
265
|
-
inputs: override.inputs ?? descriptor.inputs,
|
|
266
|
-
outputs: override.outputs ?? descriptor.outputs,
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
return { inputs: descriptor.inputs, outputs: descriptor.outputs };
|
|
78
|
+
/** MCP_TOOL / MCP_TOOLS_NODE:顶部 BUILTIN_MCP 入桩,底部 main 出桩 */
|
|
79
|
+
const MCP_TOOL_INPUTS = [{ name: 'input', type: exports.CLASSIC_PORT_TYPES.BUILTIN_MCP }];
|
|
80
|
+
const MCP_TOOL_OUTPUTS = [MAIN_OUT];
|
|
81
|
+
const NO_PORTS = { inputs: [], outputs: [], selfConnections: [] };
|
|
82
|
+
/** protocol 覆盖:MCP return-variable 等形态无出桩(rcs byProtocol 语义) */
|
|
83
|
+
const EMPTY_OUTPUTS_PROTOCOLS = new Set([
|
|
84
|
+
exports.CLASSIC_PORT_TYPES.BUILTIN_MCP,
|
|
85
|
+
exports.CLASSIC_PORT_TYPES.MCP_SERVER,
|
|
86
|
+
]);
|
|
87
|
+
function basePorts(inputs, outputs, selfConnections = []) {
|
|
88
|
+
return { inputs: ports(inputs), outputs: ports(outputs), selfConnections };
|
|
271
89
|
}
|
|
272
|
-
/**
|
|
273
|
-
function
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
const normalized = [];
|
|
277
|
-
const usedIds = new Set([exports.SWITCH_DEFAULT_BRANCH_HANDLE]);
|
|
278
|
-
let migrated = 0;
|
|
279
|
-
for (const item of branches) {
|
|
280
|
-
if (!item || typeof item !== 'object')
|
|
281
|
-
continue;
|
|
282
|
-
const branch = item;
|
|
283
|
-
let id = String(branch.id ?? '');
|
|
284
|
-
const name = String(branch.name ?? '').trim() || `分支 ${normalized.length + 1}`;
|
|
285
|
-
if (!id.startsWith('branch') || id === exports.SWITCH_DEFAULT_BRANCH_HANDLE || usedIds.has(id)) {
|
|
286
|
-
do {
|
|
287
|
-
migrated++;
|
|
288
|
-
id = `branch-migrated-${migrated}`;
|
|
289
|
-
} while (usedIds.has(id));
|
|
290
|
-
}
|
|
291
|
-
usedIds.add(id);
|
|
292
|
-
normalized.push({ id, name });
|
|
90
|
+
/** 节点 data.protocol → 端口覆盖(rcs resolveNodePorts byProtocol 分支) */
|
|
91
|
+
function applyProtocolOverride(base, protocol) {
|
|
92
|
+
if (!protocol || !EMPTY_OUTPUTS_PROTOCOLS.has(protocol)) {
|
|
93
|
+
return base;
|
|
293
94
|
}
|
|
294
|
-
return
|
|
95
|
+
return { ...base, outputs: [] };
|
|
295
96
|
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
const
|
|
299
|
-
|
|
300
|
-
if (!candidate || typeof candidate !== 'object' || Array.isArray(candidate))
|
|
301
|
-
continue;
|
|
302
|
-
const unwrapped = unwrapPropertiesLayer(candidate);
|
|
303
|
-
if (Array.isArray(unwrapped?.branches))
|
|
304
|
-
return unwrapped;
|
|
305
|
-
}
|
|
306
|
-
return undefined;
|
|
97
|
+
function readProtocol(node) {
|
|
98
|
+
const raw = (node.properties ?? {});
|
|
99
|
+
const protocol = raw.protocol;
|
|
100
|
+
return typeof protocol === 'string' && protocol ? protocol : undefined;
|
|
307
101
|
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
102
|
+
/** 从 properties(含 NodePackage 信封形态)提取 branches[].id(rcs switchNodePackage 语义) */
|
|
103
|
+
function readSwitchBranchIds(node) {
|
|
104
|
+
const props = (node.properties ?? {});
|
|
105
|
+
if (!props || typeof props !== 'object')
|
|
106
|
+
return [];
|
|
107
|
+
let container = props;
|
|
108
|
+
if (!Array.isArray(container.branches)) {
|
|
109
|
+
const unwrapped = (0, nodeEnvelope_1.unwrapNodePackagePropertiesEnvelope)(props);
|
|
110
|
+
if (unwrapped !== props &&
|
|
111
|
+
unwrapped &&
|
|
112
|
+
typeof unwrapped === 'object' &&
|
|
113
|
+
Array.isArray(unwrapped.branches)) {
|
|
114
|
+
container = unwrapped;
|
|
115
|
+
}
|
|
322
116
|
}
|
|
323
|
-
|
|
117
|
+
if (!Array.isArray(container.branches))
|
|
118
|
+
return [];
|
|
119
|
+
return container.branches
|
|
120
|
+
.map((branch) => {
|
|
121
|
+
if (!branch || typeof branch !== 'object' || Array.isArray(branch))
|
|
122
|
+
return null;
|
|
123
|
+
const id = branch.id;
|
|
124
|
+
return typeof id === 'string' && id ? id : null;
|
|
125
|
+
})
|
|
126
|
+
.filter((id) => id !== null);
|
|
324
127
|
}
|
|
325
128
|
/**
|
|
326
|
-
*
|
|
327
|
-
*
|
|
328
|
-
* default-branch 固定追加在末尾;branches 为空时仅返回 [defaultPort]。
|
|
129
|
+
* SwitchNode 动态分支端口派生:端口 = branches[].id + default-branch
|
|
130
|
+
* (对齐 rcs resolveSwitchNodePackagePortSchema,分支端口 max=1)
|
|
329
131
|
*/
|
|
330
|
-
function
|
|
331
|
-
const template = options?.template ?? {
|
|
332
|
-
name: 'branch-1',
|
|
333
|
-
display_name: '分支',
|
|
334
|
-
type: 'main',
|
|
335
|
-
max_connections: 1,
|
|
336
|
-
};
|
|
337
|
-
const defaultPort = options?.defaultPort ?? {
|
|
338
|
-
name: exports.SWITCH_DEFAULT_BRANCH_HANDLE,
|
|
339
|
-
display_name: 'default',
|
|
340
|
-
type: 'main',
|
|
341
|
-
max_connections: 1,
|
|
342
|
-
};
|
|
132
|
+
function resolveSwitchBranchOutputs(branchIds) {
|
|
343
133
|
return [
|
|
344
|
-
...
|
|
345
|
-
|
|
346
|
-
name: branch.id,
|
|
347
|
-
display_name: branch.name,
|
|
348
|
-
})),
|
|
349
|
-
defaultPort,
|
|
134
|
+
...branchIds.map((id) => port({ name: id, max: 1 })),
|
|
135
|
+
port({ name: switchBranch_1.DEFAULT_BRANCH_HANDLE, max: 1 }),
|
|
350
136
|
];
|
|
351
137
|
}
|
|
352
138
|
/**
|
|
353
|
-
*
|
|
354
|
-
*
|
|
139
|
+
* 按 (node_type, protocol, branches) 解析经典节点端口表。
|
|
140
|
+
*
|
|
141
|
+
* node_type 为 rcs NodeType 枚举值(如 'ConditionNode'、'LoopNode')。
|
|
142
|
+
* 未知类型返回 null(调用方回退行为不回退)。
|
|
355
143
|
*/
|
|
356
|
-
function
|
|
357
|
-
const
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
144
|
+
function resolveClassicNodePorts(node) {
|
|
145
|
+
const nodeType = node.node_type || 'ActionNode';
|
|
146
|
+
const protocol = readProtocol(node);
|
|
147
|
+
let base;
|
|
148
|
+
switch (nodeType) {
|
|
149
|
+
case 'ActionNode':
|
|
150
|
+
case 'dynamic':
|
|
151
|
+
case 'custom':
|
|
152
|
+
base = basePorts([MAIN_IN], [MAIN_OUT]);
|
|
153
|
+
break;
|
|
154
|
+
case 'StartEventNode':
|
|
155
|
+
base = basePorts([], [MAIN_OUT]);
|
|
156
|
+
break;
|
|
157
|
+
case 'ConditionNode':
|
|
158
|
+
base = basePorts([MAIN_IN], [
|
|
159
|
+
{ name: 'true', max: 1 },
|
|
160
|
+
{ name: 'false', max: 1 },
|
|
161
|
+
]);
|
|
162
|
+
break;
|
|
163
|
+
case 'LoopNode':
|
|
164
|
+
case 'SelfLoopNode':
|
|
165
|
+
base = basePorts([MAIN_IN], [
|
|
166
|
+
{ name: 'done', max: 1 },
|
|
167
|
+
{ name: 'loop', max: 1 },
|
|
168
|
+
], LOOP_SELF_CONNECTIONS);
|
|
169
|
+
break;
|
|
170
|
+
case 'SwitchNode': {
|
|
171
|
+
const branchIds = readSwitchBranchIds(node);
|
|
172
|
+
base = basePorts([MAIN_IN], resolveSwitchBranchOutputs(branchIds));
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
case 'AgentNode':
|
|
176
|
+
case 'BrowserNode':
|
|
177
|
+
base = basePorts(AI_SLAVE_INPUTS, [MAIN_OUT]);
|
|
178
|
+
break;
|
|
179
|
+
case 'AISubNode':
|
|
180
|
+
case 'VectorStoreNode':
|
|
181
|
+
// AI 子节点只有出桩;协议由 data.protocol 决定(默认 AI_LANGUAGE_MODEL)
|
|
182
|
+
base = basePorts([], [{ name: 'ai_model', type: protocol ?? exports.CLASSIC_PORT_TYPES.AI_LANGUAGE_MODEL, max: 1 }]);
|
|
183
|
+
break;
|
|
184
|
+
case 'StickyNoteNode':
|
|
185
|
+
return NO_PORTS;
|
|
186
|
+
case 'MCPServerNode':
|
|
187
|
+
case 'MCP_TRIGGER_NODE':
|
|
188
|
+
base = basePorts(MCP_SERVER_INPUTS, MCP_SERVER_OUTPUTS);
|
|
189
|
+
break;
|
|
190
|
+
case 'BuiltinMCPNode':
|
|
191
|
+
base = basePorts(BUILTIN_MCP_INPUTS, BUILTIN_MCP_OUTPUTS);
|
|
192
|
+
break;
|
|
193
|
+
case 'MCPToolNode':
|
|
194
|
+
case 'MCP_TOOLS_NODE':
|
|
195
|
+
base = basePorts(MCP_TOOL_INPUTS, MCP_TOOL_OUTPUTS);
|
|
196
|
+
break;
|
|
197
|
+
default:
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
return applyProtocolOverride(base, protocol);
|
|
381
201
|
}
|
|
382
202
|
/**
|
|
383
|
-
*
|
|
384
|
-
*
|
|
203
|
+
* 判断自环边是否被节点 auto_connect 规则声明
|
|
204
|
+
* (对齐 rcs connectionCheck.ts / nodeAutoConnect.ts isSelfConnectionAllowed 语义)。
|
|
385
205
|
*/
|
|
386
|
-
function
|
|
387
|
-
if (
|
|
388
|
-
return
|
|
389
|
-
const
|
|
390
|
-
|
|
391
|
-
return schema;
|
|
392
|
-
const schemaOutputs = schema.outputs ?? [];
|
|
393
|
-
const template = schemaOutputs.find((port) => port.name !== exports.SWITCH_DEFAULT_BRANCH_HANDLE) ??
|
|
394
|
-
{ name: 'branch-1', display_name: '分支', type: 'main' };
|
|
395
|
-
const defaultPort = schemaOutputs.find((port) => port.name === exports.SWITCH_DEFAULT_BRANCH_HANDLE) ??
|
|
396
|
-
{
|
|
397
|
-
name: exports.SWITCH_DEFAULT_BRANCH_HANDLE,
|
|
398
|
-
display_name: 'Default',
|
|
399
|
-
type: 'main',
|
|
400
|
-
};
|
|
401
|
-
return {
|
|
402
|
-
...schema,
|
|
403
|
-
outputs: deriveSwitchOutputPorts(branches, { template, defaultPort }),
|
|
404
|
-
};
|
|
405
|
-
}
|
|
406
|
-
/** skills 渲染用:全部内置类型(保持表定义顺序) */
|
|
407
|
-
function listClassicNodeTypes() {
|
|
408
|
-
return Object.values(exports.CLASSIC_NODE_DESCRIPTORS).map((d) => ({
|
|
409
|
-
nodeType: d.nodeType,
|
|
410
|
-
label: d.label,
|
|
411
|
-
}));
|
|
206
|
+
function isClassicSelfConnectionAllowed(node, sourceHandle, targetHandle) {
|
|
207
|
+
if (!sourceHandle || !targetHandle)
|
|
208
|
+
return false;
|
|
209
|
+
const portsTable = resolveClassicNodePorts(node);
|
|
210
|
+
return Boolean(portsTable?.selfConnections.some((rule) => rule.source === sourceHandle && rule.target === targetHandle));
|
|
412
211
|
}
|
|
413
212
|
//# sourceMappingURL=classicNodePorts.js.map
|