@agentforge/patterns 0.16.1 → 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
@@ -2679,16 +2679,82 @@ function wrapReActAgent(workerId, agent, verbose = false) {
2679
2679
  };
2680
2680
  }
2681
2681
 
2682
- // src/multi-agent/nodes.ts
2682
+ // src/multi-agent/nodes/shared.ts
2683
2683
  var import_messages5 = require("@langchain/core/messages");
2684
2684
  var import_core8 = require("@agentforge/core");
2685
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
+ }
2686
2723
  function convertWorkerToolsForLangChain(tools) {
2687
2724
  const safeTools = tools ?? [];
2688
- return (0, import_core8.toLangChainTools)(
2689
- safeTools
2690
- );
2725
+ return (0, import_core8.toLangChainTools)(safeTools);
2691
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
2692
2758
  var DEFAULT_AGGREGATOR_SYSTEM_PROMPT = `You are an aggregator agent responsible for combining results from multiple worker agents.
2693
2759
 
2694
2760
  Your job is to:
@@ -2698,12 +2764,124 @@ Your job is to:
2698
2764
  4. Provide a clear, comprehensive final answer
2699
2765
 
2700
2766
  Be concise but thorough in your aggregation.`;
2701
- 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 = {}) {
2702
2782
  const {
2703
- strategy,
2704
- verbose = false,
2705
- maxIterations = 10
2783
+ model,
2784
+ systemPrompt = DEFAULT_AGGREGATOR_SYSTEM_PROMPT,
2785
+ aggregateFn
2706
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;
2707
2885
  return async (state) => {
2708
2886
  try {
2709
2887
  logger2.info("Supervisor node executing", {
@@ -2724,9 +2902,7 @@ function createSupervisorNode(config) {
2724
2902
  currentAgent: "aggregator"
2725
2903
  };
2726
2904
  }
2727
- const allCompleted = state.activeAssignments.every(
2728
- (assignment) => state.completedTasks.some((task2) => task2.assignmentId === assignment.id)
2729
- );
2905
+ const allCompleted = allAssignmentsCompleted(state);
2730
2906
  logger2.debug("Checking task completion", {
2731
2907
  activeAssignments: state.activeAssignments.length,
2732
2908
  completedTasks: state.completedTasks.length,
@@ -2764,6 +2940,7 @@ function createSupervisorNode(config) {
2764
2940
  reasoning: decision.reasoning,
2765
2941
  confidence: decision.confidence
2766
2942
  });
2943
+ logger2.debug(`Routing to ${targetAgents[0]}: ${decision.reasoning}`);
2767
2944
  } else {
2768
2945
  logger2.info("Routing to multiple agents in parallel", {
2769
2946
  targetAgents,
@@ -2771,57 +2948,22 @@ function createSupervisorNode(config) {
2771
2948
  reasoning: decision.reasoning,
2772
2949
  confidence: decision.confidence
2773
2950
  });
2951
+ logger2.debug(
2952
+ `Routing to ${targetAgents.length} agents in parallel [${targetAgents.join(", ")}]: ${decision.reasoning}`
2953
+ );
2774
2954
  }
2775
- if (targetAgents.length === 1) {
2776
- logger2.debug(`Routing to ${targetAgents[0]}: ${decision.reasoning}`);
2777
- } else {
2778
- logger2.debug(`Routing to ${targetAgents.length} agents in parallel [${targetAgents.join(", ")}]: ${decision.reasoning}`);
2779
- }
2780
- const task = state.messages[state.messages.length - 1]?.content || state.input;
2781
- const assignments = targetAgents.map((workerId) => ({
2782
- id: `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
2783
- workerId,
2784
- task,
2785
- priority: 5,
2786
- assignedAt: Date.now()
2787
- }));
2955
+ const task = getLatestTaskContent(state);
2956
+ const assignments = createTaskAssignments(targetAgents, task);
2788
2957
  logger2.debug("Created task assignments", {
2789
2958
  assignmentCount: assignments.length,
2790
- assignments: assignments.map((a) => ({
2791
- id: a.id,
2792
- workerId: a.workerId,
2793
- taskLength: a.task.length
2959
+ assignments: assignments.map((assignment) => ({
2960
+ id: assignment.id,
2961
+ workerId: assignment.workerId,
2962
+ taskLength: assignment.task.length
2794
2963
  }))
2795
2964
  });
2796
- const messages = assignments.map((assignment) => ({
2797
- id: `msg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
2798
- from: "supervisor",
2799
- to: [assignment.workerId],
2800
- type: "task_assignment",
2801
- content: assignment.task,
2802
- timestamp: Date.now(),
2803
- metadata: {
2804
- assignmentId: assignment.id,
2805
- priority: assignment.priority
2806
- }
2807
- }));
2808
- const updatedWorkers = { ...state.workers };
2809
- for (const assignment of assignments) {
2810
- const worker = updatedWorkers[assignment.workerId];
2811
- if (!worker) {
2812
- logger2.error("Worker not found in state", {
2813
- workerId: assignment.workerId,
2814
- availableWorkers: Object.keys(updatedWorkers)
2815
- });
2816
- throw new Error(
2817
- `Worker ${assignment.workerId} not found in state.workers. Available workers: ${Object.keys(updatedWorkers).join(", ")}`
2818
- );
2819
- }
2820
- updatedWorkers[assignment.workerId] = {
2821
- ...worker,
2822
- currentWorkload: worker.currentWorkload + 1
2823
- };
2824
- }
2965
+ const messages = createAssignmentMessages(assignments);
2966
+ const updatedWorkers = incrementAssignedWorkerLoads(state, assignments);
2825
2967
  logger2.info("Supervisor routing complete", {
2826
2968
  currentAgent: targetAgents.join(","),
2827
2969
  status: "executing",
@@ -2831,41 +2973,187 @@ function createSupervisorNode(config) {
2831
2973
  });
2832
2974
  return {
2833
2975
  currentAgent: targetAgents.join(","),
2834
- // Store all agents (for backward compat)
2835
2976
  status: "executing",
2836
2977
  routingHistory: [decision],
2837
2978
  activeAssignments: assignments,
2838
- // Multiple assignments for parallel execution!
2839
2979
  messages,
2840
2980
  workers: updatedWorkers,
2841
- // Include updated workload
2842
- // Add 1 to iteration counter (uses additive reducer)
2843
2981
  iteration: 1
2844
2982
  };
2845
2983
  } catch (error) {
2984
+ const errorMessage = handleNodeError(error, "supervisor", false);
2846
2985
  logger2.error("Supervisor node error", {
2847
- error: error instanceof Error ? error.message : String(error),
2986
+ error: errorMessage,
2848
2987
  ...error instanceof Error && error.stack ? { stack: error.stack } : {},
2849
2988
  iteration: state.iteration
2850
2989
  });
2851
2990
  return {
2852
2991
  status: "failed",
2853
- error: error instanceof Error ? error.message : "Unknown error in supervisor"
2992
+ error: errorMessage
2854
2993
  };
2855
2994
  }
2856
2995
  };
2857
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
+ }
2858
3155
  function createWorkerNode(config) {
2859
- const {
2860
- id,
2861
- capabilities,
2862
- model,
2863
- tools = [],
2864
- systemPrompt,
2865
- verbose = false,
2866
- executeFn,
2867
- agent
2868
- } = config;
3156
+ const { id, model, executeFn, agent } = config;
2869
3157
  return async (state, runConfig) => {
2870
3158
  try {
2871
3159
  logger2.info("Worker node executing", {
@@ -2873,9 +3161,7 @@ function createWorkerNode(config) {
2873
3161
  iteration: state.iteration,
2874
3162
  activeAssignments: state.activeAssignments.length
2875
3163
  });
2876
- const currentAssignment = state.activeAssignments.find(
2877
- (assignment) => assignment.workerId === id && !state.completedTasks.some((task) => task.assignmentId === assignment.id)
2878
- );
3164
+ const currentAssignment = findCurrentAssignment(state, id);
2879
3165
  if (!currentAssignment) {
2880
3166
  logger2.debug("No active assignment found for worker", {
2881
3167
  workerId: id,
@@ -2887,105 +3173,35 @@ function createWorkerNode(config) {
2887
3173
  logger2.info("Worker processing assignment", {
2888
3174
  workerId: id,
2889
3175
  assignmentId: currentAssignment.id,
2890
- taskLength: currentAssignment.task.length,
2891
- 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
2892
3182
  });
2893
- async function executeWithLLM() {
2894
- logger2.debug("Using default LLM execution", {
2895
- workerId: id,
2896
- hasTools: tools.length > 0,
2897
- toolCount: tools.length
2898
- });
2899
- const defaultSystemPrompt = `You are a specialized worker agent with the following capabilities:
2900
- Skills: ${capabilities.skills.join(", ")}
2901
- Tools: ${capabilities.tools.join(", ")}
2902
-
2903
- Execute the assigned task using your skills and tools. Provide a clear, actionable result.`;
2904
- const messages = [
2905
- new import_messages5.SystemMessage(systemPrompt || defaultSystemPrompt),
2906
- new import_messages5.HumanMessage(currentAssignment.task)
2907
- ];
2908
- let modelToUse = model;
2909
- if (tools.length > 0 && model.bindTools) {
2910
- logger2.debug("Binding tools to model", {
2911
- workerId: id,
2912
- toolCount: tools.length,
2913
- toolNames: tools.map((t) => t.metadata.name)
2914
- });
2915
- const langchainTools = convertWorkerToolsForLangChain(tools);
2916
- modelToUse = model.bindTools(langchainTools);
2917
- }
2918
- logger2.debug("Invoking LLM", { workerId: id });
2919
- const response = await modelToUse.invoke(messages);
2920
- const result = typeof response.content === "string" ? response.content : JSON.stringify(response.content);
2921
- logger2.info("Worker task completed", {
2922
- workerId: id,
2923
- assignmentId: currentAssignment.id,
2924
- resultLength: result.length,
2925
- resultPreview: result.substring(0, 100)
2926
- });
2927
- const taskResult = {
2928
- assignmentId: currentAssignment.id,
2929
- workerId: id,
2930
- success: true,
2931
- result,
2932
- completedAt: Date.now(),
2933
- metadata: {
2934
- skills_used: capabilities.skills
2935
- }
2936
- };
2937
- const message = {
2938
- id: `msg-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
2939
- from: id,
2940
- to: ["supervisor"],
2941
- type: "task_result",
2942
- content: result,
2943
- timestamp: Date.now(),
2944
- metadata: {
2945
- assignmentId: currentAssignment.id,
2946
- success: true
2947
- }
2948
- };
2949
- return {
2950
- completedTasks: [taskResult],
2951
- messages: [message]
2952
- };
2953
- }
2954
3183
  let executionResult;
2955
3184
  if (executeFn) {
2956
3185
  logger2.debug("Using custom execution function", { workerId: id });
2957
3186
  executionResult = await executeFn(state, runConfig);
2958
3187
  } else if (agent && isReActAgent(agent)) {
2959
3188
  logger2.debug("Using ReAct agent", { workerId: id });
2960
- const wrappedFn = wrapReActAgent(id, agent, verbose);
3189
+ const wrappedFn = wrapReActAgent(id, agent, config.verbose ?? false);
2961
3190
  executionResult = await wrappedFn(state, runConfig);
2962
3191
  } else if (model) {
2963
- 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);
2964
3198
  } else {
2965
3199
  logger2.error("Worker missing required configuration", { workerId: id });
2966
3200
  throw new Error(
2967
3201
  `Worker ${id} requires either a model, an agent, or a custom execution function. Provide one of: config.model, config.agent, or config.executeFn`
2968
3202
  );
2969
3203
  }
2970
- const currentWorker = state.workers[id];
2971
- const baseWorkers = {
2972
- ...state.workers,
2973
- ...executionResult.workers || {}
2974
- };
2975
- const workerToUpdate = baseWorkers[id] || currentWorker;
2976
- const updatedWorkers = {
2977
- ...baseWorkers,
2978
- [id]: {
2979
- ...workerToUpdate,
2980
- currentWorkload: Math.max(0, workerToUpdate.currentWorkload - 1)
2981
- }
2982
- };
2983
- logger2.debug("Worker workload decremented", {
2984
- workerId: id,
2985
- previousWorkload: workerToUpdate.currentWorkload,
2986
- newWorkload: updatedWorkers[id].currentWorkload,
2987
- hadExecutionResultWorkers: !!executionResult.workers
2988
- });
3204
+ const updatedWorkers = mergeWorkersWithDecrement(state, id, executionResult);
2989
3205
  return {
2990
3206
  ...executionResult,
2991
3207
  workers: updatedWorkers
@@ -2996,41 +3212,29 @@ Execute the assigned task using your skills and tools. Provide a clear, actionab
2996
3212
  workerId: id,
2997
3213
  error: errorMessage
2998
3214
  });
2999
- const currentWorker = state.workers[id];
3000
- const updatedWorkers = {
3001
- ...state.workers,
3002
- [id]: {
3003
- ...currentWorker,
3004
- currentWorkload: Math.max(0, currentWorker.currentWorkload - 1)
3005
- }
3006
- };
3007
- logger2.debug("Worker workload decremented (error path)", {
3008
- workerId: id,
3009
- previousWorkload: currentWorker.currentWorkload,
3010
- newWorkload: updatedWorkers[id].currentWorkload
3011
- });
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
+ }
3012
3229
  const currentAssignment = state.activeAssignments.find(
3013
3230
  (assignment) => assignment.workerId === id
3014
3231
  );
3015
3232
  if (currentAssignment) {
3016
- logger2.warn("Creating error result for assignment", {
3017
- workerId: id,
3018
- assignmentId: currentAssignment.id
3019
- });
3020
- const errorResult = {
3021
- assignmentId: currentAssignment.id,
3022
- workerId: id,
3023
- success: false,
3024
- result: "",
3025
- error: errorMessage,
3026
- completedAt: Date.now()
3027
- };
3028
3233
  return {
3029
- completedTasks: [errorResult],
3234
+ completedTasks: [createErrorTaskResult(currentAssignment, id, errorMessage)],
3030
3235
  currentAgent: "supervisor",
3031
3236
  status: "routing",
3032
3237
  workers: updatedWorkers
3033
- // Include workload update
3034
3238
  };
3035
3239
  }
3036
3240
  logger2.error("No assignment found for error handling", { workerId: id });
@@ -3038,95 +3242,6 @@ Execute the assigned task using your skills and tools. Provide a clear, actionab
3038
3242
  status: "failed",
3039
3243
  error: errorMessage,
3040
3244
  workers: updatedWorkers
3041
- // Include workload update even on failure
3042
- };
3043
- }
3044
- };
3045
- }
3046
- function createAggregatorNode(config = {}) {
3047
- const {
3048
- model,
3049
- systemPrompt = DEFAULT_AGGREGATOR_SYSTEM_PROMPT,
3050
- aggregateFn,
3051
- verbose = false
3052
- } = config;
3053
- return async (state) => {
3054
- try {
3055
- logger2.info("Aggregator node executing", {
3056
- completedTasks: state.completedTasks.length,
3057
- successfulTasks: state.completedTasks.filter((t) => t.success).length,
3058
- failedTasks: state.completedTasks.filter((t) => !t.success).length
3059
- });
3060
- logger2.debug("Combining results from workers");
3061
- if (aggregateFn) {
3062
- logger2.debug("Using custom aggregation function");
3063
- const response2 = await aggregateFn(state);
3064
- logger2.info("Custom aggregation complete", {
3065
- responseLength: response2.length
3066
- });
3067
- return {
3068
- response: response2,
3069
- status: "completed"
3070
- };
3071
- }
3072
- if (state.completedTasks.length === 0) {
3073
- logger2.warn("No completed tasks to aggregate");
3074
- return {
3075
- response: "No tasks were completed.",
3076
- status: "completed"
3077
- };
3078
- }
3079
- if (!model) {
3080
- logger2.debug("No model provided, concatenating results");
3081
- const combinedResults = state.completedTasks.filter((task) => task.success).map((task) => task.result).join("\n\n");
3082
- logger2.info("Simple concatenation complete", {
3083
- resultLength: combinedResults.length
3084
- });
3085
- return {
3086
- response: combinedResults || "No successful results to aggregate.",
3087
- status: "completed"
3088
- };
3089
- }
3090
- logger2.debug("Using LLM for intelligent aggregation", {
3091
- taskCount: state.completedTasks.length
3092
- });
3093
- const taskResults = state.completedTasks.map((task, idx) => {
3094
- const status = task.success ? "\u2713" : "\u2717";
3095
- const result = task.success ? task.result : `Error: ${task.error}`;
3096
- return `${idx + 1}. [${status}] Worker ${task.workerId}:
3097
- ${result}`;
3098
- }).join("\n\n");
3099
- const userPrompt = `Original query: ${state.input}
3100
-
3101
- Worker results:
3102
- ${taskResults}
3103
-
3104
- Please synthesize these results into a comprehensive response that addresses the original query.`;
3105
- const messages = [
3106
- new import_messages5.SystemMessage(systemPrompt),
3107
- new import_messages5.HumanMessage(userPrompt)
3108
- ];
3109
- logger2.debug("Invoking aggregation LLM");
3110
- const response = await model.invoke(messages);
3111
- const aggregatedResponse = typeof response.content === "string" ? response.content : JSON.stringify(response.content);
3112
- logger2.info("Aggregation complete", {
3113
- responseLength: aggregatedResponse.length,
3114
- responsePreview: aggregatedResponse.substring(0, 100)
3115
- });
3116
- logger2.debug("Aggregation complete");
3117
- return {
3118
- response: aggregatedResponse,
3119
- status: "completed"
3120
- };
3121
- } catch (error) {
3122
- logger2.error("Aggregator node error", {
3123
- error: error instanceof Error ? error.message : String(error),
3124
- ...error instanceof Error && error.stack ? { stack: error.stack } : {},
3125
- completedTasks: state.completedTasks.length
3126
- });
3127
- return {
3128
- status: "failed",
3129
- error: error instanceof Error ? error.message : "Unknown error in aggregator"
3130
3245
  };
3131
3246
  }
3132
3247
  };