@agentforge/patterns 0.16.91 → 0.17.1
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 +291 -118
- package/dist/index.d.cts +42 -20
- package/dist/index.d.ts +42 -20
- package/dist/index.js +289 -118
- 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,291 @@ 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
|
-
mergeWorkers(input, workerCapabilities),
|
|
3527
|
-
config
|
|
3528
|
-
);
|
|
3544
|
+
function normalizeWorkerRegistryRecord(workerId, capabilities, tools) {
|
|
3545
|
+
return Object.freeze({
|
|
3546
|
+
...normalizeWorkerDeclaredCapabilities(workerId, capabilities, tools),
|
|
3547
|
+
...normalizeWorkerStatus(capabilities)
|
|
3529
3548
|
});
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
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 } : {}
|
|
3536
3562
|
});
|
|
3537
|
-
return system;
|
|
3538
3563
|
}
|
|
3539
|
-
function
|
|
3540
|
-
if (
|
|
3541
|
-
|
|
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."
|
|
3569
|
+
);
|
|
3542
3570
|
}
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
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
|
+
const publishRoutingSkills = (updates) => {
|
|
3577
|
+
if (updates.length === 0) {
|
|
3578
|
+
return;
|
|
3579
|
+
}
|
|
3580
|
+
validateIdentities(updates);
|
|
3581
|
+
const replacements = updates.map((update) => {
|
|
3582
|
+
const current = workerCapabilities[update.id];
|
|
3583
|
+
if (!Object.hasOwn(workerCapabilities, update.id) || !current) {
|
|
3584
|
+
throw new WorkerLifecycleError(
|
|
3585
|
+
"unknown-worker",
|
|
3586
|
+
`Cannot update unknown Worker "${update.id}" after compilation.`
|
|
3587
|
+
);
|
|
3588
|
+
}
|
|
3589
|
+
if (update.assertedTools !== void 0) {
|
|
3590
|
+
const assertedTools = [...normalizeWorkerToolNames(update.id, update.assertedTools)].sort();
|
|
3591
|
+
const executableTools = [...current.tools].sort();
|
|
3592
|
+
if (assertedTools.length !== executableTools.length || assertedTools.some((toolName, index) => toolName !== executableTools[index])) {
|
|
3593
|
+
throw new WorkerLifecycleError(
|
|
3594
|
+
"invalid-tool",
|
|
3595
|
+
`Worker "${update.id}" tools do not match its compiled executable tools.`
|
|
3596
|
+
);
|
|
3597
|
+
}
|
|
3598
|
+
}
|
|
3599
|
+
return [
|
|
3600
|
+
update.id,
|
|
3601
|
+
asCompatibleWorkerCapabilities(
|
|
3602
|
+
Object.freeze({
|
|
3603
|
+
...current,
|
|
3604
|
+
skills: Object.freeze([...update.skills])
|
|
3605
|
+
})
|
|
3606
|
+
)
|
|
3607
|
+
];
|
|
3553
3608
|
});
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
system.stream = (async function(input, config) {
|
|
3558
|
-
return system._originalStream(
|
|
3559
|
-
mergeWorkers(input, system._workerRegistry || {}),
|
|
3560
|
-
config
|
|
3561
|
-
);
|
|
3609
|
+
workerCapabilities = Object.freeze({
|
|
3610
|
+
...workerCapabilities,
|
|
3611
|
+
...Object.fromEntries(replacements)
|
|
3562
3612
|
});
|
|
3613
|
+
};
|
|
3614
|
+
return Object.freeze({
|
|
3615
|
+
topology,
|
|
3616
|
+
captureSnapshot: (statusOverrides) => {
|
|
3617
|
+
const publishedCapabilities = workerCapabilities;
|
|
3618
|
+
for (const workerId of Object.keys(statusOverrides)) {
|
|
3619
|
+
if (!Object.hasOwn(publishedCapabilities, workerId)) {
|
|
3620
|
+
throw new WorkerLifecycleError(
|
|
3621
|
+
"unknown-worker",
|
|
3622
|
+
`Invocation state contains unknown Worker "${workerId}".`
|
|
3623
|
+
);
|
|
3624
|
+
}
|
|
3625
|
+
}
|
|
3626
|
+
return Object.fromEntries(
|
|
3627
|
+
Object.entries(publishedCapabilities).map(([workerId, capabilities]) => {
|
|
3628
|
+
const status = Object.hasOwn(statusOverrides, workerId) ? statusOverrides[workerId] : capabilities;
|
|
3629
|
+
return [
|
|
3630
|
+
workerId,
|
|
3631
|
+
{
|
|
3632
|
+
skills: [...capabilities.skills],
|
|
3633
|
+
tools: [...capabilities.tools],
|
|
3634
|
+
available: status.available,
|
|
3635
|
+
currentWorkload: status.currentWorkload
|
|
3636
|
+
}
|
|
3637
|
+
];
|
|
3638
|
+
})
|
|
3639
|
+
);
|
|
3640
|
+
},
|
|
3641
|
+
publishRoutingSkills
|
|
3642
|
+
});
|
|
3643
|
+
}
|
|
3644
|
+
function associateWorkerLifecycle(system, lifecycle) {
|
|
3645
|
+
workerLifecycles.set(system, lifecycle);
|
|
3646
|
+
}
|
|
3647
|
+
function resolveWorkerLifecycle(system) {
|
|
3648
|
+
const lifecycle = workerLifecycles.get(system);
|
|
3649
|
+
if (!lifecycle) {
|
|
3650
|
+
throw new WorkerLifecycleError(
|
|
3651
|
+
"unsupported-system",
|
|
3652
|
+
"The compiled graph was not created by the Worker lifecycle."
|
|
3653
|
+
);
|
|
3563
3654
|
}
|
|
3655
|
+
return lifecycle;
|
|
3656
|
+
}
|
|
3657
|
+
function createWorkerRegistryData(workers) {
|
|
3658
|
+
validateIdentities(workers);
|
|
3659
|
+
return Object.freeze(
|
|
3660
|
+
Object.fromEntries(
|
|
3661
|
+
workers.map((worker) => [
|
|
3662
|
+
worker.id,
|
|
3663
|
+
asCompatibleWorkerCapabilities(
|
|
3664
|
+
normalizeWorkerRegistryRecord(
|
|
3665
|
+
worker.id,
|
|
3666
|
+
worker.capabilities,
|
|
3667
|
+
worker.capabilities.tools.map((name) => ({ name }))
|
|
3668
|
+
)
|
|
3669
|
+
)
|
|
3670
|
+
])
|
|
3671
|
+
)
|
|
3672
|
+
);
|
|
3673
|
+
}
|
|
3674
|
+
|
|
3675
|
+
// src/multi-agent/worker-initialization.ts
|
|
3676
|
+
var logger4 = createPatternLogger("agentforge:patterns:multi-agent:worker-initialization");
|
|
3677
|
+
function createWorkerInitializationNode(lifecycle) {
|
|
3678
|
+
return async (state) => {
|
|
3679
|
+
const topologyWorkerIds = lifecycle.topology.map((worker) => worker.id);
|
|
3680
|
+
logger4.info("Worker initialization started", {
|
|
3681
|
+
workerCount: topologyWorkerIds.length,
|
|
3682
|
+
statusOverrideCount: Object.keys(state.workers).length
|
|
3683
|
+
});
|
|
3684
|
+
let workers;
|
|
3685
|
+
try {
|
|
3686
|
+
workers = lifecycle.captureSnapshot(state.workers);
|
|
3687
|
+
} catch (error) {
|
|
3688
|
+
logger4.error("Worker initialization failed", {
|
|
3689
|
+
error: error instanceof Error ? error.message : String(error),
|
|
3690
|
+
invocationWorkerIds: Object.keys(state.workers),
|
|
3691
|
+
topologyWorkerIds
|
|
3692
|
+
});
|
|
3693
|
+
throw error;
|
|
3694
|
+
}
|
|
3695
|
+
logger4.info("Worker initialization complete", {
|
|
3696
|
+
workerCount: Object.keys(workers).length,
|
|
3697
|
+
workerIds: Object.keys(workers)
|
|
3698
|
+
});
|
|
3699
|
+
return { workers };
|
|
3700
|
+
};
|
|
3564
3701
|
}
|
|
3565
3702
|
|
|
3566
3703
|
// src/multi-agent/agent-graph.ts
|
|
3567
|
-
var
|
|
3704
|
+
var logger5 = createPatternLogger("agentforge:patterns:multi-agent:system");
|
|
3568
3705
|
function createSupervisorRouter() {
|
|
3569
3706
|
return (state) => {
|
|
3570
|
-
|
|
3707
|
+
logger5.debug("Supervisor router executing", {
|
|
3571
3708
|
status: state.status,
|
|
3572
3709
|
...state.currentAgent ? { currentAgent: state.currentAgent } : {},
|
|
3573
3710
|
iteration: state.iteration
|
|
3574
3711
|
});
|
|
3575
3712
|
if (state.status === "completed" || state.status === "failed") {
|
|
3576
|
-
|
|
3713
|
+
logger5.info("Supervisor router: ending workflow", { status: state.status });
|
|
3577
3714
|
return import_langgraph4.END;
|
|
3578
3715
|
}
|
|
3579
3716
|
if (state.status === "aggregating") {
|
|
3580
|
-
|
|
3717
|
+
logger5.info("Supervisor router: routing to aggregator");
|
|
3581
3718
|
return "aggregator";
|
|
3582
3719
|
}
|
|
3583
3720
|
if (state.currentAgent && state.currentAgent !== "supervisor") {
|
|
3584
3721
|
if (state.currentAgent.includes(",")) {
|
|
3585
3722
|
const agents = state.currentAgent.split(",").map((agent) => agent.trim());
|
|
3586
|
-
|
|
3723
|
+
logger5.info("Supervisor router: parallel routing", {
|
|
3587
3724
|
agents,
|
|
3588
3725
|
count: agents.length
|
|
3589
3726
|
});
|
|
3590
3727
|
return agents;
|
|
3591
3728
|
}
|
|
3592
|
-
|
|
3729
|
+
logger5.info("Supervisor router: single agent routing", {
|
|
3593
3730
|
targetAgent: state.currentAgent
|
|
3594
3731
|
});
|
|
3595
3732
|
return state.currentAgent;
|
|
3596
3733
|
}
|
|
3597
|
-
|
|
3734
|
+
logger5.debug("Supervisor router: staying at supervisor");
|
|
3598
3735
|
return "supervisor";
|
|
3599
3736
|
};
|
|
3600
3737
|
}
|
|
3601
3738
|
function createWorkerRouter() {
|
|
3602
3739
|
return (state) => {
|
|
3603
|
-
|
|
3740
|
+
logger5.debug("Worker router executing", {
|
|
3604
3741
|
iteration: state.iteration,
|
|
3605
3742
|
completedTasks: state.completedTasks.length
|
|
3606
3743
|
});
|
|
3607
|
-
|
|
3744
|
+
logger5.debug("Worker router: returning to supervisor");
|
|
3608
3745
|
return "supervisor";
|
|
3609
3746
|
};
|
|
3610
3747
|
}
|
|
3611
3748
|
function createAggregatorRouter() {
|
|
3612
3749
|
return (state) => {
|
|
3613
|
-
|
|
3750
|
+
logger5.info("Aggregator router: ending workflow", {
|
|
3614
3751
|
completedTasks: state.completedTasks.length,
|
|
3615
3752
|
status: state.status
|
|
3616
3753
|
});
|
|
3617
3754
|
return import_langgraph4.END;
|
|
3618
3755
|
};
|
|
3619
3756
|
}
|
|
3620
|
-
function createCompiledMultiAgentSystem(config) {
|
|
3621
|
-
const {
|
|
3622
|
-
supervisor,
|
|
3623
|
-
workers,
|
|
3624
|
-
aggregator,
|
|
3625
|
-
maxIterations = 10,
|
|
3626
|
-
verbose = false,
|
|
3627
|
-
checkpointer
|
|
3628
|
-
} = config;
|
|
3757
|
+
function createCompiledMultiAgentSystem(config, lifecycle = admitWorkerTopology(config.workers)) {
|
|
3758
|
+
const { supervisor, aggregator, maxIterations = 10, verbose = false, checkpointer } = config;
|
|
3629
3759
|
const workflow = new import_langgraph4.StateGraph(MultiAgentState);
|
|
3630
3760
|
const workerIds = [];
|
|
3631
|
-
|
|
3632
|
-
workflow.addNode(
|
|
3633
|
-
|
|
3634
|
-
createSupervisorNode({ ...supervisor, maxIterations, verbose })
|
|
3635
|
-
);
|
|
3636
|
-
for (const workerConfig of workers) {
|
|
3761
|
+
workflow.addNode("initializeWorkers", createWorkerInitializationNode(lifecycle));
|
|
3762
|
+
workflow.addNode("supervisor", createSupervisorNode({ ...supervisor, maxIterations, verbose }));
|
|
3763
|
+
for (const workerConfig of lifecycle.topology) {
|
|
3637
3764
|
workflow.addNode(
|
|
3638
3765
|
workerConfig.id,
|
|
3639
3766
|
createWorkerNode({
|
|
@@ -3642,7 +3769,6 @@ function createCompiledMultiAgentSystem(config) {
|
|
|
3642
3769
|
})
|
|
3643
3770
|
);
|
|
3644
3771
|
workerIds.push(workerConfig.id);
|
|
3645
|
-
workerCapabilities[workerConfig.id] = workerConfig.capabilities;
|
|
3646
3772
|
}
|
|
3647
3773
|
workflow.addNode(
|
|
3648
3774
|
"aggregator",
|
|
@@ -3654,65 +3780,110 @@ function createCompiledMultiAgentSystem(config) {
|
|
|
3654
3780
|
const supervisorRouter = createSupervisorRouter();
|
|
3655
3781
|
const workerRouter = createWorkerRouter();
|
|
3656
3782
|
const aggregatorRouter = createAggregatorRouter();
|
|
3657
|
-
workflow.setEntryPoint("
|
|
3783
|
+
workflow.setEntryPoint("initializeWorkers");
|
|
3784
|
+
workflow.addEdge("initializeWorkers", "supervisor");
|
|
3658
3785
|
workflow.addConditionalEdges("supervisor", supervisorRouter, ["aggregator", import_langgraph4.END, ...workerIds]);
|
|
3659
3786
|
for (const workerId of workerIds) {
|
|
3660
3787
|
workflow.addConditionalEdges(workerId, workerRouter, ["supervisor"]);
|
|
3661
3788
|
}
|
|
3662
3789
|
workflow.addConditionalEdges("aggregator", aggregatorRouter, [import_langgraph4.END]);
|
|
3663
|
-
const
|
|
3790
|
+
const system = workflow.compile(
|
|
3664
3791
|
checkpointer ? { checkpointer } : void 0
|
|
3665
3792
|
);
|
|
3666
|
-
|
|
3793
|
+
associateWorkerLifecycle(system, lifecycle);
|
|
3794
|
+
return system;
|
|
3795
|
+
}
|
|
3796
|
+
|
|
3797
|
+
// src/multi-agent/agent-runtime.ts
|
|
3798
|
+
function registerWorkerCapabilities(system, workers) {
|
|
3799
|
+
resolveWorkerLifecycle(system).publishRoutingSkills(
|
|
3800
|
+
workers.map((worker) => ({
|
|
3801
|
+
id: worker.name,
|
|
3802
|
+
skills: worker.capabilities,
|
|
3803
|
+
...worker.tools === void 0 ? {} : { assertedTools: worker.tools }
|
|
3804
|
+
}))
|
|
3805
|
+
);
|
|
3806
|
+
}
|
|
3807
|
+
|
|
3808
|
+
// src/multi-agent/agent-workers.ts
|
|
3809
|
+
function toWorkerConfig(worker, fallbackModel) {
|
|
3810
|
+
return {
|
|
3811
|
+
id: worker.name,
|
|
3812
|
+
capabilities: {
|
|
3813
|
+
skills: worker.capabilities,
|
|
3814
|
+
tools: [],
|
|
3815
|
+
available: true,
|
|
3816
|
+
currentWorkload: 0
|
|
3817
|
+
},
|
|
3818
|
+
model: worker.model || fallbackModel,
|
|
3819
|
+
tools: worker.tools,
|
|
3820
|
+
systemPrompt: worker.systemPrompt
|
|
3821
|
+
};
|
|
3667
3822
|
}
|
|
3668
3823
|
|
|
3669
3824
|
// src/multi-agent/agent-builder.ts
|
|
3670
3825
|
var MultiAgentSystemBuilder = class {
|
|
3671
3826
|
config;
|
|
3672
|
-
|
|
3827
|
+
lifecycle;
|
|
3673
3828
|
compiled = false;
|
|
3674
3829
|
constructor(config) {
|
|
3675
3830
|
this.config = {
|
|
3676
3831
|
...config,
|
|
3677
|
-
workers:
|
|
3832
|
+
workers: []
|
|
3678
3833
|
};
|
|
3834
|
+
this.lifecycle = config.workers?.length ? admitWorkerTopology(config.workers) : void 0;
|
|
3679
3835
|
}
|
|
3680
3836
|
registerWorkers(workers) {
|
|
3681
3837
|
if (this.compiled) {
|
|
3682
3838
|
throw new Error("Cannot register workers after the system has been compiled");
|
|
3683
3839
|
}
|
|
3684
|
-
|
|
3685
|
-
|
|
3840
|
+
if (workers.length === 0) {
|
|
3841
|
+
return this;
|
|
3686
3842
|
}
|
|
3843
|
+
const existingWorkers = this.lifecycle?.topology ?? [];
|
|
3844
|
+
const pendingWorkers = workers.map(
|
|
3845
|
+
(worker) => toWorkerConfig(worker, this.config.supervisor.model)
|
|
3846
|
+
);
|
|
3847
|
+
const lifecycle = admitWorkerTopology([...existingWorkers, ...pendingWorkers]);
|
|
3848
|
+
this.lifecycle = lifecycle;
|
|
3687
3849
|
return this;
|
|
3688
3850
|
}
|
|
3689
3851
|
build() {
|
|
3690
3852
|
if (this.compiled) {
|
|
3691
3853
|
throw new Error("System has already been compiled");
|
|
3692
3854
|
}
|
|
3693
|
-
const
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3855
|
+
const lifecycle = this.lifecycle ?? admitWorkerTopology([]);
|
|
3856
|
+
const system = createCompiledMultiAgentSystem(
|
|
3857
|
+
{
|
|
3858
|
+
...this.config,
|
|
3859
|
+
workers: [...lifecycle.topology]
|
|
3860
|
+
},
|
|
3861
|
+
lifecycle
|
|
3862
|
+
);
|
|
3697
3863
|
this.compiled = true;
|
|
3698
|
-
return
|
|
3699
|
-
...this.config,
|
|
3700
|
-
workers: allWorkers
|
|
3701
|
-
});
|
|
3864
|
+
return system;
|
|
3702
3865
|
}
|
|
3703
3866
|
};
|
|
3704
3867
|
|
|
3705
3868
|
// src/multi-agent/agent.ts
|
|
3706
|
-
var
|
|
3869
|
+
var logger6 = createPatternLogger("agentforge:patterns:multi-agent:system");
|
|
3870
|
+
var systemsWarnedAboutLegacyRegistration = /* @__PURE__ */ new WeakSet();
|
|
3707
3871
|
function createMultiAgentSystem(config) {
|
|
3708
|
-
|
|
3872
|
+
const lifecycle = admitWorkerTopology(config.workers);
|
|
3873
|
+
return createCompiledMultiAgentSystem(config, lifecycle);
|
|
3709
3874
|
}
|
|
3710
3875
|
function registerWorkers(system, workers) {
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
3876
|
+
if (!systemsWarnedAboutLegacyRegistration.has(system)) {
|
|
3877
|
+
systemsWarnedAboutLegacyRegistration.add(system);
|
|
3878
|
+
logger6.warn(
|
|
3879
|
+
"[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"
|
|
3880
|
+
);
|
|
3881
|
+
}
|
|
3714
3882
|
registerWorkerCapabilities(system, workers);
|
|
3715
3883
|
}
|
|
3884
|
+
function createWorkersRegistry(workers) {
|
|
3885
|
+
return createWorkerRegistryData(workers);
|
|
3886
|
+
}
|
|
3716
3887
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3717
3888
|
0 && (module.exports = {
|
|
3718
3889
|
AgentMessageSchema,
|
|
@@ -3766,6 +3937,7 @@ function registerWorkers(system, workers) {
|
|
|
3766
3937
|
ToolCallSchema,
|
|
3767
3938
|
ToolResultSchema,
|
|
3768
3939
|
WorkerCapabilitiesSchema,
|
|
3940
|
+
WorkerLifecycleError,
|
|
3769
3941
|
buildDeduplicationMetrics,
|
|
3770
3942
|
calculateDeduplicationSavings,
|
|
3771
3943
|
createAggregatorNode,
|
|
@@ -3785,6 +3957,7 @@ function registerWorkers(system, workers) {
|
|
|
3785
3957
|
createReviserNode,
|
|
3786
3958
|
createSupervisorNode,
|
|
3787
3959
|
createWorkerNode,
|
|
3960
|
+
createWorkersRegistry,
|
|
3788
3961
|
generateToolCallCacheKey,
|
|
3789
3962
|
getRoutingStrategy,
|
|
3790
3963
|
llmBasedRouting,
|