@lhi/n8m 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agentic/graph.d.ts +16 -0
- package/dist/agentic/nodes/architect.d.ts +1 -0
- package/dist/agentic/nodes/architect.js +9 -7
- package/dist/agentic/nodes/supervisor.d.ts +2 -0
- package/dist/agentic/nodes/supervisor.js +10 -8
- package/dist/agentic/state.d.ts +1 -0
- package/dist/agentic/state.js +5 -0
- package/dist/services/ai.service.d.ts +13 -0
- package/dist/services/ai.service.js +83 -0
- package/oclif.manifest.json +1 -1
- package/package.json +1 -1
package/dist/agentic/graph.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export declare const graph: import("@langchain/langgraph").CompiledStateGraph<{
|
|
|
12
12
|
strategies: any[];
|
|
13
13
|
candidates: any[];
|
|
14
14
|
customTools: Record<string, string>;
|
|
15
|
+
collaborationLog: string[];
|
|
15
16
|
}, {
|
|
16
17
|
userGoal?: string | undefined;
|
|
17
18
|
spec?: any;
|
|
@@ -25,6 +26,7 @@ export declare const graph: import("@langchain/langgraph").CompiledStateGraph<{
|
|
|
25
26
|
strategies?: any[] | undefined;
|
|
26
27
|
candidates?: any[] | undefined;
|
|
27
28
|
customTools?: Record<string, string> | undefined;
|
|
29
|
+
collaborationLog?: string[] | undefined;
|
|
28
30
|
}, "__start__" | "architect" | "engineer" | "reviewer" | "supervisor" | "qa", {
|
|
29
31
|
userGoal: {
|
|
30
32
|
(): import("@langchain/langgraph").LastValue<string>;
|
|
@@ -74,6 +76,7 @@ export declare const graph: import("@langchain/langgraph").CompiledStateGraph<{
|
|
|
74
76
|
};
|
|
75
77
|
candidates: import("@langchain/langgraph").BinaryOperatorAggregate<any[], any[]>;
|
|
76
78
|
customTools: import("@langchain/langgraph").BinaryOperatorAggregate<Record<string, string>, Record<string, string>>;
|
|
79
|
+
collaborationLog: import("@langchain/langgraph").BinaryOperatorAggregate<string[], string[]>;
|
|
77
80
|
}, {
|
|
78
81
|
userGoal: {
|
|
79
82
|
(): import("@langchain/langgraph").LastValue<string>;
|
|
@@ -123,11 +126,13 @@ export declare const graph: import("@langchain/langgraph").CompiledStateGraph<{
|
|
|
123
126
|
};
|
|
124
127
|
candidates: import("@langchain/langgraph").BinaryOperatorAggregate<any[], any[]>;
|
|
125
128
|
customTools: import("@langchain/langgraph").BinaryOperatorAggregate<Record<string, string>, Record<string, string>>;
|
|
129
|
+
collaborationLog: import("@langchain/langgraph").BinaryOperatorAggregate<string[], string[]>;
|
|
126
130
|
}, import("@langchain/langgraph").StateDefinition, {
|
|
127
131
|
architect: {
|
|
128
132
|
spec: any;
|
|
129
133
|
strategies: any[];
|
|
130
134
|
needsClarification: any;
|
|
135
|
+
collaborationLog: string[];
|
|
131
136
|
};
|
|
132
137
|
engineer: {
|
|
133
138
|
workflowJson: any;
|
|
@@ -188,11 +193,14 @@ export declare const graph: import("@langchain/langgraph").CompiledStateGraph<{
|
|
|
188
193
|
};
|
|
189
194
|
candidates: import("@langchain/langgraph").BinaryOperatorAggregate<any[], any[]>;
|
|
190
195
|
customTools: import("@langchain/langgraph").BinaryOperatorAggregate<Record<string, string>, Record<string, string>>;
|
|
196
|
+
collaborationLog: import("@langchain/langgraph").BinaryOperatorAggregate<string[], string[]>;
|
|
191
197
|
}>;
|
|
192
198
|
supervisor: {
|
|
193
199
|
workflowJson?: undefined;
|
|
200
|
+
collaborationLog?: undefined;
|
|
194
201
|
} | {
|
|
195
202
|
workflowJson: any;
|
|
203
|
+
collaborationLog: string[];
|
|
196
204
|
};
|
|
197
205
|
qa: import("@langchain/langgraph").UpdateType<{
|
|
198
206
|
userGoal: {
|
|
@@ -243,6 +251,7 @@ export declare const graph: import("@langchain/langgraph").CompiledStateGraph<{
|
|
|
243
251
|
};
|
|
244
252
|
candidates: import("@langchain/langgraph").BinaryOperatorAggregate<any[], any[]>;
|
|
245
253
|
customTools: import("@langchain/langgraph").BinaryOperatorAggregate<Record<string, string>, Record<string, string>>;
|
|
254
|
+
collaborationLog: import("@langchain/langgraph").BinaryOperatorAggregate<string[], string[]>;
|
|
246
255
|
}>;
|
|
247
256
|
}, unknown, unknown>;
|
|
248
257
|
/**
|
|
@@ -300,6 +309,7 @@ export declare const runAgenticWorkflow: (goal: string, initialState?: Partial<t
|
|
|
300
309
|
};
|
|
301
310
|
candidates: import("@langchain/langgraph").BinaryOperatorAggregate<any[], any[]>;
|
|
302
311
|
customTools: import("@langchain/langgraph").BinaryOperatorAggregate<Record<string, string>, Record<string, string>>;
|
|
312
|
+
collaborationLog: import("@langchain/langgraph").BinaryOperatorAggregate<string[], string[]>;
|
|
303
313
|
}>>;
|
|
304
314
|
/**
|
|
305
315
|
* Run the Agentic Workflow with Streaming
|
|
@@ -311,6 +321,7 @@ export declare const runAgenticWorkflowStream: (goal: string, threadId?: string)
|
|
|
311
321
|
spec: any;
|
|
312
322
|
strategies: any[];
|
|
313
323
|
needsClarification: any;
|
|
324
|
+
collaborationLog: string[];
|
|
314
325
|
} | undefined;
|
|
315
326
|
engineer?: {
|
|
316
327
|
workflowJson: any;
|
|
@@ -371,11 +382,14 @@ export declare const runAgenticWorkflowStream: (goal: string, threadId?: string)
|
|
|
371
382
|
};
|
|
372
383
|
candidates: import("@langchain/langgraph").BinaryOperatorAggregate<any[], any[]>;
|
|
373
384
|
customTools: import("@langchain/langgraph").BinaryOperatorAggregate<Record<string, string>, Record<string, string>>;
|
|
385
|
+
collaborationLog: import("@langchain/langgraph").BinaryOperatorAggregate<string[], string[]>;
|
|
374
386
|
}> | undefined;
|
|
375
387
|
supervisor?: {
|
|
376
388
|
workflowJson?: undefined;
|
|
389
|
+
collaborationLog?: undefined;
|
|
377
390
|
} | {
|
|
378
391
|
workflowJson: any;
|
|
392
|
+
collaborationLog: string[];
|
|
379
393
|
} | undefined;
|
|
380
394
|
qa?: import("@langchain/langgraph").UpdateType<{
|
|
381
395
|
userGoal: {
|
|
@@ -426,6 +440,7 @@ export declare const runAgenticWorkflowStream: (goal: string, threadId?: string)
|
|
|
426
440
|
};
|
|
427
441
|
candidates: import("@langchain/langgraph").BinaryOperatorAggregate<any[], any[]>;
|
|
428
442
|
customTools: import("@langchain/langgraph").BinaryOperatorAggregate<Record<string, string>, Record<string, string>>;
|
|
443
|
+
collaborationLog: import("@langchain/langgraph").BinaryOperatorAggregate<string[], string[]>;
|
|
429
444
|
}> | undefined;
|
|
430
445
|
}>>;
|
|
431
446
|
/**
|
|
@@ -480,4 +495,5 @@ export declare const resumeAgenticWorkflow: (threadId: string, input?: any) => P
|
|
|
480
495
|
};
|
|
481
496
|
candidates: import("@langchain/langgraph").BinaryOperatorAggregate<any[], any[]>;
|
|
482
497
|
customTools: import("@langchain/langgraph").BinaryOperatorAggregate<Record<string, string>, Record<string, string>>;
|
|
498
|
+
collaborationLog: import("@langchain/langgraph").BinaryOperatorAggregate<string[], string[]>;
|
|
483
499
|
}>>;
|
|
@@ -30,18 +30,20 @@ export const architectNode = async (state) => {
|
|
|
30
30
|
// Check if the spec requires clarification
|
|
31
31
|
const questions = spec.questions;
|
|
32
32
|
const needsClarification = questions && questions.length > 0;
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
|
|
33
|
+
// Multi-agent collaboration: generate an alternative strategy in parallel with the primary.
|
|
34
|
+
// Both are handed off to separate Engineer agents that run concurrently.
|
|
35
|
+
const alternativeSpec = await aiService.generateAlternativeSpec(state.userGoal, spec);
|
|
36
36
|
const strategies = [
|
|
37
|
-
{ ...spec,
|
|
38
|
-
|
|
39
|
-
// { ...spec, name: "Alternative Strategy (Robust)" }
|
|
37
|
+
{ ...spec, strategyName: "Primary Strategy" },
|
|
38
|
+
{ ...alternativeSpec, strategyName: "Alternative Strategy" },
|
|
40
39
|
];
|
|
40
|
+
const logEntry = `Architect: Generated 2 strategies — "${strategies[0].suggestedName}" (primary) and "${strategies[1].suggestedName}" (alternative)`;
|
|
41
|
+
console.log(`[Architect] ${logEntry}`);
|
|
41
42
|
return {
|
|
42
|
-
spec,
|
|
43
|
+
spec,
|
|
43
44
|
strategies,
|
|
44
45
|
needsClarification,
|
|
46
|
+
collaborationLog: [logEntry],
|
|
45
47
|
};
|
|
46
48
|
}
|
|
47
49
|
catch (error) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { AIService } from "../../services/ai.service.js";
|
|
1
2
|
import { theme } from "../../utils/theme.js";
|
|
2
3
|
export const supervisorNode = async (state) => {
|
|
3
4
|
const candidates = state.candidates;
|
|
@@ -5,14 +6,15 @@ export const supervisorNode = async (state) => {
|
|
|
5
6
|
// Fallback: use existing workflowJson if available
|
|
6
7
|
return {};
|
|
7
8
|
}
|
|
8
|
-
console.log(theme.agent(`Supervisor
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
console.log(theme.success(`Supervisor selected: ${bestCandidate.name || "Unnamed Workflow"}`));
|
|
14
|
-
|
|
9
|
+
console.log(theme.agent(`Supervisor evaluating ${candidates.length} candidate(s)...`));
|
|
10
|
+
const aiService = AIService.getInstance();
|
|
11
|
+
const evaluation = await aiService.evaluateCandidates(state.userGoal, candidates);
|
|
12
|
+
const bestCandidate = candidates[evaluation.selectedIndex] ?? candidates[0];
|
|
13
|
+
const logEntry = `Supervisor: Selected candidate ${evaluation.selectedIndex + 1}/${candidates.length} ("${bestCandidate.name || 'Unnamed'}"). Reason: ${evaluation.reason}`;
|
|
14
|
+
console.log(theme.success(`Supervisor selected: ${bestCandidate.name || "Unnamed Workflow"} (candidate ${evaluation.selectedIndex + 1})`));
|
|
15
|
+
console.log(theme.agent(` → ${evaluation.reason}`));
|
|
15
16
|
return {
|
|
16
|
-
workflowJson: bestCandidate
|
|
17
|
+
workflowJson: bestCandidate,
|
|
18
|
+
collaborationLog: [logEntry],
|
|
17
19
|
};
|
|
18
20
|
};
|
package/dist/agentic/state.d.ts
CHANGED
|
@@ -48,4 +48,5 @@ export declare const TeamState: import("@langchain/langgraph").AnnotationRoot<{
|
|
|
48
48
|
};
|
|
49
49
|
candidates: import("@langchain/langgraph").BinaryOperatorAggregate<any[], any[]>;
|
|
50
50
|
customTools: import("@langchain/langgraph").BinaryOperatorAggregate<Record<string, string>, Record<string, string>>;
|
|
51
|
+
collaborationLog: import("@langchain/langgraph").BinaryOperatorAggregate<string[], string[]>;
|
|
51
52
|
}>;
|
package/dist/agentic/state.js
CHANGED
|
@@ -23,4 +23,9 @@ export const TeamState = Annotation.Root({
|
|
|
23
23
|
reducer: (x, y) => ({ ...x, ...y }),
|
|
24
24
|
default: () => ({}),
|
|
25
25
|
}),
|
|
26
|
+
// Collaboration Log: agents record their reasoning for visibility
|
|
27
|
+
collaborationLog: Annotation({
|
|
28
|
+
reducer: (x, y) => x.concat(y),
|
|
29
|
+
default: () => [],
|
|
30
|
+
}),
|
|
26
31
|
});
|
|
@@ -44,6 +44,19 @@ export declare class AIService {
|
|
|
44
44
|
* Force-fix connection structure to prevent "object is not iterable" errors
|
|
45
45
|
*/
|
|
46
46
|
private fixN8nConnections;
|
|
47
|
+
/**
|
|
48
|
+
* Generate an alternative workflow specification with a different approach to the same goal.
|
|
49
|
+
* Used by the Architect node to produce a second strategy for parallel Engineer execution.
|
|
50
|
+
*/
|
|
51
|
+
generateAlternativeSpec(goal: string, primarySpec: any): Promise<any>;
|
|
52
|
+
/**
|
|
53
|
+
* Evaluate multiple workflow candidates and select the best one for the given goal.
|
|
54
|
+
* Used by the Supervisor node to choose between parallel Engineer outputs.
|
|
55
|
+
*/
|
|
56
|
+
evaluateCandidates(goal: string, candidates: any[]): Promise<{
|
|
57
|
+
selectedIndex: number;
|
|
58
|
+
reason: string;
|
|
59
|
+
}>;
|
|
47
60
|
/**
|
|
48
61
|
* Validate against real node types and shim unknown ones
|
|
49
62
|
*/
|
|
@@ -370,6 +370,89 @@ export class AIService {
|
|
|
370
370
|
workflow.connections = fixedConnections;
|
|
371
371
|
return workflow;
|
|
372
372
|
}
|
|
373
|
+
/**
|
|
374
|
+
* Generate an alternative workflow specification with a different approach to the same goal.
|
|
375
|
+
* Used by the Architect node to produce a second strategy for parallel Engineer execution.
|
|
376
|
+
*/
|
|
377
|
+
async generateAlternativeSpec(goal, primarySpec) {
|
|
378
|
+
const prompt = `You are an n8n Solutions Architect exploring alternative workflow designs.
|
|
379
|
+
|
|
380
|
+
A primary solution already exists for this goal. Your task is to design a DIFFERENT approach that achieves the same result.
|
|
381
|
+
|
|
382
|
+
Goal: ${goal}
|
|
383
|
+
|
|
384
|
+
Primary Specification (for reference — design something DIFFERENT):
|
|
385
|
+
${JSON.stringify(primarySpec, null, 2)}
|
|
386
|
+
|
|
387
|
+
Create an alternative approach that:
|
|
388
|
+
- Uses DIFFERENT n8n nodes or integrations where possible
|
|
389
|
+
- May take a simpler, more minimal path OR a more robust, comprehensive one
|
|
390
|
+
- Achieves the SAME end goal
|
|
391
|
+
|
|
392
|
+
Output ONLY valid JSON with this structure:
|
|
393
|
+
{
|
|
394
|
+
"goal": "...",
|
|
395
|
+
"suggestedName": "...",
|
|
396
|
+
"tasks": [...],
|
|
397
|
+
"nodes": [...],
|
|
398
|
+
"assumptions": [...],
|
|
399
|
+
"questions": [],
|
|
400
|
+
"strategyType": "alternative"
|
|
401
|
+
}`;
|
|
402
|
+
const response = await this.generateContent(prompt, { temperature: 0.9 });
|
|
403
|
+
let cleanJson = response || '{}';
|
|
404
|
+
cleanJson = cleanJson.replace(/```json\n?|\n?```/g, '').trim();
|
|
405
|
+
try {
|
|
406
|
+
return JSON.parse(cleanJson);
|
|
407
|
+
}
|
|
408
|
+
catch {
|
|
409
|
+
console.warn('[AIService] Failed to parse alternative spec, falling back to primary variant');
|
|
410
|
+
return { ...primarySpec, suggestedName: `${primarySpec.suggestedName} (Alt)`, strategyType: 'alternative' };
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Evaluate multiple workflow candidates and select the best one for the given goal.
|
|
415
|
+
* Used by the Supervisor node to choose between parallel Engineer outputs.
|
|
416
|
+
*/
|
|
417
|
+
async evaluateCandidates(goal, candidates) {
|
|
418
|
+
if (candidates.length <= 1) {
|
|
419
|
+
return { selectedIndex: 0, reason: 'Single candidate — no evaluation needed.' };
|
|
420
|
+
}
|
|
421
|
+
const candidateSummaries = candidates.map((c, i) => {
|
|
422
|
+
const nodeNames = c?.nodes?.map((n) => n.name || n.type).join(', ') || 'unknown nodes';
|
|
423
|
+
return `Candidate ${i + 1}: "${c?.name || 'Unnamed'}" — Nodes: [${nodeNames}]`;
|
|
424
|
+
}).join('\n');
|
|
425
|
+
const prompt = `You are an n8n Solutions Architect evaluating workflow implementations.
|
|
426
|
+
|
|
427
|
+
Goal: ${goal}
|
|
428
|
+
|
|
429
|
+
Evaluate these ${candidates.length} candidate workflows and select the BEST one:
|
|
430
|
+
${candidateSummaries}
|
|
431
|
+
|
|
432
|
+
Select the best candidate based on:
|
|
433
|
+
1. Completeness — does it fully achieve the goal?
|
|
434
|
+
2. Node quality — are the nodes standard and appropriate?
|
|
435
|
+
3. Simplicity — is it appropriately complex (not over-engineered)?
|
|
436
|
+
4. Data flow — is the logic sound?
|
|
437
|
+
|
|
438
|
+
Output ONLY valid JSON:
|
|
439
|
+
{ "selectedIndex": <0-based integer>, "reason": "<1-2 sentence explanation>" }`;
|
|
440
|
+
const response = await this.generateContent(prompt, { temperature: 0.3 });
|
|
441
|
+
let cleanJson = response || '{}';
|
|
442
|
+
cleanJson = cleanJson.replace(/```json\n?|\n?```/g, '').trim();
|
|
443
|
+
try {
|
|
444
|
+
const result = JSON.parse(cleanJson);
|
|
445
|
+
const idx = typeof result.selectedIndex === 'number' ? result.selectedIndex : 0;
|
|
446
|
+
return {
|
|
447
|
+
selectedIndex: Math.max(0, Math.min(idx, candidates.length - 1)),
|
|
448
|
+
reason: result.reason || 'Best overall candidate.',
|
|
449
|
+
};
|
|
450
|
+
}
|
|
451
|
+
catch {
|
|
452
|
+
console.warn('[AIService] Failed to parse candidate evaluation, defaulting to index 0');
|
|
453
|
+
return { selectedIndex: 0, reason: 'Evaluation failed, defaulting to first candidate.' };
|
|
454
|
+
}
|
|
455
|
+
}
|
|
373
456
|
/**
|
|
374
457
|
* Validate against real node types and shim unknown ones
|
|
375
458
|
*/
|
package/oclif.manifest.json
CHANGED