@agentforge/patterns 0.16.0 → 0.16.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/dist/index.cjs CHANGED
@@ -888,7 +888,7 @@ var PlanStepSchema = import_zod4.z.object({
888
888
  /**
889
889
  * Optional arguments for the tool
890
890
  */
891
- args: import_zod4.z.record(import_zod4.z.any()).optional().describe("Arguments to pass to the tool")
891
+ args: import_zod4.z.record(import_zod4.z.string(), import_zod4.z.unknown()).optional().describe("Arguments to pass to the tool")
892
892
  });
893
893
  var CompletedStepSchema = import_zod4.z.object({
894
894
  /**
@@ -898,7 +898,7 @@ var CompletedStepSchema = import_zod4.z.object({
898
898
  /**
899
899
  * The result of executing the step
900
900
  */
901
- result: import_zod4.z.any().describe("The result of executing the step"),
901
+ result: import_zod4.z.unknown().describe("The result of executing the step"),
902
902
  /**
903
903
  * Whether the step succeeded
904
904
  */
@@ -1075,6 +1075,9 @@ var REMAINING_STEP_TEMPLATE = `Step {stepNumber}: {description}
1075
1075
  var plannerLogger = createPatternLogger("agentforge:patterns:plan-execute:planner");
1076
1076
  var executorLogger = createPatternLogger("agentforge:patterns:plan-execute:executor");
1077
1077
  var replannerLogger = createPatternLogger("agentforge:patterns:plan-execute:replanner");
1078
+ function invokePlanExecuteTool(tool, args) {
1079
+ return tool.invoke.call(tool, args);
1080
+ }
1078
1081
  function createPlannerNode(config) {
1079
1082
  const {
1080
1083
  model,
@@ -1142,10 +1145,18 @@ function createExecutorNode(config) {
1142
1145
  const {
1143
1146
  tools,
1144
1147
  model,
1145
- parallel = false,
1148
+ parallel,
1146
1149
  stepTimeout = 3e4,
1147
1150
  enableDeduplication = true
1148
1151
  } = config;
1152
+ if (typeof model !== "undefined") {
1153
+ executorLogger.warn("ExecutorConfig.model is currently unsupported and will be ignored");
1154
+ }
1155
+ if (typeof parallel !== "undefined") {
1156
+ executorLogger.warn("ExecutorConfig.parallel is currently unsupported and will be ignored", {
1157
+ parallel
1158
+ });
1159
+ }
1149
1160
  return async (state) => {
1150
1161
  const { plan, currentStepIndex = 0, pastSteps = [], iteration = 0 } = state;
1151
1162
  try {
@@ -1222,13 +1233,20 @@ function createExecutorNode(config) {
1222
1233
  throw new Error(`Tool not found: ${currentStep.tool}`);
1223
1234
  }
1224
1235
  const startTime = Date.now();
1225
- const timeoutPromise = new Promise(
1226
- (_, reject) => setTimeout(() => reject(new Error("Step execution timeout")), stepTimeout)
1227
- );
1228
- result = await Promise.race([
1229
- tool.invoke(currentStep.args || {}),
1230
- timeoutPromise
1231
- ]);
1236
+ let timeoutId;
1237
+ try {
1238
+ const timeoutPromise = new Promise((_, reject) => {
1239
+ timeoutId = setTimeout(() => reject(new Error("Step execution timeout")), stepTimeout);
1240
+ });
1241
+ result = await Promise.race([
1242
+ invokePlanExecuteTool(tool, currentStep.args || {}),
1243
+ timeoutPromise
1244
+ ]);
1245
+ } finally {
1246
+ if (timeoutId !== void 0) {
1247
+ clearTimeout(timeoutId);
1248
+ }
1249
+ }
1232
1250
  const executionTime = Date.now() - startTime;
1233
1251
  executorLogger.debug("Step executed successfully", {
1234
1252
  stepId: currentStep.id,
@@ -1285,9 +1303,14 @@ function createExecutorNode(config) {
1285
1303
  function createReplannerNode(config) {
1286
1304
  const {
1287
1305
  model,
1288
- replanThreshold = 0.7,
1306
+ replanThreshold,
1289
1307
  systemPrompt = DEFAULT_REPLANNER_SYSTEM_PROMPT
1290
1308
  } = config;
1309
+ if (typeof replanThreshold !== "undefined") {
1310
+ replannerLogger.warn("ReplannerConfig.replanThreshold is currently unsupported and will be ignored", {
1311
+ replanThreshold
1312
+ });
1313
+ }
1291
1314
  return async (state) => {
1292
1315
  const startTime = Date.now();
1293
1316
  try {
@@ -2656,16 +2679,82 @@ function wrapReActAgent(workerId, agent, verbose = false) {
2656
2679
  };
2657
2680
  }
2658
2681
 
2659
- // src/multi-agent/nodes.ts
2682
+ // src/multi-agent/nodes/shared.ts
2660
2683
  var import_messages5 = require("@langchain/core/messages");
2661
2684
  var import_core8 = require("@agentforge/core");
2662
2685
  var logger2 = createPatternLogger("agentforge:patterns:multi-agent:nodes");
2686
+ function createGeneratedId(prefix) {
2687
+ return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 11)}`;
2688
+ }
2689
+ function createTaskAssignmentId() {
2690
+ return `task_${Date.now()}_${Math.random().toString(36).slice(2, 11)}`;
2691
+ }
2692
+ function getLatestTaskContent(state) {
2693
+ return state.messages[state.messages.length - 1]?.content || state.input;
2694
+ }
2695
+ function createTaskAssignments(workerIds, task) {
2696
+ return workerIds.map((workerId) => ({
2697
+ id: createTaskAssignmentId(),
2698
+ workerId,
2699
+ task,
2700
+ priority: 5,
2701
+ assignedAt: Date.now()
2702
+ }));
2703
+ }
2704
+ function createAssignmentMessages(assignments) {
2705
+ return assignments.map((assignment) => ({
2706
+ id: createGeneratedId("msg"),
2707
+ from: "supervisor",
2708
+ to: [assignment.workerId],
2709
+ type: "task_assignment",
2710
+ content: assignment.task,
2711
+ timestamp: Date.now(),
2712
+ metadata: {
2713
+ assignmentId: assignment.id,
2714
+ priority: assignment.priority
2715
+ }
2716
+ }));
2717
+ }
2718
+ function findCurrentAssignment(state, workerId) {
2719
+ return state.activeAssignments.find(
2720
+ (assignment) => assignment.workerId === workerId && !state.completedTasks.some((task) => task.assignmentId === assignment.id)
2721
+ );
2722
+ }
2663
2723
  function convertWorkerToolsForLangChain(tools) {
2664
2724
  const safeTools = tools ?? [];
2665
- return (0, import_core8.toLangChainTools)(
2666
- safeTools
2667
- );
2725
+ return (0, import_core8.toLangChainTools)(safeTools);
2668
2726
  }
2727
+ function serializeModelContent(content) {
2728
+ if (typeof content === "string") {
2729
+ return content;
2730
+ }
2731
+ try {
2732
+ const serialized = JSON.stringify(content);
2733
+ if (typeof serialized !== "string") {
2734
+ const error = new Error(
2735
+ "Failed to serialize model content: JSON.stringify returned undefined"
2736
+ );
2737
+ logger2.error("Model content serialization failed", {
2738
+ errorMessage: error.message,
2739
+ contentType: content === null ? "null" : typeof content
2740
+ });
2741
+ throw error;
2742
+ }
2743
+ return serialized;
2744
+ } catch (error) {
2745
+ const normalizedError = error instanceof Error ? error : new Error("Unknown error during model content serialization");
2746
+ logger2.error("Model content serialization threw an error", {
2747
+ errorMessage: normalizedError.message,
2748
+ contentType: content === null ? "null" : typeof content
2749
+ });
2750
+ throw normalizedError;
2751
+ }
2752
+ }
2753
+ function createPromptMessages(systemPrompt, task) {
2754
+ return [new import_messages5.SystemMessage(systemPrompt), new import_messages5.HumanMessage(task)];
2755
+ }
2756
+
2757
+ // src/multi-agent/nodes/aggregator.ts
2669
2758
  var DEFAULT_AGGREGATOR_SYSTEM_PROMPT = `You are an aggregator agent responsible for combining results from multiple worker agents.
2670
2759
 
2671
2760
  Your job is to:
@@ -2675,12 +2764,124 @@ Your job is to:
2675
2764
  4. Provide a clear, comprehensive final answer
2676
2765
 
2677
2766
  Be concise but thorough in your aggregation.`;
2678
- function createSupervisorNode(config) {
2767
+ function createAggregationPrompt(state) {
2768
+ const taskResults = state.completedTasks.map((task, idx) => {
2769
+ const status = task.success ? "\u2713" : "\u2717";
2770
+ const result = task.success ? task.result : `Error: ${task.error}`;
2771
+ return `${idx + 1}. [${status}] Worker ${task.workerId}:
2772
+ ${result}`;
2773
+ }).join("\n\n");
2774
+ return `Original query: ${state.input}
2775
+
2776
+ Worker results:
2777
+ ${taskResults}
2778
+
2779
+ Please synthesize these results into a comprehensive response that addresses the original query.`;
2780
+ }
2781
+ function createAggregatorNode(config = {}) {
2679
2782
  const {
2680
- strategy,
2681
- verbose = false,
2682
- maxIterations = 10
2783
+ model,
2784
+ systemPrompt = DEFAULT_AGGREGATOR_SYSTEM_PROMPT,
2785
+ aggregateFn
2683
2786
  } = config;
2787
+ return async (state) => {
2788
+ try {
2789
+ logger2.info("Aggregator node executing", {
2790
+ completedTasks: state.completedTasks.length,
2791
+ successfulTasks: state.completedTasks.filter((task) => task.success).length,
2792
+ failedTasks: state.completedTasks.filter((task) => !task.success).length
2793
+ });
2794
+ logger2.debug("Combining results from workers");
2795
+ if (aggregateFn) {
2796
+ logger2.debug("Using custom aggregation function");
2797
+ const response2 = await aggregateFn(state);
2798
+ logger2.info("Custom aggregation complete", {
2799
+ responseLength: response2.length
2800
+ });
2801
+ return {
2802
+ response: response2,
2803
+ status: "completed"
2804
+ };
2805
+ }
2806
+ if (state.completedTasks.length === 0) {
2807
+ logger2.warn("No completed tasks to aggregate");
2808
+ return {
2809
+ response: "No tasks were completed.",
2810
+ status: "completed"
2811
+ };
2812
+ }
2813
+ if (!model) {
2814
+ logger2.debug("No model provided, concatenating results");
2815
+ const combinedResults = state.completedTasks.filter((task) => task.success).map((task) => task.result).join("\n\n");
2816
+ logger2.info("Simple concatenation complete", {
2817
+ resultLength: combinedResults.length
2818
+ });
2819
+ return {
2820
+ response: combinedResults || "No successful results to aggregate.",
2821
+ status: "completed"
2822
+ };
2823
+ }
2824
+ logger2.debug("Using LLM for intelligent aggregation", {
2825
+ taskCount: state.completedTasks.length
2826
+ });
2827
+ const messages = createPromptMessages(systemPrompt, createAggregationPrompt(state));
2828
+ logger2.debug("Invoking aggregation LLM");
2829
+ const response = await model.invoke(messages);
2830
+ const aggregatedResponse = serializeModelContent(response.content);
2831
+ logger2.info("Aggregation complete", {
2832
+ responseLength: aggregatedResponse.length
2833
+ });
2834
+ logger2.debug("Aggregation response details", {
2835
+ responseLength: aggregatedResponse.length
2836
+ });
2837
+ logger2.debug("Aggregation complete");
2838
+ return {
2839
+ response: aggregatedResponse,
2840
+ status: "completed"
2841
+ };
2842
+ } catch (error) {
2843
+ const errorMessage = handleNodeError(error, "aggregator", false);
2844
+ logger2.error("Aggregator node error", {
2845
+ error: errorMessage,
2846
+ ...error instanceof Error && error.stack ? { stack: error.stack } : {},
2847
+ completedTasks: state.completedTasks.length
2848
+ });
2849
+ return {
2850
+ status: "failed",
2851
+ error: errorMessage
2852
+ };
2853
+ }
2854
+ };
2855
+ }
2856
+
2857
+ // src/multi-agent/nodes/supervisor.ts
2858
+ function allAssignmentsCompleted(state) {
2859
+ return state.activeAssignments.every(
2860
+ (assignment) => state.completedTasks.some((task) => task.assignmentId === assignment.id)
2861
+ );
2862
+ }
2863
+ function incrementAssignedWorkerLoads(state, assignments) {
2864
+ const updatedWorkers = { ...state.workers };
2865
+ for (const assignment of assignments) {
2866
+ const worker = updatedWorkers[assignment.workerId];
2867
+ if (!worker) {
2868
+ logger2.error("Worker not found in state", {
2869
+ workerId: assignment.workerId,
2870
+ availableWorkers: Object.keys(updatedWorkers)
2871
+ });
2872
+ throw new Error(
2873
+ `Worker ${assignment.workerId} not found in state.workers. Available workers: ${Object.keys(updatedWorkers).join(", ")}`
2874
+ );
2875
+ }
2876
+ updatedWorkers[assignment.workerId] = {
2877
+ ...worker,
2878
+ currentWorkload: worker.currentWorkload + 1
2879
+ };
2880
+ }
2881
+ return updatedWorkers;
2882
+ }
2883
+ function createSupervisorNode(config) {
2884
+ const { strategy, maxIterations = 10 } = config;
2684
2885
  return async (state) => {
2685
2886
  try {
2686
2887
  logger2.info("Supervisor node executing", {
@@ -2701,9 +2902,7 @@ function createSupervisorNode(config) {
2701
2902
  currentAgent: "aggregator"
2702
2903
  };
2703
2904
  }
2704
- const allCompleted = state.activeAssignments.every(
2705
- (assignment) => state.completedTasks.some((task2) => task2.assignmentId === assignment.id)
2706
- );
2905
+ const allCompleted = allAssignmentsCompleted(state);
2707
2906
  logger2.debug("Checking task completion", {
2708
2907
  activeAssignments: state.activeAssignments.length,
2709
2908
  completedTasks: state.completedTasks.length,
@@ -2741,6 +2940,7 @@ function createSupervisorNode(config) {
2741
2940
  reasoning: decision.reasoning,
2742
2941
  confidence: decision.confidence
2743
2942
  });
2943
+ logger2.debug(`Routing to ${targetAgents[0]}: ${decision.reasoning}`);
2744
2944
  } else {
2745
2945
  logger2.info("Routing to multiple agents in parallel", {
2746
2946
  targetAgents,
@@ -2748,57 +2948,22 @@ function createSupervisorNode(config) {
2748
2948
  reasoning: decision.reasoning,
2749
2949
  confidence: decision.confidence
2750
2950
  });
2951
+ logger2.debug(
2952
+ `Routing to ${targetAgents.length} agents in parallel [${targetAgents.join(", ")}]: ${decision.reasoning}`
2953
+ );
2751
2954
  }
2752
- if (targetAgents.length === 1) {
2753
- logger2.debug(`Routing to ${targetAgents[0]}: ${decision.reasoning}`);
2754
- } else {
2755
- logger2.debug(`Routing to ${targetAgents.length} agents in parallel [${targetAgents.join(", ")}]: ${decision.reasoning}`);
2756
- }
2757
- const task = state.messages[state.messages.length - 1]?.content || state.input;
2758
- const assignments = targetAgents.map((workerId) => ({
2759
- id: `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
2760
- workerId,
2761
- task,
2762
- priority: 5,
2763
- assignedAt: Date.now()
2764
- }));
2955
+ const task = getLatestTaskContent(state);
2956
+ const assignments = createTaskAssignments(targetAgents, task);
2765
2957
  logger2.debug("Created task assignments", {
2766
2958
  assignmentCount: assignments.length,
2767
- assignments: assignments.map((a) => ({
2768
- id: a.id,
2769
- workerId: a.workerId,
2770
- taskLength: a.task.length
2959
+ assignments: assignments.map((assignment) => ({
2960
+ id: assignment.id,
2961
+ workerId: assignment.workerId,
2962
+ taskLength: assignment.task.length
2771
2963
  }))
2772
2964
  });
2773
- const messages = assignments.map((assignment) => ({
2774
- id: `msg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
2775
- from: "supervisor",
2776
- to: [assignment.workerId],
2777
- type: "task_assignment",
2778
- content: assignment.task,
2779
- timestamp: Date.now(),
2780
- metadata: {
2781
- assignmentId: assignment.id,
2782
- priority: assignment.priority
2783
- }
2784
- }));
2785
- const updatedWorkers = { ...state.workers };
2786
- for (const assignment of assignments) {
2787
- const worker = updatedWorkers[assignment.workerId];
2788
- if (!worker) {
2789
- logger2.error("Worker not found in state", {
2790
- workerId: assignment.workerId,
2791
- availableWorkers: Object.keys(updatedWorkers)
2792
- });
2793
- throw new Error(
2794
- `Worker ${assignment.workerId} not found in state.workers. Available workers: ${Object.keys(updatedWorkers).join(", ")}`
2795
- );
2796
- }
2797
- updatedWorkers[assignment.workerId] = {
2798
- ...worker,
2799
- currentWorkload: worker.currentWorkload + 1
2800
- };
2801
- }
2965
+ const messages = createAssignmentMessages(assignments);
2966
+ const updatedWorkers = incrementAssignedWorkerLoads(state, assignments);
2802
2967
  logger2.info("Supervisor routing complete", {
2803
2968
  currentAgent: targetAgents.join(","),
2804
2969
  status: "executing",
@@ -2808,41 +2973,187 @@ function createSupervisorNode(config) {
2808
2973
  });
2809
2974
  return {
2810
2975
  currentAgent: targetAgents.join(","),
2811
- // Store all agents (for backward compat)
2812
2976
  status: "executing",
2813
2977
  routingHistory: [decision],
2814
2978
  activeAssignments: assignments,
2815
- // Multiple assignments for parallel execution!
2816
2979
  messages,
2817
2980
  workers: updatedWorkers,
2818
- // Include updated workload
2819
- // Add 1 to iteration counter (uses additive reducer)
2820
2981
  iteration: 1
2821
2982
  };
2822
2983
  } catch (error) {
2984
+ const errorMessage = handleNodeError(error, "supervisor", false);
2823
2985
  logger2.error("Supervisor node error", {
2824
- error: error instanceof Error ? error.message : String(error),
2986
+ error: errorMessage,
2825
2987
  ...error instanceof Error && error.stack ? { stack: error.stack } : {},
2826
2988
  iteration: state.iteration
2827
2989
  });
2828
2990
  return {
2829
2991
  status: "failed",
2830
- error: error instanceof Error ? error.message : "Unknown error in supervisor"
2992
+ error: errorMessage
2831
2993
  };
2832
2994
  }
2833
2995
  };
2834
2996
  }
2997
+
2998
+ // src/multi-agent/nodes/worker.ts
2999
+ function buildDefaultSystemPrompt(config) {
3000
+ return `You are a specialized worker agent with the following capabilities:
3001
+ Skills: ${config.capabilities.skills.join(", ")}
3002
+ Tools: ${config.capabilities.tools.join(", ")}
3003
+
3004
+ Execute the assigned task using your skills and tools. Provide a clear, actionable result.`;
3005
+ }
3006
+ async function invokeWorkerModel(model, config, assignment) {
3007
+ const messages = createPromptMessages(
3008
+ config.systemPrompt || buildDefaultSystemPrompt(config),
3009
+ assignment.task
3010
+ );
3011
+ let modelToUse = model;
3012
+ if (config.tools && config.tools.length > 0 && model.bindTools) {
3013
+ logger2.debug("Binding tools to model", {
3014
+ workerId: config.id,
3015
+ toolCount: config.tools.length,
3016
+ toolNames: config.tools.map((tool) => tool.metadata.name)
3017
+ });
3018
+ modelToUse = model.bindTools(
3019
+ convertWorkerToolsForLangChain(config.tools)
3020
+ );
3021
+ }
3022
+ logger2.debug("Invoking LLM", { workerId: config.id });
3023
+ const response = await modelToUse.invoke(messages);
3024
+ const result = serializeModelContent(response.content);
3025
+ logger2.info("Worker task completed", {
3026
+ workerId: config.id,
3027
+ assignmentId: assignment.id,
3028
+ resultLength: result.length
3029
+ });
3030
+ logger2.debug("Worker result details", {
3031
+ workerId: config.id,
3032
+ assignmentId: assignment.id,
3033
+ resultLength: result.length
3034
+ });
3035
+ const taskResult = {
3036
+ assignmentId: assignment.id,
3037
+ workerId: config.id,
3038
+ success: true,
3039
+ result,
3040
+ completedAt: Date.now(),
3041
+ metadata: {
3042
+ skills_used: config.capabilities.skills
3043
+ }
3044
+ };
3045
+ const message = {
3046
+ id: createGeneratedId("msg"),
3047
+ from: config.id,
3048
+ to: ["supervisor"],
3049
+ type: "task_result",
3050
+ content: result,
3051
+ timestamp: Date.now(),
3052
+ metadata: {
3053
+ assignmentId: assignment.id,
3054
+ success: true
3055
+ }
3056
+ };
3057
+ return {
3058
+ completedTasks: [taskResult],
3059
+ messages: [message]
3060
+ };
3061
+ }
3062
+ function getStateWorkerOrThrow(state, workerId) {
3063
+ const currentWorker = state.workers[workerId];
3064
+ if (!currentWorker) {
3065
+ logger2.error("Attempted to decrement workload for unknown worker", {
3066
+ workerId,
3067
+ availableWorkers: Object.keys(state.workers)
3068
+ });
3069
+ throw new Error(`Worker "${workerId}" not found when decrementing workload.`);
3070
+ }
3071
+ return currentWorker;
3072
+ }
3073
+ function resolvePreviousWorkload(workerId, currentWorker, workerFromExecution) {
3074
+ const workloadFromWorker = workerFromExecution?.currentWorkload;
3075
+ if (typeof workloadFromWorker === "number" && Number.isFinite(workloadFromWorker)) {
3076
+ return workloadFromWorker;
3077
+ }
3078
+ if (typeof currentWorker.currentWorkload === "number" && Number.isFinite(currentWorker.currentWorkload)) {
3079
+ return currentWorker.currentWorkload;
3080
+ }
3081
+ logger2.error("Worker workload is not a valid number; cannot decrement", {
3082
+ workerId,
3083
+ workloadFromState: currentWorker.currentWorkload,
3084
+ ...typeof workloadFromWorker === "number" ? { workloadFromWorker } : {}
3085
+ });
3086
+ throw new Error(
3087
+ `Worker "${workerId}" does not have a valid numeric currentWorkload to decrement.`
3088
+ );
3089
+ }
3090
+ function mergeWorkersWithDecrement(state, workerId, executionResult) {
3091
+ const currentWorker = getStateWorkerOrThrow(state, workerId);
3092
+ const executionResultWorkers = executionResult.workers || {};
3093
+ const baseWorkers = {
3094
+ ...state.workers,
3095
+ ...executionResultWorkers
3096
+ };
3097
+ const workerFromExecution = executionResultWorkers[workerId];
3098
+ const previousWorkload = resolvePreviousWorkload(
3099
+ workerId,
3100
+ currentWorker,
3101
+ workerFromExecution
3102
+ );
3103
+ const hasWorkerOverride = typeof workerFromExecution === "object" && workerFromExecution !== null;
3104
+ const updatedWorker = hasWorkerOverride ? {
3105
+ ...currentWorker,
3106
+ ...workerFromExecution,
3107
+ currentWorkload: Math.max(0, previousWorkload - 1)
3108
+ } : {
3109
+ ...currentWorker,
3110
+ currentWorkload: Math.max(0, previousWorkload - 1)
3111
+ };
3112
+ const updatedWorkers = {
3113
+ ...baseWorkers,
3114
+ [workerId]: updatedWorker
3115
+ };
3116
+ logger2.debug("Worker workload decremented", {
3117
+ workerId,
3118
+ previousWorkload,
3119
+ newWorkload: updatedWorkers[workerId].currentWorkload,
3120
+ hadExecutionResultWorkers: !!executionResult.workers
3121
+ });
3122
+ return updatedWorkers;
3123
+ }
3124
+ function decrementWorkerOnError(state, workerId) {
3125
+ const currentWorker = getStateWorkerOrThrow(state, workerId);
3126
+ const previousWorkload = resolvePreviousWorkload(workerId, currentWorker);
3127
+ const updatedWorkers = {
3128
+ ...state.workers,
3129
+ [workerId]: {
3130
+ ...currentWorker,
3131
+ currentWorkload: Math.max(0, previousWorkload - 1)
3132
+ }
3133
+ };
3134
+ logger2.debug("Worker workload decremented (error path)", {
3135
+ workerId,
3136
+ previousWorkload,
3137
+ newWorkload: updatedWorkers[workerId].currentWorkload
3138
+ });
3139
+ return updatedWorkers;
3140
+ }
3141
+ function createErrorTaskResult(assignment, workerId, errorMessage) {
3142
+ logger2.warn("Creating error result for assignment", {
3143
+ workerId,
3144
+ assignmentId: assignment.id
3145
+ });
3146
+ return {
3147
+ assignmentId: assignment.id,
3148
+ workerId,
3149
+ success: false,
3150
+ result: "",
3151
+ error: errorMessage,
3152
+ completedAt: Date.now()
3153
+ };
3154
+ }
2835
3155
  function createWorkerNode(config) {
2836
- const {
2837
- id,
2838
- capabilities,
2839
- model,
2840
- tools = [],
2841
- systemPrompt,
2842
- verbose = false,
2843
- executeFn,
2844
- agent
2845
- } = config;
3156
+ const { id, model, executeFn, agent } = config;
2846
3157
  return async (state, runConfig) => {
2847
3158
  try {
2848
3159
  logger2.info("Worker node executing", {
@@ -2850,9 +3161,7 @@ function createWorkerNode(config) {
2850
3161
  iteration: state.iteration,
2851
3162
  activeAssignments: state.activeAssignments.length
2852
3163
  });
2853
- const currentAssignment = state.activeAssignments.find(
2854
- (assignment) => assignment.workerId === id && !state.completedTasks.some((task) => task.assignmentId === assignment.id)
2855
- );
3164
+ const currentAssignment = findCurrentAssignment(state, id);
2856
3165
  if (!currentAssignment) {
2857
3166
  logger2.debug("No active assignment found for worker", {
2858
3167
  workerId: id,
@@ -2864,105 +3173,35 @@ function createWorkerNode(config) {
2864
3173
  logger2.info("Worker processing assignment", {
2865
3174
  workerId: id,
2866
3175
  assignmentId: currentAssignment.id,
2867
- taskLength: currentAssignment.task.length,
2868
- taskPreview: currentAssignment.task.substring(0, 100)
3176
+ taskLength: currentAssignment.task.length
3177
+ });
3178
+ logger2.debug("Worker assignment details", {
3179
+ workerId: id,
3180
+ assignmentId: currentAssignment.id,
3181
+ taskLength: currentAssignment.task.length
2869
3182
  });
2870
- async function executeWithLLM() {
2871
- logger2.debug("Using default LLM execution", {
2872
- workerId: id,
2873
- hasTools: tools.length > 0,
2874
- toolCount: tools.length
2875
- });
2876
- const defaultSystemPrompt = `You are a specialized worker agent with the following capabilities:
2877
- Skills: ${capabilities.skills.join(", ")}
2878
- Tools: ${capabilities.tools.join(", ")}
2879
-
2880
- Execute the assigned task using your skills and tools. Provide a clear, actionable result.`;
2881
- const messages = [
2882
- new import_messages5.SystemMessage(systemPrompt || defaultSystemPrompt),
2883
- new import_messages5.HumanMessage(currentAssignment.task)
2884
- ];
2885
- let modelToUse = model;
2886
- if (tools.length > 0 && model.bindTools) {
2887
- logger2.debug("Binding tools to model", {
2888
- workerId: id,
2889
- toolCount: tools.length,
2890
- toolNames: tools.map((t) => t.metadata.name)
2891
- });
2892
- const langchainTools = convertWorkerToolsForLangChain(tools);
2893
- modelToUse = model.bindTools(langchainTools);
2894
- }
2895
- logger2.debug("Invoking LLM", { workerId: id });
2896
- const response = await modelToUse.invoke(messages);
2897
- const result = typeof response.content === "string" ? response.content : JSON.stringify(response.content);
2898
- logger2.info("Worker task completed", {
2899
- workerId: id,
2900
- assignmentId: currentAssignment.id,
2901
- resultLength: result.length,
2902
- resultPreview: result.substring(0, 100)
2903
- });
2904
- const taskResult = {
2905
- assignmentId: currentAssignment.id,
2906
- workerId: id,
2907
- success: true,
2908
- result,
2909
- completedAt: Date.now(),
2910
- metadata: {
2911
- skills_used: capabilities.skills
2912
- }
2913
- };
2914
- const message = {
2915
- id: `msg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
2916
- from: id,
2917
- to: ["supervisor"],
2918
- type: "task_result",
2919
- content: result,
2920
- timestamp: Date.now(),
2921
- metadata: {
2922
- assignmentId: currentAssignment.id,
2923
- success: true
2924
- }
2925
- };
2926
- return {
2927
- completedTasks: [taskResult],
2928
- messages: [message]
2929
- };
2930
- }
2931
3183
  let executionResult;
2932
3184
  if (executeFn) {
2933
3185
  logger2.debug("Using custom execution function", { workerId: id });
2934
3186
  executionResult = await executeFn(state, runConfig);
2935
3187
  } else if (agent && isReActAgent(agent)) {
2936
3188
  logger2.debug("Using ReAct agent", { workerId: id });
2937
- const wrappedFn = wrapReActAgent(id, agent, verbose);
3189
+ const wrappedFn = wrapReActAgent(id, agent, config.verbose ?? false);
2938
3190
  executionResult = await wrappedFn(state, runConfig);
2939
3191
  } else if (model) {
2940
- executionResult = await executeWithLLM();
3192
+ logger2.debug("Using default LLM execution", {
3193
+ workerId: id,
3194
+ hasTools: (config.tools ?? []).length > 0,
3195
+ toolCount: (config.tools ?? []).length
3196
+ });
3197
+ executionResult = await invokeWorkerModel(model, config, currentAssignment);
2941
3198
  } else {
2942
3199
  logger2.error("Worker missing required configuration", { workerId: id });
2943
3200
  throw new Error(
2944
3201
  `Worker ${id} requires either a model, an agent, or a custom execution function. Provide one of: config.model, config.agent, or config.executeFn`
2945
3202
  );
2946
3203
  }
2947
- const currentWorker = state.workers[id];
2948
- const baseWorkers = {
2949
- ...state.workers,
2950
- ...executionResult.workers || {}
2951
- };
2952
- const workerToUpdate = baseWorkers[id] || currentWorker;
2953
- const updatedWorkers = {
2954
- ...baseWorkers,
2955
- [id]: {
2956
- ...workerToUpdate,
2957
- currentWorkload: Math.max(0, workerToUpdate.currentWorkload - 1)
2958
- }
2959
- };
2960
- logger2.debug("Worker workload decremented", {
2961
- workerId: id,
2962
- previousWorkload: workerToUpdate.currentWorkload,
2963
- newWorkload: updatedWorkers[id].currentWorkload,
2964
- hadExecutionResultWorkers: !!executionResult.workers
2965
- });
3204
+ const updatedWorkers = mergeWorkersWithDecrement(state, id, executionResult);
2966
3205
  return {
2967
3206
  ...executionResult,
2968
3207
  workers: updatedWorkers
@@ -2973,41 +3212,29 @@ Execute the assigned task using your skills and tools. Provide a clear, actionab
2973
3212
  workerId: id,
2974
3213
  error: errorMessage
2975
3214
  });
2976
- const currentWorker = state.workers[id];
2977
- const updatedWorkers = {
2978
- ...state.workers,
2979
- [id]: {
2980
- ...currentWorker,
2981
- currentWorkload: Math.max(0, currentWorker.currentWorkload - 1)
2982
- }
2983
- };
2984
- logger2.debug("Worker workload decremented (error path)", {
2985
- workerId: id,
2986
- previousWorkload: currentWorker.currentWorkload,
2987
- newWorkload: updatedWorkers[id].currentWorkload
2988
- });
3215
+ let updatedWorkers;
3216
+ try {
3217
+ updatedWorkers = decrementWorkerOnError(state, id);
3218
+ } catch (workloadError) {
3219
+ const workloadErrorMessage = workloadError instanceof Error ? workloadError.message : String(workloadError);
3220
+ logger2.error("Worker error handling failed", {
3221
+ workerId: id,
3222
+ error: workloadErrorMessage
3223
+ });
3224
+ return {
3225
+ status: "failed",
3226
+ error: `${errorMessage}. ${workloadErrorMessage}`
3227
+ };
3228
+ }
2989
3229
  const currentAssignment = state.activeAssignments.find(
2990
3230
  (assignment) => assignment.workerId === id
2991
3231
  );
2992
3232
  if (currentAssignment) {
2993
- logger2.warn("Creating error result for assignment", {
2994
- workerId: id,
2995
- assignmentId: currentAssignment.id
2996
- });
2997
- const errorResult = {
2998
- assignmentId: currentAssignment.id,
2999
- workerId: id,
3000
- success: false,
3001
- result: "",
3002
- error: errorMessage,
3003
- completedAt: Date.now()
3004
- };
3005
3233
  return {
3006
- completedTasks: [errorResult],
3234
+ completedTasks: [createErrorTaskResult(currentAssignment, id, errorMessage)],
3007
3235
  currentAgent: "supervisor",
3008
3236
  status: "routing",
3009
3237
  workers: updatedWorkers
3010
- // Include workload update
3011
3238
  };
3012
3239
  }
3013
3240
  logger2.error("No assignment found for error handling", { workerId: id });
@@ -3015,95 +3242,6 @@ Execute the assigned task using your skills and tools. Provide a clear, actionab
3015
3242
  status: "failed",
3016
3243
  error: errorMessage,
3017
3244
  workers: updatedWorkers
3018
- // Include workload update even on failure
3019
- };
3020
- }
3021
- };
3022
- }
3023
- function createAggregatorNode(config = {}) {
3024
- const {
3025
- model,
3026
- systemPrompt = DEFAULT_AGGREGATOR_SYSTEM_PROMPT,
3027
- aggregateFn,
3028
- verbose = false
3029
- } = config;
3030
- return async (state) => {
3031
- try {
3032
- logger2.info("Aggregator node executing", {
3033
- completedTasks: state.completedTasks.length,
3034
- successfulTasks: state.completedTasks.filter((t) => t.success).length,
3035
- failedTasks: state.completedTasks.filter((t) => !t.success).length
3036
- });
3037
- logger2.debug("Combining results from workers");
3038
- if (aggregateFn) {
3039
- logger2.debug("Using custom aggregation function");
3040
- const response2 = await aggregateFn(state);
3041
- logger2.info("Custom aggregation complete", {
3042
- responseLength: response2.length
3043
- });
3044
- return {
3045
- response: response2,
3046
- status: "completed"
3047
- };
3048
- }
3049
- if (state.completedTasks.length === 0) {
3050
- logger2.warn("No completed tasks to aggregate");
3051
- return {
3052
- response: "No tasks were completed.",
3053
- status: "completed"
3054
- };
3055
- }
3056
- if (!model) {
3057
- logger2.debug("No model provided, concatenating results");
3058
- const combinedResults = state.completedTasks.filter((task) => task.success).map((task) => task.result).join("\n\n");
3059
- logger2.info("Simple concatenation complete", {
3060
- resultLength: combinedResults.length
3061
- });
3062
- return {
3063
- response: combinedResults || "No successful results to aggregate.",
3064
- status: "completed"
3065
- };
3066
- }
3067
- logger2.debug("Using LLM for intelligent aggregation", {
3068
- taskCount: state.completedTasks.length
3069
- });
3070
- const taskResults = state.completedTasks.map((task, idx) => {
3071
- const status = task.success ? "\u2713" : "\u2717";
3072
- const result = task.success ? task.result : `Error: ${task.error}`;
3073
- return `${idx + 1}. [${status}] Worker ${task.workerId}:
3074
- ${result}`;
3075
- }).join("\n\n");
3076
- const userPrompt = `Original query: ${state.input}
3077
-
3078
- Worker results:
3079
- ${taskResults}
3080
-
3081
- Please synthesize these results into a comprehensive response that addresses the original query.`;
3082
- const messages = [
3083
- new import_messages5.SystemMessage(systemPrompt),
3084
- new import_messages5.HumanMessage(userPrompt)
3085
- ];
3086
- logger2.debug("Invoking aggregation LLM");
3087
- const response = await model.invoke(messages);
3088
- const aggregatedResponse = typeof response.content === "string" ? response.content : JSON.stringify(response.content);
3089
- logger2.info("Aggregation complete", {
3090
- responseLength: aggregatedResponse.length,
3091
- responsePreview: aggregatedResponse.substring(0, 100)
3092
- });
3093
- logger2.debug("Aggregation complete");
3094
- return {
3095
- response: aggregatedResponse,
3096
- status: "completed"
3097
- };
3098
- } catch (error) {
3099
- logger2.error("Aggregator node error", {
3100
- error: error instanceof Error ? error.message : String(error),
3101
- ...error instanceof Error && error.stack ? { stack: error.stack } : {},
3102
- completedTasks: state.completedTasks.length
3103
- });
3104
- return {
3105
- status: "failed",
3106
- error: error instanceof Error ? error.message : "Unknown error in aggregator"
3107
3245
  };
3108
3246
  }
3109
3247
  };