@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 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
- - Dynamic worker registration
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
- - `registerWorkers(system, workers)` - Update worker capabilities in state (Note: does not add worker nodes to compiled graphs; use builder or pass workers to createMultiAgentSystem)
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(logger6, verbose, message, data) {
436
+ function debugIfVerbose(logger7, verbose, message, data) {
435
437
  if (verbose) {
436
- logger6.debug(message, data);
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: (left, right) => ({
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/agent-workers.ts
3481
- function getToolName(tool) {
3482
- if (!tool || typeof tool !== "object") {
3483
- return "unknown";
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
- const candidate = tool;
3486
- if (typeof candidate.metadata?.name === "string") {
3487
- return candidate.metadata.name;
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
- if (typeof candidate.name === "string") {
3490
- return candidate.name;
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 "unknown";
3510
+ return Object.freeze(toolNames);
3493
3511
  }
3494
- function toWorkerCapabilities(worker) {
3495
- return {
3496
- skills: worker.capabilities,
3497
- tools: worker.tools?.map((tool) => getToolName(tool)) || [],
3498
- available: true,
3499
- currentWorkload: 0
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 toWorkerConfig(worker, fallbackModel) {
3532
+ function normalizeWorkerDeclaredCapabilities(workerId, capabilities, tools) {
3503
3533
  return {
3504
- id: worker.name,
3505
- capabilities: toWorkerCapabilities(worker),
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
- ...input,
3516
- workers: {
3517
- ...workerCapabilities,
3518
- ...input.workers || {}
3519
- }
3540
+ available: capabilities.available,
3541
+ currentWorkload: capabilities.currentWorkload
3520
3542
  };
3521
3543
  }
3522
- function wrapCompiledSystem(system, workerCapabilities) {
3523
- const originalInvoke = system.invoke.bind(system);
3524
- system.invoke = (async function(input, config) {
3525
- return originalInvoke(
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
- const originalStream = system.stream.bind(system);
3531
- system.stream = (async function(input, config) {
3532
- return originalStream(
3533
- mergeWorkers(input, workerCapabilities),
3534
- config
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 registerWorkerCapabilities(system, workers) {
3540
- if (!system._workerRegistry) {
3541
- system._workerRegistry = {};
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
- for (const worker of workers) {
3544
- system._workerRegistry[worker.name] = toWorkerCapabilities(worker);
3545
- }
3546
- if (!system._originalInvoke) {
3547
- system._originalInvoke = system.invoke.bind(system);
3548
- system.invoke = (async function(input, config) {
3549
- return system._originalInvoke(
3550
- mergeWorkers(input, system._workerRegistry || {}),
3551
- config
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
- if (!system._originalStream) {
3556
- system._originalStream = system.stream.bind(system);
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 logger4 = createPatternLogger("agentforge:patterns:multi-agent:system");
3704
+ var logger5 = createPatternLogger("agentforge:patterns:multi-agent:system");
3568
3705
  function createSupervisorRouter() {
3569
3706
  return (state) => {
3570
- logger4.debug("Supervisor router executing", {
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
- logger4.info("Supervisor router: ending workflow", { status: state.status });
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
- logger4.info("Supervisor router: routing to aggregator");
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
- logger4.info("Supervisor router: parallel routing", {
3723
+ logger5.info("Supervisor router: parallel routing", {
3587
3724
  agents,
3588
3725
  count: agents.length
3589
3726
  });
3590
3727
  return agents;
3591
3728
  }
3592
- logger4.info("Supervisor router: single agent routing", {
3729
+ logger5.info("Supervisor router: single agent routing", {
3593
3730
  targetAgent: state.currentAgent
3594
3731
  });
3595
3732
  return state.currentAgent;
3596
3733
  }
3597
- logger4.debug("Supervisor router: staying at supervisor");
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
- logger4.debug("Worker router executing", {
3740
+ logger5.debug("Worker router executing", {
3604
3741
  iteration: state.iteration,
3605
3742
  completedTasks: state.completedTasks.length
3606
3743
  });
3607
- logger4.debug("Worker router: returning to supervisor");
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
- logger4.info("Aggregator router: ending workflow", {
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
- const workerCapabilities = {};
3632
- workflow.addNode(
3633
- "supervisor",
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("supervisor");
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 compiled = workflow.compile(
3790
+ const system = workflow.compile(
3664
3791
  checkpointer ? { checkpointer } : void 0
3665
3792
  );
3666
- return wrapCompiledSystem(compiled, workerCapabilities);
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
- additionalWorkers = [];
3827
+ lifecycle;
3673
3828
  compiled = false;
3674
3829
  constructor(config) {
3675
3830
  this.config = {
3676
3831
  ...config,
3677
- workers: config.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
- for (const worker of workers) {
3685
- this.additionalWorkers.push(toWorkerConfig(worker, this.config.supervisor.model));
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 allWorkers = [...this.config.workers, ...this.additionalWorkers];
3694
- if (allWorkers.length === 0) {
3695
- throw new Error("At least one worker must be registered before building the system");
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 createCompiledMultiAgentSystem({
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 logger5 = createPatternLogger("agentforge:patterns:multi-agent:system");
3869
+ var logger6 = createPatternLogger("agentforge:patterns:multi-agent:system");
3870
+ var systemsWarnedAboutLegacyRegistration = /* @__PURE__ */ new WeakSet();
3707
3871
  function createMultiAgentSystem(config) {
3708
- return createCompiledMultiAgentSystem(config);
3872
+ const lifecycle = admitWorkerTopology(config.workers);
3873
+ return createCompiledMultiAgentSystem(config, lifecycle);
3709
3874
  }
3710
3875
  function registerWorkers(system, workers) {
3711
- logger5.warn(
3712
- "[AgentForge] registerWorkers() on a compiled system only updates worker capabilities in state.\nIt does NOT add worker nodes to the graph. Use MultiAgentSystemBuilder for proper worker registration.\nSee: https://github.com/TVScoundrel/agentforge/blob/main/packages/patterns/docs/multi-agent-pattern.md"
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,