@cascadeflow/n8n-nodes-cascadeflow 0.4.6 → 0.4.8
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CascadeFlow.node.d.ts","sourceRoot":"","sources":["../../../nodes/CascadeFlow/CascadeFlow.node.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,SAAS,EACT,oBAAoB,EAErB,MAAM,cAAc,CAAC;AAItB,qBAAa,WAAY,YAAW,SAAS;IAC3C,WAAW,EAAE,oBAAoB,
|
|
1
|
+
{"version":3,"file":"CascadeFlow.node.d.ts","sourceRoot":"","sources":["../../../nodes/CascadeFlow/CascadeFlow.node.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,SAAS,EACT,oBAAoB,EAErB,MAAM,cAAc,CAAC;AAItB,qBAAa,WAAY,YAAW,SAAS;IAC3C,WAAW,EAAE,oBAAoB,CAmE/B;IAEI,OAAO,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC;CAuOxE"}
|
|
@@ -10,36 +10,19 @@ class CascadeFlow {
|
|
|
10
10
|
name: 'cascadeFlow',
|
|
11
11
|
icon: 'file:cascadeflow.svg',
|
|
12
12
|
group: ['transform'],
|
|
13
|
-
version:
|
|
13
|
+
version: 3,
|
|
14
14
|
subtitle: 'AI Model Cascading',
|
|
15
15
|
description: 'Smart AI model cascading with 40-85% cost savings',
|
|
16
16
|
defaults: {
|
|
17
17
|
name: 'CascadeFlow',
|
|
18
18
|
},
|
|
19
19
|
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
|
|
20
|
-
inputs: ['main', 'main'],
|
|
21
|
-
inputNames: ['Drafter
|
|
22
|
-
outputs
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
name: 'cascadeFlowApi',
|
|
26
|
-
required: true,
|
|
27
|
-
},
|
|
28
|
-
],
|
|
20
|
+
inputs: ['main', 'main', 'main'],
|
|
21
|
+
inputNames: ['Chat/Agent Output', 'Drafter Provider', 'Verifier Provider'],
|
|
22
|
+
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
|
|
23
|
+
outputs: ['main', 'main'],
|
|
24
|
+
outputNames: ['Draft Accepted', 'Escalated to Verifier'],
|
|
29
25
|
properties: [
|
|
30
|
-
// Input message
|
|
31
|
-
{
|
|
32
|
-
displayName: 'Prompt',
|
|
33
|
-
name: 'prompt',
|
|
34
|
-
type: 'string',
|
|
35
|
-
default: '',
|
|
36
|
-
required: true,
|
|
37
|
-
typeOptions: {
|
|
38
|
-
rows: 4,
|
|
39
|
-
},
|
|
40
|
-
description: 'The message or query to send to AI models',
|
|
41
|
-
placeholder: 'What is the capital of France?',
|
|
42
|
-
},
|
|
43
26
|
// Quality Threshold
|
|
44
27
|
{
|
|
45
28
|
displayName: 'Quality Threshold',
|
|
@@ -53,18 +36,21 @@ class CascadeFlow {
|
|
|
53
36
|
},
|
|
54
37
|
description: 'Minimum quality score (0-1) to accept drafter response. Lower = more cost savings, higher = better quality.',
|
|
55
38
|
},
|
|
39
|
+
// Split Output by Path
|
|
40
|
+
{
|
|
41
|
+
displayName: 'Split Output by Path',
|
|
42
|
+
name: 'splitOutput',
|
|
43
|
+
type: 'boolean',
|
|
44
|
+
default: false,
|
|
45
|
+
description: 'Whether to split output into two connectors: one for draft-accepted responses, one for escalated responses. Enables visual flow tracking.',
|
|
46
|
+
},
|
|
56
47
|
// Output Options
|
|
57
48
|
{
|
|
58
|
-
displayName: 'Output',
|
|
49
|
+
displayName: 'Output Format',
|
|
59
50
|
name: 'output',
|
|
60
51
|
type: 'options',
|
|
61
|
-
default: '
|
|
52
|
+
default: 'contentOnly',
|
|
62
53
|
options: [
|
|
63
|
-
{
|
|
64
|
-
name: 'Full Metrics',
|
|
65
|
-
value: 'fullMetrics',
|
|
66
|
-
description: 'Return response + all cascade metrics',
|
|
67
|
-
},
|
|
68
54
|
{
|
|
69
55
|
name: 'Content Only',
|
|
70
56
|
value: 'contentOnly',
|
|
@@ -75,6 +61,11 @@ class CascadeFlow {
|
|
|
75
61
|
value: 'metricsSummary',
|
|
76
62
|
description: 'Return response + key metrics (cost, savings, model)',
|
|
77
63
|
},
|
|
64
|
+
{
|
|
65
|
+
name: 'Full Metrics',
|
|
66
|
+
value: 'fullMetrics',
|
|
67
|
+
description: 'Return response + all cascade metrics',
|
|
68
|
+
},
|
|
78
69
|
],
|
|
79
70
|
description: 'What data to return',
|
|
80
71
|
},
|
|
@@ -83,54 +74,115 @@ class CascadeFlow {
|
|
|
83
74
|
}
|
|
84
75
|
async execute() {
|
|
85
76
|
const returnData = [];
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const
|
|
89
|
-
//
|
|
90
|
-
const
|
|
91
|
-
// Helper to
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
anthropic: 'anthropicApiKey',
|
|
96
|
-
groq: 'groqApiKey',
|
|
97
|
-
together: 'togetherApiKey',
|
|
98
|
-
huggingface: 'huggingfaceApiKey',
|
|
99
|
-
};
|
|
100
|
-
const keyName = keyMap[provider];
|
|
101
|
-
if (!keyName) {
|
|
102
|
-
return '';
|
|
77
|
+
const escalatedData = [];
|
|
78
|
+
// Get data from all three inputs
|
|
79
|
+
const inputData = this.getInputData(0); // Input (prompt/query)
|
|
80
|
+
const drafterInputData = this.getInputData(1); // Drafter model
|
|
81
|
+
const verifierInputData = this.getInputData(2); // Verifier model
|
|
82
|
+
// Helper to extract model config from provider node output
|
|
83
|
+
const extractModelConfig = (providerData, inputName) => {
|
|
84
|
+
if (!providerData || providerData.length === 0) {
|
|
85
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), `No data received from ${inputName} input. Please connect a provider node (OpenAI, Anthropic, vLLM, Ollama, etc.).`);
|
|
103
86
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
87
|
+
const data = providerData[0].json;
|
|
88
|
+
// Extract model information - handle various provider formats
|
|
89
|
+
// OpenAI, Anthropic, Groq typically use 'model'
|
|
90
|
+
// Some custom providers might use 'modelName' or 'name'
|
|
91
|
+
const modelName = data.model ||
|
|
92
|
+
data.modelName ||
|
|
93
|
+
data.name ||
|
|
94
|
+
data.model_name ||
|
|
95
|
+
'gpt-4o-mini';
|
|
96
|
+
// Try to detect provider from various fields
|
|
97
|
+
let providerStr = data.provider ||
|
|
98
|
+
data.providerName ||
|
|
99
|
+
'';
|
|
100
|
+
// If no explicit provider, try to infer from model name or base_url
|
|
101
|
+
if (!providerStr) {
|
|
102
|
+
if (modelName.includes('gpt') || modelName.includes('o1') || modelName.includes('o3')) {
|
|
103
|
+
providerStr = 'openai';
|
|
104
|
+
}
|
|
105
|
+
else if (modelName.includes('claude')) {
|
|
106
|
+
providerStr = 'anthropic';
|
|
107
|
+
}
|
|
108
|
+
else if (modelName.includes('llama') || modelName.includes('mixtral') || modelName.includes('qwen')) {
|
|
109
|
+
// Check for vLLM or Ollama
|
|
110
|
+
const baseUrl = data.baseUrl || data.base_url || '';
|
|
111
|
+
if (baseUrl.includes('ollama') || baseUrl.includes('11434')) {
|
|
112
|
+
providerStr = 'ollama';
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
providerStr = 'vllm';
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
providerStr = 'openai'; // Default fallback
|
|
120
|
+
}
|
|
110
121
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
const
|
|
117
|
-
|
|
122
|
+
// Extract API configuration
|
|
123
|
+
const apiKey = data.apiKey ||
|
|
124
|
+
data.api_key ||
|
|
125
|
+
data.token ||
|
|
126
|
+
'';
|
|
127
|
+
const baseUrl = data.baseUrl ||
|
|
128
|
+
data.base_url ||
|
|
129
|
+
undefined;
|
|
130
|
+
// Cost estimation - use provided cost or estimate based on provider
|
|
131
|
+
let cost = data.cost || data.modelCost;
|
|
132
|
+
if (!cost) {
|
|
133
|
+
// Rough estimates per 1K tokens (blended input/output)
|
|
134
|
+
if (providerStr === 'anthropic') {
|
|
135
|
+
cost = modelName.includes('opus') ? 0.03 : 0.006;
|
|
136
|
+
}
|
|
137
|
+
else if (providerStr === 'openai') {
|
|
138
|
+
if (modelName.includes('o1') || modelName.includes('o3'))
|
|
139
|
+
cost = 0.03;
|
|
140
|
+
else if (modelName.includes('gpt-4'))
|
|
141
|
+
cost = 0.006;
|
|
142
|
+
else
|
|
143
|
+
cost = 0.0004;
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
cost = 0.001; // Default for local/other providers
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
const config = {
|
|
118
150
|
name: modelName,
|
|
119
151
|
provider: providerStr,
|
|
120
152
|
cost,
|
|
121
|
-
apiKey
|
|
153
|
+
apiKey,
|
|
122
154
|
};
|
|
155
|
+
// Add baseUrl if provided (for vLLM, Ollama, custom endpoints)
|
|
156
|
+
if (baseUrl) {
|
|
157
|
+
config.baseUrl = baseUrl;
|
|
158
|
+
}
|
|
159
|
+
return config;
|
|
123
160
|
};
|
|
124
|
-
// Extract model configurations from inputs
|
|
125
|
-
const drafterConfig = extractModelConfig(drafterInputData, 'Drafter');
|
|
126
|
-
const verifierConfig = extractModelConfig(verifierInputData, 'Verifier');
|
|
161
|
+
// Extract model configurations from provider inputs
|
|
162
|
+
const drafterConfig = extractModelConfig(drafterInputData, 'Drafter Model');
|
|
163
|
+
const verifierConfig = extractModelConfig(verifierInputData, 'Verifier Model');
|
|
127
164
|
const modelConfigs = [drafterConfig, verifierConfig];
|
|
128
|
-
|
|
165
|
+
// Get split output setting (same for all items)
|
|
166
|
+
const splitOutput = this.getNodeParameter('splitOutput', 0, false);
|
|
167
|
+
// Process each input item
|
|
168
|
+
for (let itemIndex = 0; itemIndex < inputData.length; itemIndex++) {
|
|
129
169
|
try {
|
|
130
170
|
// Get parameters
|
|
131
|
-
const prompt = this.getNodeParameter('prompt', itemIndex);
|
|
132
171
|
const qualityThreshold = this.getNodeParameter('qualityThreshold', itemIndex, 0.7);
|
|
133
|
-
const outputMode = this.getNodeParameter('output', itemIndex, '
|
|
172
|
+
const outputMode = this.getNodeParameter('output', itemIndex, 'contentOnly');
|
|
173
|
+
// Extract prompt from input data - support various field names
|
|
174
|
+
const item = inputData[itemIndex].json;
|
|
175
|
+
const prompt = item.prompt ||
|
|
176
|
+
item.message ||
|
|
177
|
+
item.query ||
|
|
178
|
+
item.text ||
|
|
179
|
+
item.input ||
|
|
180
|
+
JSON.stringify(item);
|
|
181
|
+
if (!prompt || prompt.length === 0) {
|
|
182
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'No prompt found in input data. Connect a node that provides prompt, message, query, text, or input field.', { itemIndex });
|
|
183
|
+
}
|
|
184
|
+
// Extract tools if provided (for function calling)
|
|
185
|
+
const tools = item.tools || undefined;
|
|
134
186
|
// Create CascadeAgent
|
|
135
187
|
const agent = new core_1.CascadeAgent({
|
|
136
188
|
models: modelConfigs,
|
|
@@ -141,6 +193,9 @@ class CascadeFlow {
|
|
|
141
193
|
});
|
|
142
194
|
// Prepare run options
|
|
143
195
|
const runOptions = {};
|
|
196
|
+
if (tools) {
|
|
197
|
+
runOptions.tools = tools;
|
|
198
|
+
}
|
|
144
199
|
// Execute cascade
|
|
145
200
|
const result = await agent.run(prompt, runOptions);
|
|
146
201
|
// Format output based on outputMode
|
|
@@ -165,7 +220,6 @@ class CascadeFlow {
|
|
|
165
220
|
};
|
|
166
221
|
break;
|
|
167
222
|
case 'fullMetrics':
|
|
168
|
-
default:
|
|
169
223
|
outputData = {
|
|
170
224
|
...result,
|
|
171
225
|
// Add n8n-friendly summary
|
|
@@ -178,27 +232,51 @@ class CascadeFlow {
|
|
|
178
232
|
},
|
|
179
233
|
};
|
|
180
234
|
break;
|
|
235
|
+
default:
|
|
236
|
+
outputData = result;
|
|
181
237
|
}
|
|
182
|
-
|
|
238
|
+
const outputItem = {
|
|
183
239
|
json: outputData,
|
|
184
240
|
pairedItem: { item: itemIndex },
|
|
185
|
-
}
|
|
241
|
+
};
|
|
242
|
+
// Route to appropriate output based on splitOutput setting
|
|
243
|
+
if (splitOutput) {
|
|
244
|
+
if (result.draftAccepted) {
|
|
245
|
+
returnData.push(outputItem);
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
escalatedData.push(outputItem);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
else {
|
|
252
|
+
returnData.push(outputItem);
|
|
253
|
+
}
|
|
186
254
|
}
|
|
187
255
|
catch (error) {
|
|
188
256
|
if (this.continueOnFail()) {
|
|
189
257
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
190
|
-
|
|
258
|
+
const errorItem = {
|
|
191
259
|
json: {
|
|
192
260
|
error: errorMessage,
|
|
193
261
|
},
|
|
194
262
|
pairedItem: { item: itemIndex },
|
|
195
|
-
}
|
|
263
|
+
};
|
|
264
|
+
// Errors always go to first output
|
|
265
|
+
returnData.push(errorItem);
|
|
196
266
|
continue;
|
|
197
267
|
}
|
|
198
268
|
throw error;
|
|
199
269
|
}
|
|
200
270
|
}
|
|
201
|
-
|
|
271
|
+
// Return appropriate outputs based on splitOutput setting
|
|
272
|
+
if (splitOutput) {
|
|
273
|
+
// Split mode: Draft accepted goes to output 0, escalated to output 1
|
|
274
|
+
return [returnData, escalatedData];
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
// Single output mode: All results go to output 0, output 1 is empty
|
|
278
|
+
return [returnData, []];
|
|
279
|
+
}
|
|
202
280
|
}
|
|
203
281
|
}
|
|
204
282
|
exports.CascadeFlow = CascadeFlow;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CascadeFlow.node.js","sourceRoot":"","sources":["../../../nodes/CascadeFlow/CascadeFlow.node.ts"],"names":[],"mappings":";;;AAAA,+CAMsB;AAEtB,4CAA8D;AAE9D,MAAa,WAAW;IAAxB;QACE,gBAAW,GAAyB;YAClC,WAAW,EAAE,aAAa;YAC1B,IAAI,EAAE,aAAa;YACnB,IAAI,EAAE,sBAAsB;YAC5B,KAAK,EAAE,CAAC,WAAW,CAAC;YACpB,OAAO,EAAE,CAAC;YACV,QAAQ,EAAE,oBAAoB;YAC9B,WAAW,EAAE,mDAAmD;YAChE,QAAQ,EAAE;gBACR,IAAI,EAAE,aAAa;aACpB;YACD,2FAA2F;YAC3F,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"CascadeFlow.node.js","sourceRoot":"","sources":["../../../nodes/CascadeFlow/CascadeFlow.node.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,43 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 91.76 91.76">
|
|
2
3
|
<defs>
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
<style>
|
|
5
|
+
.cls-1 {
|
|
6
|
+
fill: #667eea;
|
|
7
|
+
}
|
|
8
|
+
</style>
|
|
7
9
|
</defs>
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
<
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
<text x="50" y="24" text-anchor="middle" font-size="10" fill="white" font-weight="bold">D</text>
|
|
14
|
-
|
|
15
|
-
<!-- Arrow -->
|
|
16
|
-
<path d="M 50 28 L 50 40" stroke="url(#grad1)" stroke-width="2" fill="none" opacity="0.6"/>
|
|
17
|
-
<polygon points="50,40 47,35 53,35" fill="url(#grad1)" opacity="0.6"/>
|
|
18
|
-
|
|
19
|
-
<!-- Quality check diamond -->
|
|
20
|
-
<g opacity="0.8">
|
|
21
|
-
<path d="M 50 42 L 58 50 L 50 58 L 42 50 Z" fill="url(#grad1)"/>
|
|
22
|
-
<text x="50" y="53" text-anchor="middle" font-size="8" fill="white" font-weight="bold">✓</text>
|
|
23
|
-
</g>
|
|
24
|
-
|
|
25
|
-
<!-- Branch paths -->
|
|
26
|
-
<path d="M 50 58 L 30 75" stroke="url(#grad1)" stroke-width="2" fill="none" opacity="0.6" stroke-dasharray="2,2"/>
|
|
27
|
-
<path d="M 50 58 L 50 75" stroke="url(#grad1)" stroke-width="2" fill="none"/>
|
|
28
|
-
|
|
29
|
-
<!-- Bottom tier (verifier - optional) -->
|
|
30
|
-
<circle cx="30" cy="80" r="7" opacity="0.4" stroke="#764ba2" stroke-width="1" fill="none"/>
|
|
31
|
-
<text x="30" y="84" text-anchor="middle" font-size="9" fill="#764ba2" opacity="0.4">V</text>
|
|
32
|
-
|
|
33
|
-
<!-- Result -->
|
|
34
|
-
<circle cx="50" cy="80" r="8"/>
|
|
35
|
-
<text x="50" y="84" text-anchor="middle" font-size="10" fill="white" font-weight="bold">✓</text>
|
|
36
|
-
</g>
|
|
37
|
-
|
|
38
|
-
<!-- Cost savings indicator -->
|
|
39
|
-
<g opacity="0.9">
|
|
40
|
-
<rect x="65" y="75" width="30" height="14" rx="3" fill="#10b981"/>
|
|
41
|
-
<text x="80" y="84" text-anchor="middle" font-size="9" fill="white" font-weight="bold">-85%</text>
|
|
42
|
-
</g>
|
|
10
|
+
<path class="cls-1" d="M38.19,54.36c-4.15-4.15-4.15-10.87,0-15.02,4.15-4.15,10.87-4.15,15.02,0,4.15,4.15,4.15,10.87,0,15.02s-10.87,4.15-15.02,0Z"/>
|
|
11
|
+
<path class="cls-1" d="M63.4,91.76H28.7c-7.93,0-14.35-6.42-14.35-14.35h49.05v14.35Z"/>
|
|
12
|
+
<path class="cls-1" d="M14.35,77.41c-7.93,0-14.35-6.42-14.35-14.35V29.8h14.35v47.61Z"/>
|
|
13
|
+
<path class="cls-1" d="M28.36,0h34.7c7.93,0,14.35,6.42,14.35,14.35H28.36V0Z"/>
|
|
14
|
+
<path class="cls-1" d="M77.41,14.35c7.93,0,14.35,6.42,14.35,14.35v33.26h-14.35V14.35Z"/>
|
|
43
15
|
</svg>
|