@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 +7 -0
- package/dist/index.cjs +89 -72
- package/dist/index.js +89 -72
- package/package.json +1 -1
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
|
-
|
|
2679
|
-
}
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
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
|
-
|
|
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
|
-
...
|
|
2754
|
-
currentWorkload: Math.max(0,
|
|
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
|
-
|
|
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
|
-
|
|
2576
|
-
}
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
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
|
-
|
|
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
|
-
...
|
|
2651
|
-
currentWorkload: Math.max(0,
|
|
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
|
-
|
|
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", {
|