@cascadeflow/n8n-nodes-cascadeflow 0.6.7 → 0.7.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/README.md +16 -11
- package/dist/nodes/CascadeFlowAgent/CascadeFlowAgent.node.d.ts +34 -0
- package/dist/nodes/CascadeFlowAgent/CascadeFlowAgent.node.d.ts.map +1 -0
- package/dist/nodes/CascadeFlowAgent/CascadeFlowAgent.node.js +466 -0
- package/dist/nodes/CascadeFlowAgent/CascadeFlowAgent.node.js.map +1 -0
- package/dist/nodes/CascadeFlowAgent/__tests__/cascadeflow-agent-executor.test.d.ts +2 -0
- package/dist/nodes/CascadeFlowAgent/__tests__/cascadeflow-agent-executor.test.d.ts.map +1 -0
- package/dist/nodes/CascadeFlowAgent/__tests__/cascadeflow-agent-executor.test.js +98 -0
- package/dist/nodes/CascadeFlowAgent/__tests__/cascadeflow-agent-executor.test.js.map +1 -0
- package/dist/nodes/CascadeFlowAgent/cascadeflow.svg +15 -0
- package/dist/nodes/LmChatCascadeFlow/LmChatCascadeFlow.node.d.ts +100 -0
- package/dist/nodes/LmChatCascadeFlow/LmChatCascadeFlow.node.d.ts.map +1 -1
- package/dist/nodes/LmChatCascadeFlow/LmChatCascadeFlow.node.js +432 -303
- package/dist/nodes/LmChatCascadeFlow/LmChatCascadeFlow.node.js.map +1 -1
- package/dist/nodes/LmChatCascadeFlow/__tests__/lm-chat-cascadeflow-node.test.d.ts +2 -0
- package/dist/nodes/LmChatCascadeFlow/__tests__/lm-chat-cascadeflow-node.test.d.ts.map +1 -0
- package/dist/nodes/LmChatCascadeFlow/__tests__/lm-chat-cascadeflow-node.test.js +59 -0
- package/dist/nodes/LmChatCascadeFlow/__tests__/lm-chat-cascadeflow-node.test.js.map +1 -0
- package/dist/nodes/LmChatCascadeFlow/cascade-metadata.d.ts +27 -0
- package/dist/nodes/LmChatCascadeFlow/cascade-metadata.d.ts.map +1 -0
- package/dist/nodes/LmChatCascadeFlow/cascade-metadata.js +21 -0
- package/dist/nodes/LmChatCascadeFlow/cascade-metadata.js.map +1 -0
- package/dist/nodes/LmChatCascadeFlow/config.d.ts +41 -0
- package/dist/nodes/LmChatCascadeFlow/config.d.ts.map +1 -0
- package/dist/nodes/LmChatCascadeFlow/config.js +87 -0
- package/dist/nodes/LmChatCascadeFlow/config.js.map +1 -0
- package/package.json +17 -12
|
@@ -1,76 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.LmChatCascadeFlow = void 0;
|
|
3
|
+
exports.LmChatCascadeFlow = exports.CascadeChatModel = void 0;
|
|
4
4
|
const n8n_workflow_1 = require("n8n-workflow");
|
|
5
5
|
const chat_models_1 = require("@langchain/core/language_models/chat_models");
|
|
6
6
|
const outputs_1 = require("@langchain/core/outputs");
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
//
|
|
10
|
-
const DOMAINS = {
|
|
11
|
-
CODE: 'code',
|
|
12
|
-
DATA: 'data',
|
|
13
|
-
STRUCTURED: 'structured',
|
|
14
|
-
RAG: 'rag',
|
|
15
|
-
CONVERSATION: 'conversation',
|
|
16
|
-
TOOL: 'tool',
|
|
17
|
-
CREATIVE: 'creative',
|
|
18
|
-
SUMMARY: 'summary',
|
|
19
|
-
TRANSLATION: 'translation',
|
|
20
|
-
MATH: 'math',
|
|
21
|
-
SCIENCE: 'science',
|
|
22
|
-
MEDICAL: 'medical',
|
|
23
|
-
LEGAL: 'legal',
|
|
24
|
-
FINANCIAL: 'financial',
|
|
25
|
-
MULTIMODAL: 'multimodal',
|
|
26
|
-
GENERAL: 'general',
|
|
27
|
-
};
|
|
28
|
-
// Domain display names for n8n UI
|
|
29
|
-
const DOMAIN_DISPLAY_NAMES = {
|
|
30
|
-
code: 'Code',
|
|
31
|
-
data: 'Data Analysis',
|
|
32
|
-
structured: 'Structured Output',
|
|
33
|
-
rag: 'RAG (Retrieval)',
|
|
34
|
-
conversation: 'Conversation',
|
|
35
|
-
tool: 'Tool Calling',
|
|
36
|
-
creative: 'Creative Writing',
|
|
37
|
-
summary: 'Summarization',
|
|
38
|
-
translation: 'Translation',
|
|
39
|
-
math: 'Mathematics',
|
|
40
|
-
science: 'Science',
|
|
41
|
-
medical: 'Medical',
|
|
42
|
-
legal: 'Legal',
|
|
43
|
-
financial: 'Financial',
|
|
44
|
-
multimodal: 'Multimodal',
|
|
45
|
-
general: 'General',
|
|
46
|
-
};
|
|
47
|
-
// Domain descriptions for n8n UI
|
|
48
|
-
const DOMAIN_DESCRIPTIONS = {
|
|
49
|
-
code: 'Programming, debugging, code generation',
|
|
50
|
-
data: 'Data analysis, statistics, pandas/SQL',
|
|
51
|
-
structured: 'JSON, XML, structured data extraction',
|
|
52
|
-
rag: 'Retrieval-augmented generation, document Q&A',
|
|
53
|
-
conversation: 'Chat, dialogue, multi-turn conversations',
|
|
54
|
-
tool: 'Function calling, tool use, API interactions',
|
|
55
|
-
creative: 'Creative writing, stories, poetry',
|
|
56
|
-
summary: 'Text summarization, condensing content',
|
|
57
|
-
translation: 'Language translation, multilingual',
|
|
58
|
-
math: 'Mathematical reasoning, calculations, proofs',
|
|
59
|
-
science: 'Scientific knowledge, research, experiments',
|
|
60
|
-
medical: 'Healthcare, medical knowledge, clinical',
|
|
61
|
-
legal: 'Legal documents, contracts, regulations',
|
|
62
|
-
financial: 'Finance, accounting, investment analysis',
|
|
63
|
-
multimodal: 'Images, audio, video understanding',
|
|
64
|
-
general: 'General purpose, fallback domain',
|
|
65
|
-
};
|
|
66
|
-
// Quality validation, cost tracking, routing, and circuit breaker - optional import
|
|
7
|
+
const config_1 = require("./config");
|
|
8
|
+
const cascade_metadata_1 = require("./cascade-metadata");
|
|
9
|
+
// Quality validation, cost tracking, and routing - optional import
|
|
67
10
|
let QualityValidator;
|
|
68
11
|
let CASCADE_QUALITY_CONFIG;
|
|
69
12
|
let CostCalculator;
|
|
70
13
|
let ComplexityDetector;
|
|
71
14
|
let PreRouter;
|
|
72
|
-
let
|
|
73
|
-
let CircuitBreaker;
|
|
15
|
+
let DomainRouter;
|
|
74
16
|
try {
|
|
75
17
|
const cascadeCore = require('@cascadeflow/core');
|
|
76
18
|
QualityValidator = cascadeCore.QualityValidator;
|
|
@@ -78,8 +20,7 @@ try {
|
|
|
78
20
|
CostCalculator = cascadeCore.CostCalculator;
|
|
79
21
|
ComplexityDetector = cascadeCore.ComplexityDetector;
|
|
80
22
|
PreRouter = cascadeCore.PreRouter;
|
|
81
|
-
|
|
82
|
-
CircuitBreaker = cascadeCore.CircuitBreaker;
|
|
23
|
+
DomainRouter = cascadeCore.DomainRouter;
|
|
83
24
|
}
|
|
84
25
|
catch (e) {
|
|
85
26
|
// @cascadeflow/core not available - use simple validation and estimates
|
|
@@ -90,10 +31,11 @@ catch (e) {
|
|
|
90
31
|
* and implements intelligent domain-aware cascading logic with cost tracking
|
|
91
32
|
*/
|
|
92
33
|
class CascadeChatModel extends chat_models_1.BaseChatModel {
|
|
93
|
-
constructor(
|
|
34
|
+
constructor(drafterModelGetter, verifierModelGetter, qualityThreshold = 0.7, useSemanticValidation = true, useAlignmentScoring = true, useComplexityRouting = true, useComplexityThresholds = true, useDomainRouting = false, enabledDomains = [], domainModelGetters = new Map(), domainConfigs = new Map(), confidenceThresholds) {
|
|
94
35
|
super({});
|
|
95
36
|
// Domain-specific models and configurations
|
|
96
37
|
this.domainModels = new Map();
|
|
38
|
+
this.domainModelGetters = new Map();
|
|
97
39
|
this.domainConfigs = new Map();
|
|
98
40
|
this.enabledDomains = [];
|
|
99
41
|
// Cost tracking
|
|
@@ -103,14 +45,17 @@ class CascadeChatModel extends chat_models_1.BaseChatModel {
|
|
|
103
45
|
this.drafterCount = 0;
|
|
104
46
|
this.verifierCount = 0;
|
|
105
47
|
this.domainCounts = new Map();
|
|
106
|
-
this.
|
|
48
|
+
this.drafterModelGetter = drafterModelGetter;
|
|
107
49
|
this.verifierModelGetter = verifierModelGetter;
|
|
108
50
|
this.qualityThreshold = qualityThreshold;
|
|
109
51
|
this.enabledDomains = enabledDomains;
|
|
110
52
|
this.domainConfigs = domainConfigs;
|
|
53
|
+
this.domainModelGetters = domainModelGetters;
|
|
54
|
+
this.confidenceThresholds = confidenceThresholds;
|
|
55
|
+
this.useComplexityThresholds = useComplexityThresholds;
|
|
56
|
+
this.useComplexityRouting = useComplexityRouting;
|
|
111
57
|
// Store domain model getters for lazy loading
|
|
112
|
-
for (const [domain
|
|
113
|
-
// Lazy load domain models
|
|
58
|
+
for (const [domain] of domainModelGetters.entries()) {
|
|
114
59
|
this.domainModels.set(domain, undefined);
|
|
115
60
|
}
|
|
116
61
|
// Initialize quality validator with CASCADE-optimized config + semantic validation
|
|
@@ -119,6 +64,7 @@ class CascadeChatModel extends chat_models_1.BaseChatModel {
|
|
|
119
64
|
this.qualityValidator = new QualityValidator({
|
|
120
65
|
...CASCADE_QUALITY_CONFIG,
|
|
121
66
|
minConfidence: qualityThreshold,
|
|
67
|
+
confidenceThresholds: useComplexityThresholds ? confidenceThresholds : undefined,
|
|
122
68
|
useSemanticValidation,
|
|
123
69
|
useAlignmentScoring,
|
|
124
70
|
semanticThreshold: 0.5,
|
|
@@ -154,10 +100,10 @@ class CascadeChatModel extends chat_models_1.BaseChatModel {
|
|
|
154
100
|
this.costCalculator = null;
|
|
155
101
|
}
|
|
156
102
|
// Initialize complexity detector and domain detector
|
|
157
|
-
if (useComplexityRouting && ComplexityDetector) {
|
|
103
|
+
if ((useComplexityRouting || useComplexityThresholds) && ComplexityDetector) {
|
|
158
104
|
try {
|
|
159
105
|
this.complexityDetector = new ComplexityDetector();
|
|
160
|
-
console.log('🧠 CascadeFlow complexity
|
|
106
|
+
console.log('🧠 CascadeFlow complexity detector initialized');
|
|
161
107
|
}
|
|
162
108
|
catch (e) {
|
|
163
109
|
console.warn('⚠️ Complexity detector initialization failed');
|
|
@@ -167,38 +113,20 @@ class CascadeChatModel extends chat_models_1.BaseChatModel {
|
|
|
167
113
|
else {
|
|
168
114
|
this.complexityDetector = null;
|
|
169
115
|
}
|
|
170
|
-
// Initialize domain
|
|
171
|
-
if (useDomainRouting &&
|
|
116
|
+
// Initialize domain router if domain routing is enabled
|
|
117
|
+
if (useDomainRouting && DomainRouter && enabledDomains.length > 0) {
|
|
172
118
|
try {
|
|
173
|
-
this.domainDetector = new
|
|
119
|
+
this.domainDetector = new DomainRouter();
|
|
174
120
|
console.log(`🎯 CascadeFlow domain routing enabled for: ${enabledDomains.join(', ')}`);
|
|
175
121
|
}
|
|
176
122
|
catch (e) {
|
|
177
|
-
console.warn('⚠️ Domain
|
|
123
|
+
console.warn('⚠️ Domain router initialization failed');
|
|
178
124
|
this.domainDetector = null;
|
|
179
125
|
}
|
|
180
126
|
}
|
|
181
127
|
else {
|
|
182
128
|
this.domainDetector = null;
|
|
183
129
|
}
|
|
184
|
-
// Initialize circuit breaker for fault tolerance
|
|
185
|
-
if (useCircuitBreaker && CircuitBreaker) {
|
|
186
|
-
try {
|
|
187
|
-
this.circuitBreaker = new CircuitBreaker({
|
|
188
|
-
failureThreshold: 3,
|
|
189
|
-
recoveryTimeout: 30000, // 30 seconds
|
|
190
|
-
halfOpenMaxCalls: 2,
|
|
191
|
-
});
|
|
192
|
-
console.log('🛡️ CascadeFlow circuit breaker enabled');
|
|
193
|
-
}
|
|
194
|
-
catch (e) {
|
|
195
|
-
console.warn('⚠️ Circuit breaker initialization failed');
|
|
196
|
-
this.circuitBreaker = null;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
else {
|
|
200
|
-
this.circuitBreaker = null;
|
|
201
|
-
}
|
|
202
130
|
}
|
|
203
131
|
async getVerifierModel() {
|
|
204
132
|
if (!this.verifierModel) {
|
|
@@ -210,15 +138,72 @@ class CascadeChatModel extends chat_models_1.BaseChatModel {
|
|
|
210
138
|
return this.verifierModel;
|
|
211
139
|
}
|
|
212
140
|
/**
|
|
213
|
-
*
|
|
141
|
+
* Agent helper: force a direct verifier call (bypasses cascade logic) while still
|
|
142
|
+
* attaching the same `response_metadata` fields as the standard flows.
|
|
143
|
+
*/
|
|
144
|
+
async invokeVerifierDirect(messages, options, runManager) {
|
|
145
|
+
const verifierModel = await this.getVerifierModel();
|
|
146
|
+
const verifierInfo = this.getModelInfo(verifierModel);
|
|
147
|
+
await runManager?.handleText(`⚡ Agent route: using verifier directly (${verifierInfo})\n`);
|
|
148
|
+
const start = Date.now();
|
|
149
|
+
const verifierMessage = await verifierModel.invoke(messages, options);
|
|
150
|
+
const latency = Date.now() - start;
|
|
151
|
+
const verifierCost = await this.calculateMessageCost(verifierMessage, verifierModel);
|
|
152
|
+
const costBreakdown = {
|
|
153
|
+
drafter: 0,
|
|
154
|
+
verifier: verifierCost,
|
|
155
|
+
total: verifierCost,
|
|
156
|
+
};
|
|
157
|
+
if (!verifierMessage.response_metadata) {
|
|
158
|
+
verifierMessage.response_metadata = {};
|
|
159
|
+
}
|
|
160
|
+
verifierMessage.response_metadata.cascadeflow = {
|
|
161
|
+
flow: 'agent_verifier_direct',
|
|
162
|
+
model_used: 'verifier',
|
|
163
|
+
latency_ms: latency,
|
|
164
|
+
cost_usd: verifierCost,
|
|
165
|
+
};
|
|
166
|
+
this.attachCascadeMetadata(verifierMessage, (0, cascade_metadata_1.buildCascadeMetadata)({
|
|
167
|
+
modelUsed: 'verifier',
|
|
168
|
+
domain: null,
|
|
169
|
+
costs: costBreakdown,
|
|
170
|
+
baselineCost: verifierCost,
|
|
171
|
+
}));
|
|
172
|
+
return verifierMessage;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Lazy-load drafter model (so n8n highlights it only when actually used).
|
|
176
|
+
*/
|
|
177
|
+
async getDrafterModel() {
|
|
178
|
+
if (!this.drafterModel) {
|
|
179
|
+
this.drafterModel = await this.drafterModelGetter();
|
|
180
|
+
}
|
|
181
|
+
return this.drafterModel;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Get a connected domain-specific model (lazy-loaded).
|
|
185
|
+
* Returns undefined if no domain model is connected.
|
|
214
186
|
*/
|
|
215
187
|
async getDomainModel(domain) {
|
|
216
188
|
const existingModel = this.domainModels.get(domain);
|
|
217
189
|
if (existingModel) {
|
|
218
190
|
return existingModel;
|
|
219
191
|
}
|
|
220
|
-
|
|
221
|
-
|
|
192
|
+
const getter = this.domainModelGetters.get(domain);
|
|
193
|
+
if (!getter) {
|
|
194
|
+
return undefined;
|
|
195
|
+
}
|
|
196
|
+
try {
|
|
197
|
+
const model = await getter();
|
|
198
|
+
if (model) {
|
|
199
|
+
this.domainModels.set(domain, model);
|
|
200
|
+
return model;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
catch {
|
|
204
|
+
// Treat as "not connected"
|
|
205
|
+
}
|
|
206
|
+
return undefined;
|
|
222
207
|
}
|
|
223
208
|
/**
|
|
224
209
|
* Helper to get model info string (type and name)
|
|
@@ -228,6 +213,76 @@ class CascadeChatModel extends chat_models_1.BaseChatModel {
|
|
|
228
213
|
const modelName = model.modelName || model.model || 'unknown';
|
|
229
214
|
return `${type} (${modelName})`;
|
|
230
215
|
}
|
|
216
|
+
/**
|
|
217
|
+
* Detect query complexity using whichever detector API is available.
|
|
218
|
+
*/
|
|
219
|
+
async detectComplexity(queryText) {
|
|
220
|
+
if (!this.complexityDetector) {
|
|
221
|
+
return {};
|
|
222
|
+
}
|
|
223
|
+
try {
|
|
224
|
+
if (typeof this.complexityDetector.detectComplexity === 'function') {
|
|
225
|
+
const result = await this.complexityDetector.detectComplexity(queryText);
|
|
226
|
+
return {
|
|
227
|
+
level: result.level ?? result.complexity,
|
|
228
|
+
confidence: result.confidence,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
if (typeof this.complexityDetector.detect === 'function') {
|
|
232
|
+
const result = await this.complexityDetector.detect(queryText);
|
|
233
|
+
return {
|
|
234
|
+
level: result.complexity ?? result.level,
|
|
235
|
+
confidence: result.confidence,
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
catch (e) {
|
|
240
|
+
console.warn('Complexity detection failed, using normal flow');
|
|
241
|
+
}
|
|
242
|
+
return {};
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Get effective confidence threshold for a given complexity tier.
|
|
246
|
+
*/
|
|
247
|
+
getThresholdForComplexity(complexity) {
|
|
248
|
+
if (!complexity || !this.useComplexityThresholds || !this.confidenceThresholds) {
|
|
249
|
+
return this.qualityThreshold;
|
|
250
|
+
}
|
|
251
|
+
switch (complexity) {
|
|
252
|
+
case 'trivial':
|
|
253
|
+
return this.confidenceThresholds.trivial ?? this.qualityThreshold;
|
|
254
|
+
case 'simple':
|
|
255
|
+
return this.confidenceThresholds.simple ?? this.qualityThreshold;
|
|
256
|
+
case 'moderate':
|
|
257
|
+
return this.confidenceThresholds.moderate ?? this.qualityThreshold;
|
|
258
|
+
case 'hard':
|
|
259
|
+
return this.confidenceThresholds.hard ?? this.qualityThreshold;
|
|
260
|
+
case 'expert':
|
|
261
|
+
return this.confidenceThresholds.expert ?? this.qualityThreshold;
|
|
262
|
+
default:
|
|
263
|
+
return this.qualityThreshold;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Estimate baseline cost for a different model using the same token usage.
|
|
268
|
+
*/
|
|
269
|
+
async estimateAlternateModelCost(message, model) {
|
|
270
|
+
if (!model) {
|
|
271
|
+
return undefined;
|
|
272
|
+
}
|
|
273
|
+
try {
|
|
274
|
+
return await this.calculateMessageCost(message, model);
|
|
275
|
+
}
|
|
276
|
+
catch (e) {
|
|
277
|
+
return undefined;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
attachCascadeMetadata(message, metadata) {
|
|
281
|
+
if (!message.response_metadata) {
|
|
282
|
+
message.response_metadata = {};
|
|
283
|
+
}
|
|
284
|
+
message.response_metadata.cf = metadata;
|
|
285
|
+
}
|
|
231
286
|
/**
|
|
232
287
|
* Detect the domain of a query using semantic detection
|
|
233
288
|
*/
|
|
@@ -328,7 +383,7 @@ class CascadeChatModel extends chat_models_1.BaseChatModel {
|
|
|
328
383
|
/**
|
|
329
384
|
* Simple quality validation fallback (when @cascadeflow/core not available)
|
|
330
385
|
*/
|
|
331
|
-
simpleQualityCheck(responseText) {
|
|
386
|
+
simpleQualityCheck(responseText, threshold) {
|
|
332
387
|
const wordCount = responseText.split(/\s+/).length;
|
|
333
388
|
let confidence = 0.75;
|
|
334
389
|
if (wordCount < 5) {
|
|
@@ -345,10 +400,10 @@ class CascadeChatModel extends chat_models_1.BaseChatModel {
|
|
|
345
400
|
if (hasUncertainty) {
|
|
346
401
|
confidence -= 0.20;
|
|
347
402
|
}
|
|
348
|
-
const passed = confidence >=
|
|
403
|
+
const passed = confidence >= threshold;
|
|
349
404
|
const reason = passed
|
|
350
|
-
? `Simple check passed (confidence: ${confidence.toFixed(2)} >= ${
|
|
351
|
-
: `Simple check failed (confidence: ${confidence.toFixed(2)} < ${
|
|
405
|
+
? `Simple check passed (confidence: ${confidence.toFixed(2)} >= ${threshold})`
|
|
406
|
+
: `Simple check failed (confidence: ${confidence.toFixed(2)} < ${threshold})`;
|
|
352
407
|
return { passed, confidence, score: confidence, reason };
|
|
353
408
|
}
|
|
354
409
|
_llmType() {
|
|
@@ -363,10 +418,10 @@ class CascadeChatModel extends chat_models_1.BaseChatModel {
|
|
|
363
418
|
if (this.enabledDomains.length > 0) {
|
|
364
419
|
detectedDomain = await this.detectDomain(queryText);
|
|
365
420
|
if (detectedDomain) {
|
|
366
|
-
const
|
|
367
|
-
if (
|
|
368
|
-
domainModel =
|
|
369
|
-
await runManager?.handleText(`🎯 Domain: ${DOMAIN_DISPLAY_NAMES[detectedDomain]} → Using domain-specific model\n`);
|
|
421
|
+
const connectedDomainModel = await this.getDomainModel(detectedDomain);
|
|
422
|
+
if (connectedDomainModel) {
|
|
423
|
+
domainModel = connectedDomainModel;
|
|
424
|
+
await runManager?.handleText(`🎯 Domain: ${config_1.DOMAIN_DISPLAY_NAMES[detectedDomain]} → Using domain-specific model\n`);
|
|
370
425
|
}
|
|
371
426
|
}
|
|
372
427
|
}
|
|
@@ -374,9 +429,9 @@ class CascadeChatModel extends chat_models_1.BaseChatModel {
|
|
|
374
429
|
let complexity;
|
|
375
430
|
let shouldSkipDrafter = false;
|
|
376
431
|
if (this.complexityDetector) {
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
432
|
+
const complexityResult = await this.detectComplexity(queryText);
|
|
433
|
+
complexity = complexityResult.level;
|
|
434
|
+
if (complexity && this.useComplexityRouting) {
|
|
380
435
|
if (complexity === 'hard' || complexity === 'expert') {
|
|
381
436
|
shouldSkipDrafter = true;
|
|
382
437
|
await runManager?.handleText(`🧠 Complexity: ${complexity} → Routing directly to verifier (skip drafter)\n`);
|
|
@@ -387,27 +442,22 @@ class CascadeChatModel extends chat_models_1.BaseChatModel {
|
|
|
387
442
|
console.log(`🧠 Complexity: ${complexity} → Drafter route`);
|
|
388
443
|
}
|
|
389
444
|
}
|
|
390
|
-
catch (e) {
|
|
391
|
-
console.warn('Complexity detection failed, using normal flow');
|
|
392
|
-
}
|
|
393
445
|
}
|
|
394
|
-
// Step 3:
|
|
395
|
-
const executeWithProtection = async (model, modelType) => {
|
|
396
|
-
if (this.circuitBreaker) {
|
|
397
|
-
return await this.circuitBreaker.execute(modelType, async () => await model.invoke(messages, options));
|
|
398
|
-
}
|
|
399
|
-
return await model.invoke(messages, options);
|
|
400
|
-
};
|
|
401
|
-
// Step 3a: If complexity routing says skip drafter, go directly to verifier
|
|
446
|
+
// Step 3: If complexity routing says skip drafter, go directly to verifier
|
|
402
447
|
if (shouldSkipDrafter) {
|
|
403
448
|
const verifierModel = await this.getVerifierModel();
|
|
404
449
|
const verifierInfo = this.getModelInfo(verifierModel);
|
|
405
450
|
await runManager?.handleText(`⚡ Direct route: Using verifier for ${complexity} query\n`);
|
|
406
451
|
const verifierStartTime = Date.now();
|
|
407
|
-
const verifierMessage = await
|
|
452
|
+
const verifierMessage = await verifierModel.invoke(messages, options);
|
|
408
453
|
const verifierLatency = Date.now() - verifierStartTime;
|
|
409
454
|
this.verifierCount++;
|
|
410
455
|
const verifierCost = await this.calculateMessageCost(verifierMessage, verifierModel);
|
|
456
|
+
const costBreakdown = {
|
|
457
|
+
drafter: 0,
|
|
458
|
+
verifier: verifierCost,
|
|
459
|
+
total: verifierCost,
|
|
460
|
+
};
|
|
411
461
|
const flowLog = `
|
|
412
462
|
┌────────────────────────────────────────────┐
|
|
413
463
|
│ ⚡ FLOW: DIRECT VERIFIER (SMART ROUTE) │
|
|
@@ -433,6 +483,11 @@ class CascadeChatModel extends chat_models_1.BaseChatModel {
|
|
|
433
483
|
model_used: 'verifier',
|
|
434
484
|
reason: `Query complexity (${complexity}) warranted direct verifier routing`
|
|
435
485
|
};
|
|
486
|
+
this.attachCascadeMetadata(verifierMessage, (0, cascade_metadata_1.buildCascadeMetadata)({
|
|
487
|
+
modelUsed: 'verifier',
|
|
488
|
+
domain: detectedDomain,
|
|
489
|
+
costs: costBreakdown,
|
|
490
|
+
}));
|
|
436
491
|
return {
|
|
437
492
|
generations: [{
|
|
438
493
|
text: verifierMessage.content.toString(),
|
|
@@ -441,13 +496,13 @@ class CascadeChatModel extends chat_models_1.BaseChatModel {
|
|
|
441
496
|
};
|
|
442
497
|
}
|
|
443
498
|
// Step 4: Try domain-specific model first if available
|
|
444
|
-
const modelToUse = domainModel || this.
|
|
499
|
+
const modelToUse = domainModel || (await this.getDrafterModel());
|
|
445
500
|
const modelType = domainModel ? `domain:${detectedDomain}` : 'drafter';
|
|
446
501
|
const modelInfo = this.getModelInfo(modelToUse);
|
|
447
502
|
await runManager?.handleText(`🎯 CascadeFlow: Trying ${modelType} model: ${modelInfo}\n`);
|
|
448
503
|
console.log(`🎯 CascadeFlow: Trying ${modelType} model: ${modelInfo}`);
|
|
449
504
|
const drafterStartTime = Date.now();
|
|
450
|
-
const drafterMessage = await
|
|
505
|
+
const drafterMessage = await modelToUse.invoke(messages, options);
|
|
451
506
|
const drafterLatency = Date.now() - drafterStartTime;
|
|
452
507
|
if (domainModel && detectedDomain) {
|
|
453
508
|
this.domainCounts.set(detectedDomain, (this.domainCounts.get(detectedDomain) || 0) + 1);
|
|
@@ -469,7 +524,7 @@ class CascadeChatModel extends chat_models_1.BaseChatModel {
|
|
|
469
524
|
Query → ${modelType} → Tool Calls (${toolCallsCount}) → Response
|
|
470
525
|
⚡ Tool calling: ${modelType} generated tool calls
|
|
471
526
|
Model used: ${modelInfo}
|
|
472
|
-
${detectedDomain ? `Domain: ${DOMAIN_DISPLAY_NAMES[detectedDomain]}` : ''}
|
|
527
|
+
${detectedDomain ? `Domain: ${config_1.DOMAIN_DISPLAY_NAMES[detectedDomain]}` : ''}
|
|
473
528
|
Latency: ${drafterLatency}ms
|
|
474
529
|
📊 Stats: ${this.drafterCount} drafter, ${this.verifierCount} verifier
|
|
475
530
|
`;
|
|
@@ -486,6 +541,20 @@ class CascadeChatModel extends chat_models_1.BaseChatModel {
|
|
|
486
541
|
latency_ms: drafterLatency,
|
|
487
542
|
model_used: modelType
|
|
488
543
|
};
|
|
544
|
+
const drafterCost = await this.calculateMessageCost(drafterMessage, modelToUse);
|
|
545
|
+
const baselineCost = await this.estimateAlternateModelCost(drafterMessage, this.verifierModel);
|
|
546
|
+
const costBreakdown = {
|
|
547
|
+
drafter: drafterCost,
|
|
548
|
+
verifier: 0,
|
|
549
|
+
total: drafterCost,
|
|
550
|
+
...(detectedDomain ? { domain: drafterCost } : {}),
|
|
551
|
+
};
|
|
552
|
+
this.attachCascadeMetadata(drafterMessage, (0, cascade_metadata_1.buildCascadeMetadata)({
|
|
553
|
+
modelUsed: modelType,
|
|
554
|
+
domain: detectedDomain,
|
|
555
|
+
costs: costBreakdown,
|
|
556
|
+
baselineCost,
|
|
557
|
+
}));
|
|
489
558
|
return {
|
|
490
559
|
generations: [{
|
|
491
560
|
text: drafterMessage.content.toString(),
|
|
@@ -495,15 +564,15 @@ class CascadeChatModel extends chat_models_1.BaseChatModel {
|
|
|
495
564
|
}
|
|
496
565
|
// Step 6: Quality check with domain-aware threshold
|
|
497
566
|
const responseText = drafterMessage.content.toString();
|
|
498
|
-
const
|
|
499
|
-
?
|
|
500
|
-
:
|
|
567
|
+
const domainThreshold = detectedDomain
|
|
568
|
+
? this.domainConfigs.get(detectedDomain)?.threshold
|
|
569
|
+
: undefined;
|
|
570
|
+
const effectiveThreshold = domainThreshold ?? this.getThresholdForComplexity(complexity);
|
|
501
571
|
let validationResult;
|
|
502
572
|
if (this.qualityValidator) {
|
|
503
573
|
try {
|
|
504
|
-
validationResult = await this.qualityValidator.validate(responseText, queryText);
|
|
505
|
-
|
|
506
|
-
const qualityLog = ` 📊 Quality validation: confidence=${validationResult.confidence.toFixed(2)}, threshold=${effectiveThreshold}, method=${validationResult.method}\n`;
|
|
574
|
+
validationResult = await this.qualityValidator.validate(responseText, queryText, undefined, complexity, domainThreshold);
|
|
575
|
+
const qualityLog = ` 📊 Quality validation: confidence=${validationResult.confidence.toFixed(2)}, threshold=${effectiveThreshold}, method=${validationResult.method}${complexity ? `, complexity=${complexity}` : ''}\n`;
|
|
507
576
|
await runManager?.handleText(qualityLog);
|
|
508
577
|
console.log(qualityLog);
|
|
509
578
|
if (validationResult.details?.alignmentScore) {
|
|
@@ -516,13 +585,11 @@ class CascadeChatModel extends chat_models_1.BaseChatModel {
|
|
|
516
585
|
const errorLog = ` ⚠️ Quality validator error, using simple check: ${e}\n`;
|
|
517
586
|
await runManager?.handleText(errorLog);
|
|
518
587
|
console.warn(errorLog);
|
|
519
|
-
validationResult = this.simpleQualityCheck(responseText);
|
|
520
|
-
validationResult.passed = validationResult.confidence >= effectiveThreshold;
|
|
588
|
+
validationResult = this.simpleQualityCheck(responseText, effectiveThreshold);
|
|
521
589
|
}
|
|
522
590
|
}
|
|
523
591
|
else {
|
|
524
|
-
validationResult = this.simpleQualityCheck(responseText);
|
|
525
|
-
validationResult.passed = validationResult.confidence >= effectiveThreshold;
|
|
592
|
+
validationResult = this.simpleQualityCheck(responseText, effectiveThreshold);
|
|
526
593
|
const simpleLog = ` 📊 Simple quality check: confidence=${validationResult.confidence.toFixed(2)}\n`;
|
|
527
594
|
await runManager?.handleText(simpleLog);
|
|
528
595
|
console.log(simpleLog);
|
|
@@ -530,6 +597,13 @@ class CascadeChatModel extends chat_models_1.BaseChatModel {
|
|
|
530
597
|
// Step 7: If quality is sufficient, return response
|
|
531
598
|
if (validationResult.passed) {
|
|
532
599
|
const drafterCost = await this.calculateMessageCost(drafterMessage, modelToUse);
|
|
600
|
+
const baselineCost = await this.estimateAlternateModelCost(drafterMessage, this.verifierModel);
|
|
601
|
+
const costBreakdown = {
|
|
602
|
+
drafter: drafterCost,
|
|
603
|
+
verifier: 0,
|
|
604
|
+
total: drafterCost,
|
|
605
|
+
...(detectedDomain ? { domain: drafterCost } : {}),
|
|
606
|
+
};
|
|
533
607
|
const flowLog = `
|
|
534
608
|
┌─────────────────────────────────────────┐
|
|
535
609
|
│ ✅ FLOW: ${modelType.toUpperCase()} ACCEPTED (FAST PATH) │
|
|
@@ -537,7 +611,7 @@ class CascadeChatModel extends chat_models_1.BaseChatModel {
|
|
|
537
611
|
Query → ${detectedDomain ? `Domain(${detectedDomain}) → ` : ''}${modelType} → Quality Check ✅ → Response
|
|
538
612
|
⚡ Fast & Cheap: Used ${modelType} model only
|
|
539
613
|
Model used: ${modelInfo}
|
|
540
|
-
${detectedDomain ? `Domain: ${DOMAIN_DISPLAY_NAMES[detectedDomain]}` : ''}
|
|
614
|
+
${detectedDomain ? `Domain: ${config_1.DOMAIN_DISPLAY_NAMES[detectedDomain]}` : ''}
|
|
541
615
|
Confidence: ${validationResult.confidence.toFixed(2)} (threshold: ${effectiveThreshold})
|
|
542
616
|
Quality score: ${validationResult.score.toFixed(2)}
|
|
543
617
|
Latency: ${drafterLatency}ms
|
|
@@ -558,6 +632,13 @@ class CascadeChatModel extends chat_models_1.BaseChatModel {
|
|
|
558
632
|
cost_usd: drafterCost,
|
|
559
633
|
model_used: modelType
|
|
560
634
|
};
|
|
635
|
+
this.attachCascadeMetadata(drafterMessage, (0, cascade_metadata_1.buildCascadeMetadata)({
|
|
636
|
+
modelUsed: modelType,
|
|
637
|
+
domain: detectedDomain,
|
|
638
|
+
confidence: validationResult.confidence,
|
|
639
|
+
costs: costBreakdown,
|
|
640
|
+
baselineCost,
|
|
641
|
+
}));
|
|
561
642
|
return {
|
|
562
643
|
generations: [{
|
|
563
644
|
text: drafterMessage.content.toString(),
|
|
@@ -582,18 +663,19 @@ class CascadeChatModel extends chat_models_1.BaseChatModel {
|
|
|
582
663
|
const verifierStartTime = Date.now();
|
|
583
664
|
const verifierModel = await this.getVerifierModel();
|
|
584
665
|
const verifierInfo = this.getModelInfo(verifierModel);
|
|
585
|
-
const verifierMessage = await
|
|
666
|
+
const verifierMessage = await verifierModel.invoke(messages, options);
|
|
586
667
|
const verifierLatency = Date.now() - verifierStartTime;
|
|
587
668
|
this.verifierCount++;
|
|
588
669
|
const verifierCost = await this.calculateMessageCost(verifierMessage, verifierModel);
|
|
589
|
-
const
|
|
670
|
+
const drafterCost = await this.calculateMessageCost(drafterMessage, modelToUse);
|
|
671
|
+
const totalCost = drafterCost + verifierCost;
|
|
590
672
|
const totalLatency = drafterLatency + verifierLatency;
|
|
591
673
|
const acceptanceRate = (this.drafterCount / (this.drafterCount + this.verifierCount) * 100).toFixed(1);
|
|
592
674
|
const completionLog = ` ✅ Verifier completed successfully
|
|
593
675
|
Model used: ${verifierInfo}
|
|
594
676
|
Verifier latency: ${verifierLatency}ms
|
|
595
677
|
Total latency: ${totalLatency}ms (${modelType}: ${drafterLatency}ms + verifier: ${verifierLatency}ms)
|
|
596
|
-
💰 Cost: $${totalCost.toFixed(6)} (
|
|
678
|
+
💰 Cost: $${totalCost.toFixed(6)} (drafter $${drafterCost.toFixed(6)} + verifier $${verifierCost.toFixed(6)})
|
|
597
679
|
📊 Stats: ${this.drafterCount} drafter (${acceptanceRate}%), ${this.verifierCount} verifier
|
|
598
680
|
`;
|
|
599
681
|
await runManager?.handleText(completionLog);
|
|
@@ -612,6 +694,19 @@ class CascadeChatModel extends chat_models_1.BaseChatModel {
|
|
|
612
694
|
model_used: 'verifier',
|
|
613
695
|
reason: validationResult.reason
|
|
614
696
|
};
|
|
697
|
+
const costBreakdown = {
|
|
698
|
+
drafter: drafterCost,
|
|
699
|
+
verifier: verifierCost,
|
|
700
|
+
total: totalCost,
|
|
701
|
+
...(detectedDomain ? { domain: drafterCost } : {}),
|
|
702
|
+
};
|
|
703
|
+
this.attachCascadeMetadata(verifierMessage, (0, cascade_metadata_1.buildCascadeMetadata)({
|
|
704
|
+
modelUsed: 'verifier',
|
|
705
|
+
domain: detectedDomain,
|
|
706
|
+
confidence: validationResult.confidence,
|
|
707
|
+
costs: costBreakdown,
|
|
708
|
+
baselineCost: totalCost,
|
|
709
|
+
}));
|
|
615
710
|
return {
|
|
616
711
|
generations: [{
|
|
617
712
|
text: verifierMessage.content.toString(),
|
|
@@ -620,15 +715,13 @@ class CascadeChatModel extends chat_models_1.BaseChatModel {
|
|
|
620
715
|
};
|
|
621
716
|
}
|
|
622
717
|
catch (error) {
|
|
623
|
-
// Handle circuit breaker open state
|
|
624
718
|
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
625
|
-
const isCircuitOpen = errorMsg.includes('Circuit breaker') || errorMsg.includes('circuit is open');
|
|
626
719
|
const errorLog = `
|
|
627
720
|
┌─────────────────────────────────────────────┐
|
|
628
|
-
│ ❌ FLOW:
|
|
721
|
+
│ ❌ FLOW: DRAFTER ERROR - FALLBACK PATH │
|
|
629
722
|
└─────────────────────────────────────────────┘
|
|
630
|
-
Query → Drafter ❌
|
|
631
|
-
🔄 Fallback:
|
|
723
|
+
Query → Drafter ❌ ERROR → Verifier → Response
|
|
724
|
+
🔄 Fallback: Drafter failed, using verifier as backup
|
|
632
725
|
Error: ${errorMsg}
|
|
633
726
|
🔄 Loading verifier model...
|
|
634
727
|
`;
|
|
@@ -638,9 +731,10 @@ class CascadeChatModel extends chat_models_1.BaseChatModel {
|
|
|
638
731
|
const verifierInfo = this.getModelInfo(verifierModel);
|
|
639
732
|
const verifierMessage = await verifierModel.invoke(messages, options);
|
|
640
733
|
this.verifierCount++;
|
|
734
|
+
const verifierCost = await this.calculateMessageCost(verifierMessage, verifierModel);
|
|
641
735
|
const fallbackCompleteLog = ` ✅ Verifier fallback completed successfully
|
|
642
736
|
Model used: ${verifierInfo}
|
|
643
|
-
💰 Cost:
|
|
737
|
+
💰 Cost: $${verifierCost.toFixed(6)} (fallback due to error)
|
|
644
738
|
`;
|
|
645
739
|
await runManager?.handleText(fallbackCompleteLog);
|
|
646
740
|
console.log(fallbackCompleteLog);
|
|
@@ -648,11 +742,23 @@ class CascadeChatModel extends chat_models_1.BaseChatModel {
|
|
|
648
742
|
verifierMessage.response_metadata = {};
|
|
649
743
|
}
|
|
650
744
|
verifierMessage.response_metadata.cascadeflow = {
|
|
651
|
-
flow:
|
|
745
|
+
flow: 'error_fallback',
|
|
652
746
|
error: errorMsg,
|
|
653
747
|
cost_savings_percent: 0,
|
|
654
|
-
model_used: 'verifier'
|
|
748
|
+
model_used: 'verifier',
|
|
749
|
+
cost_usd: verifierCost
|
|
750
|
+
};
|
|
751
|
+
const costBreakdown = {
|
|
752
|
+
drafter: 0,
|
|
753
|
+
verifier: verifierCost,
|
|
754
|
+
total: verifierCost,
|
|
655
755
|
};
|
|
756
|
+
this.attachCascadeMetadata(verifierMessage, (0, cascade_metadata_1.buildCascadeMetadata)({
|
|
757
|
+
modelUsed: 'verifier',
|
|
758
|
+
domain: null,
|
|
759
|
+
costs: costBreakdown,
|
|
760
|
+
baselineCost: verifierCost,
|
|
761
|
+
}));
|
|
656
762
|
return {
|
|
657
763
|
generations: [{
|
|
658
764
|
text: verifierMessage.content.toString(),
|
|
@@ -669,18 +775,28 @@ class CascadeChatModel extends chat_models_1.BaseChatModel {
|
|
|
669
775
|
const queryText = messages.map(m => m.content.toString()).join(' ');
|
|
670
776
|
// Detect domain for streaming
|
|
671
777
|
let detectedDomain = null;
|
|
672
|
-
let
|
|
778
|
+
let complexity;
|
|
779
|
+
let modelToUse = null;
|
|
780
|
+
let usingDomainModel = false;
|
|
673
781
|
if (this.enabledDomains.length > 0) {
|
|
674
782
|
detectedDomain = await this.detectDomain(queryText);
|
|
675
783
|
if (detectedDomain) {
|
|
676
|
-
const
|
|
677
|
-
if (
|
|
678
|
-
modelToUse =
|
|
784
|
+
const connectedDomainModel = await this.getDomainModel(detectedDomain);
|
|
785
|
+
if (connectedDomainModel) {
|
|
786
|
+
modelToUse = connectedDomainModel;
|
|
787
|
+
usingDomainModel = true;
|
|
679
788
|
}
|
|
680
789
|
}
|
|
681
790
|
}
|
|
791
|
+
if (this.complexityDetector && this.useComplexityThresholds) {
|
|
792
|
+
const complexityResult = await this.detectComplexity(queryText);
|
|
793
|
+
complexity = complexityResult.level;
|
|
794
|
+
}
|
|
795
|
+
if (!modelToUse) {
|
|
796
|
+
modelToUse = await this.getDrafterModel();
|
|
797
|
+
}
|
|
682
798
|
const modelInfo = this.getModelInfo(modelToUse);
|
|
683
|
-
const modelType = detectedDomain ? `domain:${detectedDomain}` : 'drafter';
|
|
799
|
+
const modelType = usingDomainModel && detectedDomain ? `domain:${detectedDomain}` : 'drafter';
|
|
684
800
|
await runManager?.handleText(`🎯 CascadeFlow (Streaming): Trying ${modelType} model: ${modelInfo}\n`);
|
|
685
801
|
console.log(`🎯 CascadeFlow (Streaming): Trying ${modelType} model: ${modelInfo}`);
|
|
686
802
|
const drafterStartTime = Date.now();
|
|
@@ -697,7 +813,12 @@ class CascadeChatModel extends chat_models_1.BaseChatModel {
|
|
|
697
813
|
yield generationChunk;
|
|
698
814
|
}
|
|
699
815
|
const drafterLatency = Date.now() - drafterStartTime;
|
|
700
|
-
|
|
816
|
+
if (usingDomainModel && detectedDomain) {
|
|
817
|
+
this.domainCounts.set(detectedDomain, (this.domainCounts.get(detectedDomain) || 0) + 1);
|
|
818
|
+
}
|
|
819
|
+
else {
|
|
820
|
+
this.drafterCount++;
|
|
821
|
+
}
|
|
701
822
|
if (lastChunk && this.hasToolCalls(lastChunk.message)) {
|
|
702
823
|
const toolCallsCount = this.getToolCallsCount(lastChunk.message);
|
|
703
824
|
const toolLog = `\n🔧 Tool calls detected (${toolCallsCount}) - cascade complete\n`;
|
|
@@ -706,24 +827,22 @@ class CascadeChatModel extends chat_models_1.BaseChatModel {
|
|
|
706
827
|
return;
|
|
707
828
|
}
|
|
708
829
|
await runManager?.handleText(`\n📊 Running quality check...\n`);
|
|
709
|
-
const
|
|
710
|
-
?
|
|
711
|
-
:
|
|
830
|
+
const domainThreshold = detectedDomain
|
|
831
|
+
? this.domainConfigs.get(detectedDomain)?.threshold
|
|
832
|
+
: undefined;
|
|
833
|
+
const effectiveThreshold = domainThreshold ?? this.getThresholdForComplexity(complexity);
|
|
712
834
|
let validationResult;
|
|
713
835
|
if (this.qualityValidator) {
|
|
714
836
|
try {
|
|
715
|
-
validationResult = await this.qualityValidator.validate(fullDrafterContent, queryText);
|
|
716
|
-
validationResult.passed = validationResult.confidence >= effectiveThreshold;
|
|
837
|
+
validationResult = await this.qualityValidator.validate(fullDrafterContent, queryText, undefined, complexity, domainThreshold);
|
|
717
838
|
await runManager?.handleText(` Confidence: ${validationResult.confidence.toFixed(2)} (threshold: ${effectiveThreshold})\n`);
|
|
718
839
|
}
|
|
719
840
|
catch (e) {
|
|
720
|
-
validationResult = this.simpleQualityCheck(fullDrafterContent);
|
|
721
|
-
validationResult.passed = validationResult.confidence >= effectiveThreshold;
|
|
841
|
+
validationResult = this.simpleQualityCheck(fullDrafterContent, effectiveThreshold);
|
|
722
842
|
}
|
|
723
843
|
}
|
|
724
844
|
else {
|
|
725
|
-
validationResult = this.simpleQualityCheck(fullDrafterContent);
|
|
726
|
-
validationResult.passed = validationResult.confidence >= effectiveThreshold;
|
|
845
|
+
validationResult = this.simpleQualityCheck(fullDrafterContent, effectiveThreshold);
|
|
727
846
|
}
|
|
728
847
|
if (validationResult.passed) {
|
|
729
848
|
await runManager?.handleText(`✅ Quality check passed - cascade complete (${modelType} accepted)\n`);
|
|
@@ -764,6 +883,7 @@ class CascadeChatModel extends chat_models_1.BaseChatModel {
|
|
|
764
883
|
}
|
|
765
884
|
}
|
|
766
885
|
}
|
|
886
|
+
exports.CascadeChatModel = CascadeChatModel;
|
|
767
887
|
// =============================================================================
|
|
768
888
|
// Generate dynamic inputs based on enabled domains
|
|
769
889
|
// =============================================================================
|
|
@@ -785,7 +905,7 @@ function generateDomainInputs(enabledDomains) {
|
|
|
785
905
|
// Add domain-specific model inputs for each enabled domain
|
|
786
906
|
for (const domain of enabledDomains) {
|
|
787
907
|
baseInputs.push({
|
|
788
|
-
displayName: `${DOMAIN_DISPLAY_NAMES[domain]} Model`,
|
|
908
|
+
displayName: `${config_1.DOMAIN_DISPLAY_NAMES[domain]} Model`,
|
|
789
909
|
type: 'ai_languageModel',
|
|
790
910
|
maxConnections: 1,
|
|
791
911
|
required: false,
|
|
@@ -797,10 +917,18 @@ function generateDomainInputs(enabledDomains) {
|
|
|
797
917
|
// Generate domain toggle properties for n8n UI
|
|
798
918
|
// =============================================================================
|
|
799
919
|
function generateDomainProperties() {
|
|
800
|
-
const domainOptions = Object.entries(DOMAINS).map(([key, value]) => ({
|
|
801
|
-
name: DOMAIN_DISPLAY_NAMES[value],
|
|
920
|
+
const domainOptions = Object.entries(config_1.DOMAINS).map(([key, value]) => ({
|
|
921
|
+
name: config_1.DOMAIN_DISPLAY_NAMES[value],
|
|
802
922
|
value: value,
|
|
803
|
-
description: DOMAIN_DESCRIPTIONS[value],
|
|
923
|
+
description: config_1.DOMAIN_DESCRIPTIONS[value],
|
|
924
|
+
}));
|
|
925
|
+
const domainToggleProperties = config_1.DOMAIN_UI_CONFIGS.map(({ domain, toggleName }) => ({
|
|
926
|
+
displayName: `Enable ${config_1.DOMAIN_DISPLAY_NAMES[domain]} Domain`,
|
|
927
|
+
name: toggleName,
|
|
928
|
+
type: 'boolean',
|
|
929
|
+
default: false,
|
|
930
|
+
displayOptions: { show: { enableDomainRouting: [true] } },
|
|
931
|
+
description: `Whether to enable ${config_1.DOMAIN_DESCRIPTIONS[domain]}. When enabled, adds a "${config_1.DOMAIN_DISPLAY_NAMES[domain]} Model" input port.`,
|
|
804
932
|
}));
|
|
805
933
|
return [
|
|
806
934
|
{
|
|
@@ -811,70 +939,7 @@ function generateDomainProperties() {
|
|
|
811
939
|
description: 'Whether to enable intelligent routing based on detected query domain (math, code, legal, etc.)',
|
|
812
940
|
},
|
|
813
941
|
// Individual domain toggles - each one adds its own model input port
|
|
814
|
-
|
|
815
|
-
displayName: 'Enable Code Domain',
|
|
816
|
-
name: 'enableCodeDomain',
|
|
817
|
-
type: 'boolean',
|
|
818
|
-
default: false,
|
|
819
|
-
displayOptions: { show: { enableDomainRouting: [true] } },
|
|
820
|
-
description: 'Whether to enable code domain routing. When enabled, adds a "Code Model" input port.',
|
|
821
|
-
},
|
|
822
|
-
{
|
|
823
|
-
displayName: 'Enable Math Domain',
|
|
824
|
-
name: 'enableMathDomain',
|
|
825
|
-
type: 'boolean',
|
|
826
|
-
default: false,
|
|
827
|
-
displayOptions: { show: { enableDomainRouting: [true] } },
|
|
828
|
-
description: 'Whether to enable math domain routing. When enabled, adds a "Math Model" input port.',
|
|
829
|
-
},
|
|
830
|
-
{
|
|
831
|
-
displayName: 'Enable Data Domain',
|
|
832
|
-
name: 'enableDataDomain',
|
|
833
|
-
type: 'boolean',
|
|
834
|
-
default: false,
|
|
835
|
-
displayOptions: { show: { enableDomainRouting: [true] } },
|
|
836
|
-
description: 'Whether to enable data analysis domain routing. When enabled, adds a "Data Model" input port.',
|
|
837
|
-
},
|
|
838
|
-
{
|
|
839
|
-
displayName: 'Enable Creative Domain',
|
|
840
|
-
name: 'enableCreativeDomain',
|
|
841
|
-
type: 'boolean',
|
|
842
|
-
default: false,
|
|
843
|
-
displayOptions: { show: { enableDomainRouting: [true] } },
|
|
844
|
-
description: 'Whether to enable creative writing domain routing. When enabled, adds a "Creative Model" input port.',
|
|
845
|
-
},
|
|
846
|
-
{
|
|
847
|
-
displayName: 'Enable Legal Domain',
|
|
848
|
-
name: 'enableLegalDomain',
|
|
849
|
-
type: 'boolean',
|
|
850
|
-
default: false,
|
|
851
|
-
displayOptions: { show: { enableDomainRouting: [true] } },
|
|
852
|
-
description: 'Whether to enable legal domain routing. When enabled, adds a "Legal Model" input port.',
|
|
853
|
-
},
|
|
854
|
-
{
|
|
855
|
-
displayName: 'Enable Medical Domain',
|
|
856
|
-
name: 'enableMedicalDomain',
|
|
857
|
-
type: 'boolean',
|
|
858
|
-
default: false,
|
|
859
|
-
displayOptions: { show: { enableDomainRouting: [true] } },
|
|
860
|
-
description: 'Whether to enable medical domain routing. When enabled, adds a "Medical Model" input port.',
|
|
861
|
-
},
|
|
862
|
-
{
|
|
863
|
-
displayName: 'Enable Financial Domain',
|
|
864
|
-
name: 'enableFinancialDomain',
|
|
865
|
-
type: 'boolean',
|
|
866
|
-
default: false,
|
|
867
|
-
displayOptions: { show: { enableDomainRouting: [true] } },
|
|
868
|
-
description: 'Whether to enable financial domain routing. When enabled, adds a "Financial Model" input port.',
|
|
869
|
-
},
|
|
870
|
-
{
|
|
871
|
-
displayName: 'Enable Science Domain',
|
|
872
|
-
name: 'enableScienceDomain',
|
|
873
|
-
type: 'boolean',
|
|
874
|
-
default: false,
|
|
875
|
-
displayOptions: { show: { enableDomainRouting: [true] } },
|
|
876
|
-
description: 'Whether to enable science domain routing. When enabled, adds a "Science Model" input port.',
|
|
877
|
-
},
|
|
942
|
+
...domainToggleProperties,
|
|
878
943
|
{
|
|
879
944
|
displayName: 'Domain-Specific Settings',
|
|
880
945
|
name: 'domainSettings',
|
|
@@ -905,7 +970,7 @@ function generateDomainProperties() {
|
|
|
905
970
|
displayName: 'Quality Threshold',
|
|
906
971
|
name: 'threshold',
|
|
907
972
|
type: 'number',
|
|
908
|
-
default: 0.
|
|
973
|
+
default: 0.4,
|
|
909
974
|
typeOptions: {
|
|
910
975
|
minValue: 0,
|
|
911
976
|
maxValue: 1,
|
|
@@ -980,26 +1045,50 @@ class LmChatCascadeFlow {
|
|
|
980
1045
|
if (params?.enableCodeDomain) {
|
|
981
1046
|
inputs.push({ displayName: 'Code', type: 'ai_languageModel', maxConnections: 1, required: false });
|
|
982
1047
|
}
|
|
983
|
-
if (params?.enableMathDomain) {
|
|
984
|
-
inputs.push({ displayName: 'Math', type: 'ai_languageModel', maxConnections: 1, required: false });
|
|
985
|
-
}
|
|
986
1048
|
if (params?.enableDataDomain) {
|
|
987
|
-
inputs.push({ displayName: 'Data', type: 'ai_languageModel', maxConnections: 1, required: false });
|
|
1049
|
+
inputs.push({ displayName: 'Data Analysis', type: 'ai_languageModel', maxConnections: 1, required: false });
|
|
1050
|
+
}
|
|
1051
|
+
if (params?.enableStructuredDomain) {
|
|
1052
|
+
inputs.push({ displayName: 'Structured Output', type: 'ai_languageModel', maxConnections: 1, required: false });
|
|
1053
|
+
}
|
|
1054
|
+
if (params?.enableRagDomain) {
|
|
1055
|
+
inputs.push({ displayName: 'RAG (Retrieval)', type: 'ai_languageModel', maxConnections: 1, required: false });
|
|
1056
|
+
}
|
|
1057
|
+
if (params?.enableConversationDomain) {
|
|
1058
|
+
inputs.push({ displayName: 'Conversation', type: 'ai_languageModel', maxConnections: 1, required: false });
|
|
1059
|
+
}
|
|
1060
|
+
if (params?.enableToolDomain) {
|
|
1061
|
+
inputs.push({ displayName: 'Tool Calling', type: 'ai_languageModel', maxConnections: 1, required: false });
|
|
988
1062
|
}
|
|
989
1063
|
if (params?.enableCreativeDomain) {
|
|
990
1064
|
inputs.push({ displayName: 'Creative', type: 'ai_languageModel', maxConnections: 1, required: false });
|
|
991
1065
|
}
|
|
992
|
-
if (params?.
|
|
993
|
-
inputs.push({ displayName: '
|
|
1066
|
+
if (params?.enableSummaryDomain) {
|
|
1067
|
+
inputs.push({ displayName: 'Summary', type: 'ai_languageModel', maxConnections: 1, required: false });
|
|
1068
|
+
}
|
|
1069
|
+
if (params?.enableTranslationDomain) {
|
|
1070
|
+
inputs.push({ displayName: 'Translation', type: 'ai_languageModel', maxConnections: 1, required: false });
|
|
1071
|
+
}
|
|
1072
|
+
if (params?.enableMathDomain) {
|
|
1073
|
+
inputs.push({ displayName: 'Math', type: 'ai_languageModel', maxConnections: 1, required: false });
|
|
1074
|
+
}
|
|
1075
|
+
if (params?.enableScienceDomain) {
|
|
1076
|
+
inputs.push({ displayName: 'Science', type: 'ai_languageModel', maxConnections: 1, required: false });
|
|
994
1077
|
}
|
|
995
1078
|
if (params?.enableMedicalDomain) {
|
|
996
1079
|
inputs.push({ displayName: 'Medical', type: 'ai_languageModel', maxConnections: 1, required: false });
|
|
997
1080
|
}
|
|
1081
|
+
if (params?.enableLegalDomain) {
|
|
1082
|
+
inputs.push({ displayName: 'Legal', type: 'ai_languageModel', maxConnections: 1, required: false });
|
|
1083
|
+
}
|
|
998
1084
|
if (params?.enableFinancialDomain) {
|
|
999
1085
|
inputs.push({ displayName: 'Financial', type: 'ai_languageModel', maxConnections: 1, required: false });
|
|
1000
1086
|
}
|
|
1001
|
-
if (params?.
|
|
1002
|
-
inputs.push({ displayName: '
|
|
1087
|
+
if (params?.enableMultimodalDomain) {
|
|
1088
|
+
inputs.push({ displayName: 'Multimodal', type: 'ai_languageModel', maxConnections: 1, required: false });
|
|
1089
|
+
}
|
|
1090
|
+
if (params?.enableGeneralDomain) {
|
|
1091
|
+
inputs.push({ displayName: 'General', type: 'ai_languageModel', maxConnections: 1, required: false });
|
|
1003
1092
|
}
|
|
1004
1093
|
}
|
|
1005
1094
|
|
|
@@ -1013,13 +1102,85 @@ class LmChatCascadeFlow {
|
|
|
1013
1102
|
displayName: 'Quality Threshold',
|
|
1014
1103
|
name: 'qualityThreshold',
|
|
1015
1104
|
type: 'number',
|
|
1016
|
-
default: 0.
|
|
1105
|
+
default: 0.4,
|
|
1106
|
+
typeOptions: {
|
|
1107
|
+
minValue: 0,
|
|
1108
|
+
maxValue: 1,
|
|
1109
|
+
numberPrecision: 2,
|
|
1110
|
+
},
|
|
1111
|
+
description: 'Minimum quality score (0-1) to accept drafter response when complexity thresholds are disabled',
|
|
1112
|
+
},
|
|
1113
|
+
{
|
|
1114
|
+
displayName: 'Use Complexity Thresholds',
|
|
1115
|
+
name: 'useComplexityThresholds',
|
|
1116
|
+
type: 'boolean',
|
|
1117
|
+
default: true,
|
|
1118
|
+
description: 'Whether to use per-complexity confidence thresholds (trivial → expert) to match CascadeFlow Python defaults',
|
|
1119
|
+
},
|
|
1120
|
+
{
|
|
1121
|
+
displayName: 'Trivial Threshold',
|
|
1122
|
+
name: 'trivialThreshold',
|
|
1123
|
+
type: 'number',
|
|
1124
|
+
default: 0.25,
|
|
1125
|
+
displayOptions: { show: { useComplexityThresholds: [true] } },
|
|
1017
1126
|
typeOptions: {
|
|
1018
1127
|
minValue: 0,
|
|
1019
1128
|
maxValue: 1,
|
|
1020
1129
|
numberPrecision: 2,
|
|
1021
1130
|
},
|
|
1022
|
-
description: 'Minimum
|
|
1131
|
+
description: 'Minimum confidence for trivial queries',
|
|
1132
|
+
},
|
|
1133
|
+
{
|
|
1134
|
+
displayName: 'Simple Threshold',
|
|
1135
|
+
name: 'simpleThreshold',
|
|
1136
|
+
type: 'number',
|
|
1137
|
+
default: 0.4,
|
|
1138
|
+
displayOptions: { show: { useComplexityThresholds: [true] } },
|
|
1139
|
+
typeOptions: {
|
|
1140
|
+
minValue: 0,
|
|
1141
|
+
maxValue: 1,
|
|
1142
|
+
numberPrecision: 2,
|
|
1143
|
+
},
|
|
1144
|
+
description: 'Minimum confidence for simple queries',
|
|
1145
|
+
},
|
|
1146
|
+
{
|
|
1147
|
+
displayName: 'Moderate Threshold',
|
|
1148
|
+
name: 'moderateThreshold',
|
|
1149
|
+
type: 'number',
|
|
1150
|
+
default: 0.55,
|
|
1151
|
+
displayOptions: { show: { useComplexityThresholds: [true] } },
|
|
1152
|
+
typeOptions: {
|
|
1153
|
+
minValue: 0,
|
|
1154
|
+
maxValue: 1,
|
|
1155
|
+
numberPrecision: 2,
|
|
1156
|
+
},
|
|
1157
|
+
description: 'Minimum confidence for moderate queries',
|
|
1158
|
+
},
|
|
1159
|
+
{
|
|
1160
|
+
displayName: 'Hard Threshold',
|
|
1161
|
+
name: 'hardThreshold',
|
|
1162
|
+
type: 'number',
|
|
1163
|
+
default: 0.7,
|
|
1164
|
+
displayOptions: { show: { useComplexityThresholds: [true] } },
|
|
1165
|
+
typeOptions: {
|
|
1166
|
+
minValue: 0,
|
|
1167
|
+
maxValue: 1,
|
|
1168
|
+
numberPrecision: 2,
|
|
1169
|
+
},
|
|
1170
|
+
description: 'Minimum confidence for hard queries',
|
|
1171
|
+
},
|
|
1172
|
+
{
|
|
1173
|
+
displayName: 'Expert Threshold',
|
|
1174
|
+
name: 'expertThreshold',
|
|
1175
|
+
type: 'number',
|
|
1176
|
+
default: 0.8,
|
|
1177
|
+
displayOptions: { show: { useComplexityThresholds: [true] } },
|
|
1178
|
+
typeOptions: {
|
|
1179
|
+
minValue: 0,
|
|
1180
|
+
maxValue: 1,
|
|
1181
|
+
numberPrecision: 2,
|
|
1182
|
+
},
|
|
1183
|
+
description: 'Minimum confidence for expert queries',
|
|
1023
1184
|
},
|
|
1024
1185
|
{
|
|
1025
1186
|
displayName: 'Enable Alignment Scoring',
|
|
@@ -1035,13 +1196,6 @@ class LmChatCascadeFlow {
|
|
|
1035
1196
|
default: true,
|
|
1036
1197
|
description: 'Whether to route queries directly to the verifier based on detected complexity',
|
|
1037
1198
|
},
|
|
1038
|
-
{
|
|
1039
|
-
displayName: 'Enable Circuit Breaker',
|
|
1040
|
-
name: 'useCircuitBreaker',
|
|
1041
|
-
type: 'boolean',
|
|
1042
|
-
default: true,
|
|
1043
|
-
description: 'Whether to use circuit breaker for fault tolerance (auto-fallback on repeated failures)',
|
|
1044
|
-
},
|
|
1045
1199
|
// Domain routing settings
|
|
1046
1200
|
...generateDomainProperties(),
|
|
1047
1201
|
],
|
|
@@ -1049,41 +1203,30 @@ class LmChatCascadeFlow {
|
|
|
1049
1203
|
}
|
|
1050
1204
|
async supplyData() {
|
|
1051
1205
|
// Get core parameters
|
|
1052
|
-
const qualityThreshold = this.getNodeParameter('qualityThreshold', 0,
|
|
1206
|
+
const qualityThreshold = this.getNodeParameter('qualityThreshold', 0, config_1.DEFAULT_COMPLEXITY_THRESHOLDS.simple);
|
|
1053
1207
|
const useSemanticValidation = false; // Disabled - loads heavy ML model causing OOM in n8n
|
|
1054
1208
|
const useAlignmentScoring = this.getNodeParameter('useAlignmentScoring', 0, true);
|
|
1055
1209
|
const useComplexityRouting = this.getNodeParameter('useComplexityRouting', 0, true);
|
|
1056
|
-
const
|
|
1210
|
+
const useComplexityThresholds = this.getNodeParameter('useComplexityThresholds', 0, true);
|
|
1211
|
+
const confidenceThresholds = useComplexityThresholds
|
|
1212
|
+
? {
|
|
1213
|
+
trivial: this.getNodeParameter('trivialThreshold', 0, config_1.DEFAULT_COMPLEXITY_THRESHOLDS.trivial),
|
|
1214
|
+
simple: this.getNodeParameter('simpleThreshold', 0, config_1.DEFAULT_COMPLEXITY_THRESHOLDS.simple),
|
|
1215
|
+
moderate: this.getNodeParameter('moderateThreshold', 0, config_1.DEFAULT_COMPLEXITY_THRESHOLDS.moderate),
|
|
1216
|
+
hard: this.getNodeParameter('hardThreshold', 0, config_1.DEFAULT_COMPLEXITY_THRESHOLDS.hard),
|
|
1217
|
+
expert: this.getNodeParameter('expertThreshold', 0, config_1.DEFAULT_COMPLEXITY_THRESHOLDS.expert),
|
|
1218
|
+
}
|
|
1219
|
+
: undefined;
|
|
1057
1220
|
// Get domain routing parameters
|
|
1058
1221
|
const enableDomainRouting = this.getNodeParameter('enableDomainRouting', 0, false);
|
|
1059
1222
|
// Build enabledDomains array from individual toggle parameters
|
|
1060
1223
|
const enabledDomains = [];
|
|
1061
1224
|
if (enableDomainRouting) {
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
}
|
|
1066
|
-
if (this.getNodeParameter('enableMathDomain', 0, false)) {
|
|
1067
|
-
enabledDomains.push('math');
|
|
1068
|
-
}
|
|
1069
|
-
if (this.getNodeParameter('enableDataDomain', 0, false)) {
|
|
1070
|
-
enabledDomains.push('data');
|
|
1071
|
-
}
|
|
1072
|
-
if (this.getNodeParameter('enableCreativeDomain', 0, false)) {
|
|
1073
|
-
enabledDomains.push('creative');
|
|
1074
|
-
}
|
|
1075
|
-
if (this.getNodeParameter('enableLegalDomain', 0, false)) {
|
|
1076
|
-
enabledDomains.push('legal');
|
|
1077
|
-
}
|
|
1078
|
-
if (this.getNodeParameter('enableMedicalDomain', 0, false)) {
|
|
1079
|
-
enabledDomains.push('medical');
|
|
1080
|
-
}
|
|
1081
|
-
if (this.getNodeParameter('enableFinancialDomain', 0, false)) {
|
|
1082
|
-
enabledDomains.push('financial');
|
|
1083
|
-
}
|
|
1084
|
-
if (this.getNodeParameter('enableScienceDomain', 0, false)) {
|
|
1085
|
-
enabledDomains.push('science');
|
|
1225
|
+
const toggleParams = {};
|
|
1226
|
+
for (const { toggleName } of config_1.DOMAIN_UI_CONFIGS) {
|
|
1227
|
+
toggleParams[toggleName] = this.getNodeParameter(toggleName, 0, false);
|
|
1086
1228
|
}
|
|
1229
|
+
enabledDomains.push(...(0, config_1.getEnabledDomains)(toggleParams));
|
|
1087
1230
|
}
|
|
1088
1231
|
// Get domain-specific settings
|
|
1089
1232
|
const domainSettingsRaw = this.getNodeParameter('domainSettings', 0, { domainConfig: [] });
|
|
@@ -1097,12 +1240,15 @@ class LmChatCascadeFlow {
|
|
|
1097
1240
|
});
|
|
1098
1241
|
}
|
|
1099
1242
|
}
|
|
1100
|
-
//
|
|
1101
|
-
const
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1243
|
+
// Lazy loader for drafter (index 1 - bottom port, labeled "Drafter")
|
|
1244
|
+
const drafterModelGetter = async () => {
|
|
1245
|
+
const drafterData = await this.getInputConnectionData('ai_languageModel', 1);
|
|
1246
|
+
const drafterModel = (Array.isArray(drafterData) ? drafterData[0] : drafterData);
|
|
1247
|
+
if (!drafterModel) {
|
|
1248
|
+
throw new n8n_workflow_1.NodeOperationError(this.getNode(), 'Drafter model is required. Please connect your DRAFTER model to the BOTTOM port (labeled "Drafter").');
|
|
1249
|
+
}
|
|
1250
|
+
return drafterModel;
|
|
1251
|
+
};
|
|
1106
1252
|
// Create lazy loader for verifier (index 0 - top port, labeled "Verifier")
|
|
1107
1253
|
const verifierModelGetter = async () => {
|
|
1108
1254
|
const verifierData = await this.getInputConnectionData('ai_languageModel', 0);
|
|
@@ -1127,50 +1273,33 @@ class LmChatCascadeFlow {
|
|
|
1127
1273
|
try {
|
|
1128
1274
|
const domainData = await this.getInputConnectionData('ai_languageModel', domainIndex);
|
|
1129
1275
|
const domainModel = (Array.isArray(domainData) ? domainData[0] : domainData);
|
|
1130
|
-
|
|
1131
|
-
// Store in domain config
|
|
1132
|
-
const config = domainConfigs.get(domain) || {
|
|
1133
|
-
enabled: true,
|
|
1134
|
-
threshold: qualityThreshold,
|
|
1135
|
-
temperature: 0.7,
|
|
1136
|
-
};
|
|
1137
|
-
config.model = domainModel;
|
|
1138
|
-
domainConfigs.set(domain, config);
|
|
1139
|
-
return domainModel;
|
|
1140
|
-
}
|
|
1276
|
+
return domainModel || undefined;
|
|
1141
1277
|
}
|
|
1142
|
-
catch
|
|
1143
|
-
|
|
1278
|
+
catch {
|
|
1279
|
+
return undefined;
|
|
1144
1280
|
}
|
|
1145
1281
|
return undefined;
|
|
1146
1282
|
});
|
|
1147
1283
|
}
|
|
1148
1284
|
}
|
|
1149
|
-
// Eagerly load domain models
|
|
1150
|
-
for (const [domain, getter] of domainModelGetters.entries()) {
|
|
1151
|
-
await getter();
|
|
1152
|
-
}
|
|
1153
|
-
// Debug info
|
|
1154
|
-
const getDrafterInfo = () => {
|
|
1155
|
-
const type = typeof drafterModel._llmType === 'function' ? drafterModel._llmType() : 'unknown';
|
|
1156
|
-
const modelName = drafterModel.modelName || drafterModel.model || 'unknown';
|
|
1157
|
-
return `${type} (${modelName})`;
|
|
1158
|
-
};
|
|
1159
1285
|
console.log('🚀 CascadeFlow v2 initialized');
|
|
1160
1286
|
console.log(` PORT MAPPING:`);
|
|
1161
1287
|
console.log(` ├─ TOP port (labeled "Verifier") → VERIFIER model: lazy-loaded`);
|
|
1162
|
-
console.log(` └─ BOTTOM port (labeled "Drafter") → DRAFTER model:
|
|
1288
|
+
console.log(` └─ BOTTOM port (labeled "Drafter") → DRAFTER model: lazy-loaded`);
|
|
1163
1289
|
console.log(` Quality threshold: ${qualityThreshold}`);
|
|
1164
1290
|
console.log(` Semantic validation: ${useSemanticValidation ? 'enabled' : 'disabled'}`);
|
|
1165
1291
|
console.log(` Alignment scoring: ${useAlignmentScoring ? 'enabled' : 'disabled'}`);
|
|
1166
1292
|
console.log(` Complexity routing: ${useComplexityRouting ? 'enabled' : 'disabled'}`);
|
|
1167
|
-
console.log(`
|
|
1293
|
+
console.log(` Complexity thresholds: ${useComplexityThresholds ? 'enabled' : 'disabled'}`);
|
|
1168
1294
|
console.log(` Domain routing: ${enableDomainRouting ? 'enabled' : 'disabled'}`);
|
|
1169
1295
|
if (enabledDomains.length > 0) {
|
|
1170
1296
|
console.log(` Enabled domains: ${enabledDomains.join(', ')}`);
|
|
1171
1297
|
}
|
|
1298
|
+
if (useComplexityThresholds && confidenceThresholds) {
|
|
1299
|
+
console.log(` Thresholds: ${JSON.stringify(confidenceThresholds)}`);
|
|
1300
|
+
}
|
|
1172
1301
|
// Create and return the cascade model
|
|
1173
|
-
const cascadeModel = new CascadeChatModel(
|
|
1302
|
+
const cascadeModel = new CascadeChatModel(drafterModelGetter, verifierModelGetter, qualityThreshold, useSemanticValidation, useAlignmentScoring, useComplexityRouting, useComplexityThresholds, enableDomainRouting, enabledDomains, domainModelGetters, domainConfigs, confidenceThresholds);
|
|
1174
1303
|
return {
|
|
1175
1304
|
response: cascadeModel,
|
|
1176
1305
|
};
|