@n8n/workflow-sdk 0.9.0 → 0.10.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.
Files changed (183) hide show
  1. package/dist/build.tsbuildinfo +1 -1
  2. package/dist/generate-types/generate-types.js +1 -1
  3. package/dist/generate-types/generate-types.js.map +1 -1
  4. package/dist/index.d.ts +1 -0
  5. package/dist/index.js +4 -2
  6. package/dist/index.js.map +1 -1
  7. package/dist/prompts/best-practices/guides/chatbot.d.ts +7 -0
  8. package/dist/prompts/best-practices/guides/chatbot.js +120 -0
  9. package/dist/prompts/best-practices/guides/chatbot.js.map +1 -0
  10. package/dist/prompts/best-practices/guides/content-generation.d.ts +7 -0
  11. package/dist/prompts/best-practices/guides/content-generation.js +117 -0
  12. package/dist/prompts/best-practices/guides/content-generation.js.map +1 -0
  13. package/dist/prompts/best-practices/guides/data-analysis.d.ts +7 -0
  14. package/dist/prompts/best-practices/guides/data-analysis.js +369 -0
  15. package/dist/prompts/best-practices/guides/data-analysis.js.map +1 -0
  16. package/dist/prompts/best-practices/guides/data-extraction.d.ts +7 -0
  17. package/dist/prompts/best-practices/guides/data-extraction.js +124 -0
  18. package/dist/prompts/best-practices/guides/data-extraction.js.map +1 -0
  19. package/dist/prompts/best-practices/guides/data-persistence.d.ts +7 -0
  20. package/dist/prompts/best-practices/guides/data-persistence.js +199 -0
  21. package/dist/prompts/best-practices/guides/data-persistence.js.map +1 -0
  22. package/dist/prompts/best-practices/guides/data-transformation.d.ts +7 -0
  23. package/dist/prompts/best-practices/guides/data-transformation.js +148 -0
  24. package/dist/prompts/best-practices/guides/data-transformation.js.map +1 -0
  25. package/dist/prompts/best-practices/guides/document-processing.d.ts +7 -0
  26. package/dist/prompts/best-practices/guides/document-processing.js +334 -0
  27. package/dist/prompts/best-practices/guides/document-processing.js.map +1 -0
  28. package/dist/prompts/best-practices/guides/enrichment.d.ts +7 -0
  29. package/dist/prompts/best-practices/guides/enrichment.js +273 -0
  30. package/dist/prompts/best-practices/guides/enrichment.js.map +1 -0
  31. package/dist/prompts/best-practices/guides/form-input.d.ts +7 -0
  32. package/dist/prompts/best-practices/guides/form-input.js +175 -0
  33. package/dist/prompts/best-practices/guides/form-input.js.map +1 -0
  34. package/dist/prompts/best-practices/guides/human-in-the-loop.d.ts +7 -0
  35. package/dist/prompts/best-practices/guides/human-in-the-loop.js +270 -0
  36. package/dist/prompts/best-practices/guides/human-in-the-loop.js.map +1 -0
  37. package/dist/prompts/best-practices/guides/knowledge-base.d.ts +7 -0
  38. package/dist/prompts/best-practices/guides/knowledge-base.js +270 -0
  39. package/dist/prompts/best-practices/guides/knowledge-base.js.map +1 -0
  40. package/dist/prompts/best-practices/guides/monitoring.d.ts +7 -0
  41. package/dist/prompts/best-practices/guides/monitoring.js +173 -0
  42. package/dist/prompts/best-practices/guides/monitoring.js.map +1 -0
  43. package/dist/prompts/best-practices/guides/notification.d.ts +7 -0
  44. package/dist/prompts/best-practices/guides/notification.js +137 -0
  45. package/dist/prompts/best-practices/guides/notification.js.map +1 -0
  46. package/dist/prompts/best-practices/guides/scheduling.d.ts +7 -0
  47. package/dist/prompts/best-practices/guides/scheduling.js +154 -0
  48. package/dist/prompts/best-practices/guides/scheduling.js.map +1 -0
  49. package/dist/prompts/best-practices/guides/scraping-and-research.d.ts +7 -0
  50. package/dist/prompts/best-practices/guides/scraping-and-research.js +160 -0
  51. package/dist/prompts/best-practices/guides/scraping-and-research.js.map +1 -0
  52. package/dist/prompts/best-practices/guides/triage.d.ts +7 -0
  53. package/dist/prompts/best-practices/guides/triage.js +151 -0
  54. package/dist/prompts/best-practices/guides/triage.js.map +1 -0
  55. package/dist/prompts/best-practices/index.d.ts +20 -0
  56. package/dist/prompts/best-practices/index.js +69 -0
  57. package/dist/prompts/best-practices/index.js.map +1 -0
  58. package/dist/prompts/best-practices/types.d.ts +25 -0
  59. package/dist/prompts/best-practices/types.js +40 -0
  60. package/dist/prompts/best-practices/types.js.map +1 -0
  61. package/dist/prompts/index.d.ts +3 -0
  62. package/dist/prompts/index.js +25 -0
  63. package/dist/prompts/index.js.map +1 -0
  64. package/dist/prompts/node-guidance/index.d.ts +3 -0
  65. package/dist/prompts/node-guidance/index.js +20 -0
  66. package/dist/prompts/node-guidance/index.js.map +1 -0
  67. package/dist/prompts/node-guidance/node-recommendations/audio-generation.d.ts +2 -0
  68. package/dist/prompts/node-guidance/node-recommendations/audio-generation.js +18 -0
  69. package/dist/prompts/node-guidance/node-recommendations/audio-generation.js.map +1 -0
  70. package/dist/prompts/node-guidance/node-recommendations/format-recommendation.d.ts +2 -0
  71. package/dist/prompts/node-guidance/node-recommendations/format-recommendation.js +27 -0
  72. package/dist/prompts/node-guidance/node-recommendations/format-recommendation.js.map +1 -0
  73. package/dist/prompts/node-guidance/node-recommendations/image-generation.d.ts +2 -0
  74. package/dist/prompts/node-guidance/node-recommendations/image-generation.js +18 -0
  75. package/dist/prompts/node-guidance/node-recommendations/image-generation.js.map +1 -0
  76. package/dist/prompts/node-guidance/node-recommendations/index.d.ts +6 -0
  77. package/dist/prompts/node-guidance/node-recommendations/index.js +17 -0
  78. package/dist/prompts/node-guidance/node-recommendations/index.js.map +1 -0
  79. package/dist/prompts/node-guidance/node-recommendations/text-manipulation.d.ts +2 -0
  80. package/dist/prompts/node-guidance/node-recommendations/text-manipulation.js +27 -0
  81. package/dist/prompts/node-guidance/node-recommendations/text-manipulation.js.map +1 -0
  82. package/dist/prompts/node-guidance/node-recommendations/types.d.ts +26 -0
  83. package/dist/prompts/node-guidance/node-recommendations/types.js +16 -0
  84. package/dist/prompts/node-guidance/node-recommendations/types.js.map +1 -0
  85. package/dist/prompts/node-guidance/node-recommendations/video-generation.d.ts +2 -0
  86. package/dist/prompts/node-guidance/node-recommendations/video-generation.js +15 -0
  87. package/dist/prompts/node-guidance/node-recommendations/video-generation.js.map +1 -0
  88. package/dist/prompts/node-guidance/node-tips/index.d.ts +3 -0
  89. package/dist/prompts/node-guidance/node-tips/index.js +8 -0
  90. package/dist/prompts/node-guidance/node-tips/index.js.map +1 -0
  91. package/dist/prompts/node-guidance/node-tips/structured-output-parser.d.ts +2 -0
  92. package/dist/prompts/node-guidance/node-tips/structured-output-parser.js +35 -0
  93. package/dist/prompts/node-guidance/node-tips/structured-output-parser.js.map +1 -0
  94. package/dist/prompts/node-guidance/node-tips/types.d.ts +7 -0
  95. package/dist/prompts/node-guidance/node-tips/types.js +3 -0
  96. package/dist/prompts/node-guidance/node-tips/types.js.map +1 -0
  97. package/dist/prompts/node-guidance/node-tips/webhook.d.ts +2 -0
  98. package/dist/prompts/node-guidance/node-tips/webhook.js +38 -0
  99. package/dist/prompts/node-guidance/node-tips/webhook.js.map +1 -0
  100. package/dist/prompts/node-guidance/parameter-guides/embedding-nodes.d.ts +2 -0
  101. package/dist/prompts/node-guidance/parameter-guides/embedding-nodes.js +70 -0
  102. package/dist/prompts/node-guidance/parameter-guides/embedding-nodes.js.map +1 -0
  103. package/dist/prompts/node-guidance/parameter-guides/gmail.d.ts +2 -0
  104. package/dist/prompts/node-guidance/parameter-guides/gmail.js +53 -0
  105. package/dist/prompts/node-guidance/parameter-guides/gmail.js.map +1 -0
  106. package/dist/prompts/node-guidance/parameter-guides/http-request.d.ts +2 -0
  107. package/dist/prompts/node-guidance/parameter-guides/http-request.js +139 -0
  108. package/dist/prompts/node-guidance/parameter-guides/http-request.js.map +1 -0
  109. package/dist/prompts/node-guidance/parameter-guides/if-node.d.ts +2 -0
  110. package/dist/prompts/node-guidance/parameter-guides/if-node.js +159 -0
  111. package/dist/prompts/node-guidance/parameter-guides/if-node.js.map +1 -0
  112. package/dist/prompts/node-guidance/parameter-guides/index.d.ts +12 -0
  113. package/dist/prompts/node-guidance/parameter-guides/index.js +26 -0
  114. package/dist/prompts/node-guidance/parameter-guides/index.js.map +1 -0
  115. package/dist/prompts/node-guidance/parameter-guides/predecessor-output.d.ts +2 -0
  116. package/dist/prompts/node-guidance/parameter-guides/predecessor-output.js +25 -0
  117. package/dist/prompts/node-guidance/parameter-guides/predecessor-output.js.map +1 -0
  118. package/dist/prompts/node-guidance/parameter-guides/resource-locator.d.ts +2 -0
  119. package/dist/prompts/node-guidance/parameter-guides/resource-locator.js +40 -0
  120. package/dist/prompts/node-guidance/parameter-guides/resource-locator.js.map +1 -0
  121. package/dist/prompts/node-guidance/parameter-guides/set-node.d.ts +2 -0
  122. package/dist/prompts/node-guidance/parameter-guides/set-node.js +94 -0
  123. package/dist/prompts/node-guidance/parameter-guides/set-node.js.map +1 -0
  124. package/dist/prompts/node-guidance/parameter-guides/switch-node.d.ts +2 -0
  125. package/dist/prompts/node-guidance/parameter-guides/switch-node.js +75 -0
  126. package/dist/prompts/node-guidance/parameter-guides/switch-node.js.map +1 -0
  127. package/dist/prompts/node-guidance/parameter-guides/system-message.d.ts +2 -0
  128. package/dist/prompts/node-guidance/parameter-guides/system-message.js +96 -0
  129. package/dist/prompts/node-guidance/parameter-guides/system-message.js.map +1 -0
  130. package/dist/prompts/node-guidance/parameter-guides/text-fields.d.ts +2 -0
  131. package/dist/prompts/node-guidance/parameter-guides/text-fields.js +31 -0
  132. package/dist/prompts/node-guidance/parameter-guides/text-fields.js.map +1 -0
  133. package/dist/prompts/node-guidance/parameter-guides/tool-nodes.d.ts +2 -0
  134. package/dist/prompts/node-guidance/parameter-guides/tool-nodes.js +76 -0
  135. package/dist/prompts/node-guidance/parameter-guides/tool-nodes.js.map +1 -0
  136. package/dist/prompts/node-guidance/parameter-guides/types.d.ts +18 -0
  137. package/dist/prompts/node-guidance/parameter-guides/types.js +3 -0
  138. package/dist/prompts/node-guidance/parameter-guides/types.js.map +1 -0
  139. package/dist/prompts/node-selection/ai-nodes.d.ts +2 -0
  140. package/dist/prompts/node-selection/ai-nodes.js +35 -0
  141. package/dist/prompts/node-selection/ai-nodes.js.map +1 -0
  142. package/dist/prompts/node-selection/connection-parameters.d.ts +1 -0
  143. package/dist/prompts/node-selection/connection-parameters.js +13 -0
  144. package/dist/prompts/node-selection/connection-parameters.js.map +1 -0
  145. package/dist/prompts/node-selection/index.d.ts +5 -0
  146. package/dist/prompts/node-selection/index.js +16 -0
  147. package/dist/prompts/node-selection/index.js.map +1 -0
  148. package/dist/prompts/node-selection/native-preference.d.ts +1 -0
  149. package/dist/prompts/node-selection/native-preference.js +18 -0
  150. package/dist/prompts/node-selection/native-preference.js.map +1 -0
  151. package/dist/prompts/node-selection/trigger-selection.d.ts +1 -0
  152. package/dist/prompts/node-selection/trigger-selection.js +23 -0
  153. package/dist/prompts/node-selection/trigger-selection.js.map +1 -0
  154. package/dist/prompts/node-selection/use-case-patterns.d.ts +2 -0
  155. package/dist/prompts/node-selection/use-case-patterns.js +58 -0
  156. package/dist/prompts/node-selection/use-case-patterns.js.map +1 -0
  157. package/dist/prompts/sdk-reference/additional-functions.d.ts +1 -0
  158. package/dist/prompts/sdk-reference/additional-functions.js +20 -0
  159. package/dist/prompts/sdk-reference/additional-functions.js.map +1 -0
  160. package/dist/prompts/sdk-reference/expressions.d.ts +1 -0
  161. package/dist/prompts/sdk-reference/expressions.js +34 -0
  162. package/dist/prompts/sdk-reference/expressions.js.map +1 -0
  163. package/dist/prompts/sdk-reference/index.d.ts +5 -0
  164. package/dist/prompts/sdk-reference/index.js +14 -0
  165. package/dist/prompts/sdk-reference/index.js.map +1 -0
  166. package/dist/prompts/sdk-reference/workflow-patterns-detailed.d.ts +1 -0
  167. package/dist/prompts/sdk-reference/workflow-patterns-detailed.js +398 -0
  168. package/dist/prompts/sdk-reference/workflow-patterns-detailed.js.map +1 -0
  169. package/dist/prompts/sdk-reference/workflow-patterns.d.ts +2 -0
  170. package/dist/prompts/sdk-reference/workflow-patterns.js +479 -0
  171. package/dist/prompts/sdk-reference/workflow-patterns.js.map +1 -0
  172. package/dist/prompts/sdk-reference/workflow-rules.d.ts +1 -0
  173. package/dist/prompts/sdk-reference/workflow-rules.js +23 -0
  174. package/dist/prompts/sdk-reference/workflow-rules.js.map +1 -0
  175. package/dist/workflow-builder/plugins/defaults.js +1 -0
  176. package/dist/workflow-builder/plugins/defaults.js.map +1 -1
  177. package/dist/workflow-builder/plugins/validators/filter-node-validator.d.ts +2 -0
  178. package/dist/workflow-builder/plugins/validators/filter-node-validator.js +90 -0
  179. package/dist/workflow-builder/plugins/validators/filter-node-validator.js.map +1 -0
  180. package/dist/workflow-builder/plugins/validators/index.d.ts +1 -0
  181. package/dist/workflow-builder/plugins/validators/index.js +3 -1
  182. package/dist/workflow-builder/plugins/validators/index.js.map +1 -1
  183. package/package.json +50 -4
