@agentforge/patterns 0.16.91 → 0.17.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 +10 -3
- package/dist/index.cjs +292 -115
- package/dist/index.d.cts +42 -20
- package/dist/index.d.ts +42 -20
- package/dist/index.js +290 -115
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -84,7 +84,7 @@ The Multi-Agent pattern coordinates multiple specialized agents for complex task
|
|
|
84
84
|
- Flexible routing strategies (LLM-based, skill-based, rule-based, round-robin, load-balanced)
|
|
85
85
|
- Parallel execution support
|
|
86
86
|
- Intelligent result aggregation
|
|
87
|
-
-
|
|
87
|
+
- Fixed Worker topology construction before compilation
|
|
88
88
|
- **22+ tests** - Comprehensive coverage
|
|
89
89
|
|
|
90
90
|
## Installation
|
|
@@ -418,6 +418,7 @@ import {
|
|
|
418
418
|
```typescript
|
|
419
419
|
import {
|
|
420
420
|
createMultiAgentSystem,
|
|
421
|
+
createWorkersRegistry,
|
|
421
422
|
registerWorkers,
|
|
422
423
|
createSupervisorNode,
|
|
423
424
|
createWorkerNode,
|
|
@@ -428,7 +429,14 @@ import {
|
|
|
428
429
|
**Main API**:
|
|
429
430
|
- `createMultiAgentSystem(config)` - Create a complete Multi-Agent system
|
|
430
431
|
- `MultiAgentSystemBuilder` - Builder for creating Multi-Agent systems with workers
|
|
431
|
-
- `
|
|
432
|
+
- `createWorkersRegistry(workers)` - Construct detached, normalized Worker registry records containing declared capabilities and invocation status without admitting Workers or creating graph topology
|
|
433
|
+
- `registerWorkers(system, workers)` - Deprecated adapter that updates routing skills for known Workers; supplied tools must match the compiled executable tool set
|
|
434
|
+
|
|
435
|
+
Worker identities and executable tools are fixed when the Multi-Agent System is
|
|
436
|
+
compiled. The builder's `registerWorkers(workers)` method constructs that topology
|
|
437
|
+
before `build()`. The deprecated `registerWorkers(system, workers)` adapter does
|
|
438
|
+
not add executable Worker nodes: it may update routing skills for known Workers,
|
|
439
|
+
and those updates are visible only to later executions.
|
|
432
440
|
|
|
433
441
|
**Configuration**:
|
|
434
442
|
```typescript
|
|
@@ -540,4 +548,3 @@ pnpm typecheck
|
|
|
540
548
|
## License
|
|
541
549
|
|
|
542
550
|
MIT © 2026 Tom Van Schoor
|
|
543
|
-
|
package/dist/index.cjs
CHANGED
|
@@ -71,6 +71,7 @@ __export(index_exports, {
|
|
|
71
71
|
ToolCallSchema: () => ToolCallSchema,
|
|
72
72
|
ToolResultSchema: () => ToolResultSchema,
|
|
73
73
|
WorkerCapabilitiesSchema: () => WorkerCapabilitiesSchema,
|
|
74
|
+
WorkerLifecycleError: () => WorkerLifecycleError,
|
|
74
75
|
buildDeduplicationMetrics: () => buildDeduplicationMetrics,
|
|
75
76
|
calculateDeduplicationSavings: () => calculateDeduplicationSavings,
|
|
76
77
|
createAggregatorNode: () => createAggregatorNode,
|
|
@@ -90,6 +91,7 @@ __export(index_exports, {
|
|
|
90
91
|
createReviserNode: () => createReviserNode,
|
|
91
92
|
createSupervisorNode: () => createSupervisorNode,
|
|
92
93
|
createWorkerNode: () => createWorkerNode,
|
|
94
|
+
createWorkersRegistry: () => createWorkersRegistry,
|
|
93
95
|
generateToolCallCacheKey: () => generateToolCallCacheKey,
|
|
94
96
|
getRoutingStrategy: () => getRoutingStrategy,
|
|
95
97
|
llmBasedRouting: () => llmBasedRouting,
|
|
@@ -431,9 +433,9 @@ function stringifyActionArguments(arguments_) {
|
|
|
431
433
|
function getLatestThought(thoughts) {
|
|
432
434
|
return thoughts[thoughts.length - 1]?.content ?? "";
|
|
433
435
|
}
|
|
434
|
-
function debugIfVerbose(
|
|
436
|
+
function debugIfVerbose(logger7, verbose, message, data) {
|
|
435
437
|
if (verbose) {
|
|
436
|
-
|
|
438
|
+
logger7.debug(message, data);
|
|
437
439
|
}
|
|
438
440
|
}
|
|
439
441
|
|
|
@@ -2265,10 +2267,7 @@ var MultiAgentStateConfig = {
|
|
|
2265
2267
|
*/
|
|
2266
2268
|
workers: {
|
|
2267
2269
|
schema: import_zod13.z.record(import_zod13.z.string(), WorkerCapabilitiesSchema),
|
|
2268
|
-
reducer: (
|
|
2269
|
-
...left,
|
|
2270
|
-
...right
|
|
2271
|
-
}),
|
|
2270
|
+
reducer: (_left, right) => right,
|
|
2272
2271
|
default: () => ({}),
|
|
2273
2272
|
description: "Available worker agents and their capabilities"
|
|
2274
2273
|
},
|
|
@@ -3477,163 +3476,295 @@ function createWorkerNode(config) {
|
|
|
3477
3476
|
// src/multi-agent/agent-graph.ts
|
|
3478
3477
|
var import_langgraph4 = require("@langchain/langgraph");
|
|
3479
3478
|
|
|
3480
|
-
// src/multi-agent/
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3479
|
+
// src/multi-agent/worker-lifecycle.ts
|
|
3480
|
+
var WorkerLifecycleError = class extends Error {
|
|
3481
|
+
reason;
|
|
3482
|
+
constructor(reason, message) {
|
|
3483
|
+
super(message);
|
|
3484
|
+
this.name = "WorkerLifecycleError";
|
|
3485
|
+
this.reason = reason;
|
|
3484
3486
|
}
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3487
|
+
};
|
|
3488
|
+
var workerLifecycles = /* @__PURE__ */ new WeakMap();
|
|
3489
|
+
function normalizeToolName(tool, workerId, index) {
|
|
3490
|
+
const candidate = tool && typeof tool === "object" ? tool : void 0;
|
|
3491
|
+
const rawName = candidate?.metadata?.name ?? candidate?.name;
|
|
3492
|
+
const name = typeof rawName === "string" ? rawName.trim() : "";
|
|
3493
|
+
if (!name) {
|
|
3494
|
+
throw new WorkerLifecycleError(
|
|
3495
|
+
"invalid-tool",
|
|
3496
|
+
`Worker "${workerId}" has a nameless tool at index ${index}.`
|
|
3497
|
+
);
|
|
3488
3498
|
}
|
|
3489
|
-
|
|
3490
|
-
|
|
3499
|
+
return name;
|
|
3500
|
+
}
|
|
3501
|
+
function normalizeWorkerToolNames(workerId, tools) {
|
|
3502
|
+
const toolNames = (tools ?? []).map((tool, index) => normalizeToolName(tool, workerId, index));
|
|
3503
|
+
const uniqueToolNames = new Set(toolNames);
|
|
3504
|
+
if (uniqueToolNames.size !== toolNames.length) {
|
|
3505
|
+
throw new WorkerLifecycleError(
|
|
3506
|
+
"invalid-tool",
|
|
3507
|
+
`Worker "${workerId}" has duplicate normalized tool names.`
|
|
3508
|
+
);
|
|
3491
3509
|
}
|
|
3492
|
-
return
|
|
3510
|
+
return Object.freeze(toolNames);
|
|
3493
3511
|
}
|
|
3494
|
-
function
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3512
|
+
function validateIdentities(workers) {
|
|
3513
|
+
for (const worker of workers) {
|
|
3514
|
+
if (!worker.id || worker.id.trim() !== worker.id || worker.id.includes(",")) {
|
|
3515
|
+
throw new WorkerLifecycleError(
|
|
3516
|
+
"invalid-identity",
|
|
3517
|
+
`Worker identity "${worker.id}" must be non-empty, trimmed, and comma-free.`
|
|
3518
|
+
);
|
|
3519
|
+
}
|
|
3520
|
+
}
|
|
3521
|
+
const identities = /* @__PURE__ */ new Set();
|
|
3522
|
+
for (const worker of workers) {
|
|
3523
|
+
if (identities.has(worker.id)) {
|
|
3524
|
+
throw new WorkerLifecycleError(
|
|
3525
|
+
"duplicate-identity",
|
|
3526
|
+
`Worker identity "${worker.id}" appears more than once in the Worker batch.`
|
|
3527
|
+
);
|
|
3528
|
+
}
|
|
3529
|
+
identities.add(worker.id);
|
|
3530
|
+
}
|
|
3501
3531
|
}
|
|
3502
|
-
function
|
|
3532
|
+
function normalizeWorkerDeclaredCapabilities(workerId, capabilities, tools) {
|
|
3503
3533
|
return {
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
model: worker.model || fallbackModel,
|
|
3507
|
-
tools: worker.tools,
|
|
3508
|
-
systemPrompt: worker.systemPrompt
|
|
3534
|
+
skills: Object.freeze([...capabilities.skills]),
|
|
3535
|
+
tools: normalizeWorkerToolNames(workerId, tools)
|
|
3509
3536
|
};
|
|
3510
3537
|
}
|
|
3511
|
-
|
|
3512
|
-
// src/multi-agent/agent-runtime.ts
|
|
3513
|
-
function mergeWorkers(input, workerCapabilities) {
|
|
3538
|
+
function normalizeWorkerStatus(capabilities) {
|
|
3514
3539
|
return {
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
...workerCapabilities,
|
|
3518
|
-
...input.workers || {}
|
|
3519
|
-
}
|
|
3540
|
+
available: capabilities.available,
|
|
3541
|
+
currentWorkload: capabilities.currentWorkload
|
|
3520
3542
|
};
|
|
3521
3543
|
}
|
|
3522
|
-
function
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3544
|
+
function normalizeWorkerRegistryRecord(workerId, capabilities, tools) {
|
|
3545
|
+
return Object.freeze({
|
|
3546
|
+
...normalizeWorkerDeclaredCapabilities(workerId, capabilities, tools),
|
|
3547
|
+
...normalizeWorkerStatus(capabilities)
|
|
3548
|
+
});
|
|
3549
|
+
}
|
|
3550
|
+
function asCompatibleWorkerCapabilities(record) {
|
|
3551
|
+
return record;
|
|
3552
|
+
}
|
|
3553
|
+
function admitWorker(worker) {
|
|
3554
|
+
const capabilities = asCompatibleWorkerCapabilities(
|
|
3555
|
+
normalizeWorkerRegistryRecord(worker.id, worker.capabilities, worker.tools)
|
|
3556
|
+
);
|
|
3557
|
+
const tools = worker.tools ? Object.freeze([...worker.tools]) : void 0;
|
|
3558
|
+
return Object.freeze({
|
|
3559
|
+
...worker,
|
|
3560
|
+
capabilities,
|
|
3561
|
+
...tools ? { tools } : {}
|
|
3529
3562
|
});
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3563
|
+
}
|
|
3564
|
+
function admitWorkerTopology(workers) {
|
|
3565
|
+
if (workers.length === 0) {
|
|
3566
|
+
throw new WorkerLifecycleError(
|
|
3567
|
+
"empty-topology",
|
|
3568
|
+
"A Multi-Agent System requires at least one Worker."
|
|
3535
3569
|
);
|
|
3570
|
+
}
|
|
3571
|
+
validateIdentities(workers);
|
|
3572
|
+
const topology = Object.freeze(workers.map(admitWorker));
|
|
3573
|
+
let workerCapabilities = Object.freeze(
|
|
3574
|
+
Object.fromEntries(topology.map((worker) => [worker.id, worker.capabilities]))
|
|
3575
|
+
);
|
|
3576
|
+
return Object.freeze({
|
|
3577
|
+
topology,
|
|
3578
|
+
captureWorkerSnapshot: () => workerCapabilities,
|
|
3579
|
+
updateRoutingSkills: (updates) => {
|
|
3580
|
+
if (updates.length === 0) {
|
|
3581
|
+
return;
|
|
3582
|
+
}
|
|
3583
|
+
validateIdentities(updates);
|
|
3584
|
+
const replacements = updates.map((update) => {
|
|
3585
|
+
const current = workerCapabilities[update.id];
|
|
3586
|
+
if (!Object.hasOwn(workerCapabilities, update.id) || !current) {
|
|
3587
|
+
throw new WorkerLifecycleError(
|
|
3588
|
+
"unknown-worker",
|
|
3589
|
+
`Cannot update unknown Worker "${update.id}" after compilation.`
|
|
3590
|
+
);
|
|
3591
|
+
}
|
|
3592
|
+
if (update.assertedTools !== void 0) {
|
|
3593
|
+
const assertedTools = [
|
|
3594
|
+
...normalizeWorkerToolNames(update.id, update.assertedTools)
|
|
3595
|
+
].sort();
|
|
3596
|
+
const executableTools = [...current.tools].sort();
|
|
3597
|
+
if (assertedTools.length !== executableTools.length || assertedTools.some((toolName, index) => toolName !== executableTools[index])) {
|
|
3598
|
+
throw new WorkerLifecycleError(
|
|
3599
|
+
"invalid-tool",
|
|
3600
|
+
`Worker "${update.id}" tools do not match its compiled executable tools.`
|
|
3601
|
+
);
|
|
3602
|
+
}
|
|
3603
|
+
}
|
|
3604
|
+
return [
|
|
3605
|
+
update.id,
|
|
3606
|
+
asCompatibleWorkerCapabilities(
|
|
3607
|
+
Object.freeze({
|
|
3608
|
+
...current,
|
|
3609
|
+
skills: Object.freeze([...update.skills])
|
|
3610
|
+
})
|
|
3611
|
+
)
|
|
3612
|
+
];
|
|
3613
|
+
});
|
|
3614
|
+
workerCapabilities = Object.freeze({
|
|
3615
|
+
...workerCapabilities,
|
|
3616
|
+
...Object.fromEntries(replacements)
|
|
3617
|
+
});
|
|
3618
|
+
}
|
|
3536
3619
|
});
|
|
3537
|
-
return system;
|
|
3538
3620
|
}
|
|
3539
|
-
function
|
|
3540
|
-
|
|
3541
|
-
|
|
3621
|
+
function associateWorkerLifecycle(system, lifecycle) {
|
|
3622
|
+
workerLifecycles.set(system, lifecycle);
|
|
3623
|
+
}
|
|
3624
|
+
function resolveWorkerLifecycle(system) {
|
|
3625
|
+
const lifecycle = workerLifecycles.get(system);
|
|
3626
|
+
if (!lifecycle) {
|
|
3627
|
+
throw new WorkerLifecycleError(
|
|
3628
|
+
"unsupported-system",
|
|
3629
|
+
"The compiled graph was not created by the Worker lifecycle."
|
|
3630
|
+
);
|
|
3542
3631
|
}
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3632
|
+
return lifecycle;
|
|
3633
|
+
}
|
|
3634
|
+
function createWorkerRegistryData(workers) {
|
|
3635
|
+
validateIdentities(workers);
|
|
3636
|
+
return Object.freeze(
|
|
3637
|
+
Object.fromEntries(
|
|
3638
|
+
workers.map((worker) => [
|
|
3639
|
+
worker.id,
|
|
3640
|
+
asCompatibleWorkerCapabilities(
|
|
3641
|
+
normalizeWorkerRegistryRecord(
|
|
3642
|
+
worker.id,
|
|
3643
|
+
worker.capabilities,
|
|
3644
|
+
worker.capabilities.tools.map((name) => ({ name }))
|
|
3645
|
+
)
|
|
3646
|
+
)
|
|
3647
|
+
])
|
|
3648
|
+
)
|
|
3649
|
+
);
|
|
3650
|
+
}
|
|
3651
|
+
|
|
3652
|
+
// src/multi-agent/worker-initialization.ts
|
|
3653
|
+
var logger4 = createPatternLogger("agentforge:patterns:multi-agent:worker-initialization");
|
|
3654
|
+
function initializeWorkerState(topologyCapabilities, invocationWorkers) {
|
|
3655
|
+
for (const workerId of Object.keys(invocationWorkers)) {
|
|
3656
|
+
if (!Object.hasOwn(topologyCapabilities, workerId)) {
|
|
3657
|
+
throw new WorkerLifecycleError(
|
|
3658
|
+
"unknown-worker",
|
|
3659
|
+
`Invocation state contains unknown Worker "${workerId}".`
|
|
3552
3660
|
);
|
|
3553
|
-
}
|
|
3661
|
+
}
|
|
3554
3662
|
}
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
return
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3663
|
+
return Object.fromEntries(
|
|
3664
|
+
Object.entries(topologyCapabilities).map(([workerId, capabilities]) => {
|
|
3665
|
+
const status = Object.hasOwn(invocationWorkers, workerId) ? invocationWorkers[workerId] : capabilities;
|
|
3666
|
+
return [
|
|
3667
|
+
workerId,
|
|
3668
|
+
{
|
|
3669
|
+
skills: [...capabilities.skills],
|
|
3670
|
+
tools: [...capabilities.tools],
|
|
3671
|
+
available: status.available,
|
|
3672
|
+
currentWorkload: status.currentWorkload
|
|
3673
|
+
}
|
|
3674
|
+
];
|
|
3675
|
+
})
|
|
3676
|
+
);
|
|
3677
|
+
}
|
|
3678
|
+
function createWorkerInitializationNode(captureWorkerSnapshot) {
|
|
3679
|
+
return async (state) => {
|
|
3680
|
+
const topologyCapabilities = captureWorkerSnapshot();
|
|
3681
|
+
logger4.info("Worker initialization started", {
|
|
3682
|
+
workerCount: Object.keys(topologyCapabilities).length,
|
|
3683
|
+
statusOverrideCount: Object.keys(state.workers).length
|
|
3562
3684
|
});
|
|
3563
|
-
|
|
3685
|
+
let workers;
|
|
3686
|
+
try {
|
|
3687
|
+
workers = initializeWorkerState(topologyCapabilities, state.workers);
|
|
3688
|
+
} catch (error) {
|
|
3689
|
+
logger4.error("Worker initialization failed", {
|
|
3690
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3691
|
+
invocationWorkerIds: Object.keys(state.workers),
|
|
3692
|
+
topologyWorkerIds: Object.keys(topologyCapabilities)
|
|
3693
|
+
});
|
|
3694
|
+
throw error;
|
|
3695
|
+
}
|
|
3696
|
+
logger4.info("Worker initialization complete", {
|
|
3697
|
+
workerCount: Object.keys(workers).length,
|
|
3698
|
+
workerIds: Object.keys(workers)
|
|
3699
|
+
});
|
|
3700
|
+
return { workers };
|
|
3701
|
+
};
|
|
3564
3702
|
}
|
|
3565
3703
|
|
|
3566
3704
|
// src/multi-agent/agent-graph.ts
|
|
3567
|
-
var
|
|
3705
|
+
var logger5 = createPatternLogger("agentforge:patterns:multi-agent:system");
|
|
3568
3706
|
function createSupervisorRouter() {
|
|
3569
3707
|
return (state) => {
|
|
3570
|
-
|
|
3708
|
+
logger5.debug("Supervisor router executing", {
|
|
3571
3709
|
status: state.status,
|
|
3572
3710
|
...state.currentAgent ? { currentAgent: state.currentAgent } : {},
|
|
3573
3711
|
iteration: state.iteration
|
|
3574
3712
|
});
|
|
3575
3713
|
if (state.status === "completed" || state.status === "failed") {
|
|
3576
|
-
|
|
3714
|
+
logger5.info("Supervisor router: ending workflow", { status: state.status });
|
|
3577
3715
|
return import_langgraph4.END;
|
|
3578
3716
|
}
|
|
3579
3717
|
if (state.status === "aggregating") {
|
|
3580
|
-
|
|
3718
|
+
logger5.info("Supervisor router: routing to aggregator");
|
|
3581
3719
|
return "aggregator";
|
|
3582
3720
|
}
|
|
3583
3721
|
if (state.currentAgent && state.currentAgent !== "supervisor") {
|
|
3584
3722
|
if (state.currentAgent.includes(",")) {
|
|
3585
3723
|
const agents = state.currentAgent.split(",").map((agent) => agent.trim());
|
|
3586
|
-
|
|
3724
|
+
logger5.info("Supervisor router: parallel routing", {
|
|
3587
3725
|
agents,
|
|
3588
3726
|
count: agents.length
|
|
3589
3727
|
});
|
|
3590
3728
|
return agents;
|
|
3591
3729
|
}
|
|
3592
|
-
|
|
3730
|
+
logger5.info("Supervisor router: single agent routing", {
|
|
3593
3731
|
targetAgent: state.currentAgent
|
|
3594
3732
|
});
|
|
3595
3733
|
return state.currentAgent;
|
|
3596
3734
|
}
|
|
3597
|
-
|
|
3735
|
+
logger5.debug("Supervisor router: staying at supervisor");
|
|
3598
3736
|
return "supervisor";
|
|
3599
3737
|
};
|
|
3600
3738
|
}
|
|
3601
3739
|
function createWorkerRouter() {
|
|
3602
3740
|
return (state) => {
|
|
3603
|
-
|
|
3741
|
+
logger5.debug("Worker router executing", {
|
|
3604
3742
|
iteration: state.iteration,
|
|
3605
3743
|
completedTasks: state.completedTasks.length
|
|
3606
3744
|
});
|
|
3607
|
-
|
|
3745
|
+
logger5.debug("Worker router: returning to supervisor");
|
|
3608
3746
|
return "supervisor";
|
|
3609
3747
|
};
|
|
3610
3748
|
}
|
|
3611
3749
|
function createAggregatorRouter() {
|
|
3612
3750
|
return (state) => {
|
|
3613
|
-
|
|
3751
|
+
logger5.info("Aggregator router: ending workflow", {
|
|
3614
3752
|
completedTasks: state.completedTasks.length,
|
|
3615
3753
|
status: state.status
|
|
3616
3754
|
});
|
|
3617
3755
|
return import_langgraph4.END;
|
|
3618
3756
|
};
|
|
3619
3757
|
}
|
|
3620
|
-
function createCompiledMultiAgentSystem(config) {
|
|
3621
|
-
const {
|
|
3622
|
-
supervisor,
|
|
3623
|
-
workers,
|
|
3624
|
-
aggregator,
|
|
3625
|
-
maxIterations = 10,
|
|
3626
|
-
verbose = false,
|
|
3627
|
-
checkpointer
|
|
3628
|
-
} = config;
|
|
3758
|
+
function createCompiledMultiAgentSystem(config, lifecycle = admitWorkerTopology(config.workers)) {
|
|
3759
|
+
const { supervisor, aggregator, maxIterations = 10, verbose = false, checkpointer } = config;
|
|
3629
3760
|
const workflow = new import_langgraph4.StateGraph(MultiAgentState);
|
|
3630
3761
|
const workerIds = [];
|
|
3631
|
-
const workerCapabilities = {};
|
|
3632
3762
|
workflow.addNode(
|
|
3633
|
-
"
|
|
3634
|
-
|
|
3763
|
+
"initializeWorkers",
|
|
3764
|
+
createWorkerInitializationNode(lifecycle.captureWorkerSnapshot)
|
|
3635
3765
|
);
|
|
3636
|
-
|
|
3766
|
+
workflow.addNode("supervisor", createSupervisorNode({ ...supervisor, maxIterations, verbose }));
|
|
3767
|
+
for (const workerConfig of lifecycle.topology) {
|
|
3637
3768
|
workflow.addNode(
|
|
3638
3769
|
workerConfig.id,
|
|
3639
3770
|
createWorkerNode({
|
|
@@ -3642,7 +3773,6 @@ function createCompiledMultiAgentSystem(config) {
|
|
|
3642
3773
|
})
|
|
3643
3774
|
);
|
|
3644
3775
|
workerIds.push(workerConfig.id);
|
|
3645
|
-
workerCapabilities[workerConfig.id] = workerConfig.capabilities;
|
|
3646
3776
|
}
|
|
3647
3777
|
workflow.addNode(
|
|
3648
3778
|
"aggregator",
|
|
@@ -3654,65 +3784,110 @@ function createCompiledMultiAgentSystem(config) {
|
|
|
3654
3784
|
const supervisorRouter = createSupervisorRouter();
|
|
3655
3785
|
const workerRouter = createWorkerRouter();
|
|
3656
3786
|
const aggregatorRouter = createAggregatorRouter();
|
|
3657
|
-
workflow.setEntryPoint("
|
|
3787
|
+
workflow.setEntryPoint("initializeWorkers");
|
|
3788
|
+
workflow.addEdge("initializeWorkers", "supervisor");
|
|
3658
3789
|
workflow.addConditionalEdges("supervisor", supervisorRouter, ["aggregator", import_langgraph4.END, ...workerIds]);
|
|
3659
3790
|
for (const workerId of workerIds) {
|
|
3660
3791
|
workflow.addConditionalEdges(workerId, workerRouter, ["supervisor"]);
|
|
3661
3792
|
}
|
|
3662
3793
|
workflow.addConditionalEdges("aggregator", aggregatorRouter, [import_langgraph4.END]);
|
|
3663
|
-
const
|
|
3794
|
+
const system = workflow.compile(
|
|
3664
3795
|
checkpointer ? { checkpointer } : void 0
|
|
3665
3796
|
);
|
|
3666
|
-
|
|
3797
|
+
associateWorkerLifecycle(system, lifecycle);
|
|
3798
|
+
return system;
|
|
3799
|
+
}
|
|
3800
|
+
|
|
3801
|
+
// src/multi-agent/agent-runtime.ts
|
|
3802
|
+
function registerWorkerCapabilities(system, workers) {
|
|
3803
|
+
resolveWorkerLifecycle(system).updateRoutingSkills(
|
|
3804
|
+
workers.map((worker) => ({
|
|
3805
|
+
id: worker.name,
|
|
3806
|
+
skills: worker.capabilities,
|
|
3807
|
+
...worker.tools === void 0 ? {} : { assertedTools: worker.tools }
|
|
3808
|
+
}))
|
|
3809
|
+
);
|
|
3810
|
+
}
|
|
3811
|
+
|
|
3812
|
+
// src/multi-agent/agent-workers.ts
|
|
3813
|
+
function toWorkerConfig(worker, fallbackModel) {
|
|
3814
|
+
return {
|
|
3815
|
+
id: worker.name,
|
|
3816
|
+
capabilities: {
|
|
3817
|
+
skills: worker.capabilities,
|
|
3818
|
+
tools: [],
|
|
3819
|
+
available: true,
|
|
3820
|
+
currentWorkload: 0
|
|
3821
|
+
},
|
|
3822
|
+
model: worker.model || fallbackModel,
|
|
3823
|
+
tools: worker.tools,
|
|
3824
|
+
systemPrompt: worker.systemPrompt
|
|
3825
|
+
};
|
|
3667
3826
|
}
|
|
3668
3827
|
|
|
3669
3828
|
// src/multi-agent/agent-builder.ts
|
|
3670
3829
|
var MultiAgentSystemBuilder = class {
|
|
3671
3830
|
config;
|
|
3672
|
-
|
|
3831
|
+
lifecycle;
|
|
3673
3832
|
compiled = false;
|
|
3674
3833
|
constructor(config) {
|
|
3675
3834
|
this.config = {
|
|
3676
3835
|
...config,
|
|
3677
|
-
workers:
|
|
3836
|
+
workers: []
|
|
3678
3837
|
};
|
|
3838
|
+
this.lifecycle = config.workers?.length ? admitWorkerTopology(config.workers) : void 0;
|
|
3679
3839
|
}
|
|
3680
3840
|
registerWorkers(workers) {
|
|
3681
3841
|
if (this.compiled) {
|
|
3682
3842
|
throw new Error("Cannot register workers after the system has been compiled");
|
|
3683
3843
|
}
|
|
3684
|
-
|
|
3685
|
-
|
|
3844
|
+
if (workers.length === 0) {
|
|
3845
|
+
return this;
|
|
3686
3846
|
}
|
|
3847
|
+
const existingWorkers = this.lifecycle?.topology ?? [];
|
|
3848
|
+
const pendingWorkers = workers.map(
|
|
3849
|
+
(worker) => toWorkerConfig(worker, this.config.supervisor.model)
|
|
3850
|
+
);
|
|
3851
|
+
const lifecycle = admitWorkerTopology([...existingWorkers, ...pendingWorkers]);
|
|
3852
|
+
this.lifecycle = lifecycle;
|
|
3687
3853
|
return this;
|
|
3688
3854
|
}
|
|
3689
3855
|
build() {
|
|
3690
3856
|
if (this.compiled) {
|
|
3691
3857
|
throw new Error("System has already been compiled");
|
|
3692
3858
|
}
|
|
3693
|
-
const
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3859
|
+
const lifecycle = this.lifecycle ?? admitWorkerTopology([]);
|
|
3860
|
+
const system = createCompiledMultiAgentSystem(
|
|
3861
|
+
{
|
|
3862
|
+
...this.config,
|
|
3863
|
+
workers: [...lifecycle.topology]
|
|
3864
|
+
},
|
|
3865
|
+
lifecycle
|
|
3866
|
+
);
|
|
3697
3867
|
this.compiled = true;
|
|
3698
|
-
return
|
|
3699
|
-
...this.config,
|
|
3700
|
-
workers: allWorkers
|
|
3701
|
-
});
|
|
3868
|
+
return system;
|
|
3702
3869
|
}
|
|
3703
3870
|
};
|
|
3704
3871
|
|
|
3705
3872
|
// src/multi-agent/agent.ts
|
|
3706
|
-
var
|
|
3873
|
+
var logger6 = createPatternLogger("agentforge:patterns:multi-agent:system");
|
|
3874
|
+
var systemsWarnedAboutLegacyRegistration = /* @__PURE__ */ new WeakSet();
|
|
3707
3875
|
function createMultiAgentSystem(config) {
|
|
3708
|
-
|
|
3876
|
+
const lifecycle = admitWorkerTopology(config.workers);
|
|
3877
|
+
return createCompiledMultiAgentSystem(config, lifecycle);
|
|
3709
3878
|
}
|
|
3710
3879
|
function registerWorkers(system, workers) {
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3880
|
+
if (!systemsWarnedAboutLegacyRegistration.has(system)) {
|
|
3881
|
+
systemsWarnedAboutLegacyRegistration.add(system);
|
|
3882
|
+
logger6.warn(
|
|
3883
|
+
"[AgentForge] registerWorkers() on a compiled system only updates routing skills for known Workers.\nIt does NOT add Worker nodes or change compiled tools. Use MultiAgentSystemBuilder before compilation.\nSee: https://github.com/TVScoundrel/agentforge/blob/main/packages/patterns/docs/multi-agent-pattern.md"
|
|
3884
|
+
);
|
|
3885
|
+
}
|
|
3714
3886
|
registerWorkerCapabilities(system, workers);
|
|
3715
3887
|
}
|
|
3888
|
+
function createWorkersRegistry(workers) {
|
|
3889
|
+
return createWorkerRegistryData(workers);
|
|
3890
|
+
}
|
|
3716
3891
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3717
3892
|
0 && (module.exports = {
|
|
3718
3893
|
AgentMessageSchema,
|
|
@@ -3766,6 +3941,7 @@ function registerWorkers(system, workers) {
|
|
|
3766
3941
|
ToolCallSchema,
|
|
3767
3942
|
ToolResultSchema,
|
|
3768
3943
|
WorkerCapabilitiesSchema,
|
|
3944
|
+
WorkerLifecycleError,
|
|
3769
3945
|
buildDeduplicationMetrics,
|
|
3770
3946
|
calculateDeduplicationSavings,
|
|
3771
3947
|
createAggregatorNode,
|
|
@@ -3785,6 +3961,7 @@ function registerWorkers(system, workers) {
|
|
|
3785
3961
|
createReviserNode,
|
|
3786
3962
|
createSupervisorNode,
|
|
3787
3963
|
createWorkerNode,
|
|
3964
|
+
createWorkersRegistry,
|
|
3788
3965
|
generateToolCallCacheKey,
|
|
3789
3966
|
getRoutingStrategy,
|
|
3790
3967
|
llmBasedRouting,
|