@atom8n/ai-workflow-builder 1.4.3 → 1.5.1
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/dist/build.tsbuildinfo +1 -1
- package/dist/prompts/chains/parameter-updater/guides/predecessor-output.d.ts +2 -0
- package/dist/prompts/chains/parameter-updater/guides/predecessor-output.js +24 -0
- package/dist/prompts/shared/node-guidance/index.d.ts +1 -0
- package/dist/prompts/shared/node-guidance/index.js +5 -0
- package/dist/prompts/shared/node-guidance/structured-output-parser.d.ts +2 -0
- package/dist/prompts/shared/node-guidance/structured-output-parser.js +34 -0
- package/dist/prompts/shared/node-recommendations/audio-generation.d.ts +2 -0
- package/dist/prompts/shared/node-recommendations/audio-generation.js +17 -0
- package/dist/prompts/shared/node-recommendations/image-generation.d.ts +2 -0
- package/dist/prompts/shared/node-recommendations/image-generation.js +17 -0
- package/dist/prompts/shared/node-recommendations/index.d.ts +3 -0
- package/dist/prompts/shared/node-recommendations/index.js +16 -0
- package/dist/prompts/shared/node-recommendations/text-manipulation.d.ts +2 -0
- package/dist/prompts/shared/node-recommendations/text-manipulation.js +26 -0
- package/dist/prompts/shared/node-recommendations/utils/format-recommendation.d.ts +2 -0
- package/dist/prompts/shared/node-recommendations/utils/format-recommendation.js +23 -0
- package/dist/prompts/shared/node-recommendations/video-generation.d.ts +2 -0
- package/dist/prompts/shared/node-recommendations/video-generation.js +14 -0
- package/dist/tools/best-practices/data-persistence.d.ts +7 -0
- package/dist/tools/best-practices/data-persistence.js +196 -0
- package/dist/tools/get-documentation.tool.d.ts +79 -0
- package/dist/tools/get-documentation.tool.js +163 -0
- package/dist/tools/rename-node.tool.d.ts +15 -0
- package/dist/tools/rename-node.tool.js +140 -0
- package/dist/types/node-guidance.d.ts +7 -0
- package/dist/types/node-guidance.js +2 -0
- package/dist/types/node-recommendations.d.ts +26 -0
- package/dist/types/node-recommendations.js +15 -0
- package/dist/utils/resource-operation-extractor.d.ts +16 -0
- package/dist/utils/resource-operation-extractor.js +147 -0
- package/dist/validation/auto-fix/auto-fix-connections.d.ts +21 -0
- package/dist/validation/auto-fix/auto-fix-connections.js +206 -0
- package/dist/validation/auto-fix/index.d.ts +2 -0
- package/dist/validation/auto-fix/index.js +5 -0
- package/package.json +7 -7
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.autoFixConnections = autoFixConnections;
|
|
4
|
+
const connection_utils_1 = require("../../tools/utils/connection.utils");
|
|
5
|
+
const node_helpers_1 = require("../../utils/node-helpers");
|
|
6
|
+
const node_type_map_1 = require("../../validation/utils/node-type-map");
|
|
7
|
+
const resolve_connections_1 = require("../../validation/utils/resolve-connections");
|
|
8
|
+
function findExistingOutgoingConnection(connections, nodeName, connectionType) {
|
|
9
|
+
const nodeConnections = connections[nodeName];
|
|
10
|
+
if (!nodeConnections)
|
|
11
|
+
return false;
|
|
12
|
+
const typeConnections = nodeConnections[connectionType];
|
|
13
|
+
if (!typeConnections)
|
|
14
|
+
return false;
|
|
15
|
+
return typeConnections.some((connArray) => connArray && connArray.length > 0);
|
|
16
|
+
}
|
|
17
|
+
function connectionExistsBetweenNodes(connections, sourceNodeName, targetNodeName, connectionType) {
|
|
18
|
+
const nodeConnections = connections[sourceNodeName];
|
|
19
|
+
if (!nodeConnections)
|
|
20
|
+
return false;
|
|
21
|
+
const typeConnections = nodeConnections[connectionType];
|
|
22
|
+
if (!typeConnections)
|
|
23
|
+
return false;
|
|
24
|
+
return typeConnections.some((connArray) => connArray?.some((conn) => conn.node === targetNodeName));
|
|
25
|
+
}
|
|
26
|
+
function checkNodeHasInputConnection(connections, targetNodeName, connectionType) {
|
|
27
|
+
for (const [, nodeConns] of Object.entries(connections)) {
|
|
28
|
+
const typeConns = nodeConns[connectionType];
|
|
29
|
+
if (!typeConns)
|
|
30
|
+
continue;
|
|
31
|
+
for (const connArray of typeConns) {
|
|
32
|
+
if (connArray?.some((conn) => conn.node === targetNodeName)) {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
function buildSubNodeOutputsMap(workflow, nodeTypeMap, nodeTypesByName) {
|
|
40
|
+
const subNodeOutputs = new Map();
|
|
41
|
+
for (const node of workflow.nodes) {
|
|
42
|
+
if (node.disabled)
|
|
43
|
+
continue;
|
|
44
|
+
const nodeType = (0, node_type_map_1.getNodeTypeForNode)(node, nodeTypeMap, nodeTypesByName);
|
|
45
|
+
if (!nodeType)
|
|
46
|
+
continue;
|
|
47
|
+
if ((0, node_helpers_1.isSubNode)(nodeType, node)) {
|
|
48
|
+
try {
|
|
49
|
+
const nodeInfo = { node, nodeType };
|
|
50
|
+
const outputs = (0, resolve_connections_1.resolveNodeOutputs)(nodeInfo);
|
|
51
|
+
if (outputs.size > 0) {
|
|
52
|
+
subNodeOutputs.set(node.name, outputs);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return subNodeOutputs;
|
|
60
|
+
}
|
|
61
|
+
function findCandidateSubNodes(ctx, targetNodeName, missingType) {
|
|
62
|
+
const candidates = [];
|
|
63
|
+
for (const [subNodeName, outputs] of ctx.subNodeOutputs) {
|
|
64
|
+
if (outputs.has(missingType)) {
|
|
65
|
+
const alreadyConnectedToTarget = connectionExistsBetweenNodes(ctx.result.updatedConnections, subNodeName, targetNodeName, missingType);
|
|
66
|
+
if (!alreadyConnectedToTarget) {
|
|
67
|
+
candidates.push(subNodeName);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return candidates;
|
|
72
|
+
}
|
|
73
|
+
function processMissingInputViolation(ctx, violation) {
|
|
74
|
+
const nodeName = violation.metadata?.nodeName;
|
|
75
|
+
const missingType = violation.metadata?.missingType;
|
|
76
|
+
if (!nodeName || !missingType)
|
|
77
|
+
return;
|
|
78
|
+
const targetNode = ctx.nodesByName.get(nodeName);
|
|
79
|
+
if (!targetNode || targetNode.disabled)
|
|
80
|
+
return;
|
|
81
|
+
if (!missingType.startsWith('ai_'))
|
|
82
|
+
return;
|
|
83
|
+
const candidates = findCandidateSubNodes(ctx, nodeName, missingType);
|
|
84
|
+
if (candidates.length === 1) {
|
|
85
|
+
const sourceNodeName = candidates[0];
|
|
86
|
+
ctx.result.updatedConnections = (0, connection_utils_1.createConnection)(ctx.result.updatedConnections, sourceNodeName, nodeName, missingType, 0, 0);
|
|
87
|
+
ctx.connectedSubNodes.add(sourceNodeName);
|
|
88
|
+
ctx.result.fixed.push({
|
|
89
|
+
sourceNodeName,
|
|
90
|
+
targetNodeName: nodeName,
|
|
91
|
+
connectionType: missingType,
|
|
92
|
+
reason: `Auto-connected orphaned sub-node to target requiring ${missingType}`,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
else if (candidates.length === 0) {
|
|
96
|
+
ctx.result.unfixable.push({
|
|
97
|
+
nodeName,
|
|
98
|
+
missingInputType: missingType,
|
|
99
|
+
reason: `No available sub-node provides ${missingType}`,
|
|
100
|
+
candidateCount: 0,
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
ctx.result.unfixable.push({
|
|
105
|
+
nodeName,
|
|
106
|
+
missingInputType: missingType,
|
|
107
|
+
reason: `Multiple sub-nodes (${candidates.join(', ')}) can provide ${missingType} - ambiguous`,
|
|
108
|
+
candidateCount: candidates.length,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function findTargetCandidates(ctx, subNodeName, outputType) {
|
|
113
|
+
const targetCandidates = [];
|
|
114
|
+
for (const node of ctx.workflow.nodes) {
|
|
115
|
+
if (node.disabled || node.name === subNodeName)
|
|
116
|
+
continue;
|
|
117
|
+
const nodeType = (0, node_type_map_1.getNodeTypeForNode)(node, ctx.nodeTypeMap, ctx.nodeTypesByName);
|
|
118
|
+
if (!nodeType)
|
|
119
|
+
continue;
|
|
120
|
+
if ((0, node_helpers_1.isSubNode)(nodeType, node))
|
|
121
|
+
continue;
|
|
122
|
+
try {
|
|
123
|
+
const nodeInfo = { node, nodeType };
|
|
124
|
+
const inputs = (0, resolve_connections_1.resolveNodeInputs)(nodeInfo);
|
|
125
|
+
const acceptsType = inputs.some((input) => input.type === outputType);
|
|
126
|
+
if (acceptsType) {
|
|
127
|
+
const hasConnection = checkNodeHasInputConnection(ctx.result.updatedConnections, node.name, outputType);
|
|
128
|
+
if (!hasConnection) {
|
|
129
|
+
targetCandidates.push(node.name);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return targetCandidates;
|
|
137
|
+
}
|
|
138
|
+
function processDisconnectedSubNodeViolation(ctx, violation) {
|
|
139
|
+
const subNodeName = violation.metadata?.nodeName;
|
|
140
|
+
const outputType = violation.metadata?.outputType;
|
|
141
|
+
if (!subNodeName || !outputType)
|
|
142
|
+
return;
|
|
143
|
+
const subNode = ctx.nodesByName.get(subNodeName);
|
|
144
|
+
if (!subNode || subNode.disabled)
|
|
145
|
+
return;
|
|
146
|
+
if (ctx.connectedSubNodes.has(subNodeName))
|
|
147
|
+
return;
|
|
148
|
+
const nowConnected = findExistingOutgoingConnection(ctx.result.updatedConnections, subNodeName, outputType);
|
|
149
|
+
if (nowConnected)
|
|
150
|
+
return;
|
|
151
|
+
const targetCandidates = findTargetCandidates(ctx, subNodeName, outputType);
|
|
152
|
+
if (targetCandidates.length === 1) {
|
|
153
|
+
const targetNodeName = targetCandidates[0];
|
|
154
|
+
ctx.result.updatedConnections = (0, connection_utils_1.createConnection)(ctx.result.updatedConnections, subNodeName, targetNodeName, outputType, 0, 0);
|
|
155
|
+
ctx.connectedSubNodes.add(subNodeName);
|
|
156
|
+
ctx.result.fixed.push({
|
|
157
|
+
sourceNodeName: subNodeName,
|
|
158
|
+
targetNodeName,
|
|
159
|
+
connectionType: outputType,
|
|
160
|
+
reason: 'Auto-connected disconnected sub-node to only available target',
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
else if (targetCandidates.length === 0) {
|
|
164
|
+
ctx.result.unfixable.push({
|
|
165
|
+
nodeName: subNodeName,
|
|
166
|
+
missingInputType: outputType,
|
|
167
|
+
reason: `No target node accepts ${outputType} input`,
|
|
168
|
+
candidateCount: 0,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
ctx.result.unfixable.push({
|
|
173
|
+
nodeName: subNodeName,
|
|
174
|
+
missingInputType: outputType,
|
|
175
|
+
reason: `Multiple targets (${targetCandidates.join(', ')}) accept ${outputType} - ambiguous`,
|
|
176
|
+
candidateCount: targetCandidates.length,
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function autoFixConnections(workflow, nodeTypes, violations) {
|
|
181
|
+
const { nodeTypeMap, nodeTypesByName } = (0, node_type_map_1.createNodeTypeMaps)(nodeTypes);
|
|
182
|
+
const nodesByName = new Map(workflow.nodes.map((node) => [node.name, node]));
|
|
183
|
+
const subNodeOutputs = buildSubNodeOutputsMap(workflow, nodeTypeMap, nodeTypesByName);
|
|
184
|
+
const ctx = {
|
|
185
|
+
result: {
|
|
186
|
+
fixed: [],
|
|
187
|
+
unfixable: [],
|
|
188
|
+
updatedConnections: structuredClone(workflow.connections ?? {}),
|
|
189
|
+
},
|
|
190
|
+
nodeTypeMap,
|
|
191
|
+
nodeTypesByName,
|
|
192
|
+
nodesByName,
|
|
193
|
+
subNodeOutputs,
|
|
194
|
+
connectedSubNodes: new Set(),
|
|
195
|
+
workflow,
|
|
196
|
+
};
|
|
197
|
+
const missingInputViolations = violations.filter((v) => v.name === 'node-missing-required-input');
|
|
198
|
+
for (const violation of missingInputViolations) {
|
|
199
|
+
processMissingInputViolation(ctx, violation);
|
|
200
|
+
}
|
|
201
|
+
const disconnectedSubNodeViolations = violations.filter((v) => v.name === 'sub-node-not-connected');
|
|
202
|
+
for (const violation of disconnectedSubNodeViolations) {
|
|
203
|
+
processDisconnectedSubNodeViolation(ctx, violation);
|
|
204
|
+
}
|
|
205
|
+
return ctx.result;
|
|
206
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.autoFixConnections = void 0;
|
|
4
|
+
var auto_fix_connections_1 = require("./auto-fix-connections");
|
|
5
|
+
Object.defineProperty(exports, "autoFixConnections", { enumerable: true, get: function () { return auto_fix_connections_1.autoFixConnections; } });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atom8n/ai-workflow-builder",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"clean": "rimraf dist .turbo",
|
|
6
6
|
"typecheck": "tsc --noEmit",
|
|
@@ -53,20 +53,20 @@
|
|
|
53
53
|
"@langchain/core": "1.1.0",
|
|
54
54
|
"@langchain/langgraph": "1.0.2",
|
|
55
55
|
"@langchain/openai": "1.1.3",
|
|
56
|
-
"@n8n/backend-common": "npm:@atom8n/backend-common@1.
|
|
57
|
-
"@n8n/config": "npm:@atom8n/config@2.
|
|
58
|
-
"@n8n/di": "npm:@atom8n/di@0.
|
|
59
|
-
"@n8n/utils": "npm:@atom8n/utils@1.
|
|
56
|
+
"@n8n/backend-common": "npm:@atom8n/backend-common@1.5.1",
|
|
57
|
+
"@n8n/config": "npm:@atom8n/config@2.4.1",
|
|
58
|
+
"@n8n/di": "npm:@atom8n/di@0.13.1",
|
|
59
|
+
"@n8n/utils": "npm:@atom8n/utils@1.24.1",
|
|
60
60
|
"@n8n_io/ai-assistant-sdk": "1.19.1",
|
|
61
61
|
"csv-parse": "5.5.0",
|
|
62
62
|
"langsmith": "^0.3.45",
|
|
63
63
|
"lodash": "4.17.21",
|
|
64
|
-
"n8n-workflow": "npm:@atom8n/n8n-workflow@2.
|
|
64
|
+
"n8n-workflow": "npm:@atom8n/n8n-workflow@2.5.1",
|
|
65
65
|
"picocolors": "1.0.1",
|
|
66
66
|
"zod": "3.25.67"
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
|
-
"@n8n/typescript-config": "npm:@atom8n/typescript-config@1.
|
|
69
|
+
"@n8n/typescript-config": "npm:@atom8n/typescript-config@1.6.1",
|
|
70
70
|
"@types/cli-progress": "^3.11.5",
|
|
71
71
|
"cli-progress": "^3.12.0",
|
|
72
72
|
"cli-table3": "^0.6.3",
|