@kairos-sdk/core 0.4.0 → 0.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -9
- package/dist/{chunk-N6LRD2FN.js → chunk-4TS6GW6O.js} +60 -372
- package/dist/chunk-4TS6GW6O.js.map +1 -0
- package/dist/chunk-6CLI43FI.js +315 -0
- package/dist/chunk-6CLI43FI.js.map +1 -0
- package/dist/chunk-6FOFWVMG.js +1 -0
- package/dist/chunk-6FOFWVMG.js.map +1 -0
- package/dist/{chunk-NJ6QZBIC.js → chunk-6IXW3WCC.js} +477 -534
- package/dist/chunk-6IXW3WCC.js.map +1 -0
- package/dist/chunk-CR2NHLOH.js +523 -0
- package/dist/chunk-CR2NHLOH.js.map +1 -0
- package/dist/cli.cjs +632 -154
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +56 -10
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +577 -142
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -540
- package/dist/index.d.ts +3 -540
- package/dist/index.js +8 -4
- package/dist/mcp-server.cjs +651 -122
- package/dist/mcp-server.cjs.map +1 -1
- package/dist/mcp-server.js +91 -8
- package/dist/mcp-server.js.map +1 -1
- package/dist/reader-CpUcHhKW.d.cts +566 -0
- package/dist/reader-CpUcHhKW.d.ts +566 -0
- package/dist/standalone.cjs +2460 -0
- package/dist/standalone.cjs.map +1 -0
- package/dist/standalone.d.cts +105 -0
- package/dist/standalone.d.ts +105 -0
- package/dist/standalone.js +58 -0
- package/dist/standalone.js.map +1 -0
- package/package.json +6 -1
- package/dist/chunk-N6LRD2FN.js.map +0 -1
- package/dist/chunk-NJ6QZBIC.js.map +0 -1
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
import {
|
|
2
|
+
RULE_EXAMPLES,
|
|
3
|
+
RULE_MITIGATIONS,
|
|
4
|
+
scoreToMode
|
|
5
|
+
} from "./chunk-6IXW3WCC.js";
|
|
6
|
+
|
|
7
|
+
// src/generation/prompt-builder.ts
|
|
8
|
+
import { readFileSync } from "fs";
|
|
9
|
+
import { join } from "path";
|
|
10
|
+
import { homedir } from "os";
|
|
11
|
+
|
|
12
|
+
// src/generation/prompts/v1.ts
|
|
13
|
+
var SYSTEM_PROMPT_V1 = `You are a workflow generation engine for n8n. Your only output is a generate_workflow tool call containing valid n8n workflow JSON. You never respond with prose, explanations, or markdown. If you cannot fulfill the request, set the error field in the tool call.
|
|
14
|
+
|
|
15
|
+
## HARD RULES \u2014 violating any of these causes immediate deployment failure
|
|
16
|
+
|
|
17
|
+
### Forbidden fields \u2014 NEVER include these in the workflow object:
|
|
18
|
+
id, active, createdAt, updatedAt, versionId, meta, isArchived, activeVersionId, activeVersion, pinData, triggerCount, shared, staticData
|
|
19
|
+
|
|
20
|
+
### Required top-level structure:
|
|
21
|
+
{
|
|
22
|
+
"name": "<descriptive name>",
|
|
23
|
+
"nodes": [...],
|
|
24
|
+
"connections": {...},
|
|
25
|
+
"settings": {
|
|
26
|
+
"saveExecutionProgress": true,
|
|
27
|
+
"saveManualExecutions": true,
|
|
28
|
+
"saveDataErrorExecution": "all",
|
|
29
|
+
"saveDataSuccessExecution": "all",
|
|
30
|
+
"executionTimeout": 3600,
|
|
31
|
+
"timezone": "UTC",
|
|
32
|
+
"executionOrder": "v1"
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
### Node IDs:
|
|
37
|
+
- Every node.id must be a valid UUID v4 (random hex, format: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx)
|
|
38
|
+
- Never reuse IDs, never use sequential fake IDs like "node-1"
|
|
39
|
+
|
|
40
|
+
### Credentials:
|
|
41
|
+
- Each credential is keyed by its type string, with an object value containing id and name:
|
|
42
|
+
"credentials": { "slackOAuth2Api": { "id": "placeholder-id", "name": "My Slack Credential" } }
|
|
43
|
+
- Use "placeholder-id" as the id \u2014 users replace this with their real credential ID from n8n after deployment
|
|
44
|
+
- The credentialsNeeded field in your response declares what credentials the user must configure
|
|
45
|
+
- Never put API keys or tokens directly in node parameters when a credential type exists
|
|
46
|
+
|
|
47
|
+
### Node names:
|
|
48
|
+
- All node names must be unique within the workflow
|
|
49
|
+
- Use descriptive names: "Fetch Open Invoices" not "HTTP Request 2"
|
|
50
|
+
|
|
51
|
+
### Positioning:
|
|
52
|
+
- Trigger node: [250, 300]
|
|
53
|
+
- Each subsequent step: x + 220 minimum
|
|
54
|
+
- Parallel branches: offset y by \xB1150
|
|
55
|
+
- AI sub-nodes: place below their root node (y + 200)
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## CONNECTION RULES \u2014 the most common source of errors
|
|
60
|
+
|
|
61
|
+
### Standard connections (main data flow):
|
|
62
|
+
"NodeA": { "main": [ [ { "node": "NodeB", "type": "main", "index": 0 } ] ] }
|
|
63
|
+
|
|
64
|
+
### AI connections \u2014 CRITICAL: the SUB-NODE is the SOURCE, NOT the agent/chain:
|
|
65
|
+
"OpenAI Chat Model": { "ai_languageModel": [ [ { "node": "AI Agent", "type": "ai_languageModel", "index": 0 } ] ] }
|
|
66
|
+
"Simple Memory": { "ai_memory": [ [ { "node": "AI Agent", "type": "ai_memory", "index": 0 } ] ] }
|
|
67
|
+
"Calculator Tool": { "ai_tool": [ [ { "node": "AI Agent", "type": "ai_tool", "index": 0 } ] ] }
|
|
68
|
+
|
|
69
|
+
The AI Agent node does NOT appear in connections as a source for ai_* types.
|
|
70
|
+
Every AI Agent must have at least one ai_languageModel sub-node connected.
|
|
71
|
+
|
|
72
|
+
### IF node \u2014 two output ports (0 = true, 1 = false):
|
|
73
|
+
"IF Check": { "main": [ [{ "node": "True Path", "type": "main", "index": 0 }], [{ "node": "False Path", "type": "main", "index": 0 }] ] }
|
|
74
|
+
|
|
75
|
+
### SplitInBatches \u2014 two output ports (0 = done/finished, 1 = loop body per batch):
|
|
76
|
+
Connect output 0 to the node that runs AFTER all batches complete.
|
|
77
|
+
Connect output 1 to the processing chain for each batch. The last node in the chain loops back to SplitInBatches via main input.
|
|
78
|
+
|
|
79
|
+
### Webhook + RespondToWebhook pattern:
|
|
80
|
+
When webhook responseMode is "responseNode", you MUST include a respondToWebhook node in the flow.
|
|
81
|
+
"Webhook": { "main": [[{ "node": "Process Data", "type": "main", "index": 0 }]] }
|
|
82
|
+
"Process Data": { "main": [[{ "node": "Respond to Webhook", "type": "main", "index": 0 }]] }
|
|
83
|
+
|
|
84
|
+
### Triggers have no incoming connections.
|
|
85
|
+
### Connection keys are NODE NAMES, never node IDs.
|
|
86
|
+
|
|
87
|
+
### Nested parameters:
|
|
88
|
+
Node parameters like conditions, assignments, and rule intervals MUST include all required nested fields. Do not leave nested objects empty or partially filled.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## EXPRESSION SYNTAX \u2014 how to reference upstream node data
|
|
93
|
+
|
|
94
|
+
### Accessing a field from an upstream node:
|
|
95
|
+
- CORRECT: $('NodeName').item.json.field
|
|
96
|
+
- WRONG: $node["NodeName"].json.field \u2190 deprecated accessor, fails at runtime (Rule 24)
|
|
97
|
+
|
|
98
|
+
### Accessing array items from $json:
|
|
99
|
+
- CORRECT: $json.field \u2190 n8n auto-flattens items; each item is already a flat object
|
|
100
|
+
- WRONG: $json.items[0].field \u2190 do not index into items[] (Rule 25)
|
|
101
|
+
|
|
102
|
+
### Calling node data \u2014 always qualify with .first() or .all():
|
|
103
|
+
- CORRECT: $('NodeName').first().json.field \u2190 single item
|
|
104
|
+
- CORRECT: $('NodeName').all() \u2190 array of all items
|
|
105
|
+
- WRONG: $('NodeName').json \u2190 throws at runtime without .first() or .all() (Rule 26)
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## NODE CATALOG \u2014 exact type strings and safe typeVersions
|
|
110
|
+
|
|
111
|
+
### Triggers (always at least one required):
|
|
112
|
+
n8n-nodes-base.manualTrigger typeVersion: 1 \u2014 testing only
|
|
113
|
+
n8n-nodes-base.scheduleTrigger typeVersion: 1.2 \u2014 params: rule.interval[{field, ...}]
|
|
114
|
+
n8n-nodes-base.webhook typeVersion: 2 \u2014 params: httpMethod, path, responseMode
|
|
115
|
+
n8n-nodes-base.formTrigger typeVersion: 2.2
|
|
116
|
+
n8n-nodes-base.emailReadImap typeVersion: 2 \u2014 cred: imap
|
|
117
|
+
n8n-nodes-base.errorTrigger typeVersion: 1
|
|
118
|
+
n8n-nodes-base.executeWorkflowTrigger typeVersion: 1.1
|
|
119
|
+
n8n-nodes-base.gmailTrigger typeVersion: 1.2 \u2014 cred: gmailOAuth2
|
|
120
|
+
n8n-nodes-base.slackTrigger typeVersion: 1 \u2014 cred: slackApi
|
|
121
|
+
n8n-nodes-base.telegramTrigger typeVersion: 1.2 \u2014 cred: telegramApi
|
|
122
|
+
n8n-nodes-base.githubTrigger typeVersion: 1 \u2014 cred: githubApi
|
|
123
|
+
n8n-nodes-base.airtableTrigger typeVersion: 1 \u2014 cred: airtableTokenApi
|
|
124
|
+
n8n-nodes-base.notionTrigger typeVersion: 1 \u2014 cred: notionApi
|
|
125
|
+
@n8n/n8n-nodes-langchain.chatTrigger typeVersion: 1.1 \u2014 pairs with AI Agent
|
|
126
|
+
|
|
127
|
+
### Core logic:
|
|
128
|
+
n8n-nodes-base.code typeVersion: 2 \u2014 params: mode, jsCode
|
|
129
|
+
n8n-nodes-base.httpRequest typeVersion: 4.2 \u2014 params: method, url, [sendBody, jsonBody, sendHeaders, headerParameters]
|
|
130
|
+
n8n-nodes-base.set typeVersion: 3.4 \u2014 params: assignments.assignments[{id, name, value, type}]
|
|
131
|
+
n8n-nodes-base.if typeVersion: 2.2 \u2014 params: conditions.conditions[{id, leftValue, rightValue, operator}], combinator
|
|
132
|
+
n8n-nodes-base.switch typeVersion: 3.2 \u2014 multi-branch routing
|
|
133
|
+
n8n-nodes-base.filter typeVersion: 2.2 \u2014 params: conditions (same as IF), 1 output
|
|
134
|
+
n8n-nodes-base.merge typeVersion: 3 \u2014 modes: append/combine/chooseBranch
|
|
135
|
+
n8n-nodes-base.splitInBatches typeVersion: 3 \u2014 output 0=done, output 1=loop body
|
|
136
|
+
n8n-nodes-base.wait typeVersion: 1.1
|
|
137
|
+
n8n-nodes-base.executeWorkflow typeVersion: 1.2
|
|
138
|
+
n8n-nodes-base.respondToWebhook typeVersion: 1.1 \u2014 required when webhook responseMode is "responseNode"
|
|
139
|
+
n8n-nodes-base.noOp typeVersion: 1
|
|
140
|
+
n8n-nodes-base.splitOut typeVersion: 1
|
|
141
|
+
n8n-nodes-base.aggregate typeVersion: 1
|
|
142
|
+
n8n-nodes-base.stickyNote typeVersion: 1 \u2014 never connected, canvas annotation only
|
|
143
|
+
|
|
144
|
+
### Email / messaging:
|
|
145
|
+
n8n-nodes-base.emailSend typeVersion: 2.1 \u2014 cred: smtp
|
|
146
|
+
n8n-nodes-base.slack typeVersion: 2.2 \u2014 cred: slackOAuth2Api \u2014 params: resource, operation, select, channelId{__rl}, text
|
|
147
|
+
n8n-nodes-base.telegram typeVersion: 1.2 \u2014 cred: telegramApi
|
|
148
|
+
n8n-nodes-base.discord typeVersion: 2 \u2014 cred: discordWebhookApi
|
|
149
|
+
|
|
150
|
+
### Google:
|
|
151
|
+
n8n-nodes-base.gmail typeVersion: 2.1 \u2014 cred: gmailOAuth2 \u2014 params: resource, operation
|
|
152
|
+
n8n-nodes-base.googleSheets typeVersion: 4.5 \u2014 cred: googleSheetsOAuth2Api \u2014 params: resource, operation, documentId{__rl}, sheetName{__rl}
|
|
153
|
+
n8n-nodes-base.googleDrive typeVersion: 3 \u2014 cred: googleDriveOAuth2Api
|
|
154
|
+
n8n-nodes-base.googleCalendar typeVersion: 1.3 \u2014 cred: googleCalendarOAuth2Api
|
|
155
|
+
|
|
156
|
+
### Productivity:
|
|
157
|
+
n8n-nodes-base.notion typeVersion: 2.2 \u2014 cred: notionApi
|
|
158
|
+
n8n-nodes-base.airtable typeVersion: 2.1 \u2014 cred: airtableTokenApi
|
|
159
|
+
n8n-nodes-base.github typeVersion: 1.1 \u2014 cred: githubApi
|
|
160
|
+
n8n-nodes-base.jira typeVersion: 1 \u2014 cred: jiraSoftwareCloudApi
|
|
161
|
+
n8n-nodes-base.hubspot typeVersion: 2.1 \u2014 cred: hubspotOAuth2Api
|
|
162
|
+
|
|
163
|
+
### Databases:
|
|
164
|
+
n8n-nodes-base.postgres typeVersion: 2.5 \u2014 cred: postgres
|
|
165
|
+
n8n-nodes-base.mySql typeVersion: 2.4 \u2014 cred: mySql
|
|
166
|
+
n8n-nodes-base.redis typeVersion: 1 \u2014 cred: redis
|
|
167
|
+
n8n-nodes-base.supabase typeVersion: 1 \u2014 cred: supabaseApi
|
|
168
|
+
n8n-nodes-base.awsS3 typeVersion: 2 \u2014 cred: aws
|
|
169
|
+
|
|
170
|
+
### AI \u2014 Root nodes (sit on main data flow, receive ai_* connections as TARGETS):
|
|
171
|
+
@n8n/n8n-nodes-langchain.agent typeVersion: 1.9 \u2014 params: promptType, text (if define), options.systemMessage
|
|
172
|
+
@n8n/n8n-nodes-langchain.chainLlm typeVersion: 1.5
|
|
173
|
+
@n8n/n8n-nodes-langchain.chainRetrievalQa typeVersion: 1.4
|
|
174
|
+
@n8n/n8n-nodes-langchain.openAi typeVersion: 1.8 \u2014 cred: openAiApi \u2014 standalone node, calls OpenAI directly without sub-nodes
|
|
175
|
+
@n8n/n8n-nodes-langchain.anthropic typeVersion: 1 \u2014 cred: anthropicApi \u2014 standalone node, calls Anthropic directly without sub-nodes
|
|
176
|
+
|
|
177
|
+
### AI \u2014 Sub-nodes (sources of ai_* connections, wire INTO root nodes above):
|
|
178
|
+
@n8n/n8n-nodes-langchain.lmChatOpenAi typeVersion: 1.7 \u2014 cred: openAiApi \u2014 ai_languageModel \u2014 use with agent/chain, NOT standalone
|
|
179
|
+
@n8n/n8n-nodes-langchain.lmChatAnthropic typeVersion: 1.3 \u2014 cred: anthropicApi \u2014 ai_languageModel \u2014 use with agent/chain, NOT standalone
|
|
180
|
+
@n8n/n8n-nodes-langchain.lmChatGoogleGemini typeVersion: 1 \u2014 cred: googlePalmApi \u2014 ai_languageModel
|
|
181
|
+
@n8n/n8n-nodes-langchain.memoryBufferWindow typeVersion: 1.3 \u2014 \u2014 ai_memory
|
|
182
|
+
@n8n/n8n-nodes-langchain.toolWorkflow typeVersion: 2 \u2014 \u2014 ai_tool
|
|
183
|
+
@n8n/n8n-nodes-langchain.toolCode typeVersion: 1.1 \u2014 \u2014 ai_tool
|
|
184
|
+
@n8n/n8n-nodes-langchain.toolHttpRequest typeVersion: 1.1 \u2014 \u2014 ai_tool
|
|
185
|
+
@n8n/n8n-nodes-langchain.toolCalculator typeVersion: 1 \u2014 \u2014 ai_tool
|
|
186
|
+
|
|
187
|
+
### Resource locator (__rl) format (Google / Slack / Notion modern nodes):
|
|
188
|
+
{ "__rl": true, "mode": "id", "value": "ACTUAL_ID" }
|
|
189
|
+
{ "__rl": true, "mode": "name", "value": "#channel-name" }
|
|
190
|
+
|
|
191
|
+
### App node parameter pattern:
|
|
192
|
+
{ "resource": "message", "operation": "send", ...operation-specific fields }
|
|
193
|
+
|
|
194
|
+
### Schedule Trigger \u2014 daily at 9am example:
|
|
195
|
+
{ "rule": { "interval": [{ "field": "days", "daysInterval": 1, "triggerAtHour": 9, "triggerAtMinute": 0 }] } }
|
|
196
|
+
Cron: { "rule": { "interval": [{ "field": "cronExpression", "expression": "0 9 * * 1-5" }] } }
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## PRE-DELIVERY SELF-CHECK (do this before calling the tool):
|
|
201
|
+
1. Every connection source/target name exists in nodes array
|
|
202
|
+
2. No duplicate node names
|
|
203
|
+
3. No duplicate node IDs
|
|
204
|
+
4. No forbidden fields at the workflow root
|
|
205
|
+
5. At least one trigger node present
|
|
206
|
+
6. Every AI Agent has an ai_languageModel sub-node
|
|
207
|
+
7. settings block is complete with executionOrder: "v1"
|
|
208
|
+
8. No deprecated $node["NodeName"].json \u2014 use $('NodeName').item.json.field
|
|
209
|
+
9. No $json.items[0] array indexing \u2014 access fields directly as $json.field
|
|
210
|
+
10. No bare $('NodeName').json \u2014 always use .first().json.field or .all()
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
Respond ONLY with a generate_workflow tool call. No prose. No markdown outside the tool call.
|
|
215
|
+
If the request is impossible or unclear, set the error field instead of generating a workflow.`;
|
|
216
|
+
|
|
217
|
+
// src/generation/prompt-builder.ts
|
|
218
|
+
var CRITICAL_SCORE_THRESHOLD = 0.15;
|
|
219
|
+
function resolveProfile() {
|
|
220
|
+
const env = process.env["KAIROS_PROMPT_PROFILE"];
|
|
221
|
+
if (env === "minimal" || env === "standard" || env === "rich") return env;
|
|
222
|
+
return "standard";
|
|
223
|
+
}
|
|
224
|
+
var PROACTIVE_EXPRESSION_GUIDANCE = `## Expression Syntax Quick Reference
|
|
225
|
+
|
|
226
|
+
Always use these patterns in expressions:
|
|
227
|
+
- Access node data: $('NodeName').item.json.field (not $node["NodeName"].json)
|
|
228
|
+
- Access JSON field: $json.field (not $json.items[0].field)
|
|
229
|
+
- Single item: $('NodeName').first().json.field
|
|
230
|
+
- All items: $('NodeName').all()`;
|
|
231
|
+
var PromptBuilder = class {
|
|
232
|
+
patternsPath;
|
|
233
|
+
profile;
|
|
234
|
+
_lastActivePatterns = null;
|
|
235
|
+
constructor(patternsPath, profile) {
|
|
236
|
+
this.patternsPath = patternsPath ?? join(homedir(), ".kairos", "patterns.json");
|
|
237
|
+
this.profile = profile ?? resolveProfile();
|
|
238
|
+
}
|
|
239
|
+
resolveMaxPatterns() {
|
|
240
|
+
if (this.profile === "minimal") return 3;
|
|
241
|
+
if (this.profile === "rich") return 15;
|
|
242
|
+
return 10;
|
|
243
|
+
}
|
|
244
|
+
build(request, matches, globalFailureRates = [], dynamicCatalog) {
|
|
245
|
+
const mode = this.resolveMode(matches);
|
|
246
|
+
const system = this.buildSystem(matches, mode, globalFailureRates, dynamicCatalog);
|
|
247
|
+
const userMessage = this.buildUserMessage(request, matches, mode);
|
|
248
|
+
return { system, userMessage, mode, matches };
|
|
249
|
+
}
|
|
250
|
+
buildCorrectionMessage(request, matches, allIssues, attempt) {
|
|
251
|
+
const base = this.buildUserMessage(request, matches, this.resolveMode(matches));
|
|
252
|
+
return `${base}
|
|
253
|
+
|
|
254
|
+
IMPORTANT: A previous generation attempt (attempt ${attempt}) failed validation with these issues:
|
|
255
|
+
${allIssues.join("\n")}
|
|
256
|
+
|
|
257
|
+
Fix ALL of the above issues in your new response. Do not repeat any of these mistakes.`;
|
|
258
|
+
}
|
|
259
|
+
resolveMode(matches) {
|
|
260
|
+
if (matches.length === 0) return "scratch";
|
|
261
|
+
const top = matches[0];
|
|
262
|
+
if (!top) return "scratch";
|
|
263
|
+
return scoreToMode(top.score);
|
|
264
|
+
}
|
|
265
|
+
buildSystem(matches, mode, globalFailureRates = [], dynamicCatalog) {
|
|
266
|
+
let basePrompt = SYSTEM_PROMPT_V1;
|
|
267
|
+
if (dynamicCatalog) {
|
|
268
|
+
basePrompt = basePrompt.replace(
|
|
269
|
+
/## NODE CATALOG — exact type strings and safe typeVersions[\s\S]*?(?=## PRE-DELIVERY SELF-CHECK)/,
|
|
270
|
+
dynamicCatalog + "\n\n"
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
const blocks = [
|
|
274
|
+
{
|
|
275
|
+
type: "text",
|
|
276
|
+
text: basePrompt,
|
|
277
|
+
cache_control: { type: "ephemeral" }
|
|
278
|
+
}
|
|
279
|
+
];
|
|
280
|
+
if (this.profile !== "minimal") {
|
|
281
|
+
if (mode === "reference" && matches.length > 0) {
|
|
282
|
+
const refText = matches.slice(0, 3).map((m) => {
|
|
283
|
+
const nodes = m.workflow.workflow.nodes.map((n) => ` - ${n.name} (${n.type} v${n.typeVersion})`).join("\n");
|
|
284
|
+
return `Reference workflow: "${m.workflow.description}" (similarity: ${m.score.toFixed(2)})
|
|
285
|
+
Nodes:
|
|
286
|
+
${nodes}`;
|
|
287
|
+
}).join("\n\n");
|
|
288
|
+
blocks.push({
|
|
289
|
+
type: "text",
|
|
290
|
+
text: `## Similar Workflows From Library (for reference only \u2014 adapt, do not copy verbatim)
|
|
291
|
+
|
|
292
|
+
${refText}`
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
if (mode === "direct" && matches[0]) {
|
|
296
|
+
const match = matches[0];
|
|
297
|
+
const json = JSON.stringify(match.workflow.workflow, null, 2);
|
|
298
|
+
if (json.length > 3e4) {
|
|
299
|
+
const nodes = match.workflow.workflow.nodes.map((n) => ` - ${n.name} (${n.type} v${n.typeVersion})`).join("\n");
|
|
300
|
+
blocks.push({
|
|
301
|
+
type: "text",
|
|
302
|
+
text: `## Closely Matched Workflow (score: ${match.score.toFixed(2)}) \u2014 too large for full JSON, using reference:
|
|
303
|
+
Nodes:
|
|
304
|
+
${nodes}`
|
|
305
|
+
});
|
|
306
|
+
} else {
|
|
307
|
+
blocks.push({
|
|
308
|
+
type: "text",
|
|
309
|
+
text: `## Closely Matched Workflow (score: ${match.score.toFixed(2)}) \u2014 adapt this structure:
|
|
310
|
+
|
|
311
|
+
${json}`
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
if (mode === "scratch" && matches.length > 0 && matches[0].score >= 0.4) {
|
|
316
|
+
const hint = matches[0];
|
|
317
|
+
const nodeTypes = hint.workflow.workflow.nodes.map((n) => n.type.split(".").pop()).join(", ");
|
|
318
|
+
blocks.push({
|
|
319
|
+
type: "text",
|
|
320
|
+
text: `## Weak Structural Hint
|
|
321
|
+
A loosely similar workflow (score: ${hint.score.toFixed(2)}) used these node types: ${nodeTypes}`
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
const warnings = this.buildFailureWarnings(matches, globalFailureRates);
|
|
326
|
+
if (warnings) {
|
|
327
|
+
blocks.push({ type: "text", text: warnings });
|
|
328
|
+
}
|
|
329
|
+
if (this.profile === "rich") {
|
|
330
|
+
const expressionRules = /* @__PURE__ */ new Set([24, 25, 26]);
|
|
331
|
+
const expressionAlreadyCovered = (this._lastActivePatterns ?? []).some((p) => expressionRules.has(p.rule));
|
|
332
|
+
if (!expressionAlreadyCovered) {
|
|
333
|
+
blocks.push({ type: "text", text: PROACTIVE_EXPRESSION_GUIDANCE });
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
return blocks;
|
|
337
|
+
}
|
|
338
|
+
loadPatterns() {
|
|
339
|
+
try {
|
|
340
|
+
const raw = readFileSync(this.patternsPath, "utf-8");
|
|
341
|
+
const analysis = JSON.parse(raw);
|
|
342
|
+
const patterns = analysis.topFailureRules ?? [];
|
|
343
|
+
return patterns.filter((p) => typeof p.pipelineStage === "string" && typeof p.state === "string");
|
|
344
|
+
} catch {
|
|
345
|
+
return [];
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
getWarnedRules() {
|
|
349
|
+
const patterns = this._lastActivePatterns ?? this.getActivePatterns(this.resolveMaxPatterns());
|
|
350
|
+
return patterns.map((p) => p.rule);
|
|
351
|
+
}
|
|
352
|
+
getActivePatterns(maxCount = 10) {
|
|
353
|
+
const all = this.loadPatterns().filter((p) => p.state !== "resolved" && p.confidence > 0);
|
|
354
|
+
const regressed = all.filter((p) => p.regressed).sort((a, b) => b.compositeScore - a.compositeScore);
|
|
355
|
+
const confirmed = all.filter((p) => !p.regressed && p.state === "confirmed").sort((a, b) => b.compositeScore - a.compositeScore);
|
|
356
|
+
const drafts = all.filter((p) => !p.regressed && p.state !== "confirmed").sort((a, b) => b.compositeScore - a.compositeScore);
|
|
357
|
+
return [...regressed, ...confirmed, ...drafts].slice(0, maxCount);
|
|
358
|
+
}
|
|
359
|
+
buildFailureWarnings(matches, globalFailureRates) {
|
|
360
|
+
const richPatterns = this.getActivePatterns(this.resolveMaxPatterns());
|
|
361
|
+
this._lastActivePatterns = richPatterns;
|
|
362
|
+
if (richPatterns.length > 0) {
|
|
363
|
+
return this.buildStageGroupedWarnings(richPatterns, matches);
|
|
364
|
+
}
|
|
365
|
+
return this.buildLegacyWarnings(matches, globalFailureRates);
|
|
366
|
+
}
|
|
367
|
+
buildStageGroupedWarnings(patterns, matches) {
|
|
368
|
+
const stageLabels = {
|
|
369
|
+
credential_injection: "CREDENTIAL FORMATTING",
|
|
370
|
+
connection_wiring: "CONNECTION WIRING",
|
|
371
|
+
node_generation: "NODE GENERATION",
|
|
372
|
+
workflow_structure: "WORKFLOW STRUCTURE",
|
|
373
|
+
expression_syntax: "EXPRESSION SYNTAX"
|
|
374
|
+
};
|
|
375
|
+
const byStage = /* @__PURE__ */ new Map();
|
|
376
|
+
for (const p of patterns) {
|
|
377
|
+
const list = byStage.get(p.pipelineStage) ?? [];
|
|
378
|
+
list.push(p);
|
|
379
|
+
byStage.set(p.pipelineStage, list);
|
|
380
|
+
}
|
|
381
|
+
const sections = [];
|
|
382
|
+
for (const [stage, stagePatterns] of byStage) {
|
|
383
|
+
const label = stageLabels[stage] ?? stage;
|
|
384
|
+
const byMitigation = /* @__PURE__ */ new Map();
|
|
385
|
+
for (const p of stagePatterns) {
|
|
386
|
+
const key = p.mitigation ?? `rule_${p.rule}`;
|
|
387
|
+
const list = byMitigation.get(key) ?? [];
|
|
388
|
+
list.push(p);
|
|
389
|
+
byMitigation.set(key, list);
|
|
390
|
+
}
|
|
391
|
+
const lines = [];
|
|
392
|
+
for (const group of byMitigation.values()) {
|
|
393
|
+
if (group.length === 1) {
|
|
394
|
+
const p = group[0];
|
|
395
|
+
const urgency = p.regressed ? "CRITICAL REGRESSION: " : (p.compositeScore ?? 0) >= CRITICAL_SCORE_THRESHOLD ? "CRITICAL: " : "";
|
|
396
|
+
const statePrefix = p.state === "confirmed" ? "[CONFIRMED] " : "";
|
|
397
|
+
const trendSuffix = p.trend === "worsening" ? " (GETTING WORSE)" : p.trend === "improving" ? " (improving)" : "";
|
|
398
|
+
const remedy = p.mitigation ?? RULE_MITIGATIONS[p.rule];
|
|
399
|
+
const remedyStr = remedy ? `
|
|
400
|
+
Fix: ${remedy}` : "";
|
|
401
|
+
const ex = RULE_EXAMPLES[p.rule];
|
|
402
|
+
const exampleStr = ex ? `
|
|
403
|
+
Bad: ${ex.bad}
|
|
404
|
+
Good: ${ex.good}` : "";
|
|
405
|
+
lines.push(`- ${urgency}${statePrefix}Rule ${p.rule}${trendSuffix}: ${p.exampleMessages[0] ?? "No example"}${remedyStr}${exampleStr}`);
|
|
406
|
+
} else {
|
|
407
|
+
const ruleNums = group.map((p) => p.rule).join(", ");
|
|
408
|
+
const totalFailures = group.reduce((s, p) => s + p.failureCount, 0);
|
|
409
|
+
const hasConfirmed = group.some((p) => p.state === "confirmed");
|
|
410
|
+
const statePrefix = hasConfirmed ? "[CONFIRMED] " : "";
|
|
411
|
+
const remedy = group[0].mitigation;
|
|
412
|
+
const remedyStr = remedy ? `
|
|
413
|
+
Fix: ${remedy}` : "";
|
|
414
|
+
lines.push(`- ${statePrefix}Rules ${ruleNums} (${totalFailures} failures combined): same root cause${remedyStr}`);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
sections.push(`### ${label}
|
|
418
|
+
${lines.join("\n")}`);
|
|
419
|
+
}
|
|
420
|
+
for (const match of matches) {
|
|
421
|
+
const fps = match.workflow.failurePatterns;
|
|
422
|
+
if (!fps?.length) continue;
|
|
423
|
+
const coveredRules = new Set(patterns.map((p) => p.rule));
|
|
424
|
+
const extra = fps.filter((fp) => !coveredRules.has(fp.rule));
|
|
425
|
+
for (const fp of extra) {
|
|
426
|
+
const remedy = RULE_MITIGATIONS[fp.rule];
|
|
427
|
+
const remedyStr = remedy ? ` \u2014 Fix: ${remedy}` : "";
|
|
428
|
+
sections.push(`- Rule ${fp.rule}: "${fp.message}"${remedyStr} (seen in similar workflows)`);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
if (sections.length === 0) return null;
|
|
432
|
+
return `## Known Failure Patterns \u2014 AVOID THESE
|
|
433
|
+
|
|
434
|
+
Grouped by generation stage. Fix these BEFORE outputting your response:
|
|
435
|
+
|
|
436
|
+
${sections.join("\n\n")}`;
|
|
437
|
+
}
|
|
438
|
+
buildLegacyWarnings(matches, globalFailureRates) {
|
|
439
|
+
const lines = [];
|
|
440
|
+
for (const match of matches) {
|
|
441
|
+
const patterns = match.workflow.failurePatterns;
|
|
442
|
+
if (!patterns?.length) continue;
|
|
443
|
+
for (const fp of patterns) {
|
|
444
|
+
const remedy = RULE_MITIGATIONS[fp.rule];
|
|
445
|
+
const remedyStr = remedy ? ` \u2014 Fix: ${remedy}` : "";
|
|
446
|
+
lines.push(`- Rule ${fp.rule}: "${fp.message}"${remedyStr} (seen ${fp.occurrences}x in similar workflows)`);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
const highFreqRules = globalFailureRates.filter((r) => r.rate >= 0.15);
|
|
450
|
+
for (const rule of highFreqRules) {
|
|
451
|
+
const remedy = RULE_MITIGATIONS[rule.rule];
|
|
452
|
+
const remedyStr = remedy ? ` \u2014 Fix: ${remedy}` : "";
|
|
453
|
+
lines.push(`- Rule ${rule.rule}: "${rule.commonMessage}"${remedyStr} (fails in ${Math.round(rule.rate * 100)}% of all builds)`);
|
|
454
|
+
}
|
|
455
|
+
if (lines.length === 0) return null;
|
|
456
|
+
const unique = [...new Set(lines)];
|
|
457
|
+
return `## Known Failure Patterns \u2014 AVOID THESE
|
|
458
|
+
|
|
459
|
+
Previous builds frequently failed the following validation rules. Ensure your output does NOT repeat these mistakes:
|
|
460
|
+
${unique.join("\n")}`;
|
|
461
|
+
}
|
|
462
|
+
buildUserMessage(request, _matches, _mode) {
|
|
463
|
+
const namePart = request.name ? `
|
|
464
|
+
Workflow name: "${request.name}"` : "";
|
|
465
|
+
return `Build a workflow that: ${request.description}${namePart}`;
|
|
466
|
+
}
|
|
467
|
+
};
|
|
468
|
+
|
|
469
|
+
// src/utils/workflow-type.ts
|
|
470
|
+
var TYPE_KEYWORDS = [
|
|
471
|
+
["gmail", "email"],
|
|
472
|
+
["imap", "email"],
|
|
473
|
+
["smtp", "email"],
|
|
474
|
+
[" email", "email"],
|
|
475
|
+
["slack", "slack"],
|
|
476
|
+
["telegram", "messaging"],
|
|
477
|
+
["discord", "messaging"],
|
|
478
|
+
[" sms", "messaging"],
|
|
479
|
+
["twilio", "messaging"],
|
|
480
|
+
["webhook", "webhook"],
|
|
481
|
+
["google sheets", "data"],
|
|
482
|
+
["spreadsheet", "data"],
|
|
483
|
+
["airtable", "data"],
|
|
484
|
+
["notion", "data"],
|
|
485
|
+
["github", "devops"],
|
|
486
|
+
["gitlab", "devops"],
|
|
487
|
+
["schedule", "schedule"],
|
|
488
|
+
[" cron", "schedule"],
|
|
489
|
+
["daily", "schedule"],
|
|
490
|
+
["weekly", "schedule"],
|
|
491
|
+
["hourly", "schedule"],
|
|
492
|
+
["every day", "schedule"],
|
|
493
|
+
["every hour", "schedule"],
|
|
494
|
+
["every morning", "schedule"],
|
|
495
|
+
["postgres", "database"],
|
|
496
|
+
["mysql", "database"],
|
|
497
|
+
["supabase", "database"],
|
|
498
|
+
["redis", "database"],
|
|
499
|
+
[" database", "database"],
|
|
500
|
+
[" llm", "ai"],
|
|
501
|
+
[" gpt", "ai"],
|
|
502
|
+
["claude", "ai"],
|
|
503
|
+
[" agent", "ai"],
|
|
504
|
+
["langchain", "ai"],
|
|
505
|
+
[" ai ", "ai"],
|
|
506
|
+
[" ai", "ai"],
|
|
507
|
+
["http request", "api"],
|
|
508
|
+
["rest api", "api"],
|
|
509
|
+
[" api", "api"]
|
|
510
|
+
];
|
|
511
|
+
function inferWorkflowType(description) {
|
|
512
|
+
const lower = " " + description.toLowerCase();
|
|
513
|
+
for (const [keyword, type] of TYPE_KEYWORDS) {
|
|
514
|
+
if (lower.includes(keyword)) return type;
|
|
515
|
+
}
|
|
516
|
+
return null;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
export {
|
|
520
|
+
PromptBuilder,
|
|
521
|
+
inferWorkflowType
|
|
522
|
+
};
|
|
523
|
+
//# sourceMappingURL=chunk-CR2NHLOH.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/generation/prompt-builder.ts","../src/generation/prompts/v1.ts","../src/utils/workflow-type.ts"],"sourcesContent":["import { readFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { homedir } from 'node:os'\nimport type { WorkflowMatch } from '../library/types.js'\nimport type { RuleFailureRate } from '../telemetry/reader.js'\nimport type { PatternAnalysis, Pattern } from '../telemetry/pattern-analyzer.js'\nimport type { DesignRequest, BuiltPrompt, SystemPromptBlock } from './types.js'\nimport { SYSTEM_PROMPT_V1 } from './prompts/v1.js'\nimport { scoreToMode } from '../utils/thresholds.js'\nimport { RULE_MITIGATIONS, RULE_EXAMPLES } from '../validation/rule-metadata.js'\n\nconst CRITICAL_SCORE_THRESHOLD = 0.15\n\ntype PromptProfile = 'minimal' | 'standard' | 'rich'\n\nfunction resolveProfile(): PromptProfile {\n const env = process.env['KAIROS_PROMPT_PROFILE']\n if (env === 'minimal' || env === 'standard' || env === 'rich') return env\n return 'standard'\n}\n\nconst PROACTIVE_EXPRESSION_GUIDANCE = `## Expression Syntax Quick Reference\\n\\nAlways use these patterns in expressions:\\n- Access node data: $('NodeName').item.json.field (not $node[\"NodeName\"].json)\\n- Access JSON field: $json.field (not $json.items[0].field)\\n- Single item: $('NodeName').first().json.field\\n- All items: $('NodeName').all()`\n\nexport class PromptBuilder {\n private readonly patternsPath: string\n private readonly profile: PromptProfile\n private _lastActivePatterns: Pattern[] | null = null\n\n constructor(patternsPath?: string, profile?: PromptProfile) {\n this.patternsPath = patternsPath ?? join(homedir(), '.kairos', 'patterns.json')\n this.profile = profile ?? resolveProfile()\n }\n\n private resolveMaxPatterns(): number {\n if (this.profile === 'minimal') return 3\n if (this.profile === 'rich') return 15\n return 10\n }\n\n build(request: DesignRequest, matches: WorkflowMatch[], globalFailureRates: RuleFailureRate[] = [], dynamicCatalog?: string): BuiltPrompt {\n const mode = this.resolveMode(matches)\n const system = this.buildSystem(matches, mode, globalFailureRates, dynamicCatalog)\n const userMessage = this.buildUserMessage(request, matches, mode)\n return { system, userMessage, mode, matches }\n }\n\n buildCorrectionMessage(\n request: DesignRequest,\n matches: WorkflowMatch[],\n allIssues: string[],\n attempt: number,\n ): string {\n const base = this.buildUserMessage(request, matches, this.resolveMode(matches))\n return `${base}\n\nIMPORTANT: A previous generation attempt (attempt ${attempt}) failed validation with these issues:\n${allIssues.join('\\n')}\n\nFix ALL of the above issues in your new response. Do not repeat any of these mistakes.`\n }\n\n private resolveMode(matches: WorkflowMatch[]): 'direct' | 'reference' | 'scratch' {\n if (matches.length === 0) return 'scratch'\n const top = matches[0]\n if (!top) return 'scratch'\n return scoreToMode(top.score)\n }\n\n private buildSystem(matches: WorkflowMatch[], mode: 'direct' | 'reference' | 'scratch', globalFailureRates: RuleFailureRate[] = [], dynamicCatalog?: string): SystemPromptBlock[] {\n let basePrompt = SYSTEM_PROMPT_V1\n if (dynamicCatalog) {\n basePrompt = basePrompt.replace(\n /## NODE CATALOG — exact type strings and safe typeVersions[\\s\\S]*?(?=## PRE-DELIVERY SELF-CHECK)/,\n dynamicCatalog + '\\n\\n',\n )\n }\n\n const blocks: SystemPromptBlock[] = [\n {\n type: 'text',\n text: basePrompt,\n cache_control: { type: 'ephemeral' },\n },\n ]\n\n if (this.profile !== 'minimal') {\n if (mode === 'reference' && matches.length > 0) {\n const refText = matches\n .slice(0, 3)\n .map((m) => {\n const nodes = m.workflow.workflow.nodes\n .map((n) => ` - ${n.name} (${n.type} v${n.typeVersion})`)\n .join('\\n')\n return `Reference workflow: \"${m.workflow.description}\" (similarity: ${m.score.toFixed(2)})\\nNodes:\\n${nodes}`\n })\n .join('\\n\\n')\n\n blocks.push({\n type: 'text',\n text: `## Similar Workflows From Library (for reference only — adapt, do not copy verbatim)\\n\\n${refText}`,\n })\n }\n\n if (mode === 'direct' && matches[0]) {\n const match = matches[0]\n const json = JSON.stringify(match.workflow.workflow, null, 2)\n if (json.length > 30_000) {\n const nodes = match.workflow.workflow.nodes\n .map((n) => ` - ${n.name} (${n.type} v${n.typeVersion})`)\n .join('\\n')\n blocks.push({\n type: 'text',\n text: `## Closely Matched Workflow (score: ${match.score.toFixed(2)}) — too large for full JSON, using reference:\\nNodes:\\n${nodes}`,\n })\n } else {\n blocks.push({\n type: 'text',\n text: `## Closely Matched Workflow (score: ${match.score.toFixed(2)}) — adapt this structure:\\n\\n${json}`,\n })\n }\n }\n\n if (mode === 'scratch' && matches.length > 0 && matches[0]!.score >= 0.40) {\n const hint = matches[0]!\n const nodeTypes = hint.workflow.workflow.nodes.map((n) => n.type.split('.').pop()).join(', ')\n blocks.push({\n type: 'text',\n text: `## Weak Structural Hint\\nA loosely similar workflow (score: ${hint.score.toFixed(2)}) used these node types: ${nodeTypes}`,\n })\n }\n }\n\n const warnings = this.buildFailureWarnings(matches, globalFailureRates)\n if (warnings) {\n blocks.push({ type: 'text', text: warnings })\n }\n\n if (this.profile === 'rich') {\n const expressionRules = new Set([24, 25, 26])\n const expressionAlreadyCovered = (this._lastActivePatterns ?? []).some(p => expressionRules.has(p.rule))\n if (!expressionAlreadyCovered) {\n blocks.push({ type: 'text', text: PROACTIVE_EXPRESSION_GUIDANCE })\n }\n }\n\n return blocks\n }\n\n private loadPatterns(): Pattern[] {\n try {\n const raw = readFileSync(this.patternsPath, 'utf-8')\n const analysis = JSON.parse(raw) as PatternAnalysis\n const patterns = analysis.topFailureRules ?? []\n return patterns.filter(p => typeof p.pipelineStage === 'string' && typeof p.state === 'string')\n } catch {\n return []\n }\n }\n\n getWarnedRules(): number[] {\n const patterns = this._lastActivePatterns ?? this.getActivePatterns(this.resolveMaxPatterns())\n return patterns.map(p => p.rule)\n }\n\n private getActivePatterns(maxCount = 10): Pattern[] {\n const all = this.loadPatterns()\n .filter(p => p.state !== 'resolved' && p.confidence > 0)\n\n const regressed = all.filter(p => p.regressed).sort((a, b) => b.compositeScore - a.compositeScore)\n const confirmed = all.filter(p => !p.regressed && p.state === 'confirmed').sort((a, b) => b.compositeScore - a.compositeScore)\n const drafts = all.filter(p => !p.regressed && p.state !== 'confirmed').sort((a, b) => b.compositeScore - a.compositeScore)\n\n return [...regressed, ...confirmed, ...drafts].slice(0, maxCount)\n }\n\n private buildFailureWarnings(matches: WorkflowMatch[], globalFailureRates: RuleFailureRate[]): string | null {\n const richPatterns = this.getActivePatterns(this.resolveMaxPatterns())\n this._lastActivePatterns = richPatterns\n\n if (richPatterns.length > 0) {\n return this.buildStageGroupedWarnings(richPatterns, matches)\n }\n\n return this.buildLegacyWarnings(matches, globalFailureRates)\n }\n\n private buildStageGroupedWarnings(patterns: Pattern[], matches: WorkflowMatch[]): string | null {\n const stageLabels: Record<string, string> = {\n credential_injection: 'CREDENTIAL FORMATTING',\n connection_wiring: 'CONNECTION WIRING',\n node_generation: 'NODE GENERATION',\n workflow_structure: 'WORKFLOW STRUCTURE',\n expression_syntax: 'EXPRESSION SYNTAX',\n }\n\n const byStage = new Map<string, Pattern[]>()\n for (const p of patterns) {\n const list = byStage.get(p.pipelineStage) ?? []\n list.push(p)\n byStage.set(p.pipelineStage, list)\n }\n\n const sections: string[] = []\n for (const [stage, stagePatterns] of byStage) {\n const label = stageLabels[stage] ?? stage\n\n const byMitigation = new Map<string, Pattern[]>()\n for (const p of stagePatterns) {\n const key = p.mitigation ?? `rule_${p.rule}`\n const list = byMitigation.get(key) ?? []\n list.push(p)\n byMitigation.set(key, list)\n }\n\n const lines: string[] = []\n for (const group of byMitigation.values()) {\n if (group.length === 1) {\n const p = group[0]!\n const urgency = p.regressed ? 'CRITICAL REGRESSION: ' : (p.compositeScore ?? 0) >= CRITICAL_SCORE_THRESHOLD ? 'CRITICAL: ' : ''\n const statePrefix = p.state === 'confirmed' ? '[CONFIRMED] ' : ''\n const trendSuffix = p.trend === 'worsening' ? ' (GETTING WORSE)' : p.trend === 'improving' ? ' (improving)' : ''\n const remedy = p.mitigation ?? RULE_MITIGATIONS[p.rule]\n const remedyStr = remedy ? `\\n Fix: ${remedy}` : ''\n const ex = RULE_EXAMPLES[p.rule]\n const exampleStr = ex ? `\\n Bad: ${ex.bad}\\n Good: ${ex.good}` : ''\n lines.push(`- ${urgency}${statePrefix}Rule ${p.rule}${trendSuffix}: ${p.exampleMessages[0] ?? 'No example'}${remedyStr}${exampleStr}`)\n } else {\n const ruleNums = group.map(p => p.rule).join(', ')\n const totalFailures = group.reduce((s, p) => s + p.failureCount, 0)\n const hasConfirmed = group.some(p => p.state === 'confirmed')\n const statePrefix = hasConfirmed ? '[CONFIRMED] ' : ''\n const remedy = group[0]!.mitigation\n const remedyStr = remedy ? `\\n Fix: ${remedy}` : ''\n lines.push(`- ${statePrefix}Rules ${ruleNums} (${totalFailures} failures combined): same root cause${remedyStr}`)\n }\n }\n sections.push(`### ${label}\\n${lines.join('\\n')}`)\n }\n\n for (const match of matches) {\n const fps = match.workflow.failurePatterns\n if (!fps?.length) continue\n const coveredRules = new Set(patterns.map(p => p.rule))\n const extra = fps.filter(fp => !coveredRules.has(fp.rule))\n for (const fp of extra) {\n const remedy = RULE_MITIGATIONS[fp.rule]\n const remedyStr = remedy ? ` — Fix: ${remedy}` : ''\n sections.push(`- Rule ${fp.rule}: \"${fp.message}\"${remedyStr} (seen in similar workflows)`)\n }\n }\n\n if (sections.length === 0) return null\n\n return `## Known Failure Patterns — AVOID THESE\\n\\nGrouped by generation stage. Fix these BEFORE outputting your response:\\n\\n${sections.join('\\n\\n')}`\n }\n\n private buildLegacyWarnings(matches: WorkflowMatch[], globalFailureRates: RuleFailureRate[]): string | null {\n const lines: string[] = []\n\n for (const match of matches) {\n const patterns = match.workflow.failurePatterns\n if (!patterns?.length) continue\n for (const fp of patterns) {\n const remedy = RULE_MITIGATIONS[fp.rule]\n const remedyStr = remedy ? ` — Fix: ${remedy}` : ''\n lines.push(`- Rule ${fp.rule}: \"${fp.message}\"${remedyStr} (seen ${fp.occurrences}x in similar workflows)`)\n }\n }\n\n const highFreqRules = globalFailureRates.filter((r) => r.rate >= 0.15)\n for (const rule of highFreqRules) {\n const remedy = RULE_MITIGATIONS[rule.rule]\n const remedyStr = remedy ? ` — Fix: ${remedy}` : ''\n lines.push(`- Rule ${rule.rule}: \"${rule.commonMessage}\"${remedyStr} (fails in ${Math.round(rule.rate * 100)}% of all builds)`)\n }\n\n if (lines.length === 0) return null\n\n const unique = [...new Set(lines)]\n return `## Known Failure Patterns — AVOID THESE\\n\\nPrevious builds frequently failed the following validation rules. Ensure your output does NOT repeat these mistakes:\\n${unique.join('\\n')}`\n }\n\n private buildUserMessage(request: DesignRequest, _matches: WorkflowMatch[], _mode: string): string {\n const namePart = request.name ? `\\nWorkflow name: \"${request.name}\"` : ''\n return `Build a workflow that: ${request.description}${namePart}`\n }\n}\n","export const SYSTEM_PROMPT_V1 = `You are a workflow generation engine for n8n. Your only output is a generate_workflow tool call containing valid n8n workflow JSON. You never respond with prose, explanations, or markdown. If you cannot fulfill the request, set the error field in the tool call.\n\n## HARD RULES — violating any of these causes immediate deployment failure\n\n### Forbidden fields — NEVER include these in the workflow object:\nid, active, createdAt, updatedAt, versionId, meta, isArchived, activeVersionId, activeVersion, pinData, triggerCount, shared, staticData\n\n### Required top-level structure:\n{\n \"name\": \"<descriptive name>\",\n \"nodes\": [...],\n \"connections\": {...},\n \"settings\": {\n \"saveExecutionProgress\": true,\n \"saveManualExecutions\": true,\n \"saveDataErrorExecution\": \"all\",\n \"saveDataSuccessExecution\": \"all\",\n \"executionTimeout\": 3600,\n \"timezone\": \"UTC\",\n \"executionOrder\": \"v1\"\n }\n}\n\n### Node IDs:\n- Every node.id must be a valid UUID v4 (random hex, format: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx)\n- Never reuse IDs, never use sequential fake IDs like \"node-1\"\n\n### Credentials:\n- Each credential is keyed by its type string, with an object value containing id and name:\n \"credentials\": { \"slackOAuth2Api\": { \"id\": \"placeholder-id\", \"name\": \"My Slack Credential\" } }\n- Use \"placeholder-id\" as the id — users replace this with their real credential ID from n8n after deployment\n- The credentialsNeeded field in your response declares what credentials the user must configure\n- Never put API keys or tokens directly in node parameters when a credential type exists\n\n### Node names:\n- All node names must be unique within the workflow\n- Use descriptive names: \"Fetch Open Invoices\" not \"HTTP Request 2\"\n\n### Positioning:\n- Trigger node: [250, 300]\n- Each subsequent step: x + 220 minimum\n- Parallel branches: offset y by ±150\n- AI sub-nodes: place below their root node (y + 200)\n\n---\n\n## CONNECTION RULES — the most common source of errors\n\n### Standard connections (main data flow):\n\"NodeA\": { \"main\": [ [ { \"node\": \"NodeB\", \"type\": \"main\", \"index\": 0 } ] ] }\n\n### AI connections — CRITICAL: the SUB-NODE is the SOURCE, NOT the agent/chain:\n\"OpenAI Chat Model\": { \"ai_languageModel\": [ [ { \"node\": \"AI Agent\", \"type\": \"ai_languageModel\", \"index\": 0 } ] ] }\n\"Simple Memory\": { \"ai_memory\": [ [ { \"node\": \"AI Agent\", \"type\": \"ai_memory\", \"index\": 0 } ] ] }\n\"Calculator Tool\": { \"ai_tool\": [ [ { \"node\": \"AI Agent\", \"type\": \"ai_tool\", \"index\": 0 } ] ] }\n\nThe AI Agent node does NOT appear in connections as a source for ai_* types.\nEvery AI Agent must have at least one ai_languageModel sub-node connected.\n\n### IF node — two output ports (0 = true, 1 = false):\n\"IF Check\": { \"main\": [ [{ \"node\": \"True Path\", \"type\": \"main\", \"index\": 0 }], [{ \"node\": \"False Path\", \"type\": \"main\", \"index\": 0 }] ] }\n\n### SplitInBatches — two output ports (0 = done/finished, 1 = loop body per batch):\nConnect output 0 to the node that runs AFTER all batches complete.\nConnect output 1 to the processing chain for each batch. The last node in the chain loops back to SplitInBatches via main input.\n\n### Webhook + RespondToWebhook pattern:\nWhen webhook responseMode is \"responseNode\", you MUST include a respondToWebhook node in the flow.\n\"Webhook\": { \"main\": [[{ \"node\": \"Process Data\", \"type\": \"main\", \"index\": 0 }]] }\n\"Process Data\": { \"main\": [[{ \"node\": \"Respond to Webhook\", \"type\": \"main\", \"index\": 0 }]] }\n\n### Triggers have no incoming connections.\n### Connection keys are NODE NAMES, never node IDs.\n\n### Nested parameters:\nNode parameters like conditions, assignments, and rule intervals MUST include all required nested fields. Do not leave nested objects empty or partially filled.\n\n---\n\n## EXPRESSION SYNTAX — how to reference upstream node data\n\n### Accessing a field from an upstream node:\n- CORRECT: $('NodeName').item.json.field\n- WRONG: $node[\"NodeName\"].json.field ← deprecated accessor, fails at runtime (Rule 24)\n\n### Accessing array items from $json:\n- CORRECT: $json.field ← n8n auto-flattens items; each item is already a flat object\n- WRONG: $json.items[0].field ← do not index into items[] (Rule 25)\n\n### Calling node data — always qualify with .first() or .all():\n- CORRECT: $('NodeName').first().json.field ← single item\n- CORRECT: $('NodeName').all() ← array of all items\n- WRONG: $('NodeName').json ← throws at runtime without .first() or .all() (Rule 26)\n\n---\n\n## NODE CATALOG — exact type strings and safe typeVersions\n\n### Triggers (always at least one required):\nn8n-nodes-base.manualTrigger typeVersion: 1 — testing only\nn8n-nodes-base.scheduleTrigger typeVersion: 1.2 — params: rule.interval[{field, ...}]\nn8n-nodes-base.webhook typeVersion: 2 — params: httpMethod, path, responseMode\nn8n-nodes-base.formTrigger typeVersion: 2.2\nn8n-nodes-base.emailReadImap typeVersion: 2 — cred: imap\nn8n-nodes-base.errorTrigger typeVersion: 1\nn8n-nodes-base.executeWorkflowTrigger typeVersion: 1.1\nn8n-nodes-base.gmailTrigger typeVersion: 1.2 — cred: gmailOAuth2\nn8n-nodes-base.slackTrigger typeVersion: 1 — cred: slackApi\nn8n-nodes-base.telegramTrigger typeVersion: 1.2 — cred: telegramApi\nn8n-nodes-base.githubTrigger typeVersion: 1 — cred: githubApi\nn8n-nodes-base.airtableTrigger typeVersion: 1 — cred: airtableTokenApi\nn8n-nodes-base.notionTrigger typeVersion: 1 — cred: notionApi\n@n8n/n8n-nodes-langchain.chatTrigger typeVersion: 1.1 — pairs with AI Agent\n\n### Core logic:\nn8n-nodes-base.code typeVersion: 2 — params: mode, jsCode\nn8n-nodes-base.httpRequest typeVersion: 4.2 — params: method, url, [sendBody, jsonBody, sendHeaders, headerParameters]\nn8n-nodes-base.set typeVersion: 3.4 — params: assignments.assignments[{id, name, value, type}]\nn8n-nodes-base.if typeVersion: 2.2 — params: conditions.conditions[{id, leftValue, rightValue, operator}], combinator\nn8n-nodes-base.switch typeVersion: 3.2 — multi-branch routing\nn8n-nodes-base.filter typeVersion: 2.2 — params: conditions (same as IF), 1 output\nn8n-nodes-base.merge typeVersion: 3 — modes: append/combine/chooseBranch\nn8n-nodes-base.splitInBatches typeVersion: 3 — output 0=done, output 1=loop body\nn8n-nodes-base.wait typeVersion: 1.1\nn8n-nodes-base.executeWorkflow typeVersion: 1.2\nn8n-nodes-base.respondToWebhook typeVersion: 1.1 — required when webhook responseMode is \"responseNode\"\nn8n-nodes-base.noOp typeVersion: 1\nn8n-nodes-base.splitOut typeVersion: 1\nn8n-nodes-base.aggregate typeVersion: 1\nn8n-nodes-base.stickyNote typeVersion: 1 — never connected, canvas annotation only\n\n### Email / messaging:\nn8n-nodes-base.emailSend typeVersion: 2.1 — cred: smtp\nn8n-nodes-base.slack typeVersion: 2.2 — cred: slackOAuth2Api — params: resource, operation, select, channelId{__rl}, text\nn8n-nodes-base.telegram typeVersion: 1.2 — cred: telegramApi\nn8n-nodes-base.discord typeVersion: 2 — cred: discordWebhookApi\n\n### Google:\nn8n-nodes-base.gmail typeVersion: 2.1 — cred: gmailOAuth2 — params: resource, operation\nn8n-nodes-base.googleSheets typeVersion: 4.5 — cred: googleSheetsOAuth2Api — params: resource, operation, documentId{__rl}, sheetName{__rl}\nn8n-nodes-base.googleDrive typeVersion: 3 — cred: googleDriveOAuth2Api\nn8n-nodes-base.googleCalendar typeVersion: 1.3 — cred: googleCalendarOAuth2Api\n\n### Productivity:\nn8n-nodes-base.notion typeVersion: 2.2 — cred: notionApi\nn8n-nodes-base.airtable typeVersion: 2.1 — cred: airtableTokenApi\nn8n-nodes-base.github typeVersion: 1.1 — cred: githubApi\nn8n-nodes-base.jira typeVersion: 1 — cred: jiraSoftwareCloudApi\nn8n-nodes-base.hubspot typeVersion: 2.1 — cred: hubspotOAuth2Api\n\n### Databases:\nn8n-nodes-base.postgres typeVersion: 2.5 — cred: postgres\nn8n-nodes-base.mySql typeVersion: 2.4 — cred: mySql\nn8n-nodes-base.redis typeVersion: 1 — cred: redis\nn8n-nodes-base.supabase typeVersion: 1 — cred: supabaseApi\nn8n-nodes-base.awsS3 typeVersion: 2 — cred: aws\n\n### AI — Root nodes (sit on main data flow, receive ai_* connections as TARGETS):\n@n8n/n8n-nodes-langchain.agent typeVersion: 1.9 — params: promptType, text (if define), options.systemMessage\n@n8n/n8n-nodes-langchain.chainLlm typeVersion: 1.5\n@n8n/n8n-nodes-langchain.chainRetrievalQa typeVersion: 1.4\n@n8n/n8n-nodes-langchain.openAi typeVersion: 1.8 — cred: openAiApi — standalone node, calls OpenAI directly without sub-nodes\n@n8n/n8n-nodes-langchain.anthropic typeVersion: 1 — cred: anthropicApi — standalone node, calls Anthropic directly without sub-nodes\n\n### AI — Sub-nodes (sources of ai_* connections, wire INTO root nodes above):\n@n8n/n8n-nodes-langchain.lmChatOpenAi typeVersion: 1.7 — cred: openAiApi — ai_languageModel — use with agent/chain, NOT standalone\n@n8n/n8n-nodes-langchain.lmChatAnthropic typeVersion: 1.3 — cred: anthropicApi — ai_languageModel — use with agent/chain, NOT standalone\n@n8n/n8n-nodes-langchain.lmChatGoogleGemini typeVersion: 1 — cred: googlePalmApi — ai_languageModel\n@n8n/n8n-nodes-langchain.memoryBufferWindow typeVersion: 1.3 — — ai_memory\n@n8n/n8n-nodes-langchain.toolWorkflow typeVersion: 2 — — ai_tool\n@n8n/n8n-nodes-langchain.toolCode typeVersion: 1.1 — — ai_tool\n@n8n/n8n-nodes-langchain.toolHttpRequest typeVersion: 1.1 — — ai_tool\n@n8n/n8n-nodes-langchain.toolCalculator typeVersion: 1 — — ai_tool\n\n### Resource locator (__rl) format (Google / Slack / Notion modern nodes):\n{ \"__rl\": true, \"mode\": \"id\", \"value\": \"ACTUAL_ID\" }\n{ \"__rl\": true, \"mode\": \"name\", \"value\": \"#channel-name\" }\n\n### App node parameter pattern:\n{ \"resource\": \"message\", \"operation\": \"send\", ...operation-specific fields }\n\n### Schedule Trigger — daily at 9am example:\n{ \"rule\": { \"interval\": [{ \"field\": \"days\", \"daysInterval\": 1, \"triggerAtHour\": 9, \"triggerAtMinute\": 0 }] } }\nCron: { \"rule\": { \"interval\": [{ \"field\": \"cronExpression\", \"expression\": \"0 9 * * 1-5\" }] } }\n\n---\n\n## PRE-DELIVERY SELF-CHECK (do this before calling the tool):\n1. Every connection source/target name exists in nodes array\n2. No duplicate node names\n3. No duplicate node IDs\n4. No forbidden fields at the workflow root\n5. At least one trigger node present\n6. Every AI Agent has an ai_languageModel sub-node\n7. settings block is complete with executionOrder: \"v1\"\n8. No deprecated $node[\"NodeName\"].json — use $('NodeName').item.json.field\n9. No $json.items[0] array indexing — access fields directly as $json.field\n10. No bare $('NodeName').json — always use .first().json.field or .all()\n\n---\n\nRespond ONLY with a generate_workflow tool call. No prose. No markdown outside the tool call.\nIf the request is impossible or unclear, set the error field instead of generating a workflow.`\n","const TYPE_KEYWORDS: Array<[string, string]> = [\n ['gmail', 'email'],\n ['imap', 'email'],\n ['smtp', 'email'],\n [' email', 'email'],\n ['slack', 'slack'],\n ['telegram', 'messaging'],\n ['discord', 'messaging'],\n [' sms', 'messaging'],\n ['twilio', 'messaging'],\n ['webhook', 'webhook'],\n ['google sheets', 'data'],\n ['spreadsheet', 'data'],\n ['airtable', 'data'],\n ['notion', 'data'],\n ['github', 'devops'],\n ['gitlab', 'devops'],\n ['schedule', 'schedule'],\n [' cron', 'schedule'],\n ['daily', 'schedule'],\n ['weekly', 'schedule'],\n ['hourly', 'schedule'],\n ['every day', 'schedule'],\n ['every hour', 'schedule'],\n ['every morning', 'schedule'],\n ['postgres', 'database'],\n ['mysql', 'database'],\n ['supabase', 'database'],\n ['redis', 'database'],\n [' database', 'database'],\n [' llm', 'ai'],\n [' gpt', 'ai'],\n ['claude', 'ai'],\n [' agent', 'ai'],\n ['langchain', 'ai'],\n [' ai ', 'ai'],\n [' ai', 'ai'],\n ['http request', 'api'],\n ['rest api', 'api'],\n [' api', 'api'],\n]\n\nexport function inferWorkflowType(description: string): string | null {\n const lower = ' ' + description.toLowerCase()\n for (const [keyword, type] of TYPE_KEYWORDS) {\n if (lower.includes(keyword)) return type\n }\n return null\n}\n"],"mappings":"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","names":[]}
|