@n8n/instance-ai 1.3.5 → 1.5.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/agent/credential-guardrails.prompt.d.ts +1 -0
- package/dist/agent/credential-guardrails.prompt.js +5 -0
- package/dist/agent/credential-guardrails.prompt.js.map +1 -0
- package/dist/agent/instance-agent.js +0 -1
- package/dist/agent/instance-agent.js.map +1 -1
- package/dist/agent/shared-prompts.d.ts +4 -0
- package/dist/agent/shared-prompts.js +17 -0
- package/dist/agent/shared-prompts.js.map +1 -0
- package/dist/agent/sub-agent-debriefing.d.ts +2 -2
- package/dist/agent/sub-agent-factory.d.ts +1 -1
- package/dist/agent/sub-agent-factory.js +7 -7
- package/dist/agent/sub-agent-factory.js.map +1 -1
- package/dist/agent/system-prompt.js +56 -29
- package/dist/agent/system-prompt.js.map +1 -1
- package/dist/build.tsbuildinfo +1 -1
- package/dist/constants/max-steps.d.ts +1 -1
- package/dist/constants/max-steps.js +1 -1
- package/dist/constants/max-steps.js.map +1 -1
- package/dist/constants/model-settings.d.ts +3 -0
- package/dist/constants/model-settings.js +7 -0
- package/dist/constants/model-settings.js.map +1 -0
- package/dist/index.d.ts +9 -3
- package/dist/index.js +10 -2
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +6 -0
- package/dist/planned-tasks/planned-task-permissions.d.ts +2 -0
- package/dist/planned-tasks/planned-task-permissions.js +8 -2
- package/dist/planned-tasks/planned-task-permissions.js.map +1 -1
- package/dist/planned-tasks/planned-task-service.d.ts +14 -1
- package/dist/planned-tasks/planned-task-service.js +138 -2
- package/dist/planned-tasks/planned-task-service.js.map +1 -1
- package/dist/runtime/background-task-manager.d.ts +25 -1
- package/dist/runtime/background-task-manager.js +66 -2
- package/dist/runtime/background-task-manager.js.map +1 -1
- package/dist/runtime/builder-sandbox-session-registry.d.ts +45 -0
- package/dist/runtime/builder-sandbox-session-registry.js +159 -0
- package/dist/runtime/builder-sandbox-session-registry.js.map +1 -0
- package/dist/runtime/run-state-registry.d.ts +7 -4
- package/dist/runtime/run-state-registry.js +9 -0
- package/dist/runtime/run-state-registry.js.map +1 -1
- package/dist/storage/agent-tree-snapshot.d.ts +2 -0
- package/dist/storage/planned-task-storage.js +2 -1
- package/dist/storage/planned-task-storage.js.map +1 -1
- package/dist/storage/workflow-loop-storage.d.ts +292 -12
- package/dist/stream/consume-with-hitl.d.ts +1 -0
- package/dist/stream/consume-with-hitl.js +1 -0
- package/dist/stream/consume-with-hitl.js.map +1 -1
- package/dist/tools/credentials.tool.js +20 -3
- package/dist/tools/credentials.tool.js.map +1 -1
- package/dist/tools/data-tables.tool.js +60 -22
- package/dist/tools/data-tables.tool.js.map +1 -1
- package/dist/tools/executions.tool.js +4 -1
- package/dist/tools/executions.tool.js.map +1 -1
- package/dist/tools/index.d.ts +1 -2
- package/dist/tools/index.js +2 -3
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/nodes/suggested-nodes-data.js +1 -1
- package/dist/tools/nodes/suggested-nodes-data.js.map +1 -1
- package/dist/tools/nodes.tool.js +25 -13
- package/dist/tools/nodes.tool.js.map +1 -1
- package/dist/tools/orchestration/add-plan-item.tool.js +3 -1
- package/dist/tools/orchestration/add-plan-item.tool.js.map +1 -1
- package/dist/tools/orchestration/blueprint-accumulator.d.ts +4 -1
- package/dist/tools/orchestration/blueprint-accumulator.js +28 -0
- package/dist/tools/orchestration/blueprint-accumulator.js.map +1 -1
- package/dist/tools/orchestration/blueprint.schema.d.ts +60 -15
- package/dist/tools/orchestration/blueprint.schema.js +15 -1
- package/dist/tools/orchestration/blueprint.schema.js.map +1 -1
- package/dist/tools/orchestration/browser-credential-setup.prompt.d.ts +13 -0
- package/dist/tools/orchestration/browser-credential-setup.prompt.js +140 -0
- package/dist/tools/orchestration/browser-credential-setup.prompt.js.map +1 -0
- package/dist/tools/orchestration/browser-credential-setup.tool.d.ts +1 -0
- package/dist/tools/orchestration/browser-credential-setup.tool.js +8 -139
- package/dist/tools/orchestration/browser-credential-setup.tool.js.map +1 -1
- package/dist/tools/orchestration/build-workflow-agent.prompt.js +137 -239
- package/dist/tools/orchestration/build-workflow-agent.prompt.js.map +1 -1
- package/dist/tools/orchestration/build-workflow-agent.tool.d.ts +51 -3
- package/dist/tools/orchestration/build-workflow-agent.tool.js +842 -269
- package/dist/tools/orchestration/build-workflow-agent.tool.js.map +1 -1
- package/dist/tools/orchestration/builder-memory-compaction.d.ts +38 -0
- package/dist/tools/orchestration/builder-memory-compaction.js +146 -0
- package/dist/tools/orchestration/builder-memory-compaction.js.map +1 -0
- package/dist/tools/orchestration/complete-checkpoint.tool.d.ts +2 -0
- package/dist/tools/orchestration/complete-checkpoint.tool.js +76 -0
- package/dist/tools/orchestration/complete-checkpoint.tool.js.map +1 -0
- package/dist/tools/orchestration/data-table-agent.prompt.d.ts +1 -1
- package/dist/tools/orchestration/data-table-agent.prompt.js +4 -6
- package/dist/tools/orchestration/data-table-agent.prompt.js.map +1 -1
- package/dist/tools/orchestration/data-table-agent.tool.js +34 -18
- package/dist/tools/orchestration/data-table-agent.tool.js.map +1 -1
- package/dist/tools/orchestration/delegate.tool.js +33 -17
- package/dist/tools/orchestration/delegate.tool.js.map +1 -1
- package/dist/tools/orchestration/plan-agent-prompt.d.ts +1 -1
- package/dist/tools/orchestration/plan-agent-prompt.js +17 -17
- package/dist/tools/orchestration/plan-agent-prompt.js.map +1 -1
- package/dist/tools/orchestration/plan-with-agent.tool.d.ts +8 -0
- package/dist/tools/orchestration/plan-with-agent.tool.js +43 -12
- package/dist/tools/orchestration/plan-with-agent.tool.js.map +1 -1
- package/dist/tools/orchestration/plan.tool.js +82 -2
- package/dist/tools/orchestration/plan.tool.js.map +1 -1
- package/dist/tools/orchestration/report-verification-verdict.tool.d.ts +40 -2
- package/dist/tools/orchestration/report-verification-verdict.tool.js +89 -7
- package/dist/tools/orchestration/report-verification-verdict.tool.js.map +1 -1
- package/dist/tools/orchestration/research-agent-prompt.d.ts +1 -1
- package/dist/tools/orchestration/research-agent-prompt.js +2 -4
- package/dist/tools/orchestration/research-agent-prompt.js.map +1 -1
- package/dist/tools/orchestration/research-with-agent.tool.js +33 -17
- package/dist/tools/orchestration/research-with-agent.tool.js.map +1 -1
- package/dist/tools/orchestration/verify-built-workflow.tool.d.ts +8 -2
- package/dist/tools/orchestration/verify-built-workflow.tool.js +476 -6
- package/dist/tools/orchestration/verify-built-workflow.tool.js.map +1 -1
- package/dist/tools/research.tool.js +2 -2
- package/dist/tools/research.tool.js.map +1 -1
- package/dist/tools/shared/ask-user.tool.js +2 -1
- package/dist/tools/shared/ask-user.tool.js.map +1 -1
- package/dist/tools/templates.tool.js +5 -90
- package/dist/tools/templates.tool.js.map +1 -1
- package/dist/tools/web-research/sanitize-web-content.d.ts +0 -1
- package/dist/tools/web-research/sanitize-web-content.js +0 -9
- package/dist/tools/web-research/sanitize-web-content.js.map +1 -1
- package/dist/tools/workflows/apply-workflow-credentials.tool.d.ts +2 -2
- package/dist/tools/workflows/build-workflow.tool.d.ts +8 -8
- package/dist/tools/workflows/build-workflow.tool.js +14 -2
- package/dist/tools/workflows/build-workflow.tool.js.map +1 -1
- package/dist/tools/workflows/materialize-node-type.tool.d.ts +8 -8
- package/dist/tools/workflows/resolve-credentials.js +6 -6
- package/dist/tools/workflows/resolve-credentials.js.map +1 -1
- package/dist/tools/workflows/setup-workflow.service.js +3 -2
- package/dist/tools/workflows/setup-workflow.service.js.map +1 -1
- package/dist/tools/workflows/submit-workflow-identity.d.ts +35 -0
- package/dist/tools/workflows/submit-workflow-identity.js +154 -0
- package/dist/tools/workflows/submit-workflow-identity.js.map +1 -0
- package/dist/tools/workflows/submit-workflow.tool.d.ts +82 -3
- package/dist/tools/workflows/submit-workflow.tool.js +114 -35
- package/dist/tools/workflows/submit-workflow.tool.js.map +1 -1
- package/dist/tracing/langsmith-tracing.d.ts +12 -0
- package/dist/tracing/langsmith-tracing.js +35 -3
- package/dist/tracing/langsmith-tracing.js.map +1 -1
- package/dist/tracing/trace-replay.d.ts +3 -0
- package/dist/tracing/trace-replay.js +65 -0
- package/dist/tracing/trace-replay.js.map +1 -1
- package/dist/types.d.ts +82 -12
- package/dist/utils/eval-agents.js +4 -2
- package/dist/utils/eval-agents.js.map +1 -1
- package/dist/workflow-builder/parse-validate.d.ts +5 -1
- package/dist/workflow-builder/parse-validate.js +4 -3
- package/dist/workflow-builder/parse-validate.js.map +1 -1
- package/dist/workflow-loop/guidance.js +15 -5
- package/dist/workflow-loop/guidance.js.map +1 -1
- package/dist/workflow-loop/index.d.ts +3 -2
- package/dist/workflow-loop/index.js +9 -1
- package/dist/workflow-loop/index.js.map +1 -1
- package/dist/workflow-loop/remediation.d.ts +13 -0
- package/dist/workflow-loop/remediation.js +36 -0
- package/dist/workflow-loop/remediation.js.map +1 -0
- package/dist/workflow-loop/runtime.js +7 -0
- package/dist/workflow-loop/runtime.js.map +1 -1
- package/dist/workflow-loop/workflow-loop-controller.d.ts +1 -1
- package/dist/workflow-loop/workflow-loop-controller.js +196 -29
- package/dist/workflow-loop/workflow-loop-controller.js.map +1 -1
- package/dist/workflow-loop/workflow-loop-state.d.ts +338 -8
- package/dist/workflow-loop/workflow-loop-state.js +44 -1
- package/dist/workflow-loop/workflow-loop-state.js.map +1 -1
- package/dist/workflow-loop/workflow-task-service.d.ts +2 -1
- package/dist/workflow-loop/workflow-task-service.js +4 -0
- package/dist/workflow-loop/workflow-task-service.js.map +1 -1
- package/dist/workspace/builder-sandbox-factory.d.ts +6 -1
- package/dist/workspace/builder-sandbox-factory.js +115 -26
- package/dist/workspace/builder-sandbox-factory.js.map +1 -1
- package/dist/workspace/create-workspace.d.ts +2 -0
- package/dist/workspace/create-workspace.js.map +1 -1
- package/dist/workspace/pack-workspace-sdk.d.ts +9 -0
- package/dist/workspace/pack-workspace-sdk.js +80 -0
- package/dist/workspace/pack-workspace-sdk.js.map +1 -0
- package/dist/workspace/sandbox-fs.d.ts +1 -1
- package/dist/workspace/sandbox-fs.js +3 -1
- package/dist/workspace/sandbox-fs.js.map +1 -1
- package/dist/workspace/sandbox-setup.js +83 -19
- package/dist/workspace/sandbox-setup.js.map +1 -1
- package/dist/workspace/snapshot-manager.d.ts +14 -2
- package/dist/workspace/snapshot-manager.js +57 -1
- package/dist/workspace/snapshot-manager.js.map +1 -1
- package/package.json +15 -8
- package/dist/tools/templates/template-api.d.ts +0 -21
- package/dist/tools/templates/template-api.js +0 -104
- package/dist/tools/templates/template-api.js.map +0 -1
- package/dist/tools/templates/types.d.ts +0 -52
- package/dist/tools/templates/types.js +0 -37
- package/dist/tools/templates/types.js.map +0 -1
- package/dist/tools/utils/mermaid.utils.d.ts +0 -15
- package/dist/tools/utils/mermaid.utils.js +0 -622
- package/dist/tools/utils/mermaid.utils.js.map +0 -1
- package/dist/tools/utils/node-configuration.utils.d.ts +0 -6
- package/dist/tools/utils/node-configuration.utils.js +0 -77
- package/dist/tools/utils/node-configuration.utils.js.map +0 -1
|
@@ -5,20 +5,40 @@ exports.createSandboxBuilderAgentPrompt = createSandboxBuilderAgentPrompt;
|
|
|
5
5
|
const parameter_guides_1 = require("@n8n/workflow-sdk/prompts/node-guidance/parameter-guides");
|
|
6
6
|
const node_selection_1 = require("@n8n/workflow-sdk/prompts/node-selection");
|
|
7
7
|
const sdk_reference_1 = require("@n8n/workflow-sdk/prompts/sdk-reference");
|
|
8
|
-
const
|
|
9
|
-
const
|
|
8
|
+
const shared_prompts_1 = require("../../agent/shared-prompts");
|
|
9
|
+
const BUILDER_OUTPUT_DISCIPLINE = `## Output Discipline
|
|
10
|
+
- Your text output is visible to the user. Be concise and natural.
|
|
11
|
+
- Only output text for: errors that need attention, or a brief natural completion message.
|
|
12
|
+
- No emojis, no filler phrases, no markdown headers in your text output.
|
|
13
|
+
- When conversation context is provided, use it to continue naturally — do not repeat information the user already knows.
|
|
14
|
+
|
|
15
|
+
### No narration (critical)
|
|
16
|
+
Do NOT announce what you're about to do. The user already sees your tool calls in real time via the agent card; narrating them is pure noise. Stay silent while working; speak only on completion or when blocked.
|
|
17
|
+
|
|
18
|
+
BAD (do not write anything like this):
|
|
19
|
+
- "I'll build this family AI assistant for Telegram. Let me start by discovering credentials and resources..."
|
|
20
|
+
- "I'll start by reading the current workflow code and looking up the correct Linear node type definition."
|
|
21
|
+
- "I don't see any pinData — let me check if there's something embedded in the workflow..."
|
|
22
|
+
- "Let me look up the Slack channel IDs now."
|
|
23
|
+
|
|
24
|
+
GOOD (one-line, only on completion or block):
|
|
25
|
+
- "Family AI assistant workflow ready — uses Telegram, OpenAI, and your shopping list data table."
|
|
26
|
+
- "Workflow updated: removed the stale pinData from the weather check node."
|
|
27
|
+
- "Blocked: the Linear API credential is missing and the setup wizard is needed before I can continue."`;
|
|
10
28
|
const SDK_CODE_RULES = `## SDK Code Rules
|
|
11
29
|
|
|
12
30
|
- Do NOT specify node positions — they are auto-calculated by the layout engine.
|
|
13
31
|
- For credentials, see the credential rules in your specific workflow process section below.
|
|
14
|
-
-
|
|
32
|
+
- For placeholders, see the ## Placeholders section.
|
|
15
33
|
- Use \`expr('{{ $json.field }}')\` for n8n expressions. Variables MUST be inside \`{{ }}\`.
|
|
16
34
|
- Do NOT use \`as const\` assertions — the workflow parser only supports JavaScript syntax, not TypeScript-only features. Just use plain string literals.
|
|
17
35
|
- Use string values directly for discriminator fields like \`resource\` and \`operation\` (e.g., \`resource: 'message'\` not \`resource: 'message' as const\`).
|
|
18
36
|
- When editing a pre-loaded workflow, **remove \`position\` arrays** from node configs — they are auto-calculated.
|
|
19
37
|
- **No em-dash (\`—\`) or other special Unicode characters in node names or string values.** Use plain hyphen (\`-\`) instead. The SDK parser cannot handle em-dashes.
|
|
20
38
|
- **IF node combinator** must be \`'and'\` or \`'or'\` (not \`'any'\` or \`'all'\`).`;
|
|
21
|
-
|
|
39
|
+
function buildBuilderSpecificPatterns(mode) {
|
|
40
|
+
const openAiCredExample = mode === 'sandbox' ? "{ id: 'credId', name: 'OpenAI account' }" : "newCredential('OpenAI')";
|
|
41
|
+
return `## Critical Patterns (Common Mistakes)
|
|
22
42
|
|
|
23
43
|
**Pay attention to @builderHint annotations in search results and type definitions** — these provide critical guidance on how to correctly configure node parameters. Write them out as notes when reviewing — they prevent common configuration mistakes.
|
|
24
44
|
|
|
@@ -33,13 +53,23 @@ After writing any workflow with IF, Switch, or Filter nodes, verify:
|
|
|
33
53
|
|
|
34
54
|
### AI Agent with Subnodes — use factory functions in subnodes config
|
|
35
55
|
\`\`\`javascript
|
|
56
|
+
const chatTrigger = trigger({
|
|
57
|
+
type: '@n8n/n8n-nodes-langchain.chatTrigger',
|
|
58
|
+
version: 1.3,
|
|
59
|
+
config: {
|
|
60
|
+
name: 'Chat Trigger',
|
|
61
|
+
parameters: { public: false },
|
|
62
|
+
output: [{ sessionId: 'chat-session-id', chatInput: 'Hello' }]
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
36
66
|
const model = languageModel({
|
|
37
67
|
type: '@n8n/n8n-nodes-langchain.lmChatOpenAi',
|
|
38
68
|
version: 1.3,
|
|
39
69
|
config: {
|
|
40
70
|
name: 'OpenAI Chat Model',
|
|
41
|
-
parameters: { model: { __rl: true, mode: 'list', value: 'gpt-
|
|
42
|
-
credentials: { openAiApi:
|
|
71
|
+
parameters: { model: { __rl: true, mode: 'list', value: 'gpt-5.4' } },
|
|
72
|
+
credentials: { openAiApi: ${openAiCredExample} }
|
|
43
73
|
}
|
|
44
74
|
});
|
|
45
75
|
|
|
@@ -55,6 +85,19 @@ const parser = outputParser({
|
|
|
55
85
|
}
|
|
56
86
|
});
|
|
57
87
|
|
|
88
|
+
const memoryNode = memory({
|
|
89
|
+
type: '@n8n/n8n-nodes-langchain.memoryBufferWindow',
|
|
90
|
+
version: 1.3,
|
|
91
|
+
config: {
|
|
92
|
+
name: 'Conversation Memory',
|
|
93
|
+
parameters: {
|
|
94
|
+
sessionIdType: 'customKey',
|
|
95
|
+
sessionKey: nodeJson(chatTrigger, 'sessionId'),
|
|
96
|
+
contextWindowLength: 10
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
|
|
58
101
|
const agent = node({
|
|
59
102
|
type: '@n8n/n8n-nodes-langchain.agent',
|
|
60
103
|
version: 3.1,
|
|
@@ -66,11 +109,12 @@ const agent = node({
|
|
|
66
109
|
hasOutputParser: true,
|
|
67
110
|
options: { systemMessage: 'You are an expert...' }
|
|
68
111
|
},
|
|
69
|
-
subnodes: { model: model, outputParser: parser }
|
|
112
|
+
subnodes: { model: model, memory: memoryNode, outputParser: parser }
|
|
70
113
|
}
|
|
71
114
|
});
|
|
72
115
|
\`\`\`
|
|
73
116
|
WRONG: \`.to(agent, { connectionType: 'ai_languageModel' })\` — subnodes MUST be in the config object.
|
|
117
|
+
For values inside AI subnodes, use explicit references such as \`nodeJson(triggerNode, 'sessionId')\` instead of \`$json.sessionId\`. For Chat Trigger memory specifically, \`sessionIdType: 'fromInput'\` is also valid.
|
|
74
118
|
|
|
75
119
|
### Code Node
|
|
76
120
|
\`\`\`javascript
|
|
@@ -172,192 +216,6 @@ export default workflow('id', 'name')
|
|
|
172
216
|
.add(scheduleTrigger).to(processNode);
|
|
173
217
|
\`\`\`
|
|
174
218
|
|
|
175
|
-
### Web App (SPA served from a webhook)
|
|
176
|
-
|
|
177
|
-
Serve a single-page application from an n8n webhook. The workflow fetches data, then renders a full HTML page with a client-side framework.
|
|
178
|
-
|
|
179
|
-
<web_app_pattern>
|
|
180
|
-
**Architecture:** Webhook (responseNode) -> Code node (build HTML) -> Respond with text/html
|
|
181
|
-
|
|
182
|
-
**File-based HTML (REQUIRED for pages > ~50 lines):**
|
|
183
|
-
Write the HTML to a separate file (e.g., \`chunks/dashboard.html\`), then in the SDK TypeScript code use \`readFileSync\` + \`JSON.stringify\` to safely embed it in a Code node. This eliminates ALL escaping problems:
|
|
184
|
-
|
|
185
|
-
1. Write your full HTML (with CSS, JS, Alpine.js/Tailwind) to \`chunks/page.html\`
|
|
186
|
-
2. In \`src/workflow.ts\`: \`const htmlTemplate = readFileSync(join(__dirname, '../chunks/page.html'), 'utf8');\`
|
|
187
|
-
3. Use \`JSON.stringify(htmlTemplate)\` to create a safe JS string literal for the Code node's jsCode
|
|
188
|
-
4. For data injection, embed a \`__DATA_PLACEHOLDER__\` token in the HTML and replace it at runtime
|
|
189
|
-
|
|
190
|
-
**NEVER embed large HTML directly in jsCode** — not as template literals, not as arrays of quoted lines. Both break for real-world pages (20KB+). Always use the file-based pattern.
|
|
191
|
-
|
|
192
|
-
**For small static HTML (< 50 lines):** You may inline as an array of quoted strings + \`.join('\\n')\`, but still prefer the file-based approach.
|
|
193
|
-
|
|
194
|
-
**Data injection patterns:**
|
|
195
|
-
- Static page (no server data): embed HTML directly, no placeholder needed
|
|
196
|
-
- Dynamic data: put \`<script id="__data" type="application/json">__DATA_PLACEHOLDER__</script>\` in the HTML. At runtime, the Code node replaces \`__DATA_PLACEHOLDER__\` with base64-encoded JSON. Client-side: \`JSON.parse(atob(document.getElementById('__data').textContent))\`
|
|
197
|
-
- Do NOT place bare \`{{ $json... }}\` inside an HTML string parameter
|
|
198
|
-
|
|
199
|
-
**Multi-route SPA (dashboard with API endpoints):**
|
|
200
|
-
Use multiple webhooks in one workflow — one serves the HTML page, others serve JSON API endpoints. The HTML's JavaScript uses \`fetch()\` to call sibling webhook paths.
|
|
201
|
-
|
|
202
|
-
**Default stack:** Alpine.js + Tailwind CSS via CDN. No build step, works in a single HTML file.
|
|
203
|
-
|
|
204
|
-
**Respond correctly:** Use respondToWebhook with respondWith: "text", put the HTML in responseBody via expression, and set Content-Type header.
|
|
205
|
-
</web_app_pattern>
|
|
206
|
-
|
|
207
|
-
#### Example: Multi-route dashboard with DataTable API
|
|
208
|
-
|
|
209
|
-
**chunks/dashboard.html** — the full HTML page (write this file first):
|
|
210
|
-
\`\`\`html
|
|
211
|
-
<!DOCTYPE html>
|
|
212
|
-
<html lang="en">
|
|
213
|
-
<head>
|
|
214
|
-
<meta charset="UTF-8">
|
|
215
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
216
|
-
<title>Dashboard</title>
|
|
217
|
-
<script src="https://cdn.tailwindcss.com"></script>
|
|
218
|
-
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3/dist/cdn.min.js"></script>
|
|
219
|
-
</head>
|
|
220
|
-
<body class="bg-gray-50 min-h-screen p-8">
|
|
221
|
-
<h1 class="text-2xl font-bold mb-6">Dashboard</h1>
|
|
222
|
-
<div x-data="app()" x-init="loadItems()">
|
|
223
|
-
<template x-for="item in items" :key="item.id">
|
|
224
|
-
<div class="bg-white rounded-lg shadow p-4 mb-3 flex items-center gap-3">
|
|
225
|
-
<input type="checkbox" :checked="item.completed" @change="toggle(item)">
|
|
226
|
-
<span x-text="item.title" :class="item.completed && 'line-through text-gray-400'"></span>
|
|
227
|
-
</div>
|
|
228
|
-
</template>
|
|
229
|
-
<form @submit.prevent="addItem()" class="mt-4 flex gap-2">
|
|
230
|
-
<input x-model="newTitle" placeholder="New item..." class="border rounded px-3 py-2 flex-1">
|
|
231
|
-
<button type="submit" class="bg-blue-600 text-white px-4 py-2 rounded">Add</button>
|
|
232
|
-
</form>
|
|
233
|
-
</div>
|
|
234
|
-
<!-- Server data injected at runtime (base64-encoded JSON) -->
|
|
235
|
-
<script id="__data" type="application/json">__DATA_PLACEHOLDER__</script>
|
|
236
|
-
<script>
|
|
237
|
-
function app() {
|
|
238
|
-
return {
|
|
239
|
-
items: JSON.parse(atob(document.getElementById('__data').textContent)),
|
|
240
|
-
newTitle: '',
|
|
241
|
-
async toggle(item) {
|
|
242
|
-
await fetch('/webhook/app/items/toggle', {
|
|
243
|
-
method: 'POST', headers: {'Content-Type': 'application/json'},
|
|
244
|
-
body: JSON.stringify({ id: item.id, completed: !item.completed })
|
|
245
|
-
});
|
|
246
|
-
item.completed = !item.completed;
|
|
247
|
-
},
|
|
248
|
-
async addItem() {
|
|
249
|
-
if (!this.newTitle.trim()) return;
|
|
250
|
-
const res = await fetch('/webhook/app/items/add', {
|
|
251
|
-
method: 'POST', headers: {'Content-Type': 'application/json'},
|
|
252
|
-
body: JSON.stringify({ title: this.newTitle })
|
|
253
|
-
});
|
|
254
|
-
const created = await res.json();
|
|
255
|
-
this.items.push(created);
|
|
256
|
-
this.newTitle = '';
|
|
257
|
-
},
|
|
258
|
-
loadItems() { /* items already loaded from __data */ }
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
</script>
|
|
262
|
-
</body>
|
|
263
|
-
</html>
|
|
264
|
-
\`\`\`
|
|
265
|
-
|
|
266
|
-
**src/workflow.ts** — the workflow with 4 webhook routes:
|
|
267
|
-
\`\`\`javascript
|
|
268
|
-
import { workflow, node, trigger, expr } from '@n8n/workflow-sdk';
|
|
269
|
-
import { readFileSync } from 'fs';
|
|
270
|
-
import { join } from 'path';
|
|
271
|
-
|
|
272
|
-
// Read the HTML template at build time — eliminates all escaping issues
|
|
273
|
-
const htmlTemplate = readFileSync(join(__dirname, '../chunks/dashboard.html'), 'utf8');
|
|
274
|
-
|
|
275
|
-
// ── Webhooks ──────────────────────────────────────────────
|
|
276
|
-
const pageWebhook = trigger({
|
|
277
|
-
type: 'n8n-nodes-base.webhook', version: 2.1,
|
|
278
|
-
config: { name: 'GET /app', parameters: { httpMethod: 'GET', path: 'app', responseMode: 'responseNode', options: {} } }
|
|
279
|
-
});
|
|
280
|
-
const getItemsWebhook = trigger({
|
|
281
|
-
type: 'n8n-nodes-base.webhook', version: 2.1,
|
|
282
|
-
config: { name: 'GET /app/items', parameters: { httpMethod: 'GET', path: 'app/items', responseMode: 'responseNode', options: {} } }
|
|
283
|
-
});
|
|
284
|
-
const toggleWebhook = trigger({
|
|
285
|
-
type: 'n8n-nodes-base.webhook', version: 2.1,
|
|
286
|
-
config: { name: 'POST /app/items/toggle', parameters: { httpMethod: 'POST', path: 'app/items/toggle', responseMode: 'responseNode', options: {} } }
|
|
287
|
-
});
|
|
288
|
-
const addWebhook = trigger({
|
|
289
|
-
type: 'n8n-nodes-base.webhook', version: 2.1,
|
|
290
|
-
config: { name: 'POST /app/items/add', parameters: { httpMethod: 'POST', path: 'app/items/add', responseMode: 'responseNode', options: {} } }
|
|
291
|
-
});
|
|
292
|
-
|
|
293
|
-
// ── Route 1: Serve HTML page with pre-loaded data ─────────
|
|
294
|
-
const fetchAllItems = node({
|
|
295
|
-
type: 'n8n-nodes-base.dataTable', version: 1.1,
|
|
296
|
-
config: { name: 'Fetch Items', parameters: { resource: 'row', operation: 'get', dataTableId: { __rl: true, mode: 'name', value: 'items' }, returnAll: true, options: {} } }
|
|
297
|
-
});
|
|
298
|
-
const aggregateItems = node({
|
|
299
|
-
type: 'n8n-nodes-base.aggregate', version: 1,
|
|
300
|
-
config: { name: 'Aggregate', parameters: { aggregate: 'aggregateAllItemData', destinationFieldName: 'data', options: {} } }
|
|
301
|
-
});
|
|
302
|
-
// JSON.stringify in the SDK code creates a safe JS string literal — no escaping issues
|
|
303
|
-
const buildPage = node({
|
|
304
|
-
type: 'n8n-nodes-base.code', version: 2,
|
|
305
|
-
config: {
|
|
306
|
-
name: 'Build Page',
|
|
307
|
-
parameters: {
|
|
308
|
-
mode: 'runOnceForAllItems',
|
|
309
|
-
jsCode: 'var data = $input.all()[0].json.data || [];\\n'
|
|
310
|
-
+ 'var encoded = Buffer.from(JSON.stringify(data)).toString("base64");\\n'
|
|
311
|
-
+ 'var html = ' + JSON.stringify(htmlTemplate) + '.replace("__DATA_PLACEHOLDER__", encoded);\\n'
|
|
312
|
-
+ 'return [{ json: { html: html } }];'
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
});
|
|
316
|
-
const respondHtml = node({
|
|
317
|
-
type: 'n8n-nodes-base.respondToWebhook', version: 1.1,
|
|
318
|
-
config: { name: 'Respond HTML', parameters: { respondWith: 'text', responseBody: expr('{{ $json.html }}'), options: { responseHeaders: { entries: [{ name: 'Content-Type', value: 'text/html; charset=utf-8' }] } } } }
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
// ── Route 2: GET items as JSON ────────────────────────────
|
|
322
|
-
const fetchItemsJson = node({
|
|
323
|
-
type: 'n8n-nodes-base.dataTable', version: 1.1,
|
|
324
|
-
config: { name: 'Get Items JSON', parameters: { resource: 'row', operation: 'get', dataTableId: { __rl: true, mode: 'name', value: 'items' }, returnAll: true, options: {} } }
|
|
325
|
-
});
|
|
326
|
-
const respondItems = node({
|
|
327
|
-
type: 'n8n-nodes-base.respondToWebhook', version: 1.1,
|
|
328
|
-
config: { name: 'Respond Items', parameters: { respondWith: 'allEntries', options: {} } }
|
|
329
|
-
});
|
|
330
|
-
|
|
331
|
-
// ── Route 3: Toggle item completion ───────────────────────
|
|
332
|
-
const updateItem = node({
|
|
333
|
-
type: 'n8n-nodes-base.dataTable', version: 1.1,
|
|
334
|
-
config: { name: 'Update Item', parameters: { resource: 'row', operation: 'update', dataTableId: { __rl: true, mode: 'name', value: 'items' }, matchingColumns: ['id'], columns: { mappingMode: 'defineBelow', value: { id: expr('{{ $json.body.id }}'), completed: expr('{{ $json.body.completed }}') }, schema: [{ id: 'id', displayName: 'id', required: false, defaultMatch: true, display: true, type: 'string', canBeUsedToMatch: true }, { id: 'completed', displayName: 'completed', required: false, defaultMatch: false, display: true, type: 'boolean', canBeUsedToMatch: false }] }, options: {} } }
|
|
335
|
-
});
|
|
336
|
-
const respondToggle = node({
|
|
337
|
-
type: 'n8n-nodes-base.respondToWebhook', version: 1.1,
|
|
338
|
-
config: { name: 'Respond Toggle', parameters: { respondWith: 'allEntries', options: {} } }
|
|
339
|
-
});
|
|
340
|
-
|
|
341
|
-
// ── Route 4: Add new item ─────────────────────────────────
|
|
342
|
-
const insertItem = node({
|
|
343
|
-
type: 'n8n-nodes-base.dataTable', version: 1.1,
|
|
344
|
-
config: { name: 'Insert Item', parameters: { resource: 'row', operation: 'insert', dataTableId: { __rl: true, mode: 'name', value: 'items' }, columns: { mappingMode: 'defineBelow', value: { title: expr('{{ $json.body.title }}'), completed: false }, schema: [{ id: 'title', displayName: 'title', required: false, defaultMatch: false, display: true, type: 'string', canBeUsedToMatch: true }, { id: 'completed', displayName: 'completed', required: false, defaultMatch: false, display: true, type: 'boolean', canBeUsedToMatch: false }] }, options: {} } }
|
|
345
|
-
});
|
|
346
|
-
const respondAdd = node({
|
|
347
|
-
type: 'n8n-nodes-base.respondToWebhook', version: 1.1,
|
|
348
|
-
config: { name: 'Respond Add', parameters: { respondWith: 'allEntries', options: {} } }
|
|
349
|
-
});
|
|
350
|
-
|
|
351
|
-
// ── Wire it all together ──────────────────────────────────
|
|
352
|
-
export default workflow('id', 'Item Dashboard')
|
|
353
|
-
.add(pageWebhook).to(fetchAllItems).to(aggregateItems).to(buildPage).to(respondHtml)
|
|
354
|
-
.add(getItemsWebhook).to(fetchItemsJson).to(respondItems)
|
|
355
|
-
.add(toggleWebhook).to(updateItem).to(respondToggle)
|
|
356
|
-
.add(addWebhook).to(insertItem).to(respondAdd);
|
|
357
|
-
\`\`\`
|
|
358
|
-
|
|
359
|
-
**Key takeaway:** \`JSON.stringify(htmlTemplate)\` at build time produces a perfectly escaped JS string. The Code node's jsCode is just 4 lines. No escaping problems, no matter how large the HTML.
|
|
360
|
-
|
|
361
219
|
### Google Sheets — documentId and sheetName (RLC fields)
|
|
362
220
|
|
|
363
221
|
These are Resource Locator fields that require the \`__rl\` object format:
|
|
@@ -385,65 +243,95 @@ ${node_selection_1.CONNECTION_CHANGING_PARAMETERS}
|
|
|
385
243
|
|
|
386
244
|
### Baseline Flow Control Nodes
|
|
387
245
|
${node_selection_1.BASELINE_FLOW_CONTROL}`;
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
246
|
+
}
|
|
247
|
+
const BUILDER_SPECIFIC_PATTERNS_TOOL = buildBuilderSpecificPatterns('tool');
|
|
248
|
+
const BUILDER_SPECIFIC_PATTERNS_SANDBOX = buildBuilderSpecificPatterns('sandbox');
|
|
249
|
+
const SANDBOX_WORKFLOW_RULES = `Follow these rules strictly when generating workflows:
|
|
250
|
+
|
|
251
|
+
1. **Always use raw credential objects from \`credentials(action="list")\`**
|
|
252
|
+
- Wire credentials as \`{ id, name }\` objects returned by \`credentials(action="list")\`
|
|
253
|
+
- NEVER use placeholder strings, fake API keys, or hardcoded auth values
|
|
254
|
+
- Example: \`credentials: { slackApi: { id: 'yXYBqho73obh58ZS', name: 'Slack Bot' } }\`
|
|
255
|
+
- The key (e.g. \`slackApi\`) is the credential **type** from the node type definition
|
|
256
|
+
|
|
257
|
+
2. **Trust empty item lists — don't synthesize fake items**
|
|
258
|
+
- When a query returns 0 items, downstream nodes simply don't run for that execution. For scheduled or polling triggers this is the correct "nothing to do this round" signal — the next run will execute normally when data appears.
|
|
259
|
+
- DO NOT add \`alwaysOutputData: true\` just to "keep the chain alive." Forcing an empty \`{}\` item downstream is what causes \`undefined\` reads, failed HTTP calls to \`GET undefined\`, and Code-node crashes on missing fields.
|
|
260
|
+
- DO NOT add an IF gate before a loop to check "has items?" — loops (\`splitInBatches\`, per-item nodes, \`filter\`) already no-op on empty input. The gate is redundant and adds a failure surface.
|
|
261
|
+
- \`alwaysOutputData: true\` is only correct when you specifically need a downstream branch to run on the "empty" case — e.g. a dedicated "no matches found" notification path. In that case, pair it with an \`IF\` that explicitly checks for the empty case and routes accordingly. Never use it as a default.
|
|
262
|
+
- To drop invalid items mid-pipeline, use a \`filter\` node. A \`filter\` that rejects everything emits 0 items and the chain correctly stops — no \`IF\` + \`splitInBatches\` composition needed.
|
|
263
|
+
|
|
264
|
+
3. **Use \`executeOnce: true\` for single-execution nodes**
|
|
265
|
+
- When a node receives N items but should only execute once (not N times), set \`executeOnce: true\`
|
|
266
|
+
- Common cases: sending a summary notification, generating a report, calling an API that doesn't need per-item execution
|
|
267
|
+
- Example: \`config: { ..., executeOnce: true }\`
|
|
268
|
+
|
|
269
|
+
4. **Pick the right control-flow primitive**
|
|
270
|
+
- **Per-item loop with side effects (fetch, embed, write)** → \`splitInBatches\` with \`batchSize: 1\` feeding the per-item work, loop back via \`nextBatch\`. No \`IF\` gate before it.
|
|
271
|
+
- **Drop items that don't match a predicate** → \`filter\`. It emits 0 items when nothing matches, and the chain stops cleanly.
|
|
272
|
+
- **Two mutually exclusive paths that both do real work** → \`IF\` (\`onTrue\` / \`onFalse\`).
|
|
273
|
+
- **Many mutually exclusive paths keyed off a value** → \`switch\` (\`onCase\`).
|
|
274
|
+
- Nested control flow is supported: \`ifNode.onTrue(loopBuilder)\`, \`switchNode.onCase(0, loopBuilder)\`, and \`splitInBatches(sib).onEachBatch(ifElseBuilder)\` all compile and wire correctly. Use them when the semantics genuinely call for it, not as a workaround for empty-list handling.`;
|
|
275
|
+
function composeSdkRulesAndPatterns(mode) {
|
|
276
|
+
const sandboxOverride = mode === 'sandbox'
|
|
277
|
+
? "> **Sandbox credential override**: The SDK pattern examples below use `newCredential('X')`. " +
|
|
278
|
+
"In sandbox mode, replace every `newCredential('X')` with the raw `{ id, name }` object from " +
|
|
279
|
+
'`credentials(action="list")`. `newCredential()` serializes to `undefined` in sandbox and will ' +
|
|
280
|
+
'silently drop credentials from the saved workflow.'
|
|
281
|
+
: null;
|
|
282
|
+
return [
|
|
283
|
+
SDK_CODE_RULES,
|
|
284
|
+
mode === 'sandbox' ? SANDBOX_WORKFLOW_RULES : sdk_reference_1.WORKFLOW_RULES,
|
|
285
|
+
...(sandboxOverride ? [sandboxOverride] : []),
|
|
286
|
+
'## SDK Patterns Reference\n\n' + sdk_reference_1.WORKFLOW_SDK_PATTERNS,
|
|
287
|
+
'## Expression Reference\n\n' + sdk_reference_1.EXPRESSION_REFERENCE,
|
|
288
|
+
'## Additional Functions\n\n' + sdk_reference_1.ADDITIONAL_FUNCTIONS,
|
|
289
|
+
'## Node-Specific Configuration Guides',
|
|
290
|
+
parameter_guides_1.IF_NODE_GUIDE.content,
|
|
291
|
+
parameter_guides_1.SWITCH_NODE_GUIDE.content,
|
|
292
|
+
parameter_guides_1.SET_NODE_GUIDE.content,
|
|
293
|
+
parameter_guides_1.HTTP_REQUEST_GUIDE.content,
|
|
294
|
+
parameter_guides_1.TOOL_NODES_GUIDE.content,
|
|
295
|
+
parameter_guides_1.EMBEDDING_NODES_GUIDE.content,
|
|
296
|
+
parameter_guides_1.RESOURCE_LOCATOR_GUIDE.content,
|
|
297
|
+
mode === 'sandbox' ? BUILDER_SPECIFIC_PATTERNS_SANDBOX : BUILDER_SPECIFIC_PATTERNS_TOOL,
|
|
298
|
+
].join('\n\n');
|
|
299
|
+
}
|
|
300
|
+
const SDK_RULES_AND_PATTERNS_TOOL = composeSdkRulesAndPatterns('tool');
|
|
301
|
+
const SDK_RULES_AND_PATTERNS_SANDBOX = composeSdkRulesAndPatterns('sandbox');
|
|
404
302
|
exports.BUILDER_AGENT_PROMPT = `You are an expert n8n workflow builder. You generate complete, valid TypeScript code using the @n8n/workflow-sdk.
|
|
405
303
|
|
|
406
|
-
|
|
407
|
-
- Your text output is visible to the user. Be concise but natural.
|
|
408
|
-
- Do NOT narrate your process ("I'll build this step by step", "Let me start by"). Just do the work.
|
|
409
|
-
- No emojis, no filler phrases, no markdown headers in your text output.
|
|
410
|
-
- When conversation context is provided, use it to continue naturally — do not repeat information the user already knows.
|
|
411
|
-
- Only output text for: errors that need attention, or a brief natural completion message.
|
|
304
|
+
${BUILDER_OUTPUT_DISCIPLINE}
|
|
412
305
|
|
|
413
306
|
## Repair Strategy
|
|
414
307
|
When called with failure details for an existing workflow, start from the pre-loaded code — do not re-discover node types already present.
|
|
415
308
|
|
|
416
309
|
## Escalation
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
310
|
+
${shared_prompts_1.ASK_USER_FALLBACK}
|
|
311
|
+
|
|
312
|
+
${shared_prompts_1.PLACEHOLDERS_RULE}
|
|
420
313
|
|
|
421
314
|
## Mandatory Process
|
|
422
315
|
1. **Research**: If the workflow fits a known category (notification, chatbot, scheduling, data_transformation, etc.), call \`nodes(action="suggested")\` first for curated recommendations. Then use \`nodes(action="search")\` for service-specific nodes (use short service names: "Gmail", "Slack", not "send email SMTP"). The results include \`discriminators\` (available resources and operations) for nodes that need them. Then call \`nodes(action="type-definition")\` with the appropriate resource/operation to get the TypeScript schema with exact parameter names and types. **Pay attention to @builderHint annotations** in search results and type definitions — they prevent common configuration mistakes.
|
|
423
316
|
2. **Build**: Write TypeScript SDK code and call \`build-workflow\`. Follow the SDK patterns below exactly.
|
|
424
317
|
3. **Fix errors**: If \`build-workflow\` returns errors, use **patch mode**: call \`build-workflow\` with \`patches\` (array of \`{old_str, new_str}\` replacements). Patches apply to your last submitted code, or auto-fetch from the saved workflow if \`workflowId\` is given. Much faster than resending full code.
|
|
425
318
|
4. **Modify existing workflows**: When updating a workflow, call \`build-workflow\` with \`workflowId\` + \`patches\`. The tool fetches the current code and applies your patches. Use \`workflows(action="get-as-code")\` first to see the current code if you need to identify what to replace.
|
|
426
|
-
|
|
319
|
+
5. **Done**: When \`build-workflow\` succeeds, output a brief, natural completion message.
|
|
427
320
|
|
|
428
|
-
Do NOT produce visible output until step
|
|
321
|
+
Do NOT produce visible output until step 5. All reasoning happens internally.
|
|
429
322
|
|
|
430
|
-
## Credential Rules
|
|
323
|
+
## Credential Rules (tool mode)
|
|
431
324
|
- Always use \`newCredential('Credential Name')\` for credentials, never fake keys or placeholders.
|
|
432
|
-
- NEVER use raw credential objects like \`{ id: '...', name: '...' }
|
|
325
|
+
- NEVER use raw credential objects like \`{ id: '...', name: '...' }\` — that form is for sandbox mode only.
|
|
433
326
|
- When editing a pre-loaded workflow, the roundtripped code may have credentials as raw objects — replace them with \`newCredential()\` calls.
|
|
434
327
|
- Unresolved credentials (where the user chose mock data or no credential is available) will be automatically mocked via pinned data at submit time. Always declare \`output\` on nodes that use credentials so mock data is available. The workflow will be testable via manual/test runs but not production-ready until real credentials are added.
|
|
435
328
|
|
|
436
|
-
${
|
|
329
|
+
${SDK_RULES_AND_PATTERNS_TOOL}
|
|
437
330
|
`;
|
|
438
331
|
function createSandboxBuilderAgentPrompt(workspaceRoot) {
|
|
439
332
|
return `You are an expert n8n workflow builder working inside a sandbox with real TypeScript tooling. You write workflow code as files and use \`tsc\` for validation.
|
|
440
333
|
|
|
441
|
-
|
|
442
|
-
- Your text output is visible to the user. Be concise but natural.
|
|
443
|
-
- Do NOT narrate your process ("I'll build this step by step", "Let me start by"). Just do the work.
|
|
444
|
-
- No emojis, no filler phrases, no markdown headers in your text output.
|
|
445
|
-
- When conversation context is provided, use it to continue naturally — do not repeat information the user already knows.
|
|
446
|
-
- Only output text for: errors that need attention, or a brief natural completion message.
|
|
334
|
+
${BUILDER_OUTPUT_DISCIPLINE}
|
|
447
335
|
|
|
448
336
|
## Workspace Layout
|
|
449
337
|
|
|
@@ -598,9 +486,9 @@ Replace \`CHUNK_WORKFLOW_ID\` with the actual ID returned by \`submit-workflow\`
|
|
|
598
486
|
- **Complex workflows** (5+ nodes, multiple integrations): Decompose into chunks.
|
|
599
487
|
Build, test, and compose. Each chunk is reusable across workflows.
|
|
600
488
|
|
|
601
|
-
|
|
489
|
+
${shared_prompts_1.PLACEHOLDERS_RULE}
|
|
602
490
|
|
|
603
|
-
|
|
491
|
+
## Setup Workflows (Create Missing Resources)
|
|
604
492
|
|
|
605
493
|
When \`nodes(action="explore-resources")\` returns no results for a required resource:
|
|
606
494
|
|
|
@@ -615,9 +503,7 @@ When \`nodes(action="explore-resources")\` returns no results for a required res
|
|
|
615
503
|
When called with failure details for an existing workflow, start from the pre-loaded code — do not re-discover node types already present.
|
|
616
504
|
|
|
617
505
|
## Escalation
|
|
618
|
-
|
|
619
|
-
- Do NOT retry the same failing approach more than twice — ask the user instead.
|
|
620
|
-
- ${PLACEHOLDER_ESCALATION}
|
|
506
|
+
${shared_prompts_1.ASK_USER_FALLBACK}
|
|
621
507
|
|
|
622
508
|
## Sandbox Isolation
|
|
623
509
|
|
|
@@ -635,9 +521,9 @@ When called with failure details for an existing workflow, start from the pre-lo
|
|
|
635
521
|
- **For large HTML, use the file-based pattern.** Write HTML to \`chunks/page.html\`, then \`readFileSync\` + \`JSON.stringify\` in your SDK code. NEVER embed large HTML directly in jsCode — it will break. See the web_app_pattern section.
|
|
636
522
|
- **Em-dash and Unicode**: the sandbox executes real JS so these technically work, but prefer plain hyphens for consistency with the shared SDK rules.
|
|
637
523
|
|
|
638
|
-
## Credentials
|
|
524
|
+
## Credentials (sandbox mode)
|
|
639
525
|
|
|
640
|
-
Call \`credentials(action="list")\` early. Each credential has an \`id\`, \`name\`, and \`type\`. Wire them into nodes like this:
|
|
526
|
+
Sandbox mode uses **raw credential objects** (not \`newCredential()\`). Call \`credentials(action="list")\` early. Each credential has an \`id\`, \`name\`, and \`type\`. Wire them into nodes like this:
|
|
641
527
|
|
|
642
528
|
\`\`\`typescript
|
|
643
529
|
credentials: {
|
|
@@ -649,6 +535,8 @@ The key (\`openWeatherMapApi\`) is the credential **type** from the node type de
|
|
|
649
535
|
|
|
650
536
|
If the required credential type is not in \`credentials(action="list")\` results, call \`credentials(action="search-types")\` with the service name (e.g. "linear", "notion") to discover available dedicated credential types. Always prefer dedicated types over generic auth (\`httpHeaderAuth\`, \`httpBearerAuth\`, etc.). When generic auth is truly needed (no dedicated type exists), prefer \`httpBearerAuth\` over \`httpHeaderAuth\`.
|
|
651
537
|
|
|
538
|
+
The credential-selection guidance above applies to outbound service calls. For inbound trigger nodes such as Webhook, Form Trigger, Chat Trigger, and MCP Trigger, keep authentication at its default \`none\` unless the user explicitly asks to authenticate inbound traffic.
|
|
539
|
+
|
|
652
540
|
## Data Tables
|
|
653
541
|
|
|
654
542
|
n8n normalizes column names to snake_case (e.g., \`dayName\` → \`day_name\`). Always call \`data-tables(action="schema")\` before using a data table in workflow code to get the real column names.
|
|
@@ -683,8 +571,10 @@ n8n normalizes column names to snake_case (e.g., \`dayName\` → \`day_name\`).
|
|
|
683
571
|
|
|
684
572
|
4. **Resolve real resource IDs**: Check the node schemas from step 3 for parameters with \`searchListMethod\` or \`loadOptionsMethod\`. For EACH one, call \`nodes(action="explore-resources")\` with the node type, method name, and the matching credential from step 1 to discover real resource IDs.
|
|
685
573
|
- **This is mandatory for: calendars, spreadsheets, channels, folders, models, databases, and any other list-based parameter.** Do NOT assume values like "primary", "default", or "General" — always look up the real ID.
|
|
574
|
+
- **LLM models in particular** (OpenAI, Anthropic, Groq, etc.): always call \`explore-resources\` with the node's \`@searchListMethod\` when a credential for that provider is attached. The live list reflects what the credential can actually access — free/cheap tiers are often limited (e.g. an OpenAI free-tier key may only return \`gpt-5-mini\`). Picking a model ID that the credential can't access produces a broken workflow. The list is sorted newest-first; use the \`@builderHint\` as selection guidance (e.g. "prefer the GPT-5.4 family") over the live results, not as a hard-coded pick.
|
|
686
575
|
- Example: Google Calendar's \`calendar\` parameter uses \`searchListMethod: getCalendars\`. Call \`nodes(action="explore-resources")\` with \`methodName: "getCalendars"\` to get the actual calendar ID (e.g., "user@example.com"), not "primary".
|
|
687
576
|
- **Never use \`placeholder()\` or fake IDs for discoverable resources.** Create them via a setup workflow instead (see "Setup Workflows" section). For user-provided values, follow the placeholder rules in "SDK Code Rules".
|
|
577
|
+
- **If \`explore-resources\` returns more than one match and the user did not name a specific one, use \`placeholder('Select <resource>')\` for that parameter** (e.g. \`placeholder('Select a calendar')\`, \`placeholder('Select a Slack channel')\`). Picking one silently is a guess; the setup wizard surfaces placeholders so the user can choose after the build. Only pick a single match without prompting.
|
|
688
578
|
- If the resource can't be created via n8n (e.g., Slack channels), explain clearly in your summary what the user needs to set up.
|
|
689
579
|
|
|
690
580
|
5. **Write workflow code** to \`${workspaceRoot}/src/workflow.ts\`.
|
|
@@ -722,13 +612,21 @@ Follow the **Compositional Workflow Pattern** above. The process becomes:
|
|
|
722
612
|
Do NOT produce visible output until the final step. All reasoning happens internally.
|
|
723
613
|
|
|
724
614
|
## Modifying Existing Workflows
|
|
725
|
-
When modifying an existing workflow, the current code is **already pre-loaded** into \`${workspaceRoot}/src/workflow.ts\` with SDK imports.
|
|
726
|
-
|
|
615
|
+
When modifying an existing workflow, the current code is **already pre-loaded** into \`${workspaceRoot}/src/workflow.ts\` with SDK imports.
|
|
616
|
+
|
|
617
|
+
**Pre-flight check before any edit**: If the change introduces a node type not already in the file, or touches parameter values you haven't just looked up (model IDs, RLC values, enum selections, credential types, versions, etc.), call \`nodes(action="type-definition")\` first. Read \`@builderHint\`, \`@default\`, \`@searchListMethod\`, and \`@loadOptionsMethod\` from the output.
|
|
618
|
+
|
|
619
|
+
**Live credential-backed lookups are the source of truth for RLC/list parameters.** When a node exposes \`@searchListMethod\` or \`@loadOptionsMethod\` and a credential for its type is attached, call \`nodes(action="explore-resources")\` to query what the credential can actually access — don't rely on \`@default\` or memory. Treat \`@builderHint\` as *selection guidance over the live list* ("prefer the GPT-5.4 family", "prefer the most recent Sonnet") rather than as the source of the value itself. When no credential is attached, fall back to \`@default\`. If the hint and \`@default\` disagree on the fallback, prefer the hint — it's curated more actively.
|
|
620
|
+
|
|
621
|
+
Do not guess method names for \`explore-resources\`, and do not fill parameter values in from memory, even when the node or parameter feels familiar. This applies to swaps (Anthropic → OpenAI), model changes, trigger changes, and any parameter whose allowed values are unclear.
|
|
622
|
+
|
|
623
|
+
Steps:
|
|
624
|
+
- Read the current code with \`read_file\`
|
|
727
625
|
- Edit using \`edit_file\` for targeted changes or \`write_file\` for full rewrites (always use absolute paths)
|
|
728
626
|
- Run tsc → submit-workflow with the \`workflowId\`
|
|
729
627
|
- Do NOT call \`workflows(action="get-as-code")\` — the file is already populated
|
|
730
628
|
|
|
731
|
-
${
|
|
629
|
+
${SDK_RULES_AND_PATTERNS_SANDBOX}
|
|
732
630
|
`;
|
|
733
631
|
}
|
|
734
632
|
//# sourceMappingURL=build-workflow-agent.prompt.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-workflow-agent.prompt.js","sourceRoot":"","sources":["../../../src/tools/orchestration/build-workflow-agent.prompt.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"build-workflow-agent.prompt.js","sourceRoot":"","sources":["../../../src/tools/orchestration/build-workflow-agent.prompt.ts"],"names":[],"mappings":";;;AAgYA,0EA4SC;AApqBD,+FAQkE;AAClE,6EAIkD;AAClD,2EAKiD;AAEjD,+DAAkF;AAIlF,MAAM,yBAAyB,GAAG;;;;;;;;;;;;;;;;;;0GAkBwE,CAAC;AAI3G,MAAM,cAAc,GAAG;;;;;;;;;;qFAU8D,CAAC;AAKtF,SAAS,4BAA4B,CAAC,IAAwB;IAC7D,MAAM,iBAAiB,GACtB,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,0CAA0C,CAAC,CAAC,CAAC,yBAAyB,CAAC;IAC7F,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCA+BwB,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAuK/C,iCAAgB;;;EAGhB,+CAA8B;;;EAG9B,sCAAqB,EAAE,CAAC;AAC1B,CAAC;AAED,MAAM,8BAA8B,GAAG,4BAA4B,CAAC,MAAM,CAAC,CAAC;AAC5E,MAAM,iCAAiC,GAAG,4BAA4B,CAAC,SAAS,CAAC,CAAC;AAOlF,MAAM,sBAAsB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;qSAyBsQ,CAAC;AAEtS,SAAS,0BAA0B,CAAC,IAAwB;IAM3D,MAAM,eAAe,GACpB,IAAI,KAAK,SAAS;QACjB,CAAC,CAAC,8FAA8F;YAC/F,8FAA8F;YAC9F,gGAAgG;YAChG,oDAAoD;QACrD,CAAC,CAAC,IAAI,CAAC;IACT,OAAO;QACN,cAAc;QACd,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,8BAAc;QAC5D,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7C,+BAA+B,GAAG,qCAAqB;QACvD,6BAA6B,GAAG,oCAAoB;QACpD,6BAA6B,GAAG,oCAAoB;QACpD,uCAAuC;QACvC,gCAAa,CAAC,OAAO;QACrB,oCAAiB,CAAC,OAAO;QACzB,iCAAc,CAAC,OAAO;QACtB,qCAAkB,CAAC,OAAO;QAC1B,mCAAgB,CAAC,OAAO;QACxB,wCAAqB,CAAC,OAAO;QAC7B,yCAAsB,CAAC,OAAO;QAC9B,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,iCAAiC,CAAC,CAAC,CAAC,8BAA8B;KACvF,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAChB,CAAC;AAED,MAAM,2BAA2B,GAAG,0BAA0B,CAAC,MAAM,CAAC,CAAC;AACvE,MAAM,8BAA8B,GAAG,0BAA0B,CAAC,SAAS,CAAC,CAAC;AAIhE,QAAA,oBAAoB,GAAG;;EAElC,yBAAyB;;;;;;EAMzB,kCAAiB;;EAEjB,kCAAiB;;;;;;;;;;;;;;;;;EAiBjB,2BAA2B;CAC5B,CAAC;AAIF,SAAgB,+BAA+B,CAAC,aAAqB;IACpE,OAAO;;EAEN,yBAAyB;;;;0BAID,aAAa,6DAA6D,aAAa;;;EAG/G,aAAa;;;;;;;;;;;;;;;;;;KAkBV,aAAa;;;;;;;;;;;;;;;KAeb,aAAa;;;;;;;;;;;;;;;;;;;;;KAqBb,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAsDb,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwChB,kCAAiB;;;;;;;;;;;;;;;;;EAiBjB,kCAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sCA4DmB,aAAa;;;;;;;;;;;;;;kCAcjB,aAAa;;;;;;;;;;;;;;;;;;;;;;;;6BAwBlB,aAAa;;;;sCAIJ,aAAa;;;;;;;yFAOsC,aAAa;;;;;;;;;;;;;;EAcpG,8BAA8B;CAC/B,CAAC;AACF,CAAC"}
|
|
@@ -1,18 +1,57 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import type {
|
|
3
|
-
import { type
|
|
2
|
+
import type { OrchestrationContext } from '../../types';
|
|
3
|
+
import { type WorkflowBuildOutcome, type WorkflowLoopState } from '../../workflow-loop';
|
|
4
|
+
import { type SubmitWorkflowAttempt, type SubmitWorkflowOutput } from '../workflows/submit-workflow.tool';
|
|
5
|
+
export declare function buildWarmBuilderFollowUp(input: {
|
|
6
|
+
task: string;
|
|
7
|
+
conversationContext?: string;
|
|
8
|
+
workflowId: string;
|
|
9
|
+
workItemId: string;
|
|
10
|
+
}): string;
|
|
4
11
|
export declare function recordSuccessfulWorkflowBuilds(tool: unknown, onWorkflowId: (workflowId: string) => void): void;
|
|
12
|
+
export declare function mergeLatestVerificationIntoOutcome(outcome: WorkflowBuildOutcome, latestOutcome: WorkflowBuildOutcome | undefined): WorkflowBuildOutcome;
|
|
13
|
+
export declare function withTerminalLoopState(outcome: WorkflowBuildOutcome, state: WorkflowLoopState | undefined): WorkflowBuildOutcome;
|
|
14
|
+
export declare function finalizeBuildResult(context: OrchestrationContext, workItemId: string, result: {
|
|
15
|
+
text: string;
|
|
16
|
+
outcome: WorkflowBuildOutcome;
|
|
17
|
+
}): Promise<{
|
|
18
|
+
text: string;
|
|
19
|
+
outcome: WorkflowBuildOutcome;
|
|
20
|
+
}>;
|
|
5
21
|
export declare function resultFromPostStreamError(input: {
|
|
6
22
|
error: unknown;
|
|
7
23
|
submitAttempts: SubmitWorkflowAttempt[];
|
|
8
24
|
mainWorkflowPath: string;
|
|
9
25
|
workItemId: string;
|
|
26
|
+
runId: string;
|
|
27
|
+
taskId: string;
|
|
28
|
+
}): {
|
|
29
|
+
text: string;
|
|
30
|
+
outcome: WorkflowBuildOutcome;
|
|
31
|
+
} | undefined;
|
|
32
|
+
export declare function resultFromLaterFailedMainSubmit(input: {
|
|
33
|
+
failedAttempt: SubmitWorkflowAttempt;
|
|
34
|
+
submitAttempts: SubmitWorkflowAttempt[];
|
|
35
|
+
mainWorkflowPath: string;
|
|
36
|
+
workItemId: string;
|
|
37
|
+
runId: string;
|
|
10
38
|
taskId: string;
|
|
11
|
-
}):
|
|
39
|
+
}): {
|
|
40
|
+
text: string;
|
|
41
|
+
outcome: WorkflowBuildOutcome;
|
|
42
|
+
} | undefined;
|
|
43
|
+
export declare function attemptFromAutoResubmit(input: {
|
|
44
|
+
latestAttempt: SubmitWorkflowAttempt | undefined;
|
|
45
|
+
resubmit: SubmitWorkflowOutput;
|
|
46
|
+
filePath: string;
|
|
47
|
+
sourceHash: string;
|
|
48
|
+
}): SubmitWorkflowAttempt | undefined;
|
|
49
|
+
export declare function shouldRecoverSavedWorkflowAfterFailedSubmit(attempt: SubmitWorkflowAttempt): boolean;
|
|
12
50
|
export interface StartBuildWorkflowAgentInput {
|
|
13
51
|
task: string;
|
|
14
52
|
workflowId?: string;
|
|
15
53
|
conversationContext?: string;
|
|
54
|
+
workItemId?: string;
|
|
16
55
|
taskId?: string;
|
|
17
56
|
agentId?: string;
|
|
18
57
|
plannedTaskId?: string;
|
|
@@ -27,13 +66,22 @@ export declare const buildWorkflowAgentInputSchema: z.ZodObject<{
|
|
|
27
66
|
task: z.ZodString;
|
|
28
67
|
workflowId: z.ZodOptional<z.ZodString>;
|
|
29
68
|
conversationContext: z.ZodOptional<z.ZodString>;
|
|
69
|
+
workItemId: z.ZodOptional<z.ZodString>;
|
|
70
|
+
bypassPlan: z.ZodOptional<z.ZodBoolean>;
|
|
71
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
30
72
|
}, "strip", z.ZodTypeAny, {
|
|
31
73
|
task: string;
|
|
32
74
|
workflowId?: string | undefined;
|
|
75
|
+
reason?: string | undefined;
|
|
76
|
+
workItemId?: string | undefined;
|
|
33
77
|
conversationContext?: string | undefined;
|
|
78
|
+
bypassPlan?: boolean | undefined;
|
|
34
79
|
}, {
|
|
35
80
|
task: string;
|
|
36
81
|
workflowId?: string | undefined;
|
|
82
|
+
reason?: string | undefined;
|
|
83
|
+
workItemId?: string | undefined;
|
|
37
84
|
conversationContext?: string | undefined;
|
|
85
|
+
bypassPlan?: boolean | undefined;
|
|
38
86
|
}>;
|
|
39
87
|
export declare function createBuildWorkflowAgentTool(context: OrchestrationContext): import("@mastra/core/tools").Tool<InferPublicSchema<T>, InferPublicSchema<T>, InferPublicSchema<T>, InferPublicSchema<T>, import("@mastra/core/tools").ToolExecutionContext<InferPublicSchema<T>, InferPublicSchema<T>, unknown>, "build-workflow-with-agent", unknown>;
|