@@ -0,0 +1 @@
1
+ export declare const WORKFLOW_PATTERNS_DETAILED = "<linear_chain>\n```javascript\nimport { workflow, node, trigger, sticky, placeholder, newCredential, ifElse, switchCase, merge, splitInBatches, nextBatch, languageModel, memory, tool, outputParser, embedding, embeddings, vectorStore, retriever, documentLoader, textSplitter, reranker, fromAi, expr } from '@n8n/workflow-sdk';\n\n// 1. Define all nodes first\nconst startTrigger = trigger({\n type: 'n8n-nodes-base.manualTrigger',\n version: 1,\n config: { name: 'Start', position: [240, 300] },\n output: [{}]\n});\n\nconst fetchData = node({\n type: 'n8n-nodes-base.httpRequest',\n version: 4.3,\n config: { name: 'Fetch Data', parameters: { method: 'GET', url: '...' }, position: [540, 300] },\n output: [{ id: 1, title: 'Item 1' }]\n});\n\nconst processData = node({\n type: 'n8n-nodes-base.set',\n version: 3.4,\n config: { name: 'Process Data', parameters: {}, position: [840, 300] },\n output: [{ id: 1, title: 'Item 1', processed: true }]\n});\n\n// 2. Compose workflow\nexport default workflow('id', 'name')\n .add(startTrigger)\n .to(fetchData)\n .to(processData);\n```\n\n</linear_chain>\n\n<independent_sources>\nWhen nodes return more than 1 item, chaining causes item multiplication: if Source A returns N items, a chained Source B runs N times instead of once.\n\nFix with `executeOnce: true` (simplest) or parallel branches + Merge (when combining results):\n\n```javascript\n// sourceA outputs 10 items. sourceB outputs 10 items.\n// sourceB runs once per item from sourceA.\n// WRONG - processResults runs 100 times\n// startTrigger.to(sourceA.to(sourceB.to(processResults)))\n\n// FIX 1 - executeOnce: sourceB runs once regardless of input items\nconst sourceB = node({ ..., config: { ..., executeOnce: true } });\nstartTrigger.to(sourceA.to(sourceB.to(processResults)));\n\n// FIX 2 - parallel branches + Merge (combine by position)\n// Pairs items by index, merging fields from both inputs into one item.\n// @example input0: [{ a: 1 }, { a: 2 }] input1: [{ b: 10, c: 'x' }, { b: 20 }]\n// output: [{ a: 1, b: 10, c: 'x' }, { a: 2, b: 20, c: undefined }]\nconst combineResults = merge({\n version: 3.2,\n config: { name: 'Combine Results', parameters: { mode: 'combine', combineBy: 'combineByPosition' } }\n});\nexport default workflow('id', 'name')\n .add(startTrigger)\n .to(sourceA.to(combineResults.input(0)))\n .add(startTrigger)\n .to(sourceB.to(combineResults.input(1)))\n .add(combineResults)\n .to(processResults);\n\n// FIX 3 - parallel branches + Merge (append)\n// Concatenates all items from all inputs into one list sequentially.\n// @example input0: [{ a: 1 }, { a: 2 }] input1: [{ b: 10 }]\n// output: [{ a: 1 }, { a: 2 }, { b: 10 }]\nconst allResults = merge({\n version: 3.2,\n config: { name: 'All Results', parameters: { mode: 'append' } }\n});\nexport default workflow('id', 'name')\n .add(startTrigger)\n .to(sourceA.to(allResults.input(0)))\n .add(startTrigger)\n .to(sourceB.to(allResults.input(1)))\n .add(allResults)\n .to(processResults);\n```\n\n</independent_sources>\n\n<conditional_branching>\n\n**CRITICAL:** Each branch defines a COMPLETE processing path. Chain multiple steps INSIDE the branch using .to().\n\n```javascript\n// Assume other nodes are declared\nconst checkValid = ifElse({ version: 2.2, config: { name: 'Check Valid', parameters: {...} } });\n\nexport default workflow('id', 'name')\n .add(startTrigger)\n .to(checkValid\n .onTrue(formatData.to(enrichData.to(saveToDb))) // Chain 3 nodes on true branch\n .onFalse(logError));\n```\n\n</conditional_branching>\n\n<multi_way_routing>\n\n```javascript\n// Assume other nodes are declared\nconst routeByPriority = switchCase({ version: 3.2, config: { name: 'Route by Priority', parameters: {...} } });\n\nexport default workflow('id', 'name')\n .add(startTrigger)\n .to(routeByPriority\n .onCase(0, processUrgent.to(notifyTeam.to(escalate))) // Chain of 3 nodes\n .onCase(1, processNormal)\n .onCase(2, archive));\n```\n\n</multi_way_routing>\n\n<parallel_execution>\n```javascript\nconst combineResults = merge({\n version: 3.2,\n config: {\n name: 'Combine Results',\n parameters: { mode: 'combine' },\n position: [840, 300]\n }\n});\n\nconst branch1 = node({ type: 'n8n-nodes-base.httpRequest', ... });\nconst branch2 = node({ type: 'n8n-nodes-base.httpRequest', ... });\nconst processResults = node({ type: 'n8n-nodes-base.set', ... });\n\n// Connect branches to specific merge inputs using .input(n)\nexport default workflow('id', 'name')\n .add(trigger({ ... }))\n .to(branch1.to(combineResults.input(0)))\n .add(trigger({ ... }))\n .to(branch2.to(combineResults.input(1)))\n .add(combineResults)\n .to(processResults);\n```\n\n</parallel_execution>\n\n<batch_processing>\n```javascript\nconst startTrigger = trigger({\n type: 'n8n-nodes-base.manualTrigger', version: 1,\n config: { name: 'Start', position: [240, 300] },\n output: [{}]\n});\n\nconst fetchRecords = node({\n type: 'n8n-nodes-base.httpRequest', version: 4.3,\n config: { name: 'Fetch Records', parameters: { method: 'GET', url: '...' }, position: [540, 300] },\n output: [{ id: 1 }, { id: 2 }, { id: 3 }]\n});\n\nconst finalizeResults = node({\n type: 'n8n-nodes-base.set', version: 3.4,\n config: { name: 'Finalize', parameters: {}, position: [1140, 200] },\n output: [{ summary: 'Processed 3 records' }]\n});\n\nconst processRecord = node({\n type: 'n8n-nodes-base.httpRequest', version: 4.3,\n config: { name: 'Process Record', parameters: { method: 'POST', url: '...' }, position: [1140, 400] },\n output: [{ id: 1, status: 'processed' }]\n});\n\nconst sibNode = splitInBatches({ version: 3, config: { name: 'Batch Process', parameters: { batchSize: 10 }, position: [840, 300] } });\n\nexport default workflow('id', 'name')\n .add(startTrigger)\n .to(fetchRecords)\n .to(sibNode\n .onDone(finalizeResults)\n .onEachBatch(processRecord.to(nextBatch(sibNode)))\n );\n```\n\n</batch_processing>\n\n<multiple_triggers>\n```javascript\nconst webhookTrigger = trigger({\n type: 'n8n-nodes-base.webhook', version: 2.1,\n config: { name: 'Webhook', position: [240, 200] },\n output: [{ body: { data: 'webhook payload' } }]\n});\n\nconst processWebhook = node({\n type: 'n8n-nodes-base.set', version: 3.4,\n config: { name: 'Process Webhook', parameters: {}, position: [540, 200] },\n output: [{ data: 'webhook payload', processed: true }]\n});\n\nconst scheduleTrigger = trigger({\n type: 'n8n-nodes-base.scheduleTrigger', version: 1.3,\n config: { name: 'Daily Schedule', parameters: {}, position: [240, 500] },\n output: [{}]\n});\n\nconst processSchedule = node({\n type: 'n8n-nodes-base.set', version: 3.4,\n config: { name: 'Process Schedule', parameters: {}, position: [540, 500] },\n output: [{ scheduled: true }]\n});\n\nexport default workflow('id', 'name')\n .add(webhookTrigger)\n .to(processWebhook)\n .add(scheduleTrigger)\n .to(processSchedule);\n```\n\n</multiple_triggers>\n\n<fan_in>\n```javascript\n// Each trigger's execution runs in COMPLETE ISOLATION.\n// Different branches have no effect on each other.\n// Never duplicate chains for \"isolation\" - it's already guaranteed.\n\nconst webhookTrigger = trigger({\n type: 'n8n-nodes-base.webhook', version: 2.1,\n config: { name: 'Webhook Trigger', position: [240, 200] },\n output: [{ source: 'webhook' }]\n});\n\nconst scheduleTrigger = trigger({\n type: 'n8n-nodes-base.scheduleTrigger', version: 1.3,\n config: { name: 'Daily Schedule', position: [240, 500] },\n output: [{ source: 'schedule' }]\n});\n\nconst processData = node({\n type: 'n8n-nodes-base.set', version: 3.4,\n config: { name: 'Process Data', parameters: {}, position: [540, 350] },\n output: [{ processed: true }]\n});\n\nconst sendNotification = node({\n type: 'n8n-nodes-base.slack', version: 2.3,\n config: { name: 'Notify Slack', parameters: {}, position: [840, 350] },\n output: [{ ok: true }]\n});\n\nexport default workflow('id', 'name')\n .add(webhookTrigger)\n .to(processData)\n .to(sendNotification)\n .add(scheduleTrigger)\n .to(processData);\n```\n\n</fan_in>\n\n<ai_agent_basic>\n```javascript\nconst openAiModel = languageModel({\n type: '@n8n/n8n-nodes-langchain.lmChatOpenAi', version: 1.3,\n config: { name: 'OpenAI Model', parameters: {}, position: [540, 500] }\n});\n\nconst startTrigger = trigger({\n type: 'n8n-nodes-base.manualTrigger', version: 1,\n config: { name: 'Start', position: [240, 300] },\n output: [{}]\n});\n\nconst aiAgent = node({\n type: '@n8n/n8n-nodes-langchain.agent', version: 3.1,\n config: {\n name: 'AI Assistant',\n parameters: { promptType: 'define', text: 'You are a helpful assistant' },\n subnodes: { model: openAiModel },\n position: [540, 300]\n },\n output: [{ output: 'AI response text' }]\n});\n\nexport default workflow('ai-assistant', 'AI Assistant')\n .add(startTrigger)\n .to(aiAgent);\n```\n\n</ai_agent_basic>\n\n<ai_agent_with_tools>\n```javascript\nconst openAiModel = languageModel({\n type: '@n8n/n8n-nodes-langchain.lmChatOpenAi', version: 1.3,\n config: {\n name: 'OpenAI Model', parameters: {},\n credentials: { openAiApi: newCredential('OpenAI') },\n position: [540, 500]\n }\n});\n\nconst calculatorTool = tool({\n type: '@n8n/n8n-nodes-langchain.toolCalculator', version: 1,\n config: { name: 'Calculator', parameters: {}, position: [700, 500] }\n});\n\nconst startTrigger = trigger({\n type: 'n8n-nodes-base.manualTrigger', version: 1,\n config: { name: 'Start', position: [240, 300] },\n output: [{}]\n});\n\nconst aiAgent = node({\n type: '@n8n/n8n-nodes-langchain.agent', version: 3.1,\n config: {\n name: 'Math Agent',\n parameters: { promptType: 'define', text: 'You can use tools to help users' },\n subnodes: { model: openAiModel, tools: [calculatorTool] },\n position: [540, 300]\n },\n output: [{ output: '42' }]\n});\n\nexport default workflow('ai-calculator', 'AI Calculator')\n .add(startTrigger)\n .to(aiAgent);\n```\n\n</ai_agent_with_tools>\n\n<ai_agent_with_from_ai>\n```javascript\nconst gmailTool = tool({\n type: 'n8n-nodes-base.gmailTool', version: 1,\n config: {\n name: 'Gmail Tool',\n parameters: {\n sendTo: fromAi('recipient', 'Email address'),\n subject: fromAi('subject', 'Email subject'),\n message: fromAi('body', 'Email content')\n },\n credentials: { gmailOAuth2: newCredential('Gmail') },\n position: [700, 500]\n }\n});\n\nconst aiAgent = node({\n type: '@n8n/n8n-nodes-langchain.agent', version: 3.1,\n config: {\n name: 'Email Agent',\n parameters: { promptType: 'define', text: 'You can send emails' },\n subnodes: { model: openAiModel, tools: [gmailTool] },\n position: [540, 300]\n },\n output: [{ output: 'Email sent successfully' }]\n});\n\nexport default workflow('ai-email', 'AI Email Sender')\n .add(startTrigger)\n .to(aiAgent);\n```\n</ai_agent_with_from_ai>\n\n<ai_agent_with_structured_output>\n```javascript\nconst structuredParser = outputParser({\n type: '@n8n/n8n-nodes-langchain.outputParserStructured', version: 1.3,\n config: {\n name: 'Structured Output Parser',\n parameters: {\n schemaType: 'fromJson',\n jsonSchemaExample: '{ \"sentiment\": \"positive\", \"confidence\": 0.95, \"summary\": \"brief summary\" }'\n },\n position: [700, 500]\n }\n});\n\nconst aiAgent = node({\n type: '@n8n/n8n-nodes-langchain.agent', version: 3.1,\n config: {\n name: 'Sentiment Analyzer',\n parameters: { promptType: 'define', text: 'Analyze the sentiment of the input text', hasOutputParser: true },\n subnodes: { model: openAiModel, outputParser: structuredParser },\n position: [540, 300]\n },\n output: [{ sentiment: 'positive', confidence: 0.95, summary: 'The text expresses satisfaction' }]\n});\n\nexport default workflow('ai-sentiment', 'AI Sentiment Analyzer')\n .add(startTrigger)\n .to(aiAgent);\n```\n</ai_agent_with_structured_output>";
@@ -0,0 +1,398 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WORKFLOW_PATTERNS_DETAILED = void 0;
4
+ const SDK_IMPORT = "import { workflow, node, trigger, sticky, placeholder, newCredential, ifElse, switchCase, merge, splitInBatches, nextBatch, languageModel, memory, tool, outputParser, embedding, embeddings, vectorStore, retriever, documentLoader, textSplitter, reranker, fromAi, expr } from '@n8n/workflow-sdk';";
5
+ exports.WORKFLOW_PATTERNS_DETAILED = `<linear_chain>
6
+ \`\`\`javascript
7
+ ${SDK_IMPORT}
8
+
9
+ // 1. Define all nodes first
10
+ const startTrigger = trigger({
11
+ type: 'n8n-nodes-base.manualTrigger',
12
+ version: 1,
13
+ config: { name: 'Start', position: [240, 300] },
14
+ output: [{}]
15
+ });
16
+
17
+ const fetchData = node({
18
+ type: 'n8n-nodes-base.httpRequest',
19
+ version: 4.3,
20
+ config: { name: 'Fetch Data', parameters: { method: 'GET', url: '...' }, position: [540, 300] },
21
+ output: [{ id: 1, title: 'Item 1' }]
22
+ });
23
+
24
+ const processData = node({
25
+ type: 'n8n-nodes-base.set',
26
+ version: 3.4,
27
+ config: { name: 'Process Data', parameters: {}, position: [840, 300] },
28
+ output: [{ id: 1, title: 'Item 1', processed: true }]
29
+ });
30
+
31
+ // 2. Compose workflow
32
+ export default workflow('id', 'name')
33
+ .add(startTrigger)
34
+ .to(fetchData)
35
+ .to(processData);
36
+ \`\`\`
37
+
38
+ </linear_chain>
39
+
40
+ <independent_sources>
41
+ When nodes return more than 1 item, chaining causes item multiplication: if Source A returns N items, a chained Source B runs N times instead of once.
42
+
43
+ Fix with \`executeOnce: true\` (simplest) or parallel branches + Merge (when combining results):
44
+
45
+ \`\`\`javascript
46
+ // sourceA outputs 10 items. sourceB outputs 10 items.
47
+ // sourceB runs once per item from sourceA.
48
+ // WRONG - processResults runs 100 times
49
+ // startTrigger.to(sourceA.to(sourceB.to(processResults)))
50
+
51
+ // FIX 1 - executeOnce: sourceB runs once regardless of input items
52
+ const sourceB = node({ ..., config: { ..., executeOnce: true } });
53
+ startTrigger.to(sourceA.to(sourceB.to(processResults)));
54
+
55
+ // FIX 2 - parallel branches + Merge (combine by position)
56
+ // Pairs items by index, merging fields from both inputs into one item.
57
+ // @example input0: [{ a: 1 }, { a: 2 }] input1: [{ b: 10, c: 'x' }, { b: 20 }]
58
+ // output: [{ a: 1, b: 10, c: 'x' }, { a: 2, b: 20, c: undefined }]
59
+ const combineResults = merge({
60
+ version: 3.2,
61
+ config: { name: 'Combine Results', parameters: { mode: 'combine', combineBy: 'combineByPosition' } }
62
+ });
63
+ export default workflow('id', 'name')
64
+ .add(startTrigger)
65
+ .to(sourceA.to(combineResults.input(0)))
66
+ .add(startTrigger)
67
+ .to(sourceB.to(combineResults.input(1)))
68
+ .add(combineResults)
69
+ .to(processResults);
70
+
71
+ // FIX 3 - parallel branches + Merge (append)
72
+ // Concatenates all items from all inputs into one list sequentially.
73
+ // @example input0: [{ a: 1 }, { a: 2 }] input1: [{ b: 10 }]
74
+ // output: [{ a: 1 }, { a: 2 }, { b: 10 }]
75
+ const allResults = merge({
76
+ version: 3.2,
77
+ config: { name: 'All Results', parameters: { mode: 'append' } }
78
+ });
79
+ export default workflow('id', 'name')
80
+ .add(startTrigger)
81
+ .to(sourceA.to(allResults.input(0)))
82
+ .add(startTrigger)
83
+ .to(sourceB.to(allResults.input(1)))
84
+ .add(allResults)
85
+ .to(processResults);
86
+ \`\`\`
87
+
88
+ </independent_sources>
89
+
90
+ <conditional_branching>
91
+
92
+ **CRITICAL:** Each branch defines a COMPLETE processing path. Chain multiple steps INSIDE the branch using .to().
93
+
94
+ \`\`\`javascript
95
+ // Assume other nodes are declared
96
+ const checkValid = ifElse({ version: 2.2, config: { name: 'Check Valid', parameters: {...} } });
97
+
98
+ export default workflow('id', 'name')
99
+ .add(startTrigger)
100
+ .to(checkValid
101
+ .onTrue(formatData.to(enrichData.to(saveToDb))) // Chain 3 nodes on true branch
102
+ .onFalse(logError));
103
+ \`\`\`
104
+
105
+ </conditional_branching>
106
+
107
+ <multi_way_routing>
108
+
109
+ \`\`\`javascript
110
+ // Assume other nodes are declared
111
+ const routeByPriority = switchCase({ version: 3.2, config: { name: 'Route by Priority', parameters: {...} } });
112
+
113
+ export default workflow('id', 'name')
114
+ .add(startTrigger)
115
+ .to(routeByPriority
116
+ .onCase(0, processUrgent.to(notifyTeam.to(escalate))) // Chain of 3 nodes
117
+ .onCase(1, processNormal)
118
+ .onCase(2, archive));
119
+ \`\`\`
120
+
121
+ </multi_way_routing>
122
+
123
+ <parallel_execution>
124
+ \`\`\`javascript
125
+ const combineResults = merge({
126
+ version: 3.2,
127
+ config: {
128
+ name: 'Combine Results',
129
+ parameters: { mode: 'combine' },
130
+ position: [840, 300]
131
+ }
132
+ });
133
+
134
+ const branch1 = node({ type: 'n8n-nodes-base.httpRequest', ... });
135
+ const branch2 = node({ type: 'n8n-nodes-base.httpRequest', ... });
136
+ const processResults = node({ type: 'n8n-nodes-base.set', ... });
137
+
138
+ // Connect branches to specific merge inputs using .input(n)
139
+ export default workflow('id', 'name')
140
+ .add(trigger({ ... }))
141
+ .to(branch1.to(combineResults.input(0)))
142
+ .add(trigger({ ... }))
143
+ .to(branch2.to(combineResults.input(1)))
144
+ .add(combineResults)
145
+ .to(processResults);
146
+ \`\`\`
147
+
148
+ </parallel_execution>
149
+
150
+ <batch_processing>
151
+ \`\`\`javascript
152
+ const startTrigger = trigger({
153
+ type: 'n8n-nodes-base.manualTrigger', version: 1,
154
+ config: { name: 'Start', position: [240, 300] },
155
+ output: [{}]
156
+ });
157
+
158
+ const fetchRecords = node({
159
+ type: 'n8n-nodes-base.httpRequest', version: 4.3,
160
+ config: { name: 'Fetch Records', parameters: { method: 'GET', url: '...' }, position: [540, 300] },
161
+ output: [{ id: 1 }, { id: 2 }, { id: 3 }]
162
+ });
163
+
164
+ const finalizeResults = node({
165
+ type: 'n8n-nodes-base.set', version: 3.4,
166
+ config: { name: 'Finalize', parameters: {}, position: [1140, 200] },
167
+ output: [{ summary: 'Processed 3 records' }]
168
+ });
169
+
170
+ const processRecord = node({
171
+ type: 'n8n-nodes-base.httpRequest', version: 4.3,
172
+ config: { name: 'Process Record', parameters: { method: 'POST', url: '...' }, position: [1140, 400] },
173
+ output: [{ id: 1, status: 'processed' }]
174
+ });
175
+
176
+ const sibNode = splitInBatches({ version: 3, config: { name: 'Batch Process', parameters: { batchSize: 10 }, position: [840, 300] } });
177
+
178
+ export default workflow('id', 'name')
179
+ .add(startTrigger)
180
+ .to(fetchRecords)
181
+ .to(sibNode
182
+ .onDone(finalizeResults)
183
+ .onEachBatch(processRecord.to(nextBatch(sibNode)))
184
+ );
185
+ \`\`\`
186
+
187
+ </batch_processing>
188
+
189
+ <multiple_triggers>
190
+ \`\`\`javascript
191
+ const webhookTrigger = trigger({
192
+ type: 'n8n-nodes-base.webhook', version: 2.1,
193
+ config: { name: 'Webhook', position: [240, 200] },
194
+ output: [{ body: { data: 'webhook payload' } }]
195
+ });
196
+
197
+ const processWebhook = node({
198
+ type: 'n8n-nodes-base.set', version: 3.4,
199
+ config: { name: 'Process Webhook', parameters: {}, position: [540, 200] },
200
+ output: [{ data: 'webhook payload', processed: true }]
201
+ });
202
+
203
+ const scheduleTrigger = trigger({
204
+ type: 'n8n-nodes-base.scheduleTrigger', version: 1.3,
205
+ config: { name: 'Daily Schedule', parameters: {}, position: [240, 500] },
206
+ output: [{}]
207
+ });
208
+
209
+ const processSchedule = node({
210
+ type: 'n8n-nodes-base.set', version: 3.4,
211
+ config: { name: 'Process Schedule', parameters: {}, position: [540, 500] },
212
+ output: [{ scheduled: true }]
213
+ });
214
+
215
+ export default workflow('id', 'name')
216
+ .add(webhookTrigger)
217
+ .to(processWebhook)
218
+ .add(scheduleTrigger)
219
+ .to(processSchedule);
220
+ \`\`\`
221
+
222
+ </multiple_triggers>
223
+
224
+ <fan_in>
225
+ \`\`\`javascript
226
+ // Each trigger's execution runs in COMPLETE ISOLATION.
227
+ // Different branches have no effect on each other.
228
+ // Never duplicate chains for "isolation" - it's already guaranteed.
229
+
230
+ const webhookTrigger = trigger({
231
+ type: 'n8n-nodes-base.webhook', version: 2.1,
232
+ config: { name: 'Webhook Trigger', position: [240, 200] },
233
+ output: [{ source: 'webhook' }]
234
+ });
235
+
236
+ const scheduleTrigger = trigger({
237
+ type: 'n8n-nodes-base.scheduleTrigger', version: 1.3,
238
+ config: { name: 'Daily Schedule', position: [240, 500] },
239
+ output: [{ source: 'schedule' }]
240
+ });
241
+
242
+ const processData = node({
243
+ type: 'n8n-nodes-base.set', version: 3.4,
244
+ config: { name: 'Process Data', parameters: {}, position: [540, 350] },
245
+ output: [{ processed: true }]
246
+ });
247
+
248
+ const sendNotification = node({
249
+ type: 'n8n-nodes-base.slack', version: 2.3,
250
+ config: { name: 'Notify Slack', parameters: {}, position: [840, 350] },
251
+ output: [{ ok: true }]
252
+ });
253
+
254
+ export default workflow('id', 'name')
255
+ .add(webhookTrigger)
256
+ .to(processData)
257
+ .to(sendNotification)
258
+ .add(scheduleTrigger)
259
+ .to(processData);
260
+ \`\`\`
261
+
262
+ </fan_in>
263
+
264
+ <ai_agent_basic>
265
+ \`\`\`javascript
266
+ const openAiModel = languageModel({
267
+ type: '@n8n/n8n-nodes-langchain.lmChatOpenAi', version: 1.3,
268
+ config: { name: 'OpenAI Model', parameters: {}, position: [540, 500] }
269
+ });
270
+
271
+ const startTrigger = trigger({
272
+ type: 'n8n-nodes-base.manualTrigger', version: 1,
273
+ config: { name: 'Start', position: [240, 300] },
274
+ output: [{}]
275
+ });
276
+
277
+ const aiAgent = node({
278
+ type: '@n8n/n8n-nodes-langchain.agent', version: 3.1,
279
+ config: {
280
+ name: 'AI Assistant',
281
+ parameters: { promptType: 'define', text: 'You are a helpful assistant' },
282
+ subnodes: { model: openAiModel },
283
+ position: [540, 300]
284
+ },
285
+ output: [{ output: 'AI response text' }]
286
+ });
287
+
288
+ export default workflow('ai-assistant', 'AI Assistant')
289
+ .add(startTrigger)
290
+ .to(aiAgent);
291
+ \`\`\`
292
+
293
+ </ai_agent_basic>
294
+
295
+ <ai_agent_with_tools>
296
+ \`\`\`javascript
297
+ const openAiModel = languageModel({
298
+ type: '@n8n/n8n-nodes-langchain.lmChatOpenAi', version: 1.3,
299
+ config: {
300
+ name: 'OpenAI Model', parameters: {},
301
+ credentials: { openAiApi: newCredential('OpenAI') },
302
+ position: [540, 500]
303
+ }
304
+ });
305
+
306
+ const calculatorTool = tool({
307
+ type: '@n8n/n8n-nodes-langchain.toolCalculator', version: 1,
308
+ config: { name: 'Calculator', parameters: {}, position: [700, 500] }
309
+ });
310
+
311
+ const startTrigger = trigger({
312
+ type: 'n8n-nodes-base.manualTrigger', version: 1,
313
+ config: { name: 'Start', position: [240, 300] },
314
+ output: [{}]
315
+ });
316
+
317
+ const aiAgent = node({
318
+ type: '@n8n/n8n-nodes-langchain.agent', version: 3.1,
319
+ config: {
320
+ name: 'Math Agent',
321
+ parameters: { promptType: 'define', text: 'You can use tools to help users' },
322
+ subnodes: { model: openAiModel, tools: [calculatorTool] },
323
+ position: [540, 300]
324
+ },
325
+ output: [{ output: '42' }]
326
+ });
327
+
328
+ export default workflow('ai-calculator', 'AI Calculator')
329
+ .add(startTrigger)
330
+ .to(aiAgent);
331
+ \`\`\`
332
+
333
+ </ai_agent_with_tools>
334
+
335
+ <ai_agent_with_from_ai>
336
+ \`\`\`javascript
337
+ const gmailTool = tool({
338
+ type: 'n8n-nodes-base.gmailTool', version: 1,
339
+ config: {
340
+ name: 'Gmail Tool',
341
+ parameters: {
342
+ sendTo: fromAi('recipient', 'Email address'),
343
+ subject: fromAi('subject', 'Email subject'),
344
+ message: fromAi('body', 'Email content')
345
+ },
346
+ credentials: { gmailOAuth2: newCredential('Gmail') },
347
+ position: [700, 500]
348
+ }
349
+ });
350
+
351
+ const aiAgent = node({
352
+ type: '@n8n/n8n-nodes-langchain.agent', version: 3.1,
353
+ config: {
354
+ name: 'Email Agent',
355
+ parameters: { promptType: 'define', text: 'You can send emails' },
356
+ subnodes: { model: openAiModel, tools: [gmailTool] },
357
+ position: [540, 300]
358
+ },
359
+ output: [{ output: 'Email sent successfully' }]
360
+ });
361
+
362
+ export default workflow('ai-email', 'AI Email Sender')
363
+ .add(startTrigger)
364
+ .to(aiAgent);
365
+ \`\`\`
366
+ </ai_agent_with_from_ai>
367
+
368
+ <ai_agent_with_structured_output>
369
+ \`\`\`javascript
370
+ const structuredParser = outputParser({
371
+ type: '@n8n/n8n-nodes-langchain.outputParserStructured', version: 1.3,
372
+ config: {
373
+ name: 'Structured Output Parser',
374
+ parameters: {
375
+ schemaType: 'fromJson',
376
+ jsonSchemaExample: '{ "sentiment": "positive", "confidence": 0.95, "summary": "brief summary" }'
377
+ },
378
+ position: [700, 500]
379
+ }
380
+ });
381
+
382
+ const aiAgent = node({
383
+ type: '@n8n/n8n-nodes-langchain.agent', version: 3.1,
384
+ config: {
385
+ name: 'Sentiment Analyzer',
386
+ parameters: { promptType: 'define', text: 'Analyze the sentiment of the input text', hasOutputParser: true },
387
+ subnodes: { model: openAiModel, outputParser: structuredParser },
388
+ position: [540, 300]
389
+ },
390
+ output: [{ sentiment: 'positive', confidence: 0.95, summary: 'The text expresses satisfaction' }]
391
+ });
392
+
393
+ export default workflow('ai-sentiment', 'AI Sentiment Analyzer')
394
+ .add(startTrigger)
395
+ .to(aiAgent);
396
+ \`\`\`
397
+ </ai_agent_with_structured_output>`;
398
+ //# sourceMappingURL=workflow-patterns-detailed.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-patterns-detailed.js","sourceRoot":"","sources":["../../../src/prompts/sdk-reference/workflow-patterns-detailed.ts"],"names":[],"mappings":";;;AASA,MAAM,UAAU,GACf,wSAAwS,CAAC;AAE7R,QAAA,0BAA0B,GAAG;;EAExC,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mCAsYuB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const WORKFLOW_SDK_PATTERNS = "<linear_chain>\n```javascript\nimport { workflow, node, trigger, sticky, placeholder, newCredential, ifElse, switchCase, merge, splitInBatches, nextBatch, languageModel, memory, tool, outputParser, embedding, embeddings, vectorStore, retriever, documentLoader, textSplitter, fromAi, expr } from '@n8n/workflow-sdk';\n\n// 1. Define all nodes first\nconst startTrigger = trigger({\n type: 'n8n-nodes-base.manualTrigger',\n version: 1,\n config: { name: 'Start' }\n});\n\nconst fetchData = node({\n type: 'n8n-nodes-base.httpRequest',\n version: 4.3,\n config: { name: 'Fetch Data', parameters: { method: 'GET', url: '...' } }\n});\n\nconst processData = node({\n type: 'n8n-nodes-base.set',\n version: 3.4,\n config: { name: 'Process Data', parameters: {} }\n});\n\n// 2. Compose workflow\nexport default workflow('id', 'name')\n .add(startTrigger)\n .to(fetchData)\n .to(processData);\n```\n\n</linear_chain>\n\n<independent_sources>\nWhen nodes return more than 1 item, chaining causes item multiplication: if Source A returns N items, a chained Source B runs N times instead of once.\n\n**When to use `executeOnce: true`:**\n- A node fetches data independently but is chained after another data source (prevents N\u00D7M multiplication)\n- A node should summarize/aggregate all upstream items in a single call (e.g., AI summary, send one notification)\n- A node calls an API that doesn't vary per input item\n\nFix with `executeOnce: true` (simplest) or parallel branches + Merge (when combining results):\n\n```javascript\n// sourceA outputs 10 items. sourceB outputs 10 items.\n// WRONG - processResults runs 100 times\n// startTrigger.to(sourceA.to(sourceB.to(processResults)))\n\n// FIX 1 - executeOnce: sourceB runs once regardless of input items\nconst sourceB = node({ ..., config: { ..., executeOnce: true } });\nstartTrigger.to(sourceA.to(sourceB.to(processResults)));\n\n// FIX 2 - parallel branches + Merge (combine by position)\nconst combineResults = merge({\n version: 3.2,\n config: { name: 'Combine Results', parameters: { mode: 'combine', combineBy: 'combineByPosition' } }\n});\nexport default workflow('id', 'name')\n .add(startTrigger)\n .to(sourceA.to(combineResults.input(0)))\n .add(startTrigger)\n .to(sourceB.to(combineResults.input(1)))\n .add(combineResults)\n .to(processResults);\n\n// FIX 3 - parallel branches + Merge (append)\nconst allResults = merge({\n version: 3.2,\n config: { name: 'All Results', parameters: { mode: 'append' } }\n});\nexport default workflow('id', 'name')\n .add(startTrigger)\n .to(sourceA.to(allResults.input(0)))\n .add(startTrigger)\n .to(sourceB.to(allResults.input(1)))\n .add(allResults)\n .to(processResults);\n```\n\n</independent_sources>\n\n<zero_item_safety>\nNodes that fetch or filter data may return 0 items, which stops the entire downstream chain.\nUse `alwaysOutputData: true` on data-fetching nodes to ensure the chain continues with an empty item `{json: {}}`.\n\n```javascript\n// Data Table might be empty (fresh table, no matching rows)\nconst getReflections = node({\n type: 'n8n-nodes-base.dataTable',\n version: 1.1,\n config: {\n name: 'Get Reflections',\n alwaysOutputData: true, // Chain continues even if table is empty\n parameters: { resource: 'row', operation: 'get', returnAll: true }\n }\n});\n\n// Downstream Code node handles the empty case\nconst processData = node({\n type: 'n8n-nodes-base.code',\n version: 2,\n config: {\n name: 'Process Data',\n parameters: {\n mode: 'runOnceForAllItems',\n jsCode: \\`\nconst items = $input.all();\n// items will be [{json: {}}] if upstream had no data\nconst hasData = items.length > 0 && Object.keys(items[0].json).length > 0;\n// ... handle both cases\n\\`.trim()\n }\n }\n});\n```\n\n**When to use `alwaysOutputData: true`:**\n- Data Table with `operation: 'get'` (table may be empty or freshly created)\n- Any lookup/search/filter node whose result feeds into downstream processing\n- HTTP Request that may return an empty array\n\n**When NOT to use it:**\n- Trigger nodes (they always produce output)\n- Code nodes (handle empty input in your code logic instead)\n- Nodes at the end of the chain (no downstream to protect)\n\n</zero_item_safety>\n\n<conditional_branching>\n\n**CRITICAL:** Each branch defines a COMPLETE processing path. Chain multiple steps INSIDE the branch using .to().\n\nEvery IF/Filter `conditions` parameter MUST include `options`, `conditions`, and `combinator`:\n```javascript\nconst checkValid = ifElse({\n version: 2.2,\n config: {\n name: 'Check Valid',\n parameters: {\n conditions: {\n options: { caseSensitive: true, leftValue: '', typeValidation: 'strict' },\n conditions: [{ leftValue: '={{ $json.status }}', operator: { type: 'string', operation: 'equals' }, rightValue: 'active' }],\n combinator: 'and'\n }\n }\n }\n});\n\nexport default workflow('id', 'name')\n .add(startTrigger)\n .to(checkValid\n .onTrue(formatData.to(enrichData.to(saveToDb))) // Chain 3 nodes on true branch\n .onFalse(logError));\n```\n\n</conditional_branching>\n\n<multi_way_routing>\n\nSwitch rules use `rules.values` (NOT `rules.rules`). Each rule needs `outputKey` and a complete `conditions` object:\n```javascript\nconst routeByPriority = switchCase({\n version: 3.2,\n config: {\n name: 'Route by Priority',\n parameters: {\n rules: {\n values: [\n { outputKey: 'urgent', conditions: { options: { caseSensitive: true, leftValue: '', typeValidation: 'strict' }, conditions: [{ leftValue: '={{ $json.priority }}', operator: { type: 'string', operation: 'equals' }, rightValue: 'urgent' }], combinator: 'and' } },\n { outputKey: 'normal', conditions: { options: { caseSensitive: true, leftValue: '', typeValidation: 'strict' }, conditions: [{ leftValue: '={{ $json.priority }}', operator: { type: 'string', operation: 'equals' }, rightValue: 'normal' }], combinator: 'and' } },\n ]\n }\n }\n }\n});\n\nexport default workflow('id', 'name')\n .add(startTrigger)\n .to(routeByPriority\n .onCase('urgent', processUrgent.to(notifyTeam.to(escalate)))\n .onCase('normal', processNormal)\n .onDefault(archive));\n```\n\n</multi_way_routing>\n\n<parallel_execution>\n```javascript\n// First declare the Merge node using merge()\nconst combineResults = merge({\n version: 3.2,\n config: { name: 'Combine Results', parameters: { mode: 'combine' } }\n});\n\n// Declare branch nodes\nconst branch1 = node({ type: 'n8n-nodes-base.httpRequest', ... });\nconst branch2 = node({ type: 'n8n-nodes-base.httpRequest', ... });\nconst processResults = node({ type: 'n8n-nodes-base.set', ... });\n\n// Connect branches to specific merge inputs using .input(n)\nexport default workflow('id', 'name')\n .add(trigger({ ... }))\n .to(branch1.to(combineResults.input(0))) // Connect to input 0\n .add(trigger({ ... }))\n .to(branch2.to(combineResults.input(1))) // Connect to input 1\n .add(combineResults)\n .to(processResults); // Process merged results\n```\n\n</parallel_execution>\n\n<batch_processing>\n```javascript\nconst startTrigger = trigger({\n type: 'n8n-nodes-base.manualTrigger',\n version: 1,\n config: { name: 'Start' }\n});\n\nconst fetchRecords = node({\n type: 'n8n-nodes-base.httpRequest',\n version: 4.3,\n config: { name: 'Fetch Records', parameters: { method: 'GET', url: '...' } }\n});\n\nconst finalizeResults = node({\n type: 'n8n-nodes-base.set',\n version: 3.4,\n config: { name: 'Finalize', parameters: {} }\n});\n\nconst processRecord = node({\n type: 'n8n-nodes-base.httpRequest',\n version: 4.3,\n config: { name: 'Process Record', parameters: { method: 'POST', url: '...' } }\n});\n\nconst sibNode = splitInBatches({ version: 3, config: { name: 'Batch Process', parameters: { batchSize: 10 } } });\n\nexport default workflow('id', 'name')\n .add(startTrigger)\n .to(fetchRecords)\n .to(sibNode\n .onDone(finalizeResults)\n .onEachBatch(processRecord.to(nextBatch(sibNode)))\n );\n```\n\n</batch_processing>\n\n<multiple_triggers>\n```javascript\nconst webhookTrigger = trigger({\n type: 'n8n-nodes-base.webhook',\n version: 2.1,\n config: { name: 'Webhook' }\n});\n\nconst processWebhook = node({\n type: 'n8n-nodes-base.set',\n version: 3.4,\n config: { name: 'Process Webhook', parameters: {} }\n});\n\nconst scheduleTrigger = trigger({\n type: 'n8n-nodes-base.scheduleTrigger',\n version: 1.3,\n config: { name: 'Daily Schedule', parameters: {} }\n});\n\nconst processSchedule = node({\n type: 'n8n-nodes-base.set',\n version: 3.4,\n config: { name: 'Process Schedule', parameters: {} }\n});\n\nexport default workflow('id', 'name')\n .add(webhookTrigger)\n .to(processWebhook)\n .add(scheduleTrigger)\n .to(processSchedule);\n```\n\n</multiple_triggers>\n\n<fan_in>\n```javascript\n// Each trigger's execution runs in COMPLETE ISOLATION.\n// Different branches have no effect on each other.\n// Never duplicate chains for \"isolation\" - it's already guaranteed.\n\nconst webhookTrigger = trigger({\n type: 'n8n-nodes-base.webhook',\n version: 2.1,\n config: { name: 'Webhook Trigger' }\n});\n\nconst scheduleTrigger = trigger({\n type: 'n8n-nodes-base.scheduleTrigger',\n version: 1.3,\n config: { name: 'Daily Schedule' }\n});\n\nconst processData = node({\n type: 'n8n-nodes-base.set',\n version: 3.4,\n config: { name: 'Process Data', parameters: {} }\n});\n\nconst sendNotification = node({\n type: 'n8n-nodes-base.slack',\n version: 2.3,\n config: { name: 'Notify Slack', parameters: {} }\n});\n\nexport default workflow('id', 'name')\n .add(webhookTrigger)\n .to(processData)\n .to(sendNotification)\n .add(scheduleTrigger)\n .to(processData);\n```\n\n</fan_in>\n\n<ai_agent_basic>\n```javascript\nconst openAiModel = languageModel({\n type: '@n8n/n8n-nodes-langchain.lmChatOpenAi',\n version: 1.3,\n config: { name: 'OpenAI Model', parameters: {} }\n});\n\nconst startTrigger = trigger({\n type: 'n8n-nodes-base.manualTrigger',\n version: 1,\n config: { name: 'Start' }\n});\n\nconst aiAgent = node({\n type: '@n8n/n8n-nodes-langchain.agent',\n version: 3.1,\n config: {\n name: 'AI Assistant',\n parameters: { promptType: 'define', text: 'You are a helpful assistant' },\n subnodes: { model: openAiModel }\n }\n});\n\nexport default workflow('ai-assistant', 'AI Assistant')\n .add(startTrigger)\n .to(aiAgent);\n```\n\n</ai_agent_basic>\n\n<ai_agent_with_tools>\n```javascript\nconst openAiModel = languageModel({\n type: '@n8n/n8n-nodes-langchain.lmChatOpenAi',\n version: 1.3,\n config: {\n name: 'OpenAI Model',\n parameters: {},\n credentials: { openAiApi: newCredential('OpenAI') }\n }\n});\n\nconst calculatorTool = tool({\n type: '@n8n/n8n-nodes-langchain.toolCalculator',\n version: 1,\n config: { name: 'Calculator', parameters: {} }\n});\n\nconst startTrigger = trigger({\n type: 'n8n-nodes-base.manualTrigger',\n version: 1,\n config: { name: 'Start' }\n});\n\nconst aiAgent = node({\n type: '@n8n/n8n-nodes-langchain.agent',\n version: 3.1,\n config: {\n name: 'Math Agent',\n parameters: { promptType: 'define', text: 'You can use tools to help users' },\n subnodes: { model: openAiModel, tools: [calculatorTool] }\n }\n});\n\nexport default workflow('ai-calculator', 'AI Calculator')\n .add(startTrigger)\n .to(aiAgent);\n```\n\n</ai_agent_with_tools>\n\n<ai_agent_with_from_ai>\n```javascript\nconst openAiModel = languageModel({\n type: '@n8n/n8n-nodes-langchain.lmChatOpenAi',\n version: 1.3,\n config: {\n name: 'OpenAI Model',\n parameters: {},\n credentials: { openAiApi: newCredential('OpenAI') }\n }\n});\n\nconst gmailTool = tool({\n type: 'n8n-nodes-base.gmailTool',\n version: 1,\n config: {\n name: 'Gmail Tool',\n parameters: {\n sendTo: fromAi('recipient', 'Email address'),\n subject: fromAi('subject', 'Email subject'),\n message: fromAi('body', 'Email content')\n },\n credentials: { gmailOAuth2: newCredential('Gmail') }\n }\n});\n\nconst startTrigger = trigger({\n type: 'n8n-nodes-base.manualTrigger',\n version: 1,\n config: { name: 'Start' }\n});\n\nconst aiAgent = node({\n type: '@n8n/n8n-nodes-langchain.agent',\n version: 3.1,\n config: {\n name: 'Email Agent',\n parameters: { promptType: 'define', text: 'You can send emails' },\n subnodes: { model: openAiModel, tools: [gmailTool] }\n }\n});\n\nexport default workflow('ai-email', 'AI Email Sender')\n .add(startTrigger)\n .to(aiAgent);\n```\n</ai_agent_with_from_ai>\n\n<ai_agent_with_structured_output>\n```javascript\nconst structuredParser = outputParser({\n type: '@n8n/n8n-nodes-langchain.outputParserStructured',\n version: 1.3,\n config: {\n name: 'Structured Output Parser',\n parameters: {\n schemaType: 'fromJson',\n jsonSchemaExample: '{ \"sentiment\": \"positive\", \"confidence\": 0.95, \"summary\": \"brief summary\" }'\n }\n }\n});\n\nconst aiAgent = node({\n type: '@n8n/n8n-nodes-langchain.agent',\n version: 3.1,\n config: {\n name: 'Sentiment Analyzer',\n parameters: { promptType: 'define', text: 'Analyze the sentiment of the input text', hasOutputParser: true },\n subnodes: { model: openAiModel, outputParser: structuredParser }\n }\n});\n\nexport default workflow('ai-sentiment', 'AI Sentiment Analyzer')\n .add(startTrigger)\n .to(aiAgent);\n```\n</ai_agent_with_structured_output>";
2
+ export { WORKFLOW_SDK_PATTERNS as WORKFLOW_PATTERNS_CONCISE };