@agentforge/patterns 0.11.0 → 0.11.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/README.md CHANGED
@@ -514,6 +514,13 @@ pnpm test:coverage
514
514
  pnpm typecheck
515
515
  ```
516
516
 
517
+ ## 🔗 Links
518
+
519
+ - [GitHub Repository](https://github.com/TVScoundrel/agentforge)
520
+ - [npm Package](https://www.npmjs.com/package/@agentforge/patterns)
521
+ - [Changelog](https://tvscoundrel.github.io/agentforge/changelog.html) - See what's new before upgrading
522
+ - [Report Issues](https://github.com/TVScoundrel/agentforge/issues)
523
+
517
524
  ## License
518
525
 
519
526
  MIT © 2026 Tom Van Schoor
package/dist/index.cjs CHANGED
@@ -2608,11 +2608,22 @@ function createSupervisorNode(config) {
2608
2608
  priority: assignment.priority
2609
2609
  }
2610
2610
  }));
2611
+ const updatedWorkers = { ...state.workers };
2612
+ for (const assignment of assignments) {
2613
+ const worker = updatedWorkers[assignment.workerId];
2614
+ if (worker) {
2615
+ updatedWorkers[assignment.workerId] = {
2616
+ ...worker,
2617
+ currentWorkload: worker.currentWorkload + 1
2618
+ };
2619
+ }
2620
+ }
2611
2621
  logger2.info("Supervisor routing complete", {
2612
2622
  currentAgent: targetAgents.join(","),
2613
2623
  status: "executing",
2614
2624
  assignmentCount: assignments.length,
2615
- nextIteration: state.iteration + 1
2625
+ nextIteration: state.iteration + 1,
2626
+ workloadUpdates: Object.entries(updatedWorkers).filter(([id]) => targetAgents.includes(id)).map(([id, caps]) => ({ workerId: id, newWorkload: caps.currentWorkload }))
2616
2627
  });
2617
2628
  return {
2618
2629
  currentAgent: targetAgents.join(","),
@@ -2622,6 +2633,8 @@ function createSupervisorNode(config) {
2622
2633
  activeAssignments: assignments,
2623
2634
  // Multiple assignments for parallel execution!
2624
2635
  messages,
2636
+ workers: updatedWorkers,
2637
+ // Include updated workload
2625
2638
  // Add 1 to iteration counter (uses additive reducer)
2626
2639
  iteration: 1
2627
2640
  };
@@ -2673,96 +2686,100 @@ function createWorkerNode(config) {
2673
2686
  taskLength: currentAssignment.task.length,
2674
2687
  taskPreview: currentAssignment.task.substring(0, 100)
2675
2688
  });
2689
+ let executionResult;
2676
2690
  if (executeFn) {
2677
2691
  logger2.debug("Using custom execution function", { workerId: id });
2678
- return await executeFn(state, runConfig);
2679
- }
2680
- if (agent) {
2681
- if (isReActAgent(agent)) {
2682
- logger2.debug("Using ReAct agent", { workerId: id });
2683
- const wrappedFn = wrapReActAgent(id, agent, verbose);
2684
- return await wrappedFn(state, runConfig);
2685
- } else {
2686
- logger2.warn("Agent provided but not a ReAct agent, falling back", { workerId: id });
2687
- }
2688
- }
2689
- if (!model) {
2692
+ executionResult = await executeFn(state, runConfig);
2693
+ } else if (agent && isReActAgent(agent)) {
2694
+ logger2.debug("Using ReAct agent", { workerId: id });
2695
+ const wrappedFn = wrapReActAgent(id, agent, verbose);
2696
+ executionResult = await wrappedFn(state, runConfig);
2697
+ } else if (model) {
2698
+ executionResult = await executeWithLLM();
2699
+ } else {
2690
2700
  logger2.error("Worker missing required configuration", { workerId: id });
2691
2701
  throw new Error(
2692
2702
  `Worker ${id} requires either a model, an agent, or a custom execution function. Provide one of: config.model, config.agent, or config.executeFn`
2693
2703
  );
2694
2704
  }
2695
- logger2.debug("Using default LLM execution", {
2696
- workerId: id,
2697
- hasTools: tools.length > 0,
2698
- toolCount: tools.length
2699
- });
2700
- const defaultSystemPrompt = `You are a specialized worker agent with the following capabilities:
2701
- Skills: ${capabilities.skills.join(", ")}
2702
- Tools: ${capabilities.tools.join(", ")}
2703
-
2704
- Execute the assigned task using your skills and tools. Provide a clear, actionable result.`;
2705
- const messages = [
2706
- new import_messages5.SystemMessage(systemPrompt || defaultSystemPrompt),
2707
- new import_messages5.HumanMessage(currentAssignment.task)
2708
- ];
2709
- let modelToUse = model;
2710
- if (tools.length > 0 && model.bindTools) {
2711
- logger2.debug("Binding tools to model", {
2712
- workerId: id,
2713
- toolCount: tools.length,
2714
- toolNames: tools.map((t) => t.metadata.name)
2715
- });
2716
- const langchainTools = (0, import_core9.toLangChainTools)(tools);
2717
- modelToUse = model.bindTools(langchainTools);
2718
- }
2719
- logger2.debug("Invoking LLM", { workerId: id });
2720
- const response = await modelToUse.invoke(messages);
2721
- const result = typeof response.content === "string" ? response.content : JSON.stringify(response.content);
2722
- logger2.info("Worker task completed", {
2723
- workerId: id,
2724
- assignmentId: currentAssignment.id,
2725
- resultLength: result.length,
2726
- resultPreview: result.substring(0, 100)
2727
- });
2728
- const taskResult = {
2729
- assignmentId: currentAssignment.id,
2730
- workerId: id,
2731
- success: true,
2732
- result,
2733
- completedAt: Date.now(),
2734
- metadata: {
2735
- skills_used: capabilities.skills
2736
- }
2737
- };
2738
- const message = {
2739
- id: `msg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
2740
- from: id,
2741
- to: ["supervisor"],
2742
- type: "task_result",
2743
- content: result,
2744
- timestamp: Date.now(),
2745
- metadata: {
2746
- assignmentId: currentAssignment.id,
2747
- success: true
2748
- }
2749
- };
2705
+ const currentWorker = state.workers[id];
2750
2706
  const updatedWorkers = {
2751
2707
  ...state.workers,
2752
2708
  [id]: {
2753
- ...capabilities,
2754
- currentWorkload: Math.max(0, capabilities.currentWorkload - 1)
2709
+ ...currentWorker,
2710
+ currentWorkload: Math.max(0, currentWorker.currentWorkload - 1)
2755
2711
  }
2756
2712
  };
