@n8n/ai-workflow-builder 0.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.
@@ -0,0 +1,10 @@
1
+ import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
2
+ import { SystemMessage } from '@langchain/core/messages';
3
+ export declare const connectionComposerPrompt: SystemMessage;
4
+ export declare const connectionComposerChain: (llm: BaseChatModel) => import("@langchain/core/runnables").Runnable<any, Record<string, {
5
+ main: {
6
+ type: "main";
7
+ node: string;
8
+ index: number;
9
+ }[][];
10
+ }>, import("@langchain/core/runnables").RunnableConfig<Record<string, any>>>;
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.connectionComposerChain = exports.connectionComposerPrompt = void 0;
4
+ const messages_1 = require("@langchain/core/messages");
5
+ const prompts_1 = require("@langchain/core/prompts");
6
+ const tools_1 = require("@langchain/core/tools");
7
+ const n8n_workflow_1 = require("n8n-workflow");
8
+ const zod_1 = require("zod");
9
+ exports.connectionComposerPrompt = new messages_1.SystemMessage(`You are an expert in creating n8n workflow connections. Your job is to create a valid n8n workflow by connecting nodes in a logical sequence.
10
+
11
+ ## Your Task
12
+ Create connections between nodes that form a coherent, executable workflow based on the user's request.
13
+
14
+ ## Input Format
15
+ You will receive a list of n8n nodes with their details in <node> tags:
16
+ \`\`\`
17
+ <node>
18
+ {
19
+ "name": "Node display name",
20
+ "type": "n8n-nodes-base.nodeType",
21
+ "parameters": { ... },
22
+ "position": [x, y]
23
+ }
24
+ </node>
25
+ \`\`\`
26
+
27
+ ## n8n Connection Structure
28
+ In n8n workflows:
29
+ 1. Data flows from one node to the next through connections
30
+ 2. Connections are defined in the "connections" object
31
+ 3. Each node's output can connect to one or more nodes' inputs
32
+ 4. Each connection has a source node, target node, and IO indices
33
+
34
+ ## Connection Format
35
+ \`\`\`json
36
+ {
37
+ "connections": {
38
+ "Source Node Display Name": {
39
+ "main": [
40
+ [
41
+ {
42
+ "node": "Target Node Display Name",
43
+ "type": "main",
44
+ "index": 0
45
+ }
46
+ ]
47
+ ]
48
+ }
49
+ }
50
+ }
51
+ \`\`\`
52
+
53
+ ## Rules for Creating Connections
54
+ 1. ALWAYS use the node "name" field (display name) for the connection references
55
+ 2. Create a logical flow from trigger/input nodes to output/action nodes
56
+ 3. Each node MUST connect to at least one other node (except terminal nodes)
57
+ 4. Don't create loops or cycles in the workflow
58
+ 5. Ensure the output data from one node is compatible with the input expected by the next node
59
+ 6. For nodes with multiple outputs (like IF nodes), connect each output appropriately:
60
+ - For IF nodes, first output (index 0) is the TRUE branch, second output (index 1) is the FALSE branch
61
+ - For Switch nodes, each output (starting at index 0) corresponds to a different case
62
+
63
+ ## Common Workflow Patterns
64
+ 1. Trigger → Process → Action
65
+ 2. Data Source → Filter/Transform → Destination
66
+ 3. Scheduled Trigger → HTTP Request → Process Response → Send Notification
67
+ 4. Conditional Branch: Previous Node → IF Node → [True Branch, False Branch]
68
+
69
+ ## Output
70
+ Return ONLY a valid JSON object with the "connections" property following the structure above:
71
+ \`\`\`json
72
+ {
73
+ "connections": {
74
+ "NodeName1": {
75
+ "main": [[{ "node": "NodeName2", "type": "main", "index": 0 }]]
76
+ },
77
+ "NodeName2": {
78
+ "main": [
79
+ [{ "node": "TrueBranchNode", "type": "main", "index": 0 }],
80
+ [{ "node": "FalseBranchNode", "type": "main", "index": 0 }]
81
+ ]
82
+ },
83
+ ...
84
+ }
85
+ }
86
+ \`\`\``);
87
+ const connectionsSchema = zod_1.z.object({
88
+ connections: zod_1.z
89
+ .record(zod_1.z
90
+ .string()
91
+ .describe('The source node\'s display name exactly as specified in the node\'s "name" field'), zod_1.z
92
+ .object({
93
+ main: zod_1.z.array(zod_1.z.array(zod_1.z.object({
94
+ node: zod_1.z
95
+ .string()
96
+ .describe('The target node\'s display name exactly as specified in the node\'s "name" field'),
97
+ type: zod_1.z
98
+ .literal('main')
99
+ .describe('The connection type, always use "main" for standard n8n connections'),
100
+ index: zod_1.z
101
+ .number()
102
+ .describe('Output index from the source node, typically 0 for single-output nodes, 0=true/1=false for IF nodes'),
103
+ }))),
104
+ })
105
+ .describe('The connection configuration for a single source node'))
106
+ .describe('A mapping of all connections in the workflow, where each key is a source node name'),
107
+ });
108
+ const connectionComposerTool = new tools_1.DynamicStructuredTool({
109
+ name: 'compose_connections',
110
+ description: "Create valid connections between n8n nodes to form a coherent, executable workflow that implements the user's request.",
111
+ schema: connectionsSchema,
112
+ func: async (input) => {
113
+ return { connections: input.connections };
114
+ },
115
+ });
116
+ const humanTemplate = '{workflowJSON}';
117
+ const chatPrompt = prompts_1.ChatPromptTemplate.fromMessages([
118
+ exports.connectionComposerPrompt,
119
+ prompts_1.HumanMessagePromptTemplate.fromTemplate(humanTemplate),
120
+ ]);
121
+ const connectionComposerChain = (llm) => {
122
+ if (!llm.bindTools) {
123
+ throw new n8n_workflow_1.OperationalError("LLM doesn't support binding tools");
124
+ }
125
+ return chatPrompt
126
+ .pipe(llm.bindTools([connectionComposerTool], {
127
+ tool_choice: connectionComposerTool.name,
128
+ }))
129
+ .pipe((x) => {
130
+ const toolCall = x.tool_calls?.[0];
131
+ return (toolCall?.args).connections;
132
+ });
133
+ };
134
+ exports.connectionComposerChain = connectionComposerChain;
135
+ //# sourceMappingURL=connection-composer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connection-composer.js","sourceRoot":"","sources":["../../src/chains/connection-composer.ts"],"names":[],"mappings":";;;AAEA,uDAAyD;AACzD,qDAAyF;AACzF,iDAA8D;AAC9D,+CAAgD;AAChD,6BAAwB;AAEX,QAAA,wBAAwB,GAAG,IAAI,wBAAa,CACxD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6EM,CACN,CAAC;AAEF,MAAM,iBAAiB,GAAG,OAAC,CAAC,MAAM,CAAC;IAClC,WAAW,EAAE,OAAC;SACZ,MAAM,CACN,OAAC;SACC,MAAM,EAAE;SACR,QAAQ,CACR,kFAAkF,CAClF,EACF,OAAC;SACC,MAAM,CAAC;QACP,IAAI,EAAE,OAAC,CAAC,KAAK,CACZ,OAAC,CAAC,KAAK,CACN,OAAC,CAAC,MAAM,CAAC;YACR,IAAI,EAAE,OAAC;iBACL,MAAM,EAAE;iBACR,QAAQ,CACR,kFAAkF,CAClF;YACF,IAAI,EAAE,OAAC;iBACL,OAAO,CAAC,MAAM,CAAC;iBACf,QAAQ,CAAC,qEAAqE,CAAC;YACjF,KAAK,EAAE,OAAC;iBACN,MAAM,EAAE;iBACR,QAAQ,CACR,qGAAqG,CACrG;SACF,CAAC,CACF,CACD;KACD,CAAC;SACD,QAAQ,CAAC,uDAAuD,CAAC,CACnE;SACA,QAAQ,CAAC,oFAAoF,CAAC;CAChG,CAAC,CAAC;AAEH,MAAM,sBAAsB,GAAG,IAAI,6BAAqB,CAAC;IACxD,IAAI,EAAE,qBAAqB;IAC3B,WAAW,EACV,wHAAwH;IACzH,MAAM,EAAE,iBAAiB;IACzB,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE;QACrB,OAAO,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC;IAC3C,CAAC;CACD,CAAC,CAAC;AAEH,MAAM,aAAa,GAAG,gBAAgB,CAAC;AACvC,MAAM,UAAU,GAAG,4BAAkB,CAAC,YAAY,CAAC;IAClD,gCAAwB;IACxB,oCAA0B,CAAC,YAAY,CAAC,aAAa,CAAC;CACtD,CAAC,CAAC;AAEI,MAAM,uBAAuB,GAAG,CAAC,GAAkB,EAAE,EAAE;IAC7D,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;QACpB,MAAM,IAAI,+BAAgB,CAAC,mCAAmC,CAAC,CAAC;IACjE,CAAC;IAED,OAAO,UAAU;SACf,IAAI,CACJ,GAAG,CAAC,SAAS,CAAC,CAAC,sBAAsB,CAAC,EAAE;QACvC,WAAW,EAAE,sBAAsB,CAAC,IAAI;KACxC,CAAC,CACF;SACA,IAAI,CAAC,CAAC,CAAiB,EAAE,EAAE;QAC3B,MAAM,QAAQ,GAAG,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;QACnC,OAAO,CAAC,QAAQ,EAAE,IAA0C,CAAA,CAAC,WAAW,CAAC;IAC1E,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAfW,QAAA,uBAAuB,2BAelC"}
@@ -0,0 +1,8 @@
1
+ import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
2
+ import { SystemMessage } from '@langchain/core/messages';
3
+ export declare const nodeSelectorPrompt: SystemMessage;
4
+ export declare const nodesSelectionChain: (llm: BaseChatModel) => import("@langchain/core/runnables").Runnable<any, {
5
+ node: string;
6
+ score: number;
7
+ reasoning: string;
8
+ }[], import("@langchain/core/runnables").RunnableConfig<Record<string, any>>>;
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.nodesSelectionChain = exports.nodeSelectorPrompt = void 0;
4
+ const messages_1 = require("@langchain/core/messages");
5
+ const prompts_1 = require("@langchain/core/prompts");
6
+ const tools_1 = require("@langchain/core/tools");
7
+ const n8n_workflow_1 = require("n8n-workflow");
8
+ const zod_1 = require("zod");
9
+ exports.nodeSelectorPrompt = new messages_1.SystemMessage(`You are an expert in n8n workflows who selects the optimal n8n nodes to implement workflow steps.
10
+
11
+ ## Your Task
12
+ For each workflow step, recommend the most appropriate n8n nodes from the allowed list.
13
+
14
+ ## Input Information
15
+ - <user_request>: Original user workflow request
16
+ - <steps>: List of workflow steps to implement
17
+ - <allowed_n8n_nodes>: List of available n8n nodes with descriptions
18
+
19
+ ## CRITICAL REQUIREMENTS
20
+ - ONLY recommend nodes that EXACTLY match names from the <allowed_n8n_nodes> list
21
+ - NEVER suggest nodes that are not explicitly defined in <allowed_n8n_nodes>
22
+ - ALWAYS use the COMPLETE node name as it appears in <node_name> tags (e.g., "Gmail" is NOT sufficient if the node name is "n8n-nodes-base.gmail")
23
+ - VERIFY each recommended node exists in the allowed list before including it
24
+
25
+ ## Selection Criteria
26
+ 1. Functionality - Node must be able to perform the required action
27
+ 2. Integration - Prefer nodes that integrate directly with services mentioned in the user request
28
+ 3. Efficiency - Prefer nodes that accomplish the task with minimal configuration
29
+
30
+ ## Output Requirements
31
+ For the planned workflow steps, provider:
32
+ 1. List of all possibly useful nodes in order of preference
33
+ 2. Concise reasoning for why each node is suitable
34
+ 3. Use EXACT, FULL node names from <node_name> tags
35
+ 4. Pay attention to case sensitivity, e.g. "n8n-nodes-base.msql" is NOT "n8n-nodes-base.mySql"!
36
+
37
+ Remember: ONLY use nodes from the <allowed_n8n_nodes> list and ALWAYS use their FULL names exactly as provided.`);
38
+ const nodeSelectorSchema = zod_1.z.object({
39
+ recommended_nodes: zod_1.z
40
+ .array(zod_1.z.object({
41
+ score: zod_1.z.number().describe('Matching score of the node for all the workflows steps'),
42
+ node: zod_1.z
43
+ .string()
44
+ .describe('The full node type identifier (e.g., "n8n-nodes-base.if") from <allowed_n8n_nodes> list'),
45
+ reasoning: zod_1.z
46
+ .string()
47
+ .describe('Very short explanation of why this node might be used to implement the workflow step'),
48
+ }))
49
+ .min(1)
50
+ .max(20)
51
+ .describe('Recommended n8n nodes for implementing any of the workflow steps, in order of descending preference. ONLY use nodes from the <allowed_n8n_nodes> list with EXACT full names from <node_name> tags.'),
52
+ });
53
+ const nodeSelectorTool = new tools_1.DynamicStructuredTool({
54
+ name: 'select_n8n_nodes',
55
+ description: 'Match each workflow step with the most appropriate n8n nodes from the allowed list, ensuring they can implement the required functionality.',
56
+ schema: nodeSelectorSchema,
57
+ func: async ({ recommended_nodes }) => {
58
+ return { recommended_nodes };
59
+ },
60
+ });
61
+ const humanTemplate = `
62
+ <user_request>
63
+ {prompt}
64
+ </user_request>
65
+ <steps>
66
+ {steps}
67
+ </steps>
68
+ <allowed_n8n_nodes>
69
+ {allowedNodes}
70
+ </allowed_n8n_nodes>
71
+ `;
72
+ const chatPrompt = prompts_1.ChatPromptTemplate.fromMessages([
73
+ exports.nodeSelectorPrompt,
74
+ prompts_1.HumanMessagePromptTemplate.fromTemplate(humanTemplate),
75
+ ]);
76
+ const nodesSelectionChain = (llm) => {
77
+ if (!llm.bindTools) {
78
+ throw new n8n_workflow_1.OperationalError("LLM doesn't support binding tools");
79
+ }
80
+ return chatPrompt
81
+ .pipe(llm.bindTools([nodeSelectorTool], {
82
+ tool_choice: nodeSelectorTool.name,
83
+ }))
84
+ .pipe((x) => {
85
+ const toolCall = x.tool_calls?.[0];
86
+ return (toolCall?.args).recommended_nodes;
87
+ });
88
+ };
89
+ exports.nodesSelectionChain = nodesSelectionChain;
90
+ //# sourceMappingURL=node-selector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"node-selector.js","sourceRoot":"","sources":["../../src/chains/node-selector.ts"],"names":[],"mappings":";;;AAEA,uDAAyD;AACzD,qDAAyF;AACzF,iDAA8D;AAC9D,+CAAgD;AAChD,6BAAwB;AAEX,QAAA,kBAAkB,GAAG,IAAI,wBAAa,CAClD;;;;;;;;;;;;;;;;;;;;;;;;;;;;gHA4B+G,CAC/G,CAAC;AACF,MAAM,kBAAkB,GAAG,OAAC,CAAC,MAAM,CAAC;IACnC,iBAAiB,EAAE,OAAC;SAClB,KAAK,CACL,OAAC,CAAC,MAAM,CAAC;QACR,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wDAAwD,CAAC;QACpF,IAAI,EAAE,OAAC;aACL,MAAM,EAAE;aACR,QAAQ,CACR,yFAAyF,CACzF;QACF,SAAS,EAAE,OAAC;aACV,MAAM,EAAE;aACR,QAAQ,CACR,sFAAsF,CACtF;KACF,CAAC,CACF;SACA,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,EAAE,CAAC;SACP,QAAQ,CACR,oMAAoM,CACpM;CACF,CAAC,CAAC;AAEH,MAAM,gBAAgB,GAAG,IAAI,6BAAqB,CAAC;IAClD,IAAI,EAAE,kBAAkB;IACxB,WAAW,EACV,6IAA6I;IAC9I,MAAM,EAAE,kBAAkB;IAC1B,IAAI,EAAE,KAAK,EAAE,EAAE,iBAAiB,EAAE,EAAE,EAAE;QACrC,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC9B,CAAC;CACD,CAAC,CAAC;AAEH,MAAM,aAAa,GAAG;;;;;;;;;;CAUrB,CAAC;AAEF,MAAM,UAAU,GAAG,4BAAkB,CAAC,YAAY,CAAC;IAClD,0BAAkB;IAClB,oCAA0B,CAAC,YAAY,CAAC,aAAa,CAAC;CACtD,CAAC,CAAC;AAEI,MAAM,mBAAmB,GAAG,CAAC,GAAkB,EAAE,EAAE;IACzD,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;QACpB,MAAM,IAAI,+BAAgB,CAAC,mCAAmC,CAAC,CAAC;IACjE,CAAC;IAED,OAAO,UAAU;SACf,IAAI,CACJ,GAAG,CAAC,SAAS,CAAC,CAAC,gBAAgB,CAAC,EAAE;QACjC,WAAW,EAAE,gBAAgB,CAAC,IAAI;KAClC,CAAC,CACF;SACA,IAAI,CAAC,CAAC,CAAiB,EAAE,EAAE;QAC3B,MAAM,QAAQ,GAAG,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;QACnC,OAAO,CAAC,QAAQ,EAAE,IAA2C,CAAA,CAAC,iBAAiB,CAAC;IACjF,CAAC,CAAC,CAAC;AACL,CAAC,CAAC;AAfW,QAAA,mBAAmB,uBAe9B"}
@@ -0,0 +1,8 @@
1
+ import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
2
+ import { ChatPromptTemplate } from '@langchain/core/prompts';
3
+ export declare const nodesComposerPrompt: ChatPromptTemplate<any, any>;
4
+ export declare const nodesComposerChain: (llm: BaseChatModel) => import("@langchain/core/runnables").Runnable<any, {
5
+ type: string;
6
+ parameters: Record<string, any>;
7
+ name: string;
8
+ }[], import("@langchain/core/runnables").RunnableConfig<Record<string, any>>>;