@n8n/ai-workflow-builder 1.1.1 → 1.2.0

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.
Files changed (93) hide show
  1. package/dist/ai-workflow-builder-agent.service.d.ts +1 -0
  2. package/dist/ai-workflow-builder-agent.service.js +3 -0
  3. package/dist/ai-workflow-builder-agent.service.js.map +1 -1
  4. package/dist/build.tsbuildinfo +1 -1
  5. package/dist/multi-agent-workflow-subgraphs.d.ts +4 -4
  6. package/dist/multi-agent-workflow-subgraphs.js +7 -1
  7. package/dist/multi-agent-workflow-subgraphs.js.map +1 -1
  8. package/dist/parent-graph-state.d.ts +2 -2
  9. package/dist/parent-graph-state.js +3 -3
  10. package/dist/parent-graph-state.js.map +1 -1
  11. package/dist/prompts/agents/builder.prompt.js +88 -16
  12. package/dist/prompts/agents/builder.prompt.js.map +1 -1
  13. package/dist/prompts/agents/configurator.prompt.js +21 -3
  14. package/dist/prompts/agents/configurator.prompt.js.map +1 -1
  15. package/dist/prompts/agents/discovery.prompt.js +2 -1
  16. package/dist/prompts/agents/discovery.prompt.js.map +1 -1
  17. package/dist/prompts/chains/parameter-updater/guides/embedding-nodes.d.ts +2 -0
  18. package/dist/prompts/chains/parameter-updater/guides/embedding-nodes.js +70 -0
  19. package/dist/prompts/chains/parameter-updater/guides/embedding-nodes.js.map +1 -0
  20. package/dist/prompts/chains/parameter-updater/guides/index.d.ts +1 -0
  21. package/dist/prompts/chains/parameter-updater/guides/index.js +3 -1
  22. package/dist/prompts/chains/parameter-updater/guides/index.js.map +1 -1
  23. package/dist/prompts/chains/parameter-updater/registry.js +1 -0
  24. package/dist/prompts/chains/parameter-updater/registry.js.map +1 -1
  25. package/dist/session-manager.service.d.ts +1 -0
  26. package/dist/session-manager.service.js +55 -4
  27. package/dist/session-manager.service.js.map +1 -1
  28. package/dist/subgraphs/builder.subgraph.d.ts +11 -1
  29. package/dist/subgraphs/builder.subgraph.js +13 -1
  30. package/dist/subgraphs/builder.subgraph.js.map +1 -1
  31. package/dist/subgraphs/configurator.subgraph.d.ts +11 -1
  32. package/dist/subgraphs/configurator.subgraph.js +13 -1
  33. package/dist/subgraphs/configurator.subgraph.js.map +1 -1
  34. package/dist/subgraphs/discovery.subgraph.d.ts +9 -9
  35. package/dist/subgraphs/discovery.subgraph.js +6 -8
  36. package/dist/subgraphs/discovery.subgraph.js.map +1 -1
  37. package/dist/tools/best-practices/data-extraction.js +11 -1
  38. package/dist/tools/best-practices/data-extraction.js.map +1 -1
  39. package/dist/tools/best-practices/document-processing.js +12 -1
  40. package/dist/tools/best-practices/document-processing.js.map +1 -1
  41. package/dist/tools/best-practices/scraping-and-research.js +10 -0
  42. package/dist/tools/best-practices/scraping-and-research.js.map +1 -1
  43. package/dist/tools/builder-tools.js +1 -1
  44. package/dist/tools/builder-tools.js.map +1 -1
  45. package/dist/tools/get-node-examples.tool.d.ts +119 -0
  46. package/dist/tools/get-node-examples.tool.js +189 -0
  47. package/dist/tools/get-node-examples.tool.js.map +1 -0
  48. package/dist/tools/get-workflow-examples.tool.js +8 -42
  49. package/dist/tools/get-workflow-examples.tool.js.map +1 -1
  50. package/dist/tools/node-details.tool.d.ts +2 -1
  51. package/dist/tools/node-details.tool.js +48 -18
  52. package/dist/tools/node-details.tool.js.map +1 -1
  53. package/dist/tools/utils/{markdown-workflow.utils.d.ts → mermaid.utils.d.ts} +0 -1
  54. package/dist/tools/utils/mermaid.utils.js +647 -0
  55. package/dist/tools/utils/mermaid.utils.js.map +1 -0
  56. package/dist/tools/utils/node-configuration.utils.d.ts +13 -0
  57. package/dist/tools/utils/node-configuration.utils.js +75 -0
  58. package/dist/tools/utils/node-configuration.utils.js.map +1 -0
  59. package/dist/tools/utils/test/workflows/ai-assistant.workflow.js +1 -0
  60. package/dist/tools/utils/test/workflows/ai-assistant.workflow.js.map +1 -1
  61. package/dist/tools/web/templates.d.ts +17 -1
  62. package/dist/tools/web/templates.js +35 -0
  63. package/dist/tools/web/templates.js.map +1 -1
  64. package/dist/types/discovery-types.d.ts +0 -2
  65. package/dist/types/tools.d.ts +6 -1
  66. package/dist/types/web/templates.d.ts +1 -0
  67. package/dist/utils/state-reducers.d.ts +2 -3
  68. package/dist/utils/state-reducers.js +10 -15
  69. package/dist/utils/state-reducers.js.map +1 -1
  70. package/dist/utils/stream-processor.js +10 -1
  71. package/dist/utils/stream-processor.js.map +1 -1
  72. package/dist/utils/subgraph-helpers.d.ts +2 -2
  73. package/dist/utils/subgraph-helpers.js +8 -9
  74. package/dist/utils/subgraph-helpers.js.map +1 -1
  75. package/dist/utils/tool-executor.js +4 -18
  76. package/dist/utils/tool-executor.js.map +1 -1
  77. package/dist/validation/checks/from-ai.js +3 -1
  78. package/dist/validation/checks/from-ai.js.map +1 -1
  79. package/dist/validation/checks/nodes.js +10 -2
  80. package/dist/validation/checks/nodes.js.map +1 -1
  81. package/dist/validation/checks/tools.js +3 -1
  82. package/dist/validation/checks/tools.js.map +1 -1
  83. package/dist/validation/checks/trigger.js +3 -1
  84. package/dist/validation/checks/trigger.js.map +1 -1
  85. package/dist/workflow-builder-agent.d.ts +1 -0
  86. package/dist/workflow-builder-agent.js +8 -1
  87. package/dist/workflow-builder-agent.js.map +1 -1
  88. package/dist/workflow-state.d.ts +2 -2
  89. package/dist/workflow-state.js +4 -4
  90. package/dist/workflow-state.js.map +1 -1
  91. package/package.json +5 -5
  92. package/dist/tools/utils/markdown-workflow.utils.js +0 -174
  93. package/dist/tools/utils/markdown-workflow.utils.js.map +0 -1