2757
2713
  logger2.debug("Worker state update", {
2758
2714
  workerId: id,
2715
+ previousWorkload: currentWorker.currentWorkload,
2759
2716
  newWorkload: updatedWorkers[id].currentWorkload
2760
2717
  });
2761
2718
  return {
2762
- completedTasks: [taskResult],
2763
- messages: [message],
2719
+ ...executionResult,
2764
2720
  workers: updatedWorkers
2765
2721
  };
2722
+ async function executeWithLLM() {
2723
+ logger2.debug("Using default LLM execution", {
2724
+ workerId: id,
2725
+ hasTools: tools.length > 0,
2726
+ toolCount: tools.length
2727
+ });
2728
+ const defaultSystemPrompt = `You are a specialized worker agent with the following capabilities:
2729
+ Skills: ${capabilities.skills.join(", ")}
2730
+ Tools: ${capabilities.tools.join(", ")}
2731
+
2732
+ Execute the assigned task using your skills and tools. Provide a clear, actionable result.`;
2733
+ const messages = [
2734
+ new import_messages5.SystemMessage(systemPrompt || defaultSystemPrompt),
2735
+ new import_messages5.HumanMessage(currentAssignment.task)
2736
+ ];
2737
+ let modelToUse = model;
2738
+ if (tools.length > 0 && model.bindTools) {
2739
+ logger2.debug("Binding tools to model", {
2740
+ workerId: id,
2741
+ toolCount: tools.length,
2742
+ toolNames: tools.map((t) => t.metadata.name)
2743
+ });
2744
+ const langchainTools = (0, import_core9.toLangChainTools)(tools);
2745
+ modelToUse = model.bindTools(langchainTools);
2746
+ }
2747
+ logger2.debug("Invoking LLM", { workerId: id });
2748
+ const response = await modelToUse.invoke(messages);
2749
+ const result = typeof response.content === "string" ? response.content : JSON.stringify(response.content);
2750
+ logger2.info("Worker task completed", {
2751
+ workerId: id,
2752
+ assignmentId: currentAssignment.id,
2753
+ resultLength: result.length,
2754
+ resultPreview: result.substring(0, 100)
2755
+ });
2756
+ const taskResult = {
2757
+ assignmentId: currentAssignment.id,
2758
+ workerId: id,
2759
+ success: true,
2760
+ result,
2761
+ completedAt: Date.now(),
2762
+ metadata: {
2763
+ skills_used: capabilities.skills
2764
+ }
2765
+ };
2766
+ const message = {
2767
+ id: `msg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
2768
+ from: id,
2769
+ to: ["supervisor"],
2770
+ type: "task_result",
2771
+ content: result,
2772
+ timestamp: Date.now(),
2773
+ metadata: {
2774
+ assignmentId: currentAssignment.id,
2775
+ success: true
2776
+ }
2777
+ };
2778
+ return {
2779
+ completedTasks: [taskResult],
2780
+ messages: [message]
2781
+ };
2782
+ }
2766
2783
  } catch (error) {
2767
2784
  const errorMessage = handleNodeError(error, `worker:${id}`, false);
2768
2785
  logger2.error("Worker node error", {
package/dist/index.js CHANGED
@@ -2505,11 +2505,22 @@ function createSupervisorNode(config) {
2505
2505
  priority: assignment.priority
2506
2506
  }
2507
2507
  }));
2508
+ const updatedWorkers = { ...state.workers };
2509
+ for (const assignment of assignments) {
2510
+ const worker = updatedWorkers[assignment.workerId];
2511
+ if (worker) {
2512
+ updatedWorkers[assignment.workerId] = {
2513
+ ...worker,
2514
+ currentWorkload: worker.currentWorkload + 1
2515
+ };
2516
+ }
2517
+ }
2508
2518
  logger2.info("Supervisor routing complete", {
2509
2519
  currentAgent: targetAgents.join(","),
2510
2520
  status: "executing",
2511
2521
  assignmentCount: assignments.length,
2512
- nextIteration: state.iteration + 1
2522
+ nextIteration: state.iteration + 1,
2523
+ workloadUpdates: Object.entries(updatedWorkers).filter(([id]) => targetAgents.includes(id)).map(([id, caps]) => ({ workerId: id, newWorkload: caps.currentWorkload }))
2513
2524
  });
2514
2525
  return {
2515
2526
  currentAgent: targetAgents.join(","),
@@ -2519,6 +2530,8 @@ function createSupervisorNode(config) {
2519
2530
  activeAssignments: assignments,
2520
2531
  // Multiple assignments for parallel execution!
2521
2532
  messages,
2533
+ workers: updatedWorkers,
2534
+ // Include updated workload
2522
2535
  // Add 1 to iteration counter (uses additive reducer)
2523
2536
  iteration: 1
2524
2537
  };
@@ -2570,96 +2583,100 @@ function createWorkerNode(config) {
2570
2583
  taskLength: currentAssignment.task.length,
2571
2584
  taskPreview: currentAssignment.task.substring(0, 100)
2572
2585
  });
2586
+ let executionResult;
2573
2587
  if (executeFn) {
2574
2588
  logger2.debug("Using custom execution function", { workerId: id });
2575
- return await executeFn(state, runConfig);
2576
- }
2577
- if (agent) {
2578
- if (isReActAgent(agent)) {
2579
- logger2.debug("Using ReAct agent", { workerId: id });
2580
- const wrappedFn = wrapReActAgent(id, agent, verbose);
2581
- return await wrappedFn(state, runConfig);
2582
- } else {
2583
- logger2.warn("Agent provided but not a ReAct agent, falling back", { workerId: id });
2584
- }
2585
- }
2586
- if (!model) {
2589
+ executionResult = await executeFn(state, runConfig);
2590
+ } else if (agent && isReActAgent(agent)) {
2591
+ logger2.debug("Using ReAct agent", { workerId: id });
2592
+ const wrappedFn = wrapReActAgent(id, agent, verbose);
2593
+ executionResult = await wrappedFn(state, runConfig);
2594
+ } else if (model) {
2595
+ executionResult = await executeWithLLM();
2596
+ } else {
2587
2597
  logger2.error("Worker missing required configuration", { workerId: id });
2588
2598
  throw new Error(
2589
2599
  `Worker ${id} requires either a model, an agent, or a custom execution function. Provide one of: config.model, config.agent, or config.executeFn`
2590
2600
  );
2591
2601
  }
2592
- logger2.debug("Using default LLM execution", {
2593
- workerId: id,
2594
- hasTools: tools.length > 0,
2595
- toolCount: tools.length
2596
- });
2597
- const defaultSystemPrompt = `You are a specialized worker agent with the following capabilities:
2598
- Skills: ${capabilities.skills.join(", ")}
2599
- Tools: ${capabilities.tools.join(", ")}
2600
-
2601
- Execute the assigned task using your skills and tools. Provide a clear, actionable result.`;
2602
- const messages = [
2603
- new SystemMessage5(systemPrompt || defaultSystemPrompt),
2604
- new HumanMessage5(currentAssignment.task)
2605
- ];
2606
- let modelToUse = model;
2607
- if (tools.length > 0 && model.bindTools) {
2608
- logger2.debug("Binding tools to model", {
2609
- workerId: id,
2610
- toolCount: tools.length,
2611
- toolNames: tools.map((t) => t.metadata.name)
2612
- });
2613
- const langchainTools = toLangChainTools2(tools);
2614
- modelToUse = model.bindTools(langchainTools);
2615
- }
2616
- logger2.debug("Invoking LLM", { workerId: id });
2617
- const response = await modelToUse.invoke(messages);
2618
- const result = typeof response.content === "string" ? response.content : JSON.stringify(response.content);
2619
- logger2.info("Worker task completed", {
2620
- workerId: id,
2621
- assignmentId: currentAssignment.id,
2622
- resultLength: result.length,
2623
- resultPreview: result.substring(0, 100)
2624
- });
2625
- const taskResult = {
2626
- assignmentId: currentAssignment.id,
2627
- workerId: id,
2628
- success: true,
2629
- result,
2630
- completedAt: Date.now(),
2631
- metadata: {
2632
- skills_used: capabilities.skills
2633
- }
2634
- };
2635
- const message = {
2636
- id: `msg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
2637
- from: id,
2638
- to: ["supervisor"],
2639
- type: "task_result",
2640
- content: result,
2641
- timestamp: Date.now(),
2642
- metadata: {
2643
- assignmentId: currentAssignment.id,
2644
- success: true
2645
- }
2646
- };
2602
+ const currentWorker = state.workers[id];
2647
2603
  const updatedWorkers = {
2648
2604
  ...state.workers,
2649
2605
  [id]: {
2650
- ...capabilities,
2651
- currentWorkload: Math.max(0, capabilities.currentWorkload - 1)
2606
+ ...currentWorker,
2607
+ currentWorkload: Math.max(0, currentWorker.currentWorkload - 1)
2652
2608
  }
2653
2609
  };
2654
2610
  logger2.debug("Worker state update", {
2655
2611
  workerId: id,
2612
+ previousWorkload: currentWorker.currentWorkload,
2656
2613
  newWorkload: updatedWorkers[id].currentWorkload
2657
2614
  });
2658
2615
  return {
2659
- completedTasks: [taskResult],
2660
- messages: [message],
2616
+ ...executionResult,
2661
2617
  workers: updatedWorkers
2662
2618
  };
2619
+ async function executeWithLLM() {
2620
+ logger2.debug("Using default LLM execution", {
2621
+ workerId: id,
2622
+ hasTools: tools.length > 0,
2623
+ toolCount: tools.length
2624
+ });
2625
+ const defaultSystemPrompt = `You are a specialized worker agent with the following capabilities:
2626
+ Skills: ${capabilities.skills.join(", ")}
2627
+ Tools: ${capabilities.tools.join(", ")}
2628
+
2629
+ Execute the assigned task using your skills and tools. Provide a clear, actionable result.`;
2630
+ const messages = [
2631
+ new SystemMessage5(systemPrompt || defaultSystemPrompt),
2632
+ new HumanMessage5(currentAssignment.task)
2633
+ ];
2634
+ let modelToUse = model;
2635
+ if (tools.length > 0 && model.bindTools) {
2636
+ logger2.debug("Binding tools to model", {
2637
+ workerId: id,
2638
+ toolCount: tools.length,
2639
+ toolNames: tools.map((t) => t.metadata.name)
2640
+ });
2641
+ const langchainTools = toLangChainTools2(tools);
2642
+ modelToUse = model.bindTools(langchainTools);
2643
+ }
2644
+ logger2.debug("Invoking LLM", { workerId: id });
2645
+ const response = await modelToUse.invoke(messages);
2646
+ const result = typeof response.content === "string" ? response.content : JSON.stringify(response.content);
2647
+ logger2.info("Worker task completed", {
2648
+ workerId: id,
2649
+ assignmentId: currentAssignment.id,
2650
+ resultLength: result.length,
2651
+ resultPreview: result.substring(0, 100)
2652
+ });
2653
+ const taskResult = {
2654
+ assignmentId: currentAssignment.id,
2655
+ workerId: id,
2656
+ success: true,
2657
+ result,
2658
+ completedAt: Date.now(),
2659
+ metadata: {
2660
+ skills_used: capabilities.skills
2661
+ }
2662
+ };
2663
+ const message = {
2664
+ id: `msg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
2665
+ from: id,
2666
+ to: ["supervisor"],
2667
+ type: "task_result",
2668
+ content: result,
2669
+ timestamp: Date.now(),
2670
+ metadata: {
2671
+ assignmentId: currentAssignment.id,
2672
+ success: true
2673
+ }
2674
+ };
2675
+ return {
2676
+ completedTasks: [taskResult],
2677
+ messages: [message]
2678
+ };
2679
+ }
2663
2680
  } catch (error) {
2664
2681
  const errorMessage = handleNodeError(error, `worker:${id}`, false);
2665
2682
  logger2.error("Worker node error", {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentforge/patterns",
3
- "version": "0.11.0",
3
+ "version": "0.11.2",
4
4
  "description": "Agent patterns (ReAct, Planner-Executor) for AgentForge framework",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",