@lhi/n8m 0.2.4 → 0.3.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.
- package/README.md +149 -11
- package/dist/agentic/graph.d.ts +16 -4
- package/dist/agentic/nodes/architect.d.ts +2 -2
- package/dist/agentic/nodes/architect.js +5 -1
- package/dist/agentic/nodes/engineer.d.ts +6 -0
- package/dist/agentic/nodes/engineer.js +39 -5
- package/dist/commands/create.js +38 -1
- package/dist/commands/deploy.d.ts +2 -1
- package/dist/commands/deploy.js +119 -19
- package/dist/commands/fixture.js +31 -8
- package/dist/commands/learn.d.ts +19 -0
- package/dist/commands/learn.js +277 -0
- package/dist/commands/modify.js +210 -68
- package/dist/commands/test.d.ts +4 -0
- package/dist/commands/test.js +118 -14
- package/dist/services/ai.service.d.ts +33 -0
- package/dist/services/ai.service.js +337 -2
- package/dist/services/node-definitions.service.d.ts +8 -0
- package/dist/services/node-definitions.service.js +45 -0
- package/dist/utils/fixtureManager.d.ts +10 -0
- package/dist/utils/fixtureManager.js +43 -4
- package/dist/utils/multilinePrompt.js +33 -47
- package/dist/utils/n8nClient.js +60 -11
- package/docs/DEVELOPER_GUIDE.md +598 -0
- package/docs/N8N_NODE_REFERENCE.md +369 -0
- package/docs/patterns/bigquery-via-http.md +110 -0
- package/oclif.manifest.json +82 -3
- package/package.json +3 -1
- package/dist/fixture-schema.json +0 -162
- package/dist/resources/node-definitions-fallback.json +0 -390
- package/dist/resources/node-test-hints.json +0 -188
- package/dist/resources/workflow-test-fixtures.json +0 -42
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
# n8n Node Reference for AI Models
|
|
2
|
+
|
|
3
|
+
This document serves as a static reference for common n8n nodes when the live
|
|
4
|
+
fetch from the n8n instance fails. It covers some of the most frequently used
|
|
5
|
+
nodes and their parameters.
|
|
6
|
+
|
|
7
|
+
## Core Nodes
|
|
8
|
+
|
|
9
|
+
### 1. Manual Trigger (n8n-nodes-base.start)
|
|
10
|
+
|
|
11
|
+
- **Description**: The starting point for manual execution.
|
|
12
|
+
- **Parameters**: (None usually required)
|
|
13
|
+
|
|
14
|
+
### 2. HTTP Request (n8n-nodes-base.httpRequest)
|
|
15
|
+
|
|
16
|
+
- **Description**: Send HTTP requests to any API.
|
|
17
|
+
- **Key Parameters**:
|
|
18
|
+
- `method`: HTTP method (GET, POST, PUT, DELETE, etc.)
|
|
19
|
+
- `url`: The endpoint URL.
|
|
20
|
+
- `authentication`: "none", "predefinedCredentialType".
|
|
21
|
+
- `sendBody`: (boolean) Whether to send a body (required for POST/PUT).
|
|
22
|
+
- `body`: { `contentType`: "json"|"form-data"|"binary", `content`: { ... } }
|
|
23
|
+
- `sendHeaders`: (boolean)
|
|
24
|
+
- `headerParameters`: List of { name, value }.
|
|
25
|
+
|
|
26
|
+
### 3. Slack (n8n-nodes-base.slack)
|
|
27
|
+
|
|
28
|
+
- **Description**: Send messages, manage channels, users, files, and reactions in Slack.
|
|
29
|
+
- **Resources & Operations**:
|
|
30
|
+
- `message`: post | update | delete | get | getAll | search
|
|
31
|
+
- `channel`: create | archive | unarchive | get | getAll | history | invite | join | kick | leave | open | rename | replies | setPurpose | setTopic
|
|
32
|
+
- `file`: upload | get | getAll
|
|
33
|
+
- `reaction`: add | remove | get
|
|
34
|
+
- `user`: get | getAll | getPresence
|
|
35
|
+
- `userGroup`: create | disable | enable | get | getAll
|
|
36
|
+
- **Core Parameters** (message.post):
|
|
37
|
+
- `channel`: Channel name (`#general`) or ID (`C1234567890`). Required.
|
|
38
|
+
- `text`: Plain-text fallback. Required when no blocks/attachments present. Supports mrkdwn if `otherOptions.mrkdwn=true`.
|
|
39
|
+
- `blocksUi`: **Block Kit blocks** as a JSON array string. See Block Kit section below.
|
|
40
|
+
- `attachments`: Legacy Slack attachment array as JSON string. Prefer `blocksUi` for new workflows.
|
|
41
|
+
- **otherOptions** (collection, all optional):
|
|
42
|
+
- `thread_ts`: Timestamp of parent message — posts as a thread reply. Source from `$json.ts` on a previous Slack response.
|
|
43
|
+
- `reply_broadcast`: `true` to also broadcast a thread reply to the channel.
|
|
44
|
+
- `mrkdwn`: `true` to enable Markdown in `text`.
|
|
45
|
+
- `username`: Override the bot display name for this post.
|
|
46
|
+
- `icon_emoji`: Override bot icon with an emoji (`:robot_face:`).
|
|
47
|
+
- `icon_url`: Override bot icon with an image URL.
|
|
48
|
+
- `unfurl_links` / `unfurl_media`: Control link/media previews.
|
|
49
|
+
|
|
50
|
+
#### Block Kit (`blocksUi`) — CRITICAL NOTES
|
|
51
|
+
|
|
52
|
+
`blocksUi` must be a **valid JSON array string** at runtime. n8n parses it with
|
|
53
|
+
`JSON.parse()` — if the expression produces anything invalid the node throws
|
|
54
|
+
`"Parameter 'blocksUi' could not be parsed"`.
|
|
55
|
+
|
|
56
|
+
**Rules:**
|
|
57
|
+
1. The entire value must be a JSON array: `[{...}, {...}]`
|
|
58
|
+
2. n8n expressions (`={{ ... }}`) go **inside string values**, never at the array wrapper level.
|
|
59
|
+
3. If a referenced field might be `null`/`undefined`, guard it: `={{ $json.body.content ?? '' }}`
|
|
60
|
+
4. Keep block text under 3000 chars. Max 50 blocks per message.
|
|
61
|
+
|
|
62
|
+
**Supported block types**: `section`, `header`, `divider`, `image`, `actions`, `context`, `input`
|
|
63
|
+
|
|
64
|
+
**Minimal working examples:**
|
|
65
|
+
|
|
66
|
+
```json
|
|
67
|
+
// Simple text section
|
|
68
|
+
[{"type":"section","text":{"type":"mrkdwn","text":"={{ $json.body.content }}"}}]
|
|
69
|
+
|
|
70
|
+
// Header + body
|
|
71
|
+
[
|
|
72
|
+
{"type":"header","text":{"type":"plain_text","text":"={{ $json.body.title }}","emoji":true}},
|
|
73
|
+
{"type":"section","text":{"type":"mrkdwn","text":"={{ $json.body.content }}"}},
|
|
74
|
+
{"type":"divider"}
|
|
75
|
+
]
|
|
76
|
+
|
|
77
|
+
// Section with two fields side-by-side
|
|
78
|
+
[{"type":"section","fields":[
|
|
79
|
+
{"type":"mrkdwn","text":"*Status:*\n={{ $json.status }}"},
|
|
80
|
+
{"type":"mrkdwn","text":"*Priority:*\n={{ $json.priority }}"}
|
|
81
|
+
]}]
|
|
82
|
+
|
|
83
|
+
// Action buttons
|
|
84
|
+
[{"type":"actions","elements":[
|
|
85
|
+
{"type":"button","text":{"type":"plain_text","text":"Approve"},"style":"primary","action_id":"approve","value":"={{ $json.id }}"},
|
|
86
|
+
{"type":"button","text":{"type":"plain_text","text":"Reject"},"style":"danger","action_id":"reject","value":"={{ $json.id }}"}
|
|
87
|
+
]}]
|
|
88
|
+
|
|
89
|
+
// Context (small grey text)
|
|
90
|
+
[{"type":"context","elements":[{"type":"mrkdwn","text":"Posted by n8m • {{ $now.toISO() }}"}]}]
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Thread reply example:**
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"resource": "message",
|
|
97
|
+
"operation": "post",
|
|
98
|
+
"channel": "#alerts",
|
|
99
|
+
"text": "={{ $json.summary }}",
|
|
100
|
+
"otherOptions": {
|
|
101
|
+
"thread_ts": "={{ $json.ts }}",
|
|
102
|
+
"reply_broadcast": false
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
#### Trigger (n8n-nodes-base.slackTrigger)
|
|
108
|
+
|
|
109
|
+
Receives Slack events via webhooks. Key `triggerOn` values:
|
|
110
|
+
- `message` — new message in a channel
|
|
111
|
+
- `appMention` — bot is @mentioned
|
|
112
|
+
- `reactionAdded` / `reactionRemoved`
|
|
113
|
+
- `teamJoin` — new user joins workspace
|
|
114
|
+
- `channelCreated` — new public channel
|
|
115
|
+
|
|
116
|
+
### 4. Set (n8n-nodes-base.set)
|
|
117
|
+
|
|
118
|
+
- **Description**: Manipulate data or create new variables.
|
|
119
|
+
- **Key Parameters**:
|
|
120
|
+
- `values`: Array of { `name`, `type` (string/number/boolean), `value` }.
|
|
121
|
+
- `options`: { `keepOnlySet`: boolean }.
|
|
122
|
+
|
|
123
|
+
### 5. IF (n8n-nodes-base.if)
|
|
124
|
+
|
|
125
|
+
- **Description**: Conditional logic (True/False branches).
|
|
126
|
+
- **Key Parameters**:
|
|
127
|
+
- `conditions`: { `string`|`number`|`boolean`: [ { `value1`, `operation`,
|
|
128
|
+
`value2` } ] }
|
|
129
|
+
- Common operations: `equals`, `contains`, `isEmpty`, `isTrue`.
|
|
130
|
+
|
|
131
|
+
### 6. Webhook (n8n-nodes-base.webhook)
|
|
132
|
+
|
|
133
|
+
- **Description**: Receive external HTTP requests.
|
|
134
|
+
- **Key Parameters**:
|
|
135
|
+
- `httpMethod`: GET, POST, etc.
|
|
136
|
+
- `path`: URL path.
|
|
137
|
+
- `responseMode`: "onReceived", "lastNode".
|
|
138
|
+
|
|
139
|
+
### 7. Google Sheets (n8n-nodes-base.googleSheets)
|
|
140
|
+
|
|
141
|
+
- **Description**: Read/Write data to Google Sheets.
|
|
142
|
+
- **Key Parameters**:
|
|
143
|
+
- `resource`: "sheet".
|
|
144
|
+
- `operation`: "append", "update", "read".
|
|
145
|
+
- `sheetId`: Spreadsheet ID.
|
|
146
|
+
- `range`: Sheet name and range (e.g., "Sheet1!A:Z").
|
|
147
|
+
|
|
148
|
+
### 8. Code (n8n-nodes-base.code)
|
|
149
|
+
|
|
150
|
+
- **Description**: Run arbitrary JavaScript/TypeScript.
|
|
151
|
+
- **Key Parameters**:
|
|
152
|
+
- `language`: "javaScript" or "typeScript".
|
|
153
|
+
- `jsCode`: The code string.
|
|
154
|
+
|
|
155
|
+
### 9. Schedule Trigger (n8n-nodes-base.scheduleTrigger)
|
|
156
|
+
|
|
157
|
+
- **Description**: Triggers a workflow on a time-based schedule (cron).
|
|
158
|
+
- **Key Parameters**:
|
|
159
|
+
- `rule`: Object with `interval` array. Each entry has:
|
|
160
|
+
- `field`: `"cronExpression"` | `"hours"` | `"days"` | `"weeks"` | `"months"`
|
|
161
|
+
- `expression`: cron string when `field` is `"cronExpression"` (e.g. `"0 9 * * 1-5"`)
|
|
162
|
+
- `hoursInterval` / `minutesInterval`: numeric intervals for simpler schedules
|
|
163
|
+
- **Notes**: Use `cronExpression` for precise schedules (e.g. every weekday at 9 AM). Do NOT use `n8n-nodes-base.cron` — it is deprecated.
|
|
164
|
+
|
|
165
|
+
### 10. Execute Workflow (n8n-nodes-base.executeWorkflow)
|
|
166
|
+
|
|
167
|
+
- **Description**: Call another n8n workflow as a sub-workflow and get its output.
|
|
168
|
+
- **Key Parameters**:
|
|
169
|
+
- `source`: `"database"` (reference by ID) or `"localFile"` (path to JSON).
|
|
170
|
+
- `workflowId`: ID of the workflow to call (when `source` is `"database"`).
|
|
171
|
+
- `options.waitForSubWorkflow`: `true` to wait for the sub-workflow to finish (default).
|
|
172
|
+
|
|
173
|
+
### 11. Execute Workflow Trigger (n8n-nodes-base.executeWorkflowTrigger)
|
|
174
|
+
|
|
175
|
+
- **Description**: The trigger node that receives data when another workflow calls this one via Execute Workflow.
|
|
176
|
+
- **Parameters**: None required. The node receives whatever data the calling workflow sends.
|
|
177
|
+
- **Notes**: Use this as the start node in sub-workflows. Do NOT pair it with `n8n-nodes-base.start` in the same workflow.
|
|
178
|
+
|
|
179
|
+
### 12. Merge (n8n-nodes-base.merge)
|
|
180
|
+
|
|
181
|
+
- **Description**: Combine data from multiple input branches.
|
|
182
|
+
- **Key Parameters**:
|
|
183
|
+
- `mode`: `"append"` | `"mergeByIndex"` | `"mergeByKey"` | `"multiplex"` | `"passThrough"` | `"wait"`
|
|
184
|
+
- `propertyName1` / `propertyName2`: Key fields for `"mergeByKey"` mode.
|
|
185
|
+
- **Common use**: `"append"` to collect results from parallel branches; `"mergeByKey"` to join datasets on a shared field.
|
|
186
|
+
|
|
187
|
+
### 13. Switch (n8n-nodes-base.switch)
|
|
188
|
+
|
|
189
|
+
- **Description**: Route items to different outputs based on a value (multi-branch IF).
|
|
190
|
+
- **Key Parameters**:
|
|
191
|
+
- `dataType`: `"string"` | `"number"` | `"boolean"`
|
|
192
|
+
- `value1`: The value to compare (expression).
|
|
193
|
+
- `rules.rules`: Array of `{ value2, outputKey }` pairs.
|
|
194
|
+
- `fallbackOutput`: Index to route non-matching items (default: ignored).
|
|
195
|
+
|
|
196
|
+
### 14. Loop Over Items (n8n-nodes-base.splitInBatches)
|
|
197
|
+
|
|
198
|
+
- **Description**: Iterate over a list in chunks, re-running downstream nodes for each batch.
|
|
199
|
+
- **Key Parameters**:
|
|
200
|
+
- `batchSize`: Number of items per loop iteration.
|
|
201
|
+
- `options.reset`: `true` to reset the counter on the first run.
|
|
202
|
+
- **Notes**: Connect the "loop" output back to the nodes you want to repeat. Connect the "done" output to what runs after the loop.
|
|
203
|
+
|
|
204
|
+
### 15. Wait (n8n-nodes-base.wait)
|
|
205
|
+
|
|
206
|
+
- **Description**: Pause execution and resume on a webhook call, a time delay, or a specific date/time.
|
|
207
|
+
- **Key Parameters**:
|
|
208
|
+
- `resume`: `"timeInterval"` | `"specificTime"` | `"webhook"`
|
|
209
|
+
- `amount` + `unit`: For `"timeInterval"` (e.g. `amount: 5`, `unit: "minutes"`).
|
|
210
|
+
- `dateTime`: ISO string for `"specificTime"`.
|
|
211
|
+
|
|
212
|
+
### 16. Respond to Webhook (n8n-nodes-base.respondToWebhook)
|
|
213
|
+
|
|
214
|
+
- **Description**: Send an HTTP response back to the caller of a Webhook node.
|
|
215
|
+
- **Key Parameters**:
|
|
216
|
+
- `respondWith`: `"text"` | `"json"` | `"binary"` | `"noData"` | `"redirect"`
|
|
217
|
+
- `responseBody`: The body to return (for `"text"` or `"json"`).
|
|
218
|
+
- `responseCode`: HTTP status code (default `200`).
|
|
219
|
+
- **Notes**: Only valid when the upstream Webhook node has `responseMode: "lastNode"`. Must be the final node in the chain.
|
|
220
|
+
|
|
221
|
+
### 17. Gmail (n8n-nodes-base.gmail)
|
|
222
|
+
|
|
223
|
+
- **Description**: Send, receive, and manage Gmail messages and labels.
|
|
224
|
+
- **Resources & Operations**:
|
|
225
|
+
- `message`: `send` | `get` | `getAll` | `delete` | `reply` | `addLabels` | `removeLabels` | `markAsRead` | `markAsUnread`
|
|
226
|
+
- `label`: `create` | `delete` | `get` | `getAll`
|
|
227
|
+
- **Core send parameters**:
|
|
228
|
+
- `sendTo`: Recipient email address.
|
|
229
|
+
- `subject`: Email subject.
|
|
230
|
+
- `message`: Body text (HTML supported when `emailType: "html"`).
|
|
231
|
+
- `options.attachmentsUi`: List of binary field names to attach.
|
|
232
|
+
|
|
233
|
+
### 18. Gmail Trigger (n8n-nodes-base.gmailTrigger)
|
|
234
|
+
|
|
235
|
+
- **Description**: Polls Gmail and triggers when new messages arrive matching a filter.
|
|
236
|
+
- **Key Parameters**:
|
|
237
|
+
- `filters.labelIds`: Array of Gmail label IDs to watch (e.g. `["INBOX", "UNREAD"]`).
|
|
238
|
+
- `pollTime.mode`: `"everyMinute"` | `"everyHour"` | `"custom"` (cron).
|
|
239
|
+
- `simple`: `true` to return simplified output; `false` for raw Gmail API response.
|
|
240
|
+
|
|
241
|
+
### 19. Postgres (n8n-nodes-base.postgres)
|
|
242
|
+
|
|
243
|
+
- **Description**: Execute queries against a PostgreSQL database.
|
|
244
|
+
- **Key Parameters**:
|
|
245
|
+
- `operation`: `"executeQuery"` | `"insert"` | `"update"` | `"delete"` | `"select"`
|
|
246
|
+
- `query`: Raw SQL (for `"executeQuery"`).
|
|
247
|
+
- `table`: Target table name.
|
|
248
|
+
- `schema`: Schema name (default `"public"`).
|
|
249
|
+
- `columns`: Comma-separated column names for insert/update.
|
|
250
|
+
- **Authentication**: Requires `postgres` credential type.
|
|
251
|
+
|
|
252
|
+
### 20. MySQL (n8n-nodes-base.mySql)
|
|
253
|
+
|
|
254
|
+
- **Description**: Execute queries against a MySQL/MariaDB database.
|
|
255
|
+
- **Key Parameters**: Same pattern as Postgres (`operation`, `query`, `table`).
|
|
256
|
+
- **Authentication**: Requires `mySql` credential type.
|
|
257
|
+
|
|
258
|
+
### 21. Airtable (n8n-nodes-base.airtable)
|
|
259
|
+
|
|
260
|
+
- **Description**: Read, create, update, and delete Airtable records.
|
|
261
|
+
- **Resources & Operations**:
|
|
262
|
+
- `record`: `create` | `delete` | `get` | `list` | `update`
|
|
263
|
+
- **Key Parameters**:
|
|
264
|
+
- `baseId`: Airtable Base ID (starts with `app`).
|
|
265
|
+
- `tableId`: Table ID or name.
|
|
266
|
+
- `fields`: Object of field values for create/update.
|
|
267
|
+
- `filterByFormula`: Airtable formula string for list filtering.
|
|
268
|
+
|
|
269
|
+
### 22. Discord (n8n-nodes-base.discord)
|
|
270
|
+
|
|
271
|
+
- **Description**: Send messages and manage content in Discord channels.
|
|
272
|
+
- **Resources & Operations**:
|
|
273
|
+
- `message`: `send` | `get` | `getAll` | `delete` | `react` | `pin` | `unpin`
|
|
274
|
+
- `channel`: `create` | `delete` | `get` | `getAll` | `update`
|
|
275
|
+
- `member`: `ban` | `get` | `getAll` | `kick` | `roleAdd` | `roleRemove`
|
|
276
|
+
- **Core send parameters**:
|
|
277
|
+
- `channelId`: Target channel ID.
|
|
278
|
+
- `content`: Message text. Supports Discord markdown.
|
|
279
|
+
- `options.embeds`: Array of embed objects.
|
|
280
|
+
|
|
281
|
+
### 23. GitHub (n8n-nodes-base.github)
|
|
282
|
+
|
|
283
|
+
- **Description**: Interact with the GitHub REST API — repos, issues, PRs, releases, files.
|
|
284
|
+
- **Resources & Operations**:
|
|
285
|
+
- `issue`: `create` | `edit` | `get` | `getAll` | `lock` | `createComment`
|
|
286
|
+
- `pullRequest`: `create` | `get` | `getAll` | `createReview` | `merge`
|
|
287
|
+
- `release`: `create` | `delete` | `get` | `getAll` | `update`
|
|
288
|
+
- `file`: `create` | `delete` | `edit` | `get` | `list`
|
|
289
|
+
- `repository`: `get` | `getLicense` | `getProfile` | `listPopularPaths`
|
|
290
|
+
- **Key Parameters**:
|
|
291
|
+
- `owner`: Repository owner (user or org).
|
|
292
|
+
- `repository`: Repository name.
|
|
293
|
+
|
|
294
|
+
### 24. Notion (n8n-nodes-base.notion)
|
|
295
|
+
|
|
296
|
+
- **Description**: Read and write Notion pages, databases, blocks, and users.
|
|
297
|
+
- **Resources & Operations**:
|
|
298
|
+
- `database`: `get` | `getAll` | `search`
|
|
299
|
+
- `databasePage`: `create` | `get` | `getAll` | `update`
|
|
300
|
+
- `page`: `archive` | `create` | `get` | `search` | `update`
|
|
301
|
+
- `block`: `append` | `getAll` | `delete`
|
|
302
|
+
- `user`: `get` | `getAll`
|
|
303
|
+
- **Key Parameters**:
|
|
304
|
+
- `pageId` / `databaseId`: Notion object IDs (32-char hex, no dashes required).
|
|
305
|
+
- `propertiesUi`: Collection of property values for page create/update.
|
|
306
|
+
|
|
307
|
+
### 25. OpenAI (n8n-nodes-base.openAi)
|
|
308
|
+
|
|
309
|
+
- **Description**: Call OpenAI APIs for text, image, audio, and embeddings.
|
|
310
|
+
- **Resources & Operations**:
|
|
311
|
+
- `text`: `message` (chat completions)
|
|
312
|
+
- `image`: `generate` | `analyze`
|
|
313
|
+
- `audio`: `transcribe` | `translate` | `generateSpeech`
|
|
314
|
+
- `assistant`: `create` | `delete` | `get` | `list` | `message` | `update`
|
|
315
|
+
- `file`: `delete` | `get` | `list` | `upload`
|
|
316
|
+
- **Key chat parameters**:
|
|
317
|
+
- `modelId`: e.g. `"gpt-4o"`, `"gpt-4o-mini"`.
|
|
318
|
+
- `messages.values`: Array of `{ role, content }` objects.
|
|
319
|
+
- `options.temperature` / `options.maxTokens`.
|
|
320
|
+
|
|
321
|
+
### 26. AI Agent (n8n-nodes-langchain.agent)
|
|
322
|
+
|
|
323
|
+
- **Description**: An LLM-powered agent that can call tools in a loop to complete a goal.
|
|
324
|
+
- **Key Parameters**:
|
|
325
|
+
- `text`: The user prompt / task description. Supports `={{ $json.query }}`.
|
|
326
|
+
- `options.systemMessage`: System prompt to set the agent's persona.
|
|
327
|
+
- `options.maxIterations`: Maximum tool-call iterations (default 10).
|
|
328
|
+
- **Notes**: This is a LangChain node (`n8n-nodes-langchain`), not `n8n-nodes-base`. It requires sub-nodes connected to the `ai_tool`, `ai_memory`, and `ai_languageModel` inputs.
|
|
329
|
+
|
|
330
|
+
### 27. HTTP Request Tool (n8n-nodes-langchain.toolHttpRequest)
|
|
331
|
+
|
|
332
|
+
- **Description**: Expose an HTTP endpoint as a tool available to an AI Agent node.
|
|
333
|
+
- **Key Parameters**:
|
|
334
|
+
- `url`: The endpoint URL.
|
|
335
|
+
- `method`: HTTP method.
|
|
336
|
+
- `sendBody` / `bodyParameters`: Body to send.
|
|
337
|
+
- `description`: Human-readable description the LLM uses to decide when to call this tool.
|
|
338
|
+
- **Notes**: Connect to the `ai_tool` input of an AI Agent node.
|
|
339
|
+
|
|
340
|
+
### 28. Respond to AI Agent (n8n-nodes-langchain.toolWorkflow)
|
|
341
|
+
|
|
342
|
+
- **Description**: Expose another n8n workflow as a callable tool for an AI Agent.
|
|
343
|
+
- **Key Parameters**:
|
|
344
|
+
- `workflowId`: ID of the sub-workflow to invoke.
|
|
345
|
+
- `description`: What this tool does (seen by the LLM).
|
|
346
|
+
|
|
347
|
+
---
|
|
348
|
+
|
|
349
|
+
## Configuration Patterns
|
|
350
|
+
|
|
351
|
+
- **Authentication**: Most nodes use either `authentication: "none"` or a
|
|
352
|
+
credential type string in `nodeCredentialType`.
|
|
353
|
+
- **Expressions**: Use `={{ ... }}` for dynamic values, e.g.,
|
|
354
|
+
`={{ $json.fieldName }}`. Guard potentially null values:
|
|
355
|
+
`={{ $json.field ?? 'default' }}`.
|
|
356
|
+
- **Accessing upstream nodes**: `$('Node Name').item.json.field` or
|
|
357
|
+
`$('Node Name').all()` to get all items from a named node.
|
|
358
|
+
- **Binary data**: Access binary fields via `$binary.fieldName`. When passing
|
|
359
|
+
binary between nodes, ensure the field name matches exactly what the
|
|
360
|
+
producing node outputs (HTTP Request → `data`, Code nodes → whatever the
|
|
361
|
+
code sets).
|
|
362
|
+
- **Node Connections**: Nodes are connected using the `connections` property in
|
|
363
|
+
the workflow JSON, mapping source node outputs to target node inputs.
|
|
364
|
+
- **Error handling**: Add `"onError": "continueErrorOutput"` to a node's
|
|
365
|
+
settings to route errors to a secondary output instead of stopping the
|
|
366
|
+
workflow.
|
|
367
|
+
- **typeVersion**: Always set the correct `typeVersion` for each node type.
|
|
368
|
+
When in doubt, use the version from the live n8n instance's node schema.
|
|
369
|
+
Using an incorrect version can cause silent failures or missing parameters.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
<!-- keywords: bigquery, google bigquery, bq, sql, analytics, data warehouse, dataset, table, query, merge, insert, drop, create table -->
|
|
2
|
+
|
|
3
|
+
# Pattern: BigQuery Operations via HTTP Request
|
|
4
|
+
|
|
5
|
+
## Critical Rule
|
|
6
|
+
**NEVER use `n8n-nodes-base.googleBigQuery`** — it returns no output items for DDL/DML statements (CREATE, MERGE, UPDATE, DROP), breaking the workflow chain. Always use `n8n-nodes-base.httpRequest` with the BigQuery REST API instead.
|
|
7
|
+
|
|
8
|
+
## Authentication
|
|
9
|
+
All BigQuery HTTP nodes must use:
|
|
10
|
+
```json
|
|
11
|
+
{
|
|
12
|
+
"authentication": "predefinedCredentialType",
|
|
13
|
+
"nodeCredentialType": "googleApi"
|
|
14
|
+
}
|
|
15
|
+
```
|
|
16
|
+
The `googleApi` credential must have scopes: `https://www.googleapis.com/auth/bigquery`
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## DDL / DML Queries (CREATE, MERGE, UPDATE, DROP)
|
|
21
|
+
|
|
22
|
+
Use the `jobs.query` synchronous endpoint. It always returns a JSON response, ensuring the workflow continues.
|
|
23
|
+
|
|
24
|
+
```json
|
|
25
|
+
{
|
|
26
|
+
"parameters": {
|
|
27
|
+
"method": "POST",
|
|
28
|
+
"url": "=https://bigquery.googleapis.com/bigquery/v2/projects/YOUR_PROJECT/queries",
|
|
29
|
+
"authentication": "predefinedCredentialType",
|
|
30
|
+
"nodeCredentialType": "googleApi",
|
|
31
|
+
"sendBody": true,
|
|
32
|
+
"specifyBody": "json",
|
|
33
|
+
"jsonBody": "={{ JSON.stringify({ query: 'YOUR SQL HERE', useLegacySql: false, timeoutMs: 30000 }) }}",
|
|
34
|
+
"options": {}
|
|
35
|
+
},
|
|
36
|
+
"type": "n8n-nodes-base.httpRequest",
|
|
37
|
+
"typeVersion": 4
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### CREATE TABLE example
|
|
42
|
+
```json
|
|
43
|
+
"jsonBody": "={{ JSON.stringify({ query: 'CREATE OR REPLACE TABLE `project.dataset.table` (Email STRING, Name STRING, Stripe_plan STRING, Unsubscribed BOOL)', useLegacySql: false, timeoutMs: 30000 }) }}"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### MERGE example (reference earlier node for dynamic table name)
|
|
47
|
+
```json
|
|
48
|
+
"jsonBody": "={{ JSON.stringify({ query: 'MERGE INTO `project.dataset.target` T USING `project.dataset.' + $('Parse CSV').item.json.stagingTable + '` S ON T.Email = S.Email WHEN MATCHED THEN UPDATE SET T.Name = S.Name WHEN NOT MATCHED THEN INSERT (Email, Name) VALUES (S.Email, S.Name)', useLegacySql: false, timeoutMs: 30000 }) }}"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### UPDATE example
|
|
52
|
+
```json
|
|
53
|
+
"jsonBody": "={{ JSON.stringify({ query: 'UPDATE `project.dataset.table` T SET T.active = false WHERE T.id NOT IN (SELECT id FROM `project.dataset.' + $('upstream').item.json.stagingTable + '`)', useLegacySql: false, timeoutMs: 30000 }) }}"
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### DROP TABLE example
|
|
57
|
+
```json
|
|
58
|
+
"jsonBody": "={{ JSON.stringify({ query: 'DROP TABLE IF EXISTS `project.dataset.' + $('upstream').item.json.stagingTable + '`', useLegacySql: false, timeoutMs: 30000 }) }}"
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Streaming Insert (insertAll)
|
|
64
|
+
|
|
65
|
+
For inserting rows, use the `tabledata.insertAll` endpoint:
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"parameters": {
|
|
70
|
+
"method": "POST",
|
|
71
|
+
"url": "=https://bigquery.googleapis.com/bigquery/v2/projects/YOUR_PROJECT/datasets/YOUR_DATASET/tables/{{ $('upstream').item.json.stagingTable }}/insertAll",
|
|
72
|
+
"authentication": "predefinedCredentialType",
|
|
73
|
+
"nodeCredentialType": "googleApi",
|
|
74
|
+
"sendBody": true,
|
|
75
|
+
"specifyBody": "json",
|
|
76
|
+
"jsonBody": "={{ JSON.stringify({ rows: $('Parse CSV').item.json.rows }) }}",
|
|
77
|
+
"options": {}
|
|
78
|
+
},
|
|
79
|
+
"type": "n8n-nodes-base.httpRequest",
|
|
80
|
+
"typeVersion": 4
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Each row in `rows` must have an `insertId` (string) and `json` object:
|
|
85
|
+
```json
|
|
86
|
+
{ "insertId": "0", "json": { "Email": "user@example.com", "Name": "User" } }
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## Error Cleanup Pattern
|
|
92
|
+
|
|
93
|
+
When a workflow creates a staging table, all intermediate nodes must have an error connection to a cleanup node that drops the table. This prevents orphaned tables on failure.
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
"connections": {
|
|
97
|
+
"Create Staging Table": {
|
|
98
|
+
"main": [ [ { "node": "Insert Rows", "type": "main", "index": 0 } ] ],
|
|
99
|
+
"error": [ [ { "node": "Drop Staging Table (Error)", "type": "main", "index": 0 } ] ]
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
The error cleanup node uses `$('Generate Table Name').item.json.stagingTable` (not `$('Parse CSV')`) because errors may fire before the CSV parsing node runs.
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Required IAM Roles for Service Account
|
|
109
|
+
- `roles/bigquery.jobUser` — run jobs
|
|
110
|
+
- `roles/bigquery.dataEditor` — read/write table data
|
package/oclif.manifest.json
CHANGED
|
@@ -122,13 +122,14 @@
|
|
|
122
122
|
"aliases": [],
|
|
123
123
|
"args": {
|
|
124
124
|
"workflow": {
|
|
125
|
-
"description": "Path to
|
|
125
|
+
"description": "Path to workflow JSON file (omit for interactive menu)",
|
|
126
126
|
"name": "workflow",
|
|
127
|
-
"required":
|
|
127
|
+
"required": false
|
|
128
128
|
}
|
|
129
129
|
},
|
|
130
130
|
"description": "Push workflows to n8n instance via API",
|
|
131
131
|
"examples": [
|
|
132
|
+
"<%= config.bin %> <%= command.id %>",
|
|
132
133
|
"<%= config.bin %> <%= command.id %> ./workflows/slack-notifier.json"
|
|
133
134
|
],
|
|
134
135
|
"flags": {
|
|
@@ -147,6 +148,14 @@
|
|
|
147
148
|
"name": "activate",
|
|
148
149
|
"allowNo": false,
|
|
149
150
|
"type": "boolean"
|
|
151
|
+
},
|
|
152
|
+
"dir": {
|
|
153
|
+
"char": "d",
|
|
154
|
+
"description": "Directory to scan for workflows (default: ./workflows)",
|
|
155
|
+
"name": "dir",
|
|
156
|
+
"hasDynamicHelp": false,
|
|
157
|
+
"multiple": false,
|
|
158
|
+
"type": "option"
|
|
150
159
|
}
|
|
151
160
|
},
|
|
152
161
|
"hasDynamicHelp": false,
|
|
@@ -239,6 +248,76 @@
|
|
|
239
248
|
"fixture.js"
|
|
240
249
|
]
|
|
241
250
|
},
|
|
251
|
+
"learn": {
|
|
252
|
+
"aliases": [],
|
|
253
|
+
"args": {
|
|
254
|
+
"workflow": {
|
|
255
|
+
"description": "Path to workflow JSON file (omit for interactive menu)",
|
|
256
|
+
"name": "workflow",
|
|
257
|
+
"required": false
|
|
258
|
+
}
|
|
259
|
+
},
|
|
260
|
+
"description": "Extract reusable patterns from a validated workflow into the pattern library",
|
|
261
|
+
"examples": [
|
|
262
|
+
"<%= config.bin %> <%= command.id %>",
|
|
263
|
+
"<%= config.bin %> <%= command.id %> ./workflows/my-workflow/workflow.json",
|
|
264
|
+
"<%= config.bin %> <%= command.id %> --github owner/repo",
|
|
265
|
+
"<%= config.bin %> <%= command.id %> --github owner/repo --github-path patterns/google"
|
|
266
|
+
],
|
|
267
|
+
"flags": {
|
|
268
|
+
"dir": {
|
|
269
|
+
"char": "d",
|
|
270
|
+
"description": "Directory to scan for workflows (default: ./workflows)",
|
|
271
|
+
"name": "dir",
|
|
272
|
+
"hasDynamicHelp": false,
|
|
273
|
+
"multiple": false,
|
|
274
|
+
"type": "option"
|
|
275
|
+
},
|
|
276
|
+
"all": {
|
|
277
|
+
"description": "Generate patterns for all workflows in the directory",
|
|
278
|
+
"name": "all",
|
|
279
|
+
"allowNo": false,
|
|
280
|
+
"type": "boolean"
|
|
281
|
+
},
|
|
282
|
+
"github": {
|
|
283
|
+
"description": "Import patterns from a GitHub repo (format: owner/repo or owner/repo@branch)",
|
|
284
|
+
"name": "github",
|
|
285
|
+
"hasDynamicHelp": false,
|
|
286
|
+
"multiple": false,
|
|
287
|
+
"type": "option"
|
|
288
|
+
},
|
|
289
|
+
"github-path": {
|
|
290
|
+
"description": "Path within the GitHub repo to import from (default: patterns)",
|
|
291
|
+
"name": "github-path",
|
|
292
|
+
"default": "patterns",
|
|
293
|
+
"hasDynamicHelp": false,
|
|
294
|
+
"multiple": false,
|
|
295
|
+
"type": "option"
|
|
296
|
+
},
|
|
297
|
+
"token": {
|
|
298
|
+
"description": "GitHub personal access token (increases rate limit for public repos)",
|
|
299
|
+
"env": "GITHUB_TOKEN",
|
|
300
|
+
"name": "token",
|
|
301
|
+
"hasDynamicHelp": false,
|
|
302
|
+
"multiple": false,
|
|
303
|
+
"type": "option"
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
"hasDynamicHelp": false,
|
|
307
|
+
"hiddenAliases": [],
|
|
308
|
+
"id": "learn",
|
|
309
|
+
"pluginAlias": "@lhi/n8m",
|
|
310
|
+
"pluginName": "@lhi/n8m",
|
|
311
|
+
"pluginType": "core",
|
|
312
|
+
"strict": true,
|
|
313
|
+
"enableJsonFlag": false,
|
|
314
|
+
"isESM": true,
|
|
315
|
+
"relativePath": [
|
|
316
|
+
"dist",
|
|
317
|
+
"commands",
|
|
318
|
+
"learn.js"
|
|
319
|
+
]
|
|
320
|
+
},
|
|
242
321
|
"mcp": {
|
|
243
322
|
"aliases": [],
|
|
244
323
|
"args": {},
|
|
@@ -439,5 +518,5 @@
|
|
|
439
518
|
]
|
|
440
519
|
}
|
|
441
520
|
},
|
|
442
|
-
"version": "0.
|
|
521
|
+
"version": "0.3.0"
|
|
443
522
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lhi/n8m",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Agentic n8n CLI wrapper - A Skill Bridge for n8n workflow automation",
|
|
5
5
|
"author": "Lem Canady",
|
|
6
6
|
"license": "MIT",
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"files": [
|
|
16
16
|
"bin",
|
|
17
17
|
"dist",
|
|
18
|
+
"docs",
|
|
18
19
|
"oclif.manifest.json"
|
|
19
20
|
],
|
|
20
21
|
"dependencies": {
|
|
@@ -94,6 +95,7 @@
|
|
|
94
95
|
"n8m": "./bin/run.js",
|
|
95
96
|
"start": "npm run build && ./bin/run.js",
|
|
96
97
|
"dev": "tsc -b -w",
|
|
98
|
+
"generate-patterns": "tsx scripts/generate-patterns.ts",
|
|
97
99
|
"version": "oclif readme && git add README.md"
|
|
98
100
|
}
|
|
99
101
|
}
|