@@ -0,0 +1,647 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.mermaidStringify = mermaidStringify;
4
+ exports.processWorkflowExamples = processWorkflowExamples;
5
+ const node_configuration_utils_1 = require("./node-configuration.utils");
6
+ const DEFAULT_MERMAID_OPTIONS = {
7
+ includeNodeType: true,
8
+ includeNodeParameters: true,
9
+ includeNodeName: true,
10
+ collectNodeConfigurations: false,
11
+ };
12
+ const CONDITIONAL_NODE_TYPES = new Set([
13
+ 'n8n-nodes-base.if',
14
+ 'n8n-nodes-base.switch',
15
+ 'n8n-nodes-base.filter',
16
+ ]);
17
+ const AGENT_NODE_TYPE = '@n8n/n8n-nodes-langchain.agent';
18
+ const STICKY_NOTE_TYPE = 'n8n-nodes-base.stickyNote';
19
+ const DEFAULT_NODE_WIDTH = 100;
20
+ const DEFAULT_NODE_HEIGHT = 100;
21
+ const DEFAULT_STICKY_WIDTH = 150;
22
+ const DEFAULT_STICKY_HEIGHT = 80;
23
+ class MermaidBuilder {
24
+ nodes;
25
+ connections;
26
+ options;
27
+ nodeConfigurations;
28
+ nodeIdMap;
29
+ nodeByName;
30
+ stickyOverlaps;
31
+ agentSubgraphs;
32
+ nodesInSubgraphs;
33
+ definedNodes = new Set();
34
+ lines = [];
35
+ subgraphCounter = 0;
36
+ constructor(nodes, connections, options, existingConfigurations) {
37
+ const regularNodes = nodes.filter((n) => n.type !== STICKY_NOTE_TYPE);
38
+ const stickyNotes = nodes.filter((n) => n.type === STICKY_NOTE_TYPE);
39
+ this.nodes = regularNodes;
40
+ this.connections = connections;
41
+ this.options = options;
42
+ this.nodeConfigurations = existingConfigurations ?? {};
43
+ this.nodeIdMap = this.createNodeIdMap();
44
+ this.nodeByName = new Map(regularNodes.map((n) => [n.name, n]));
45
+ this.stickyOverlaps = this.categorizeStickyOverlaps(stickyNotes);
46
+ const nodesInStickySubgraphs = new Set();
47
+ for (const { nodeNames } of this.stickyOverlaps.multiNodeOverlap) {
48
+ for (const name of nodeNames) {
49
+ nodesInStickySubgraphs.add(name);
50
+ }
51
+ }
52
+ this.agentSubgraphs = this.findAgentSubgraphs(nodesInStickySubgraphs);
53
+ this.nodesInSubgraphs = new Set(nodesInStickySubgraphs);
54
+ for (const { agentNode, aiConnectedNodeNames } of this.agentSubgraphs) {
55
+ this.nodesInSubgraphs.add(agentNode.name);
56
+ for (const name of aiConnectedNodeNames) {
57
+ this.nodesInSubgraphs.add(name);
58
+ }
59
+ }
60
+ }
61
+ build() {
62
+ for (const sticky of this.stickyOverlaps.noOverlap) {
63
+ this.lines.push(this.formatStickyComment(sticky.content));
64
+ }
65
+ this.buildMainFlow();
66
+ this.buildStickySubgraphs();
67
+ this.buildAgentSubgraphs();
68
+ this.buildConnectionsToSubgraphs();
69
+ this.buildConnectionsFromSubgraphs();
70
+ this.buildInterSubgraphConnections();
71
+ return {
72
+ lines: ['```mermaid', 'flowchart TD', ...this.lines, '```'],
73
+ nodeConfigurations: this.nodeConfigurations,
74
+ };
75
+ }
76
+ createNodeIdMap() {
77
+ const map = new Map();
78
+ this.nodes.forEach((node, idx) => {
79
+ map.set(node.name, `n${idx + 1}`);
80
+ });
81
+ return map;
82
+ }
83
+ categorizeStickyOverlaps(stickyNotes) {
84
+ const result = {
85
+ noOverlap: [],
86
+ singleNodeOverlap: new Map(),
87
+ multiNodeOverlap: [],
88
+ };
89
+ for (const sticky of stickyNotes) {
90
+ const bounds = this.extractStickyBounds(sticky);
91
+ if (!bounds.content)
92
+ continue;
93
+ const overlappingNodes = this.nodes.filter((node) => this.isNodeWithinStickyBounds(node.position[0], node.position[1], bounds));
94
+ if (overlappingNodes.length === 0) {
95
+ result.noOverlap.push(bounds);
96
+ }
97
+ else if (overlappingNodes.length === 1) {
98
+ result.singleNodeOverlap.set(overlappingNodes[0].name, bounds);
99
+ }
100
+ else {
101
+ result.multiNodeOverlap.push({
102
+ sticky: bounds,
103
+ nodeNames: overlappingNodes.map((n) => n.name),
104
+ });
105
+ }
106
+ }
107
+ return result;
108
+ }
109
+ extractStickyBounds(node) {
110
+ return {
111
+ node,
112
+ x: node.position[0],
113
+ y: node.position[1],
114
+ width: typeof node.parameters.width === 'number' ? node.parameters.width : DEFAULT_STICKY_WIDTH,
115
+ height: typeof node.parameters.height === 'number' ? node.parameters.height : DEFAULT_STICKY_HEIGHT,
116
+ content: typeof node.parameters.content === 'string' ? node.parameters.content.trim() : '',
117
+ };
118
+ }
119
+ isNodeWithinStickyBounds(nodeX, nodeY, sticky) {
120
+ const nodeCenterX = nodeX + DEFAULT_NODE_WIDTH / 2;
121
+ const nodeCenterY = nodeY + DEFAULT_NODE_HEIGHT / 2;
122
+ return (nodeCenterX >= sticky.x &&
123
+ nodeCenterX <= sticky.x + sticky.width &&
124
+ nodeCenterY >= sticky.y &&
125
+ nodeCenterY <= sticky.y + sticky.height);
126
+ }
127
+ findAgentSubgraphs(nodesInStickySubgraphs) {
128
+ const agentSubgraphs = [];
129
+ const agentNodes = this.nodes.filter((n) => n.type === AGENT_NODE_TYPE && !nodesInStickySubgraphs.has(n.name));
130
+ const reverseConnections = this.buildReverseConnectionMap();
131
+ for (const agentNode of agentNodes) {
132
+ const incomingConns = reverseConnections.get(agentNode.name) ?? [];
133
+ const aiConnectedNodeNames = incomingConns
134
+ .filter(({ connType, sourceName }) => connType !== 'main' && !nodesInStickySubgraphs.has(sourceName))
135
+ .map(({ sourceName }) => sourceName);
136
+ const nestedStickySubgraphs = this.findNestedStickySubgraphs(incomingConns);
137
+ if (aiConnectedNodeNames.length > 0 || nestedStickySubgraphs.length > 0) {
138
+ agentSubgraphs.push({ agentNode, aiConnectedNodeNames, nestedStickySubgraphs });
139
+ }
140
+ }
141
+ return agentSubgraphs;
142
+ }
143
+ findNestedStickySubgraphs(incomingConns) {
144
+ const nested = [];
145
+ for (const stickySubgraph of this.stickyOverlaps.multiNodeOverlap) {
146
+ const allNodesConnectToAgent = stickySubgraph.nodeNames.every((nodeName) => incomingConns.some(({ sourceName, connType }) => sourceName === nodeName && connType !== 'main'));
147
+ if (allNodesConnectToAgent) {
148
+ nested.push(stickySubgraph);
149
+ }
150
+ }
151
+ return nested;
152
+ }
153
+ buildReverseConnectionMap() {
154
+ const reverseConnections = new Map();
155
+ for (const [sourceName, sourceConns] of Object.entries(this.connections)) {
156
+ for (const { nodeName: targetName, connType } of this.getConnectionTargets(sourceConns)) {
157
+ if (!reverseConnections.has(targetName)) {
158
+ reverseConnections.set(targetName, []);
159
+ }
160
+ reverseConnections.get(targetName).push({ sourceName, connType });
161
+ }
162
+ }
163
+ return reverseConnections;
164
+ }
165
+ getConnectionTargets(nodeConns) {
166
+ const targets = [];
167
+ for (const [connType, connList] of Object.entries(nodeConns)) {
168
+ for (const connArray of connList) {
169
+ if (!connArray)
170
+ continue;
171
+ for (const conn of connArray) {
172
+ targets.push({ nodeName: conn.node, connType });
173
+ }
174
+ }
175
+ }
176
+ return targets;
177
+ }
178
+ getMainConnectionTargets(nodeConns) {
179
+ if (!nodeConns.main)
180
+ return [];
181
+ return nodeConns.main
182
+ .filter((connArray) => connArray !== null)
183
+ .flatMap((connArray) => connArray.map((conn) => conn.node));
184
+ }
185
+ findStartNodes() {
186
+ const nodesWithIncoming = new Set();
187
+ Object.values(this.connections)
188
+ .filter((conn) => conn.main)
189
+ .forEach((sourceConnections) => {
190
+ for (const connArray of sourceConnections.main) {
191
+ if (!connArray)
192
+ continue;
193
+ for (const conn of connArray) {
194
+ nodesWithIncoming.add(conn.node);
195
+ }
196
+ }
197
+ });
198
+ return this.nodes.filter((n) => !nodesWithIncoming.has(n.name));
199
+ }
200
+ formatStickyComment(content) {
201
+ return `%% ${content.replace(/\n/g, ' ').replace(/\s+/g, ' ').trim()}`;
202
+ }
203
+ getNextSubgraphId() {
204
+ this.subgraphCounter++;
205
+ return `sg${this.subgraphCounter}`;
206
+ }
207
+ buildNodeDefinition(node, id) {
208
+ const isConditional = CONDITIONAL_NODE_TYPES.has(node.type);
209
+ if (this.options.includeNodeName) {
210
+ const escapedName = node.name.replace(/"/g, "'");
211
+ return isConditional ? `${id}{"${escapedName}"}` : `${id}["${escapedName}"]`;
212
+ }
213
+ return id;
214
+ }
215
+ buildNodeCommentLines(node) {
216
+ const lines = [];
217
+ if (this.options.collectNodeConfigurations) {
218
+ const config = (0, node_configuration_utils_1.collectSingleNodeConfiguration)(node);
219
+ if (config) {
220
+ (0, node_configuration_utils_1.addNodeConfigurationToMap)(node.type, config, this.nodeConfigurations);
221
+ }
222
+ }
223
+ if (this.options.includeNodeType || this.options.includeNodeParameters) {
224
+ const typePart = this.options.includeNodeType ? this.buildNodeTypePart(node) : '';
225
+ const paramsPart = this.options.includeNodeParameters && Object.keys(node.parameters).length > 0
226
+ ? ` | ${JSON.stringify(node.parameters)}`
227
+ : '';
228
+ if (typePart || paramsPart) {
229
+ lines.push(`%% ${typePart}${paramsPart}`);
230
+ }
231
+ }
232
+ return lines;
233
+ }
234
+ buildNodeTypePart(node) {
235
+ const parts = [node.type];
236
+ if (typeof node.parameters.resource === 'string' && node.parameters.resource) {
237
+ parts.push(node.parameters.resource);
238
+ }
239
+ if (typeof node.parameters.operation === 'string' && node.parameters.operation) {
240
+ parts.push(node.parameters.operation);
241
+ }
242
+ return parts.join(':');
243
+ }
244
+ buildSingleNodeLines(node, id) {
245
+ const lines = this.buildNodeCommentLines(node);
246
+ lines.push(this.buildNodeDefinition(node, id));
247
+ return lines;
248
+ }
249
+ defineNodeIfNeeded(nodeName) {
250
+ const node = this.nodeByName.get(nodeName);
251
+ const id = this.nodeIdMap.get(nodeName);
252
+ if (!node || !id)
253
+ return id ?? '';
254
+ if (!this.definedNodes.has(nodeName)) {
255
+ this.definedNodes.add(nodeName);
256
+ const stickyForNode = this.stickyOverlaps.singleNodeOverlap.get(nodeName);
257
+ if (stickyForNode) {
258
+ this.lines.push(this.formatStickyComment(stickyForNode.content));
259
+ }
260
+ this.lines.push(...this.buildNodeCommentLines(node));
261
+ return this.buildNodeDefinition(node, id);
262
+ }
263
+ return id;
264
+ }
265
+ defineTargetAndConnect(sourceId, targetName, connType) {
266
+ const targetId = this.nodeIdMap.get(targetName);
267
+ if (!targetId)
268
+ return false;
269
+ if (!this.definedNodes.has(targetName)) {
270
+ const targetNode = this.nodeByName.get(targetName);
271
+ if (targetNode) {
272
+ const stickyForNode = this.stickyOverlaps.singleNodeOverlap.get(targetName);
273
+ if (stickyForNode) {
274
+ this.lines.push(this.formatStickyComment(stickyForNode.content));
275
+ }
276
+ this.lines.push(...this.buildNodeCommentLines(targetNode));
277
+ this.addConnection(sourceId, this.buildNodeDefinition(targetNode, targetId), connType);
278
+ this.definedNodes.add(targetName);
279
+ return connType === 'main';
280
+ }
281
+ }
282
+ else {
283
+ this.addConnection(sourceId, targetId, connType);
284
+ }
285
+ return false;
286
+ }
287
+ addConnection(sourceId, targetDef, connType) {
288
+ const arrow = connType === 'main' ? '-->' : `-.${connType}.->`;
289
+ this.lines.push(`${sourceId} ${arrow} ${targetDef}`);
290
+ }
291
+ buildMainFlow() {
292
+ const visited = new Set();
293
+ const startNodes = this.findStartNodes();
294
+ const traverse = (nodeName) => {
295
+ if (visited.has(nodeName))
296
+ return;
297
+ visited.add(nodeName);
298
+ const nodeConns = this.connections[nodeName];
299
+ const targets = nodeConns ? this.getConnectionTargets(nodeConns) : [];
300
+ for (const { nodeName: targetName, connType } of targets) {
301
+ if (this.nodesInSubgraphs.has(targetName) || this.nodesInSubgraphs.has(nodeName))
302
+ continue;
303
+ const sourceId = this.nodeIdMap.get(nodeName);
304
+ const targetDef = this.defineNodeIfNeeded(targetName);
305
+ if (sourceId) {
306
+ this.addConnection(sourceId, targetDef, connType);
307
+ }
308
+ }
309
+ if (nodeConns) {
310
+ this.getMainConnectionTargets(nodeConns)
311
+ .filter((target) => !this.nodesInSubgraphs.has(target))
312
+ .forEach((target) => traverse(target));
313
+ }
314
+ };
315
+ for (const startNode of startNodes) {
316
+ if (this.nodesInSubgraphs.has(startNode.name))
317
+ continue;
318
+ const id = this.nodeIdMap.get(startNode.name);
319
+ if (id && !this.definedNodes.has(startNode.name)) {
320
+ const stickyForNode = this.stickyOverlaps.singleNodeOverlap.get(startNode.name);
321
+ if (stickyForNode) {
322
+ this.lines.push(this.formatStickyComment(stickyForNode.content));
323
+ }
324
+ this.lines.push(...this.buildSingleNodeLines(startNode, id));
325
+ this.definedNodes.add(startNode.name);
326
+ }
327
+ traverse(startNode.name);
328
+ }
329
+ }
330
+ buildStickySubgraphs() {
331
+ const nestedStickyIds = this.getNestedStickyIds();
332
+ for (const { sticky, nodeNames } of this.stickyOverlaps.multiNodeOverlap) {
333
+ if (nestedStickyIds.has(sticky.node.id ?? ''))
334
+ continue;
335
+ this.buildSingleStickySubgraph(sticky, nodeNames);
336
+ }
337
+ }
338
+ getNestedStickyIds() {
339
+ const ids = new Set();
340
+ for (const { nestedStickySubgraphs } of this.agentSubgraphs) {
341
+ for (const { sticky } of nestedStickySubgraphs) {
342
+ ids.add(sticky.node.id ?? '');
343
+ }
344
+ }
345
+ return ids;
346
+ }
347
+ buildSingleStickySubgraph(sticky, nodeNames) {
348
+ const subgraphId = this.getNextSubgraphId();
349
+ const subgraphLabel = sticky.content.replace(/\n/g, ' ').replace(/\s+/g, ' ').trim();
350
+ this.lines.push(this.formatStickyComment(sticky.content));
351
+ this.lines.push(`subgraph ${subgraphId}["${subgraphLabel.replace(/"/g, "'")}"]`);
352
+ const subgraphNodeSet = new Set(nodeNames);
353
+ const subgraphDefinedNodes = new Set();
354
+ const startNodes = this.findSubgraphStartNodes(nodeNames, subgraphNodeSet);
355
+ for (const startNode of startNodes) {
356
+ const id = this.nodeIdMap.get(startNode.name);
357
+ if (id && !subgraphDefinedNodes.has(startNode.name)) {
358
+ this.lines.push(...this.buildSingleNodeLines(startNode, id));
359
+ subgraphDefinedNodes.add(startNode.name);
360
+ }
361
+ }
362
+ this.buildSubgraphInternalConnections(startNodes, subgraphNodeSet, subgraphDefinedNodes);
363
+ for (const name of nodeNames) {
364
+ this.definedNodes.add(name);
365
+ }
366
+ this.lines.push('end');
367
+ }
368
+ findSubgraphStartNodes(nodeNames, subgraphNodeSet) {
369
+ const nodesWithInternalIncoming = new Set();
370
+ for (const nodeName of nodeNames) {
371
+ const nodeConns = this.connections[nodeName];
372
+ if (!nodeConns)
373
+ continue;
374
+ for (const { nodeName: targetName } of this.getConnectionTargets(nodeConns)) {
375
+ if (subgraphNodeSet.has(targetName)) {
376
+ nodesWithInternalIncoming.add(targetName);
377
+ }
378
+ }
379
+ }
380
+ return nodeNames
381
+ .filter((name) => !nodesWithInternalIncoming.has(name))
382
+ .map((name) => this.nodeByName.get(name))
383
+ .filter((node) => node !== undefined);
384
+ }
385
+ buildSubgraphInternalConnections(startNodes, subgraphNodeSet, subgraphDefinedNodes) {
386
+ const visited = new Set();
387
+ const traverse = (nodeName) => {
388
+ if (visited.has(nodeName))
389
+ return;
390
+ visited.add(nodeName);
391
+ const nodeConns = this.connections[nodeName];
392
+ if (!nodeConns)
393
+ return;
394
+ const sourceId = this.nodeIdMap.get(nodeName);
395
+ if (!sourceId)
396
+ return;
397
+ for (const { nodeName: targetName, connType } of this.getConnectionTargets(nodeConns)) {
398
+ if (!subgraphNodeSet.has(targetName))
399
+ continue;
400
+ const targetId = this.nodeIdMap.get(targetName);
401
+ const targetNode = this.nodeByName.get(targetName);
402
+ if (!targetId || !targetNode)
403
+ continue;
404
+ const arrow = connType === 'main' ? '-->' : `-.${connType}.->`;
405
+ if (!subgraphDefinedNodes.has(targetName)) {
406
+ this.lines.push(...this.buildNodeCommentLines(targetNode));
407
+ this.lines.push(`${sourceId} ${arrow} ${this.buildNodeDefinition(targetNode, targetId)}`);
408
+ subgraphDefinedNodes.add(targetName);
409
+ }
410
+ else {
411
+ this.lines.push(`${sourceId} ${arrow} ${targetId}`);
412
+ }
413
+ }
414
+ this.getMainConnectionTargets(nodeConns)
415
+ .filter((t) => subgraphNodeSet.has(t))
416
+ .forEach((t) => traverse(t));
417
+ };
418
+ startNodes.forEach((n) => traverse(n.name));
419
+ }
420
+ buildAgentSubgraphs() {
421
+ for (const agentSubgraph of this.agentSubgraphs) {
422
+ this.buildSingleAgentSubgraph(agentSubgraph);
423
+ }
424
+ }
425
+ buildSingleAgentSubgraph(agentSubgraph) {
426
+ const { agentNode, aiConnectedNodeNames, nestedStickySubgraphs } = agentSubgraph;
427
+ const agentId = this.nodeIdMap.get(agentNode.name);
428
+ if (!agentId)
429
+ return;
430
+ const subgraphId = this.getNextSubgraphId();
431
+ this.lines.push(`subgraph ${subgraphId}["${agentNode.name.replace(/"/g, "'")}"]`);
432
+ for (const nodeName of aiConnectedNodeNames) {
433
+ this.defineAgentConnectedNode(nodeName);
434
+ }
435
+ for (const { sticky, nodeNames } of nestedStickySubgraphs) {
436
+ this.buildNestedStickySubgraph(sticky, nodeNames);
437
+ }
438
+ this.buildAgentNodeConnections(agentNode, agentId, aiConnectedNodeNames, nestedStickySubgraphs);
439
+ this.markAgentSubgraphNodesDefined(agentNode, aiConnectedNodeNames, nestedStickySubgraphs);
440
+ this.lines.push('end');
441
+ }
442
+ defineAgentConnectedNode(nodeName) {
443
+ const node = this.nodeByName.get(nodeName);
444
+ const id = this.nodeIdMap.get(nodeName);
445
+ if (!node || !id)
446
+ return;
447
+ const stickyForNode = this.stickyOverlaps.singleNodeOverlap.get(nodeName);
448
+ if (stickyForNode) {
449
+ this.lines.push(this.formatStickyComment(stickyForNode.content));
450
+ }
451
+ this.lines.push(...this.buildSingleNodeLines(node, id));
452
+ }
453
+ buildNestedStickySubgraph(sticky, nodeNames) {
454
+ const nestedSubgraphId = this.getNextSubgraphId();
455
+ const label = sticky.content.replace(/\n/g, ' ').replace(/\s+/g, ' ').trim();
456
+ this.lines.push(this.formatStickyComment(sticky.content));
457
+ this.lines.push(`subgraph ${nestedSubgraphId}["${label.replace(/"/g, "'")}"]`);
458
+ for (const nodeName of nodeNames) {
459
+ const node = this.nodeByName.get(nodeName);
460
+ const id = this.nodeIdMap.get(nodeName);
461
+ if (node && id) {
462
+ this.lines.push(...this.buildSingleNodeLines(node, id));
463
+ }
464
+ }
465
+ this.lines.push('end');
466
+ }
467
+ buildAgentNodeConnections(agentNode, agentId, aiConnectedNodeNames, nestedStickySubgraphs) {
468
+ const stickyForAgent = this.stickyOverlaps.singleNodeOverlap.get(agentNode.name);
469
+ if (stickyForAgent) {
470
+ this.lines.push(this.formatStickyComment(stickyForAgent.content));
471
+ }
472
+ this.lines.push(...this.buildNodeCommentLines(agentNode));
473
+ const allAiNodeNames = [
474
+ ...aiConnectedNodeNames,
475
+ ...nestedStickySubgraphs.flatMap(({ nodeNames }) => nodeNames),
476
+ ];
477
+ let agentDefined = false;
478
+ for (const nodeName of allAiNodeNames) {
479
+ const sourceId = this.nodeIdMap.get(nodeName);
480
+ const nodeConns = this.connections[nodeName];
481
+ if (!sourceId || !nodeConns)
482
+ continue;
483
+ for (const { nodeName: targetName, connType } of this.getConnectionTargets(nodeConns)) {
484
+ if (targetName !== agentNode.name || connType === 'main')
485
+ continue;
486
+ const arrow = `-.${connType}.->`;
487
+ if (!agentDefined) {
488
+ this.lines.push(`${sourceId} ${arrow} ${this.buildNodeDefinition(agentNode, agentId)}`);
489
+ agentDefined = true;
490
+ }
491
+ else {
492
+ this.lines.push(`${sourceId} ${arrow} ${agentId}`);
493
+ }
494
+ }
495
+ }
496
+ if (!agentDefined) {
497
+ this.lines.push(this.buildNodeDefinition(agentNode, agentId));
498
+ }
499
+ }
500
+ markAgentSubgraphNodesDefined(agentNode, aiConnectedNodeNames, nestedStickySubgraphs) {
501
+ for (const name of aiConnectedNodeNames) {
502
+ this.definedNodes.add(name);
503
+ }
504
+ for (const { nodeNames } of nestedStickySubgraphs) {
505
+ for (const name of nodeNames) {
506
+ this.definedNodes.add(name);
507
+ }
508
+ }
509
+ this.definedNodes.add(agentNode.name);
510
+ }
511
+ buildConnectionsToSubgraphs() {
512
+ for (const nodeName of this.definedNodes) {
513
+ if (this.nodesInSubgraphs.has(nodeName))
514
+ continue;
515
+ const nodeConns = this.connections[nodeName];
516
+ if (!nodeConns)
517
+ continue;
518
+ for (const { nodeName: targetName, connType } of this.getConnectionTargets(nodeConns)) {
519
+ if (this.nodesInSubgraphs.has(targetName)) {
520
+ const sourceId = this.nodeIdMap.get(nodeName);
521
+ const targetId = this.nodeIdMap.get(targetName);
522
+ if (sourceId && targetId) {
523
+ this.addConnection(sourceId, targetId, connType);
524
+ }
525
+ }
526
+ }
527
+ }
528
+ }
529
+ buildConnectionsFromSubgraphs() {
530
+ const nodesToProcess = [];
531
+ for (const nodeName of this.nodesInSubgraphs) {
532
+ const nodeConns = this.connections[nodeName];
533
+ if (!nodeConns)
534
+ continue;
535
+ const sourceId = this.nodeIdMap.get(nodeName);
536
+ if (!sourceId)
537
+ continue;
538
+ for (const { nodeName: targetName, connType } of this.getConnectionTargets(nodeConns)) {
539
+ if (this.nodesInSubgraphs.has(targetName))
540
+ continue;
541
+ const wasNewMainConnection = this.defineTargetAndConnect(sourceId, targetName, connType);
542
+ if (wasNewMainConnection) {
543
+ nodesToProcess.push(targetName);
544
+ }
545
+ }
546
+ }
547
+ this.continueTraversalFromNodes(nodesToProcess);
548
+ }
549
+ continueTraversalFromNodes(nodesToProcess) {
550
+ const visited = new Set();
551
+ const traverse = (nodeName) => {
552
+ if (visited.has(nodeName) || this.nodesInSubgraphs.has(nodeName))
553
+ return;
554
+ visited.add(nodeName);
555
+ const nodeConns = this.connections[nodeName];
556
+ if (!nodeConns)
557
+ return;
558
+ const sourceId = this.nodeIdMap.get(nodeName);
559
+ if (!sourceId)
560
+ return;
561
+ for (const { nodeName: targetName, connType } of this.getConnectionTargets(nodeConns)) {
562
+ if (this.nodesInSubgraphs.has(targetName)) {
563
+ const targetId = this.nodeIdMap.get(targetName);
564
+ if (targetId) {
565
+ this.addConnection(sourceId, targetId, connType);
566
+ }
567
+ continue;
568
+ }
569
+ this.defineTargetAndConnect(sourceId, targetName, connType);
570
+ }
571
+ this.getMainConnectionTargets(nodeConns)
572
+ .filter((t) => !this.nodesInSubgraphs.has(t))
573
+ .forEach((t) => traverse(t));
574
+ };
575
+ nodesToProcess.forEach((n) => traverse(n));
576
+ }
577
+ buildInterSubgraphConnections() {
578
+ const nestedStickyIds = this.getNestedStickyIds();
579
+ const outputConnections = new Set();
580
+ for (const nodeName of this.nodesInSubgraphs) {
581
+ const nodeConns = this.connections[nodeName];
582
+ if (!nodeConns)
583
+ continue;
584
+ for (const { nodeName: targetName, connType } of this.getConnectionTargets(nodeConns)) {
585
+ if (!this.nodesInSubgraphs.has(targetName))
586
+ continue;
587
+ if (this.isInNestedSticky(nodeName, nestedStickyIds))
588
+ continue;
589
+ if (this.isInNestedSticky(targetName, nestedStickyIds))
590
+ continue;
591
+ const sourceSubgraphType = this.getSubgraphType(nodeName, nestedStickyIds);
592
+ const targetSubgraphType = this.getSubgraphType(targetName, nestedStickyIds);
593
+ if (sourceSubgraphType === targetSubgraphType)
594
+ continue;
595
+ const sourceId = this.nodeIdMap.get(nodeName);
596
+ const targetId = this.nodeIdMap.get(targetName);
597
+ if (!sourceId || !targetId)
598
+ continue;
599
+ const connKey = `${sourceId}-${connType}-${targetId}`;
600
+ if (outputConnections.has(connKey))
601
+ continue;
602
+ outputConnections.add(connKey);
603
+ this.addConnection(sourceId, targetId, connType);
604
+ }
605
+ }
606
+ }
607
+ isInNestedSticky(nodeName, nestedStickyIds) {
608
+ return this.stickyOverlaps.multiNodeOverlap.some(({ sticky, nodeNames }) => nodeNames.includes(nodeName) && nestedStickyIds.has(sticky.node.id ?? ''));
609
+ }
610
+ getSubgraphType(nodeName, nestedStickyIds) {
611
+ const inStandaloneSticky = this.stickyOverlaps.multiNodeOverlap.some(({ sticky, nodeNames }) => nodeNames.includes(nodeName) && !nestedStickyIds.has(sticky.node.id ?? ''));
612
+ if (inStandaloneSticky)
613
+ return 'sticky';
614
+ const inAgentSubgraph = this.agentSubgraphs.some(({ agentNode, aiConnectedNodeNames }) => agentNode.name === nodeName || aiConnectedNodeNames.includes(nodeName));
615
+ if (inAgentSubgraph)
616
+ return 'agent';
617
+ return 'none';
618
+ }
619
+ }
620
+ function mermaidStringify(workflow, options) {
621
+ const { workflow: wf } = workflow;
622
+ const mergedOptions = {
623
+ ...DEFAULT_MERMAID_OPTIONS,
624
+ ...options,
625
+ };
626
+ const builder = new MermaidBuilder(wf.nodes, wf.connections, mergedOptions);
627
+ const result = builder.build();
628
+ return result.lines.join('\n');
629
+ }
630
+ function processWorkflowExamples(workflows, options) {
631
+ const mergedOptions = {
632
+ ...DEFAULT_MERMAID_OPTIONS,
633
+ ...options,
634
+ collectNodeConfigurations: true,
635
+ };
636
+ const allConfigurations = {};
637
+ return workflows.map((workflow) => {
638
+ const { workflow: wf } = workflow;
639
+ const builder = new MermaidBuilder(wf.nodes, wf.connections, mergedOptions, allConfigurations);
640
+ const result = builder.build();
641
+ return {
642
+ mermaid: result.lines.join('\n'),
643
+ nodeConfigurations: result.nodeConfigurations,
644
+ };
645
+ });
646
+ }
647
+ //# sourceMappingURL=mermaid.utils.js.map