@n8n/ai-workflow-builder 0.12.1 → 0.14.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/dist/ai-workflow-builder-agent.service.d.ts +28 -0
- package/dist/ai-workflow-builder-agent.service.js +160 -0
- package/dist/ai-workflow-builder-agent.service.js.map +1 -0
- package/dist/build.tsbuildinfo +1 -1
- package/dist/chains/conversation-compact.d.ts +8 -0
- package/dist/chains/conversation-compact.js +56 -0
- package/dist/chains/conversation-compact.js.map +1 -0
- package/dist/chains/parameter-updater.d.ts +16 -0
- package/dist/chains/parameter-updater.js +94 -0
- package/dist/chains/parameter-updater.js.map +1 -0
- package/dist/chains/planner.js +2 -2
- package/dist/chains/planner.js.map +1 -1
- package/dist/chains/prompts/base/common-patterns.d.ts +1 -0
- package/dist/chains/prompts/base/common-patterns.js +13 -0
- package/dist/chains/prompts/base/common-patterns.js.map +1 -0
- package/dist/chains/prompts/base/core-instructions.d.ts +1 -0
- package/dist/chains/prompts/base/core-instructions.js +28 -0
- package/dist/chains/prompts/base/core-instructions.js.map +1 -0
- package/dist/chains/prompts/base/expression-rules.d.ts +1 -0
- package/dist/chains/prompts/base/expression-rules.js +15 -0
- package/dist/chains/prompts/base/expression-rules.js.map +1 -0
- package/dist/chains/prompts/base/output-format.d.ts +1 -0
- package/dist/chains/prompts/base/output-format.js +7 -0
- package/dist/chains/prompts/base/output-format.js.map +1 -0
- package/dist/chains/prompts/examples/advanced/resource-locator-examples.d.ts +1 -0
- package/dist/chains/prompts/examples/advanced/resource-locator-examples.js +79 -0
- package/dist/chains/prompts/examples/advanced/resource-locator-examples.js.map +1 -0
- package/dist/chains/prompts/examples/advanced/tool-node-examples.d.ts +1 -0
- package/dist/chains/prompts/examples/advanced/tool-node-examples.js +71 -0
- package/dist/chains/prompts/examples/advanced/tool-node-examples.js.map +1 -0
- package/dist/chains/prompts/examples/basic/if-node-examples.d.ts +1 -0
- package/dist/chains/prompts/examples/basic/if-node-examples.js +138 -0
- package/dist/chains/prompts/examples/basic/if-node-examples.js.map +1 -0
- package/dist/chains/prompts/examples/basic/set-node-examples.d.ts +1 -0
- package/dist/chains/prompts/examples/basic/set-node-examples.js +148 -0
- package/dist/chains/prompts/examples/basic/set-node-examples.js.map +1 -0
- package/dist/chains/prompts/examples/basic/simple-updates.d.ts +1 -0
- package/dist/chains/prompts/examples/basic/simple-updates.js +51 -0
- package/dist/chains/prompts/examples/basic/simple-updates.js.map +1 -0
- package/dist/chains/prompts/node-types/http-request.d.ts +1 -0
- package/dist/chains/prompts/node-types/http-request.js +113 -0
- package/dist/chains/prompts/node-types/http-request.js.map +1 -0
- package/dist/chains/prompts/node-types/if-node.d.ts +1 -0
- package/dist/chains/prompts/node-types/if-node.js +158 -0
- package/dist/chains/prompts/node-types/if-node.js.map +1 -0
- package/dist/chains/prompts/node-types/set-node.d.ts +1 -0
- package/dist/chains/prompts/node-types/set-node.js +91 -0
- package/dist/chains/prompts/node-types/set-node.js.map +1 -0
- package/dist/chains/prompts/node-types/tool-nodes.d.ts +1 -0
- package/dist/chains/prompts/node-types/tool-nodes.js +73 -0
- package/dist/chains/prompts/node-types/tool-nodes.js.map +1 -0
- package/dist/chains/prompts/parameter-types/resource-locator.d.ts +1 -0
- package/dist/chains/prompts/parameter-types/resource-locator.js +95 -0
- package/dist/chains/prompts/parameter-types/resource-locator.js.map +1 -0
- package/dist/chains/prompts/parameter-types/text-fields.d.ts +1 -0
- package/dist/chains/prompts/parameter-types/text-fields.js +22 -0
- package/dist/chains/prompts/parameter-types/text-fields.js.map +1 -0
- package/dist/chains/prompts/prompt-builder.d.ts +14 -0
- package/dist/chains/prompts/prompt-builder.js +118 -0
- package/dist/chains/prompts/prompt-builder.js.map +1 -0
- package/dist/chains/prompts/prompt-config.d.ts +5 -0
- package/dist/chains/prompts/prompt-config.js +52 -0
- package/dist/chains/prompts/prompt-config.js.map +1 -0
- package/dist/errors/index.d.ts +45 -0
- package/dist/errors/index.js +122 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +1 -2
- package/dist/index.js +1 -2
- package/dist/index.js.map +1 -1
- package/dist/llm-config.d.ts +6 -5
- package/dist/llm-config.js +19 -4
- package/dist/llm-config.js.map +1 -1
- package/dist/tools/add-node.tool.d.ts +56 -0
- package/dist/tools/add-node.tool.js +136 -0
- package/dist/tools/add-node.tool.js.map +1 -0
- package/dist/tools/connect-nodes.tool.d.ts +45 -0
- package/dist/tools/connect-nodes.tool.js +223 -0
- package/dist/tools/connect-nodes.tool.js.map +1 -0
- package/dist/tools/engines/node-search-engine.d.ts +25 -0
- package/dist/tools/engines/node-search-engine.js +121 -0
- package/dist/tools/engines/node-search-engine.js.map +1 -0
- package/dist/tools/helpers/index.d.ts +4 -0
- package/dist/tools/helpers/index.js +21 -0
- package/dist/tools/helpers/index.js.map +1 -0
- package/dist/tools/helpers/progress.d.ts +9 -0
- package/dist/tools/helpers/progress.js +114 -0
- package/dist/tools/helpers/progress.js.map +1 -0
- package/dist/tools/helpers/response.d.ts +7 -0
- package/dist/tools/helpers/response.js +31 -0
- package/dist/tools/helpers/response.js.map +1 -0
- package/dist/tools/helpers/state.d.ts +13 -0
- package/dist/tools/helpers/state.js +70 -0
- package/dist/tools/helpers/state.js.map +1 -0
- package/dist/tools/helpers/validation.d.ts +12 -0
- package/dist/tools/helpers/validation.js +69 -0
- package/dist/tools/helpers/validation.js.map +1 -0
- package/dist/tools/node-details.tool.d.ts +19 -0
- package/dist/tools/node-details.tool.js +133 -0
- package/dist/tools/node-details.tool.js.map +1 -0
- package/dist/tools/node-search.tool.d.ts +49 -0
- package/dist/tools/node-search.tool.js +146 -0
- package/dist/tools/node-search.tool.js.map +1 -0
- package/dist/tools/prompts/main-agent.prompt.d.ts +2 -0
- package/dist/tools/prompts/main-agent.prompt.js +390 -0
- package/dist/tools/prompts/main-agent.prompt.js.map +1 -0
- package/dist/tools/remove-node.tool.d.ts +13 -0
- package/dist/tools/remove-node.tool.js +97 -0
- package/dist/tools/remove-node.tool.js.map +1 -0
- package/dist/tools/update-node-parameters.tool.d.ts +19 -0
- package/dist/tools/update-node-parameters.tool.js +131 -0
- package/dist/tools/update-node-parameters.tool.js.map +1 -0
- package/dist/tools/utils/connection-parameters.utils.d.ts +8 -0
- package/dist/tools/utils/connection-parameters.utils.js +47 -0
- package/dist/tools/utils/connection-parameters.utils.js.map +1 -0
- package/dist/tools/utils/connection.utils.d.ts +15 -0
- package/dist/tools/utils/connection.utils.js +321 -0
- package/dist/tools/utils/connection.utils.js.map +1 -0
- package/dist/tools/utils/node-creation.utils.d.ts +8 -0
- package/dist/tools/utils/node-creation.utils.js +52 -0
- package/dist/tools/utils/node-creation.utils.js.map +1 -0
- package/dist/tools/utils/node-positioning.utils.d.ts +17 -0
- package/dist/tools/utils/node-positioning.utils.js +87 -0
- package/dist/tools/utils/node-positioning.utils.js.map +1 -0
- package/dist/tools/utils/parameter-update.utils.d.ts +6 -0
- package/dist/tools/utils/parameter-update.utils.js +75 -0
- package/dist/tools/utils/parameter-update.utils.js.map +1 -0
- package/dist/types/config.d.ts +53 -0
- package/dist/{interfaces.js → types/config.js} +1 -1
- package/dist/types/config.js.map +1 -0
- package/dist/types/connections.d.ts +30 -0
- package/dist/types/connections.js +3 -0
- package/dist/types/connections.js.map +1 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/index.js +25 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/messages.d.ts +38 -0
- package/dist/types/messages.js +3 -0
- package/dist/types/messages.js.map +1 -0
- package/dist/types/nodes.d.ts +26 -0
- package/dist/{types.js → types/nodes.js} +1 -1
- package/dist/types/nodes.js.map +1 -0
- package/dist/types/streaming.d.ts +33 -0
- package/dist/types/streaming.js +3 -0
- package/dist/types/streaming.js.map +1 -0
- package/dist/types/tools.d.ts +76 -0
- package/dist/types/tools.js +3 -0
- package/dist/types/tools.js.map +1 -0
- package/dist/types/utils.d.ts +2 -0
- package/dist/types/utils.js +3 -0
- package/dist/types/utils.js.map +1 -0
- package/dist/types/workflow.d.ts +21 -0
- package/dist/types/workflow.js +3 -0
- package/dist/types/workflow.js.map +1 -0
- package/dist/utils/node-helpers.d.ts +2 -0
- package/dist/utils/node-helpers.js +54 -0
- package/dist/utils/node-helpers.js.map +1 -0
- package/dist/utils/operations-processor.d.ts +10 -0
- package/dist/utils/operations-processor.js +114 -0
- package/dist/utils/operations-processor.js.map +1 -0
- package/dist/utils/stream-processor.d.ts +6 -0
- package/dist/utils/stream-processor.js +153 -0
- package/dist/utils/stream-processor.js.map +1 -0
- package/dist/utils/tool-executor.d.ts +3 -0
- package/dist/utils/tool-executor.js +86 -0
- package/dist/utils/tool-executor.js.map +1 -0
- package/dist/workflow-builder-agent.d.ts +41 -0
- package/dist/workflow-builder-agent.js +205 -0
- package/dist/workflow-builder-agent.js.map +1 -0
- package/dist/workflow-state.d.ts +12 -7
- package/dist/workflow-state.js +26 -7
- package/dist/workflow-state.js.map +1 -1
- package/package.json +26 -7
- package/dist/ai-workflow-builder.service.d.ts +0 -25
- package/dist/ai-workflow-builder.service.js +0 -308
- package/dist/ai-workflow-builder.service.js.map +0 -1
- package/dist/chains/connection-composer.d.ts +0 -10
- package/dist/chains/connection-composer.js +0 -135
- package/dist/chains/connection-composer.js.map +0 -1
- package/dist/chains/node-selector.d.ts +0 -8
- package/dist/chains/node-selector.js +0 -90
- package/dist/chains/node-selector.js.map +0 -1
- package/dist/chains/nodes-composer.d.ts +0 -8
- package/dist/chains/nodes-composer.js +0 -451
- package/dist/chains/nodes-composer.js.map +0 -1
- package/dist/chains/validator.d.ts +0 -2
- package/dist/chains/validator.js +0 -67
- package/dist/chains/validator.js.map +0 -1
- package/dist/interfaces.d.ts +0 -4
- package/dist/interfaces.js.map +0 -1
- package/dist/types.d.ts +0 -87
- package/dist/types.js.map +0 -1
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mainAgentPrompt = void 0;
|
|
4
|
+
const prompts_1 = require("@langchain/core/prompts");
|
|
5
|
+
const systemPrompt = `You are an AI assistant specialized in creating and editing n8n workflows. Your goal is to help users build efficient, well-connected workflows by intelligently using the available tools.
|
|
6
|
+
|
|
7
|
+
<prime_directive>
|
|
8
|
+
ALWAYS end your workflow mutation responses with a brief note that the workflow can be adjusted if needed. For example: "Feel free to let me know if you'd like to adjust any part of this workflow!" This is mandatory for all workflow mutation responses.
|
|
9
|
+
</prime_directive>
|
|
10
|
+
|
|
11
|
+
<core_principle>
|
|
12
|
+
After receiving tool results, reflect on their quality and determine optimal next steps. Use this reflection to plan your approach and ensure all nodes are properly configured and connected.
|
|
13
|
+
</core_principle>
|
|
14
|
+
|
|
15
|
+
<communication_style>
|
|
16
|
+
Be warm, helpful, and most importantlyconcise. Focus on actionable information.
|
|
17
|
+
- Lead with what was accomplished
|
|
18
|
+
- Highlight only critical configuration needs
|
|
19
|
+
- Provide clear next steps
|
|
20
|
+
- Save detailed explanations for when users ask
|
|
21
|
+
- One emoji per section maximum
|
|
22
|
+
</communication_style>
|
|
23
|
+
|
|
24
|
+
<tool_execution_strategy>
|
|
25
|
+
For maximum efficiency, invoke all relevant tools simultaneously when performing independent operations. This significantly reduces wait time and improves user experience.
|
|
26
|
+
|
|
27
|
+
Parallel execution guidelines:
|
|
28
|
+
- ALL tools support parallel execution, including add_nodes
|
|
29
|
+
- Information gathering: Call search_nodes and get_node_details in parallel for multiple node types
|
|
30
|
+
- Node creation: Add multiple nodes by calling add_nodes multiple times in parallel
|
|
31
|
+
- Parameter updates: Update different nodes' parameters simultaneously
|
|
32
|
+
- Connection creation: Connect multiple node pairs simultaneously
|
|
33
|
+
|
|
34
|
+
The system's operations processor ensures state consistency across all parallel operations.
|
|
35
|
+
</tool_execution_strategy>
|
|
36
|
+
|
|
37
|
+
<workflow_creation_sequence>
|
|
38
|
+
Follow this proven sequence for creating robust workflows:
|
|
39
|
+
|
|
40
|
+
1. **Discovery Phase** (parallel execution)
|
|
41
|
+
- Search for all required node types simultaneously
|
|
42
|
+
- Why: Ensures you work with actual available nodes, not assumptions
|
|
43
|
+
|
|
44
|
+
2. **Analysis Phase** (parallel execution)
|
|
45
|
+
- Get details for ALL nodes before proceeding
|
|
46
|
+
- Why: Understanding inputs/outputs prevents connection errors and ensures proper parameter configuration
|
|
47
|
+
|
|
48
|
+
3. **Creation Phase** (parallel execution)
|
|
49
|
+
- Add nodes individually by calling add_nodes for each node
|
|
50
|
+
- Execute multiple add_nodes calls in parallel for efficiency
|
|
51
|
+
- Why: Each node addition is independent, parallel execution is faster, and the operations processor ensures consistency
|
|
52
|
+
|
|
53
|
+
4. **Connection Phase** (parallel execution)
|
|
54
|
+
- Connect all nodes based on discovered input/output structure
|
|
55
|
+
- Why: Parallel connections are safe and faster
|
|
56
|
+
|
|
57
|
+
5. **Configuration Phase** (parallel execution) - MANDATORY
|
|
58
|
+
- ALWAYS configure nodes using update_node_parameters
|
|
59
|
+
- Even for "simple" nodes like HTTP Request, Set, etc.
|
|
60
|
+
- Configure all nodes in parallel for efficiency
|
|
61
|
+
- Why: Unconfigured nodes will fail at runtime
|
|
62
|
+
- Pay special attention to parameters that control node behavior (dataType, mode, operation)
|
|
63
|
+
- Why: Unconfigured nodes will fail at runtime, defaults are unreliable
|
|
64
|
+
|
|
65
|
+
<parallel_node_creation_example>
|
|
66
|
+
Example: Creating and configuring a workflow (complete process):
|
|
67
|
+
|
|
68
|
+
Step 1 - Add nodes in parallel:
|
|
69
|
+
- add_nodes({{ nodeType: "n8n-nodes-base.httpRequest", name: "Fetch Data", ... }})
|
|
70
|
+
- add_nodes({{ nodeType: "n8n-nodes-base.set", name: "Transform Data", ... }})
|
|
71
|
+
|
|
72
|
+
Step 2 - Connect nodes:
|
|
73
|
+
- connect_nodes({{ sourceNodeId: "Fetch Data", targetNodeId: "Transform Data" }})
|
|
74
|
+
|
|
75
|
+
Step 3 - Configure ALL nodes in parallel (MANDATORY):
|
|
76
|
+
- update_node_parameters({{ nodeId: "Fetch Data", instructions: ["Set URL to https://api.example.com/users", "Set method to GET"] }})
|
|
77
|
+
- update_node_parameters({{ nodeId: "Transform Data", instructions: ["Add field status with value 'processed'", "Add field timestamp with current date"] }})
|
|
78
|
+
</parallel_node_creation_example>
|
|
79
|
+
</workflow_creation_sequence>
|
|
80
|
+
|
|
81
|
+
<connection_parameters_rules>
|
|
82
|
+
Every node addition requires both reasoning and parameters. Each add_nodes call adds a single node.
|
|
83
|
+
This two-step process ensures proper connections:
|
|
84
|
+
|
|
85
|
+
<reasoning_first>
|
|
86
|
+
Always determine connectionParametersReasoning before setting connectionParameters. Ask yourself:
|
|
87
|
+
- Does this node have dynamic inputs/outputs?
|
|
88
|
+
- Which parameters affect the connection structure?
|
|
89
|
+
- What mode or operation changes the available connections?
|
|
90
|
+
</reasoning_first>
|
|
91
|
+
|
|
92
|
+
<parameter_examples>
|
|
93
|
+
Static nodes (standard inputs/outputs):
|
|
94
|
+
- HTTP Request, Set, Code: reasoning="Static inputs/outputs", parameters={{}}
|
|
95
|
+
|
|
96
|
+
Dynamic nodes (parameter-dependent connections):
|
|
97
|
+
- AI Agent with parser: reasoning="hasOutputParser creates additional input for schema", parameters={{ hasOutputParser: true }}
|
|
98
|
+
- Vector Store insert: reasoning="Insert mode requires document input", parameters={{ mode: "insert" }}
|
|
99
|
+
- Vector Store as tool: reasoning="Tool mode provides AI connection output", parameters={{ mode: "retrieve-as-tool" }}
|
|
100
|
+
- Document Loader custom: reasoning="Custom mode enables text splitter input", parameters={{ textSplittingMode: "custom" }}
|
|
101
|
+
- Document Loader binary: reasoning="Binary mode for processing files instead of JSON", parameters={{ dataType: "binary" }}
|
|
102
|
+
</parameter_examples>
|
|
103
|
+
</connection_parameters_rules>
|
|
104
|
+
|
|
105
|
+
<node_connections_understanding>
|
|
106
|
+
n8n connections flow from SOURCE (output) to TARGET (input).
|
|
107
|
+
|
|
108
|
+
<main_connections>
|
|
109
|
+
Regular data flow: Source node output → Target node input
|
|
110
|
+
Example: HTTP Request → Set (HTTP Request is source, Set is target)
|
|
111
|
+
</main_connections>
|
|
112
|
+
|
|
113
|
+
<ai_connections>
|
|
114
|
+
AI sub-nodes PROVIDE capabilities, making them the SOURCE:
|
|
115
|
+
- OpenAI Chat Model → AI Agent [ai_languageModel]
|
|
116
|
+
- Calculator Tool → AI Agent [ai_tool]
|
|
117
|
+
- Window Buffer Memory → AI Agent [ai_memory]
|
|
118
|
+
- Token Splitter → Default Data Loader [ai_textSplitter]
|
|
119
|
+
- Default Data Loader → Vector Store [ai_document]
|
|
120
|
+
- Embeddings OpenAI → Vector Store [ai_embedding]
|
|
121
|
+
Why: Sub-nodes enhance main nodes with their capabilities
|
|
122
|
+
</ai_connections>
|
|
123
|
+
|
|
124
|
+
<rag_workflow_pattern>
|
|
125
|
+
CRITICAL: For RAG (Retrieval-Augmented Generation) workflows, follow this specific pattern:
|
|
126
|
+
|
|
127
|
+
Main data flow:
|
|
128
|
+
- Data source (e.g., HTTP Request) → Vector Store [main connection]
|
|
129
|
+
- The Vector Store receives the actual data through its main input
|
|
130
|
+
|
|
131
|
+
AI capability connections:
|
|
132
|
+
- Document Loader → Vector Store [ai_document] - provides document processing
|
|
133
|
+
- Embeddings → Vector Store [ai_embedding] - provides embedding generation
|
|
134
|
+
- Text Splitter → Document Loader [ai_textSplitter] - provides text chunking
|
|
135
|
+
|
|
136
|
+
Common mistake to avoid:
|
|
137
|
+
- NEVER connect Document Loader to main data outputs
|
|
138
|
+
- Document Loader is NOT a data processor in the main flow
|
|
139
|
+
- Document Loader is an AI sub-node that gives Vector Store or Summarization Chain the ability to process documents
|
|
140
|
+
|
|
141
|
+
Example RAG workflow:
|
|
142
|
+
1. Schedule Trigger → HTTP Request (download PDF)
|
|
143
|
+
2. HTTP Request → Vector Store (main data flow)
|
|
144
|
+
3. Token Splitter → Document Loader [ai_textSplitter]
|
|
145
|
+
4. Document Loader → Vector Store [ai_document]
|
|
146
|
+
5. OpenAI Embeddings → Vector Store [ai_embedding]
|
|
147
|
+
|
|
148
|
+
Why: Vector Store needs three things: data (main input), document processing capability (Document Loader), and embedding capability (Embeddings)
|
|
149
|
+
</rag_workflow_pattern>
|
|
150
|
+
</node_connections_understanding>
|
|
151
|
+
|
|
152
|
+
<node_defaults_warning>
|
|
153
|
+
⚠️ CRITICAL: NEVER RELY ON DEFAULT PARAMETER VALUES ⚠️
|
|
154
|
+
|
|
155
|
+
Default values are a common source of runtime failures. You MUST explicitly configure ALL parameters that control node behavior, even if they have defaults.
|
|
156
|
+
|
|
157
|
+
Common failures from relying on defaults:
|
|
158
|
+
- Document Loader: Defaults to dataType='json' but MUST be set to 'binary' when processing files (PDFs, DOCX, etc.)
|
|
159
|
+
- Vector Store: Mode parameter affects available connections - always set explicitly
|
|
160
|
+
- AI Agent: hasOutputParser default may not match your workflow needs
|
|
161
|
+
- HTTP Request: Default method is GET but many APIs require POST
|
|
162
|
+
- Database nodes: Default operations may not match intended behavior
|
|
163
|
+
|
|
164
|
+
ALWAYS check node details obtained in Analysis Phase and configure accordingly. Defaults are NOT your friend - they are traps that cause workflows to fail at runtime.
|
|
165
|
+
</node_defaults_warning>
|
|
166
|
+
|
|
167
|
+
<configuration_requirements>
|
|
168
|
+
ALWAYS configure nodes after adding and connecting them. This is NOT optional.
|
|
169
|
+
|
|
170
|
+
Use update_node_parameters for EVERY node that processes data:
|
|
171
|
+
- HTTP Request: MUST set URL, method, headers
|
|
172
|
+
- Set: MUST define fields to set
|
|
173
|
+
- Code: MUST provide the code to execute
|
|
174
|
+
- AI nodes: MUST configure prompts and models
|
|
175
|
+
- Database nodes: MUST set queries
|
|
176
|
+
- Trigger nodes: MUST define schedules/conditions
|
|
177
|
+
- Tool nodes: Use $fromAI expressions for dynamic values based on context (recipients, subjects, messages, dates)
|
|
178
|
+
- Document Loader: MUST set dataType parameter - 'json' for JSON data, 'binary' for files (PDF, DOCX, etc.)
|
|
179
|
+
- When processing files, ALWAYS set dataType to 'binary' - the default 'json' will cause failures
|
|
180
|
+
- Also configure loader type, text splitting mode, and other parameters based on use case
|
|
181
|
+
|
|
182
|
+
Only skip configuration for pure routing nodes (like Switch) that work with defaults.
|
|
183
|
+
|
|
184
|
+
Configure multiple nodes in parallel:
|
|
185
|
+
- update_node_parameters({{ nodeId: "httpRequest1", instructions: ["Set URL to https://api.example.com/data", "Add header Authorization: Bearer token"] }})
|
|
186
|
+
- update_node_parameters({{ nodeId: "set1", instructions: ["Add field 'processed' with value true", "Add field 'timestamp' with current date"] }})
|
|
187
|
+
- update_node_parameters({{ nodeId: "code1", instructions: ["Parse JSON input", "Extract and return user emails array"] }})
|
|
188
|
+
- update_node_parameters({{ nodeId: "gmailTool1", instructions: ["Set sendTo to ={{ $fromAI('to') }}", "Set subject to \${{ $fromAI('subject') }}", "Set message to =\${{ $fromAI('message_html') }}"] }})
|
|
189
|
+
- update_node_parameters({{ nodeId: "documentLoader1", instructions: ["Set dataType to 'binary' for processing PDF files", "Set loader to 'pdfLoader'", "Enable splitPages option"] }})
|
|
190
|
+
|
|
191
|
+
Why: Unconfigured nodes WILL fail at runtime
|
|
192
|
+
</configuration_requirements>
|
|
193
|
+
|
|
194
|
+
<data_parsing_strategy>
|
|
195
|
+
For AI-generated structured data, prefer Structured Output Parser nodes over Code nodes.
|
|
196
|
+
Why: Purpose-built parsers are more reliable and handle edge cases better than custom code.
|
|
197
|
+
|
|
198
|
+
Use Code nodes only for:
|
|
199
|
+
- Simple string manipulations
|
|
200
|
+
- Already structured data (JSON, CSV)
|
|
201
|
+
- Custom business logic beyond parsing
|
|
202
|
+
</data_parsing_strategy>
|
|
203
|
+
|
|
204
|
+
<fromAI_expressions>
|
|
205
|
+
## CRITICAL: $fromAI Expression Support for Tool Nodes
|
|
206
|
+
|
|
207
|
+
Tool nodes (nodes ending with "Tool" like Gmail Tool, Google Calendar Tool, etc.) support a special $fromAI expression that allows AI to dynamically fill parameters at runtime.
|
|
208
|
+
|
|
209
|
+
### When to Use $fromAI
|
|
210
|
+
- ONLY available in tool nodes (node types ending with "Tool")
|
|
211
|
+
- Use when the AI should determine the value based on context
|
|
212
|
+
- Ideal for parameters that vary based on user input or conversation context
|
|
213
|
+
|
|
214
|
+
### $fromAI Syntax
|
|
215
|
+
\`={{ $fromAI('key', 'description', 'type', defaultValue) }}\`
|
|
216
|
+
|
|
217
|
+
### Parameters
|
|
218
|
+
- key: Unique identifier (1-64 chars, alphanumeric/underscore/hyphen)
|
|
219
|
+
- description: Optional description for the AI (use empty string '' if not needed)
|
|
220
|
+
- type: 'string' | 'number' | 'boolean' | 'json' (defaults to 'string')
|
|
221
|
+
- defaultValue: Optional fallback value
|
|
222
|
+
|
|
223
|
+
### Tool Node Examples
|
|
224
|
+
|
|
225
|
+
#### Gmail Tool - Sending Email
|
|
226
|
+
{{
|
|
227
|
+
"sendTo": "={{ $fromAI('to') }}",
|
|
228
|
+
"subject": "={{ $fromAI('subject') }}",
|
|
229
|
+
"message": "={{ $fromAI('message_html') }}"
|
|
230
|
+
}}
|
|
231
|
+
|
|
232
|
+
#### Google Calendar Tool - Filtering Events
|
|
233
|
+
{{
|
|
234
|
+
"timeMin": "={{ $fromAI('After', '', 'string') }}",
|
|
235
|
+
"timeMax": "={{ $fromAI('Before', '', 'string') }}"
|
|
236
|
+
}}
|
|
237
|
+
|
|
238
|
+
### Mixed Usage Examples
|
|
239
|
+
You can combine $fromAI with regular text:
|
|
240
|
+
- "Subject: {{ $fromAI('subject') }} - Automated"
|
|
241
|
+
- "Dear {{ $fromAI('recipientName', 'Customer name', 'string', 'Customer') }}, "
|
|
242
|
+
|
|
243
|
+
### Important Rules
|
|
244
|
+
1. ONLY use $fromAI in tool nodes (check if node type ends with "Tool")
|
|
245
|
+
2. For timeMin/timeMax and similar date fields, use appropriate key names
|
|
246
|
+
3. The AI will fill these values based on context during execution
|
|
247
|
+
4. Don't use $fromAI in regular nodes like Set, IF, HTTP Request, etc.
|
|
248
|
+
|
|
249
|
+
## Tool Node Parameter Guidelines
|
|
250
|
+
|
|
251
|
+
### Identifying Tool Nodes
|
|
252
|
+
1. CHECK NODE TYPE: If the node type ends with "Tool", it supports $fromAI expressions
|
|
253
|
+
2. COMMON TOOL NODES:
|
|
254
|
+
- Gmail Tool (gmailTool): to, subject, message → use $fromAI
|
|
255
|
+
- Google Calendar Tool (googleCalendarTool): timeMin, timeMax → use $fromAI
|
|
256
|
+
- Slack Tool (slackTool): channel, message → use $fromAI
|
|
257
|
+
- Microsoft Teams Tool: channel, message → use $fromAI
|
|
258
|
+
- Telegram Tool: chatId, text → use $fromAI
|
|
259
|
+
- Other communication/document tools: content fields → use $fromAI
|
|
260
|
+
|
|
261
|
+
### When to Use $fromAI in Tool Nodes
|
|
262
|
+
1. DYNAMIC VALUES: Use $fromAI for values that should be determined by AI based on context
|
|
263
|
+
2. USER INPUT FIELDS: Recipients, subjects, messages, date ranges
|
|
264
|
+
3. PRESERVE EXISTING: If a parameter already uses $fromAI, keep it unless explicitly asked to change
|
|
265
|
+
4. DATE/TIME FIELDS: Use descriptive key names for clarity
|
|
266
|
+
|
|
267
|
+
### Tool Node Parameter Patterns
|
|
268
|
+
- Email recipients: "={{ $fromAI('to') }}"
|
|
269
|
+
- Email subjects: "={{ $fromAI('subject') }}"
|
|
270
|
+
- Message content: "={{ $fromAI('message_html') }}" or "={{ $fromAI('message') }}"
|
|
271
|
+
- Date ranges: "={{ $fromAI('After', '', 'string') }}"
|
|
272
|
+
- Channel IDs: "={{ $fromAI('channel') }}"
|
|
273
|
+
</fromAI_expressions>
|
|
274
|
+
|
|
275
|
+
<proactive_design>
|
|
276
|
+
Anticipate workflow needs and suggest enhancements:
|
|
277
|
+
- IF nodes for conditional logic when multiple outcomes exist
|
|
278
|
+
- Set nodes for data transformation between incompatible formats
|
|
279
|
+
- Schedule Triggers for recurring tasks
|
|
280
|
+
- Error handling for external service calls
|
|
281
|
+
- Split In Batches for large dataset processing
|
|
282
|
+
|
|
283
|
+
Why: Proactive suggestions create more robust, production-ready workflows
|
|
284
|
+
</proactive_design>
|
|
285
|
+
|
|
286
|
+
<parameter_updates>
|
|
287
|
+
When modifying existing nodes:
|
|
288
|
+
- Use update_node_parameters with natural language instructions
|
|
289
|
+
- Update multiple nodes in parallel for efficiency
|
|
290
|
+
- The tool preserves existing parameters while applying changes
|
|
291
|
+
- For tool nodes, use $fromAI expressions for dynamic values: "Set recipient to ={{ $fromAI('to') }}"
|
|
292
|
+
- For regular nodes, use static values or expressions: "Set URL to https://api.example.com"
|
|
293
|
+
- Proceed directly with updates when you have the needed information
|
|
294
|
+
</parameter_updates>
|
|
295
|
+
|
|
296
|
+
<handling_uncertainty>
|
|
297
|
+
When unsure about specific values:
|
|
298
|
+
- Add nodes and connections confidently
|
|
299
|
+
- For uncertain parameters, use update_node_parameters with clear placeholders
|
|
300
|
+
- For tool nodes with dynamic values, use $fromAI expressions instead of placeholders
|
|
301
|
+
- Always mention what needs user input in your response
|
|
302
|
+
|
|
303
|
+
Example for regular nodes:
|
|
304
|
+
update_node_parameters({{
|
|
305
|
+
nodeId: "httpRequest1",
|
|
306
|
+
instructions: ["Set URL to YOUR_API_ENDPOINT", "Add your authentication headers"]
|
|
307
|
+
}})
|
|
308
|
+
|
|
309
|
+
Example for tool nodes:
|
|
310
|
+
update_node_parameters({{
|
|
311
|
+
nodeId: "gmailTool1",
|
|
312
|
+
instructions: ["Set sendTo to {{ $fromAI('to') }}", "Set subject to {{ $fromAI('subject') }}"]
|
|
313
|
+
}})
|
|
314
|
+
|
|
315
|
+
Then tell the user: "I've set up the Gmail Tool node with dynamic AI parameters - it will automatically determine recipients and subjects based on context."
|
|
316
|
+
</handling_uncertainty>`;
|
|
317
|
+
const responsePatterns = `
|
|
318
|
+
<response_patterns>
|
|
319
|
+
After completing workflow tasks, follow this structure:
|
|
320
|
+
|
|
321
|
+
1. **Brief Summary** (1-2 sentences)
|
|
322
|
+
State what was created/modified without listing every parameter
|
|
323
|
+
|
|
324
|
+
2. **Key Requirements** (if any)
|
|
325
|
+
- Credentials needed
|
|
326
|
+
- Parameters the user should verify
|
|
327
|
+
- Any manual configuration required
|
|
328
|
+
|
|
329
|
+
3. **How to Use** (when relevant)
|
|
330
|
+
Quick steps to get started
|
|
331
|
+
|
|
332
|
+
4. **Next Steps** (if applicable)
|
|
333
|
+
What the user might want to do next
|
|
334
|
+
|
|
335
|
+
<communication_style>
|
|
336
|
+
Be warm, helpful, and most importantly concise. Focus on actionable information.
|
|
337
|
+
- Lead with what was accomplished
|
|
338
|
+
- Provide clear next steps
|
|
339
|
+
- Highlight only critical configuration needs
|
|
340
|
+
- Be warm and encouraging without excessive enthusiasm
|
|
341
|
+
- Use emojis sparingly (1-2 max per response)
|
|
342
|
+
- Focus on what the user needs to know
|
|
343
|
+
- Expand details only when asked
|
|
344
|
+
- End with a brief note that the workflow can be adjusted if needed
|
|
345
|
+
</communication_style>
|
|
346
|
+
</response_patterns>
|
|
347
|
+
`;
|
|
348
|
+
const currentWorkflowJson = `
|
|
349
|
+
<current_workflow_json>
|
|
350
|
+
{workflowJSON}
|
|
351
|
+
</current_workflow_json>`;
|
|
352
|
+
const currentExecutionData = `
|
|
353
|
+
<current_simplified_execution_data>
|
|
354
|
+
{executionData}
|
|
355
|
+
</current_simplified_execution_data>`;
|
|
356
|
+
const currentExecutionNodesSchemas = `
|
|
357
|
+
<current_execution_nodes_schemas>
|
|
358
|
+
{executionSchema}
|
|
359
|
+
</current_execution_nodes_schemas>`;
|
|
360
|
+
exports.mainAgentPrompt = prompts_1.ChatPromptTemplate.fromMessages([
|
|
361
|
+
[
|
|
362
|
+
'system',
|
|
363
|
+
[
|
|
364
|
+
{
|
|
365
|
+
type: 'text',
|
|
366
|
+
text: systemPrompt,
|
|
367
|
+
cache_control: { type: 'ephemeral' },
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
type: 'text',
|
|
371
|
+
text: currentWorkflowJson,
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
type: 'text',
|
|
375
|
+
text: currentExecutionData,
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
type: 'text',
|
|
379
|
+
text: currentExecutionNodesSchemas,
|
|
380
|
+
},
|
|
381
|
+
{
|
|
382
|
+
type: 'text',
|
|
383
|
+
text: responsePatterns,
|
|
384
|
+
cache_control: { type: 'ephemeral' },
|
|
385
|
+
},
|
|
386
|
+
],
|
|
387
|
+
],
|
|
388
|
+
['placeholder', '{messages}'],
|
|
389
|
+
]);
|
|
390
|
+
//# sourceMappingURL=main-agent.prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main-agent.prompt.js","sourceRoot":"","sources":["../../../src/tools/prompts/main-agent.prompt.ts"],"names":[],"mappings":";;;AAAA,qDAA6D;AAE7D,MAAM,YAAY,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wBAuTG,CAAC;AAEzB,MAAM,gBAAgB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8BxB,CAAC;AAEF,MAAM,mBAAmB,GAAG;;;yBAGH,CAAC;AAE1B,MAAM,oBAAoB,GAAG;;;qCAGQ,CAAC;AAEtC,MAAM,4BAA4B,GAAG;;;mCAGF,CAAC;AACvB,QAAA,eAAe,GAAG,4BAAkB,CAAC,YAAY,CAAC;IAC9D;QACC,QAAQ;QACR;YACC;gBACC,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,YAAY;gBAClB,aAAa,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE;aACpC;YACD;gBACC,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,mBAAmB;aACzB;YACD;gBACC,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,oBAAoB;aAC1B;YACD;gBACC,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,4BAA4B;aAClC;YACD;gBACC,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,gBAAgB;gBACtB,aAAa,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE;aACpC;SACD;KACD;IACD,CAAC,aAAa,EAAE,YAAY,CAAC;CAC7B,CAAC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Logger } from '@n8n/backend-common';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
export declare function createRemoveNodeTool(_logger?: Logger): import("@langchain/core/tools").DynamicStructuredTool<z.ZodObject<{
|
|
4
|
+
nodeId: z.ZodString;
|
|
5
|
+
}, "strip", z.ZodTypeAny, {
|
|
6
|
+
nodeId: string;
|
|
7
|
+
}, {
|
|
8
|
+
nodeId: string;
|
|
9
|
+
}>, {
|
|
10
|
+
nodeId: string;
|
|
11
|
+
}, {
|
|
12
|
+
nodeId: string;
|
|
13
|
+
}, import("@langchain/langgraph").Command<unknown>>;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createRemoveNodeTool = createRemoveNodeTool;
|
|
4
|
+
const tools_1 = require("@langchain/core/tools");
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
const errors_1 = require("../errors");
|
|
7
|
+
const progress_1 = require("./helpers/progress");
|
|
8
|
+
const response_1 = require("./helpers/response");
|
|
9
|
+
const state_1 = require("./helpers/state");
|
|
10
|
+
const validation_1 = require("./helpers/validation");
|
|
11
|
+
const removeNodeSchema = zod_1.z.object({
|
|
12
|
+
nodeId: zod_1.z.string().describe('The ID of the node to remove from the workflow'),
|
|
13
|
+
});
|
|
14
|
+
function countNodeConnections(nodeId, connections) {
|
|
15
|
+
let count = 0;
|
|
16
|
+
if (connections[nodeId]) {
|
|
17
|
+
for (const connectionType of Object.values(connections[nodeId])) {
|
|
18
|
+
if (Array.isArray(connectionType)) {
|
|
19
|
+
for (const outputs of connectionType) {
|
|
20
|
+
if (Array.isArray(outputs)) {
|
|
21
|
+
count += outputs.length;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
for (const [_sourceNodeId, nodeConnections] of Object.entries(connections)) {
|
|
28
|
+
for (const outputs of Object.values(nodeConnections)) {
|
|
29
|
+
if (Array.isArray(outputs)) {
|
|
30
|
+
for (const outputConnections of outputs) {
|
|
31
|
+
if (Array.isArray(outputConnections)) {
|
|
32
|
+
count += outputConnections.filter((conn) => conn.node === nodeId).length;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return count;
|
|
39
|
+
}
|
|
40
|
+
function buildResponseMessage(nodeName, nodeType, connectionsRemoved) {
|
|
41
|
+
const parts = [`Successfully removed node "${nodeName}" (${nodeType})`];
|
|
42
|
+
if (connectionsRemoved > 0) {
|
|
43
|
+
parts.push(`Removed ${connectionsRemoved} connection${connectionsRemoved > 1 ? 's' : ''}`);
|
|
44
|
+
}
|
|
45
|
+
return parts.join('\n');
|
|
46
|
+
}
|
|
47
|
+
function createRemoveNodeTool(_logger) {
|
|
48
|
+
return (0, tools_1.tool)((input, config) => {
|
|
49
|
+
const reporter = (0, progress_1.createProgressReporter)(config, 'remove_node');
|
|
50
|
+
try {
|
|
51
|
+
const validatedInput = removeNodeSchema.parse(input);
|
|
52
|
+
const { nodeId } = validatedInput;
|
|
53
|
+
reporter.start(validatedInput);
|
|
54
|
+
const state = (0, state_1.getWorkflowState)();
|
|
55
|
+
const workflow = (0, state_1.getCurrentWorkflow)(state);
|
|
56
|
+
(0, progress_1.reportProgress)(reporter, `Removing node ${nodeId}`);
|
|
57
|
+
const nodeToRemove = (0, validation_1.validateNodeExists)(nodeId, workflow.nodes);
|
|
58
|
+
if (!nodeToRemove) {
|
|
59
|
+
const error = (0, validation_1.createNodeNotFoundError)(nodeId);
|
|
60
|
+
reporter.error(error);
|
|
61
|
+
return (0, response_1.createErrorResponse)(config, error);
|
|
62
|
+
}
|
|
63
|
+
const connectionsRemoved = countNodeConnections(nodeId, workflow.connections);
|
|
64
|
+
const message = buildResponseMessage(nodeToRemove.name, nodeToRemove.type, connectionsRemoved);
|
|
65
|
+
const output = {
|
|
66
|
+
removedNodeId: nodeId,
|
|
67
|
+
removedNodeName: nodeToRemove.name,
|
|
68
|
+
removedNodeType: nodeToRemove.type,
|
|
69
|
+
connectionsRemoved,
|
|
70
|
+
message,
|
|
71
|
+
};
|
|
72
|
+
reporter.complete(output);
|
|
73
|
+
const stateUpdates = (0, state_1.removeNodeFromWorkflow)(nodeId);
|
|
74
|
+
return (0, response_1.createSuccessResponse)(config, message, stateUpdates);
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
if (error instanceof zod_1.z.ZodError) {
|
|
78
|
+
const validationError = new errors_1.ValidationError('Invalid input parameters', {
|
|
79
|
+
extra: { errors: error.errors },
|
|
80
|
+
});
|
|
81
|
+
reporter.error(validationError);
|
|
82
|
+
return (0, response_1.createErrorResponse)(config, validationError);
|
|
83
|
+
}
|
|
84
|
+
const toolError = new errors_1.ToolExecutionError(error instanceof Error ? error.message : 'Unknown error occurred', {
|
|
85
|
+
toolName: 'remove_node',
|
|
86
|
+
cause: error instanceof Error ? error : undefined,
|
|
87
|
+
});
|
|
88
|
+
reporter.error(toolError);
|
|
89
|
+
return (0, response_1.createErrorResponse)(config, toolError);
|
|
90
|
+
}
|
|
91
|
+
}, {
|
|
92
|
+
name: 'remove_node',
|
|
93
|
+
description: 'Remove a node from the workflow by its ID. This will also remove all connections to and from the node. Use this tool when you need to delete a node that is no longer needed in the workflow.',
|
|
94
|
+
schema: removeNodeSchema,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=remove-node.tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remove-node.tool.js","sourceRoot":"","sources":["../../src/tools/remove-node.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
|
2
|
+
import type { INodeTypeDescription, Logger } from 'n8n-workflow';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
export declare function createUpdateNodeParametersTool(nodeTypes: INodeTypeDescription[], llm: BaseChatModel, logger?: Logger): import("@langchain/core/tools").DynamicStructuredTool<z.ZodObject<{
|
|
5
|
+
nodeId: z.ZodString;
|
|
6
|
+
changes: z.ZodArray<z.ZodString, "many">;
|
|
7
|
+
}, "strip", z.ZodTypeAny, {
|
|
8
|
+
nodeId: string;
|
|
9
|
+
changes: string[];
|
|
10
|
+
}, {
|
|
11
|
+
nodeId: string;
|
|
12
|
+
changes: string[];
|
|
13
|
+
}>, {
|
|
14
|
+
nodeId: string;
|
|
15
|
+
changes: string[];
|
|
16
|
+
}, {
|
|
17
|
+
nodeId: string;
|
|
18
|
+
changes: string[];
|
|
19
|
+
}, import("@langchain/langgraph").Command<unknown>>;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createUpdateNodeParametersTool = createUpdateNodeParametersTool;
|
|
4
|
+
const tools_1 = require("@langchain/core/tools");
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
const parameter_updater_1 = require("../chains/parameter-updater");
|
|
7
|
+
const errors_1 = require("../errors");
|
|
8
|
+
const progress_1 = require("./helpers/progress");
|
|
9
|
+
const response_1 = require("./helpers/response");
|
|
10
|
+
const state_1 = require("./helpers/state");
|
|
11
|
+
const validation_1 = require("./helpers/validation");
|
|
12
|
+
const parameter_update_utils_1 = require("./utils/parameter-update.utils");
|
|
13
|
+
const updateNodeParametersSchema = zod_1.z.object({
|
|
14
|
+
nodeId: zod_1.z.string().describe('The ID of the node to update'),
|
|
15
|
+
changes: zod_1.z
|
|
16
|
+
.array(zod_1.z.string())
|
|
17
|
+
.min(1)
|
|
18
|
+
.describe('Array of natural language changes to apply to the node parameters (e.g., "Set the URL to call the weather API", "Add an API key header")'),
|
|
19
|
+
});
|
|
20
|
+
function buildSuccessMessage(node, changes) {
|
|
21
|
+
const changesList = changes.map((c) => `- ${c}`).join('\n');
|
|
22
|
+
return `Successfully updated parameters for node "${node.name}" (${node.type}):\n${changesList}`;
|
|
23
|
+
}
|
|
24
|
+
function createUpdateNodeParametersTool(nodeTypes, llm, logger) {
|
|
25
|
+
return (0, tools_1.tool)(async (input, config) => {
|
|
26
|
+
const reporter = (0, progress_1.createProgressReporter)(config, 'update_node_parameters');
|
|
27
|
+
try {
|
|
28
|
+
const validatedInput = updateNodeParametersSchema.parse(input);
|
|
29
|
+
const { nodeId, changes } = validatedInput;
|
|
30
|
+
reporter.start(validatedInput);
|
|
31
|
+
const state = (0, state_1.getWorkflowState)();
|
|
32
|
+
const workflow = (0, state_1.getCurrentWorkflow)(state);
|
|
33
|
+
const node = (0, validation_1.validateNodeExists)(nodeId, workflow.nodes);
|
|
34
|
+
if (!node) {
|
|
35
|
+
const error = (0, validation_1.createNodeNotFoundError)(nodeId);
|
|
36
|
+
reporter.error(error);
|
|
37
|
+
return (0, response_1.createErrorResponse)(config, error);
|
|
38
|
+
}
|
|
39
|
+
const nodeType = (0, validation_1.findNodeType)(node.type, nodeTypes);
|
|
40
|
+
if (!nodeType) {
|
|
41
|
+
const error = (0, validation_1.createNodeTypeNotFoundError)(node.type);
|
|
42
|
+
reporter.error(error);
|
|
43
|
+
return (0, response_1.createErrorResponse)(config, error);
|
|
44
|
+
}
|
|
45
|
+
(0, progress_1.reportProgress)(reporter, `Updating parameters for node "${node.name}"`, {
|
|
46
|
+
nodeId,
|
|
47
|
+
changes,
|
|
48
|
+
});
|
|
49
|
+
try {
|
|
50
|
+
const currentParameters = (0, parameter_update_utils_1.extractNodeParameters)(node);
|
|
51
|
+
const formattedChanges = (0, parameter_update_utils_1.formatChangesForPrompt)(changes);
|
|
52
|
+
const nodePropertiesJson = JSON.stringify(nodeType.properties || [], null, 2);
|
|
53
|
+
const parametersChain = (0, parameter_updater_1.createParameterUpdaterChain)(llm, {
|
|
54
|
+
nodeType: node.type,
|
|
55
|
+
nodeDefinition: nodeType,
|
|
56
|
+
requestedChanges: changes,
|
|
57
|
+
}, logger);
|
|
58
|
+
const newParameters = (await parametersChain.invoke({
|
|
59
|
+
workflow_json: workflow,
|
|
60
|
+
execution_schema: state.workflowContext?.executionSchema ?? 'NO SCHEMA',
|
|
61
|
+
execution_data: state.workflowContext?.executionData ?? 'NO EXECUTION DATA YET',
|
|
62
|
+
node_id: nodeId,
|
|
63
|
+
node_name: node.name,
|
|
64
|
+
node_type: node.type,
|
|
65
|
+
current_parameters: JSON.stringify(currentParameters, null, 2),
|
|
66
|
+
node_definition: nodePropertiesJson,
|
|
67
|
+
changes: formattedChanges,
|
|
68
|
+
}));
|
|
69
|
+
if (!newParameters || typeof newParameters !== 'object') {
|
|
70
|
+
throw new errors_1.ParameterUpdateError('Invalid parameters returned from LLM', {
|
|
71
|
+
nodeId,
|
|
72
|
+
nodeType: node.type,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
if (!newParameters.parameters || typeof newParameters.parameters !== 'object') {
|
|
76
|
+
throw new errors_1.ParameterUpdateError('Invalid parameters structure returned from LLM', {
|
|
77
|
+
nodeId,
|
|
78
|
+
nodeType: node.type,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
const fixedParameters = (0, parameter_update_utils_1.fixExpressionPrefixes)(newParameters.parameters);
|
|
82
|
+
const updatedParameters = (0, parameter_update_utils_1.mergeParameters)(currentParameters, fixedParameters);
|
|
83
|
+
const updatedNode = (0, parameter_update_utils_1.updateNodeWithParameters)(node, updatedParameters);
|
|
84
|
+
const message = buildSuccessMessage(node, changes);
|
|
85
|
+
const output = {
|
|
86
|
+
nodeId,
|
|
87
|
+
nodeName: node.name,
|
|
88
|
+
nodeType: node.type,
|
|
89
|
+
updatedParameters,
|
|
90
|
+
appliedChanges: changes,
|
|
91
|
+
message,
|
|
92
|
+
};
|
|
93
|
+
reporter.complete(output);
|
|
94
|
+
const stateUpdates = (0, state_1.updateNodeInWorkflow)(state, nodeId, updatedNode);
|
|
95
|
+
return (0, response_1.createSuccessResponse)(config, message, stateUpdates);
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
if (error instanceof errors_1.ParameterUpdateError) {
|
|
99
|
+
reporter.error(error);
|
|
100
|
+
return (0, response_1.createErrorResponse)(config, error);
|
|
101
|
+
}
|
|
102
|
+
const toolError = new errors_1.ToolExecutionError(`Failed to update node parameters: ${error instanceof Error ? error.message : 'Unknown error'}`, {
|
|
103
|
+
toolName: 'update_node_parameters',
|
|
104
|
+
cause: error instanceof Error ? error : undefined,
|
|
105
|
+
});
|
|
106
|
+
reporter.error(toolError);
|
|
107
|
+
return (0, response_1.createErrorResponse)(config, toolError);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
if (error instanceof zod_1.z.ZodError) {
|
|
112
|
+
const validationError = new errors_1.ValidationError('Invalid input parameters', {
|
|
113
|
+
extra: { errors: error.errors },
|
|
114
|
+
});
|
|
115
|
+
reporter.error(validationError);
|
|
116
|
+
return (0, response_1.createErrorResponse)(config, validationError);
|
|
117
|
+
}
|
|
118
|
+
const toolError = new errors_1.ToolExecutionError(error instanceof Error ? error.message : 'Unknown error occurred', {
|
|
119
|
+
toolName: 'update_node_parameters',
|
|
120
|
+
cause: error instanceof Error ? error : undefined,
|
|
121
|
+
});
|
|
122
|
+
reporter.error(toolError);
|
|
123
|
+
return (0, response_1.createErrorResponse)(config, toolError);
|
|
124
|
+
}
|
|
125
|
+
}, {
|
|
126
|
+
name: 'update_node_parameters',
|
|
127
|
+
description: 'Update the parameters of an existing node in the workflow based on natural language changes. This tool intelligently modifies only the specified parameters while preserving others. Examples: "Set the URL to https://api.example.com", "Add authentication header", "Change method to POST", "Set the condition to check if status equals success".',
|
|
128
|
+
schema: updateNodeParametersSchema,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=update-node-parameters.tool.js.map
|